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

3D图形编程

开发平台:

Visual C++

  1. //###############################################################
  2. // plvAnalyze.cc
  3. // Matt Ginzton, Lucas Pereira
  4. // Thu Jun 18 13:02:22 PDT 1998
  5. // 
  6. // Interface for reading points or groups of points from z buffer
  7. //###############################################################
  8. #include "plvGlobals.h"
  9. #include "plvDraw.h"
  10. #include "plvDrawCmds.h"
  11. #include "Trackball.h"
  12. #include "togl.h"
  13. #include "Pnt3.h"
  14. #include "defines.h"
  15. #include "sczRegCmds.h"
  16. #include "plvAnalyze.h"
  17. #include "ScanFactory.h"
  18. #include "DisplayMesh.h"
  19. #include "plvScene.h"
  20. #include "plvClipBoxCmds.h"
  21. #include "GenericScan.h"
  22. #include "Mesh.h"
  23. #include "DrawObj.h"
  24. #include "plvImageCmds.h"
  25. #include "ToglText.h"
  26. #include "Projector.h"
  27. #ifdef WIN32
  28. // don't have rint, just consider it a noop
  29. # define rint (int)
  30. #endif
  31. #ifdef linux
  32. #define MAXFLOAT FLT_MAX
  33. #endif
  34. // for determining background pixels in z buffer -- should be 0 to 1.0,
  35. // or 0x0 to 0xffffffff, but on IR's the range is somewhat different,
  36. // 0x7ffff to 0xffffff00
  37. unsigned int g_zbufferMinUI;
  38. unsigned int g_zbufferMaxUI;
  39. float g_zbufferMinF;
  40. float g_zbufferMaxF;
  41. #define ISBACKGROUND(zfloat) ((zfloat) >= g_zbufferMaxF)
  42. #ifndef MIN
  43. #define MIN(a,b)  ((a)<(b)?(a):(b))
  44. #endif
  45. #ifndef MAX
  46. #define MAX(a,b)  ((a)>(b)?(a):(b))
  47. #endif
  48. #define DEBUG 1
  49. static void readLinePixels (int x, int y, int w, int h,
  50.     GLenum component, GLenum type,
  51.     char* data, int dataSize);
  52. int
  53. WriteOrthoDepth(ClientData clientData, Tcl_Interp *interp,
  54.                 int argc, char *argv[])
  55. {
  56.    GLint viewport[4];
  57.    GLdouble projmatrix[16];
  58.    GLdouble idmatrix[16] = {1.0,0,0,0, 0,1.0,0,0, 0,0,1.0,0, 0,0,0,1.0};
  59.    GLdouble wx, wy, wz;
  60.    float *dvp;
  61.    double min_eye_z = 0.0, max_eye_z = -MAXFLOAT;
  62.    float zval;
  63.    int val;
  64.    int i, j;
  65.    if (argc != 2) {
  66.        Tcl_SetResult(interp, "Incorrect Num of Args", NULL);
  67.        return TCL_ERROR;
  68.    }
  69.    FILE *fd = fopen(argv[1], "w");
  70.    if (fd == NULL) {
  71.        Tcl_SetResult(interp, "Can't open file for writing", NULL);
  72.        return TCL_ERROR;
  73.    }
  74.    // Read the depth buffer values into a local data structure
  75.    int width = Togl_Width (toglCurrent);
  76.    int height = Togl_Height (toglCurrent);
  77.    float *depthvals = new float[width*height];
  78.    glReadBuffer(GL_FRONT);
  79.    glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT,
  80.                 GL_FLOAT, depthvals);
  81.    // Unproject the depth buffer values back to eye coordinates.
  82.    glGetIntegerv(GL_VIEWPORT, viewport);
  83.    glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
  84.    for (i=0; i<height; ++i)
  85.        for (j=0; j<width; ++j) {
  86.             dvp = &(depthvals[i*width+j]);
  87.     if (ISBACKGROUND(*dvp))
  88.        *dvp = 1000.0;
  89.             else  {
  90.                gluUnProject((GLdouble) j, (GLdouble) i, (GLdouble) *dvp,
  91.                    idmatrix, projmatrix, viewport, &wx, &wy, &wz);
  92.                if (wz > max_eye_z)
  93.   max_eye_z = wz;
  94.                if (wz < min_eye_z)
  95.   min_eye_z = wz;
  96.                *dvp = wz;
  97.             }
  98.        }
  99.    // Write the scaled depth values out to a 16-bit .PPM format file.
  100.    // Pixel value 0 is used as a "no data" flag.
  101.    double dgap = max_eye_z - min_eye_z;
  102.    double dscale = dgap / 65534.0;
  103.    double dbias = -max_eye_z - dscale;
  104.    fprintf(fd, "P3n");
  105.    fprintf(fd, "# 16-bit .PPM format displacement map (via Scanalyze)n");
  106.    fprintf(fd, "# Image dimensions: ");
  107.    fprintf(fd, "width=%g height=%gn", 2/projmatrix[0], 2/projmatrix[5]);
  108.    fprintf(fd, "# Displacement resolution=%gn", dscale);
  109.    fprintf(fd, "# Pixel values of 0 (if any) correspond to missing datan");
  110.    fprintf(fd, "%d %d 65535n", width, height);
  111.    for (i=height-1; i>=0; i--)
  112.        for (j=0; j<width; ++j)  {
  113.            zval = depthvals[i*width + j];
  114.    if (zval > 0.0)
  115.        fprintf(fd, "0 0 0n");
  116.            else  {
  117.               val = (int) rint((-zval-dbias)/dscale);
  118.       fprintf(fd, "%d %d %dn", val, val, val);
  119.    }
  120.        }
  121.    delete[] depthvals;
  122.    fclose(fd);
  123.    return TCL_OK;
  124. }
  125. //////////////////////////////////////////////////////////////////////
  126. //
  127. // Point picking tools
  128. //
  129. //////////////////////////////////////////////////////////////////////
  130. //X and Tcl are upper left origin
  131. //GL is lower left..yah
  132. int
  133. WriteWorldDataFromScreen(ClientData clientData, Tcl_Interp *interp, 
  134.        int argc, char *argv[])
  135. {
  136.   Pnt3 pt;
  137.   int width = Togl_Width(toglCurrent);
  138.   int height = Togl_Height(toglCurrent);
  139.   //ScreenToWorldCoordinates assumes GL lower left origin
  140.   if(argc !=2)
  141.     {
  142.       Tcl_SetResult(interp, "Incorrect Num of Args", NULL);
  143.       return TCL_ERROR;
  144.     }
  145.   FILE *fd = fopen(argv[1], "w");
  146.   if(fd == NULL)
  147.     {
  148.       Tcl_SetResult(interp,
  149.     "Can't open file for writing", NULL);
  150.       return TCL_ERROR;
  151.     }
  152.   //fprintf(fd, "# format is u,v x,y,z u,v, is GL (lower left) originn");
  153.   fprintf(fd, "# format is u,v x,y,z   (u,v, is upper left origin)n");
  154.   fprintf(fd, "# next line is width, height of imagen");
  155.   fprintf(fd, "%d %dn",width,height);
  156.   for(int x=0; x<width;x++)
  157.     for(int y=0;y<height;y++)
  158.       {
  159. if(ScreenToWorldCoordinates(x,y,pt))
  160.   {
  161.     //this point is on the object.
  162.     fprintf(fd,"%d %d %f %f %fn",x,height-y,pt[0],pt[1],pt[2]);
  163.   }
  164.       }
  165.   fclose(fd);
  166.   return TCL_OK;
  167. }
  168. /*
  169. {
  170.   Pnt3 pt;
  171.   //get screen size
  172.   int width = Togl_Width (toglCurrent);
  173.   int height = Togl_Height (toglCurrent);
  174.   //fprintf(stderr, "plvAnalyze.cc:WriteWorldDataFromScreen "
  175.   //  "width,height is %d,%dn",width,height);
  176.   if(argc !=2)
  177.     {
  178.       Tcl_SetResult(interp, "Incorrect Num of Args", NULL);
  179.       return TCL_ERROR;
  180.     }
  181.   FILE *fd = fopen(argv[1], "w");
  182. #ifdef DEBUG
  183.   char buffer[1024];
  184.   sprintf(buffer, "%s.iv",argv[1]);
  185.   FILE *ivfile = fopen(buffer, "w");
  186.   fprintf(ivfile, "#Inventor V2.1 ascii#nn");
  187.   //new
  188.   fprintf(ivfile, "Separator {nCoordinate3 { n point [n");
  189. #endif
  190.   if(fd == NULL)
  191.     {
  192.       Tcl_SetResult(interp,
  193.     "Can't open file for writing", NULL);
  194.       return TCL_ERROR;
  195.     }
  196.   for(int w=0; w < width; w++)
  197.     for(int h=0; h <height; h++)
  198.       {
  199. ScreenToWorldCoordinates(w,h, pt);
  200. if(pt[0] != 0.0 || pt[1] != 0.0 ||
  201.    pt[2] != 0.0)
  202.   {
  203.     fprintf(fd, "%d %d %f %f %fn",w,h,pt[0],
  204.     pt[1],pt[2]);
  205. #ifdef DEBUG
  206.     fprintf(ivfile, "%f %f %f,n",pt[0],pt[1],pt[2]);
  207.     //     fprintf(ivfile, "Separator { n");
  208.     //fprintf(ivfile, "Translation { translation %f %f %f } n",
  209.     //     pt[0],pt[1],pt[2]);
  210.     //fprintf(ivfile, "Sphere { radius .0001 }n}n");
  211. #endif
  212.   }
  213.       }
  214. #ifdef DEBUG
  215.   //add last point again, w/o the comma
  216.   fprintf(ivfile, "%f %f %f ]n",pt[0],pt[1],pt[2]);
  217.   fprintf(ivfile, "}n}n");
  218.   fclose(ivfile);
  219. #endif
  220.   fclose(fd);
  221.   return TCL_OK;
  222.   //TCL_ERROR
  223. }
  224. */
  225. int
  226. ScreenToWorldCoordinates (int x, int y, Pnt3& ptWorld)
  227. {
  228.   // assumes GL coordinates (0,0 is lower left)
  229.   return ScreenToWorldCoordinatesExt (x, y, ptWorld, toglCurrent, tbView, 0);
  230. }
  231. int
  232. ScreenToWorldCoordinatesExt (int x, int y, Pnt3& ptWorld,
  233.      struct Togl* togl, Trackball* tb,
  234.      float fudgeFactor)
  235. {
  236.   // assumes GL coordinates (0,0 is lower left)
  237.   Togl_MakeCurrent (togl);
  238.   float pixdepth;
  239.   if (theRenderParams->polyMode == GL_FILL || theRenderParams->hiddenLine)
  240.   {
  241.     // have poly data (or hidden-line/point, also filled)
  242.     // read it from front buffer
  243.     glReadBuffer (GL_FRONT);
  244.     glReadPixels (x, y, 1, 1, GL_DEPTH_COMPONENT, 
  245.   GL_FLOAT, &pixdepth);
  246.     //printf("pixdepth (from front): %fn", pixdepth);
  247.   }
  248.   else {
  249.     // don't have poly data... need to get it
  250.     GLenum oldPolyMode = theRenderParams->polyMode;
  251.     bool oldHiddenLine = theRenderParams->hiddenLine;
  252.     theRenderParams->polyMode = GL_FILL;
  253.     theRenderParams->hiddenLine = FALSE;
  254.     if (togl == toglCurrent)
  255.       drawInToglBuffer (togl, GL_BACK);
  256.     else {
  257.       //hack warning -- assumes all togls except the main one have an
  258.       //AlignmentToglInfo; need to change this
  259.       DrawAlignmentMeshToBack (togl);
  260.     }
  261.     glReadBuffer (GL_BACK);
  262.     glReadPixels (x, y, 1, 1, GL_DEPTH_COMPONENT, 
  263.   GL_FLOAT, &pixdepth);
  264.     //printf("pixdepth (from back): %fn", pixdepth);
  265.     theRenderParams->polyMode = oldPolyMode;
  266.     theRenderParams->hiddenLine = oldHiddenLine;
  267.   }
  268.   // ok, at this point, pixdepth has the zbuffer value
  269.   // ignore z-depth of 1.0 because that's the background
  270.   if (ISBACKGROUND (pixdepth))
  271.     return FALSE;
  272.   pixdepth -= fudgeFactor;
  273.   // need to unproject z-buffer data to world coordinates
  274.   Unprojector unproject (tb);
  275.   ptWorld = unproject (x, y, pixdepth);
  276.   //printf("You selected world position: %.4f %.4f %.4fn", 
  277.   //   worldPos[0], worldPos[1], worldPos[2]);
  278.   return true;
  279. }
  280. //////////////////////////////////////////////////////////////////////
  281. //
  282. // Clip line analysis tools
  283. //
  284. //////////////////////////////////////////////////////////////////////
  285. class ClipLineData
  286. {
  287. public:
  288.   ClipLineData (int w);
  289.   ~ClipLineData();
  290.   GLfloat* pixels;          // z-buffer data
  291.   GLfloat* lines;           // z-buffer data from wireframe render
  292.   Pnt3*    objPt;           // unprojected object coordinates
  293.   vec3uc color;
  294.   DisplayableMesh *theMesh;
  295. };
  296. class ClipLineInfo
  297. {
  298. public:
  299.   ClipLineInfo (int w);
  300.   ~ClipLineInfo();
  301.   // data corresponding to multiple scans
  302.   vector<ClipLineData*> data;
  303.   // info pertaining to aggregate of data collection
  304.   int width;                //width of line, in pixels
  305.   GLdouble zMin, zMax;      //min, max values in objZ
  306.   GLdouble xMin, xMax;
  307.   int nFirstGood, nLastGood;//indices of first & last
  308.                             //non-background pixels in z-buffer
  309.   // UI settings
  310.   bool  bShowScale;
  311.   bool  bShowEdges;
  312.   bool  bShowFramebuffPts;
  313.   bool  bShowColor;
  314.   int   nScaleExp;
  315.   float zRescale;
  316. };
  317. ClipLineInfo::ClipLineInfo (int w)
  318. {
  319.   width = w;
  320.   bShowScale = true;
  321.   bShowEdges = false;
  322.   bShowFramebuffPts = false;
  323.   bShowColor = true;
  324.   nScaleExp = 0;
  325.   zRescale = 1;
  326. }
  327. ClipLineInfo::~ClipLineInfo()
  328. {
  329.   for (ClipLineData** iter = data.begin(); iter < data.end(); iter++)
  330.     delete *iter;
  331. }
  332. ClipLineData::ClipLineData (int w)
  333. {
  334.   pixels = new GLfloat [w];
  335.   lines = new GLfloat [w];
  336.   objPt = new Pnt3 [w];
  337. }
  338. ClipLineData::~ClipLineData()
  339. {
  340.   delete [] pixels;
  341.   delete [] lines;
  342.   delete [] objPt;
  343. }
  344. int
  345. PlvAnalyzeLineModeCmd(ClientData clientData, Tcl_Interp *interp, 
  346.       int argc, char *argv[])
  347. {
  348.   static float zsBase = 1;
  349.   // args: analyzeTogl [show linetype bool] | [scale n] | [level bool]
  350.   if (argc < 4) {
  351.     interp->result = "Bad args to PlvAnalyzeLineModeCmd";
  352.     return TCL_ERROR;
  353.   }
  354.   struct Togl* togl = toglHash.FindTogl (argv[1]);
  355.   if (!togl) {
  356.     interp->result = "Missing togl in PlvAnalyzeLineModeCmd";
  357.     return TCL_ERROR;
  358.   }
  359.   ClipLineInfo* cli = (ClipLineInfo*)Togl_GetClientData (togl);
  360.   if (!strcmp (argv[2], "show")) {
  361.     if (argc < 5)
  362.       return TCL_ERROR;
  363.     bool bShow = atoi (argv[4]);
  364.     if (!strcmp (argv[3], "scale"))
  365.       cli->bShowScale = bShow;
  366.     else if (!strcmp (argv[3], "edges"))
  367.       cli->bShowEdges = bShow;
  368.     else if (!strcmp (argv[3], "framebuff"))
  369.       cli->bShowFramebuffPts = bShow;
  370.     else if (!strcmp (argv[3], "color"))
  371.       cli->bShowColor = bShow;
  372.   } else if (!strcmp (argv[2], "scale")) {
  373.     cli->nScaleExp = atoi (argv[3]);
  374.   } else if (!strcmp (argv[2], "zscale")) {
  375.     int zs = atoi (argv[3]);
  376.     if (!strcmp (argv[4], "start")) {
  377.       zsBase = zs / cli->zRescale;
  378.     } else {
  379.       if (!strcmp (argv[4], "reset"))
  380. cli->zRescale = 1;
  381.       else
  382. cli->zRescale = MAX (1, zs / zsBase);
  383.       double zScale = (cli->zMax - cli->zMin) / cli->zRescale;
  384.       char buf[50];
  385.       sprintf (buf, "setAnalyzeZScale %s %g", argv[1], zScale);
  386.       Tcl_Eval (interp, buf);
  387.     }
  388.   } else {
  389.     interp->result = "Bad subcommand in PlvAnalyzeModeCmd";
  390.     return TCL_ERROR;
  391.   }
  392.   Togl_PostRedisplay (togl);
  393.   return TCL_OK;
  394. }
  395. int
  396. PlvExportGraphAsText(ClientData clientData, Tcl_Interp *interp, 
  397.      int argc, char *argv[]) 
  398. {
  399.   Togl *togl;
  400.   char *winName;
  401.   FILE *datafile, *ctlfile;
  402.   ClipLineInfo *cli;
  403.   char fileName[256];
  404.   if ( argc < 3 ) {
  405.     return TCL_ERROR;
  406.   }
  407.   char toglName[100];
  408.   sprintf (toglName, "%s.togl", argv[1]);
  409.   togl = toglHash.FindTogl(toglName);
  410.   winName = argv[2];
  411.   if ( togl == NULL ) {
  412.     interp->result = "PlvExportGraphAsText: Null togl pointer";
  413.     return TCL_ERROR;
  414.   }
  415.   // don't need to check, b/c tcl caller should do it
  416.   ctlfile = fopen(winName, "w");
  417.   // don't copy the extension, but remember to add terminator
  418.   strncpy(fileName, winName, strlen(winName) - 4);
  419.   fileName[(strlen(winName) - 4)] = '';
  420.   // comment title, set postscript output
  421.   fprintf(ctlfile, "# %snset term post p c s 12n", fileName);
  422.   fprintf(ctlfile, "set size .75, .75n");
  423.   // set ps output file, set title of graph
  424.   fprintf(ctlfile, "set output "%s.ps"nset title "%s"n", fileName, fileName);
  425.  
  426.   cli = (ClipLineInfo*)Togl_GetClientData(togl);
  427.   int nPix = cli->width;
  428.   //  int k = 0;
  429.   fprintf(ctlfile, "plot ");
  430.   for (ClipLineData** pcld = cli->data.begin(); 
  431.        pcld < cli->data.end(); pcld++) {
  432.     ClipLineData* cld = *pcld;
  433.     char buff[256];
  434.     //    sprintf(buff, "%s.%i.dat", winName, k);
  435.     sprintf(buff, "%s_%s.dat", fileName, cld->theMesh->getName());
  436.     //    sprintf(buff, "%s_%s.dat", fileName, cld->theMesh->displayName);
  437.     datafile = fopen(buff, "w");
  438.     if ( datafile == NULL ) {
  439.       printf ("can't open filen");
  440.     }
  441.     fprintf(ctlfile, "'%s' title '%s' with lines", buff, cld->theMesh->getName());
  442.     if ( pcld + 1 < cli->data.end() ) {
  443.       fprintf(ctlfile, ", ");
  444.     }
  445.     for (int x = 0; x < nPix; x++ ) {
  446.       if (!ISBACKGROUND(cld->pixels[x])) {
  447. fprintf(datafile, "n%f %f", cld->objPt[x][0], cld->objPt[x][2]);
  448.       }
  449.     }
  450.     //    k++;
  451.     fclose(datafile);
  452.   }
  453.   
  454.   fclose(ctlfile);
  455.   return TCL_OK;
  456. } // PlvExportGraphAsText
  457. void
  458. PlotLineDepth (struct Togl* togl)
  459. {
  460.   ClipLineInfo* cli = (ClipLineInfo*)Togl_GetClientData (togl);
  461.   int nPixels = cli->width;
  462.   int w = Togl_Width (togl);
  463.   int h = Togl_Height (togl);
  464.   //set child's togl as current
  465.   glViewport (0, 0, w, h);
  466.   glMatrixMode (GL_MODELVIEW);
  467.   glLoadIdentity();
  468.   glMatrixMode (GL_PROJECTION);
  469.   glLoadIdentity();
  470.   glClear (GL_COLOR_BUFFER_BIT);
  471.   //draw grid -- square only if correct aspect ratio
  472.   double scaleW = (cli->xMax - cli->xMin) * 
  473.    (cli->width / (double)(cli->nLastGood - cli->nFirstGood));
  474.   double scaleH = cli->zMax - cli->zMin;
  475.   float zRescaleRatio = (cli->zRescale - 1) / cli->zRescale;
  476.   gluOrtho2D (0, scaleW, zRescaleRatio * scaleH, scaleH);
  477.   double step = pow (10, cli->nScaleExp);
  478.   if (cli->bShowScale) {
  479.     glColor3f (.3, .2, 0);  // lucas brown
  480.     glBegin (GL_LINES);
  481.     for (double i = 0; i <= scaleH; i += step) {
  482.       glVertex2f (0, i);
  483.       glVertex2f (scaleW, i);
  484.     }
  485.     for (i = 0; i <= scaleW; i += step) {
  486.       glVertex2f (i, 0);
  487.       glVertex2f (i, scaleH);
  488.     }
  489.     glEnd();
  490.   }
  491.   glMatrixMode (GL_PROJECTION);
  492.   glLoadIdentity();
  493.   //xMin and xMax will be clamped around object, ignoring background -- we 
  494.   //want to show background -- pixel width of data is 0 to cli->width;
  495.   //pixel width of object w/o background is cli->nFirstGood to cli->nLastGood;
  496.   //xMin and xMax are in nFirstGood to nLastGood range and need to be scaled
  497.   //to 0 to nPixels range.
  498.   float scale = (cli->xMax - cli->xMin) / (cli->nLastGood - cli->nFirstGood);
  499.   float left = cli->xMin - (scale * cli->nFirstGood);
  500.   float right = cli->xMax + (scale * (cli->width - 1 - cli->nLastGood));
  501.   float bottom = cli->zMin + (cli->zMax - cli->zMin) * zRescaleRatio;
  502.   float top = cli->zMax;
  503.   gluOrtho2D (left, right, bottom, top);
  504.   //printf ("X: 0, %d, %d, %dn", cli->nFirstGood, cli->nLastGood, nPixels);
  505.   //printf ("   %g, %g, %g, %gn", left, cli->xMin, cli->xMax, right);
  506.   //printf ("Z: %g to %gn", bottom, top);
  507.   //fflush (stdout);
  508.   for (ClipLineData** pcld = cli->data.begin(); pcld < cli->data.end();
  509.        pcld++) {
  510.     ClipLineData* cld = *pcld;
  511.     //in background, draw mesh wireframe borders (yellow)
  512.     if (cli->bShowEdges) {
  513.       glColor4f (1, 1, 0, .7);
  514.       glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  515.       glEnable (GL_BLEND);
  516.       float zDiff = (cli->zMax - cli->zMin) / 20;
  517.       for (int x = 0; x < nPixels; x++) {
  518. if (cld->lines[x] > 0) {    //this is the luminance value
  519.   if ((x+1) < nPixels && (cld->lines[x+1] > 0)) {
  520.     // next one is a mesh crossing too -- because these are likely
  521.     // to have come from a single mesh crossing at an oblique angle,
  522.     // shade the whole area between them.
  523.     glBegin (GL_QUADS);
  524.     glVertex2f (cld->objPt[x  ][0], cld->objPt[x][2  ] - zDiff);
  525.     glVertex2f (cld->objPt[x  ][0], cld->objPt[x][2  ] + zDiff);
  526.     glVertex2f (cld->objPt[x+1][0], cld->objPt[x+1][2] + zDiff);
  527.     glVertex2f (cld->objPt[x+1][0], cld->objPt[x+1][2] - zDiff);
  528.     glEnd();
  529.   } else {
  530.     glBegin (GL_LINES);
  531.     glVertex2f (cld->objPt[x][0], cld->objPt[x][2] - zDiff);
  532.     glVertex2f (cld->objPt[x][0], cld->objPt[x][2] + zDiff);
  533.     glEnd();
  534.   }
  535. }
  536.       }
  537.       glDisable (GL_BLEND);
  538.     }
  539.     
  540.     //draw data points, connected by lines (mesh's false color)
  541.     if (cli->bShowColor)
  542.       glColor3ub (cld->color[0], cld->color[1], cld->color[2]);
  543.     else
  544.       glColor3f (1, 1, 1);
  545.     glBegin (GL_LINE_STRIP);
  546.     for (int x = 0; x < nPixels; x++) {
  547.       if (!ISBACKGROUND(cld->pixels[x])) {
  548. glVertex2f (cld->objPt[x][0], cld->objPt[x][2]);
  549.       } else {
  550. if (x > 0) {
  551.   glVertex2f (cld->objPt[x-1][0], cli->zMin - 1);
  552. }
  553. if (x + 1 < nPixels) {
  554.   glEnd();
  555.   glBegin (GL_LINE_STRIP);
  556.   glVertex2f (cld->objPt[x+1][0], cli->zMin - 1);
  557. }
  558.       }
  559.       //printf ("True coords: %g %g %g -- from %d, %fn",
  560.       //cld->objX[x], cld->objY[x], cld->objZ[x], x, cld->pixels[x]);
  561.     }
  562.     glEnd();
  563.     
  564.     //now draw individual data points (green)
  565.     if (cli->bShowFramebuffPts) {
  566.       glColor3f (0, 1, 0);
  567.       float ptSize = (float)MIN (w, h) / nPixels;
  568.       if (ptSize < 1.0)  //scale point size with window -- don't want to
  569. ptSize = 1.0;    //dominate white line, but want points visible
  570.       glPointSize (ptSize);
  571.       glBegin (GL_POINTS);
  572.       for (x = 0 ; x < nPixels; x++) {
  573. if (!ISBACKGROUND(cld->pixels[x]))
  574.   glVertex2f (cld->objPt[x][0], cld->objPt[x][2]);
  575.       }
  576.       glEnd();
  577.     }
  578.   }
  579.   char legend[200];
  580.   sprintf (legend, "x range: %g (%g occupied); z range: %g",
  581.    scaleW, cli->xMax - cli->xMin, scaleH / cli->zRescale);
  582.   glLoadIdentity();
  583.   gluOrtho2D (0, w, 0, h);
  584.   glColor3f (1, 1, 1);
  585.   glRasterPos2i (2, 2);
  586.   DrawText (togl, legend);
  587.   Togl_SwapBuffers (togl);
  588. }
  589. void
  590. FreeLineDepthInfo (struct Togl* togl)
  591. {
  592.   ClipLineInfo* cli = (ClipLineInfo*)Togl_GetClientData (togl);
  593.   delete cli;
  594. }
  595. int nAnalysis = 0;             //need to change window name each time so
  596.        //tcl doesn't get mad at us for creating
  597.        //multiple windows with same name
  598. int
  599. PlvAnalyzeClipLineDepth(ClientData clientData, Tcl_Interp *interp, 
  600. int argc, char *argv[])
  601. {
  602.   struct Togl* toglAnalyze;
  603.   bool bFoundAnyData = false;
  604.   char meshNames[1000] = "";
  605.   if (theSel.type != Selection::line) {
  606.     interp->result = "You must first select a line";
  607.     return TCL_ERROR;
  608.   }
  609.   int dx = theSel[1].x - theSel[0].x;
  610.   int dy = theSel[1].y - theSel[0].y;
  611.   int x = theSel[0].x;
  612.   int y = theSel[0].y;
  613.   // force plot to go left-to-right for readability
  614.   if (dx < 0) { // so if it's not, flip it
  615.     x += dx;   dx *= -1;
  616.     y += dy;   dy *= -1;
  617.   }
  618.   int nPixels = max (abs(dx), abs(dy));
  619.   if (nPixels == 0) {
  620.     interp->result = "You must first select a line";
  621.     return TCL_ERROR;
  622.   }
  623.   
  624.   ClipLineInfo* cli = new ClipLineInfo (nPixels);
  625.   //need to unproject z-buffer data with identity modelview
  626.   glMatrixMode (GL_MODELVIEW);
  627.   glPushMatrix();
  628.   glLoadIdentity();
  629.   Unprojector unproject;
  630.   glPopMatrix();
  631.   // have to render without boundSelection, or bbox will show up
  632.   PushRenderParams();
  633.   theRenderParams->boundSelection = false;
  634.   for (DisplayableMesh** pdm = theScene->meshSets.begin();
  635.        pdm < theScene->meshSets.end();
  636.        pdm++) {
  637.     if (!(*pdm)->getVisible())
  638.       continue;
  639.     ClipLineData* cld = new ClipLineData (nPixels);
  640.     // render hidden line to back buffer and read data
  641.     theRenderParams->polyMode = GL_LINE;
  642.     theRenderParams->hiddenLine = true;
  643.     glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  644.     (*pdm)->drawSelf (false);
  645.     glReadBuffer (GL_BACK);
  646.     readLinePixels (x, y, dx, dy, GL_LUMINANCE, GL_FLOAT,
  647.     (char*)cld->lines, sizeof(cld->lines[0]));
  648.     // render polys to back buffer and read data
  649.     theRenderParams->polyMode = GL_FILL;
  650.     theRenderParams->hiddenLine = false;
  651.     glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  652.     (*pdm)->drawSelf (false);
  653.     glReadBuffer (GL_BACK);
  654.     readLinePixels (x, y, dx, dy, GL_DEPTH_COMPONENT, GL_FLOAT,
  655.     (char*)cld->pixels, sizeof(cld->pixels[0]));
  656.     //unproject data, and calculate min/max bounds on z coords
  657.     bool bFoundThisData = false;
  658.     for (int i = 0; i < nPixels; i++) {
  659.       cld->objPt[i] = unproject (x + i, y, cld->pixels[i]);
  660.       //ignore 1.0 because that's the background
  661.       if (!ISBACKGROUND(cld->pixels[i])) {
  662. bFoundThisData = true;
  663. if (!bFoundAnyData) {
  664.   bFoundAnyData = true;
  665.   cli->zMin = cli->zMax = cld->objPt[i][2];
  666.   cli->xMin = cli->xMax = cld->objPt[i][0];
  667.   cli->nFirstGood = i;
  668.   cli->nLastGood = i;
  669. } else {
  670.   if (i < cli->nFirstGood)
  671.     cli->nFirstGood = i;
  672.   if (i > cli->nLastGood)
  673.     cli->nLastGood = i;
  674.   float z = cld->objPt[i][2];
  675.   if (z < cli->zMin)
  676.     cli->zMin = z;
  677.   if (z > cli->zMax)
  678.     cli->zMax = z;
  679.   
  680.   float x = cld->objPt[i][0];
  681.   if (x < cli->xMin)
  682.     cli->xMin = x;
  683.   if (x > cli->xMax)
  684.     cli->xMax = x;
  685. }
  686.       }
  687.     }
  688.     if (bFoundThisData) {
  689.       const vec3uc& color = (*pdm)->getFalseColor();
  690.       cld->color[0] = color[0];
  691.       cld->color[1] = color[1];
  692.       cld->color[2] = color[2];
  693.       cld->theMesh = *pdm; // wsh added this line to be able to get names...
  694.       cli->data.push_back (cld);
  695.       if (bFoundAnyData)
  696. strcat (meshNames, " ");
  697. // strcat(meshNames, "_");
  698.       strcat (meshNames, (*pdm)->getName());
  699.     }
  700.   }
  701.   PopRenderParams();
  702.   if (!bFoundAnyData) {
  703.     interp->result =
  704.       "No data found.  To do line analysis, draw a line selection,n"
  705.       "and make sure it intersects a scan!";
  706.     delete cli;
  707.     return TCL_ERROR;
  708.   }
  709.   if (ISBACKGROUND (1 - (cli->zMax - cli->zMin))) {
  710.     interp->result =
  711.       "Region under clip line is too uniform to analyze!";
  712.     delete cli;
  713.     return TCL_ERROR;
  714.   }
  715.   //else printf ("min/max: %f/%fn", cli->zMin, cli->zMax);
  716.   //create toplevel containing togl
  717.   //need to size window to w pixels wide, 60 pixels tall (arbitrary)
  718.   //instead of using a script here, could call Tk_CreateWindow,
  719.   //Tk_GeometryRequest, and Togl_Widget
  720.   double xScale = cli->xMax - cli->xMin;
  721.   double zScale = cli->zMax - cli->zMin;
  722.   int defScale = (int)log10 (min (xScale, zScale) / 10);
  723.   cli->nScaleExp = defScale;  // in case tcl is fickle and doesn't send message
  724.   char script[1000];
  725.   sprintf (script, "createAnalyzeWindow %d %d %g %g %g "%s" %d",
  726.    ++nAnalysis,
  727.    nPixels, xScale,
  728.    xScale * (cli->width / (double)(cli->nLastGood - cli->nFirstGood)),
  729.    zScale, meshNames, defScale);
  730.   if (TCL_OK != Tcl_Eval (interp, script)) {
  731.     delete cli;
  732.     return TCL_ERROR;
  733.   }
  734.   char toglName[100];
  735.   sprintf (toglName, ".analyze%d.togl", nAnalysis);
  736.   toglAnalyze = toglHash.FindTogl (toglName);
  737.   assert (toglAnalyze != NULL);
  738.   
  739.   Togl_SetClientData (toglAnalyze, cli);
  740.   Togl_SetDisplayFunc (toglAnalyze, PlotLineDepth);
  741.   Togl_SetDestroyFunc (toglAnalyze, FreeLineDepthInfo);
  742.   // eval of createAnalyzeWindow set interp->result to name of window
  743.   // created -- leave it that way
  744.   return TCL_OK;
  745. }
  746. // run this function once at startup time, when we don't care what's
  747. // onscreen since it clears it, to initialize some important variables
  748. void storeMinMaxZBufferValues (void)
  749. {
  750.   if (g_bNoUI)
  751.     return;
  752.   assert (toglCurrent != NULL);
  753.   Togl_MakeCurrent (toglCurrent);
  754.   // clear z-buffer to get background z-value
  755.   glClearDepth (0.0);
  756.   glClear (GL_DEPTH_BUFFER_BIT);
  757.   glReadPixels (0, 0, 1, 1,
  758. GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, &g_zbufferMinUI);
  759.   glReadPixels (0, 0, 1, 1,
  760. GL_DEPTH_COMPONENT, GL_FLOAT, &g_zbufferMinF);
  761.   glClearDepth (1.0);  // this leaves it back at the default state
  762.   glClear (GL_DEPTH_BUFFER_BIT);
  763.   glReadPixels (0, 0, 1, 1,
  764. GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, &g_zbufferMaxUI);
  765.   glReadPixels (0, 0, 1, 1,
  766. GL_DEPTH_COMPONENT, GL_FLOAT, &g_zbufferMaxF);
  767.   //fprintf (stderr, "Z buffer range: %08x to %08x (%g to %g)n",
  768.   //   g_zbufferMinUI, g_zbufferMaxUI,
  769.   //   g_zbufferMinF, g_zbufferMaxF);
  770. }
  771. static unsigned int* ReadZBufferRect (int x, int y, int w, int h,
  772.       bool bRedraw = true)
  773. {
  774.   unsigned int* data = new unsigned int [w * h];
  775.   if (bRedraw) {
  776.     // draw scene
  777.     glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  778.     bool oldbs = theRenderParams->boundSelection;
  779.     theRenderParams->boundSelection = false;
  780.     drawInToglBuffer (toglCurrent, GL_BACK);
  781.     theRenderParams->boundSelection = oldbs;
  782.   }
  783.   // and collect z-buffer
  784.   glReadBuffer (GL_BACK);
  785.   glReadPixels (x, y, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, data);
  786.   if (glGetError()) {
  787.     delete[] data;
  788.     return NULL;
  789.   }
  790.   return data;
  791. }
  792. bool ReadZBufferArea (vector<Pnt3>& pts, const Selection& sel,
  793.       bool bIncludeBlanks, bool bRedraw,
  794.       bool bReverseBackground)
  795. {
  796.   Unprojector unproject (tbView);
  797.   if (sel.type == Selection::rect) {
  798.     int x = min (sel[0].x, sel[2].x);
  799.     int w = abs (sel[0].x - sel[2].x);
  800.     int y = min (sel[0].y, sel[2].y);
  801.     int h = abs (sel[0].y - sel[2].y);
  802.     unsigned int* data = ReadZBufferRect (x, y, w, h, bRedraw);
  803.     if (!data)
  804.       return false;
  805.     for (int iy = 0; iy < h; iy++) {
  806.       for (int ix = 0; ix < w; ix++) {
  807. int ofs = iy*w + ix;
  808. if (bReverseBackground ?
  809.     (data[ofs] > g_zbufferMinUI) :
  810.     (data[ofs] < g_zbufferMaxUI)) {
  811.   pts.push_back (unproject (x + ix, y + iy, data[ofs]));
  812. } else if (bIncludeBlanks) {
  813.   pts.push_back(Pnt3());
  814. }
  815.       }
  816.     }
  817.     delete[] data;
  818.     return true;
  819.   } else if (sel.type == Selection::shape) {
  820.     int width = theWidth;
  821.     int height = theHeight;
  822.     unsigned char* shapePix = filledPolyPixels (width, height, sel.pts);
  823.     if (!shapePix)
  824.       return false;
  825.     unsigned int* data = ReadZBufferRect (0, 0, width, height);
  826.     if (!data) {
  827.       delete[] shapePix;
  828.       return false;
  829.     }
  830.     // BUGBUG: does this need to obey bReverseBackground, bIncludeBlanks?
  831.     for (int x = 0; x < width; x++) {
  832.       for (int y = 0; y < height; y++) {
  833. int ofs = y*width + x;
  834. if (shapePix[ofs] != 0 && data[ofs] < g_zbufferMaxUI) {
  835.   pts.push_back (unproject (x, y, data[ofs]));
  836. }
  837.       }
  838.     }
  839.     delete[] shapePix;
  840.     delete[] data;
  841.     return true;
  842.   }
  843.   return false;
  844. }
  845. // from fitplane.cc
  846. void fitPnt3Plane (const vector<Pnt3>& pts, Pnt3& n, float& d, Pnt3& outCentroid);
  847. int
  848. PlvAlignToMeshBoxCmd(ClientData clientData, Tcl_Interp *interp, 
  849.      int argc, char *argv[])
  850. {
  851.   if (argc < 2) {
  852.     interp->result = "Bad args to PlvAlignToMeshBoxCmd";
  853.     return TCL_ERROR;
  854.   }
  855.   bool bDumpStats = false;
  856.   bool bAlign = false;
  857.   bool bCreatePlane = false;
  858.   bool bMoveMesh = false;
  859.   bool bDataSourceMesh = false;
  860.   for (int i = 2; i < argc; i++) {
  861.     if (!strcmp (argv[i], "align"))
  862.       bAlign = true;
  863.     else if (!strcmp (argv[i], "dumpstats"))
  864.       bDumpStats = true;
  865.     else if (!strcmp (argv[i], "createplane"))
  866.       bCreatePlane = true;
  867.     else if (!strcmp (argv[i], "movemesh"))
  868.       bMoveMesh = true;
  869.     else if (!strcmp (argv[i], "movecamera"))
  870.       bMoveMesh = false;
  871.     else if (!strcmp (argv[i], "data_mesh"))
  872.       bDataSourceMesh = true;
  873.     else if (!strcmp (argv[i], "data_zbuffer"))
  874.       bDataSourceMesh = false;
  875.     else if (!strcmp (argv[i], ""))
  876. ; // ignore possible blank params
  877.     else {
  878.       char str[200];
  879.       sprintf (str, "PlvAlignToMeshBoxCmd: unrecognized arg '%s'", argv[i]);
  880.       Tcl_SetResult (interp, str, TCL_VOLATILE);
  881.       return TCL_ERROR;
  882.     }
  883.   }
  884.   if (!(bAlign || bDumpStats || bCreatePlane)) {
  885.     interp->result = "PlvAlignToMeshBoxCmd: nothing to do";
  886.     return TCL_ERROR;
  887.   }
  888.   DisplayableMesh* meshDisp = FindMeshDisplayInfo (argv[1]);
  889.   if (!meshDisp) {
  890.     interp->result = "PlvAlignToMeshBoxCmd: missing mesh";
  891.     return TCL_ERROR;
  892.   }
  893.   RigidScan* meshFrom = meshDisp->getMeshData();
  894.   vector<Pnt3> pts;
  895.   if (bDataSourceMesh) {
  896.     VertexFilter* filter = filterFromSelection (meshFrom, theSel);
  897.     if (!filter) {
  898.       interp->result = "You must first select an area.";
  899.       return TCL_ERROR;
  900.     }
  901.     if (!meshFrom->filter_vertices (*filter, pts)) {
  902.       interp->result = "This scan does not implement filter_vertices.";
  903.       return TCL_ERROR;      
  904.     }
  905.     delete filter;
  906.   } else {
  907.     if (!ReadZBufferArea (pts, theSel)) {
  908.       interp->result = "Z-Buffer read failed";
  909.       return TCL_ERROR;
  910.     }
  911.     Xform<float> unxform = meshFrom->getXform();
  912.     unxform.fast_invert();
  913.     for_each (pts.begin(), pts.end(), unxform);
  914.   }
  915.   if (pts.size() == 0) {
  916.     char* reason;
  917.     if (bDataSourceMesh)
  918.       reason = "there are no mesh vertices there";
  919.     else
  920.       reason = "the z-buffer read failed";
  921.     char str[200];
  922.     sprintf (str, "No data was found inside the clipping rect.  Perhaps %s?",
  923.      reason);
  924.     Tcl_SetResult (interp, str, TCL_VOLATILE);
  925.     return TCL_ERROR;
  926.   }
  927.   Pnt3 norm;
  928.   float dist;
  929.   Pnt3 centroid;
  930.   fitPnt3Plane (pts, norm, dist, centroid);
  931.   // there are 3 relevant coordinate systems: the mesh coordinate system,
  932.   // which after applying mesh xform yields camera coordinate system,
  933.   // which after applying camera xform yields eye coordinate system.
  934.   // We just fit a plane in the mesh coordinate system.
  935.   if (bDumpStats) {
  936.     cout << "Fit plane to " << pts.size() << " vertices" << endl;
  937.     SHOW (norm);
  938.     SHOW (dist);
  939.   }
  940.   Pnt3 cameraNorm = norm;
  941.   Xform<float> xf = meshFrom->getXform();
  942.   xf.removeTranslation();
  943.   xf (cameraNorm);
  944.   if (bDumpStats)
  945.     SHOW (cameraNorm);
  946.   Pnt3 eyeNorm = cameraNorm;
  947.   float q[4], t[3];
  948.   tbView->getXform (q, t);
  949.   xf.fromQuaternion (q);
  950.   xf (eyeNorm);
  951.   if (bDumpStats)
  952.     SHOW (eyeNorm);
  953.   float err = 0;
  954.   for (Pnt3* pt = pts.begin(); pt < pts.end(); pt++) {
  955.     err += fabs (dot (*pt, norm) - dist);
  956.   }
  957.   float avgErr = err / pts.size();
  958.   if (bDumpStats)
  959.     SHOW (avgErr);
  960.   if (bAlign) {
  961.     // need to rotate such that eyeNorm points (0,0,1): at viewer
  962.     Pnt3 target (0, 0, 1);
  963.     // fitPnt3Plane seems to return +/- normals randomly.
  964.     // Flip the normal if necessary, to make it point up the visible z axis.  
  965.     // This will make our life easier later on....
  966.     if (eyeNorm[2] < 0) {
  967.       //alex commented this back in..the cout line
  968.       cout << "flipping plane" << endl;
  969.       target *= -1;
  970.     }
  971.     float cosTh = dot (eyeNorm, target);
  972.     if (fabs (cosTh - 1.0) > 1.e-6) {
  973.       Pnt3 axis = cross (eyeNorm, target);
  974.       
  975.       Pnt3 center;
  976.       ScreenPnt sc (0, 0);
  977.       int nPts = theSel.pts.size();
  978.       for (int i = 0; i < nPts; i++) {
  979. sc.x += theSel[i].x;
  980. sc.y += theSel[i].y;
  981.       }
  982.       sc.x /= nPts; sc.y /= nPts;
  983.       if (!findZBufferNeighbor (sc.x, sc.y, center, 5000)) {
  984. center = pts[nPts / 2];
  985. cerr << "Warning: center is guess" << endl;
  986.       }
  987.       if (bMoveMesh) {
  988. tbView->newRotationCenter (center, meshFrom);
  989. tbView->rotateAroundAxis (axis, acos(cosTh), meshFrom);
  990. theScene->computeBBox();
  991.       } else {
  992. tbView->newRotationCenter (center);
  993. tbView->rotateAroundAxis (axis, acos(cosTh));
  994.       }
  995.       
  996.       redraw (true);
  997.     } else {
  998.       cout << "Scanalyze considers it futile to try to make this any flatter"
  999.    << endl;
  1000.     }
  1001.   }
  1002.   if (bCreatePlane) {
  1003.     vector<Pnt3> vtx;
  1004.     const float sizeX = 500;   // TODO: would be nice to get these
  1005.     const float sizeY = 500;   // sizes from projection of clipping rect
  1006.     Pnt3 center = centroid;
  1007.     Pnt3 axisFake = norm;
  1008.     if (axisFake[0] != 0)
  1009.       axisFake[0] *= -1;
  1010.     else if (axisFake[1] != 0)
  1011.       axisFake[1] *= -1;
  1012.     else
  1013.       axisFake[2] *= -1;
  1014.     Pnt3 axis1 = cross (norm, axisFake);
  1015.     Pnt3 axis2 = cross (norm, axis1);
  1016.     vtx.push_back (center - sizeX * axis1);
  1017.     vtx.push_back (center - sizeY * axis2);
  1018.     vtx.push_back (center + sizeX * axis1);
  1019.     vtx.push_back (center + sizeY * axis2);
  1020.     vector<int> tris;
  1021.     tris.push_back (1);
  1022.     tris.push_back (0);
  1023.     tris.push_back (2);
  1024.     tris.push_back (2);
  1025.     tris.push_back (0);
  1026.     tris.push_back (3);
  1027.     RigidScan* scan = CreateScanFromGeometry (vtx, tris, "fit_plane");
  1028.     scan->setXform (meshFrom->getXform());
  1029.     DisplayableMesh* dm = theScene->addMeshSet (scan, false);
  1030.     Tcl_VarEval (interp, "addMeshToWindow ", dm->getName(), NULL);
  1031.   }
  1032.   return TCL_OK;
  1033. }
  1034. static void readLinePixels (int x, int y, int w, int h,
  1035.     GLenum component, GLenum type,
  1036.     char* data, int dataSize)
  1037. {
  1038.   // wrapper for glReadPixels, reads from (x,y) to (x+w, y+h) along
  1039.   // straight line
  1040.   if (abs(w) > abs(h)) { // step horizontal
  1041.     int dx = 1;
  1042.     if (w < 0) { dx *= -1; w *= -1; }
  1043.     float yy = y;
  1044.     float dy = (float)h / w;
  1045.     for (int i = 0; i < w; i++) {
  1046.       glReadPixels (x, (int)yy, 1, 1, component, type,
  1047.     (void*)data);
  1048.       x += dx;
  1049.       yy += dy;
  1050.       data += dataSize;
  1051.     }
  1052.   } else { // step vertical
  1053.     int dy = 1;
  1054.     if (h < 0) { dy *= -1; h *= -1; }
  1055.     float xx = x;
  1056.     float dx = (float)w / h;
  1057.     for (int i = 0; i < h; i++) {
  1058.       glReadPixels ((int)xx, y, 1, 1, component, type,
  1059.     (void*)data);
  1060.       y += dy;
  1061.       xx += dx;
  1062.       data += dataSize;
  1063.     }
  1064.   }
  1065. }
  1066. bool findZBufferNeighbor (int x, int y, Pnt3& neighbor, int kMaxTries)
  1067. {
  1068.   return findZBufferNeighborExt (x, y, neighbor,
  1069.  toglCurrent, tbView, kMaxTries);
  1070. }
  1071. bool findZBufferNeighborExt (int x, int y, Pnt3& neighbor,
  1072.      struct Togl* togl, Trackball* tb,
  1073.      int kMaxTries, Pnt3* rawPt, bool bRedraw,
  1074.      bool bReadExistingFromFront)
  1075. {
  1076.   // find the closest point to (x,y) (screen coordinates);
  1077.   // unproject it and return in world coordinates
  1078.   // assumes GL screen coordinates (0,0 is lower left)
  1079.   Togl_MakeCurrent (togl);
  1080.   int oldReadBuffer;
  1081.   glGetIntegerv (GL_READ_BUFFER, &oldReadBuffer);
  1082.   if (bRedraw) {
  1083.     PushRenderParams();
  1084.     if (togl == toglCurrent)
  1085.       drawInToglBuffer (togl, GL_BACK);
  1086.     else {
  1087.       //hack warning -- assumes all togls except the main one have an
  1088.       //AlignmentToglInfo; need to change this
  1089.       DrawAlignmentMeshToBack (togl);
  1090.     }
  1091.     PopRenderParams();
  1092.     glReadBuffer (GL_BACK);
  1093.   } else {
  1094.     if (bReadExistingFromFront)
  1095.       glReadBuffer (GL_FRONT);
  1096.     else
  1097.       glReadBuffer (GL_BACK);
  1098.   }
  1099.   int inX = x, inY = y;
  1100.   float z = 1.0;
  1101.   int nTries = 0;
  1102.   int dir = 0;
  1103.   int leftThisDir = 1;
  1104.   float leftNextDir = 1.0;
  1105.   int W = Togl_Width (togl);
  1106.   int H = Togl_Height (togl);
  1107.   while (nTries++ < kMaxTries) {
  1108.     // avoid testing offscreen pixels
  1109.     if (x >= 0 && y >= 0 && x < W && y < H) {
  1110.       glReadPixels (x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z);
  1111.       if (!ISBACKGROUND (z))
  1112. break;
  1113.     }
  1114.     // need to go 1R, 1U, 2L, 2D, 3R, 3U, 4L, 4D, etc.
  1115.     switch (dir) {
  1116.     case 0: x++; break;
  1117.     case 1: y++; break;
  1118.     case 2: x--; break;
  1119.     case 3: y--; break;
  1120.     }
  1121.     if (--leftThisDir == 0) {
  1122.       dir = (dir+1) % 4;
  1123.       leftThisDir = (int)(leftNextDir += .5);
  1124.     }
  1125.   }
  1126.   glReadBuffer ((GLenum) oldReadBuffer);
  1127.   if (ISBACKGROUND (z)) {
  1128.     cerr << "findZBufferNeighbor: nothing found among nearest " <<
  1129.       kMaxTries << " pixels to " << inX << ", " << inY << endl;
  1130.     return false;
  1131.   }
  1132.   Unprojector unproject (tb);
  1133.   neighbor = unproject (x, y, z);
  1134.   if (rawPt != NULL)
  1135.     rawPt->set (x, y, z);
  1136.   return true;
  1137. }
  1138. int
  1139. wsh_WarpMesh(ClientData clientData, Tcl_Interp *interp, 
  1140.      int argc, char *argv[])
  1141. {
  1142.   Mesh *theMesh = new Mesh();
  1143.   if (argc < 2) {
  1144.     interp->result = "Bad file name";
  1145.     return TCL_ERROR;
  1146.   }
  1147.   if ( theMesh->readPlyFile(argv[1]) == 0 ) {
  1148.     return TCL_ERROR;
  1149.   }
  1150.   theMesh->Warp();
  1151.   char buff[1000];
  1152.   sprintf(buff, "%s_warp", argv[1]);
  1153.   theMesh->writePlyFile(buff, 1, 0);
  1154.   return TCL_OK;
  1155. }
  1156. void
  1157. GetPtMeshMap (int w, int h, vector<DisplayableMesh*>& ptMeshMap)
  1158. {
  1159.   ptMeshMap.clear();
  1160.   ptMeshMap.insert (ptMeshMap.begin(), w*h, NULL);
  1161.   if (!theScene->meshSets.size())
  1162.     return;
  1163.   Togl_MakeCurrent (toglCurrent);
  1164.   int scale = 16;   // unimportant as long as small -- cuts into range
  1165.   drawSceneIndexColored (scale);
  1166.   
  1167.   vector<uchar> rgb;
  1168.   rgb.reserve (w * h * 4);
  1169.   glReadBuffer (GL_BACK);
  1170.   glPixelStorei (GL_PACK_ALIGNMENT, 4);
  1171.   glReadPixels (0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rgb.begin());
  1172.   int nErrors = 0;
  1173.   for (int y = 0; y < h; y++) {
  1174.     int yofs = y * w;
  1175.     for (int x = 0; x < w; x++) {
  1176.       int ofs = yofs + x;
  1177.       int ofs4 = 4 * ofs;
  1178.       uchar r = rgb[ofs4];
  1179.       uchar g = rgb[ofs4+1];
  1180.       uchar b = rgb[ofs4+2];
  1181.       int i = b * 1024 + g * 32 + r;
  1182.       i /= 8 * scale;
  1183.       i--; // since it's 0-based encoded in frame buffer, but really 0 is
  1184.       // background, and 1..n are meshes 0..n-1
  1185.       if (i < 0) {
  1186. // background, no mesh
  1187. ptMeshMap[ofs] = NULL;
  1188.       } else if (i >= 0 && i < theScene->meshSets.size()) {
  1189. //printf ("Found: %d,%d has mesh #%dn", x, y, i);
  1190. ptMeshMap[ofs] = theScene->meshSets[i];
  1191.       } else {
  1192. //printf ("Error: %d,%d has mesh #%d (rgb=%02x,%02x,%02x)n",
  1193. // x, y, i, (int)r, (int)g, (int)b);
  1194. ++nErrors;
  1195. ptMeshMap[ofs] = NULL;
  1196.       }
  1197.     }
  1198.   }
  1199.   if (nErrors)
  1200.     cerr << "Warning: " << nErrors << " pixels could not be read... "
  1201.  << "perhaps the rendering window is obscured?" << endl;
  1202. }
  1203. // Code stolen from GetPtMeshMap
  1204. // In this case we just want a list of the visible meshes in the
  1205. // current view. We return a vector of meshes. Set to NULL if the
  1206. // Mesh is invisible. Set to a pointer to the mesh, if it is visible.
  1207. void
  1208. GetPtMeshVector (int xstart, int ystart, int w, int h,
  1209.  int winwidth, int winheight,
  1210.  vector<DisplayableMesh*>& ptMeshMap)
  1211. {
  1212.   if (xstart < 0) xstart = 0;
  1213.   if (ystart < 0) ystart = 0;
  1214.   if (xstart+w > winwidth) w = winwidth-xstart;
  1215.   if (ystart+h > winheight) h = winheight-ystart;
  1216.   // printf ("%d %d %d %d %d %dn",xstart,ystart,w,h,winwidth,winheight);
  1217.   
  1218.   ptMeshMap.clear();
  1219.   // Set every mesh to NULL initially
  1220.   ptMeshMap.insert (ptMeshMap.begin(),theScene->meshSets.size(), NULL);
  1221.   if (!theScene->meshSets.size())
  1222.     return;
  1223.   Togl_MakeCurrent (toglCurrent);
  1224.   int scale = 16;   // unimportant as long as small -- cuts into range
  1225.   drawSceneIndexColored (scale);
  1226.   
  1227.   vector<uchar> rgb;
  1228.   rgb.reserve (winwidth * winheight * 4);
  1229.  
  1230.   glReadBuffer (GL_BACK);
  1231.   glPixelStorei (GL_PACK_ALIGNMENT, 4);
  1232.   glReadPixels (0, 0, winwidth, winheight, GL_RGBA, GL_UNSIGNED_BYTE, rgb.begin());
  1233.   // cerr << "Check In:" << xstart << " " << ystart << " " << w << " " << h << "n";
  1234.   int nErrors = 0;
  1235.   for (int y = ystart; y < h+ystart; y++) {
  1236.     int yofs = y * winwidth;
  1237.     for (int x = xstart; x < w+xstart; x++) {
  1238.       int ofs = yofs + x;
  1239.       int ofs4 = 4 * ofs;
  1240.       char r = rgb[ofs4];
  1241.       char g = rgb[ofs4+1];
  1242.       char b = rgb[ofs4+2];
  1243.       int i = b * 1024 + g * 32 + r;
  1244.       i /= 8 * scale;
  1245.       i--; // since it's 0-based encoded in frame buffer, but really 0 is
  1246.       // background, and 1..n are meshes 0..n-1
  1247.       if (i < 0) {
  1248. // background, no mesh
  1249.       } else if (i >= 0 && i < theScene->meshSets.size()) {
  1250. ptMeshMap[i] = theScene->meshSets[i];
  1251.       } else {
  1252. //printf ("Error: %d,%d has mesh #%d (rgb=%02x,%02x,%02x)n",
  1253. // x, y, i, (int)r, (int)g, (int)b);
  1254. ++nErrors;
  1255. ptMeshMap[ofs] = NULL;
  1256.       }
  1257.     }
  1258.   }
  1259.   if (nErrors)
  1260.     cerr << "Warning: " << nErrors << " pixels could not be read... "
  1261.  << "perhaps the rendering window is obscured?" << endl;
  1262. }
  1263. int wsh_AlignPointsToPlane(ClientData clientData, Tcl_Interp *interp, 
  1264.  int argc, char *argv[])
  1265. {
  1266.   if ( argc < 8 ) {
  1267.     interp->result = "wsh_AlignPointsToPlane: insufficient args";
  1268.     return TCL_ERROR;
  1269.   }
  1270.   DisplayableMesh* meshDisp = FindMeshDisplayInfo (argv[1]);
  1271.   if (!meshDisp) {
  1272.     interp->result = "wsh_AlignPointsToPlane: missing mesh";
  1273.     return TCL_ERROR;
  1274.   }
  1275.   RigidScan* meshFrom = meshDisp->getMeshData();  
  1276.   int x1 = atoi(argv[2]);
  1277.   int y1 = atoi(argv[3]);
  1278.   int x2 = atoi(argv[4]);
  1279.   int y2 = atoi(argv[5]);
  1280.   int x3 = atoi(argv[6]);
  1281.   int y3 = atoi(argv[7]);
  1282.   
  1283.   Pnt3 p1, p2, p3;
  1284.   printf("%i %i, %i %i, %i %in", x1, y1, x2, y2, x3, y3);
  1285.   findZBufferNeighbor(x1, y1, p1, 400);
  1286.   findZBufferNeighbor(x2, y2, p2, 400);
  1287.   findZBufferNeighbor(x3, y3, p3, 400);
  1288.   /*
  1289.   printf("%f %f %f, %f %f %f, %f %f %fn", p1[0], p1[1], p1[2],
  1290.  p2[0], p2[1], p2[2], p3[0], p3[1], p3[2]);
  1291.   */
  1292.   Pnt3 v1 = p1 - p3;
  1293.   Pnt3 v2 = p2 - p3;
  1294.   Pnt3 planeNorm = cross(v1, v2);
  1295.   planeNorm.normalize();
  1296.   Pnt3 target(0, 0, 1);
  1297.   if (planeNorm[2] < 0) {
  1298.     target *= -1;
  1299.   }
  1300.   float cosTh = dot(planeNorm, target);
  1301.   //  cout << cosTh << endl;
  1302.   Pnt3 axis = cross (planeNorm, target);  
  1303.   if (fabs (cosTh - 1.0) > 1.e-6) {
  1304.     //    axis.normalize();
  1305.     printf("z: %f %f %f, %fn", axis[0], axis[1], axis[2], cosTh);
  1306.     tbView->rotateAroundAxis (axis, acos(cosTh), meshFrom);
  1307.     theScene->computeBBox();
  1308.     redraw (true);
  1309.   } else {
  1310.     cout << "Scanalyze considers it futile to try to make this any flatter"
  1311.  << endl;
  1312.   }
  1313.   Xform<double> theXform;
  1314.   theXform.rot(acos(cosTh), axis[0], axis[1], axis[2]);
  1315.   Pnt3 tp1, tp2;
  1316.   theXform.apply(p1, tp1);
  1317.   theXform.apply(p2, tp2);
  1318.   Pnt3 planex = tp2 - tp1;
  1319.   planex.normalize();
  1320.   Pnt3 htarget(1, 0, 0);
  1321.   float hcosTh = dot(planex, htarget);
  1322.   if (fabs (hcosTh - 1.0) > 1.e-6) {
  1323.     Pnt3 haxis = cross (planex, htarget);
  1324.     
  1325.     printf("x: %f %f %f, %fn", haxis[0], haxis[1], haxis[2], hcosTh);
  1326.     tbView->rotateAroundAxis (haxis, acos(hcosTh), meshFrom);
  1327.     theScene->computeBBox();
  1328.     redraw (true);
  1329.   } else {
  1330.     cout << "Scanalyze considers it futile to try to make this any flatter"
  1331.  << endl;
  1332.   }  
  1333.   return TCL_OK;
  1334. } //wsh_AlignPointsToPlane
  1335. Auto_a_Line *lines_g = NULL;
  1336. int
  1337. PlvDrawAnalyzeLines(ClientData clientData, Tcl_Interp *interp, 
  1338.  int argc, char *argv[])
  1339. {
  1340.   if ( argc < 8 ) {
  1341.     interp->result = "wsh_DrawAnalyzeLines: incorrect number of args";
  1342.     return TCL_ERROR;
  1343.   }
  1344.   struct Togl *togl = toglHash.FindTogl(argv[1]);
  1345.   char axis = argv[2][0];
  1346.   int x0 = atoi(argv[3]);
  1347.   int y0 = atoi(argv[4]);
  1348.   int len = atoi(argv[5]);
  1349.   int space = atoi(argv[6]);
  1350.   int num = atoi(argv[7]);
  1351.   // output lines to rgb file
  1352.   lines_g = new Auto_a_Line(togl, axis, x0, y0, len, space, num);
  1353.   redraw(true);
  1354.   return TCL_OK;
  1355. }
  1356. // PlvClearAnalyzeLines
  1357. // a hack: the screen dump only seems to work correctly if called from tcl only
  1358. // but since the Auto_a_Line is created in C, I need to make a call to this 
  1359. // function to properly clean up.
  1360. int
  1361. PlvClearAnalyzeLines(ClientData clientData, Tcl_Interp *interp, 
  1362.  int argc, char *argv[])
  1363. {
  1364.   if ( lines_g != NULL ) {
  1365.     delete lines_g;
  1366.     lines_g = NULL;
  1367.     redraw(true);
  1368.     return TCL_OK;
  1369.   }
  1370.   interp->result = "Can't clear analyze lines because they are NULL";
  1371.   return TCL_ERROR;
  1372. }
  1373. // -------------------------------------
  1374. // Auto_a_Line
  1375. // the 2d lines that represent the cross sections made in
  1376. // auto-analysis
  1377. // -------------------------------------
  1378. extern DrawObjects draw_other_things;
  1379. Auto_a_Line::Auto_a_Line(Togl *_togl, char _axis, int _x0, int _y0, 
  1380.  int _len, int _space, int _num)
  1381. {
  1382.   togl = _togl;
  1383.   axis = _axis;
  1384.   x0 = _x0;
  1385.   y0 = _y0;
  1386.   len = _len;
  1387.   space = _space;
  1388.   num = _num;
  1389.   draw_other_things.add(this);
  1390. }
  1391. Auto_a_Line::~Auto_a_Line()
  1392. {
  1393.   draw_other_things.remove(this);
  1394. }
  1395. void
  1396. Auto_a_Line::drawthis()
  1397. {
  1398.   int width, height;
  1399.   
  1400.   width = Togl_Width (togl);
  1401.   height = Togl_Height (togl);
  1402.   glPushMatrix();
  1403.   
  1404.   glViewport(0, 0, width, height);
  1405.   glMatrixMode(GL_PROJECTION);
  1406.   glLoadIdentity();
  1407.   //  gluOrtho2D(-0.5, width+0.5, -0.5, height+0.5);
  1408.   gluOrtho2D(0, width, 0, height);
  1409.   
  1410.   glMatrixMode(GL_MODELVIEW);
  1411.   glLoadIdentity();
  1412.   
  1413.   glPushAttrib (GL_LIGHTING_BIT);
  1414.   glDisable (GL_LIGHTING);
  1415.   glColor3f(0, 1.0, 0);
  1416.   for ( int i = 0; i < num; i++ ) {
  1417.     glBegin(GL_LINES);
  1418.     if ( axis == 'y' ) { // 1 == y axis
  1419.       glVertex2i( x0, height - y0 - i*space );
  1420.       glVertex2i( x0 + len, height - y0 - i*space );
  1421.     } else { // x axis
  1422.       glVertex2i( x0 + i*space, y0);
  1423.       glVertex2i( x0 + i*space, y0 + len);
  1424.     }
  1425.     glEnd();
  1426.     printf("heren");
  1427.   }
  1428.   glPopAttrib();
  1429.   glPopMatrix();
  1430.   glFinish();
  1431. }