GlobalReg.cc
上传用户:kellyonhid
上传日期:2013-10-12
资源大小:932k
文件大小:56k
源码类别:

3D图形编程

开发平台:

Visual C++

  1. //############################################################
  2. // GlobalReg.cc
  3. // Kari Pulli
  4. // Tue Jun 23 11:54:00 PDT 1998
  5. // 
  6. // Global registration of several scans simultaneously
  7. //############################################################
  8. #include <iostream.h>
  9. #include <fstream.h>
  10. #include <stdlib.h>
  11. #include <multimap.h>
  12. #include <deque.h>
  13. #include <strstream.h>
  14. #include <sys/stat.h>
  15. #include "GlobalReg.h"
  16. #include "absorient.h"
  17. #include "TbObj.h"
  18. #include "DisplayMesh.h"
  19. #include "plvScene.h"
  20. #include "ConnComp.h"
  21. #include "Progress.h"
  22. #include "BailDetector.h"
  23. #include "DirEntries.h"
  24. #include "FileNameUtils.h"
  25. #include "ScanFactory.h"
  26. #include "CyberScan.h"
  27. #include "GroupScan.h"
  28. #include "TclCmdUtils.h"
  29. #include <math.h>
  30. // TODO: make these sliders in globalreg window
  31. #define VB_SIZE (100.0)
  32. #define NOT_FOUND (-1)
  33. #define THRESHOLD (700) // THIS SHOULD BE MUCH LARGER probably
  34. #if defined(WIN32) || defined(i386)
  35. #define LITTLE_ENDIAN
  36. #endif
  37. // setup file loading routines for a little endian machine
  38. #ifdef LITTLE_ENDIAN
  39. inline short swap_short(short x)
  40. {
  41.   return ((x & 0xff) << 8) | ((unsigned short)x >> 8);
  42. }
  43. /* unsigned is essential, otherwise bitshift will 
  44.  * sign extend and mess up the conversion.
  45.  */
  46. inline int swap_int(unsigned int x)
  47. {
  48.   return (x << 24) |
  49.          ((x << 8) & 0x00ff0000) | 
  50.  ((x >> 8) & 0x0000ff00) | 
  51.  (x >> 24);
  52. }
  53. inline float swap_float(float x)
  54. {
  55.   unsigned int y = (*((unsigned int *)&x));
  56.   y= (y << 24) |
  57.      ((y << 8) & 0x00ff0000) | 
  58.      ((y >> 8) & 0x0000ff00) | 
  59.       (y >> 24);
  60.   return (*((float *)&y));
  61. }
  62. inline short FixShort(short x)
  63. {
  64.   return (swap_short(x));
  65. }
  66. inline int FixInt(int x)
  67. {
  68.   return (swap_int(x));
  69. }
  70. inline float FixFloat(float x)
  71. {
  72.   return (swap_float(x));
  73. }
  74.  
  75. // otherwise set up file loading routines for a big endian machine
  76. #else
  77. inline short FixShort(short x)
  78. {
  79.   return (x);
  80. }
  81. inline int FixInt(int x)
  82. {
  83.   return (x);
  84. }
  85. inline float FixFloat(float x)
  86. {
  87.   return (x);
  88. }
  89. #endif
  90. // File writing routines
  91. inline void WriteInt(int x, ofstream &out)
  92. {
  93.   int temp = FixInt(x);
  94.   out.write((char*)&temp, 4);
  95. }
  96. inline void WriteFloat(float x, ofstream &out)
  97. {
  98.   float temp = FixFloat(x);
  99.   out.write((char*)&temp, 4);
  100. }
  101. inline void WriteShort(short x, ofstream &out)
  102. {
  103.   short temp = FixShort(x);
  104.   out.write((char*)&temp, 2);
  105. }
  106. /* There is no ReadChar since no special byte ordering is required for characters */
  107. inline int ReadInt(ifstream &in)
  108. {
  109.   int temp;
  110.   in.read((char*)&temp, 4);
  111.   return FixInt(temp);
  112. }
  113. inline short ReadShort(ifstream &in)
  114. {
  115.   short temp;
  116.   in.read((char*)&temp, 2);
  117.   return FixShort(temp);
  118. }
  119. inline float ReadFloat(ifstream &in)
  120. {
  121.   float temp;
  122.   in.read((char*)&temp, 4);
  123.   return FixFloat(temp);
  124. }
  125. inline void WriteSDRawPoints(vector<sd_raw_pnt> &rp, int n, ofstream &out)
  126. {
  127.   for (int i=0; i<n; i++) {
  128.     WriteInt(rp[i].config, out);
  129.     
  130.     WriteShort(rp[i].y, out); 
  131.     WriteShort(rp[i].z, out);
  132.     
  133.     WriteFloat(rp[i].nod, out);
  134.     WriteFloat(rp[i].turn, out);
  135.     WriteFloat(rp[i].tr_h, out);
  136.   }
  137. }
  138. inline void WritePnt3(vector<Pnt3> &pnt, int n, ofstream &out)
  139. {
  140.   for (int i=0; i<n; i++) {
  141.     Pnt3 p = pnt[i];
  142.     
  143.     WriteFloat(*(float *)p, out);
  144.     WriteFloat(*((float *)p + 1), out);
  145.     WriteFloat(*((float *)p + 2), out);
  146.   }
  147. }
  148. inline void ReadPnt3(vector<Pnt3> &pnt, int n, ifstream &in)
  149. {
  150.   Pnt3 tempPnt;
  151.   for (int i=0; i<n; i++) {
  152.     float f1 = ReadFloat(in);
  153.     float f2 = ReadFloat(in);
  154.     float f3 = ReadFloat(in);
  155.     tempPnt.set(f1, f2, f3);
  156.     pnt[i] = tempPnt;
  157.   }
  158. }
  159. #define GR_MESHNAMES_SEP "^^^"
  160. #define ECHO(x) cout << #x << endl; x
  161. #define FOR_MAP_ENTRIES(key, data) 
  162.   for (ITT __m = hmm.begin(); __m != hmm.end(); __m++) {
  163.     TbObj *key     = (*__m).first;
  164.     mapEntry *data = (*__m).second;
  165. #define END_FOR_MAP }
  166. #define FOR_MATCHING_KEYS(key, data) 
  167.   { pair<ITT, ITT> __p = hmm.equal_range(key);
  168.     for (ITT __i = __p.first; __i!=__p.second; __i++) {
  169.       mapEntry *data = (*__i).second;
  170. #define END_FOR_KEYS }}
  171. #define CONTAINS(vec, item) 
  172.  (find(vec.begin(),vec.end(),item) != vec.end())
  173. // this is ugly: it's linear time, which makes
  174. // processing scans n^2 (though we have small n...)
  175. inline int
  176. scan_idx(const TbObj* a, const vector<TbObj*> &scan)
  177. {
  178.   for (int i=scan.size()-1; i>=0; i--) 
  179.     if (scan[i] == a) return i;
  180.   assert(0);
  181.   return 0;
  182. }
  183. inline float
  184. dist2(const vector<Pnt3> &P, const vector<Pnt3> &Q)
  185. {
  186.   float d = 0.0;
  187.   vector<Pnt3>::const_iterator ip = P.begin();
  188.   vector<Pnt3>::const_iterator iq = Q.begin();
  189.   while (ip != P.end()) {
  190.     d += dist2(*ip, *iq);
  191.     ip++; iq++;
  192.   }
  193.   assert(iq == Q.end());
  194.   return d;
  195. }
  196. static RigidScan*
  197. createProxyScanNamed (const crope& name)
  198. {
  199.   if (strcmp (Tcl_GetVar (g_tclInterp, "allowProxiesWithGR",
  200.   TCL_GLOBAL_ONLY), "0") == 0) {
  201.     return NULL;
  202.   }
  203.   // make sure we can find the scan, else it's pointless to try to
  204.   // globalreg it because we won't be able to use the results.
  205.   Tcl_VarEval (g_tclInterp, "file_locateScan ", name.c_str(), NULL);
  206.   char* filename = g_tclInterp->result;
  207.   if (!filename[0]) {
  208.     cerr << "Unable to locate scan for " << name << endl;
  209.     return NULL;
  210.   }
  211.   
  212.   // create invisible scan with 0 bbox
  213.   RigidScan* rs = CreateScanFromBbox (filename, Pnt3(), Pnt3());
  214.   DisplayableMesh* dm = theScene->addMeshSet (rs);
  215.   //cerr << "creating proxy named " << name << " as "
  216.   //   << dm->getName() << endl;
  217.   
  218.   Tcl_VarEval (g_tclInterp, "addMeshToWindow ",
  219.        dm->getName(), " 0", NULL);
  220.   Tcl_VarEval (g_tclInterp, "changeVis ", dm->getName(), " 0", NULL);
  221.   return rs;
  222. }
  223. static void
  224. calcPairwiseRmsErr(const vector<Pnt3> &ptsa,
  225.    const vector<Pnt3> &nrma,
  226.    const vector<Pnt3> &ptsb,
  227.    const vector<Pnt3> &nrmb,
  228.    const Xform<float> &rel_xf,
  229.    float &pw_point_rmsErr,
  230.    float &pw_plane_rmsErr)
  231. {
  232.   assert(ptsa.size());
  233.   // calculate the rms for point pair distances
  234.   pw_point_rmsErr = pw_plane_rmsErr = 0.0;
  235.   Pnt3  p,nrm;
  236.   int   n = ptsa.size();
  237.   bool  do_tangents = (nrma.size() != 0);
  238.   float d;
  239.   for (int i=0; i<n; i++) {
  240.     rel_xf.apply(ptsa[i], p);
  241.     pw_point_rmsErr += dist2(p, ptsb[i]);
  242.     if (do_tangents) {
  243.       rel_xf.apply_nrm(nrma[i], nrm);
  244.       p -= ptsb[i];
  245.       d = dot(nrm, p);
  246.       pw_plane_rmsErr += d*d;
  247.       d = dot(nrmb[i], p);
  248.       pw_plane_rmsErr += d*d;
  249.     }
  250.   }
  251.   pw_point_rmsErr = sqrtf(pw_point_rmsErr / n);
  252.   pw_plane_rmsErr = sqrtf(pw_plane_rmsErr / (2*n));
  253. }
  254. void 
  255. GlobalReg::mapEntry::stats(void)
  256. {
  257.   Xform<float> xf_a = xfa->getXform();
  258.   Xform<float> xf_b = xfb->getXform();
  259.   int n = ptsa.size();
  260.   Pnt3 first, second, nrm;
  261.   maxErr = avgErr = rmsErr = 0.0;
  262.   
  263.   Xform<float> actual_rel_xf = xf_b;
  264.   actual_rel_xf.fast_invert();
  265.   actual_rel_xf = actual_rel_xf * xf_a;
  266.   
  267.   for (int j=0; j<n; j++) {
  268.     // calculate the point wise distances
  269.     first  = ptsa[j];
  270.     second = ptsa[j];
  271.     actual_rel_xf (first);
  272.     rel_xf (second);
  273.     
  274.     float d = dist2(first, second);
  275.     if (d > maxErr) maxErr = d;
  276.     rmsErr += d;
  277.     avgErr += sqrtf(d);
  278.   }
  279.   for (j=0; j<n; j++) {
  280.     // calculate the point wise distances
  281.     first  = ptsb[j];
  282.     second = ptsb[j];
  283.     actual_rel_xf.apply_inv(first,first);
  284.     rel_xf.apply_inv(second,second);
  285.     
  286.     float d = dist2(first, second);
  287.     if (d > maxErr) maxErr = d;
  288.     rmsErr += d;
  289.     avgErr += sqrtf(d);
  290.   }
  291.   n *= 2;
  292.   avgErr /= n;
  293.   rmsErr = sqrtf(rmsErr/n);
  294. }
  295. static bool 
  296. write_points(ofstream &out, vector<Pnt3> &pts, TbObj *scan)
  297. {
  298.   CyberScan* cs = dynamic_cast<CyberScan*> (scan);
  299.   if (cs && GetTclGlobalBool ("writeGRsRaw")) {
  300.     //SHOW(cs);
  301.     // magic number (CyberScan point data 1)
  302.     out.write("cpd1", 4);
  303.     // point count
  304.     int n = pts.size();
  305.     WriteInt(n, out);
  306.     
  307.     // the points
  308.     vector<sd_raw_pnt> cw(n);
  309.     for (int i=0; i<n; i++) {
  310.       if (cs->get_raw_data(pts[i], cw[i]) == false) {
  311. cerr << "Problem in GlobalReg::write_points()"
  312.      << endl;
  313. return false;
  314.       }
  315.     }
  316.     
  317.     WriteSDRawPoints(cw, n, out);    
  318.   } else {
  319.     // magic number (general point data 1)
  320.     out.write("gpd1", 4);  
  321.     // point count
  322.     int n = pts.size();
  323.     WriteInt(n, out);
  324.    
  325.     // the points
  326.     WritePnt3(pts, n, out);   
  327.   }
  328.   return !out.fail();
  329. }
  330. static bool 
  331. read_points (ifstream &in,  vector<Pnt3> &pts)
  332. {
  333.   // magic number (general point data 1)
  334.   char magic[4];
  335.   in.read(magic, 4);
  336.   if ( strncmp(magic, "cpd1", 4)==0 ) {
  337.     cout << "CyberScan raw data" << endl;
  338.     // CyberScan raw data
  339.     int n;
  340.     n = ReadInt(in);
  341.     
  342.     pts.resize(n);
  343.     unsigned int config;
  344.     short yz[2];
  345.     float nt[2]; // nod, turn
  346.     float tr_h;
  347.     CyberXform xf;
  348.     for (int i=0; i<n; i++) {
  349.       config = ReadInt(in);
  350.       yz[0] = ReadShort(in);
  351.       yz[1] = ReadShort(in);
  352.       nt[0] = ReadFloat(in);
  353.       nt[1] = ReadFloat(in);
  354.       tr_h = ReadFloat(in);
  355.        
  356.       int os = config&1; // other_screw
  357.       
  358.       xf.setup(config, tr_h, nt[os]);
  359.       xf.set_screw(nt[!os], nt[!os]);
  360.       pts[i] = xf.apply_xform(yz[0],yz[1]);
  361.       if (! pts[i].isfinite()) {
  362. SHOW(pts[i]);
  363. SHOW(i);
  364. SHOW(config);
  365. SHOW(yz[0]);
  366. SHOW(yz[1]);
  367. SHOW(nt[0]);
  368. SHOW(nt[1]);
  369. SHOW(tr_h);
  370. SHOW(os);
  371.       }
  372.     }
  373.   } else if (!strncmp (magic, "gpd1", 4)) {
  374.     // good old regular 3d points
  375.     // point count
  376.     int n;
  377.     
  378.     n = ReadInt(in);
  379.     
  380.     pts.resize(n);
  381.     
  382.     // the points
  383.     ReadPnt3(pts, n, in);
  384.   } else {
  385.     cerr << "Bad magic field in .gr file!" << endl;
  386.     return false;
  387.   }
  388.   return !in.fail();
  389. }
  390. static struct {
  391.   char* magic; int ver;
  392. } GRVersionTable[] = {
  393.   { "GR01", 1 },
  394.   { "GR02", 2 },
  395.   { "GR03", 3 },
  396.   { "GR04", 4 }
  397. };
  398. #define cGRVersionTableSize (sizeof(GRVersionTable)/sizeof(GRVersionTable[0]))
  399. #define GRVersionCurrent (GRVersionTable[cGRVersionTableSize-1].magic)
  400. int GetGRVersion (char* magic)
  401. {
  402.   for (int i = 0; i < cGRVersionTableSize; i++) {
  403.     if (!strncmp (GRVersionTable[i].magic, magic, 4))
  404.       return GRVersionTable[i].ver;
  405.   }
  406.   return 0;
  407. }
  408. // try writing the mapEntry data into a single file
  409. void
  410. GlobalReg::mapEntry::export_to_file(const std::string &gr_dir)
  411. {
  412.   // figure out the filename
  413.   const char *name1 = GetTbObjName(xfa);
  414.   const char *name2 = GetTbObjName(xfb);
  415.   if (!name1 || !name2) {
  416.     cerr << "Couldn't get names, not saving global"
  417.  << " data" << endl;
  418.     return;
  419.   }
  420.   bool flip = false;
  421.   if (strcmp(name1, name2) == 1) {
  422.     flip = true;
  423.     const char *tmp = name2;
  424.     name2 = name1; name1 = tmp;
  425.   }
  426.   
  427.   std::string path = gr_dir;
  428.   if (!manually_aligned) path += "/auto";
  429.   path += std::string("/") + name1 + GR_MESHNAMES_SEP + name2 + ".gr";
  430.   // just overwrite the file if it exists
  431. #ifdef WIN32
  432.   ofstream out(path.c_str(), ios::binary);
  433. #else
  434.   ofstream out(path.c_str());
  435. #endif
  436.   if (!out) {
  437.     cerr << "Couldn't create file " << path.c_str() << endl;
  438.     return;
  439.   } else {
  440.     SHOW(path.c_str());
  441.   }
  442.   
  443.   // fill the file with useful stuff
  444.   cout << "Writing correspondences between " << name1
  445.        << " and " << name2 << " ... ";
  446.   
  447.   out.write(GRVersionCurrent, 4); // magic number
  448.   //SHOW(name1);
  449.   //SHOW(name2);
  450.   //SHOW(dynamic_cast<CyberScan*> (xfa));
  451.   //SHOW(dynamic_cast<GroupScan*> (xfa));
  452.   if (flip) {
  453.     write_points(out, ptsb, xfb);
  454.     write_points(out, ptsa, xfa);
  455.     Xform<float> tmp_xf = rel_xf;
  456.     tmp_xf.fast_invert();
  457.     for (int i=0; i<16; i++)
  458.         WriteFloat(*((float*)tmp_xf + i), out);
  459.   } else {    
  460.     write_points(out, ptsa, xfa);
  461.     write_points(out, ptsb, xfb);
  462.     for (int i=0; i<16; i++)
  463.       WriteFloat(*((float*)rel_xf + i), out);
  464.   } 
  465.   WriteFloat(pw_point_rmsErr, out);
  466.   WriteFloat(pw_plane_rmsErr, out);
  467.   WriteInt(quality_grade, out);
  468.   out.write((char *)&manually_aligned, 1 /*sizeof(bool) */);
  469.   
  470.   if (out.fail()) return;
  471.   cout << "success." << endl;
  472.   // currently saving:
  473.   // pairwiserms errors
  474.   // point count
  475.   // points
  476.   // registration xform
  477.   // whether manually aligned
  478.   // should also write:
  479.   // rmserror to tangent plane
  480.   // sampling density? 
  481.   // or weight that would normalize based on area?
  482. }
  483. void
  484. GlobalReg::mapEntry::export_cyber_raw(const char *fname)
  485. {
  486.   // only work if both scans are CyberScans
  487.   CyberScan *csa = dynamic_cast<CyberScan*> (xfa);
  488.   CyberScan *csb = dynamic_cast<CyberScan*> (xfb);
  489.   if (!csa || !csb) return;
  490.   ofstream out(fname);
  491.   if (!out) {
  492.     cerr << "Couldn't create file " << fname << endl;
  493.     return;
  494.   } else {
  495.     SHOW(fname);
  496.   }
  497.   
  498.   int cPnt = ptsa.size();
  499.   out.write ((char*)&cPnt, sizeof(cPnt));
  500.   //bool vert;
  501.   sd_raw_pnt cw;
  502.   for (int i=0; i<cPnt; i++) {
  503.     if (csa->get_raw_data(ptsa[i], cw) == false) {
  504.       cerr << "Problem in GlobalReg::mapEntry::export_cyber_raw()"
  505.    << endl;
  506.       return;
  507.     }
  508.     int tmp = (cw.config & 0x00000001); // vert;
  509.     out.write((char*) &tmp,    sizeof(int));
  510.     out.write((char*) &cw.y,   2*sizeof(short));
  511.     out.write((char*) &cw.nod, 2*sizeof(float));
  512.   }
  513.   for (i=0; i<cPnt; i++) {
  514.     if (csb->get_raw_data(ptsb[i], cw) == false) {
  515.       cerr << "Problem in GlobalReg::mapEntry::export_cyber_raw()"
  516.    << endl;
  517.       return;
  518.     }
  519.     int tmp = (cw.config & 0x00000001); // vert;
  520.     out.write((char*) &tmp,    sizeof(int));
  521.     out.write((char*) &cw.y,   2*sizeof(short));
  522.     out.write((char*) &cw.nod, 2*sizeof(float));
  523.   }
  524.   out.write ((char*)(float*)rel_xf, 16 * sizeof(float));
  525.   
  526.   if (g_verbose) {
  527.     if (out.fail()) cout << "failure." << endl;
  528.     else            cout << "success." << endl;
  529.   }
  530. }
  531. // if partner == NULL, this fn will return the points from ALL
  532. // the scans P is partnered with
  533. void 
  534. GlobalReg::get_pts(TbObj *x, vector<Pnt3> &P, vector<Pnt3> &Q,
  535.    TbObj* partner)
  536. {
  537.   P.clear(); Q.clear();
  538.   // find entries with key x
  539.   FOR_MATCHING_KEYS(x, data) {
  540.     TbObj *datap, *dataq;
  541.     XF_F  dataxf = data->rel_xf;
  542.     vector<Pnt3> *pp;//, *qq;
  543.     if (x == data->xfa) {
  544.       datap = data->xfa; dataq = data->xfb;
  545.       pp = &data->ptsa;//  qq = &data->ptsb;
  546.     } else {
  547.       datap = data->xfb; dataq = data->xfa;
  548.       pp = &data->ptsb;//  qq = &data->ptsa;
  549.       dataxf.fast_invert();
  550.     }
  551.     if (partner != NULL && dataq != partner)
  552.       continue;
  553.     int ind = P.size();
  554.     P.insert(P.end(), pp->begin(), pp->end());
  555. #if 1
  556.     // Q becomes "where P's points should be in Q's coords"
  557.     for (int i=0; i<pp->size(); i++) {
  558.       //Pnt3 p = data->ptsa[i];
  559.       Pnt3 p = (*pp)[i];
  560.       dataxf(p);
  561.       Q.push_back(p);
  562.     }
  563. #else
  564.     Q.insert(Q.end(), qq->begin(), qq->end());
  565. #endif
  566.     // then convert to world coordinates
  567.     for_each (P.begin() + ind, P.end(), datap->getXform());
  568.     for_each (Q.begin() + ind, Q.end(), dataq->getXform());
  569.   } END_FOR_KEYS
  570. }
  571. // used for global registration, and only Horn's version
  572. void 
  573. GlobalReg::get_pts_within_group(TbObj *x,
  574. vector<Pnt3> &P, vector<Pnt3> &Q,
  575. vector<TbObj*> &group)
  576. {
  577.   P.clear(); Q.clear();
  578.   // find entries with key x
  579.   FOR_MATCHING_KEYS(x, data) {
  580.     TbObj *datap, *dataq;
  581.     XF_F  dataxf = data->rel_xf;
  582.     vector<Pnt3> *pp;//, *qq;
  583.     if (x == data->xfa) {
  584.       datap = data->xfa; dataq = data->xfb;
  585.       pp = &data->ptsa;//  qq = &data->ptsb;
  586.     } else {
  587.       datap = data->xfb; dataq = data->xfa;
  588.       pp = &data->ptsb;//  qq = &data->ptsa;
  589.       dataxf.fast_invert();
  590.     }
  591.     
  592.     if (CONTAINS(group, dataq)) {
  593.       // copy the points (in local coordinates)
  594.       int ind = P.size();
  595.       P.insert(P.end(), pp->begin(), pp->end());
  596. #if 1
  597.       // Q becomes "where P's points should be in Q's coords"
  598.       for (int i=0; i<pp->size(); i++) {
  599. Pnt3 p = (*pp)[i];
  600. dataxf(p);
  601. Q.push_back(p);
  602.       }
  603. #else
  604.       Q.insert(Q.end(), qq->begin(), qq->end());
  605. #endif
  606.       // then convert to world coordinates
  607.       for_each (P.begin() + ind, P.end(), datap->getXform());
  608.       for_each (Q.begin() + ind, Q.end(), dataq->getXform());
  609.     }
  610.   } END_FOR_KEYS;
  611.       
  612. }
  613. void
  614. GlobalReg::evaluate(const vector<TbObj*> &group)
  615. {
  616.   for (int i=0; i<group.size(); i++) {
  617.     FOR_MATCHING_KEYS(group[i], data) {
  618.       // TbObjs in a pair must be in the same group!
  619.       assert(data->xfa == group[i] ||
  620.      CONTAINS(group, data->xfa));
  621.       assert(data->xfb == group[i] ||
  622.      CONTAINS(group, data->xfb));
  623.       if (data->xfb == group[i]) continue;
  624.       
  625.       data->stats();
  626.     } END_FOR_KEYS;
  627.   }
  628. }
  629. float
  630. GlobalReg::evaluate(TbObj *one)
  631. {
  632.   // calculate the mean distance between every point pair
  633.   int   cnt   = 0;
  634.   float sumSq = 0.0;
  635.   
  636.   FOR_MATCHING_KEYS(one, data) {
  637.      data->stats();
  638.      int n     = data->ptsa.size();
  639.      float rms = data->rmsErr;
  640.      cnt   += n;
  641.      sumSq += n*rms*rms;
  642.   } END_FOR_KEYS;
  643.   if (cnt == 0) {
  644.     cerr << "GlobalReg::evaluate() didn't have entries to"
  645.  << " evaluate" << endl;
  646.     return 0.0;
  647.   }
  648.   return sqrtf(sumSq/cnt);
  649. }
  650. static crope
  651. nameFromTbObj (TbObj* tbo)
  652. {
  653.   if (tbo) {
  654.     RigidScan* rs = dynamic_cast<RigidScan*> (tbo);
  655.     if (rs) {
  656.       DisplayableMesh* dm = FindMeshDisplayInfo (rs);
  657.       if (dm) return dm->getName();
  658.       else    return rs->get_name();
  659.     }
  660.     return crope("(unknown)");
  661.   }
  662.   return crope("(NULL)");
  663. }
  664. void 
  665. GlobalReg::dump(void)
  666. {
  667.   cout << endl;
  668.   FOR_MAP_ENTRIES(key, data) {
  669.     SHOW(key);
  670.     SHOW(data);
  671.     SHOW(data->xfa);
  672.     SHOW(data->xfb);
  673.     vector<Pnt3> &ptsa = data->ptsa;
  674.     cout << "-" << endl;
  675.     copy(ptsa.begin(), ptsa.end(), 
  676.  ostream_iterator<Pnt3>(cout, "n"));
  677.     vector<Pnt3> &ptsb = data->ptsb;
  678.     cout << "-" << endl;
  679.     copy(ptsb.begin(), ptsb.end(), 
  680.  ostream_iterator<Pnt3>(cout, "n"));
  681.     cout << "-" << endl;
  682.     copy(all_scans.begin(), all_scans.end(), 
  683.  ostream_iterator<TbObj*>(cout, "n"));
  684.   } END_FOR_MAP
  685.   cout << endl;
  686. }
  687. void
  688. GlobalReg::move_back(const vector<TbObj*> &group,
  689.      const vector<XF_F> &old_xf)
  690. {
  691.   cout << "Moving the scans back..." << flush;
  692.   // first, create point pairs
  693.   vector<Pnt3> P,Q;
  694.   XF_F xfp, xfq;
  695.   int i,j;
  696.   for (i=0; i<group.size(); i++) {
  697.     FOR_MATCHING_KEYS(group[i], data) {
  698.       // each entry twice in the map
  699.       if (group[i] == data->xfb) continue;
  700.       // points in data ptsa
  701.       int end = P.size();
  702.       for (j=0; j<data->ptsa.size(); j+=20) {
  703. P.push_back(data->ptsa[j]);
  704. Q.push_back(data->ptsa[j]);
  705.       }
  706.       xfp = data->xfa->getXform();               // current xf
  707.       xfq = old_xf[scan_idx(data->xfa, group)];  // old xf
  708.       for_each(P.begin() + end, P.end(), xfp);
  709.       for_each(Q.begin() + end, Q.end(), xfq);
  710.       // points in data ptsb
  711.       end = P.size();
  712.       for (j=0; j<data->ptsb.size(); j+=20) {
  713. P.push_back(data->ptsb[j]);
  714. Q.push_back(data->ptsb[j]);
  715.       }
  716.       xfp = data->xfb->getXform();               // current xf
  717.       xfq = old_xf[scan_idx(data->xfb, group)];  // old xf
  718.       for_each(P.begin() + end, P.end(), xfp);
  719.       for_each(Q.begin() + end, Q.end(), xfq);
  720.     } END_FOR_KEYS;
  721.   }
  722.   // find the motion that brings the group back close to
  723.   // where it was
  724.   double q[7];
  725.   horn_align(&P[0], &Q[0], P.size(), q);
  726.   xfp.fromQuaternion(q, q[4], q[5], q[6]);
  727.   // apply it
  728.   for (i=0; i<group.size(); i++) {
  729.     group[i]->setXform((xfp * 
  730. group[i]->getXform()).enforce_rigidity());
  731.   }
  732.   cout << "done." << endl;
  733. }
  734. Xform<float>
  735. GlobalReg::compute_xform(vector<Pnt3> &P, vector<Pnt3> &Q)
  736. {
  737.   Xform<float> xf;
  738.   double q[7];
  739.   horn_align (&P[0], &Q[0], P.size(), q);
  740.   xf.fromQuaternion (q, q[4], q[5], q[6]);
  741.   return xf;
  742. }
  743. void
  744. GlobalReg::align_one_to_others (TbObj* one, TbObj* two)
  745. {
  746.   vector<Pnt3> P,Q;
  747.   float sum = .5*FLT_MAX, oldsum;
  748.   one->save_for_undo();
  749.   do {
  750.     oldsum = sum;
  751.     get_pts (one, P, Q, two);  // two==NULL means use all partners
  752.     if (P.size() == 0) continue;
  753.     one->setXform(compute_xform(P, Q) * one->getXform(),
  754.   false);
  755.     sum = evaluate(one);
  756.     cout << "The average point-to-point distance is "
  757.  << sum << endl;
  758.     
  759.     if (BailDetector::bail()) {
  760.       cerr << "global alignment cancelled." << endl;
  761.       break;
  762.     }
  763.   } while (2.0*(oldsum-sum) > ftol*(sum+oldsum+1.e-10));
  764. }
  765. #define FOR_ACTIVE_NBORS(scan, nbor) 
  766.   FOR_MATCHING_KEYS(scan, data) {
  767.     TbObj *nbor = (data->xfa == scan ? data->xfb : data->xfa);
  768.     if (active.end() != find(active.begin(),active.end(),nbor)){
  769. #define END_FOR_NBORS }}}}
  770. /* // get emacs identation working after above macro definition... 
  771. */
  772. // part covered by psuedo-code in the paper
  773. void
  774. GlobalReg::align_group(const vector<TbObj*> &group)
  775. {
  776.   vector<Pnt3> P,Q;
  777.   int          i;
  778.   assert (group.size() > 1);
  779.   vector<XF_F> old_xf(group.size());
  780.   for (i=0; i<group.size(); i++) {
  781.     old_xf[i] = group[i]->getXform();
  782.     group[i]->save_for_undo();
  783.   }
  784.   // new algorithm
  785.   //
  786.   // for each member of the group, calculate the number
  787.   // of links, choose the one with the most links as the seed
  788.   //
  789.   // push the seed to a queue and to the active set
  790.   // 
  791.   // process the queue until empty
  792.   //     take the scan at the front
  793.   //     align it with the scans in the active set
  794.   //     if it improves more than the threshold
  795.   //         push all the neighbors in the active set to queue
  796.   // 
  797.   // add to the queue and the active set the scan with the
  798.   // most links to scans in the active set
  799.   vector<TbObj*> active, dormant, nbors;
  800.   deque<TbObj*>  que;
  801.   TbObj *seed;
  802.   int    seed_links = 0;
  803.   // set the dormant and active sets...
  804.   if (dirty_scans.size()) {
  805.     for (i=0; i<group.size(); i++) {
  806.       if (dirty_scans.find(group[i]) != dirty_scans.end()) {
  807. dormant.push_back(group[i]);
  808.       } else {
  809. active.push_back(group[i]);
  810.       }
  811.     }
  812.   }
  813.   if (active.size() == 0) {
  814.     // active set is empty!
  815.     // initialize, find the seed (one with most links)
  816.     for (i=0; i<group.size(); i++) {
  817.       int links = 0;
  818.       FOR_MATCHING_KEYS(group[i], data) {
  819. links++;
  820.       } END_FOR_KEYS;
  821.       if (links > seed_links) {
  822. seed_links = links;
  823. seed = group[i];
  824.       }
  825.     }
  826.     assert(seed_links);
  827.     // initialize the active and dormant sets
  828.     active.push_back(seed);
  829.     dormant.clear();
  830.     dormant.reserve(group.size()-1);
  831.     for (i=0; i<group.size(); i++) {
  832.       if (group[i] != seed) dormant.push_back(group[i]);
  833.     }
  834.   }
  835.   Progress progress (dormant.size(), "Global alignment");
  836.   // process all scans
  837.   while (!dormant.empty()) {
  838.     // find the dormant scan that has the most links to scans
  839.     // in active set
  840.     seed_links = 0;
  841.     vector<TbObj*>::iterator it, pos;
  842.     for (it = dormant.begin(); it != dormant.end(); it++) {
  843.       int links = 0;
  844.       FOR_ACTIVE_NBORS(*it, nbor) {
  845. links++;
  846.       } END_FOR_NBORS;
  847.       if (links > seed_links) {
  848. seed_links = links;
  849. pos        = it;
  850.       }
  851.     }
  852.     assert(seed_links);
  853.     // remove from dormant set
  854.     seed = *pos;
  855.     int dormant_size = dormant.size();
  856.     dormant.erase(pos);
  857.     assert(dormant_size - 1 == dormant.size());
  858.     // push to active and queue
  859.     active.push_back(seed);
  860.     assert(que.empty());
  861.     que.push_back(seed);
  862.     
  863.     cout << "n";
  864.     SHOW(active.size());
  865.     SHOW(dormant.size());
  866.     // process the queue
  867.     int cnt = 0;
  868.     while (!que.empty()) {
  869.       seed = que.front();
  870.       que.pop_front();
  871.       // align front of the queue with the active set
  872.       nbors.clear();
  873.       FOR_ACTIVE_NBORS(seed, nbor) {
  874. nbors.push_back(nbor);
  875.       } END_FOR_NBORS;
  876.       SHOW(nbors.size());
  877.       
  878.       // here we already need to have determined the needed pts
  879.       get_pts_within_group(seed, P, Q, nbors);
  880.       assert(P.size());
  881.       assert(P.size() == Q.size());
  882.       float start_dist = dist2(P,Q);
  883.       SHOW(start_dist);
  884.       //Xform<float> xf;
  885.       //double q[7];
  886.       //horn_align (&P[0], &Q[0], P.size(), q);
  887.       //xf.fromQuaternion (q, q[4], q[5], q[6]);
  888.       
  889.       // ... so when we get to here we can compute a less 
  890.       // biased xform
  891.       Xform<float> xf = compute_xform(P, Q);
  892.       for_each(P.begin(), P.end(), xf);
  893.       float end_dist = dist2(P,Q);
  894.       SHOW(end_dist);
  895.       // if changed enough, push the neighbors into queue
  896.       float diff = start_dist - end_dist;
  897.       if (diff > 0.0) 
  898. seed->setXform(xf * seed->getXform(), false);
  899.       if (diff > ftol * end_dist && 
  900.   diff > 1.0e-6) {
  901. if (cnt++ < 200) {
  902.   for (it = nbors.begin(); it != nbors.end(); it++) {
  903.     if (!CONTAINS(que, *it)) {
  904.       // nbor not in queue already, push
  905.       que.push_back(*it);
  906.     }
  907.   }
  908. }
  909.       }
  910.       //SHOW(start_dist);
  911.       //SHOW(end_dist);
  912.       cout << que.size() << " left; last ";
  913.       SHOW(diff/P.size());
  914.       //SHOW(que.size());
  915.       //SHOW(active.size());
  916.       //SHOW(ftol);
  917.     }
  918.     if (!progress.updateInc())
  919.       break;
  920.     if (BailDetector::bail()) {
  921.       cerr << "global alignment cancelled." << endl;
  922.       break;
  923.     }
  924.   }
  925.   // align the new points with the old points in order
  926.   // to minimize the motion of the whole group
  927.   move_back(group, old_xf);
  928.   evaluate(group);
  929. }
  930. bool
  931. GlobalReg::getPairError(TbObj *a, TbObj *b, 
  932.                         float &pointError,
  933.                         float &planeError,
  934.                         float &globalError,
  935.                         bool  &manual)
  936. {
  937.   FOR_MATCHING_KEYS(a, data) {
  938.     if ((data->xfa == a && data->xfb == b) ||
  939. (data->xfb == a && data->xfa == b)) {
  940.       pointError  = data->pw_point_rmsErr;
  941.       planeError  = data->pw_plane_rmsErr;
  942.       globalError = data->rmsErr;
  943.       manual      = data->manually_aligned;
  944.       return true;
  945.     }
  946.   } END_FOR_KEYS;
  947.   return false;
  948. }
  949. // later overwrites the first
  950. // also if detect that both auto and manual versions
  951. // exist, unlink the auto version
  952. // or if two versions of the same link exist, delete
  953. // the older one
  954. GlobalReg::mapEntry*
  955. GlobalReg::import(const std::string &fname, bool manual)
  956. {
  957.   cout << "import " << fname.c_str() << endl;
  958.   // TODO: the below (I guess just the rfind) expects / as path separator,
  959.   // and can't deal with , so we need to either teach it or replace  for /
  960.   // to make this work on Windows.
  961.   // get the mesh names
  962.   std::string name[2];
  963.   int tmp1 = fname.rfind("/");
  964.   if (tmp1) tmp1++; // skip /
  965.   int tmp2 = fname.find(GR_MESHNAMES_SEP);
  966.   name[0].assign(fname, tmp1, tmp2-tmp1);
  967.   tmp2 += strlen(GR_MESHNAMES_SEP); // skip ::: or whatever the separator is
  968.   name[1].assign(fname, tmp2, fname.size()-tmp2-3);
  969.   // get the TbObj pointers
  970.   TbObj* tbobj[2];
  971.   for (int is = 0; is < 2; is++) {
  972.     DisplayableMesh *dm = FindMeshDisplayInfo(name[is].c_str());
  973.     if (dm) {
  974.       // the mesh is in memory
  975.       tbobj[is] = dm->getMeshData();
  976.     } else {
  977.       // the mesh is not in memory; need to proxy
  978.       tbobj[is] = createProxyScanNamed (name[is].c_str());
  979.       if (!tbobj[is]) {
  980. //cerr << "  ignoring correspondence " 
  981. //     << fname.c_str() << endl;
  982. return NULL;
  983.       }
  984.     }
  985.   }
  986.   FOR_MATCHING_KEYS(tbobj[0], data) {
  987.     if ((data->xfa == tbobj[0] && data->xfb == tbobj[1]) ||
  988. (data->xfb == tbobj[0] && data->xfa == tbobj[1])) {
  989.       // this mapentry exists!
  990.       if (manual && data->manually_aligned == false) {
  991. // the previous entry was an autoICP entry, delete
  992. cerr << "Warning: there seem to be several entries " 
  993.      << endl << "involving meshes " << name[0].c_str() 
  994.      << " and " << name[1].c_str() << endl;
  995. cerr << "Deleting autoICP *.gr entry" << endl;
  996. unlink_gr_files(data->xfa, data->xfb, true);
  997. // continue to read over this entry
  998. break;
  999.       } else {
  1000. // don't read this entry
  1001. return NULL;
  1002.       }
  1003.     }      
  1004.   } END_FOR_KEYS;
  1005. #ifdef WIN32
  1006.   ifstream in(fname.c_str(), ios::binary);
  1007. #else
  1008.   ifstream in(fname.c_str());
  1009. #endif
  1010.   if (!in) {
  1011.     cerr << "Couldn't open file " << fname.c_str()
  1012.  << " for reading" << endl;
  1013.     return NULL;
  1014.   }
  1015.   
  1016.   vector<Pnt3> ap, bp;
  1017.   float rel_xf[16];
  1018.   float pw_point_rmsErr, pw_plane_rmsErr;
  1019.   char version[4];
  1020.   in.read(version, 4);
  1021.   int cPnt;
  1022.   
  1023.   int iVersion = GetGRVersion (version);
  1024.   switch (iVersion) {
  1025.   case 1:
  1026.     // Oops, in version one saved this twice.
  1027.     // Ignore this first one.
  1028.     pw_point_rmsErr = ReadFloat(in);
  1029.     cPnt = ReadInt(in);
  1030.     ap.resize(cPnt); bp.resize(cPnt);
  1031.     ReadPnt3(ap, cPnt, in);
  1032.     ReadPnt3(bp, cPnt, in);
  1033.     /* haven't check this case, should work, but this was the code
  1034.      * that was here before the endian fix.
  1035.     in.read((char*)&pw_point_rmsErr, sizeof(float));
  1036.     in.read((char*)&cPnt, sizeof(int));
  1037.     ap.resize(cPnt); bp.resize(cPnt);
  1038.     in.read((char*)&ap[0], cPnt*sizeof(Pnt3));
  1039.     in.read((char*)&bp[0], cPnt*sizeof(Pnt3)); 
  1040.     */
  1041.     break;
  1042.   case 2:
  1043.     
  1044.     cPnt = ReadInt(in);
  1045.     ap.resize(cPnt); bp.resize(cPnt);
  1046.     ReadPnt3(ap, cPnt, in);
  1047.     ReadPnt3(bp, cPnt, in);
  1048.     /* haven't check this case, should work, but this was the code
  1049.      * that was here before the endian fix.
  1050.     in.read((char*)&cPnt, sizeof(int));
  1051.     ap.resize(cPnt); bp.resize(cPnt);
  1052.     in.read((char*)&ap[0], cPnt*sizeof(Pnt3));
  1053.     in.read((char*)&bp[0], cPnt*sizeof(Pnt3));
  1054.     */
  1055.     break;
  1056.   case 3:
  1057.   case 4:
  1058.     read_points(in, ap);
  1059.     read_points(in, bp);
  1060.     break;
  1061.   case 0:
  1062.   default:
  1063.     cerr << fname.c_str() 
  1064.  << " does not have the correct signature" << endl;
  1065.     cerr << "It may have been created with an out-of-date "
  1066.  << "version of scanalyze" << endl;
  1067.     return NULL;
  1068.   }
  1069.   for (int i=0; i<16; i++) 
  1070.     (*((float *)rel_xf + i)) = ReadFloat(in);
  1071.   pw_point_rmsErr = ReadFloat(in);
  1072.   pw_plane_rmsErr = ReadFloat(in);
  1073.   int quality = mapEntry::qual_Unknown;
  1074.   if (iVersion == 4) {
  1075.     // version 4 fields: quality, manually_aligned
  1076.     // yeah, manual is passed in to this function, but that seems a
  1077.     // broken idea to me, so let this override it
  1078.     
  1079.     quality = ReadInt(in);
  1080.     in.read((char*)&manual, 1 /*sizeof(bool)*/);
  1081.     
  1082.   }
  1083.   // create and insert mapEntry
  1084.   mapEntry* entry = addPair(tbobj[0], tbobj[1], ap, bp,
  1085.     pw_point_rmsErr, pw_plane_rmsErr,
  1086.     rel_xf, manual, 1000000, false, quality);
  1087.   // and grab its modification time from file
  1088.   struct stat fileinfo;
  1089.   stat (fname.c_str(), &fileinfo);
  1090.   entry->modifyDate = fileinfo.st_mtime;
  1091.   return entry;
  1092. }
  1093. inline void
  1094. unlink_gr_file(std::string path,
  1095.        std::string n1,
  1096.        std::string n2)
  1097. {
  1098.   path += "/";
  1099.   path += n1;
  1100.   path += GR_MESHNAMES_SEP;
  1101.   path += n2;
  1102.   path += ".gr";
  1103.   unlink_if_exists(path.c_str());  
  1104. }
  1105. void
  1106. GlobalReg::unlink_gr_files(TbObj *a, TbObj *b, bool only_auto)
  1107. {
  1108.   std::string name1, name2;
  1109.   name1 = GetTbObjName(a);
  1110.   name2 = GetTbObjName(b);
  1111.   unlink_gr_file(gr_auto_dir, name1, name2);
  1112.   unlink_gr_file(gr_auto_dir, name2, name1);
  1113.   if (only_auto == false) {
  1114.     unlink_gr_file(gr_dir, name1, name2);
  1115.     unlink_gr_file(gr_dir, name2, name1);
  1116.   }
  1117. }
  1118. GlobalReg::GlobalReg(void)
  1119.   : initial_import_done(false)
  1120. {
  1121.   
  1122.   //
  1123.   // set up gr_dir and gr_auto_dir
  1124.   //
  1125.   char *tmp = getenv("SC_GR_DIR");
  1126.   if (tmp == NULL) {
  1127.     // use the current working directory
  1128.     char buf[256];
  1129.     getcwd(buf, 256);
  1130.     gr_dir.assign(buf);
  1131.     gr_dir.append("/globalregs");
  1132.   } else {
  1133.     gr_dir.assign(tmp);
  1134.     // remove trailing slash if needed
  1135.     std::string::iterator back = gr_dir.end()-1;
  1136.     if (*back == '/') gr_dir.erase(back);
  1137.   }
  1138.   if (!check_file_access(gr_dir.c_str(), 1,1,1,1,1)) {
  1139.     // need to have something; revert to current dir
  1140.     char current[PATH_MAX];
  1141.     getcwd (current, PATH_MAX);
  1142.     gr_dir.assign (current);
  1143.     cerr << "Reverting to current dir (" << gr_dir.c_str()
  1144.  << ") for globalregs" << endl;
  1145.   }
  1146.   
  1147.   SHOW(gr_dir.c_str());
  1148.   cyber_raw_name = getenv("SC_RAW_DUMP");
  1149. }
  1150. GlobalReg::~GlobalReg(void)
  1151. {
  1152.   // delete the mapEntries
  1153.   // recall they are there twice, delete only once!
  1154.   FOR_MAP_ENTRIES(key, data) {
  1155.     if (key == data->xfa) delete data;
  1156.   } END_FOR_MAP
  1157. }
  1158. void
  1159. GlobalReg::initial_import(void)
  1160. {
  1161.   if (!initial_import_done) {
  1162.     gr_auto_dir.assign(gr_dir);
  1163.     gr_auto_dir.append("/auto");
  1164.     if (!check_file_access(gr_auto_dir.c_str(), 1,1,1,1,1)) {
  1165.       cerr << "Creating autoreg directory " 
  1166.    << gr_auto_dir.c_str() << endl;
  1167.       portable_mkdir (gr_auto_dir.c_str(), 00775);
  1168.     }
  1169.     perform_import();
  1170.     initial_import_done = true;
  1171.   }
  1172. }
  1173. void
  1174. GlobalReg::perform_import(void)
  1175. {
  1176.   cerr << "Importing *.gr... " << flush;
  1177.   int nTotal = 0, nYes = 0;
  1178.   int nTotalAuto = 0, nYesAuto = 0;
  1179.   for (DirEntries de_auto(gr_auto_dir, ".gr");
  1180.        !de_auto.done(); de_auto.next()) {
  1181.     ++nTotalAuto;
  1182.     if (import(de_auto.path()))
  1183.       ++nYesAuto;
  1184.   }
  1185.   int nQuality = mapEntry::qual_Good + 1;
  1186.   assert (nQuality == 4);
  1187.   int quality_bucket[4] = {0};
  1188.   mapEntry* entry;
  1189.   for (DirEntries de(gr_dir, ".gr"); !de.done(); de.next()) {
  1190.     ++nTotal;
  1191.     if (entry = import(de.path(),true)) {
  1192.       ++nYes;
  1193.       ++quality_bucket[entry->getQuality()];
  1194.     }
  1195.   }
  1196.   cerr << "imported " << nYesAuto << " / " << nTotalAuto << " auto; "
  1197.        << nYes << " / " << nTotal << " manual."
  1198.        << endl;
  1199.   cerr << "Quality distribution: ";
  1200.   for (int i = 0; i < nQuality; i++) {
  1201.     cerr << quality_bucket[i];
  1202.     if (i < nQuality - 1) cerr << " / ";
  1203.   }
  1204.   cerr << endl << "done." << endl;
  1205. }
  1206. GlobalReg::mapEntry*
  1207. GlobalReg::addPair(TbObj *a, TbObj *b, 
  1208.    const vector<Pnt3> &ap, const vector<Pnt3> &nrma,
  1209.    const vector<Pnt3> &bp, const vector<Pnt3> &nrmb,
  1210.    Xform<float> rel_xf,
  1211.    bool manually_aligned,
  1212.    int  max_pairs,
  1213.    bool save, int saveQual)
  1214. {
  1215.   assert(ap.size() == bp.size());
  1216.   // delete previous instance
  1217.   deletePair(a,b, save);
  1218.   // create a mapEntry
  1219.   mapEntry *me = new mapEntry(a,b,ap,bp,rel_xf,max_pairs);
  1220.   me->manually_aligned = manually_aligned;
  1221.   me->quality_grade = saveQual;
  1222.   calcPairwiseRmsErr(ap,nrma,bp,nrmb,rel_xf,
  1223.      me->pw_point_rmsErr,
  1224.      me->pw_plane_rmsErr);
  1225.   // add it twice
  1226.   hmm.insert(HMM::value_type(a,me));
  1227.   hmm.insert(HMM::value_type(b,me));
  1228.   // add to set
  1229.   all_scans.insert(a);
  1230.   all_scans.insert(b);
  1231.   dirty_scans.insert(a);
  1232.   dirty_scans.insert(b);
  1233.   // Compute errors, results stored 
  1234.   me->stats();
  1235.   if (save) me->export_to_file(gr_dir);
  1236.   if (cyber_raw_name) me->export_cyber_raw(cyber_raw_name);
  1237.   return me;
  1238. }
  1239. GlobalReg::mapEntry*
  1240. GlobalReg::addPair(TbObj *a, TbObj *b, 
  1241.    const vector<Pnt3> &ap,
  1242.    const vector<Pnt3> &bp,
  1243.    float pw_point_rmsErr,
  1244.    float pw_plane_rmsErr,
  1245.    Xform<float> rel_xf,
  1246.    bool manually_aligned,
  1247.    int  max_pairs,
  1248.    bool save, int saveQual)
  1249. {
  1250.   assert(ap.size() == bp.size());
  1251.   // delete previous instance
  1252.   deletePair(a,b, save);
  1253.   // create a mapEntry
  1254.   mapEntry *me = new mapEntry(a,b,ap,bp,rel_xf,max_pairs);
  1255.   me->manually_aligned = manually_aligned;
  1256.   me->quality_grade = saveQual;
  1257.   me->pw_point_rmsErr = pw_point_rmsErr;
  1258.   me->pw_plane_rmsErr = pw_plane_rmsErr;
  1259.   // add it twice
  1260.   hmm.insert(HMM::value_type(a,me));
  1261.   hmm.insert(HMM::value_type(b,me));
  1262.   // add to set
  1263.   all_scans.insert(a);
  1264.   all_scans.insert(b);
  1265.   dirty_scans.insert(a);
  1266.   dirty_scans.insert(b);
  1267.   // Compute errors, results stored 
  1268.   me->stats();
  1269.   if (save) me->export_to_file(gr_dir);
  1270.   if (cyber_raw_name) me->export_cyber_raw(cyber_raw_name);
  1271.   return me;
  1272. }
  1273. bool
  1274. GlobalReg::markPairQuality (TbObj *a, TbObj* b, int saveQual)
  1275. {
  1276.   FOR_MATCHING_KEYS(a, data) {
  1277.     if (data->xfa == b || data->xfb == b) {
  1278.       data->quality_grade = saveQual;
  1279.       data->export_to_file(gr_dir);
  1280.       return true;
  1281.     }
  1282.   } END_FOR_KEYS;
  1283.   return false;
  1284. }
  1285. void
  1286. GlobalReg::deletePair(TbObj *a, TbObj *b, bool deleteFile)
  1287. {
  1288.   // erase twice, delete once
  1289.   FOR_MATCHING_KEYS(a, data) {
  1290.     if (data->xfa == b || data->xfb == b) {
  1291.       hmm.erase(__i);
  1292.       break;
  1293.     }
  1294.   } END_FOR_KEYS;
  1295.   FOR_MATCHING_KEYS(b, data) {
  1296.     if (data->xfa == a || data->xfb == a) {
  1297.       hmm.erase(__i);
  1298.       delete data;
  1299.       break;
  1300.     }
  1301.   } END_FOR_KEYS;
  1302.   // if the transforms are not there, remove from set
  1303.   if (hmm.end() == hmm.find(a)) {
  1304.     all_scans.erase(a);
  1305.     dirty_scans.erase(a);
  1306.   } else {
  1307.     dirty_scans.insert(a);
  1308.   }
  1309.   if (hmm.end() == hmm.find(b)) {
  1310.     all_scans.erase(b);
  1311.     dirty_scans.erase(b);
  1312.   } else {
  1313.     dirty_scans.insert(b);
  1314.   }
  1315.   // delete the corresponding files
  1316.   if (deleteFile) unlink_gr_files(a,b);
  1317. }
  1318. void
  1319. GlobalReg::deleteAllPairs (TbObj *a, bool deleteFile)
  1320. {
  1321.   bool again;
  1322.   do {
  1323.     again = false;
  1324.     // deletion invalidates existing iterators, so don't go 
  1325.     // through the
  1326.     // FOR_MATCHING_KEYS loop more than once; exit it and restart.
  1327.     FOR_MATCHING_KEYS (a, data) {
  1328.       // erase once
  1329.       hmm.erase (__i);
  1330.       
  1331.       // possible delete the *.gr file
  1332.       if (deleteFile) unlink_gr_files(data->xfa, data->xfb);
  1333.       // erase twice
  1334.       TbObj* other = data->xfa;
  1335.       if (other == a)
  1336. other = data->xfb;
  1337.       bool foundit = false;
  1338.       FOR_MATCHING_KEYS (other, data2) {
  1339. if (data2->xfa == a || data2->xfb == a) {
  1340.   assert (data2 == data);
  1341.   hmm.erase (__i);
  1342.   foundit = true;
  1343.   break;
  1344. }
  1345.       } END_FOR_KEYS;
  1346.       assert (foundit);
  1347.       
  1348.       // delete once
  1349.       delete data;
  1350.       // then reset the iterator
  1351.       again = true;
  1352.       break;
  1353.     } END_FOR_KEYS;
  1354.   } while (again);
  1355.   assert (hmm.end() == hmm.find(a));
  1356.   all_scans.erase (a);
  1357.   cerr << "Nuked all pairs for " << nameFromTbObj (a) << endl;
  1358. }
  1359. void
  1360. GlobalReg::deleteAutoPairs (float thr, TbObj *a)
  1361. {
  1362.   bool again;
  1363.   int  cnt = 0;
  1364.   do {
  1365.     again = false;
  1366.     // deletion invalidates existing iterators, so don't go 
  1367.     // through the
  1368.     // FOR_MAP_ENTRIES loop more than once; exit it and restart.
  1369.     FOR_MAP_ENTRIES (key, data) {
  1370.       if (a != NULL && data->xfa != a && data->xfb != a) continue;
  1371.       if (!data->manually_aligned &&
  1372.   data->pw_plane_rmsErr > thr) {
  1373. cnt++;
  1374. deletePair(data->xfa, data->xfb, true);
  1375. // then reset the iterator
  1376. again = true;
  1377. break;
  1378.       }
  1379.     } END_FOR_MAP;
  1380.   } while (again);
  1381.   cerr << "Nuked " << cnt 
  1382.        << " auto pairs greater than " << thr << endl;
  1383. }
  1384. void 
  1385. GlobalReg::showPointpairCount(TbObj *a, TbObj *b)
  1386. {
  1387.   assert(a);
  1388.   if (b == NULL) {
  1389.     cout << endl << "From " 
  1390.  << nameFromTbObj(a) << " to" << endl;
  1391.     cout << "counttrmsErrtglobalErrtscan" << endl;
  1392.   }
  1393.   bool found = false;
  1394.   FOR_MATCHING_KEYS(a, data) {
  1395.     if (b == NULL) {
  1396.       cout << data->ptsa.size() << "t";
  1397.       cout << data->rmsErr << "t";
  1398.       cout << data->maxErr << "t";
  1399.       if (data->xfa == a) cout << nameFromTbObj(data->xfb);
  1400.       else                cout << nameFromTbObj(data->xfa);
  1401.       cout << endl;
  1402.       found = true;
  1403.     } else if (data->xfa == b || data->xfb == b) {
  1404.       cout << endl << data->ptsa.size() << "t";
  1405.       cout << data->rmsErr << "t";
  1406.       cout << data->maxErr << "t";
  1407.       cout << nameFromTbObj(a) << "t";
  1408.       cout << nameFromTbObj(b) << endl;
  1409.       found = true;
  1410.       break;
  1411.     }
  1412.   } END_FOR_KEYS;
  1413.   if (!found) {
  1414.     cout << "Couldn't find such pair!" << endl;
  1415.   }
  1416. }
  1417. bool
  1418. GlobalReg::pairRegistered (TbObj* a, TbObj* b,
  1419.    bool &manual,
  1420.    bool transitiveAllowed)
  1421. {
  1422.   FOR_MATCHING_KEYS(a, data) {
  1423.     if (data->xfa == a && data->xfb == b ||
  1424. data->xfb == a && data->xfa == b) {
  1425.       manual = data->manually_aligned;
  1426.       return true;
  1427.     }
  1428.   } END_FOR_KEYS;
  1429.   manual = false;
  1430.   if (transitiveAllowed) {
  1431.     // create a vector of the TbObj pointers
  1432.     vector<TbObj*> scan;
  1433.     int inda = -1, indb = -1;
  1434.     for (ITS is = all_scans.begin(); is!=all_scans.end(); is++) {
  1435.       if (*is == a)
  1436. inda = scan.size();
  1437.       if (*is == b)
  1438. indb = scan.size();
  1439.       scan.push_back(*is);
  1440.     }
  1441.     if (inda == -1 || indb == -1) {
  1442.       // one of the scans has no partners at all
  1443.       return false;
  1444.     }
  1445.     // find the connected components
  1446.     ConnComp cc(scan.size());
  1447.     FOR_MAP_ENTRIES(key, data) {
  1448.       if (key == data->xfb) continue;
  1449.       cc.connect(scan_idx(data->xfa, scan),
  1450.  scan_idx(data->xfb, scan));
  1451.     } END_FOR_MAP;
  1452.     // find connected component containing a
  1453.     vector<int> g;
  1454.     while (cc.get_next_group(g)) {
  1455.       // is a here?  if not, go to next group
  1456.       if (CONTAINS(g, inda))
  1457. continue;
  1458.       // this is a's group... is b here?
  1459.       if (CONTAINS(g, indb))
  1460. return true;  // b found in same group as a
  1461.       else
  1462. return false; // a's here but b's not
  1463.     }
  1464.     // only get here if we never found a
  1465.     cerr << "Internal error in "
  1466.  << "GlobalReg::pairRegistered(transitive)" << endl;
  1467.   }
  1468.   return false;
  1469. }
  1470. crope
  1471. GlobalReg::list_partners (TbObj* mesh, bool transitiveAllowed)
  1472. {
  1473.   crope response;
  1474.   if (!transitiveAllowed) {
  1475.     FOR_MATCHING_KEYS (mesh, data) {
  1476.       TbObj* other = data->xfa;
  1477.       if (other == mesh)
  1478. other = data->xfb;
  1479.       if (!response.empty())
  1480. response += crope (" ");
  1481.       response += nameFromTbObj(other);
  1482.     } END_FOR_KEYS;
  1483.   } else {
  1484.     // create a vector of the TbObj pointers
  1485.     vector<TbObj*> scan;
  1486.     int ind = -1;
  1487.     for (ITS is = all_scans.begin(); is!=all_scans.end(); is++) {
  1488.       if (*is == mesh)
  1489. ind = scan.size();
  1490.       scan.push_back(*is);
  1491.     }
  1492.     if (ind != -1) {
  1493.       // find the connected components
  1494.       ConnComp cc(scan.size());
  1495.       FOR_MAP_ENTRIES(key, data) {
  1496. if (key == data->xfb) continue;
  1497. cc.connect(scan_idx(data->xfa, scan),
  1498.    scan_idx(data->xfb, scan));
  1499.       } END_FOR_MAP;
  1500.       
  1501.       // find connected component containing a
  1502.       vector<int> g;
  1503.       while (cc.get_next_group(g)) {
  1504. // is a here?  if not, go to next group
  1505. if (CONTAINS(g, ind))
  1506.   continue;
  1507. // this is a's group... dump it
  1508. for (int i = 0; i < g.size(); i++) {
  1509.   if (!response.empty())
  1510.     response += crope (" ");
  1511.   response += nameFromTbObj(scan[g[i]]);
  1512. }
  1513. break;
  1514.       }
  1515.     }
  1516.   }
  1517.   return response;
  1518. }
  1519. int
  1520. GlobalReg::count_partners (TbObj* mesh)
  1521. {
  1522.   int partners = 0;
  1523.   FOR_MATCHING_KEYS (mesh, data) {
  1524.     ++partners;
  1525.   } END_FOR_KEYS;
  1526.   return partners;
  1527. }
  1528. void
  1529. GlobalReg::dump_connected_groups (void)
  1530. {
  1531.   // create a vector of the TbObj pointers
  1532.   vector<TbObj*> scan;
  1533.   for (ITS is = all_scans.begin(); is!=all_scans.end(); is++) {
  1534.     scan.push_back(*is);
  1535.   }
  1536.   
  1537.   // find the connected components
  1538.   ConnComp cc(scan.size());
  1539.   FOR_MAP_ENTRIES(key, data) {
  1540.     if (key == data->xfb) continue;
  1541.     cc.connect(scan_idx(data->xfa, scan),
  1542.        scan_idx(data->xfb, scan));
  1543.   } END_FOR_MAP;
  1544.   // dump contents of each group
  1545.   vector<int> g;
  1546.   int nGroups = 0;
  1547.   while (cc.get_next_group(g)) {
  1548.     if (g.size()) {
  1549.       cout << "group (" << g.size() << "): ";
  1550.       for (int* p = g.begin(); p != g.end(); p++)
  1551. cout << nameFromTbObj (scan[*p]) << " ";
  1552.       cout << endl;
  1553.       ++nGroups;
  1554.     }
  1555.   }
  1556.   cout << "(" << nGroups << ") total" << endl;
  1557. }
  1558. // the old version of align (no area-normalization)
  1559. void
  1560. GlobalReg::align(float _ftol,
  1561.  TbObj* scanToMove, TbObj* scanToMoveTo)
  1562. {
  1563.   ftol   = _ftol;
  1564.   if (scanToMove) {
  1565.     // just move one scan
  1566.     align_one_to_others (scanToMove, scanToMoveTo);
  1567.   } else {
  1568.     // align scans in connected groups
  1569.     // create a vector of the TbObj pointers
  1570.     vector<TbObj*> scan;
  1571.     for (ITS is = all_scans.begin(); is!=all_scans.end(); is++) {
  1572.       scan.push_back(*is);
  1573.     }
  1574.     // find the connected components
  1575.     ConnComp cc(scan.size());
  1576.     FOR_MAP_ENTRIES(key, data) {
  1577.       if (key == data->xfb) continue;
  1578.       cc.connect(scan_idx(data->xfa, scan),
  1579.  scan_idx(data->xfb, scan));
  1580.     } END_FOR_MAP;
  1581.     // for each connected component, align
  1582.     vector<int> g;
  1583.     vector<TbObj*> group;
  1584.     while (cc.get_next_group(g)) {
  1585.       if (g.size() > 1) {
  1586. group.clear();
  1587. for (int i=0; i<g.size(); i++)
  1588.   group.push_back(scan[g[i]]);
  1589. align_group(group);
  1590.       }
  1591.       if (BailDetector::bail()) {
  1592. cerr << "global alignment cancelled." << endl;
  1593. break;
  1594.       }
  1595.     }
  1596.     dirty_scans.erase(dirty_scans.begin(), dirty_scans.end());
  1597.   }
  1598. }
  1599. // NEW VERSION of align
  1600. // this align function will area-normalize (whereas
  1601. // the above fn that does not take a worldBbox won't)
  1602. // TODO: use worldBbox instead of re-computing
  1603. void
  1604. GlobalReg::align(float _ftol, Bbox worldBbox, 
  1605.  TbObj* scanToMove, TbObj* scanToMoveTo)
  1606. {
  1607.   ftol   = _ftol;
  1608.   normalize_samples(worldBbox, scanToMoveTo);
  1609.   if (scanToMove) {
  1610.     // just move one scan
  1611.     align_one_to_others (scanToMove, scanToMoveTo);
  1612.   } else {
  1613.     // align scans in connected groups
  1614.     // create a vector of the TbObj pointers
  1615.     vector<TbObj*> scan;
  1616.     for (ITS is = all_scans.begin(); is!=all_scans.end(); is++) {
  1617.       scan.push_back(*is);
  1618.     }
  1619.     // find the connected components
  1620.     ConnComp cc(scan.size());
  1621.     FOR_MAP_ENTRIES(key, data) {
  1622.       if (key == data->xfb) continue;
  1623.       cc.connect(scan_idx(data->xfa, scan),
  1624.  scan_idx(data->xfb, scan));
  1625.     } END_FOR_MAP;
  1626.     // for each connected component, align
  1627.     vector<int> g;
  1628.     vector<TbObj*> group;
  1629.     while (cc.get_next_group(g)) {
  1630.       if (g.size() > 1) {
  1631. group.clear();
  1632. for (int i=0; i<g.size(); i++)
  1633.   group.push_back(scan[g[i]]);
  1634. align_group(group);
  1635.       }
  1636.       if (BailDetector::bail()) {
  1637. cerr << "global alignment cancelled." << endl;
  1638. break;
  1639.       }
  1640.     }
  1641.     dirty_scans.erase(dirty_scans.begin(), dirty_scans.end());
  1642.   }
  1643. }
  1644. // normalize_samples goes through the map entries and throws
  1645. // out points based on a bucket structure that keeps track of
  1646. // how many points are already in the unit volume to which
  1647. // the new points belong.  only the set stored in scanToMoveTo
  1648. // in align(...) should be normalized in this way.
  1649. void GlobalReg::normalize_samples(Bbox worldBbox, TbObj *scanToMoveTo)
  1650. {
  1651.   VolumeBucket *vb;
  1652.   cerr << "initializing buckets...";
  1653.   int numBuckets = init_vol_buckets(&vb, worldBbox, scanToMoveTo,
  1654.     VB_SIZE);
  1655.   cerr << "done" << endl;
  1656.   vector<TbObj*> scans; // vectorized version of scanToMoveTo
  1657.   // check to see if we're aligning with one scan or all scans
  1658.   if (scanToMoveTo) {
  1659.     // we only have one scan - throw it in our scan vector
  1660.     scans.push_back(scanToMoveTo);
  1661.   } else { // sTMT == NULL means use all
  1662.     for (ITS is = all_scans.begin(); is!=all_scans.end(); is++) {
  1663.       scans.push_back(*is);
  1664.     }
  1665.   }
  1666.   // iterating thru our scan vector, interate thru the map to
  1667.   // find matching keys to the current scan we're considering
  1668.   // for each point in ptsa (don't check ptsb because corresponds),
  1669.   // - find which bucket it belongs to
  1670.   // - check that bucket.  
  1671.   // - if too full, delete points from a and b
  1672.   // - otherwise, throw the new points in the bucket
  1673.   int bucketInd;
  1674.   cerr << "iterating through points..." << scans.size() << " scans"
  1675.        << endl;
  1676.   for (int i = 0; i < scans.size(); i++) {
  1677.     // data is a mapEntry
  1678.     FOR_MATCHING_KEYS(scans[i], data) {
  1679.       vector<Pnt3>::iterator ip, ip2;
  1680.       ip = data->ptsa.begin();
  1681.       ip2 = data->ptsb.begin();
  1682.       for (int j = 0; j < data->ptsa.size(); j++) {
  1683. assert(ip != data->ptsa.end());
  1684. assert(ip2 != data->ptsb.end());
  1685. // changed
  1686. Pnt3 temp(data->ptsa[j]);
  1687. scans[i]->xformPnt(temp);
  1688. cerr << "pt: " << temp[0] << " " << temp[1] << " "
  1689.      << temp[2];
  1690. bucketInd = find_bucket(temp, vb, VB_SIZE, numBuckets);
  1691. if (bucketInd == NOT_FOUND) {
  1692.   temp.set((data->ptsb[j])[0],
  1693.    (data->ptsb[j])[1], (data->ptsb[j])[2]);
  1694.   scans[i]->xformPnt(temp);
  1695.   bucketInd = find_bucket(temp, vb, VB_SIZE, numBuckets);
  1696.   assert(bucketInd != NOT_FOUND);
  1697. }
  1698. //if (should_delete_point(data->ptsa[j], vb, bucketInd)) {
  1699. if (vb[bucketInd].points.size() > THRESHOLD) {
  1700.   
  1701.   data->ptsa.erase(ip);
  1702.   data->ptsb.erase(ip2);
  1703.   cerr << "...throwing out" << endl;
  1704. } else {
  1705.   vb[bucketInd].points.push_back(temp);
  1706.   //vb[bucketInd].points.push_back(data->ptsa[j]);
  1707.   //vb[bucketInd].points.push_back(data->ptsb[j]);
  1708.   cerr << "...keeping" << endl;
  1709. }
  1710. ip++; ip2++;
  1711.       } // for j
  1712.     } END_FOR_KEYS;
  1713.   } // for i
  1714.   cerr << "done" << endl;
  1715.   free(vb);
  1716. }
  1717. // linear time vector delete
  1718. // int k = 0;
  1719. //    for (vector<Pnt3>::iterator ip = data->ptsa.begin(); 
  1720. //         ip != data->ptsa.end(); ip++) {
  1721. //      cerr << "looping a..., k = " << k << ", j = "
  1722. //   << j << endl;
  1723. //      if (k == j) {
  1724. //        data->ptsa.erase(ip); break;
  1725. //      }
  1726. //      k++;
  1727. //    }
  1728. //    k = 0;
  1729. //    for (vector<Pnt3>::iterator ip2 = data->ptsb.begin(); 
  1730. //         ip2 != data->ptsb.end(); ip2++) {
  1731. //      cerr << "looping b..., k = " << k << ", j = "
  1732. //   << j << endl;
  1733. //      if (k == j) {
  1734. //        data->ptsb.erase(ip2); break;
  1735. //      }
  1736. //      k++;
  1737. //    }
  1738. bool GlobalReg::should_delete_point(Pnt3 pt, VolumeBucket *vb, 
  1739.     int bucketInd)
  1740. {
  1741.   if (vb[bucketInd].points.size() > THRESHOLD) return (true);
  1742.   // put poisson disk jitter here - efficient way to do this?
  1743.   // if we go thru all the points in the bucket, it will be
  1744.   // very slow...
  1745.   return (false);
  1746. // figure out how large the space is
  1747. // divide to make some number of buckets
  1748. // store all the min and max vars for those buckets
  1749. int GlobalReg::init_vol_buckets(VolumeBucket **vb, 
  1750. Bbox worldBbox, 
  1751. TbObj *scanToMoveTo, float bucket_side)
  1752. {
  1753.   Pnt3 min;
  1754.   Bbox bbox; // bbox around all the scans in scanToMoveTo
  1755.   if (scanToMoveTo) {
  1756.     bbox.add(scanToMoveTo->worldBbox());
  1757.   } else { // sTMT == NULL means use all
  1758.     for (ITS is = all_scans.begin(); is != all_scans.end(); is++) {
  1759.       TbObj *key = *is;
  1760.       bbox.add(key->worldBbox());
  1761.     }
  1762.   }
  1763.   min.set(bbox.min()[0], bbox.min()[1], bbox.min()[2]);
  1764.   Pnt3 dim = bbox.max() - min;
  1765.   dim /= bucket_side;
  1766.   Pnt3 xincr(bucket_side, 0, 0);
  1767.   Pnt3 yincr(0, bucket_side, 0);
  1768.   Pnt3 zincr(0, 0, bucket_side);
  1769.   
  1770.   int numBuckets = ceil(dim[0]) * ceil(dim[1]) * ceil(dim[2]);
  1771.   cerr << "Initializing " << numBuckets << " buckets...";
  1772.   *vb = new VolumeBucket[numBuckets];
  1773.   assert(*vb);
  1774.   Pnt3 vol_size(bucket_side, bucket_side, bucket_side);
  1775.   Pnt3 max;
  1776.   int cnt = 0;
  1777.   for (int i = 0; i < ceil(dim[0]); i++) {
  1778.     for (int j = 0; j < ceil(dim[1]); j++) {
  1779.       
  1780.       for (int k = 0; k < ceil(dim[2]); k++) {
  1781. max = min + vol_size;
  1782. ((*vb)[cnt]).volume = Bbox(min, max);
  1783. min += zincr;
  1784. cnt++;
  1785.       }
  1786.       min.set(min[0], min[1], bbox.min()[2]);
  1787.       min += yincr;
  1788.     }
  1789.     min.set(min[0], bbox.min()[1], min[2]);
  1790.     min += xincr;
  1791.   }
  1792.   assert(cnt == numBuckets);
  1793.   return (numBuckets);
  1794. }
  1795. // TODO: optimize so runs in constant time 
  1796. // (currently linear time)
  1797. int GlobalReg::find_bucket(Pnt3 pt, VolumeBucket *vb, 
  1798.    float bucket_side, int numBuckets)
  1799. {
  1800.   for (int i = 0; i < numBuckets; i++) {
  1801.     if (!vb[i].volume.outside(pt)) {
  1802.       return (i);
  1803.     }
  1804.   }
  1805.   return (NOT_FOUND);
  1806.   //return (1);
  1807. }
  1808. std::string
  1809. GlobalReg::dump_meshpairs (int   choice,
  1810.    float listThresh)
  1811. {
  1812.   vector<crope> names;
  1813.   vector<TbObj*> objs;
  1814.   for (DisplayableMesh** dm = theScene->meshSets.begin();
  1815.        dm < theScene->meshSets.end(); dm++) {
  1816.     if ((*dm)->getVisible()) {
  1817.       names.push_back ((*dm)->getName());
  1818.       objs.push_back ((*dm)->getMeshData());
  1819.     } else {
  1820.       cout << "Excluding invisible mesh " 
  1821.    << (*dm)->getName() << endl;
  1822.     }
  1823.   }
  1824.   int i, j;
  1825.   // write 2 digit numbers, horizontal row
  1826.   printf ("n%35s", "");
  1827.   for (i = 0; i < names.size(); i++) {
  1828.     printf (" %d ", i / 10);
  1829.   }
  1830.   printf ("n");
  1831.   printf ("%35s", "");
  1832.   for (i = 0; i < names.size(); i++) {
  1833.     printf (" %d ", i % 10);
  1834.   }
  1835.   printf ("nn");
  1836.   multimap<const float, int, greater<float> > sortedList;
  1837.   float pointError, planeError, globalError;
  1838.   bool  manual;
  1839.   for (i = 0; i < names.size(); i++) {
  1840.     printf ("%28s (%02d): ", names[i].c_str(), i);
  1841.     int nPartners = 0;
  1842.     for (j = 0; j < names.size(); j++) {
  1843.       char code[3];
  1844.       sprintf(code," -");
  1845.       bool paired = getPairError (objs[i], objs[j], 
  1846.   pointError,
  1847.   planeError,
  1848.   globalError,
  1849.   manual);
  1850.       float error;
  1851.       if      (choice == 0) error = pointError;
  1852.       else if (choice == 1) error = planeError;
  1853.       else                  error = globalError;
  1854.       if (paired) {
  1855. ++nPartners;
  1856. int i_err = int(error*10 + 0.5);
  1857. if (i_err > 99) i_err = 99;
  1858. sprintf(code,"%02d",i_err);
  1859. if (i > j)
  1860.   sortedList.insert(pair<const float, int>(error,
  1861.    i*65000+j));
  1862.       }
  1863.       // if we're at/past i, it's diagonal or upper right --
  1864.       // duplicates, don't print
  1865.       if (j == i)
  1866. sprintf(code," O");
  1867.       else if (j > i)
  1868. sprintf(code,"  ");
  1869.       if (paired && manual) printf ("%s.", code);
  1870.       else                  printf ("%s ", code);
  1871.     }
  1872.     printf ("(%d partners)n", nPartners);
  1873.   }
  1874.   printf ("n");
  1875.   printf ("Meshes and their unsorted pairwise errors:n");
  1876.   printf ("n");
  1877.   for (i = 0; i < names.size(); i++) {
  1878.     printf ("%28s:", names[i].c_str());
  1879.     for (j = 0; j < names.size(); j++) {
  1880.       bool paired = getPairError (objs[i], objs[j], 
  1881.   pointError,
  1882.   planeError,
  1883.   globalError,
  1884.   manual);
  1885.       float error;
  1886.       if      (choice == 0) error = pointError;
  1887.       else if (choice == 1) error = planeError;
  1888.       else                  error = globalError;
  1889.       if (paired) printf(" %1.2f", error);
  1890.     }
  1891.     printf ("n");
  1892.   }
  1893.   std::string ans;
  1894.   if (listThresh < FLT_MAX) {
  1895.      cout << endl << "List of worst offenders:" << endl;
  1896.      multimap<const float, int, greater<float> >::iterator it;
  1897.      for (it = sortedList.begin(); it != sortedList.end(); it++) {
  1898. float err = (*it).first;
  1899. if (err > listThresh) {
  1900.    unsigned int tricky_code = (*it).second;
  1901.    unsigned int i = tricky_code / 65000;
  1902.    unsigned int j = tricky_code % 65000;
  1903.    
  1904.    bool paired = getPairError (objs[i], objs[j], 
  1905.        pointError,
  1906.        planeError,
  1907.        globalError,
  1908.        manual);
  1909.    ans += names[i].c_str(); ans += " ";
  1910.    ans += names[j].c_str();
  1911.    if (manual) {
  1912.      printf("%s to %s: %g t(manual %f)n",
  1913.     names[i].c_str(), names[j].c_str(), 
  1914.     err, planeError);
  1915.      ans += " manual ";
  1916.    } else {
  1917.      printf("%s to %s: %g t(auto %f)n",
  1918.     names[i].c_str(), names[j].c_str(),
  1919.     err, planeError);
  1920.      ans += " auto ";
  1921.    }
  1922.    char str[256];
  1923.    sprintf(str, "%f ", err);
  1924.    ans += str;
  1925. } else {
  1926.    break;
  1927. }
  1928.      }
  1929.   }
  1930.   cout << endl;
  1931.   return ans;
  1932. }
  1933. static void
  1934. update_getPairingSummary_fields (GlobalReg::mapEntry* data,
  1935.  GlobalReg::ERRMETRIC metric,
  1936.  int count[3], float err[3], int qual[4])
  1937. {
  1938.   ++count[0];
  1939.   if (data->manually_aligned)
  1940.     ++count[1];
  1941.   else
  1942.     ++count[2];
  1943.   // choice of error metrics:
  1944.   // maxErr, avgErr, rmsErr, pw_point_rmsErr, pw_plane_rmsErr
  1945.   float errSrc;
  1946.   switch (metric) {
  1947.   case GlobalReg::errmetric_max: errSrc = data->maxErr;          break;
  1948.   case GlobalReg::errmetric_avg: errSrc = data->avgErr;          break;
  1949.   case GlobalReg::errmetric_rms: errSrc = data->rmsErr;          break;
  1950.   case GlobalReg::errmetric_pln: errSrc = data->pw_plane_rmsErr; break;
  1951.   default:  // this is the only one populated by a single icp
  1952.   case GlobalReg::errmetric_pnt: errSrc = data->pw_point_rmsErr; break;
  1953.   }
  1954.   err[0] = min (err[0], errSrc);
  1955.   err[1] += errSrc;
  1956.   err[2] = max (err[2], errSrc);
  1957.   
  1958.   ++qual[data->getQuality()];
  1959. }
  1960. bool
  1961. GlobalReg::getPairingSummary (TbObj* mesh, ERRMETRIC metric,
  1962.       int count[3], float err[3], int qual[4])
  1963. {
  1964.   count[0] = count[1] = count[2] = 0;
  1965.   qual[0] = qual[1] = qual[2] = qual[3] = 0;
  1966.   err[0] = 1e6; err[1] = err[2] = 0;
  1967.   if (mesh) {
  1968.     FOR_MATCHING_KEYS(mesh, data) {
  1969.       update_getPairingSummary_fields (data, metric, count, err, qual);
  1970.     } END_FOR_KEYS;
  1971.     
  1972.   } else {
  1973.     FOR_MAP_ENTRIES (mesh, data) {
  1974.       update_getPairingSummary_fields (data, metric, count, err, qual);
  1975.     } END_FOR_MAP;
  1976.   }
  1977.   if (count[0])
  1978.     err[1] /= count[0];
  1979.   else
  1980.     err[0] = 0;
  1981.   if (!mesh) { // don't double-count
  1982.     for (int i = 0; i < 3; i++) count[i] /= 2;
  1983.     for (i = 0; i < 4; i++) qual[i] /= 2;
  1984.   }
  1985.   
  1986.   return true;
  1987. }
  1988. bool
  1989. GlobalReg::getPairingStats (TbObj* from, TbObj* to,
  1990.     bool& bManual, int& iQuality,
  1991.     int& nPoints, time_t& date,
  1992.     float err[5])
  1993. {
  1994.   FOR_MATCHING_KEYS(from, data) {
  1995.     if (data->xfa == to || data->xfb == to) {
  1996.       bManual = data->manually_aligned;
  1997.       iQuality = data->getQuality();
  1998.       nPoints = data->ptsa.size();
  1999.       date = data->modifyDate;
  2000.       err[0] = data->maxErr;
  2001.       err[1] = data->avgErr;
  2002.       err[2] = data->rmsErr;
  2003.       err[3] = data->pw_point_rmsErr;
  2004.       err[4] = data->pw_plane_rmsErr;
  2005.       return true;
  2006.     }
  2007.   } END_FOR_KEYS;
  2008.   return false;
  2009. }
  2010. #ifdef MAIN_GR
  2011. #include "Random.h"
  2012. void
  2013. main(void)
  2014. {
  2015.   GlobalReg gr;
  2016.   int nviews = 10;
  2017.   vector<Xform<float> > xf(nviews);
  2018.   Random rnd;
  2019.   int i,j,k;
  2020.   // random initial transforms
  2021.   for (i=0; i<nviews; i++) {
  2022.     float fact = .5;
  2023.     xf[i].rotX((rnd()-.5)*M_PI*fact);
  2024.     xf[i].rotY((rnd()-.5)*M_PI*fact);
  2025.     xf[i].rotZ((rnd()-.5)*M_PI*fact);
  2026.     xf[i].translate((rnd()-.5)*fact, 
  2027.      (rnd()-.5)*fact, 
  2028.      (rnd()-.5)*fact);
  2029.   }
  2030.   vector<int> views;
  2031.   int ti;
  2032.   for (i=0; i<nviews; i++) {
  2033.     // pair each view randomly with 3 other views
  2034.     views.clear();
  2035.     views.push_back(i);
  2036.     for (j=0; j<3; j++) {
  2037.       do {
  2038. ti = nviews*rnd(); ti %= nviews;
  2039.       } while (CONTAINS(views,ti));
  2040.       views.push_back(ti);
  2041.     }
  2042.     // create 3000 random point pairs with each view pair
  2043.     vector<Pnt3> P(3000),Q(3000);
  2044.     for (j=1; j<4; j++) {
  2045.       for (k=0; k<3000; k++) {
  2046. // get a random point
  2047. Pnt3 p(rnd(), rnd(), rnd());
  2048. // store it in world coordinates according the
  2049. // current transformations
  2050. xf[views[0]].apply(p,P[k]);
  2051. xf[views[j]].apply(p,Q[k]);
  2052. // add some noise to points
  2053. P[k] += Pnt3(rnd()*.001-.0005,
  2054.      rnd()*.001-.0005,
  2055.      rnd()*.001-.0005);
  2056. Q[k] += Pnt3(rnd()*.001-.0005,
  2057.      rnd()*.001-.0005,
  2058.        rnd()*.001-.0005);
  2059.       }
  2060.       gr.addPair(&xf[i], &xf[views[j]], P, Q);
  2061.     }    
  2062.   }
  2063.   float ftol = 1.e-3;
  2064.   copy(xf.begin(), xf.end(), 
  2065.        ostream_iterator<Xform<float> >(cout, "n"));
  2066.   gr.align(ftol, alignHorn);
  2067.   copy(xf.begin(), xf.end(), 
  2068.        ostream_iterator<Xform<float> >(cout, "n"));
  2069. }
  2070. #endif // MAIN_GR