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

3D图形编程

开发平台:

Visual C++

  1. #include <iostream.h>
  2. #include <fstream.h>
  3. #include <string>
  4. #ifdef WIN32
  5. # include "winGLdecs.h"
  6. #endif
  7. #include <GL/gl.h>
  8. #include <GL/glu.h>
  9. #include <tcl.h>
  10. #include "TclCmdUtils.h"
  11. #include "togl.h"
  12. #include "plvGlobals.h"
  13. #include "plvClipBoxCmds.h"
  14. #include "plvMeshCmds.h"
  15. #include "plvDrawCmds.h"
  16. #include "plvScene.h"
  17. #include "plvDraw.h"
  18. #include "DisplayMesh.h"
  19. #include "RigidScan.h"
  20. #include "VertexFilter.h"
  21. #include "plvAnalyze.h"
  22. #include "Progress.h"
  23. #include "GroupScan.h"
  24. #include "GenericScan.h"
  25. #include "RangeGrid.h"
  26. // public globals
  27. Selection theSel;
  28. // module globals
  29. static const int kHandleSize = 3;
  30. static bool bManipulatingSel = false;
  31. static bool bMoveEntire = false;
  32. static bool bChangeExisting = false;
  33. static int iChangeExisting = 0;
  34. static int iDelete = -1;
  35. Selection::Pt ptRelativeTo;
  36. static GLint olColor = -1;
  37. static GLint handleColor = -1;
  38. static GLint handleSelColor = -1;
  39. Selection::Selection (void)
  40. {
  41.   clear();
  42. }
  43. void Selection::clear (void)
  44. {
  45.   type = none;
  46.   pts.clear();
  47. }
  48. static void drawHandle (Selection::Pt pt, bool bSelected = false);
  49. static bool ptOnHandle (Selection::Pt pt, Selection::Pt handle);
  50. static bool ptOnLine (Selection::Pt pt,
  51.       Selection::Pt start, Selection::Pt end);
  52. static int findSelectionHandle (Selection::Pt pt, const Selection& sel);
  53. static int findSelectionLine (Selection::Pt pt, const Selection& sel);
  54. // static DisplayableMesh *
  55. // ClipGroupHelper (GroupScan *groupFrom, const VertexFilter &filter);
  56. static DisplayableMesh* Renamer (DisplayableMesh *mesh);
  57. int
  58. PlvClipToSelectionCmd(ClientData clientData, Tcl_Interp *interp, 
  59.       int argc, char *argv[])
  60. {
  61.   if (argc < 2) {
  62.     interp->result = "Bad args to PlvClipToSelectionCmd";
  63.     return TCL_ERROR;
  64.   }
  65.   DisplayableMesh* meshDisp = FindMeshDisplayInfo (argv[1]);
  66.   bool bClipInvisible = false;
  67.   bool bClipMulti = false;
  68.   bool bKeepInside = true;
  69.   bool bClipInPlace = false;
  70.   for (int i = 2; i < argc; i++) {
  71.     if (!strcmp (argv[i], "inside"))
  72.       bKeepInside = true;
  73.     else if (!strcmp (argv[i], "outside"))
  74.       bKeepInside = false;
  75.     else if (!strcmp (argv[i], "inplace"))
  76.       bClipInPlace = true;
  77.     else if (!strcmp (argv[i], "newmesh"))
  78.       bClipInPlace = false;
  79.     else if (!strcmp (argv[i], "sel"))
  80.       bClipMulti = false;
  81.     else if (!strcmp (argv[i], "vis")) {
  82.       bClipMulti = true; bClipInvisible = false;
  83.     } else if (!strcmp (argv[i], "all")) {
  84.       bClipMulti = bClipInvisible = true;
  85.     }
  86.   }
  87.   // build list of scans to clip
  88.   vector<DisplayableMesh*> clippees;
  89.   if (bClipMulti) {
  90.     // push all meshes with sufficient visibility
  91.     for (DisplayableMesh** pdm = theScene->meshSets.begin();
  92.  pdm != theScene->meshSets.end();
  93.  pdm++) {
  94.       if (bClipInvisible || (*pdm)->getVisible())
  95. clippees.push_back (*pdm);
  96.     }
  97.   } else {
  98.     // just use the given source mesh
  99.     clippees.push_back (meshDisp);
  100.   }
  101.   // now iterate and clip each clippee
  102.   bool bSuccess = true;
  103.   char* error = NULL;
  104.   Progress* progress = new Progress (clippees.size(), "Clipping scans", true);
  105.   cout << "Clipping " << clippees.size() << " scans..." << endl;
  106.   for (DisplayableMesh** clippee = clippees.begin();
  107.        clippee != clippees.end();
  108.        clippee++) {
  109.     DisplayableMesh* oldDisp = *clippee;
  110.     if (!oldDisp) {
  111.       cerr << "Attempt to clip nonexistent mesh!" << endl;
  112.       bSuccess = false;
  113.       continue;
  114.     }
  115.     RigidScan* meshFrom = oldDisp->getMeshData();
  116.     VertexFilter* filter = filterFromSelection (meshFrom, theSel);
  117.     if (!filter) {
  118.       error = "First you must select an area";
  119.       bSuccess = false;
  120.       break;
  121.     }
  122.     
  123.     if (!bKeepInside) {
  124.       filter->invert();
  125.     }
  126.     
  127.     if (bClipInPlace) {
  128.       // inplace mode -- no creating new mesh, just munge the existing one
  129.       // Do it by saving the mesh's name and then making a
  130.       // filtered copy of it.  Then delete the old one, rename
  131.       // the new one and add it.
  132.       cerr << "attempting a clip of mesh: " << meshFrom->get_name() << endl;
  133.       RigidScan* meshTo = meshFrom->filtered_copy(*filter);
  134.       GroupScan *groupResult = dynamic_cast<GroupScan*>(meshTo);
  135.       if (meshTo) {
  136. if (meshTo->num_resolutions() > 0) {
  137.   char *name = strdup(meshFrom->get_name().c_str());
  138.   // get the old theMesh
  139.   char *theMeshOld = GetTclGlobal("theMesh");
  140.   
  141.   char tclCmdBuff[256];
  142.   sprintf(tclCmdBuff, "confirmDeleteMesh %s", oldDisp->getName());
  143.   if (Tcl_Eval (interp, tclCmdBuff) != TCL_OK)
  144.     cerr << "confirmDelete failed " << endl;
  145.   
  146.   
  147.   DisplayableMesh* newDisp;
  148.   if(!groupResult) {
  149.     meshTo->set_name(name);
  150.     newDisp = theScene->addMeshSet (meshTo, false);
  151.   } else {     
  152.     // clipping a group in place means that we need to 
  153.     // rename the group and all its members using 
  154.     // the Renamer routine.
  155.        
  156.     newDisp = FindMeshDisplayInfo(meshTo);
  157.   
  158.     newDisp = Renamer(newDisp);
  159.   }
  160.   
  161.   sprintf(tclCmdBuff, "clipInplaceHelper %s %s", newDisp->getName(), 
  162.   theMeshOld);
  163.   Tcl_Eval (interp, tclCmdBuff);
  164.   
  165.   free(name);
  166.   
  167. } else {
  168.   // scan supports clipping, but had no data
  169.      
  170.   Tcl_VarEval (interp, "changeVis ", oldDisp->getName(), " 0", NULL);
  171. }
  172.       } else {
  173. // scan doesn't know how to clip
  174. cerr << "Scan " << meshTo->get_name()
  175.      << " failed filtered_inplace" << endl;
  176. bSuccess = false;
  177.       }
  178.       
  179.     } else {
  180.       // newmesh mode... makes a new mesh and adds it to Mesh Controls
  181.       // filtered_copy will return NULL if not supported; will return
  182.       // valid pointer to scan with no resolutions if the clip excludes
  183.       // all data.
  184.       RigidScan* meshTo = meshFrom->filtered_copy(*filter);
  185.       
  186.       if (meshTo) {
  187. if (meshTo->num_resolutions() > 0) {
  188.   // set name, same as old with clip appended before extension
  189.   GroupScan *group = dynamic_cast<GroupScan*>(meshTo);
  190.   if (!group) {
  191.     crope name = meshFrom->get_basename()
  192.       + "Clip." + meshFrom->get_nameending();
  193.     meshTo->set_name(name);
  194.     
  195.     DisplayableMesh* newDisp = theScene->addMeshSet (meshTo, false);
  196.     Tcl_VarEval (interp, "clipMeshCreateHelper ",
  197.  oldDisp->getName(), " ", newDisp->getName(), NULL);
  198.   } else { 
  199.     // since it is a group, it has already been named + added to the scene
  200.     Tcl_VarEval (interp, "clipMeshCreateHelper ",
  201.  oldDisp->getName(), " ", 
  202.  FindMeshDisplayInfo(meshTo)->getName(), NULL);
  203.   }
  204. } else {
  205.   // scan supports clipping, but had no data
  206.   Tcl_VarEval (interp, "changeVis ", oldDisp->getName(), " 0", NULL);
  207. }
  208.       } else {
  209. // scan doesn't know how to clip
  210. cerr << "Scan " << meshFrom->get_name()
  211.      << " failed filtered_copy" << endl;
  212. bSuccess = false;
  213.       }
  214.     }
  215.     delete filter;
  216.     // update progress; check for cancel
  217.     if (!progress->updateInc()) {
  218.       cerr << "Clip operation cancelled (" 
  219.    << (clippee - clippees.begin() + 1)
  220.    << " down; " << (clippees.end() - clippee - 1)
  221.    << " to go)" << endl;
  222.       break;
  223.     }
  224.   }
  225.   delete progress;
  226.   theScene->computeBBox();
  227.   if (bSuccess)
  228.     return TCL_OK;
  229.   if (error)
  230.     interp->result = error;
  231.   else
  232.     interp->result = "At least one scan could not be clipped... "
  233.       "Perhaps it does not support filtered_copy or filter_inplace?";
  234.   return TCL_ERROR;
  235. }
  236. // This helper routine looks for the last instance
  237. // of "Clip" in haystack.
  238. // we are guaranteed that there is at least one "Clip"
  239. // in the string haystack since we just created
  240. // it as a filtered_copy.
  241. static char*
  242. my_clip_strrstr (char** haystack) 
  243. {
  244.   char *str = *haystack;
  245.   char *oldstr = str;
  246.   //cerr << "str initted to " << str << endl;
  247.   while ((str = strstr(oldstr+1, "Clip")) != NULL) {
  248.     oldstr = str;
  249.     //cerr << "Oldstr is " << oldstr << endl;
  250.   }
  251.   return oldstr;
  252. }
  253. // Clipping in place for groups works by creating a filtered
  254. // copy of the group and then renaming each member recursively.
  255. // We must delete it from the hashtable in theScene using its
  256. // old name and then add it back with the new name.
  257. // Also, theScene->meshSets (a vector) also maintains a list of
  258. // displayable meshes - but by renaming the displayable
  259. // mesh, we are ensuring that meshSets is in sync with the
  260. // hashtable which is crucial.
  261. // we have to rename both the displayable mesh and the rigid scan
  262. // The renaming takes place by finding the last occurrence of
  263. // "Clip" in the name and getting rid of it, so as to disguise
  264. // the clip as the original mesh.
  265. // (Due to complications with the hashtable/meshSets data
  266. // structures, the renaming must take place after the 
  267. // entire group has been created, not while it is being
  268. // built from its constituents).
  269. static DisplayableMesh * 
  270. Renamer (DisplayableMesh *mesh) {
  271.   vector<DisplayableMesh*>children;
  272.   vector<DisplayableMesh*>vec;
  273.   RigidScan *scan = mesh->getMeshData();
  274.   char oldname [256];
  275.   sprintf(oldname, "%s",  mesh->getMeshData()->get_basename().c_str());
  276.   char *tmp = oldname; // tmp is needed to convince compiler
  277.   *(my_clip_strrstr(&tmp)) = ''; // removes "Clip" from end of string
  278.   //cerr << "oldname is now " << oldname << endl;
  279.   crope newname;
  280.   newname = crope(oldname) + "." + mesh->getMeshData()->get_nameending();
  281.   char newbuf [PATH_MAX];
  282.   sprintf (newbuf, "%s", newname.c_str());
  283.   GroupScan *g = dynamic_cast<GroupScan*>(scan);
  284.   if (g) {
  285.     if (g->get_children_for_display(children)) {
  286.       ungroupScans(mesh);    
  287.       for (DisplayableMesh** it = children.begin(); it < children.end(); it++)
  288. vec.push_back(Renamer (*it)); // rename the descendants of the group first
  289.       mesh = groupScans(vec, newbuf, true);
  290.       return mesh;
  291.     }
  292.     return NULL; //ok as long as group has to have children
  293.   } else {
  294.     // rename rigid scan
  295.     mesh->getMeshData()->set_name(newname);
  296.     
  297.     // rename displayable mesh
  298.     char buf[PATH_MAX];
  299.     sprintf(buf, "%s",  mesh->getName());
  300.     char *tmp2 = buf;
  301.     *(my_clip_strrstr(&tmp2)) = ''; // removes "Clip" from end of string
  302.     MeshSetHashDelete(strdup(mesh->getName()));
  303.     mesh->setName(buf);
  304.     AddMeshSetToHash(mesh);
  305.     
  306.     return mesh;
  307.   }
  308. }
  309. // static DisplayableMesh *
  310. // ClipGroupHelper (GroupScan *groupFrom, const VertexFilter &filter)
  311. // {
  312. //   vector<DisplayableMesh*>newkids;
  313. //   char *oldGroupName = strdup(groupFrom->get_name().c_str());
  314. //   cerr << "Old group name " << oldGroupName << endl;
  315. //   VertexFilter *childfilter;
  316. //   DisplayableMesh *groupMeshTo, *clippedGroup;
  317.   
  318. //   vector<DisplayableMesh*>kids = 
  319. //     ungroupScans(FindMeshDisplayInfo(oldGroupName));
  320. //   for (DisplayableMesh** it = kids.begin(); it < kids.end(); it++) {
  321. //     RigidScan *from = (*it)->getMeshData();
  322. //     assert(from);
  323. //     GroupScan* g = dynamic_cast<GroupScan*>(from);
  324. //     childfilter = filter.transformedClone((float*)from->getXform());
  325. //     if (g) {
  326. //       clippedGroup = ClipGroupHelper (g, *childfilter);
  327. //       newkids.push_back(clippedGroup);
  328. //     } else {      
  329. //       RigidScan *to = from->filtered_copy(*childfilter, true);
  330. //       char *name = strdup(from->get_name().c_str());
  331. //       DisplayableMesh *disp = FindMeshDisplayInfo((*it)->getName());
  332. //       theScene->deleteMeshSet(disp);
  333. //       if (to) {
  334. //  if (to->num_resolutions() > 0) {
  335.   
  336. //    //   char *theMeshOld = "back1"; //GetTclGlobal("theMesh");
  337. //    to->set_name(name);
  338.   
  339. //    DisplayableMesh *newkid = theScene->addMeshSet(to,false);
  340.   
  341. //    newkids.push_back(newkid);
  342. //  }
  343. //       }
  344. //     }
  345. //   }
  346. //   groupMeshTo = groupScans (newkids, oldGroupName, true);
  347. //   return groupMeshTo;
  348. // }
  349. /* This function is called from interactors.tcl when the user
  350.    selects the Print Voxel Info command from the right-click
  351.    menu after specifying a rectangular box region 
  352.    - for display voxel feature */
  353. int PlvPrintVoxelsCmd(ClientData clientData, Tcl_Interp *interp, 
  354.      int argc, char *argv[])
  355. {
  356.   printf("Getting voxel information...n");
  357.   if (argc != 2) {
  358.     interp->result = "Bad args to PlvPrintVoxelsCmd";
  359.     return TCL_ERROR;
  360.   }
  361.   DisplayableMesh* meshDisp = FindMeshDisplayInfo (argv[1]);
  362.   if (meshDisp == NULL) {
  363.     interp->result = "Attempting to print voxels for non-existant mesh";
  364.     return (TCL_ERROR);
  365.   }
  366.   RigidScan* meshFrom = meshDisp->getMeshData();
  367.   if (meshFrom == NULL) {
  368.     interp->result = "PlvPrintVoxelsCmd: We don't have a mesh";
  369.     return (TCL_ERROR);
  370.   }
  371.   //GenericScan* gscanFrom = (GenericScan *) meshFrom;
  372.   GenericScan *gscanFrom = dynamic_cast<GenericScan*> (meshFrom);
  373.   if (!gscanFrom) {
  374.     interp->result = "Mesh is not a ply file";
  375.     return (TCL_ERROR);
  376.   }
  377.   VertexFilter* filter = filterFromSelection (gscanFrom, theSel);
  378.   // VertexFilter* filter = filterFromSelection (meshFrom, theSel);
  379.   if (!filter) {
  380.     interp->result = "First you must select an area";
  381.     return (TCL_ERROR);
  382.   }
  383.   RigidScan* meshTo = gscanFrom->filtered_copy(*filter);
  384.   //RigidScan* meshTo = meshFrom->filtered_copy(*filter);
  385.   GenericScan* gscanTo = (GenericScan *) meshTo;
  386.   if (meshTo->num_vertices() == 0) {
  387.     interp->result = "No vertices selected";
  388.     return (TCL_ERROR);
  389.   } else gscanTo->PrintVoxelInfo();
  390.   return (TCL_OK);
  391. }
  392. int
  393. PlvClearSelectionCmd(ClientData clientData, Tcl_Interp *interp, 
  394.      int argc, char *argv[])
  395. {
  396.   struct Togl* togl = toglHash.FindTogl (argv[1]);
  397.   assert (togl);
  398.   theSel.clear();
  399.   Togl_PostOverlayRedisplay (togl);
  400.   
  401.   return TCL_OK;
  402. }
  403. int
  404. PlvDrawLineSelectionCmd(ClientData clientData, Tcl_Interp *interp, 
  405. int argc, char *argv[])
  406. {
  407.   // args are %x %y start
  408.   if (argc < 4)
  409.     return TCL_ERROR;
  410.   Selection::Pt pt;
  411.   pt.x = atoi(argv[1]);
  412.   pt.y = theHeight - atoi(argv[2]);
  413.   if (!strcmp (argv[3], "start")) {
  414.     bChangeExisting = false;
  415.     bManipulatingSel = true;
  416.     bMoveEntire = false;
  417.     if (theSel.type == Selection::line) {
  418.       // attempt to find existing line
  419.       int iHandle = findSelectionHandle (pt, theSel);
  420.       if (iHandle >= 0) {
  421. // reuse pt that's not iHandle
  422. bChangeExisting = true;
  423. if (iHandle == 0)
  424.   theSel[0] = theSel[1];
  425. theSel[1] = pt;
  426.       } else if (ptOnLine (pt, theSel[0], theSel[1])) {
  427. bChangeExisting = true;
  428. bMoveEntire = true;
  429. ptRelativeTo = pt;
  430.       }
  431.     }
  432.     
  433.     if (!bChangeExisting)
  434.     {
  435.       // start new line
  436.       theSel.clear();
  437.       theSel.type = Selection::line;
  438.       theSel.pts.push_back (pt);
  439.       theSel.pts.push_back (pt);
  440.       ptRelativeTo.x = ptRelativeTo.y = 0;
  441.     }
  442.   } else if (!strcmp (argv[3], "stop")) {
  443.     bManipulatingSel = false;
  444.     if (theSel[0].x == theSel[1].x && theSel[0].y == theSel[1].y)
  445.       Tcl_Eval (Togl_Interp (toglCurrent), "clearSelection");
  446.   } else if (!strcmp (argv[3], "move")) {
  447.     if (theSel.type != Selection::line) {
  448.       interp->result = "Internal selection tracking error";
  449.       return TCL_ERROR;
  450.     }
  451.     if (bMoveEntire) {
  452.       theSel[0].x += pt.x - ptRelativeTo.x;
  453.       theSel[0].y += pt.y - ptRelativeTo.y;
  454.       theSel[1].x += pt.x - ptRelativeTo.x;
  455.       theSel[1].y += pt.y - ptRelativeTo.y;
  456.       ptRelativeTo = pt;
  457.     } else {
  458.       if (argc > 4 && !strcmp (argv[4], "constrain")) {
  459. int dx = abs (pt.x - theSel[0].x);
  460. int dy = abs (pt.y - theSel[0].y);
  461. if (dx > 2 * dy)   // strongly x-oriented -- x only
  462.   pt.y = theSel[0].y;
  463. else if (dy > 2 * dx) // strongly y-oriented -- y only
  464.   pt.x = theSel[0].x;
  465. else if (dx > dy)  // x dominates; 45 degree controlled by x
  466.   pt.y = theSel[0].y + dx * (pt.y > theSel[0].y ? 1 : -1);
  467. else  // 45 degree controlled by y
  468.   pt.x = theSel[0].x + dy * (pt.x > theSel[0].x ? 1 : -1);
  469.       }
  470.     theSel[1] = pt;
  471.     }
  472.   }
  473. #ifndef no_overlay_support
  474.   Togl_PostOverlayRedisplay (toglCurrent);
  475. #else
  476.   drawOverlayAndSwap(toglCurrent);
  477. #endif
  478.   return TCL_OK;
  479. }
  480. int
  481. PlvDrawShapeSelectionCmd(ClientData clientData, Tcl_Interp *interp, 
  482.  int argc, char *argv[])
  483. {
  484.   // args are %x %y start
  485.   if (argc < 4)
  486.     return TCL_ERROR;
  487.   Selection::Pt pt;
  488.   pt.x = atoi(argv[1]);
  489.   pt.y = theHeight - atoi(argv[2]);
  490.   if (!strcmp (argv[3], "start")) {
  491.     bChangeExisting = false;
  492.     bManipulatingSel = true;
  493.     bMoveEntire = false;
  494.     if (theSel.type == Selection::shape) {
  495.       // attempt to find existing polyline
  496.       int iHandle = findSelectionHandle (pt, theSel);
  497.       if (iHandle >= 0) {
  498. // reuse pt i
  499. bChangeExisting = true;
  500. iChangeExisting = iHandle;
  501.       } else {
  502. // not on a handle; look for a line
  503. if (findSelectionLine (pt, theSel) >= 0) {
  504.   bChangeExisting = true;
  505.   iChangeExisting = -1;
  506.   bMoveEntire = true;
  507.   ptRelativeTo = pt;
  508. }
  509.       }
  510.     }
  511.     
  512.     if (bChangeExisting) {
  513.       if (iChangeExisting >= 0)
  514. theSel[iChangeExisting] = pt;
  515.     } else {
  516.       if (theSel.type != Selection::shape) {
  517. // start new polyline
  518. theSel.clear();
  519. theSel.type = Selection::shape;
  520. theSel.pts.push_back (pt);
  521.       }
  522.       bChangeExisting = true;
  523.       iChangeExisting = theSel.pts.size();
  524.       theSel.pts.push_back (pt);
  525.       ptRelativeTo.x = ptRelativeTo.y = 0;
  526.     }
  527.   } else if (!strcmp (argv[3], "stop")) {
  528.     bManipulatingSel = false;
  529.   } else if (!strcmp (argv[3], "move")) {
  530.     if (theSel.type != Selection::shape) {
  531.       interp->result = "Internal selection tracking error";
  532.       return TCL_ERROR;
  533.     }
  534.     iDelete = -1;
  535.     if (bMoveEntire) {
  536.       for (int i = 0; i < theSel.pts.size(); i++) {
  537. theSel[i].x += pt.x - ptRelativeTo.x;
  538. theSel[i].y += pt.y - ptRelativeTo.y;
  539.       }
  540.       ptRelativeTo = pt;
  541.     } else if (bChangeExisting) {
  542.       theSel.pts[iChangeExisting] = pt;
  543.     }
  544.   } else if (!strcmp (argv[3], "modify")) {
  545.     // attempt to find existing polyline handle
  546.     if (theSel.type != Selection::shape) {
  547.       interp->result = "Internal selection tracking error";
  548.       return TCL_ERROR;
  549.     }
  550.     int nPts = theSel.pts.size();
  551.     bMoveEntire = false;
  552.     bChangeExisting = false;
  553.     // look for a point -- if found, start dragging it
  554.     int iHandle = findSelectionHandle (pt, theSel);
  555.     if (iHandle >= 0) {
  556.       bChangeExisting = true;
  557.       iChangeExisting = iDelete = iHandle;
  558.     } else {
  559.     // not on a point; look for a line to add a point
  560.       int iLine = findSelectionLine (pt, theSel);
  561.       if (iLine >= 0) {
  562. // insert new point between iLine and iLine+1
  563. iChangeExisting = iLine + 1;
  564. bChangeExisting = true;
  565. theSel.pts.insert (&theSel[iChangeExisting], pt);
  566.       }
  567.     }
  568.   } else if (!strcmp (argv[3], "remove")) {
  569.     // if this was a click and not a drag, remove selected pt
  570.     if (iDelete >= 0 && ptOnHandle (pt, theSel[iDelete])) {
  571.       theSel.pts.erase (&theSel[iDelete]);
  572.     }    
  573.   }
  574.  
  575. #ifndef no_overlay_support
  576.   Togl_PostOverlayRedisplay (toglCurrent);
  577. #else
  578.   drawOverlayAndSwap(toglCurrent); 
  579. #endif
  580.   return TCL_OK;
  581. }
  582. int
  583. PlvDrawBoxSelectionCmd(ClientData clientData, Tcl_Interp *interp, 
  584.        int argc, char *argv[])
  585. {
  586.   if (argc < 5)
  587.     return TCL_ERROR;
  588.   Selection::Pt pt;
  589.   pt.x = atoi(argv[2]);
  590.   pt.y = theHeight - atoi(argv[3]);
  591.   
  592.   struct Togl* togl = toglHash.FindTogl (argv[1]);
  593.   assert (togl);
  594.   // rect is stored as 4 points, corners, so that area selection
  595.   // iterators actually work with it
  596.   
  597.   if (argc > 4 && !strcmp (argv[4], "start")) {
  598.     bChangeExisting = false;
  599.     bManipulatingSel = true;
  600.     bMoveEntire = false;
  601.     // attempt to move existing points
  602.     if (theSel.type == Selection::rect) {
  603.       int iHandle = findSelectionHandle (pt, theSel);
  604.       if (iHandle >= 0) {
  605. // reuse pt iHandle
  606. bChangeExisting = true;
  607. theSel[0] = theSel[(iHandle+2)%4];
  608. theSel[2] = pt;
  609. theSel[1].x = theSel[2].x; theSel[1].y = theSel[0].y;
  610. theSel[3].x = theSel[0].x; theSel[3].y = theSel[2].y;
  611.       } else {
  612. if (findSelectionLine (pt, theSel) >= 0) {
  613.   bChangeExisting = true;
  614.   bMoveEntire = true;
  615.   ptRelativeTo = pt;
  616. }
  617.       }
  618.     }
  619.     
  620.     if (!bChangeExisting) {
  621.       theSel.clear();
  622.       theSel.type = Selection::rect;
  623.       theSel.pts.push_back (pt);
  624.       theSel.pts.push_back (pt);
  625.       theSel.pts.push_back (pt);
  626.       theSel.pts.push_back (pt);
  627.     }
  628.     return TCL_OK;
  629.   } else if (!strcmp (argv[4], "stop")) {
  630.     bManipulatingSel = false;
  631.     if (theSel[0].x == theSel[2].x && theSel[0].y == theSel[2].y)
  632.       Tcl_Eval (Togl_Interp (togl), "clearSelection");
  633.   } else {
  634.     if (theSel.type != Selection::rect) {
  635.       interp->result = "Internal selection tracking error";
  636.       return TCL_ERROR;
  637.     }
  638.     if (bMoveEntire) {
  639.       for (int i = 0; i < 4; i++) {
  640. theSel[i].x += pt.x - ptRelativeTo.x;
  641. theSel[i].y += pt.y - ptRelativeTo.y;
  642.       }
  643.       ptRelativeTo = pt;
  644.     } else {
  645.       // pt 0 doesn't change; pt 2 becomes new pont
  646.       // pt 1 needs to change x, pt 3 needs to change y
  647.       theSel[1].x = pt.x;
  648.       theSel[3].y = pt.y;
  649.       theSel[2] = pt;
  650.     }
  651.   }
  652.   
  653. #ifndef no_overlay_support
  654.   Togl_PostOverlayRedisplay (togl);
  655. #else
  656.   drawOverlayAndSwap(togl); 
  657. #endif
  658.   return TCL_OK;
  659. }
  660. int
  661. PlvGetSelectionCursorCmd(ClientData clientData, Tcl_Interp *interp, 
  662.  int argc, char *argv[])
  663. {
  664.   if (argc < 3)
  665.     return TCL_ERROR;
  666.   Selection::Pt pt;
  667.   pt.x = atoi(argv[1]);
  668.   pt.y = theHeight - atoi(argv[2]);
  669.   
  670.   // cursors: default = tcross, handle = dotbox, border = fleur
  671.   // check handles
  672.   if (findSelectionHandle (pt, theSel) >= 0)
  673.     interp->result = "dotbox";
  674.   else if (findSelectionLine (pt, theSel) >= 0)
  675.     interp->result = "fleur";
  676.   else
  677.     interp->result = "tcross";
  678.   return TCL_OK;
  679. }
  680. // ------------------------------------------------------------
  681. // PlvGetSelectionInfoCmd
  682. // Gets a string for the info of the current selection object
  683. // ------------------------------------------------------------
  684. int
  685. PlvGetSelectionInfoCmd(ClientData clientData, Tcl_Interp *interp, 
  686.   int argc, char *argv[])
  687. {
  688.   char buff[256];
  689.   switch ( theSel.type ) {
  690.   case Selection::none:
  691.     interp->result = "PlvGetSelectionInfoCmd: error -- nothing selected";
  692.     return TCL_ERROR;
  693.     //    break;
  694.   case Selection::line:
  695.     sprintf(buff, "line %i %i %i %i", theSel[0].x, theSel[0].y, 
  696.     theSel[1].x, theSel[1].y);
  697.     break; 
  698.   case Selection::rect:
  699.     /*
  700.     sprintf(buff, "rect %i %i %i %i %i %i %i %i", theSel[0].x, theSel[0].y,
  701.     theSel[1].x, theSel[1].y, theSel[2].x, theSel[2].y,
  702.     theSel[3].x, theSel[3].y);
  703.     */
  704.     break;
  705.   case Selection::shape:
  706.     // CHEAP HACK WARNING!
  707.     // Something weird happens when I try to use 0 1 2
  708.     printf("PlvGetSelectionInfoCmd: getting only first 3 pointsn");
  709.     sprintf(buff, "shape %i %i %i %i %i %i", theSel[1].x, theSel[1].y,
  710.     theSel[2].x, theSel[2].y, theSel[3].x, theSel[3].y);
  711.     break;
  712.   default:
  713.     interp->result = "PlvGetSelectionInfoCmd: error -- type not supported";
  714.     return TCL_ERROR;
  715.     //    break;
  716.   }
  717.   Tcl_SetResult(interp, buff, TCL_VOLATILE);
  718.   return TCL_OK;
  719. }
  720. int
  721. PlvMeshIntersectSelectionCmd(ClientData clientData, Tcl_Interp *interp, 
  722.      int argc, char *argv[])
  723. {
  724.   if (argc < 2) {
  725.     interp->result = "Missing mesh argument in PlvShowBySelectionCmd";
  726.     return TCL_ERROR;
  727.   }
  728.   if (theSel.type != Selection::rect) {
  729.     interp->result = "Only rectangle selections supported";
  730.     return TCL_ERROR;
  731.   }
  732.   DisplayableMesh* dm = FindMeshDisplayInfo (argv[1]);
  733.   if (!dm) {
  734.     interp->result = "Bad mesh argument in PlvShowBySelectionCmd";
  735.     return TCL_ERROR;
  736.   }
  737.   RigidScan* rs = dm->getMeshData();
  738.   Bbox scanBox = rs->worldBbox();
  739.   Bbox screenBounds;
  740.   for (int i = 0; i < 8; i++) {
  741.     Pnt3 pt = scanBox.corner (i);
  742.     screenBounds.add (pt);
  743.   }
  744.   return TCL_OK;
  745. }
  746. void
  747. initSelection (struct Togl* togl)
  748. {
  749.   if (togl) {
  750.     olColor = Togl_AllocColorOverlay (togl, 1, 0, 0);
  751.     handleColor = Togl_AllocColorOverlay (togl, 1, 1, 0);
  752.     handleSelColor = Togl_AllocColorOverlay (togl, 0, 1, 0);
  753.   }
  754. }
  755. void
  756. drawSelection (struct Togl* togl)
  757. {
  758.   int width, height;
  759.   
  760.   width = Togl_Width (togl);
  761.   height = Togl_Height (togl);
  762.   
  763.   glViewport(0, 0, width, height); 
  764.   glMatrixMode(GL_PROJECTION);
  765.   glPushMatrix(); // kberg - needed when overlay planes not available
  766.   glLoadIdentity();
  767.   gluOrtho2D(-0.5, width+0.5, -0.5, height+0.5);
  768.    
  769.   glMatrixMode(GL_MODELVIEW);
  770.   glPushMatrix(); // kberg - needed for when overlay planes not available
  771.   glLoadIdentity();
  772.   
  773.   int nPts = theSel.pts.size();
  774.   if (nPts) {
  775.     glPushAttrib (GL_LIGHTING_BIT);
  776.     glDisable (GL_LIGHTING);
  777.     
  778.     // draw handles, if it's not currently being dragged
  779.     if (!bManipulatingSel) {
  780.       for (int i = 0; i < nPts; i++)
  781. drawHandle (theSel[i],
  782.     theSel.type == Selection::shape
  783.     && ((i==0) || (i==(nPts-1))));
  784.     }
  785.   
  786.     // now draw the selection itself as a line loop   
  787. #ifdef no_overlay_support
  788.     glColor3f(1,0,0);
  789. #else
  790.      glIndexi (olColor);
  791. #endif
  792.     glBegin (GL_LINE_LOOP);
  793.     for (int i = 0; i <= nPts; i++)
  794.       glVertex2i (theSel[i%nPts].x, theSel[i%nPts].y);
  795.     glEnd();
  796.     glPopAttrib();
  797.   }
  798.   
  799.   glPopMatrix();
  800.   glMatrixMode(GL_PROJECTION);
  801.   glPopMatrix();
  802.   glFinish();
  803. }
  804. static void drawHandle (Selection::Pt pt, bool bSelected)
  805. {
  806.   glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
  807.  
  808. #ifndef no_overlay_support
  809.   glIndexi (bSelected ? handleSelColor : handleColor);
  810.   glBegin (GL_QUADS);
  811. #else
  812.   // no clue on this one, but Linux/nVidia won't draw the quads but
  813.   // will draw the line loop
  814.   glBegin(GL_LINE_LOOP);
  815.   bSelected ?  glColor3f(0,1,0) : glColor3f(1,1,0);
  816. #endif
  817.   glVertex2i (pt.x - kHandleSize, pt.y - kHandleSize);
  818.   glVertex2i (pt.x - kHandleSize, pt.y + kHandleSize);
  819.   glVertex2i (pt.x + kHandleSize, pt.y + kHandleSize);
  820.   glVertex2i (pt.x + kHandleSize, pt.y - kHandleSize);
  821.   glEnd();
  822. }
  823. static bool ptOnHandle (Selection::Pt pt, Selection::Pt handle)
  824. {
  825.   return (   abs (pt.x - handle.x) < kHandleSize
  826.   && abs (pt.y - handle.y) < kHandleSize);
  827. }
  828. static int findSelectionHandle (Selection::Pt pt, const Selection& sel)
  829. {
  830.   int nPts = sel.pts.size();
  831.   for (int i = 0; i < nPts; i++)
  832.     if (ptOnHandle (pt, sel[i]))
  833.       return i;
  834.   return -1;
  835. }
  836. static bool ptOnLine (Selection::Pt pt,
  837.       Selection::Pt start, Selection::Pt end)
  838. {
  839.   // handle vertical line
  840.   if (start.x == end.x) {
  841.     if (abs (pt.x - start.x) >= kHandleSize)
  842.       return false;
  843.     if (pt.y > start.y && pt.y > end.y)
  844.       return false;
  845.     if (pt.y < start.y && pt.y < end.y)
  846.       return false;
  847.     return true;
  848.   }
  849.   // ok, not vertical -- check horizontal
  850.   if (pt.x < start.x && pt.x < end.x)
  851.     return false;
  852.   if (pt.x > start.x && pt.x > end.x)
  853.     return false;
  854.   // ok horizontally -- get slope
  855.   float slope = (end.y - start.y) / (float)(end.x - start.x);
  856.   float icpt = start.y - slope * start.x;
  857.   int yofs = pt.y - (icpt + (slope * pt.x));
  858.   return (abs (yofs) < kHandleSize);
  859. }
  860. static int findSelectionLine (Selection::Pt pt, const Selection& sel)
  861. {
  862.   int nPts = sel.pts.size();
  863.   for (int i = 0; i < nPts; i++)
  864.     if (ptOnLine (pt, sel[i], sel[(i+1)%nPts]))
  865.       return i;
  866.   
  867.   return -1;
  868. }
  869. void splTessError (GLenum er)
  870. {
  871.   const GLubyte *str = gluErrorString (er);
  872.   cout << "Tesselation error during polyline rasterization: "
  873.        << str << endl;
  874. }
  875. vector<GLdouble*> hack_vert_alloc;
  876. void splTessCombine (GLdouble coords[3],
  877.   GLdouble* vertex_data[4],
  878.   GLfloat weight[4],
  879.   GLdouble** dataOut)
  880. {
  881.   GLdouble* vertex = new GLdouble[3];
  882.   vertex[0] = coords[0];
  883.   vertex[1] = coords[1];
  884.   vertex[2] = coords[2];
  885.   hack_vert_alloc.push_back (vertex);  // mark to free later
  886.   *dataOut = vertex;
  887. }
  888. unsigned char* filledPolyPixels (int& width, int& height,
  889.  const vector<ScreenPnt>& pts)
  890. {
  891.   // for word alignment: rounded up to nearest mult. of 4
  892.   width = 4 * ((width + 3) / 4);
  893.   // set up GL modes for rendering in screen coords
  894.   int vp[4];
  895.   glGetIntegerv(GL_VIEWPORT, vp);
  896.   glViewport(0, 0, width, height);
  897.   glMatrixMode(GL_PROJECTION);
  898.   glPushMatrix();
  899.   glLoadIdentity();
  900.   gluOrtho2D(-0.5, width+0.5, -0.5, height+0.5);
  901.   glMatrixMode(GL_MODELVIEW);
  902.   glPushMatrix();
  903.   glLoadIdentity();
  904.   // render filled polygon with tesselator
  905.   glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
  906.   glClear (GL_COLOR_BUFFER_BIT);
  907.   glDisable (GL_DEPTH_TEST);
  908.   glDisable (GL_LIGHTING);
  909.   glDisable (GL_CULL_FACE);
  910.   glColor3f (1, 1, 1);
  911. #ifdef GLU_VERSION_1_2
  912.   GLUtesselator* tess = gluNewTess();
  913.   hack_vert_alloc.clear();
  914. #ifdef WIN32
  915. #  define DECORATE (GLvoid(__stdcall *) ()) &
  916. #else
  917. #  define DECORATE (GLvoid(*) ()) &
  918. #endif
  919.   gluTessCallback (tess, GLU_TESS_VERTEX, DECORATE glVertex3dv);
  920.   gluTessCallback (tess, GLU_TESS_BEGIN,  DECORATE glBegin);
  921.   gluTessCallback (tess, GLU_TESS_END,    DECORATE glEnd);
  922.   gluTessCallback (tess, GLU_TESS_COMBINE,DECORATE splTessCombine);
  923.   gluTessCallback (tess, GLU_TESS_ERROR,  DECORATE splTessError);
  924. #undef DECORATE
  925.   gluTessBeginPolygon (tess, NULL);
  926.   gluTessBeginContour (tess);
  927.   int nPts = pts.size();
  928.   GLdouble* coords = new GLdouble [3 * (nPts + 1)];
  929.   for (int i = 0; i <= nPts; i++) {
  930.     coords[3*i  ] = pts[i%nPts].x;
  931.     coords[3*i+1] = pts[i%nPts].y;
  932.     coords[3*i+2] = 0;
  933.     gluTessVertex (tess, coords + 3*i, coords + 3*i);
  934.   }
  935.   
  936.   gluTessEndContour (tess);
  937.   gluTessEndPolygon (tess);
  938.   gluDeleteTess (tess);
  939.   delete coords;
  940.   // free memory used by combine-created vertices
  941.   for (i = 0; i < hack_vert_alloc.size(); i++)
  942.     delete hack_vert_alloc[i];
  943.   hack_vert_alloc.clear();
  944. #endif // GLU_VERSION_1_2
  945.   // read the fruits of our labors
  946.   unsigned char* pixels = new unsigned char [width*height];
  947.   memset (pixels, 0, width*height);
  948.   glReadBuffer (GL_BACK);
  949.   glReadPixels (0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE,
  950. pixels);
  951.   GLenum a = glGetError();
  952.   if (a != GL_NO_ERROR) {
  953.     cout << "raw error: " << a << endl;
  954.     cout << "GL error: " << gluErrorString (a) << endl;
  955.   }
  956.   // and reset GL params
  957.   glMatrixMode (GL_PROJECTION);
  958.   glPopMatrix();
  959.   glMatrixMode (GL_MODELVIEW);
  960.   glPopMatrix();
  961.   glViewport (vp[0], vp[1], vp[2], vp[3]);
  962. #if 0
  963.   int n = 0;
  964.   for (i = 0; i < width*height; i++) {
  965.     if (pixels[i] != 0)
  966.       n++;
  967.   }
  968.   cout << n << " pixels are set" << endl;
  969. #endif
  970.   return pixels;
  971. }
  972. int
  973. PlvGetSelectedMeshesCmd(ClientData clientData, Tcl_Interp *interp, 
  974. int argc, char *argv[])
  975. {
  976.   bool bIncludeHidden = false;
  977.   bool bInvert = false;
  978.   bool bSilent = false;
  979.   for (int i = 1; i < argc; i++) {
  980.     if (!strcmp (argv[i], "hidden"))
  981.       bIncludeHidden = true;
  982.     else if (!strcmp (argv[i], "invert"))
  983.       bInvert = true;
  984.     else if (!strcmp (argv[i], "silent"))
  985.       bSilent = true;
  986.     else {
  987.       cerr << argv[0] << " doesn't understand " << argv[i] << endl;
  988.       interp->result = "Bad argument: look at stderr";
  989.       return TCL_ERROR;
  990.     }
  991.   }
  992.   if (theSel.type != Selection::rect) {
  993.     if (bSilent && theSel.type == Selection::none)
  994.       return TCL_OK;
  995.     interp->result = "First you must select an area";
  996.     return TCL_ERROR;
  997.   }
  998.   for (i = 0; i < theScene->meshSets.size(); i++) {
  999.     DisplayableMesh *displayMesh = theScene->meshSets[i];
  1000.     if (!bIncludeHidden && !displayMesh->getVisible())
  1001.       continue;
  1002.     RigidScan *mesh = displayMesh->getMeshData();
  1003.     VertexFilter* filter = filterFromSelection (mesh, theSel);
  1004.     if (!filter) {
  1005.       interp->result = "First you must select an area";
  1006.       return TCL_ERROR;
  1007.     }
  1008.     if (bInvert)
  1009.       filter->invert();
  1010.     if (filter->accept(mesh->localBbox())) {
  1011.       Tcl_AppendElement (interp, (char*)displayMesh->getName());
  1012.     }
  1013.     delete filter;
  1014.   }
  1015.   
  1016.   return TCL_OK;
  1017. }
  1018. void resizeSelectionToWindow (struct Togl* togl)
  1019. {
  1020.   int nPts = theSel.pts.size();
  1021.   if (!nPts) return;
  1022.   float newhyp = sqrt (Togl_Width(togl)*Togl_Width(togl)
  1023.        +Togl_Height(togl)*Togl_Height(togl));
  1024.   float oldhyp = sqrt (theWidth*theWidth + theHeight*theHeight);
  1025.   float scale = newhyp / oldhyp;
  1026.   int cx = 0, cy = 0;
  1027.   for (int i = 0; i < nPts; i++) {
  1028.     cx += theSel[i].x;
  1029.     cy += theSel[i].y;
  1030.   }
  1031.   cx /= i;
  1032.   cy /= i;
  1033.   int ncx = cx * Togl_Width (togl) / theWidth;
  1034.   int ncy = cy * Togl_Height (togl) / theHeight;
  1035.   for (i = 0; i < nPts; i++) {
  1036.     theSel[i].x = ncx + scale * (theSel[i].x - cx);
  1037.     theSel[i].y = ncy + scale * (theSel[i].y - cy);
  1038.   }
  1039.   Togl_PostOverlayRedisplay (togl);
  1040. }