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

3D图形编程

开发平台:

Visual C++

  1. //////////////////////////////////////////////////////////////////////
  2. //
  3. // sczRegCmds.cc
  4. // Matt Ginzton, Kari Pulli
  5. // Fri Jun 12 15:19:16 PDT 1998
  6. // 
  7. // Interface between C and Tcl code for various registration UIs
  8. //   1.  Correspondence registration
  9. //   2.  Drag registration
  10. //   3.  Global registration
  11. //   4.  ICP
  12. //
  13. //////////////////////////////////////////////////////////////////////
  14. #include "plvGlobals.h"
  15. #include "ToglHash.h"
  16. #include "togl.h"
  17. #include "Trackball.h"
  18. #include "RigidScan.h"
  19. #include "plvMeshCmds.h"
  20. #include "plvDraw.h"
  21. #include "sczRegCmds.h"
  22. #include "plvAnalyze.h"
  23. #include "ColorUtils.h"
  24. #include "GlobalReg.h"
  25. #include "plvScene.h"
  26. #include "plvDrawCmds.h"
  27. #include "DisplayMesh.h"
  28. #include "absorient.h"
  29. #include "Random.h"
  30. #include "ToglCache.h"
  31. #include "ICP.h"
  32. #include "Progress.h"
  33. //////////////////////////////////////////////////////////////////////
  34. //
  35. // 1.  Correspondence-registration UI
  36. //
  37. //////////////////////////////////////////////////////////////////////
  38. static struct Togl* g_overviewTogl = NULL;
  39. static uchar colorNew[3] = { 0, 0, 0 };            // black
  40. static uchar colorOld[3] = { 255, 0, 0 };          // red
  41. static uchar colorSel[3] = { 0, 255, 0 };          // green
  42. static uchar colorHilite[3] = { 255, 255, 255 };   // white
  43. #define A_LITTLE_OUT_OF_THE_SCREEN  1e-6
  44. #define GLOBALREG_TOLERANCE         1.e-4
  45. class AlignmentInfo
  46. {
  47. public:
  48.   AlignmentInfo();
  49.   virtual ~AlignmentInfo();
  50.   Trackball* tb;
  51. };
  52. class AlignmentToglInfo: public AlignmentInfo
  53. {
  54. public:
  55.   void SetTargetMesh (DisplayableMesh* _md);
  56.   DisplayableMesh* meshDisplay;
  57.   RigidScan* meshData;
  58. };
  59. class CorrespondencePt
  60. {
  61. public:
  62.   DisplayableMesh* mesh;
  63.   Pnt3 pt;
  64. };
  65. class CorrespondenceList
  66. {
  67. public:
  68.   int AddPoint (DisplayableMesh* mesh, const Pnt3& pt);
  69.   CorrespondencePt* FindPoint (DisplayableMesh* mesh);
  70.   void DeletePoint (CorrespondencePt* cp);
  71.   void ToString (char* text);
  72.   int id;
  73.   uchar color[3];
  74.   vector <CorrespondencePt> points;
  75. };
  76. class AlignmentOverviewInfo: public AlignmentInfo
  77. {
  78. public:
  79.   AlignmentOverviewInfo (struct Togl* overviewTogl);
  80.   ~AlignmentOverviewInfo();
  81.   CorrespondenceList* AddCorrespondence (DisplayableMesh* mesh,
  82.  const Pnt3& pt);
  83.   CorrespondenceList* CompleteCorrespondence (bool bKeep, char* text);
  84.   vector<CorrespondenceList*> correspondences;
  85.   int GetSelectedCorrespondenceId();
  86.   CorrespondenceList* GetSelectedCorrespondence();
  87.   CorrespondenceList* GetCorrespondenceById (int id);
  88.   CorrespondenceList* GetCorrespondenceInProgress();
  89.   bool                 bColorPoints;
  90. private:
  91.   int                  nNextId;
  92.   CorrespondenceList*  correspInProgress;
  93.   ColorSet             correspColors;
  94.   struct Togl*         togl;
  95. };
  96. int 
  97. CorrespondenceList::AddPoint (DisplayableMesh* mesh, const Pnt3& pt)
  98. {
  99.   CorrespondencePt* cp = FindPoint (mesh);
  100.   if (cp != NULL) {
  101.     // already have one for this mesh -- adjust it
  102.     cp->pt = pt;
  103.   } else {
  104.     // create new correspondence for this mesh
  105.     CorrespondencePt cp;
  106.     cp.mesh = mesh;
  107.     cp.pt = pt;
  108.     points.push_back (cp);
  109.   }
  110.   return points.size();
  111. }
  112. CorrespondencePt* 
  113. CorrespondenceList::FindPoint (DisplayableMesh* mesh)
  114. {
  115.   for (CorrespondencePt* cp = points.begin(); cp < points.end(); cp++) {
  116.     if (cp->mesh == mesh)
  117.       return cp;
  118.   }
  119.   return NULL;
  120. }
  121. void 
  122. CorrespondenceList::DeletePoint (CorrespondencePt* cp)
  123. {
  124.   points.erase (cp);
  125. }
  126. void 
  127. CorrespondenceList::ToString (char* text)
  128. {
  129.   sprintf (text, "[%d]", id);
  130.   for (CorrespondencePt* cp = points.begin();
  131.        cp < points.end();
  132.        cp++) {
  133.     sprintf (text + strlen(text), " %s:(%.4g,%.4g,%.4g)",
  134.      cp->mesh->getName(),
  135.      cp->pt[0], cp->pt[1], cp->pt[2]);
  136.       
  137.     if (cp + 1 < points.end())
  138.       strcat (text, " <=>");
  139.   }
  140. }
  141. AlignmentInfo::AlignmentInfo()
  142. {
  143.   tb = NULL;
  144. }
  145. AlignmentInfo::~AlignmentInfo()
  146. {
  147.   if (tb != NULL)
  148.     delete tb;
  149. }
  150. AlignmentOverviewInfo::AlignmentOverviewInfo (struct Togl* overviewTogl)
  151. {
  152.   nNextId = 0;
  153.   correspInProgress = NULL;
  154.   togl = overviewTogl;
  155.   bColorPoints = true;
  156. }
  157. AlignmentOverviewInfo::~AlignmentOverviewInfo ()
  158. {
  159.   for (int i = 0; i < correspondences.size(); i++) {
  160.     delete correspondences[i];
  161.   }
  162.   g_overviewTogl = NULL;
  163. }
  164. CorrespondenceList* 
  165. AlignmentOverviewInfo::AddCorrespondence (DisplayableMesh* mesh, 
  166.   const Pnt3& pt)
  167. {
  168.   CorrespondenceList* clSelected = GetSelectedCorrespondence();
  169.   if (clSelected != NULL) {
  170.     clSelected->AddPoint (mesh, pt);
  171.     return clSelected;
  172.   }
  173.   if (correspInProgress == NULL) {
  174.     correspInProgress = new CorrespondenceList;
  175.     correspInProgress->id = 0;
  176.   }
  177.   correspInProgress->AddPoint (mesh, pt);
  178.   return correspInProgress;
  179. }
  180. CorrespondenceList* 
  181. AlignmentOverviewInfo::CompleteCorrespondence (bool bKeep, 
  182.        char* text)
  183. {
  184.   if (correspInProgress == NULL) {
  185.     strcpy (text, "[0]");
  186.     return NULL;     // nothing to do
  187.   }
  188.   if (correspInProgress->points.size() < 2)  // nothing to keep!
  189.     bKeep = false;
  190.   if (bKeep) {
  191.     correspInProgress->id = ++nNextId;
  192.     correspInProgress->ToString (text);
  193.     correspColors.chooseNewColor (correspInProgress->color);
  194.     correspondences.push_back (correspInProgress);
  195.     correspInProgress = NULL;
  196.     return correspondences.back();
  197.   } else {
  198.     correspInProgress->ToString (text);
  199.     delete correspInProgress;
  200.     correspInProgress = NULL;
  201.     return NULL;
  202.   }
  203. }
  204. CorrespondenceList* 
  205. AlignmentOverviewInfo::GetSelectedCorrespondence (void)
  206. {
  207.   return GetCorrespondenceById (GetSelectedCorrespondenceId());
  208. }
  209. CorrespondenceList*
  210. AlignmentOverviewInfo::GetCorrespondenceInProgress (void)
  211. {
  212.   return correspInProgress;
  213. }
  214. CorrespondenceList* 
  215. AlignmentOverviewInfo::GetCorrespondenceById (int id)
  216. {
  217.   if (id == 0)
  218.     return NULL;
  219.   CorrespondenceList** cl;
  220.   for (cl = correspondences.begin(); cl < correspondences.end(); cl++) {
  221.     if ((*cl)->id == id)
  222.       return *cl;
  223.   }
  224.   printf ("Consistency error in correspondence data structuresn");
  225.   return NULL;
  226. }
  227. int 
  228. AlignmentOverviewInfo::GetSelectedCorrespondenceId (void)
  229. {
  230.   Tcl_Interp* interp = Togl_Interp (togl);
  231.   // figure out which correspondence is selected
  232.   Tcl_Eval (interp, "getListboxSelection .reg.lines.list");
  233.   int iCorresp = 0;
  234.   if (strlen(interp->result) > 3)
  235.     iCorresp = atoi (interp->result + 1);
  236.   return iCorresp;
  237. }
  238. void 
  239. AlignmentToglInfo::SetTargetMesh (DisplayableMesh* _md)
  240. {
  241.   meshDisplay = _md;
  242.   if (meshDisplay == NULL) {
  243.     meshData = NULL;
  244.     return;
  245.   }
  246.   meshData = meshDisplay->getMeshData();
  247.   assert (meshData != NULL);
  248.   // set up trackball, rotate by current view of object...
  249.   Pnt3 up (0, 1, 0);
  250.   Pnt3 obj = meshData->localCenter();
  251.   float radius = meshData->radius();
  252.   Pnt3 camera (0, 0, radius * 3);
  253.     
  254.   //position camera in front of object
  255.   camera += obj;
  256.   tb->setup (camera, obj, up, radius);
  257.   // transform by rotations in effect: local, then viewer
  258.   Xform<float> xfr = meshData->getXform();
  259.   xfr.removeTranslation();
  260.   float q[4], t[3];
  261.   tbView->getXform (q, t);
  262.   xfr.rotQ (q[0], q[1], q[2], q[3]);
  263.   // and apply to trackball
  264.   xfr.toQuaternion (q);
  265.   tb->rotateQuat (q);
  266. }
  267. void
  268. DrawAlignmentPoint (const Pnt3& pt, uchar* color, bool bSelected = false)
  269. {
  270.   glDisable (GL_LIGHTING);
  271.   for (int iPass = 1; iPass >= 0; iPass--) {
  272.     //draw twice, once partially transparent without depth test
  273.     if (iPass == 0) {
  274.       glEnable (GL_DEPTH_TEST);
  275.       glDepthFunc (GL_LEQUAL);
  276.       glDisable (GL_BLEND);
  277.     } else {
  278.       glDisable (GL_DEPTH_TEST);
  279.       glEnable (GL_BLEND);
  280.       glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  281.     }
  282.     
  283.     if (bSelected && iPass == 1) {
  284.       glColor4ub (colorHilite[0], colorHilite[1], colorHilite[2], 255);
  285.       glPointSize (7);
  286.     } else {
  287.       glColor4ub (color[0], color[1], color[2], 256*(1-iPass/1.3));
  288.       if (bSelected)
  289. glPointSize (5);
  290.       else
  291. glPointSize (4);
  292.     }
  293.         
  294.     glBegin (GL_POINTS);
  295.     glVertex3fv (pt);
  296.     glEnd();
  297.   }
  298. }
  299. void
  300. DrawAlignmentPoints (struct Togl* togl)
  301. {
  302.   //warning: code that does not scale well with a huge number of
  303.   //correspondences, but that probably won't matter.  If it does,
  304.   //do something with better than linear performance here.
  305.   AlignmentOverviewInfo* aoi = NULL;
  306.   if (g_overviewTogl != NULL)
  307.     aoi = (AlignmentOverviewInfo*)Togl_GetClientData (g_overviewTogl);
  308.   if (aoi != NULL) {
  309.     AlignmentToglInfo* ati = (AlignmentToglInfo*)Togl_GetClientData (togl);
  310.     assert (ati != NULL);
  311.     if (ati->meshData != NULL) {
  312.       int iCorresp = aoi->GetSelectedCorrespondenceId();
  313.       // now draw all correspondences in correct color
  314.       for (int i = 0; i < aoi->correspondences.size(); i++) {
  315. CorrespondenceList* cl = aoi->correspondences[i];
  316. bool bSelected = (cl->id == iCorresp);
  317. for (CorrespondencePt* c = cl->points.begin();
  318.      c < cl->points.end();
  319.      c++) {
  320.   if (c->mesh == ati->meshDisplay) {
  321.     uchar* color;
  322.     if (aoi->bColorPoints)
  323.       color = cl->color;
  324.     else
  325.       color = bSelected ? colorSel : colorOld;
  326.     DrawAlignmentPoint (c->pt, color, bSelected);
  327.   }
  328. }
  329.       }
  330.     }
  331.     // now draw correspondence in progress
  332.     CorrespondenceList* cl = aoi->GetCorrespondenceInProgress();
  333.     if (cl != NULL) {
  334.       for (CorrespondencePt* c = cl->points.begin();
  335.    c < cl->points.end();
  336.    c++) {
  337. if (c->mesh == ati->meshDisplay)
  338.   DrawAlignmentPoint (c->pt, colorNew, true);
  339.       }
  340.     }
  341.   }
  342. }
  343. void
  344. DrawAlignmentMesh (struct Togl* togl)
  345. {
  346.   DrawAlignmentMeshToBack (togl);
  347.   DrawAlignmentPoints (togl);
  348.   Togl_SwapBuffers (togl);
  349. }
  350. void
  351. DrawAlignmentMeshToBack (struct Togl* togl)
  352. {
  353.   AlignmentToglInfo* ati = (AlignmentToglInfo*)Togl_GetClientData (togl);
  354.   assert (ati != NULL);
  355.   if (ati->meshData == NULL)
  356.     return;
  357.   // initialize buffers and modes
  358.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  359.   ati->tb->setSize (Togl_Width (togl), Togl_Height (togl));
  360.   glViewport(0, 0, Togl_Width (togl), Togl_Height (togl));
  361.   glEnable (GL_DEPTH_TEST);
  362.   glDepthFunc (GL_LESS);
  363.   // Prepare projection
  364.   ati->tb->applyProjection();
  365.   // set up lighting
  366.   glEnable(GL_LIGHTING);
  367.   glEnable(GL_LIGHT0);
  368.   glMatrixMode (GL_MODELVIEW);
  369.   glLoadIdentity();
  370.   float downZaxis[4] = { 0, 0, 1, 0 };
  371.   glLightfv(GL_LIGHT0, GL_POSITION, downZaxis);
  372.   // prepare modelview
  373.   ati->tb->applyXform();
  374.   // now render
  375.   ati->meshDisplay->drawImmediate();
  376. }
  377. void
  378. SpinToglTrackball (struct Togl* togl)
  379. {
  380.   AlignmentInfo* ai = (AlignmentInfo*)Togl_GetClientData (togl);
  381.   assert (ai != NULL);
  382.   if (ai->tb->isSpinning())
  383.   {
  384.     Togl_PostRedisplay (togl);
  385.   }
  386. }
  387. void
  388. FreeAlignmentInfo (struct Togl* togl)
  389. {
  390.   AlignmentInfo* ai = (AlignmentInfo*)Togl_GetClientData (togl);
  391.   assert (ai != NULL);
  392.   delete ai;
  393.   Togl_SetClientData (togl, NULL);
  394. }
  395. int
  396. PlvBindToglToAlignmentOverviewCmd(ClientData clientData, Tcl_Interp *interp, 
  397.   int argc, char *argv[])
  398. {
  399.   if (argc < 2) {
  400.     interp->result = "Bad arguments to PlvBindToglToAlignmentOverviewCmd";
  401.     return TCL_ERROR;
  402.   }
  403.   struct Togl* togl = toglHash.FindTogl (argv[1]);
  404.   if (togl == NULL) {
  405.     interp->result = "Missing togl widget in PlvBindToglToAlignmentViewCmd";
  406.     return TCL_ERROR;
  407.   }
  408.   assert (0 == strcmp (argv[1], Togl_Ident (togl)));
  409.   AlignmentOverviewInfo* aoi = new AlignmentOverviewInfo (togl);
  410.   aoi->tb = new Trackball;
  411.   Togl_SetClientData (togl, aoi);
  412.   Togl_SetDestroyFunc (togl, FreeAlignmentInfo);
  413.   Togl_SetTimerFunc (togl, SpinToglTrackball);
  414.   assert (g_overviewTogl == NULL);
  415.   g_overviewTogl = togl;
  416.   return TCL_OK;
  417. }
  418. int
  419. PlvCorrespRegParmsCmd(ClientData clientData, Tcl_Interp *interp, 
  420.       int argc, char *argv[])
  421. {
  422.   if (argc < 3) {
  423.     interp->result = "Bad arguments to PlvCorrespRegParmsCmd";
  424.     return TCL_ERROR;
  425.   }
  426.   struct Togl* togl = toglHash.FindTogl (argv[1]);
  427.   if (togl == NULL) {
  428.     interp->result = "Missing togl widget in PlvCorrespRegParmsCmd";
  429.     return TCL_ERROR;
  430.   }
  431.   AlignmentOverviewInfo* aoi =
  432.     (AlignmentOverviewInfo*)Togl_GetClientData (togl);
  433.   if (!strcmp (argv[2], "colorpoints")) {
  434.     if (argc > 2) {
  435.       aoi->bColorPoints = atoi (argv[3]);
  436.     } else {
  437.       interp->result = aoi->bColorPoints ? "1" : "0";
  438.     }
  439.   }
  440.   return TCL_OK;
  441. }
  442. int
  443. PlvBindToglToAlignmentViewCmd(ClientData clientData, Tcl_Interp *interp, 
  444.       int argc, char *argv[])
  445. {
  446.   if (argc < 3) {
  447.     interp->result = "Bad arguments to PlvBindToglToAlignmentViewCmd";
  448.     return TCL_ERROR;
  449.   }
  450.   struct Togl* togl = toglHash.FindTogl (argv[1]);
  451.   if (togl == NULL) {
  452.     interp->result = "Missing togl widget in PlvBindToglToAlignmentViewCmd";
  453.     return TCL_ERROR;
  454.   }
  455.   assert (0 == strcmp (argv[1], Togl_Ident (togl)));
  456.   DisplayableMesh* mesh = FindMeshDisplayInfo (argv[2]);
  457.   if (mesh == NULL && strcmp (argv[2], "")) {
  458.     interp->result = "Missing mesh in PlvBindToglToAlignmentViewCmd";
  459.     return TCL_ERROR;
  460.   }
  461.   //set that togl widget up to display the given mesh
  462.   AlignmentToglInfo* ati = (AlignmentToglInfo*)Togl_GetClientData (togl);
  463.   if (ati == NULL) {
  464.     ati = new AlignmentToglInfo;
  465.     ati->tb = new Trackball;
  466.     Togl_SetClientData (togl, ati);
  467.     Togl_SetDisplayFunc (togl, DrawAlignmentMesh);
  468.     Togl_SetDestroyFunc (togl, FreeAlignmentInfo);
  469.     Togl_SetTimerFunc (togl, SpinToglTrackball);
  470.   }
  471.   ati->SetTargetMesh (mesh);
  472.   Togl_PostRedisplay (togl);
  473.   return TCL_OK;
  474. }
  475. int
  476. PlvRegUIMouseCmd (ClientData clientData, Tcl_Interp *interp, 
  477.   int argc, char *argv[])
  478. {
  479.   // argument string: togl button x y time [start|stop]
  480.   if (argc < 6) {
  481.     interp->result = "Bad arguments to PlvRegUIMouseCmd";
  482.     return TCL_ERROR;
  483.   }
  484.   struct Togl* togl = toglHash.FindTogl (argv[1]);
  485.   if (togl == NULL) {
  486.     interp->result = "Missing togl widget in PlvRegUIMouseCmd";
  487.     return TCL_ERROR;
  488.   }
  489.   int button = atoi (argv[2]);
  490.   int mouseX = atoi (argv[3]);
  491.   int mouseY = atoi (argv[4]);
  492.   int eventT = atoi (argv[5]);
  493.   bool up = TRUE;
  494.   if (argc > 6 && !strcmp (argv[6], "start"))
  495.     up = FALSE;
  496.   AlignmentToglInfo* ati = (AlignmentToglInfo*)Togl_GetClientData (togl);
  497.   assert (ati != NULL);
  498.   
  499.   if (button == 0)
  500.     ati->tb->move (mouseX, mouseY, eventT);
  501.   else
  502.     ati->tb->pressButton (button, up, mouseX, mouseY, eventT);
  503.   Togl_PostRedisplay (togl);
  504.   return TCL_OK;
  505. }
  506. int
  507. PlvAddPartialRegCorrespondenceCmd (ClientData clientData, Tcl_Interp *interp, 
  508.    int argc, char *argv[])
  509. {
  510.   //argument string: togl overviewTogl x y
  511.   if (argc < 5) {
  512.     interp->result = "Bad arguments to PlvAddPartialRegCorrespondenceCmd";
  513.     return TCL_ERROR;
  514.   }
  515.   struct Togl* togl = toglHash.FindTogl (argv[1]);
  516.   struct Togl* toglOV = toglHash.FindTogl (argv[2]);
  517.   if (togl == NULL) {
  518.     interp->result = "Missing togl widget in PlvCreateRegCorrespondenceCmd";
  519.     return TCL_ERROR;
  520.   }
  521.   int x = atoi (argv[3]);
  522.   int y = Togl_Height (togl) - atoi (argv[4]);
  523.   AlignmentToglInfo* ati = (AlignmentToglInfo*)Togl_GetClientData (togl);
  524.   assert (ati != NULL);
  525.   AlignmentOverviewInfo* aoi =
  526.     (AlignmentOverviewInfo*)Togl_GetClientData (toglOV);
  527.   Pnt3 pt;
  528.   if (!findZBufferNeighborExt (x, y, pt, togl, ati->tb, 300)) {
  529.     // allow removal of one point from an existing correspondence,
  530.     // if it has more than two points
  531.     CorrespondenceList* clSelected = aoi->GetSelectedCorrespondence();
  532.     CorrespondencePt* cpOld = NULL;
  533.     if (clSelected != NULL) {
  534.       if (clSelected->points.size() > 2)
  535. cpOld = clSelected->FindPoint (ati->meshDisplay);
  536.       else
  537. printf ("Cannot delete last two points from correspondencen");
  538.     }
  539.     if (cpOld != NULL) { // prompt to delete point
  540.       Tcl_VarEval (interp, "tk_dialog .reg.confirm {Delete point?} "
  541.    "{Delete meshset ", 
  542.    ati->meshDisplay->getName(),
  543.    " from correspondence?} {} 0 No Yes", NULL);
  544.       if (atoi (interp->result) != 0) {
  545. clSelected->DeletePoint (cpOld);
  546. Tcl_Eval (interp, "rebuildSelectedCorrespondenceString");
  547. DrawAlignmentMesh (togl);
  548.       }
  549.     }
  550.     interp->result = "";
  551.     return TCL_OK;
  552.   }
  553.   // add to temporary correspondence set
  554.   CorrespondenceList* cl = aoi->AddCorrespondence (ati->meshDisplay, pt);
  555.   // if modifying existing corresp, tell tcl
  556.   if (cl->id != 0) {
  557.     Tcl_Eval (interp, "rebuildSelectedCorrespondenceString");
  558.   }
  559.   // draw new point hilited
  560.   DrawAlignmentMeshToBack (togl);
  561.   DrawAlignmentPoints (togl);
  562.   Togl_SwapBuffers (togl);
  563.   interp->result = (char*)ati->meshDisplay->getName();
  564.   return TCL_OK;
  565. }
  566. int
  567. PlvDeleteRegCorrespondenceCmd (ClientData clientData, Tcl_Interp *interp, 
  568.        int argc, char *argv[])
  569. {
  570.   if (argc != 3) {
  571.     interp->result = "Bad arguments to PlvDeleteRegCorrespondenceCmd";
  572.     return TCL_ERROR;
  573.   }
  574.   struct Togl* toglOV = toglHash.FindTogl (argv[1]);
  575.   if (!toglOV) {
  576.     interp->result = "Missing overview togl widget in DeleteRegCorrespondence";
  577.     return TCL_ERROR;
  578.   }
  579.   AlignmentOverviewInfo* aoi =
  580.     (AlignmentOverviewInfo*)Togl_GetClientData (toglOV);
  581.   assert (aoi != NULL);
  582.   int iCorresp = atoi (argv[2] + 1);  // in format [nnn] asdfasd
  583.   for (CorrespondenceList** cl = aoi->correspondences.begin();
  584.        cl < aoi->correspondences.end();
  585.        cl++) {
  586.     if ((*cl)->id == iCorresp) {
  587.       aoi->correspondences.erase (cl);
  588.       return TCL_OK;
  589.     }
  590.   }
  591.   interp->result = "Index not found in PlvDeleteRegCorrespondenceCmd";
  592.   return TCL_ERROR;
  593. }
  594. int
  595. PlvConfirmRegCorrespondenceCmd (ClientData clientData, Tcl_Interp *interp, 
  596. int argc, char *argv[])
  597. {
  598.   if (argc < 2) {
  599.     interp->result = "Bad arguments to PlvConfirmRegCorrespondenceCmd";
  600.     return TCL_ERROR;
  601.   }
  602.   struct Togl* toglOV = toglHash.FindTogl (argv[1]);
  603.   if (!toglOV) {
  604.     interp->result = "Missing overview togl widget in CreateRegCorrespondence";
  605.     return TCL_ERROR;
  606.   }
  607.   AlignmentOverviewInfo* aoi =
  608.     (AlignmentOverviewInfo*)Togl_GetClientData (toglOV);
  609.   assert (aoi != NULL);
  610.   bool bKeep = true;
  611.   if (argc > 2 && 0 == strcmp (argv[2], "delete"))
  612.     bKeep = false;
  613.   char text[2000];
  614.   CorrespondenceList* cl = aoi->CompleteCorrespondence (bKeep, text);
  615.   Tcl_SetResult (interp, text, TCL_VOLATILE);
  616.   return TCL_OK;
  617. }
  618. int
  619. PlvGetCorrespondenceInfoCmd (ClientData clientData, Tcl_Interp *interp, 
  620.      int argc, char *argv[])
  621. {
  622.   if (argc != 3) {
  623.     interp->result = "Bad arguments to PlvGetCorrespondenceInfoCmd";
  624.     return TCL_ERROR;
  625.   }
  626.   struct Togl* toglOV = toglHash.FindTogl (argv[1]);
  627.   if (toglOV == NULL) {
  628.     interp->result = "Missing overlay togl in PlvGetCorrespondenceInfoCmd";
  629.     return TCL_ERROR;
  630.   }
  631.   int idCorresp = atoi (argv[2]);
  632.   if (idCorresp == 0) {
  633.     interp->result = "Bad correspondence id in PlvGetCorrespondenceInfoCmd";
  634.     return TCL_ERROR;
  635.   }
  636.   AlignmentOverviewInfo* aoi =
  637.     (AlignmentOverviewInfo*)Togl_GetClientData (toglOV);
  638.   assert (aoi != NULL);
  639.   CorrespondenceList* cl = aoi->GetCorrespondenceById (idCorresp);
  640.   if (cl == NULL) {
  641.     interp->result = "Missing correspondence in PlvGetCorrespondenceInfoCmd";
  642.     return TCL_ERROR;
  643.   }
  644.   char text[2000];
  645.   cl->ToString (text);
  646.   Tcl_SetResult (interp, text, TCL_VOLATILE);
  647.   return TCL_OK;
  648. }
  649. static int CorrespRegOneMesh (AlignmentOverviewInfo* aoi,
  650.       DisplayableMesh* meshFrom,
  651.       DisplayableMesh* meshTo);
  652. static int CorrespRegAllToAll (AlignmentOverviewInfo* aoi);
  653. int
  654. PlvCorrespondenceRegistrationCmd (ClientData clientData, Tcl_Interp *interp, 
  655.   int argc, char *argv[])
  656. {
  657.   // arguments are: overviewTogl mode from to
  658.   // from and to are irrelevant for all2all mode, but must exist
  659.   if (argc != 5) {
  660.     interp->result = "Bad arguments to PlvCorrespondenceRegistrationCmd";
  661.     return TCL_ERROR;
  662.   }
  663.   // get correspondence list
  664.   struct Togl* toglOV = toglHash.FindTogl (argv[1]);
  665.   if (toglOV == NULL) {
  666.     interp->result = "Missing overview togl in PlvCorrespRegistrationCmd";
  667.     return TCL_ERROR;
  668.   }
  669.   AlignmentOverviewInfo* aoi = (AlignmentOverviewInfo*)
  670. Togl_GetClientData (toglOV);
  671.   assert (aoi != NULL);
  672.   // get mode
  673.   enum { from2to, from2all, all2all, error } mode = error;
  674.   if (!strcmp (argv[2], "from2to")) {
  675.     mode = from2to;
  676.   } else if (!strcmp (argv[2], "from2all")) {
  677.     mode = from2all;
  678.   } else if (!strcmp (argv[2], "all2all")) {
  679.     mode = all2all;
  680.   }
  681.   switch (mode) {
  682.   case all2all:
  683.     return CorrespRegAllToAll (aoi);
  684.   case from2to:
  685.   case from2all:
  686.     {
  687.       DisplayableMesh* meshFrom = FindMeshDisplayInfo (argv[3]);
  688.       if (!meshFrom) {
  689. interp->result = "Missing 'from' mesh in PlvCorrespRegistrationCmd";
  690. return TCL_ERROR;
  691.       }
  692.       if (mode == from2all)
  693. return CorrespRegOneMesh (aoi, meshFrom, NULL);
  694.       else {
  695. DisplayableMesh* meshTo = FindMeshDisplayInfo (argv[4]);
  696. if (!meshTo) {
  697.   interp->result = "Missing 'to' mesh in PlvCorrespRegistrationCmd";
  698.   return TCL_ERROR;
  699. }
  700. return CorrespRegOneMesh (aoi, meshFrom, meshTo);
  701.       }
  702.     }
  703.   }
  704.     
  705.   interp->result = "Bad mode passed to PlvCorrespRegistrationCmd";
  706.   return TCL_ERROR;
  707. }
  708. static int
  709. CorrespRegOneMesh (AlignmentOverviewInfo* aoi, DisplayableMesh* meshFrom,
  710.    DisplayableMesh* meshTo)
  711. {
  712.   // pass meshTo as NULL to use all correspondences involving meshFrom
  713.   // (from2all), or meshTo as a specific mesh to use only correspondences
  714.   // between meshFrom and meshTo (from2to).
  715.   RigidScan* msFrom = meshFrom->getMeshData();
  716.   RigidScan* msTo = meshTo->getMeshData();
  717.   // build lists of points from these meshes
  718.   // transform points to world coordinates
  719.   vector<Pnt3> srcPt, dstPt;
  720.   for (int i = 0; i < aoi->correspondences.size(); i++) {
  721.     CorrespondenceList* cl = aoi->correspondences[i];
  722.     CorrespondencePt* cpThis = cl->FindPoint (meshFrom);
  723.     if (cpThis != NULL) { // references this mesh
  724.       for (CorrespondencePt* cpOther = cl->points.begin();
  725.    cpOther < cl->points.end();
  726.    cpOther++) {
  727. // don't add us-us to list
  728. if (cpThis == cpOther)
  729.   continue;
  730. // and if from2to mode, only add corresp. involving To mesh
  731. if (meshTo != NULL && cpOther->mesh != meshTo)
  732.   continue;
  733. srcPt.push_back (cpThis->pt);
  734. cpThis->mesh->getMeshData()->xformPnt (srcPt.back());
  735. dstPt.push_back (cpOther->pt);
  736. cpOther->mesh->getMeshData()->xformPnt (dstPt.back());
  737.       }
  738.     }
  739.   }
  740.   double q[7];
  741.   horn_align (&srcPt[0], &dstPt[0], srcPt.size(), q);
  742.   Xform<float> xf = msFrom->getXform();
  743.   xf.addQuaternion (q, 7);
  744.   msFrom->setXform (xf);
  745.   theScene->computeBBox();
  746.   return TCL_OK;
  747. }
  748. static int
  749. CorrespRegAllToAll (AlignmentOverviewInfo* aoi)
  750. {
  751.   GlobalReg gr;
  752.   assert (aoi != NULL);
  753.   // for each pair of meshes, find all correspondences involving them
  754.   // and add pairs to globalreg gr
  755.   // so: iterate mesh pairs
  756.   int numSets = theScene->meshSets.size();
  757.   for (int iFrom = 0; iFrom < numSets; iFrom++) {
  758.     for (int iTo = iFrom + 1; iTo < numSets; iTo++) {
  759.       DisplayableMesh* mdFrom = theScene->meshSets[iFrom];
  760.       DisplayableMesh* mdTo = theScene->meshSets[iTo];
  761.       RigidScan* msFrom = mdFrom->getMeshData();
  762.       RigidScan* msTo = mdTo->getMeshData();
  763.       vector<Pnt3> pntFrom;
  764.       vector<Pnt3> pntTo;
  765.       // then iterate correspondences
  766.       for (int i = 0; i < aoi->correspondences.size(); i++) {
  767. CorrespondenceList* cl = aoi->correspondences[i];
  768. // if correspondence mentions both meshes currently under consideration
  769. CorrespondencePt* cpFrom = cl->FindPoint (mdFrom);
  770. CorrespondencePt* cpTo = cl->FindPoint (mdTo);
  771. if (cpFrom != NULL && cpTo != NULL) {
  772.   // then add points (in local coords) to pair data
  773.   pntFrom.push_back (cpFrom->pt);
  774.   pntTo.push_back (cpTo->pt);
  775. }
  776.       }
  777.       // now, if there were any correspondences between these meshes,
  778.       // add to globalreg
  779.       if (pntFrom.size() != 0) {
  780. gr.addPair(msFrom, msTo,
  781.    pntFrom, vector<Pnt3>(),
  782.    pntTo,   vector<Pnt3>());
  783. cout << pntFrom.size();
  784.       } else {
  785. cout << "no";
  786.       }
  787.       cout << " correspondences between "
  788.    << mdFrom->getName() << " and " << mdTo->getName()
  789.    << endl;
  790.     }
  791.   }
  792.   
  793.   gr.align (GLOBALREG_TOLERANCE, theScene->worldBbox());
  794.   theScene->computeBBox();
  795.   return TCL_OK;
  796. }
  797. //////////////////////////////////////////////////////////////////////
  798. //
  799. // 2nd method: drag-registration
  800. // UI and implementation follows
  801. //
  802. //////////////////////////////////////////////////////////////////////
  803. static void dragAlign (DisplayableMesh* mesh, AlignmentMethod method);
  804. int
  805. PlvDragRegisterCmd (ClientData clientData, Tcl_Interp *interp, 
  806.     int argc, char *argv[])
  807. {
  808.   // argument: name of mesh being registered (to all visible meshes)
  809.   if (argc < 2) {
  810.     interp->result = "Bad arguments to PlvDragRegisterCmd";
  811.     return TCL_ERROR;
  812.   }
  813.   DisplayableMesh* ms = FindMeshDisplayInfo (argv[1]);
  814.   if (ms == NULL) {
  815.     interp->result = "Missing meshset in PlvDragRegisterCmd";
  816.     return TCL_ERROR;
  817.   }
  818.   AlignmentMethod method = alignHorn;
  819.   if (argc > 2) {
  820.     if (       !strcmp (argv[2], "horn")) {
  821.       method = alignHorn;
  822.     } else if (!strcmp (argv[2], "chen")) {
  823.       method = alignChenMedioni;
  824.     }
  825.   }
  826.   dragAlign (ms, method);
  827.   DisplayCache::InvalidateToglCache (toglCurrent);
  828.   return TCL_OK;
  829. }
  830. #define ISBACKGROUND(x)  ((x)>=zBackground)
  831. class SceneBuf
  832. {
  833. public:
  834.   SceneBuf (int w, int h)
  835.     {
  836.       width = w;
  837.       height = h;
  838.       z = new unsigned int[width*height];
  839.       zBackground = 0xffffffff;
  840.       pt = new Pnt3*[w];
  841.       for (int x = 0; x < w; x++) {
  842. pt[x] = new Pnt3[h];
  843.       }
  844.     }
  845.   ~SceneBuf()
  846.     {
  847.       delete[] z;
  848.       for (int x = 0; x < width; x++) {
  849. delete[] pt[x];
  850.       }
  851.       delete[] pt;
  852.     }
  853.   unsigned int* z;
  854.   unsigned int zBackground;
  855.   Pnt3** pt;
  856.   int width, height;
  857. };
  858. // BUGBUG this next function is now very similar to ReadZBufferRect...
  859. // should merge code
  860. SceneBuf* 
  861. GetScenePoints (DisplayableMesh* meshWithout = NULL)
  862. {
  863.   // allocate buffer storage
  864.   Togl_MakeCurrent (toglCurrent);
  865.   int width = Togl_Width (toglCurrent);
  866.   int height = Togl_Height (toglCurrent);
  867.   
  868.   SceneBuf* sceneBuf = new SceneBuf (width, height);
  869.   // clear z-buffer to get background z-value
  870.   glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  871.   unsigned int zBackground;
  872.   glReadPixels (0, 0, 1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT,
  873. &zBackground);
  874.   sceneBuf->zBackground = zBackground;
  875.   // draw scene
  876.   if (meshWithout)
  877.     meshWithout->setVisible (false);
  878.   drawInToglBuffer (toglCurrent, GL_BACK);
  879.   if (meshWithout)
  880.     meshWithout->setVisible (true);
  881.   // and collect z-buffer
  882.   glReadBuffer (GL_BACK);
  883.   glReadPixels (0, 0, width, height, GL_DEPTH_COMPONENT,
  884. GL_UNSIGNED_INT, sceneBuf->z);
  885.   glMatrixMode (GL_MODELVIEW);
  886.   glPushMatrix();
  887.   glLoadIdentity ();
  888.   tbView->applyXform();
  889.   GLdouble model[16], proj[16];
  890.   glGetDoublev(GL_MODELVIEW_MATRIX, model);    // applied from trackball
  891.   glGetDoublev(GL_PROJECTION_MATRIX, proj);    // current GL state
  892.   glPopMatrix();
  893.   Xform<float> projMat = Xform<float>(proj) * Xform<float>(model);
  894.   projMat.invert();
  895.   for (int x = 0; x < width; x++) {
  896.     for (int y = 0; y < height; y++) {
  897.       int ofs = y*width + x;
  898.       if (!ISBACKGROUND (sceneBuf->z[ofs])) {
  899. float tx = (2. * x / width) - 1;
  900. float ty = (2. * y / height) - 1;
  901. float tz = (2. * sceneBuf->z[ofs] / (float)zBackground) - 1;
  902. sceneBuf->pt[x][y] = projMat.unproject (tx, ty, tz);
  903.       }
  904.       else
  905. sceneBuf->pt[x][y] = Pnt3(0.0);
  906.     }
  907.   }
  908.   return sceneBuf;
  909. }
  910. void
  911. GetMeshSceneOverlapPoints (DisplayableMesh* meshDisplay,
  912.    const SceneBuf& sceneBuf,
  913.    vector<Pnt3>& ptMesh,
  914.    vector<Pnt3>& ptScene,
  915.    vector<int>* ptSceneOfs)
  916. {
  917.   // already have rendering of scene without mesh
  918.   // render mesh alone, to back buffer and collect z information
  919.   // allocate buffer storage
  920.   Togl_MakeCurrent (toglCurrent);
  921.   int width = Togl_Width (toglCurrent);
  922.   int height = Togl_Height (toglCurrent);
  923.   
  924.   unsigned int* bufMesh = new unsigned int[width*height];
  925.   // now draw mesh alone
  926.   glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  927.   // but first, while buffer is clear, get background z-value
  928.   unsigned int zBackground;
  929.   glReadPixels (0, 0, 1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT,
  930. &zBackground);
  931.   glMatrixMode (GL_MODELVIEW);
  932.   glPushMatrix();
  933.   meshDisplay->getMeshData()->gl_xform();
  934.   meshDisplay->drawList();
  935.   glFinish();
  936.   glPopMatrix();
  937.   // and collect z-buffer
  938.   glReadPixels (0, 0, width, height, GL_DEPTH_COMPONENT,
  939. GL_UNSIGNED_INT, bufMesh);
  940.   glMatrixMode (GL_MODELVIEW);
  941.   glPushMatrix();
  942.   glLoadIdentity ();
  943.   tbView->applyXform();
  944.   GLdouble model[16], proj[16];
  945.   glGetDoublev(GL_MODELVIEW_MATRIX, model);    // applied from trackball
  946.   glGetDoublev(GL_PROJECTION_MATRIX, proj);    // current GL state
  947.   glPopMatrix();
  948.   Xform<float> projMat = Xform<float>(proj) * Xform<float>(model);
  949.   projMat.invert();
  950.   // iterate points that overlap, untransform and add to point lists
  951.   for (int x = 0; x < width; x++) {
  952.     for (int y = 0; y < height; y++) {
  953.       int ofs = y*width + x;
  954.       if (!ISBACKGROUND (sceneBuf.z[ofs]) &&
  955.   !ISBACKGROUND (bufMesh[ofs])) {
  956. // time to unproject
  957. float tx = (2. * x / width) - 1;
  958. float ty = (2. * y / height) - 1;
  959. float tz = (2. * bufMesh[ofs] / (float)zBackground) - 1;
  960. Pnt3 unproj = projMat.unproject (tx, ty, tz);
  961. ptScene.push_back (sceneBuf.pt[x][y]);
  962. if (ptSceneOfs != NULL)
  963.   ptSceneOfs->push_back (ofs);
  964. ptMesh.push_back (unproj);
  965. #if 0
  966. Pnt3 fast = projMat.unproject_fast (tx, ty, tz);
  967. SHOW (fast - unproj);
  968. #endif
  969. #if 0
  970. SHOW(ofs);
  971. SHOW(bufScene[ofs]);
  972. SHOW(bufMesh[ ofs]);
  973. SHOW(Pnt3(scenePos));
  974. SHOW(Pnt3( meshPos));
  975. #endif
  976.       }
  977.     }
  978.   }
  979.   printf ("Have %ld overlapping pointsn", ptScene.size());
  980.   delete[] bufMesh;
  981. }
  982. static void 
  983. calculateNormals (vector<Pnt3>& normals, SceneBuf* sceneBuf,
  984.   const vector<int>& sampPos)
  985. {
  986.   Pnt3 norm;
  987.   for (int i = 0; i < normals.size(); i++) {
  988.     // calculate and average cross product of all (possibly 8)
  989.     // triangles sharing this point and its neighbors
  990.     norm = 0.0;
  991.     // first, calculate ray from this point to each of its
  992.     // 8 neighbors
  993.     vector<Pnt3> rays;
  994.     rays.reserve (normals.size());
  995.     int ofs = sampPos[i];
  996.     int ptX = ofs % sceneBuf->width;
  997.     int ptY = ofs / sceneBuf->width;
  998.     for (int ix = -1; ix <= 1; ix++) {
  999.       for (int iy = -1; iy <= 1; iy++) {
  1000. if (ix == 0 && iy == 0) continue;
  1001. int x = ptX + ix; int y = ptY + iy;
  1002. int iofs = y * sceneBuf->width + x;
  1003. if (sceneBuf->z[iofs] >= sceneBuf->zBackground)
  1004.   continue; // no data at this point
  1005. rays.push_back (sceneBuf->pt[x][y] - 
  1006. sceneBuf->pt[ptX][ptY]);
  1007.       }
  1008.     }
  1009.     // now we have up to 8 rays from chosen point to its existing
  1010.     // neighbors
  1011.     // calculate cross products and add to norm
  1012.     for (int ray = 0; ray < rays.size(); ray++) {
  1013.       Pnt3 ray1 = rays[ray];
  1014.       Pnt3 ray2 = rays[(ray+1)%rays.size()];
  1015.       Pnt3 tn = (cross (ray1, ray2)).normalize();
  1016.       cout << "SubNormal " << ray << ":";
  1017.       SHOW (tn);
  1018.       norm += (cross (ray1, ray2)).normalize();
  1019.     }
  1020.     normals[i] = norm.normalize();
  1021.     SHOW(normals[i]);
  1022.   }
  1023. }
  1024. static void 
  1025. dragAlign (DisplayableMesh* mesh, AlignmentMethod method)
  1026. {
  1027.   const int nIterations = 20;
  1028.   const int nPtsPerIter = 8;
  1029.   RigidScan* scan = mesh->getMeshData();
  1030.   Xform<float> orig = scan->getXform();
  1031.   Xform<float> best = orig;
  1032.   float bestCost = -1;
  1033.   // restrict to small drawing area to speed up buffer reading
  1034.   int oldResCap = theResCap;
  1035.   theResCap = 100;
  1036.   // calculate minimum allowed mesh overlap, in pixels
  1037.   int minOverlap = (theResCap * theResCap) * 0.01; // 1% overlap minimum
  1038.   printf ("Starting drag alignment (%d iterations)n",
  1039.   nIterations);
  1040.   SceneBuf* sceneBuf = GetScenePoints (mesh);
  1041.   // establish initial correspondences
  1042.   vector<Pnt3> ptOrigMesh, ptOrigScene;
  1043.   vector<int> ptSceneOfs;
  1044.   GetMeshSceneOverlapPoints (mesh, *sceneBuf, 
  1045.      ptOrigMesh, ptOrigScene,
  1046.      method == alignChenMedioni
  1047.      ? &ptSceneOfs : NULL);
  1048.   for (int iter = 0; iter < nIterations; iter++) {
  1049.     vector<Pnt3> ptMesh, ptScene;
  1050.     // randomly choose 8 points from overlap region
  1051.     // and align using them
  1052.     vector<Pnt3> subPtMesh(nPtsPerIter), subPtScene(nPtsPerIter);
  1053.     vector<int> subSampPos(nPtsPerIter);
  1054.     for (int iPt = 0; iPt < nPtsPerIter; iPt++) {
  1055.       int iPos = drand48() * ptOrigMesh.size();
  1056.       subPtMesh[iPt] =  ptOrigMesh [iPos];
  1057.       subPtScene[iPt] = ptOrigScene[iPos];
  1058.       if (ptSceneOfs.size() > iPt)
  1059. subSampPos[iPt] = ptSceneOfs[iPos];
  1060.     }
  1061.     double q[7];
  1062.     Xform<float> current (orig);
  1063.     switch (method) {
  1064.     case alignChenMedioni: {
  1065.       vector<Pnt3> nrmScene (nPtsPerIter);
  1066.       calculateNormals (nrmScene, sceneBuf, subSampPos);
  1067.       chen_medioni (&subPtMesh[0], &subPtScene[0], &nrmScene[0],
  1068.     nPtsPerIter, q);
  1069.       }
  1070.       break;
  1071.     case alignHorn:
  1072.     default:
  1073.       horn_align (&subPtMesh[0], &subPtScene[0], nPtsPerIter, q);
  1074.     }
  1075.     current.addQuaternion (q, 7);
  1076.     // rerender using new transformation, to evaluate it
  1077.     scan->setXform (current);
  1078.     // this is unnecessary for algorithm, but looks neat:
  1079.     drawInToglBuffer (toglCurrent, GL_FRONT);
  1080.     GetMeshSceneOverlapPoints (mesh, *sceneBuf, ptMesh, ptScene,
  1081.        NULL);
  1082.     scan->setXform (orig);
  1083.     // if overlap is too small, reject this guess outright
  1084.     if (ptMesh.size() < minOverlap) {
  1085.       printf ("tOverlap region too small (%ld points)n", 
  1086.       ptMesh.size());
  1087.       continue;
  1088.     }
  1089.     // calc cost: average distance between corresponding points
  1090.     float cost = 0;
  1091.     for (int i = 0; i < ptMesh.size(); i++) {
  1092.       cost += dist (ptMesh[i], ptScene[i]);
  1093.     }
  1094.     cost /= ptMesh.size();
  1095. printf ("tCost for %ld points is %gn", ptMesh.size(), cost);
  1096.     // update best if this is better
  1097.     if (cost < bestCost || bestCost < 0) {
  1098.       best = current;
  1099.       bestCost = cost;
  1100.     }
  1101.   }
  1102.   // apply best transformation
  1103.   printf ("Best cost is %gn", bestCost);
  1104.   scan->setXform (best);
  1105.   theResCap = oldResCap;
  1106.   delete sceneBuf;
  1107. }
  1108. //////////////////////////////////////////////////////////////////
  1109. //
  1110. // 3rd method: global registration
  1111. // code and UI follows
  1112. //
  1113. //////////////////////////////////////////////////////////////////
  1114. int
  1115. PlvGlobalRegistrationCmd (ClientData clientData, Tcl_Interp *interp, 
  1116.   int argc, char *argv[])
  1117. {
  1118.   if (argc < 2) {
  1119.     interp->result = "Bad argument to PlvGlobalRegistrationCmd";
  1120.     return TCL_ERROR;
  1121.   }
  1122.   GlobalReg* gr = theScene->globalReg;
  1123.   assert (gr != NULL);
  1124.   if (       !strcmp (argv[1], "reset")) {
  1125.     delete gr;
  1126.     theScene->globalReg = new GlobalReg;
  1127.   } else if (!strcmp (argv[1], "init_import")) {
  1128.     gr->initial_import();
  1129.   } else if (!strcmp (argv[1], "re_import")) {
  1130.     gr->perform_import();
  1131.   } else if (!strcmp (argv[1], "register")) {
  1132.     if (argc < 3) {
  1133.       interp->result = "Bad argument to PlvGlobalRegistrationCmd";
  1134.       return TCL_ERROR;
  1135.     }
  1136.     TbObj* scanToMove = NULL;   // default to registering all scans
  1137.     TbObj* scanToMoveTo = NULL; // default to registering to all scans
  1138.     if (argc > 3) {
  1139.       DisplayableMesh* dm = FindMeshDisplayInfo (argv[3]);
  1140.       if (dm != NULL) {
  1141. scanToMove = dm->getMeshData();
  1142.       }
  1143.       if (scanToMove == NULL) {
  1144. cerr << "Scan " << argv[3] << " does not exist." << endl;
  1145. interp->result =
  1146.   "Bad mesh passed to GlobalReg 1->all align";
  1147. return TCL_ERROR;
  1148.       }
  1149.     }
  1150.     if (argc > 4) {
  1151.       DisplayableMesh* dm = FindMeshDisplayInfo (argv[4]);
  1152.       if (dm != NULL) {
  1153. scanToMoveTo = dm->getMeshData();
  1154.       }
  1155.       if (scanToMoveTo == NULL) {
  1156. cerr << "Scan " << argv[4] << " does not exist." << endl;
  1157. interp->result =
  1158.   "Bad mesh passed to GlobalReg 1->2 align";
  1159. return TCL_ERROR;
  1160.       }
  1161.     }
  1162.     // to put in code for normalizing, comment out this align call
  1163.     // and call the one below it
  1164.     gr->align (atof(argv[2]),
  1165.        scanToMove, scanToMoveTo);
  1166.     //gr->align (atof(argv[2]), theScene->worldBbox(),
  1167.     //       scanToMove, scanToMoveTo);
  1168.     theScene->computeBBox();
  1169.   } else if (!strcmp (argv[1], "pairstatus")) {
  1170.     if (argc < 4) {
  1171.       interp->result = "Bad # args";
  1172.       return TCL_ERROR;
  1173.     }
  1174.     DisplayableMesh* dm1 = FindMeshDisplayInfo (argv[2]);
  1175.     DisplayableMesh* dm2 = FindMeshDisplayInfo (argv[3]);
  1176.     if (!dm1 || !dm2) {
  1177.       //interp->result = "Bad mesh specified - sczRegCmds.cc:PlvGlobalRegistrationCmd pairstatus";
  1178.       //      rihan 7/9/01
  1179.       interp->result = "0";
  1180.     } else {
  1181.       bool bTrans = false;
  1182.       if (argc > 4 && !strcmp (argv[4], "transitive"))
  1183. bTrans = true;
  1184.       bool manual;
  1185.       bool reg = gr->pairRegistered (dm1->getMeshData(),
  1186.      dm2->getMeshData(),
  1187.      manual,
  1188.      bTrans);
  1189.       interp->result = reg ? "1" : "0";
  1190.     }
  1191.   } else if (!strcmp (argv[1], "listpairsfor")) {
  1192.     if (argc < 3) {
  1193.       interp->result = "Bad # args";
  1194.       return TCL_ERROR;
  1195.     }
  1196.     DisplayableMesh* dm = FindMeshDisplayInfo (argv[2]);
  1197.     if (!dm) {
  1198.       interp->result = "Bad mesh specified - sczRegCmds.cc:PlvGlobalRegistrationCmd listpairsfor";
  1199.       return TCL_ERROR;
  1200.     }
  1201.     
  1202.     bool bTrans = false;
  1203.     if (argc > 3 && !strcmp (argv[3], "transitive"))
  1204.       bTrans = true;
  1205.     crope partners = gr->list_partners(dm->getMeshData(), bTrans);
  1206.     Tcl_SetResult (interp, (char*)partners.c_str(), TCL_VOLATILE);
  1207.   } else if (!strcmp (argv[1], "dumpallpairs")) {
  1208.     std::string tcl_cmd;
  1209.     if (argc > 3) {
  1210.       float showThresh = atof(argv[3]);
  1211.       tcl_cmd = gr->dump_meshpairs(atoi(argv[2]),
  1212.     showThresh);
  1213.     } else {
  1214.       tcl_cmd = gr->dump_meshpairs(atoi(argv[2]));
  1215.     }
  1216.     Tcl_SetResult (interp, (char*) tcl_cmd.c_str(), TCL_VOLATILE);
  1217.   } else if (!strcmp (argv[1], "getpaircount")) {
  1218.     if (argc < 3) {
  1219.       interp->result = "bad # args";
  1220.       return TCL_ERROR;
  1221.     }
  1222.     DisplayableMesh* dm = FindMeshDisplayInfo (argv[2]);
  1223.     if (!dm) {
  1224.       interp->result = "Bad mesh specified - sczRegCmds.cc:PlvGlobalRegistrationCmd getpaircount";
  1225.       return TCL_ERROR;
  1226.     }
  1227.     int nPartners = gr->count_partners (dm->getMeshData());
  1228.     char buf[10];
  1229.     sprintf (buf, "%d", nPartners);
  1230.     Tcl_SetResult (interp, buf, TCL_VOLATILE);
  1231.   } else if (!strcmp (argv[1], "groupstatus")) {
  1232.     gr->dump_connected_groups();
  1233.   } else if (!strcmp (argv[1], "killpair")) {
  1234.     if (argc < 4) {
  1235.       interp->result =
  1236. "Bad args to PlvGlobalRegistrationCmd killpair";
  1237.       return TCL_ERROR;
  1238.     }
  1239.     DisplayableMesh* dm1 = FindMeshDisplayInfo (argv[2]);
  1240.     DisplayableMesh* dm2 = FindMeshDisplayInfo (argv[3]);
  1241.     // "mesh *" is allowed to leave dm2 NULL and delete 
  1242.     // all involving mesh
  1243.     if (!dm1 || (!dm2 && argv[3][0] != '*')) {
  1244.       interp->result = 
  1245. "Bad mesh in PlvGlobalRegistrationCmd killpair";
  1246.       return TCL_ERROR;
  1247.     }
  1248.     if (dm2)
  1249.       gr->deletePair (dm1->getMeshData(),
  1250.       dm2->getMeshData(), true);
  1251.     else
  1252.       gr->deleteAllPairs (dm1->getMeshData(), true);
  1253.   } else if (!strcmp (argv[1], "point_pair_count")) {
  1254.     if (argc < 4) {
  1255.       interp->result =
  1256. "Bad args to PlvGlobalRegistrationCmd point_pair_count";
  1257.       return TCL_ERROR;
  1258.     }
  1259.     DisplayableMesh* dm1 = FindMeshDisplayInfo (argv[2]);
  1260.     DisplayableMesh* dm2 = FindMeshDisplayInfo (argv[3]);
  1261.     // "mesh *" is allowed to leave dm2 NULL and deals with 
  1262.     // all involving meshes
  1263.     if (!dm1 || (!dm2 && argv[3][0] != '*')) {
  1264.       interp->result = 
  1265. "Bad mesh in PlvGlobalRegistrationCmd point_pair_count";
  1266.       return TCL_ERROR;
  1267.     }
  1268.     if (dm2)  gr->showPointpairCount(dm1->getMeshData(),
  1269.      dm2->getMeshData());
  1270.     else      gr->showPointpairCount(dm1->getMeshData());
  1271.   } else if (!strcmp (argv[1], "deleteautopairs")) {
  1272.     if (argc < 3 || argc > 4) {
  1273.       interp->result =
  1274. "Bad args to PlvGlobalRegistrationCmd deleteautopairs";
  1275.       return TCL_ERROR;
  1276.     }
  1277.     TbObj* tb = NULL;
  1278.     if (argc == 4) {
  1279.       DisplayableMesh* dm = FindMeshDisplayInfo (argv[3]);
  1280.       if (!dm) {
  1281. interp->result = 
  1282.   "Bad mesh in PlvGlobalRegistrationCmd deleteautopairs";
  1283. return TCL_ERROR;
  1284.       }
  1285.       tb = dm->getMeshData();
  1286.     }
  1287.     gr->deleteAutoPairs(atof(argv[2]), tb);
  1288.   } else if (!strcmp (argv[1], "getstats")) {
  1289.     DisplayableMesh *dm1 = NULL, *dm2 = NULL;
  1290.     if (argc > 3) {
  1291.       dm1 = FindMeshDisplayInfo (argv[2]);
  1292.       dm2 = FindMeshDisplayInfo (argv[3]);
  1293.     }
  1294.     if (!dm1 || !dm2) {
  1295.       interp->result = "Bad mesh passed to getstats";
  1296.       return TCL_ERROR;
  1297.     }
  1298.     int iQuality, nPoints;
  1299.     time_t date;
  1300.     bool bManual;
  1301.     float errs[5];
  1302.     if (!gr->getPairingStats (dm1->getMeshData(), dm2->getMeshData(),
  1303.       bManual, iQuality, nPoints, date, errs)) {
  1304.       interp->result = "Can't get stats for given mesh";
  1305.       return TCL_ERROR;
  1306.     }
  1307.     struct tm* pTime = localtime (&date);
  1308.     char szStats[200];
  1309.     sprintf (szStats, "%c %d %d %.3f %.3f %.3f %.3f %.3f %4d/%02d/%02d",
  1310.      bManual ? 'M' : 'A',
  1311.      iQuality, nPoints,
  1312.      errs[0], errs[1], errs[2], errs[3], errs[4],
  1313.      1900 + pTime->tm_year, 1 + pTime->tm_mon, pTime->tm_mday);
  1314.     Tcl_SetResult (interp, szStats, TCL_VOLATILE);
  1315.   } else if (!strcmp (argv[1], "getstatsummary")) {
  1316.     int qual[4];    // unknown/bad/fair/good
  1317.     float err[3];   // min/avg/max
  1318.     int count[3];   // total/man/auto
  1319.     DisplayableMesh* dm = NULL;
  1320.     if (argc > 2)
  1321.       dm = FindMeshDisplayInfo (argv[2]);
  1322.     if (!dm && 0 != strcmp (argv[2], "*")) {
  1323.       interp->result = "Bad mesh passed to getstatsummary";
  1324.       return TCL_ERROR;
  1325.     }
  1326.     TbObj* tb = dm ? dm->getMeshData() : NULL;
  1327.     // TODO
  1328.     GlobalReg::ERRMETRIC metric = GlobalReg::errmetric_pnt;
  1329.     if (!gr->getPairingSummary (tb, metric, count, err, qual)) {
  1330.       interp->result = "Can't get summary for given mesh";
  1331.       return TCL_ERROR;
  1332.     }
  1333.     char szStats[200];
  1334.     sprintf (szStats, "%d %d %d %.3f %.3f %.3f %d %d %d %d",
  1335.      count[0], count[1], count[2],
  1336.      err[0], err[1], err[2],
  1337.      qual[0], qual[1], qual[2], qual[3]);
  1338.     Tcl_SetResult (interp, szStats, TCL_VOLATILE);
  1339.   } else {
  1340.     interp->result = "Bad argument to PlvGlobalRegistrationCmd";
  1341.     return TCL_ERROR;
  1342.   }
  1343.   return TCL_OK;
  1344. }
  1345. //////////////////////////////////////////////////////////////////
  1346. //
  1347. // 4th method: ICP
  1348. // code and UI follows
  1349. //
  1350. //////////////////////////////////////////////////////////////////
  1351. ICP<RigidScan*> icp;
  1352. int
  1353. PlvRegIcpCmd(ClientData clientData, Tcl_Interp *interp, 
  1354.   int argc, char *argv[])
  1355. {
  1356.   if (argc != 14) {
  1357.     interp->result = "Usage: plv_icpregister n"
  1358.       "t<sampling density [0,1]>n"
  1359.       "t<normal-space sampling {0|1}>n"
  1360.       "t<number of iterations [1,20]>n"
  1361.       "t<culling percentage [0,99]>n"
  1362.       "t<no boundary targets {0|1}>n"
  1363.       "t<optimization method {point|plane}>n"
  1364.       "t<source mesh>n"
  1365.       "t<target mesh>n"
  1366.       "t<edge threshold kind {abs|rel}>n"
  1367.       "t<edge threshold value>n"
  1368.       "t<save results for globalreg {0|1}>n"
  1369.       "t<save at most n pairs [0,a_big_number]>n"
  1370.       "t<quality rating [0..3]>n";
  1371.     return TCL_ERROR;
  1372.   }
  1373.   DisplayableMesh *mdSrc = FindMeshDisplayInfo(argv[7]);
  1374.   DisplayableMesh *mdTrg = FindMeshDisplayInfo(argv[8]);
  1375.   assert(mdSrc && mdTrg);
  1376.   RigidScan* mSrc = mdSrc->getMeshData();
  1377.   RigidScan* mTrg = mdTrg->getMeshData();
  1378.   assert(mSrc && mTrg);
  1379.   // run the alignment
  1380.   icp.set(mSrc, mTrg);
  1381.   icp.allow_bdry = !atoi(argv[5]);
  1382.   float avgError = icp.align(atof(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4]),
  1383.      argv[6][1] == 'o', argv[9][0] == 'a',
  1384.      atof(argv[10]));
  1385.   // if requested, add pairs to globalreg
  1386.   bool bSaveForGlobal = atoi (argv[11]);
  1387.   if (bSaveForGlobal) {
  1388.     assert (theScene->globalReg != NULL);
  1389.     vector<Pnt3> ptSrc, ptTrg, nrmSrc, nrmTrg;
  1390.     icp.get_pairs_for_global (ptSrc, nrmSrc, ptTrg, nrmTrg);
  1391.     
  1392.     if (ptSrc.size() || ptTrg.size()) {
  1393.       cout << "Aligned pairs saved for global registration: "
  1394.    << mdSrc->getName() << " and " 
  1395.    << mdTrg->getName() << endl;
  1396.       int max_pairs = atoi(argv[12]);
  1397.       int quality = atoi(argv[13]);
  1398.       theScene->globalReg->addPair(mSrc, mTrg, ptSrc, nrmSrc,
  1399.    ptTrg, nrmTrg,
  1400.    mTrg->getXform().fast_invert() *
  1401.    mSrc->getXform(),
  1402.    true, max_pairs, true, quality);
  1403.     }
  1404.   }
  1405.   char szError[20];
  1406.   sprintf (szError, "%g", avgError);
  1407.   Tcl_SetResult (interp, szError, TCL_VOLATILE);
  1408.   return TCL_OK;
  1409. }
  1410. int
  1411. PlvRegIcpMarkQualityCmd(ClientData clientData, Tcl_Interp *interp, 
  1412. int argc, char *argv[])
  1413. {
  1414.   if (argc != 4) {
  1415.     interp->result = "Bad args to PlvRegIcpMarkQualityCmd";
  1416.     return TCL_ERROR;
  1417.   }
  1418.   DisplayableMesh *mdSrc = FindMeshDisplayInfo(argv[1]);
  1419.   DisplayableMesh *mdTrg = FindMeshDisplayInfo(argv[2]);
  1420.   assert(mdSrc && mdTrg);
  1421.   RigidScan* mSrc = mdSrc->getMeshData();
  1422.   RigidScan* mTrg = mdTrg->getMeshData();
  1423.   assert(mSrc && mTrg);
  1424.   int quality = atoi (argv[3]);
  1425.   if (quality < 0 || quality > 3) {
  1426.     interp->result = "Quality out of range in PlvRegIcpMarkQualityCmd";
  1427.     return TCL_ERROR;
  1428.   }
  1429.   if (!theScene->globalReg->markPairQuality (mSrc, mTrg, quality)) {
  1430.     interp->result = "General failure in PlvRegIcpMarkQualityCmd";
  1431.     return TCL_ERROR;
  1432.   }
  1433.   return TCL_OK;
  1434. }
  1435. int
  1436. PlvShowIcpLinesCmd(ClientData clientData, Tcl_Interp *interp, 
  1437.   int argc, char *argv[])
  1438. {
  1439.   if (argc < 2) {
  1440.     interp->result = "Bad arguments to PlvShowIcpLinesCmd";
  1441.     return TCL_ERROR;
  1442.   }
  1443.   bool show = atoi (argv[1]);
  1444.   if (show)
  1445.     icp.show_lines();
  1446.   else
  1447.     icp.hide_lines();
  1448.   return TCL_OK;
  1449. }
  1450. int
  1451. SczAutoRegisterCmd(ClientData clientData, Tcl_Interp *interp, 
  1452.       int argc, char *argv[])
  1453. {
  1454.   if (argc < 7) {
  1455.     interp->result = "Usage: scz_auto_register n"
  1456.       "t[visible | current] [visible | all] [name_of_curr_mesh] "
  1457.       "[error_thresh] [nTargetPairs] [bPreserveExisting] [bNormSSample]n";
  1458.     return TCL_ERROR;
  1459.   }
  1460.   // pair with visible/all meshes
  1461.   bool bFromVisible = !strcmp("visible", argv[1]);
  1462.   bool bToVisible   = !strcmp("visible", argv[2]);
  1463.   // error threshold
  1464.   float final_error_thresh = atof(argv[4]);
  1465.   
  1466.   if (final_error_thresh <= 0) {
  1467.     interp->result = "Error threshold has to be positive!n";
  1468.     return TCL_ERROR;
  1469.   }
  1470.   // target number of pairs to yield from alignment
  1471.   int nTargetPairs = atoi (argv[5]);
  1472.   if (nTargetPairs <= 0)
  1473.     nTargetPairs = 1000;
  1474.   // overwrite existing correspondences, or ignore meshes that
  1475.   // are already  paired?
  1476.   bool bOverwrite = !atoi (argv[6]);
  1477.   bool bNormSSample = atoi(argv[7]);
  1478.   // ctor
  1479.   AutoICP<RigidScan*> auto_align (theScene->globalReg,
  1480.   final_error_thresh);
  1481.   vector<DisplayableMesh*>& scans = theScene->meshSets;
  1482.   cout << "Calculating pairs:" << endl << endl;
  1483.   DisplayableMesh *currMesh = FindMeshDisplayInfo (argv[3]);
  1484.   if (!currMesh) {
  1485.     interp->result =
  1486.       "Couldn't find the current mesh!";
  1487.     return TCL_ERROR;
  1488.   }
  1489.   DisplayableMesh** begin = scans.begin();
  1490.   DisplayableMesh** end = scans.end();
  1491.   DisplayableMesh** first, ** second;
  1492.   GlobalReg *gr = theScene->globalReg;
  1493.   int cnt = 0;
  1494.   for (first = begin; first != end; first++) {
  1495.     if (( bFromVisible && (*first)->getVisible()) ||
  1496. (!bFromVisible && *first == currMesh)) {
  1497.       for (second = begin; second != end; second++) {
  1498. if (first == second) continue;
  1499. if (bToVisible && !(*second)->getVisible()) continue;
  1500. if (bFromVisible && (*second)->getVisible() &&
  1501.     second < first) continue;
  1502. RigidScan* rs1 = (*first)->getMeshData();
  1503. RigidScan* rs2 = (*second)->getMeshData();
  1504. bool manual;
  1505. if (gr->pairRegistered(rs1, rs2, manual)) {
  1506.   if (manual)      continue;
  1507.   if (!bOverwrite) continue;
  1508. }
  1509. if (rs1->num_vertices() == 0 || 
  1510.     rs2->num_vertices() == 0) { 
  1511.   continue;
  1512. }
  1513. cnt++;
  1514.       }
  1515.     }
  1516.   }
  1517.   bool bBail = false;
  1518.   Progress progress (cnt, "Calculating pairs");
  1519.   for (first = begin; first != end; first++) {
  1520.     if (( bFromVisible && (*first)->getVisible()) ||
  1521. (!bFromVisible && *first == currMesh)) {
  1522.       for (second = begin; second != end; second++) {
  1523. if (first == second) continue;
  1524. if (bToVisible && !(*second)->getVisible()) continue;
  1525. if (bFromVisible && (*second)->getVisible() &&
  1526.     second < first) continue;
  1527. RigidScan* rs1 = (*first)->getMeshData();
  1528. RigidScan* rs2 = (*second)->getMeshData();
  1529. // are these meshes already registered?
  1530. // never override a manually registered pair...
  1531. bool manual;
  1532. if (theScene->globalReg->pairRegistered(rs1, rs2,
  1533. manual)) {
  1534.   if (manual) {
  1535.     cerr << "Don't override manual alignment for "
  1536.  << (*first)->getName()
  1537.  << " and " << (*second)->getName() << endl;
  1538.     continue;
  1539.   }
  1540.   if (!bOverwrite) {
  1541.     cerr << "Already paired: " << (*first)->getName()
  1542.  << " and " << (*second)->getName() << endl;
  1543.     continue;
  1544.   }
  1545. }
  1546. //
  1547. // ok, passes all tests... register
  1548. //
  1549. // TODO: set threshold based on mesh resolutions
  1550. if (rs1->num_vertices() == 0 || 
  1551.     rs2->num_vertices() == 0) { 
  1552.   cout << "Skipping empty scan" << endl;
  1553.   continue;
  1554. }
  1555. if (!progress.updateInc()) {
  1556.   cerr << "Warning: cancelled; "
  1557.        << "not all scan pairs considered." << endl;
  1558.   bBail = true;
  1559.   break;
  1560. }
  1561. // ok, try to align
  1562. cout << "Trying " << (*first)->getName() << " and " 
  1563.      << (*second)->getName() << endl;
  1564. // normal-space sample: bNormSSample
  1565. if (auto_align.add_pair (rs1, rs2, nTargetPairs, bNormSSample)) {
  1566.   cout << "Paired " << (*first)->getName()
  1567.        << " and " << (*second)->getName() << endl;
  1568. }
  1569.       }
  1570.     }
  1571.     
  1572.     if (bBail) break;
  1573.   }
  1574.   
  1575.   return TCL_OK;
  1576. }