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

3D图形编程

开发平台:

Visual C++

  1. //############################################################
  2. // 
  3. // CyraResLevel.cc
  4. //
  5. // Lucas Pereira
  6. // Thu Jul 16 15:20:47 1998
  7. //
  8. // Part of CyraScan.cc,
  9. //    Store range scan information from a Cyra Cyrax Beta 
  10. //    time-of-flight laser range scanner.
  11. //
  12. //############################################################
  13. #include "CyraResLevel.h"
  14. #include <tcl.h>
  15. #include <stdio.h>
  16. #include <iostream.h>
  17. #include <fstream.h>
  18. #include <stack.h>
  19. #include <stdlib.h>
  20. #include "defines.h"
  21. #include "TriMeshUtils.h"
  22. #include "KDindtree.h"
  23. #include "ColorUtils.h"
  24. #include "plvScene.h"
  25. #include "MeshTransport.h"
  26. #include "VertexFilter.h"
  27. #ifdef WIN32
  28. #  define random rand
  29. #endif
  30. // The maximum depth distance across which it will tesselate.
  31. // (Bigger than this, it assumes a noncontinuous surface)
  32. #define DEFAULT_CYRA_TESS_DEPTH 80;
  33. float CyraTessDepth = DEFAULT_CYRA_TESS_DEPTH;
  34. // Default to filtering on...
  35. #define DEFAULT_CYRA_FILTER_SPIKES TRUE;
  36. bool CyraFilterSpikes = DEFAULT_CYRA_FILTER_SPIKES;
  37. // Default to fill holes  on...
  38. #define DEFAULT_CYRA_FILL_HOLES TRUE;
  39. bool CyraFillHoles = DEFAULT_CYRA_FILL_HOLES;
  40. //////////////////////////////////////////////////////////////////////
  41. // CyraSample   (One single data point)
  42. // Helper functions...
  43. //////////////////////////////////////////////////////////////////////
  44. void 
  45. CyraSample::zero(void) {
  46.   vtx[0] = vtx[1] = vtx[2] = 0;
  47.   nrm[0] = nrm[1] = nrm[2] = 0;
  48.   intensity = 0;
  49.   confidence = 0;
  50. }
  51.   
  52. // interp 2 samples
  53. void 
  54. CyraSample::interp(CyraSample &a, CyraSample &b) {
  55.   for (int i = 0; i < 3; i++) {
  56.     vtx[i] = 0.5 * (a.vtx[i] + b.vtx[i]);
  57.     nrm[i] = 0.5 * (a.nrm[i] + b.nrm[i]);
  58.   }
  59.   intensity = 0.5 * (a.intensity + b.intensity);
  60.   confidence = 0.5 * (a.confidence + b.confidence);
  61. }
  62. // interp 3 samples, weighted 1/4, 1/2, 1/4
  63. void 
  64. CyraSample::interp(CyraSample &a, CyraSample &b, CyraSample &c) {
  65.   for (int i = 0; i < 3; i++) {
  66.     vtx[i] = 0.25 * (a.vtx[i] + b.vtx[i]+b.vtx[i] + c.vtx[i]);
  67.     nrm[i] = 0.25 * (a.nrm[i] + b.nrm[i]+b.nrm[i] + c.nrm[i]);
  68.   }
  69.   intensity = 0.25 * (a.intensity + b.intensity+b.intensity + c.intensity);
  70.   confidence = 0.25 * (a.confidence + b.confidence+b.confidence + 
  71.        c.confidence);
  72. }
  73.  
  74. // Interpolate arbitrary number of samples, weighted evenly...
  75. void 
  76. CyraSample::interp(int nsamps, CyraSample *samps[]) {
  77.   assert(nsamps > 0);
  78.   this->zero();
  79.   float wt = 1.0 / nsamps;
  80.   // add up the values of every sample...
  81.   for (int samnum = 0; samnum < nsamps; samnum++) {
  82.     for (int i=0; i < 3; i++) {
  83.       vtx[i] += samps[samnum]->vtx[i];
  84.       nrm[i] += samps[samnum]->nrm[i];
  85.     }
  86.     intensity += samps[samnum]->intensity;
  87.     confidence += samps[samnum]->confidence;
  88.   }
  89.   // divide by the appropriate weight...
  90.   for (int i=0; i < 3; i++) {
  91.     vtx[i] /= wt;
  92.     nrm[i] /= wt;
  93.   }
  94.   intensity /= wt;
  95.   confidence /= wt;
  96. }
  97.  
  98. bool 
  99. CyraSample::isValid(void) {
  100.   return((vtx[2] > 0) ? TRUE : FALSE);
  101. }
  102. //////////////////////////////////////////////////////////////////////
  103. // CyraResLevel  (one resolution level for a cyra scan)
  104. //////////////////////////////////////////////////////////////////////
  105.  
  106. CyraResLevel::CyraResLevel(void) {
  107.   // Clear arrays
  108.   width = 0;
  109.   height = 0;
  110.   numpoints = 0;
  111.   numtris = 0;
  112.   points.clear();
  113.   tris.clear();
  114.   origin.set(0,0,0);
  115.   isDirty_cache = true;
  116.   cachedPoints.clear();
  117.   cachedNorms.clear();
  118.   cachedBoundary.clear();
  119.   kdtree = NULL;
  120. }
  121. CyraResLevel::~CyraResLevel(void) {
  122.   // do nothing yet
  123.   if (kdtree) delete kdtree;
  124. }
  125. // PUSH_TRI --  basically a macro used by the mesh-generation function
  126. // to look up the 3 vertices in vert_inds, and do tstrips if necessary
  127. inline void PUSH_TRI(int &ov2, int &ov3, vector<int> &tri_inds,
  128.       const bool stripped,  
  129.       const vector<int> &vert_inds,
  130.       const int v1, const int v2, const int v3)
  131.   // will next tri be odd or even? (even tris get flipped)
  132.   static bool oddtri = true; 
  133.   if (stripped) { 
  134.     if (oddtri && (ov2 == v2 && ov3 == v1)) { 
  135.       // odd-numbered triangle
  136.       tri_inds.push_back(vert_inds[v3]); 
  137.       oddtri = false;
  138.     } else if (!oddtri && (ov2 == v1 && ov3 == v3)) { 
  139.       // even-numbered triangle -- listed backwards 
  140.       tri_inds.push_back(vert_inds[v2]); 
  141.       oddtri = true;
  142.     } else { 
  143.       tri_inds.push_back(-1); 
  144.       tri_inds.push_back(vert_inds[v1]); 
  145.       tri_inds.push_back(vert_inds[v2]); 
  146.       tri_inds.push_back(vert_inds[v3]); 
  147.       oddtri = false;
  148.     } 
  149.     ov2 = v2; 
  150.     ov3 = v3; 
  151.   } else {  
  152.     tri_inds.push_back(vert_inds[v1]); 
  153.     tri_inds.push_back(vert_inds[v2]); 
  154.     tri_inds.push_back(vert_inds[v3]); 
  155.   } 
  156. }
  157.      
  158. // Add the geometry for this reslevel to the list
  159. MeshTransport*
  160. CyraResLevel::mesh(bool perVertex, bool stripped,
  161.    ColorSource color, int colorSize)
  162. {
  163.   // Offset (index) for the next vertex;
  164.   int vertoffset = 0;
  165.   ////// Vertices /////
  166.   // The valid vertices need contiguous index numbers.  So fill an
  167.   // array vert_inds -- index numbers with a 1-1 correspondence
  168.   // to the array of vertices.
  169.   vector<int> vert_inds;
  170.   vert_inds.reserve(points.size());
  171.   // Set the vert_inds array
  172.   for (int i = 0; i < points.size(); i++) {
  173.     vert_inds.push_back((points[i].confidence > 0) ? 
  174. vertoffset++ : -1);
  175.   }
  176.   vector<Pnt3>* vtx = new vector<Pnt3>;
  177.   vector<short>* nrm = new vector<short>;
  178.   vector<int>* tri_inds = new vector<int>;
  179.   // Add each valid vertex to vtx, nrm(?)
  180.   FOR_EACH_VERT(vtx->push_back(v->vtx));
  181.   if (perVertex) {
  182.     FOR_EACH_VERT(nrm->insert (nrm->end(), v->nrm, v->nrm + 3));
  183.   } else {
  184.     FOR_EACH_TRI(pushNormalAsShorts
  185.  (*nrm, ((Pnt3)cross(points[tv3].vtx-points[tv2].vtx, 
  186.      points[tv1].vtx-points[tv2].vtx))
  187.   .normalize()));
  188.   }
  189.   ////// Triangles /////
  190.   // Now fill in the triangle array
  191.   // Initialize the "old v2, v3" values used in tstripping
  192.   int ov2 = -1; int ov3 = -1;
  193.   // call the FOR_EACH_TRI macro, which defines tv1, tv2, tv3.
  194.   FOR_EACH_TRI(PUSH_TRI(ov2, ov3, *tri_inds, stripped, 
  195. vert_inds, tv1, tv2, tv3));
  196.   // Terminate the last tstrip
  197.   if (stripped) {
  198.     tri_inds->push_back(-1);
  199.   }
  200.   MeshTransport* mt = new MeshTransport;
  201.   mt->setVtx (vtx, MeshTransport::steal);
  202.   mt->setNrm (nrm, MeshTransport::steal);
  203.   mt->setTris (tri_inds, MeshTransport::steal);
  204.   if (color != RigidScan::colorNone) {
  205.     vector<uchar>* colors = new vector<uchar>;
  206.     int nColors = perVertex ? vtx->size() : num_tris();
  207.     colors->reserve (colorSize * nColors);
  208.     if (colorMesh (*colors, perVertex, color, colorSize))
  209.       mt->setColor (colors, MeshTransport::steal);
  210.     else
  211.       delete colors;
  212.   }
  213.   return mt;
  214. }
  215. // Fill in the colors array.
  216. bool 
  217. CyraResLevel::colorMesh(vector<uchar>   &colors,
  218. bool             perVertex,
  219. ColorSource      source,
  220. int              colorsize)
  221. {
  222.   switch (source) {
  223.   case RigidScan::colorConf:
  224.     // ========= Color by Confidence =========
  225.     if (perVertex) {
  226.       cerr << "adding per-vertex conf color..." << endl;
  227.       // per-vertex confidence
  228.       FOR_EACH_VERT(pushColor(colors, colorsize, (float)
  229.       (v->confidence / 
  230.        CYRA_DEFAULT_CONFIDENCE)));
  231.     } else {
  232.       cerr << "adding per-face conf color..." << endl;
  233.       // per-face confidence (take min of 3 confidences)
  234.       FOR_EACH_TRI(pushColor(colors, colorsize, (float)
  235.      (MIN(points[tv1].confidence,
  236.        MIN(points[tv2].confidence,
  237.    points[tv3].confidence)) / 
  238.    CYRA_DEFAULT_CONFIDENCE)));
  239.     }
  240.     break;
  241.   case RigidScan::colorIntensity:
  242.     // ========= Color by Intensity =========
  243.     if (perVertex) {
  244.       // per-vertex intensity
  245.       FOR_EACH_VERT(pushColor(colors, colorsize, (float)
  246.       ((v->intensity+2048.0) / 4096)));
  247.     } else {
  248.       // per-face intensity (take min of 3 intensitys)
  249.       FOR_EACH_TRI(pushColor(colors, colorsize, (float)
  250.      ((MIN(points[tv1].intensity,
  251.    MIN(points[tv2].intensity,
  252.        points[tv3].intensity)) + 2048.0) /
  253.       4096)));
  254.     }
  255.   case RigidScan::colorTrue:
  256.     // ========== Color TrueColor ==========
  257.     if (perVertex) {
  258.       // per-vertex TrueColor
  259.       // BUGBUG: For now, just color using intensity, because
  260.       // I don't yet store colors for CyraScans.
  261.       FOR_EACH_VERT(pushColor(colors, colorsize, (float)
  262.       ((v->intensity+2048.0) / 4096)));
  263.     } else {
  264.       // per-face TrueColor (take avg of 3 TrueColors)
  265.       FOR_EACH_TRI(pushColor(colors, colorsize, (float)
  266.      ((MIN(points[tv1].intensity,
  267.    MIN(points[tv2].intensity,
  268.        points[tv3].intensity)) + 2048.0) /
  269.       4096)));
  270.     }
  271.   case RigidScan::colorBoundary:
  272.     {
  273.       create_kdtree();  // BUGBUG, this is a little heavyhanded approach
  274.       colors.reserve (colorsize * cachedBoundary.size());
  275.       bool* end = cachedBoundary.end();
  276.       for (bool* c = cachedBoundary.begin(); c < end; c++)
  277. pushConf (colors, colorsize, (uchar)(*c ? 0 : 255));
  278.     }
  279.     break;
  280.   default:
  281.     cerr << "Unhandled Color Mode.  colorsource = " << source << endl;
  282.     return false;
  283.   }
  284.   return true;
  285. }
  286. bool
  287. CyraResLevel::ReadPts(const crope &inname) 
  288. {
  289.   // open the input .pts file
  290.   const char* filename = inname.c_str();
  291.   FILE *inFile = fopen(filename, "r");
  292.   if (inFile==NULL) return FALSE;
  293.   bool isOldPtsFormat = false; // old or new cyra .pts?
  294.   // Read the 3-line .pts header
  295.   fscanf(inFile, "%dn", &width);
  296.   fscanf(inFile, "%dn", &height);
  297.   float a,b,c;
  298.   fscanf(inFile, "%f %f %fn", &a, &b, &c);
  299.   origin.set(a,b,c);
  300.   cerr << "Reading " << width << "x" << height << " Cyra scan...";
  301.   // Read in the points, since this is the only data actually in
  302.   // a .pts file....
  303.   CyraSample samp;
  304.   // Figure out whether it's the old or new cyra format
  305.   // old: X new: X
  306.   //      Y       Y
  307.   //      0 0 0 0 0 0
  308.   //    x1 y1 z1 c1 nx1 ny1 nz1 1 0 0
  309.   //    x2 y2 z2 c2 nx2 ny2 nz2 0 1 0
  310.   //    x3 y3 z3 c3 nx3 ny3 nz3 0 0 1
  311.   //    ...                   1 0 0 0
  312.   //                         0 1 0 0 
  313.   //                           0 0 1 0
  314.   //                         0 0 0 1
  315.   // x1 y1 z1 c1
  316.   // x2 y2 z2 c2
  317.   // ...
  318.   char buf[2000];
  319.   int n1, n2, n3;
  320.   // Read first line after 0 0 0 
  321.   fgets(buf, 2000, inFile);
  322.   int nitems = sscanf(buf, "%g %g %g %d %d %d %dn", 
  323.       &(samp.vtx[0]), &(samp.vtx[1]), &(samp.vtx[2]), 
  324.       &(samp.intensity),
  325.       &n1, &n2, &n3);
  326.   if (nitems == 7) {
  327.     // was the x1 y1 z1 c1 nx1 ny1 nz1 line... old format
  328.     isOldPtsFormat = true;
  329.     cerr << " (old format) ";
  330.   } else if (nitems == 3) {
  331.     // was the new format
  332.     isOldPtsFormat = false;
  333.     cerr << " (new format) ";
  334.     // NOTE:  Skip (ignore) the 3+4 matrix lines
  335.     for (int j=0; j < 7; j++) {
  336.       fgets(buf, 2000,inFile);
  337.     }
  338.   }
  339.   // Now, our assertion is that first line of data is read into
  340.   // buf...
  341.   // First reserve space, so we don't waste time doing multi mallocs...
  342.   points.reserve(width * height);
  343.   for (int x=0; x < width; x++) {
  344.     for (int y=0; y < height; y++) {
  345.       // Read position, intensity, normals
  346.       Pnt3 filenrm;
  347.       // Whether isOldPtsFormat or not, just ignore the normals that
  348.       // are in the .pts file, for now...  Since the normals Cyra generates
  349.       // are generally bogus anyways.
  350.       int nread = sscanf(buf, "%f %f %f %dn", 
  351.  &(samp.vtx[0]), &(samp.vtx[1]), &(samp.vtx[2]), 
  352.  &(samp.intensity));
  353.       fgets(buf, 2000, inFile);
  354.       if (nread != 4) {
  355. int lineno = ((isOldPtsFormat)?4:11) + x*height + y;
  356. cerr << "Error: Trouble reading Cyra input line " << lineno 
  357.      << "." << endl;
  358. return false;
  359.       }
  360.      
  361.       samp.nrm[0] = 0; samp.nrm[1] = 0; samp.nrm[2] = 32767;
  362.       // Convert to millimeters
  363.       samp.vtx *= 1000.0;
  364.       // Compute confidence 
  365.       if (samp.vtx[0] == 0. && samp.vtx[1] == 0. &&
  366.   samp.vtx[2] == 0. && samp.intensity == 0) {
  367. // then point is missing data
  368. samp.confidence = 0.0;
  369.       } else {
  370. samp.confidence = CYRA_DEFAULT_CONFIDENCE;
  371. // count number of valid points
  372. numpoints++;
  373.  
  374. // unweight specular highlights -- linearly
  375. // make the weight falloff to 0 between intensities
  376. // -800 and 2048
  377. if (samp.intensity > -800) {
  378.   float unweightfactor = (2048.0 - samp.intensity) / 
  379.     (2048.0 - (-800));
  380.   samp.confidence *= unweightfactor;
  381. }
  382. // also make the weight falloff between -1600 and -2048
  383. if (samp.intensity < -1600) {
  384.   float unweightfactor = (2048.0 + samp.intensity) / 
  385.     (2048.0 - 1600.0);
  386.   samp.confidence *= unweightfactor;
  387. }
  388.       }
  389.     
  390.       // Now put the vertex into the array
  391.       points.push_back(samp);
  392.     }
  393.   }
  394.   cerr << "done." << endl;
  395.   // Now actually figure out the "correct" tesselation
  396.   // first reserve space, so we don't waste time doing multi mallocs...
  397.   tris.reserve((width-1) * (height-1));
  398.   // Grab the CyraTessDepth from TCL...
  399.   char* CTDstring = Tcl_GetVar (g_tclInterp, "CyraTessDepth", TCL_GLOBAL_ONLY);
  400.   if (CTDstring == NULL) {
  401.     CyraTessDepth = DEFAULT_CYRA_TESS_DEPTH;
  402.   } else {
  403.     // String defined, get it...?
  404.     sscanf(CTDstring, "%f", &CyraTessDepth);
  405.     // If 0, then set to default
  406.     if (CyraTessDepth == 0) {
  407.       CyraTessDepth = DEFAULT_CYRA_TESS_DEPTH;
  408.     }
  409.   }
  410.   // Grab the CyraFilterSpikes from TCL...
  411.   char* CFSstring = Tcl_GetVar (g_tclInterp, "CyraFilterSpikes", TCL_GLOBAL_ONLY);
  412.   if (CFSstring == NULL) {
  413.     CyraFilterSpikes = DEFAULT_CYRA_FILTER_SPIKES;
  414.   } else {
  415.     // String defined, get it...?
  416.     int CFSval;
  417.     sscanf(CFSstring, "%d", &CFSval);
  418.     CyraFilterSpikes = (CFSval == 0) ? FALSE : TRUE;
  419.   }
  420.   // Grab the CyraFillHoles from TCL...
  421.   char* CFHstring = Tcl_GetVar (g_tclInterp, "CyraFillHoles", TCL_GLOBAL_ONLY);
  422.   if (CFHstring == NULL) {
  423.     CyraFillHoles = DEFAULT_CYRA_FILTER_SPIKES;
  424.   } else {
  425.     // String defined, get it...?
  426.     int CFHval;
  427.     sscanf(CFHstring, "%d", &CFHval);
  428.     CyraFillHoles = (CFHval == 0) ? FALSE : TRUE;
  429.   }
  430.   ////////////// Filter out spikes?  ///////////
  431.   if (CyraFilterSpikes) {
  432.     cerr << "Filtering out high-intensity spikes....";
  433.     for (x=0; x < width-1; x++) {
  434.       for (int y=0; y < height-1; y++) {
  435. CyraSample *v1 = &(point(x,y));
  436. // Look for random single spikes of noise...
  437. float myZ  = v1->vtx[2];
  438. int myI = v1->intensity;
  439. float neighborZ = 0;
  440. float neighborI = 0;
  441. float neighborWt = 0;
  442. int neighborsDeeper = 0;
  443. int neighborsCloser = 0;
  444.       // over 3x3 neighborhood...
  445.       // within 300mm depth...
  446. for (int nex = MAX(0,x-1); nex <= MIN(width-1, x+1); nex++) {
  447.   for (int ney = MAX(0,y-1); ney <= MIN(width-1, y+1); ney++) {
  448.     CyraSample *ne = &point(nex, ney);
  449.     if (ne->vtx[2] < myZ) neighborsDeeper++;
  450.     else neighborsCloser++;
  451.     if (ne->vtx[2] > myZ - 150 && ne->vtx[2] < myZ + 150 &&
  452. (nex != x || ney != y) && ne->intensity < myI) {
  453.       float neWt = myI - ne->intensity;
  454.       neighborZ += ne->vtx[2] * neWt;
  455.       neighborI += ne->intensity *neWt;
  456.       neighborWt += neWt;
  457.     }
  458.   }
  459. }
  460. if (neighborWt != 0) {
  461.   neighborZ /= neighborWt;
  462.   neighborI /= neighborWt;
  463.       
  464.   if (neighborsDeeper <=2 && neighborsCloser >= 5 &&
  465.     myI > neighborI + 20) {
  466.     // This point seems to be farther away, and brighter, than
  467.     // most of it's neighbors... We think it's the funny artifact...
  468.     //cerr << "before dd: " << (myZ-neighborZ) << " " << (myI-neighborI) 
  469.     //     << " depths: " << myZ << " , " << neighborZ << " ; intens: " 
  470.     //     << myI << " , " << neighborI << endl;
  471.     float posScale = neighborZ / myZ;
  472.     v1->vtx[0] *= posScale;
  473.     v1->vtx[1] *= posScale;
  474.     v1->vtx[2] *= posScale;
  475.     v1->intensity = neighborI;
  476.   }
  477. }
  478.       }  // end of filtering spikes...
  479.     }
  480.     cerr << "Done! (filtering)n";
  481.   }
  482.   ////////////// Fill holes? ///////////
  483.   if (CyraFillHoles) {
  484.     cerr << "Filling Tiny Holes....";
  485.     for (x=0; x < width-1; x++) {
  486.       for (int y=0; y < height-1; y++) {
  487. CyraSample *v1 = &(point(x,y));
  488. float myZ  = v1->vtx[2];
  489. float neighborsZ = 0;
  490. float neighborsWt = 0;
  491. int xstart = MAX(0, x-1);
  492. int ystart = MAX(0, y-1);
  493. int xend = MIN(width-1, x+1);
  494. int yend = MIN(height-1, y+1);
  495. // over 3x3 neighborhood...
  496. // find the mean...
  497. for (int nex = xstart; nex <= xend; nex++) {
  498.   for (int ney = ystart; ney <= yend; ney++) {
  499.     CyraSample *ne = &point(nex, ney);
  500.     if (nex != x || ney != y) {
  501.       neighborsZ += ne->vtx[2];
  502.       neighborsWt += 1.0;
  503.     }
  504.   }
  505. }
  506. neighborsZ /= neighborsWt;
  507. // Find the neighbor closest to the mean...
  508. // over 3x3 neighborhood...
  509. float closestZ = point(xstart, ystart).vtx[2];
  510. float closestDZ2 = (neighborsZ-closestZ)*(neighborsZ-closestZ);
  511. for (nex = xstart; nex <= xend; nex++) {
  512.   for (int ney = ystart; ney <= yend; ney++) {
  513.     CyraSample *ne = &point(nex, ney);
  514.     float neDZ2 = (neighborsZ-ne->vtx[2])*(neighborsZ-ne->vtx[2]);
  515.     if (neDZ2 < closestDZ2) {
  516.       closestDZ2 = neDZ2;
  517.       closestZ = ne->vtx[2];
  518.     }
  519.   }
  520. }
  521. // Set neighborsZ to be closestZ
  522. // (this way, if we have one outlier, we'll still grab from the
  523. // z depth of the main cluster...)
  524. neighborsZ = closestZ;
  525. // Make sure the neighbors are clustered closely together...
  526. // say, within 150mm of each other...?
  527. int neighborsClose = 0;
  528. float neighborX = 0;
  529. float neighborY = 0;
  530. float neighborZ = 0;
  531. float neighborI = 0;
  532. float neighborConf = 0;
  533. for (nex = xstart; nex <= xend; nex++) {
  534.   for (int ney = ystart; ney <= yend; ney++) {
  535.     CyraSample *ne = &point(nex, ney);
  536.     if ((nex != x || ney != y) &&
  537. (ne->vtx[2] < neighborsZ + CyraTessDepth && 
  538.  ne->vtx[2] > neighborsZ - CyraTessDepth)) {
  539.       neighborsClose++;
  540.       neighborX += ne->vtx[0];
  541.       neighborY += ne->vtx[1];
  542.       neighborZ += ne->vtx[2];
  543.       neighborI += ne->intensity;
  544.       neighborConf += ne->confidence;
  545.     }
  546.   }
  547. }
  548. //cerr <<" "<<neighborsClose<< ", nz " <<neighborsZ<< " , myz " <<myZ<< endl;
  549. // Only fill holes of data off by more than 150mm...
  550. // e.g. make sure this point is far from the neighborhood,
  551. if (neighborsWt < 7 || neighborsClose < 7 || 
  552.     (neighborsZ < myZ + CyraTessDepth && 
  553.      neighborsZ > myZ - CyraTessDepth)) continue;
  554. // otherwise, modify the puppy....
  555. v1->vtx[0] = neighborX / neighborsClose;
  556. v1->vtx[1] = neighborY / neighborsClose;
  557. v1->vtx[2] = neighborZ / neighborsClose;
  558. v1->intensity = neighborI / neighborsClose;
  559. v1->confidence = neighborConf / neighborsClose;
  560.       }  // end of filling holes...
  561.     }
  562.     cerr << "Done! (filling holes)n";
  563.   }
  564.   
  565.   ////////////// Generate the Tesselation ///////////
  566.   cerr << "Generating tesselation...";
  567.   for (x=0; x < width-1; x++) {
  568.     for (int y=0; y < height-1; y++) {
  569.       // get pointers to the four vertices surrounding this
  570.       // square:
  571.       // 2 4 
  572.       // 1 3
  573.       CyraSample *v1 = &(point(x,y));
  574.       CyraSample *v2 = &(point(x,y+1));
  575.       CyraSample *v3 = &(point(x+1,y));
  576.       CyraSample *v4 = &(point(x+1,y+1));
  577.       CyraTess tess = TESS0;
  578.       // Set mask bit to be true if a vertex:
  579.       //   a) exists (has confidence)
  580.       //   b) is not an occlusion edge
  581.       unsigned int mask = 
  582. ((v4->confidence && !grazing(v3->vtx, v4->vtx, v2->vtx))? 8 : 0) +
  583. ((v3->confidence && !grazing(v1->vtx, v3->vtx, v4->vtx))? 4 : 0) +
  584. ((v2->confidence && !grazing(v4->vtx, v2->vtx, v1->vtx))? 2 : 0) +
  585. ((v1->confidence && !grazing(v2->vtx, v1->vtx, v3->vtx))? 1 : 0);
  586.       switch (mask) {
  587.       case 15:
  588. // verts: 1 2 3 4 
  589. tess = TESS14;
  590. numtris += 2;
  591. break;
  592.       case 14:
  593. // verts: 2 3 4 
  594. tess = TESS4;
  595. numtris++;
  596. break;
  597.       case 13:
  598. // verts: 1 3 4
  599. tess = TESS3;
  600. numtris++;
  601. break;
  602.       case 11:
  603. // verts 1 2 4
  604. tess = TESS2;
  605. numtris++;
  606. break;
  607.       case 7:
  608. // verts 1 2 3
  609. tess = TESS1;
  610. numtris++;
  611. break;
  612.       default:
  613. // two or less vertices
  614. tess = TESS0;
  615. break;
  616.       }
  617.       // Now put the tesselation into the array
  618.       tris.push_back(tess);
  619.     }
  620.   }
  621.   cerr << "Done! (tesselating)" << endl;
  622.   CalcNormals();
  623.   cerr << "Loaded " << numpoints << " vertices, " <<
  624.     numtris << " triangles." << endl;
  625.   return true;
  626. }
  627. bool
  628. CyraResLevel::WritePts(const crope &outname) 
  629. {
  630.   CyraSample samp;
  631.   // open the output .pts file
  632.   const char* filename = outname.c_str();
  633.   FILE *outFile = fopen(filename, "w");
  634.   if (outFile==NULL) {
  635.     cerr << "Error: couldn't open output file " << filename << endl;
  636.     return FALSE;
  637.   }
  638.   // compute bounds, so we can crop to the smallest rectangle
  639.   // that contains all the data.
  640.   int lox   = width-1;
  641.   int hix   = 0;
  642.   int loy   = height-1;
  643.   int hiy   = 0;
  644.   for (int x=0; x < width; x++) {
  645.     for (int y=0; y < height; y++) {
  646.       samp = point(x,y);
  647.       if (samp.confidence != 0) {
  648.   lox = (x<lox) ? x : lox;
  649.   hix = (x>hix) ? x : hix;
  650. loy = (y<loy) ? y : loy;
  651. hiy = (y>hiy) ? y : hiy;
  652.       }
  653.     }
  654.   }
  655.   if (lox > hix || loy > hiy) {
  656.     cerr << "Error:  no nonzero-points found.  Aborting..." << endl;
  657.     return FALSE;
  658.   }
  659.   // Write the 3-line .pts header
  660.   fprintf(outFile, "%dn", hix - lox + 1);
  661.   fprintf(outFile, "%dn", hiy - loy + 1);
  662.   fprintf(outFile, "%f %f %fn", origin[0], origin[1], origin[2]);
  663.   cerr << "Writing " << (hix-lox+1) << "x" << (hiy-loy+1) << " Cyra scan...";
  664.   // Write out the points, since this is the only data actually in
  665.   // a .pts file....
  666.   for (x=lox; x <= hix; x++) {
  667.     for (int y=loy; y <= hiy; y++) {
  668.       samp = point(x,y);
  669.       if (samp.confidence == 0) {
  670. fprintf(outFile, "0 0 0 0 0 0 0n");
  671.       } else {
  672. // divide by 1000, since .pts files are always in meters
  673. fprintf(outFile, "%.5f %.5f %.5f %d 0 0 1n", 
  674. samp.vtx[0]/1000.0, samp.vtx[1]/1000.0, samp.vtx[2]/1000.0,
  675. samp.intensity);
  676.       }
  677.     }
  678.   }
  679.   fclose(outFile);
  680.   cerr << "Done." << endl;
  681.   return TRUE;
  682. }
  683. // Recompute the normals
  684. void
  685. CyraResLevel::CalcNormals(void)
  686. {
  687.   // Compute Normals
  688.   Pnt3 hedge, vedge, norm;
  689.   Pnt3 v1, v2, v3, v4;
  690.   CyraTess tess;
  691.   
  692.   for (int x=0; x < width; x++) {
  693.     for (int y=0; y < height; y++) {
  694.       if (point(x,y).confidence > 0) {
  695. hedge.set(0,0,0);
  696. vedge.set(0,0,0);
  697. // Lower left corner
  698. if (x >0 && y > 0) {
  699.   v1 = point(x-1, y-1).vtx;
  700.   v2 = point(x-1, y  ).vtx;
  701.   v3 = point(x  , y-1).vtx;
  702.   v4 = point(x  , y  ).vtx;
  703.   tess = tri(x-1, y-1);
  704.   switch (tess) {
  705.   case TESS2:
  706.     hedge += 0.5*(v4-v2);
  707.     vedge += 0.5*(v2-v1);
  708.     break;
  709.   case TESS3:
  710.     hedge += 0.5*(v3-v1);
  711.     vedge += 0.5*(v4-v3);
  712.     break;
  713.   case TESS4:
  714.   case TESS14:
  715.     hedge += 1.0*(v4-v2);
  716.     vedge += 1.0*(v4-v3);
  717.     break;
  718.   case TESS23:
  719.     hedge += 0.5*(v4-v2);
  720.     hedge += 0.5*(v3-v1);
  721.     vedge += 0.5*(v2-v1);
  722.     vedge += 0.5*(v4-v3);
  723.     break;
  724.   }
  725. }
  726. // Upper left corner
  727. if (x > 0 && y < height-1) {
  728.   v1 = point(x-1,y  ).vtx;
  729.   v2 = point(x-1,y+1).vtx;
  730.   v3 = point(x  ,y  ).vtx;
  731.   v4 = point(x  ,y+1).vtx;
  732.   tess = tri(x-1,y);
  733.   switch (tess) {
  734.   case TESS1:
  735.     hedge += 0.5*(v3-v1);
  736.     vedge += 0.5*(v2-v1);
  737.     break;
  738.   case TESS3:
  739.   case TESS23:
  740.     hedge += 1.0*(v3-v1);
  741.     vedge += 1.0*(v4-v3);
  742.     break;
  743.   case TESS4:
  744.     hedge += 0.5*(v4-v2);
  745.     vedge += 0.5*(v4-v3);
  746.     break;
  747.   case TESS14:
  748.     hedge += 0.5*(v4-v2);
  749.     hedge += 0.5*(v3-v1);
  750.     vedge += 0.5*(v2-v1);
  751.     vedge += 0.5*(v4-v3);
  752.     break;
  753.   }
  754. }
  755. // Lower right corner
  756. if (x < width-1 && y > 0) {
  757.   v1 = point(x  ,y-1).vtx;
  758.   v2 = point(x  ,y  ).vtx;
  759.   v3 = point(x+1,y-1).vtx;
  760.   v4 = point(x+1,y  ).vtx;
  761.   tess = tri(x,y-1);
  762.   switch (tess) {
  763.   case TESS1:
  764.     hedge += 0.5*(v3-v1);
  765.     vedge += 0.5*(v2-v1);
  766.     break;
  767.   case TESS2:
  768.   case TESS23:
  769.     hedge += 1.0*(v4-v2);
  770.     vedge += 1.0*(v2-v1);
  771.     break;
  772.   case TESS4:
  773.     hedge += 0.5*(v4-v2);
  774.     vedge += 0.5*(v4-v3);
  775.     break;
  776.   case TESS14:
  777.     hedge += 0.5*(v4-v2);
  778.     hedge += 0.5*(v3-v1);
  779.     vedge += 0.5*(v2-v1);
  780.     vedge += 0.5*(v4-v3);
  781.     break;
  782.   }
  783. }
  784. // Upper right corner
  785. if (x < width-1 && y < height-1) {
  786.   v1 = point(x  ,y  ).vtx;
  787.   v2 = point(x  ,y+1).vtx;
  788.   v3 = point(x+1,y  ).vtx;
  789.   v4 = point(x+1,y+1).vtx;
  790.   tess = tri(x,y);
  791.   switch (tess) {
  792.   case TESS1:
  793.   case TESS14:
  794.     hedge += 1.0*(v3-v1);
  795.     vedge += 1.0*(v2-v1);
  796.     break;
  797.   case TESS2:
  798.     hedge += 0.5*(v4-v2);
  799.     vedge += 0.5*(v2-v1);
  800.     break;
  801.   case TESS3:
  802.     hedge += 0.5*(v3-v1);
  803.     vedge += 0.5*(v4-v3);
  804.     break;
  805.   case TESS23:
  806.     hedge += 0.5*(v4-v2);
  807.     hedge += 0.5*(v3-v1);
  808.     vedge += 0.5*(v2-v1);
  809.     vedge += 0.5*(v4-v3);
  810.     break;
  811.   }
  812. }
  813. // Now compute cross product, save normal
  814. norm = cross(hedge, vedge);
  815. norm.normalize();
  816. norm *= 32767;
  817. point(x, y).nrm[0] = norm[0];
  818. point(x, y).nrm[1] = norm[1];
  819. point(x, y).nrm[2] = norm[2];
  820.       }
  821.     }
  822.   }
  823. }
  824. // detects grazing tris
  825. bool
  826. CyraResLevel::grazing(Pnt3 v1, Pnt3 v2, Pnt3 v3)
  827. {
  828. #if 0
  829.   // First compute (negative) norm, which should point pretty 
  830.   // much away from the origin.  Compare this to the vector
  831.   // from the origin....
  832.   Pnt3 edge1 = v3 - v2;
  833.   Pnt3 edge2 = v2 - v1;
  834.   Pnt3 norm = cross(edge1, edge2);
  835.   norm.normalize();
  836.   // Treat v2 as a vector from 0,0,0
  837.   v2.normalize();
  838.   float cosdev = dot(norm, v2);
  839.   //if (cosdev < .259) {
  840.     // More than 75-degrees away from perpendicular
  841.   if (cosdev < .017) {
  842.     // more than 89-degrees away from perpendicular
  843.     return true;
  844.   } else {
  845.     return false;
  846.   }
  847.   // #else
  848.   // #ifdef USE_Z_AS_DEPTH
  849.   // Check to see if depth difference is greater than our
  850.   // typical occlusion distance (CyraTessDepthmm)
  851.   if (v1[2] > v2[2] + CyraTessDepth ||
  852.       v1[2] > v3[2] + CyraTessDepth ||
  853.       v2[2] > v1[2] + CyraTessDepth ||
  854.       v2[2] > v3[2] + CyraTessDepth ||
  855.       v3[2] > v1[2] + CyraTessDepth ||
  856.       v3[2] > v2[2] + CyraTessDepth) {
  857.     return true;
  858.   } else {
  859.     return false;
  860.   }
  861. #else
  862.   // Don't use Z as depth... compute distance from the center...
  863.   float v1dist = sqrtf(v1[0]*v1[0] + v1[1]*v1[1] + v1[2]*v1[2]);
  864.   float v2dist = sqrtf(v2[0]*v2[0] + v2[1]*v2[1] + v2[2]*v2[2]);
  865.   float v3dist = sqrtf(v3[0]*v3[0] + v3[1]*v3[1] + v3[2]*v3[2]);
  866.   if (v1dist > v2dist + CyraTessDepth ||
  867.       v1dist > v3dist + CyraTessDepth ||
  868.       v2dist > v1dist + CyraTessDepth ||
  869.       v2dist > v3dist + CyraTessDepth ||
  870.       v3dist > v1dist + CyraTessDepth ||
  871.       v3dist > v2dist + CyraTessDepth) {
  872.     return true;
  873.   } else {
  874.     return false;
  875.   }
  876.   //#endif  // USE_Z_AS_DEPTH
  877. #endif  // 0  
  878. }
  879. int 
  880. CyraResLevel::num_vertices(void)
  881. {
  882.   return numpoints;
  883. }
  884. int 
  885. CyraResLevel::num_tris(void)
  886. {
  887.   return numtris;
  888. }
  889. void 
  890. CyraResLevel::growBBox(Bbox &bbox)
  891. {
  892.   FOR_EACH_VERT(bbox.add(v->vtx));
  893. }
  894. void flip3shorts (short* p)
  895. {
  896.   p[0] *= -1;
  897.   p[1] *= -1;
  898.   p[2] *= -1;
  899. }
  900. void
  901. CyraResLevel::flipNormals(void)
  902. {
  903.   // Ok, to flip the normals, we:
  904.   //     1. Reverse the order of the vertical scanlines (in memory)
  905.   //     2. Reverse the order of the Triangle tesselation flags (in mem)
  906.   //     3. Reverse the sign of the per-vertex normals
  907.   ////// 1. Reverse the order of the vertical scanlines (in memory)
  908.   CyraSample samp;
  909.   for (int xx=0; xx < width/2; xx++) {
  910.     for (int yy=0; yy < height; yy++) {
  911.       samp = point(xx,yy);
  912.       point(xx,yy) = point(width-xx-1, yy);
  913.       point(width-xx-1, yy) = samp;
  914.     }
  915.   }
  916.   ////// 2. Reverse the order of the Triangle tesselation flags (in mem)
  917.   // (This also requires changing TESS1 <-> TESS3, TESS2 <-> TESS4)
  918.   CyraTess tess;
  919.   // Note:  only goes to width-1, but want to do middle col, too, so
  920.   // the width-1+1 cancel out...
  921.   for (xx=0; xx < (width)/2; xx++) {
  922.     for (int yy=0; yy < height-1; yy++) {
  923.       tess = tri(xx,yy);
  924.       // Set scanline xx to be mirror of width-xx-2
  925.       switch(tri(width-xx-2, yy)) {
  926.       case TESS0:
  927. tri(xx,yy) = TESS0; break;
  928.       case TESS1:
  929. tri(xx,yy) = TESS3; break;
  930.       case TESS2:
  931. tri(xx,yy) = TESS4; break;
  932.       case TESS3:
  933. tri(xx,yy) = TESS1; break;
  934.       case TESS4:
  935. tri(xx,yy) = TESS2; break;
  936.       case TESS14:
  937.       case TESS23:
  938. tri(xx,yy) = TESS14; break;
  939.       }
  940.       // Set scanline width-xx-2 to be mirror of xx
  941.       switch(tess) {
  942.       case TESS0:
  943. tri(width-xx-2,yy) = TESS0; break;
  944.       case TESS1:
  945. tri(width-xx-2,yy) = TESS3; break;
  946.       case TESS2:
  947. tri(width-xx-2,yy) = TESS4; break;
  948.       case TESS3:
  949. tri(width-xx-2,yy) = TESS1; break;
  950.       case TESS4:
  951. tri(width-xx-2,yy) = TESS2; break;
  952.       case TESS14:
  953.       case TESS23:
  954. tri(width-xx-2,yy) = TESS14; break;
  955.       }
  956.     }
  957.   }
  958.   ////// 3. Reverse the sign of the per-vertex normals
  959.   FOR_EACH_VERT(flip3shorts (v->nrm));
  960. }
  961. bool 
  962. CyraResLevel::filtered_copy(CyraResLevel &original, 
  963.     const VertexFilter& filter)
  964. {
  965.   width  = original.width;
  966.   height = original.height;
  967.   numpoints = 0; 
  968.   numtris   = 0;   
  969.   points.clear();
  970.   tris.clear();
  971.   origin = original.origin;
  972.   CyraSample zero;
  973.   zero.vtx.set(0,0,0);
  974.   zero.nrm[0] = 0; zero.nrm[1] = 0; zero.nrm[2] = 32767;
  975.   zero.confidence = 0;
  976.   zero.intensity  = 0;
  977.   // Copy the vertices
  978.   for (int i=0; i < original.points.size(); i++) {
  979.     if (filter.accept(original.points[i].vtx)) {
  980.       points.push_back(original.points[i]);
  981.       numpoints++;
  982.     } else {
  983.       points.push_back(zero);
  984.     }
  985.   }
  986.   // Copy the triangles
  987.   for (int xx=0; xx < width-1; xx++) {
  988.     for (int yy=0; yy < height-1; yy++) {
  989.       bool conf00 = (point(xx,yy).confidence > 0);
  990.       bool conf01 = (point(xx,yy+1).confidence > 0);
  991.       bool conf10 = (point(xx+1,yy).confidence > 0);
  992.       bool conf11 = (point(xx+1,yy+1).confidence > 0);
  993.       // Compute new tess, minus possible vertices
  994.       CyraTess tess;
  995.       switch (original.tri(xx, yy)) {
  996.       case TESS0:
  997. tess = TESS0;
  998. break;
  999.       case TESS1:
  1000. if (conf00 && conf10 && conf01) tess = TESS1;
  1001. else tess = TESS0;
  1002. break;
  1003.       case TESS2:
  1004. if (conf00 && conf01 && conf11) tess = TESS2;
  1005. else tess = TESS0;
  1006. break;
  1007.       case TESS3:
  1008. if (conf00 && conf10 && conf11) tess = TESS3;
  1009. else tess = TESS0;
  1010. break;
  1011.       case TESS4:
  1012. if (conf01 && conf10 && conf11) tess = TESS4;
  1013. else tess = TESS0;
  1014. break;
  1015.       case TESS14:
  1016.       case TESS23:
  1017. if (conf00 && conf01 && conf10 && conf11) tess = TESS14;
  1018. else if (conf00 && conf01 && conf10) tess = TESS1;
  1019. else if (conf00 && conf01 && conf11) tess = TESS2;
  1020. else if (conf00 && conf10 && conf11) tess = TESS3;
  1021. else if (conf01 && conf10 && conf11) tess = TESS4;
  1022. else tess = TESS0;
  1023. break;
  1024.       default:
  1025. cerr << "Unhandled tesselation flag " << original.tri(xx,yy) 
  1026.      << " in clipping..." << endl;
  1027.       }
  1028.       // Push Tri flag, increment numtris
  1029.       tris.push_back(tess);
  1030.       if (tess == TESS14 || tess == TESS23) numtris+=2;
  1031.       else if (tess == TESS0) numtris += 0;
  1032.       else numtris ++;
  1033.     }
  1034.   }
  1035.   return true;
  1036. }
  1037. bool 
  1038. CyraResLevel::filter_inplace(const VertexFilter& filter)
  1039. {
  1040.   numpoints = 0; 
  1041.   numtris   = 0;   
  1042.   CyraSample zero;
  1043.   zero.vtx.set(0,0,0);
  1044.   zero.nrm[0] = zero.nrm[1] = 0; zero.nrm[2] = 32767;
  1045.   zero.confidence = 0;
  1046.   zero.intensity  = 0;
  1047.   // Filter the vertices
  1048.   FOR_EACH_VERT(*v = (filter.accept(v->vtx) && ++numpoints)? *v : zero);
  1049.   // Copy the triangles
  1050.   for (int xx=0; xx < width-1; xx++) {
  1051.     for (int yy=0; yy < height-1; yy++) {
  1052.       bool conf00 = (point(xx,yy).confidence > 0);
  1053.       bool conf01 = (point(xx,yy+1).confidence > 0);
  1054.       bool conf10 = (point(xx+1,yy).confidence > 0);
  1055.       bool conf11 = (point(xx+1,yy+1).confidence > 0);
  1056.       // Compute new tess, minus possible vertices
  1057.       CyraTess tess;
  1058.       switch (tri(xx, yy)) {
  1059.       case TESS0:
  1060. tess = TESS0;
  1061. break;
  1062.       case TESS1:
  1063. if (conf00 && conf10 && conf01) tess = TESS1;
  1064. else tess = TESS0;
  1065. break;
  1066.       case TESS2:
  1067. if (conf00 && conf01 && conf11) tess = TESS2;
  1068. else tess = TESS0;
  1069. break;
  1070.       case TESS3:
  1071. if (conf00 && conf10 && conf11) tess = TESS3;
  1072. else tess = TESS0;
  1073. break;
  1074.       case TESS4:
  1075. if (conf01 && conf10 && conf11) tess = TESS4;
  1076. else tess = TESS0;
  1077. break;
  1078.       case TESS14:
  1079.       case TESS23:
  1080. if (conf00 && conf01 && conf10 && conf11) tess = TESS14;
  1081. else if (conf00 && conf01 && conf10) tess = TESS1;
  1082. else if (conf00 && conf01 && conf11) tess = TESS2;
  1083. else if (conf00 && conf10 && conf11) tess = TESS3;
  1084. else if (conf01 && conf10 && conf11) tess = TESS4;
  1085. else tess = TESS0;
  1086. break;
  1087.       default:
  1088. cerr << "Unhandled tesselation flag " << tri(xx,yy) 
  1089.      << " in clipping..." << endl;
  1090.       }
  1091.       // Push Tri flag, increment numtris
  1092.       tri(xx,yy) = tess;
  1093.       if (tess == TESS14 || tess == TESS23) numtris+=2;
  1094.       else if (tess == TESS0) numtris += 0;
  1095.       else numtris ++;
  1096.     }
  1097.   }
  1098.   isDirty_cache = true;
  1099.   return true;
  1100. }
  1101. void
  1102. CyraResLevel::create_kdtree(void)
  1103. {
  1104.   // If everything built, no-op.
  1105.   if ((!isDirty_cache) && (kdtree)) return;
  1106.   // otherwise, rebuild
  1107.   if (kdtree) delete kdtree;
  1108.   cachedPoints.clear();
  1109.   cachedNorms.clear();
  1110.   cachedBoundary.clear();
  1111.   // re-assemble cachedPoints, norms, boundary
  1112.   cachedPoints.reserve(num_vertices());
  1113.   cachedNorms.reserve(num_vertices() * 3);
  1114.   cachedBoundary.reserve(num_vertices());
  1115.   FOR_EACH_VERT(cachedPoints.push_back(v->vtx));
  1116.   FOR_EACH_VERT(cachedNorms.insert (cachedNorms.end(), v->nrm, v->nrm + 3));
  1117.   FOR_EACH_VERT(cachedBoundary.push_back
  1118. ((bool) (vx == 0 || vx == width-1 ||
  1119.  vy == 0 || vy == height-1 ||
  1120.  (tri(vx-1,vy-1) != TESS14 && 
  1121.   tri(vx-1,vy-1) != TESS23 && 
  1122.   tri(vx-1,vy-1) != TESS4) ||
  1123.  (tri(vx-1,vy) != TESS14 && 
  1124.   tri(vx-1,vy) != TESS23 && 
  1125.   tri(vx-1,vy) != TESS3) ||
  1126.  (tri(vx,vy-1) != TESS14 && 
  1127.   tri(vx,vy-1) != TESS23 && 
  1128.   tri(vx,vy-1) != TESS2) ||
  1129.  (tri(vx,vy) != TESS14 && 
  1130.   tri(vx,vy) != TESS23 && 
  1131.   tri(vx,vy) != TESS1))));
  1132.   kdtree = CreateKDindtree (cachedPoints.begin(), cachedNorms.begin(),
  1133.     cachedPoints.size());
  1134.   isDirty_cache = false;
  1135. }
  1136. // for ICP...
  1137. void
  1138. CyraResLevel::subsample_points(float rate, vector<Pnt3> &p, vector<Pnt3> &n)
  1139. {
  1140.   int nv = num_vertices();
  1141.   int totalNum = (int)(rate * nv);
  1142.   if (totalNum > nv) return;
  1143.   
  1144.   p.clear(); p.reserve(totalNum);
  1145.   n.clear(); n.reserve(totalNum);
  1146.   
  1147.   int num = totalNum;
  1148.   int end = nv;
  1149.   for (int i = 0; i < end; i++) {
  1150.     if (random()%nv < num) {
  1151.       p.push_back(points[i].vtx);    // save point
  1152.       pushNormalAsPnt3 (n, points[i].nrm, 0);
  1153.       num--;
  1154.     }
  1155.     nv--;
  1156.   }
  1157.   assert(num == 0);
  1158.   if (p.size() != totalNum) {
  1159.     printf("Selected wrong number of points in the CyraResLevel subsample proc.n");
  1160.   }
  1161. }  
  1162. bool 
  1163. CyraResLevel::closest_point(const Pnt3 &p, const Pnt3 &n, 
  1164. Pnt3 &cp, Pnt3 &cn,
  1165. float thr, bool bdry_ok)
  1166. {
  1167.   create_kdtree();
  1168.   int ind, ans;
  1169.   ans = kdtree->search(&cachedPoints[0], 
  1170.        &cachedNorms[0], p, n, ind, thr);
  1171.   if (ans) {
  1172.     if (!bdry_ok) {
  1173.       // disallow closest points that are on the mesh boundary
  1174.       if (cachedBoundary[ind]) return 0;
  1175.     }
  1176.     cp = cachedPoints[ind];
  1177.     short *sp = &cachedNorms[ind*3];
  1178.     cn.set(sp[0]/32767.0, 
  1179.    sp[1]/32767.0, 
  1180.    sp[2]/32767.0);
  1181.   }
  1182.   return ans;
  1183. }