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

3D图形编程

开发平台:

Visual C++

  1. //############################################################
  2. // 
  3. // MMScan.cc
  4. //
  5. // Jeremy Ginsberg
  6. //
  7. // Stores all information pertaining to a 3DScanners ModelMaker H
  8. // scan "conglomerate"... this contains many small scan fragments,
  9. // each of which can be characterized by a single viewing direction.
  10. //
  11. // Data structures revamped starting rev1.35 to better encapsulate the
  12. // idea of a collection of scan fragments.
  13. //
  14. //
  15. // $Date: 2001/07/02 17:56:26 $
  16. // $Revision: 1.66 $
  17. //
  18. //############################################################
  19. #include "MMScan.h"
  20. #include "MeshTransport.h"
  21. #include "TriMeshUtils.h"
  22. #include "KDindtree.h"
  23. #include "ColorUtils.h"
  24. #include "Progress.h"
  25. #include "VertexFilter.h"
  26. #include "Random.h"
  27. #include <stdio.h>
  28. #include <iostream.h>
  29. #include <fstream.h>
  30. #include "sys/stat.h"
  31. #include "plvScene.h"
  32. #define STRIPE_PTS 312          // max number of points in a given stripe
  33. #define SUBSAMPS 6              // number of resolutions to create
  34. MMScan::MMScan()
  35. {
  36.   haveScanDir = false;
  37.   isDirty_mem = false;
  38.   isDirty_disk = false;
  39.   scans.clear();
  40. }
  41. MMScan::~MMScan()
  42. {
  43.   while (kdtree.size()) {
  44.     delete (kdtree.back());
  45.     kdtree.pop_back();
  46.   }
  47.   scans.clear();
  48. }
  49. static bool 
  50. getXformFilename (const char* meshName, char* xfName)
  51. {
  52.   if (meshName == NULL || meshName[0] == 0)
  53.     return FALSE;
  54.   strcpy (xfName, meshName);
  55.   char* pExt = strrchr (xfName, '.');
  56.   if (pExt == NULL)
  57.     pExt = xfName + strlen (xfName);
  58.   strcpy (pExt, ".xf");
  59.   return TRUE;
  60. }
  61. void
  62. MMScan::absorb_xforms(char *basename)
  63. {
  64.   char buffer[PATH_MAX];
  65.   strcpy(buffer, basename);
  66.   char *pExt = strrchr(buffer, '.');
  67.   if (pExt == NULL)
  68.     pExt = buffer + strlen(buffer);
  69.   
  70.   for (int i = 0; i < scans.size(); i++) {
  71.     char temp[15];
  72.     if (i < 10) sprintf(temp, "_00%d.xf", i);
  73.       else if (i < 100) sprintf(temp, "_0%d.xf", i);
  74.         else sprintf(temp, "_%d.xf", i);
  75.     strcpy(pExt, temp);
  76.     TbObj tempObj;
  77.     Xform<float> newXF;
  78.     tempObj.readXform(buffer);
  79.     newXF = tempObj.getXform();
  80.     cout << "Filename sought: " << buffer << endl;
  81.     cout << newXF << endl;
  82.     for (int j = 0; j < scans[i].meshes.size(); j++) {
  83.       for (int k = 0; k < scans[i].meshes[j].vtx.size(); k++) {
  84. newXF(scans[i].meshes[j].vtx[k]);
  85.       }
  86.     }
  87.   }
  88.   computeBBox();
  89. }
  90.   
  91.     
  92. int
  93. MMScan::write_xform_ply(int whichRes, char *directory,
  94. crope &confLines, bool applyXform)
  95. {
  96.   if (!load_resolution(whichRes)) {
  97.     cerr << "MMScan::write_xform_ply couldn't load desired resolution"
  98.  << endl;
  99.     return 0;
  100.   }
  101.   if (scans[0].meshes[whichRes].tris.size() == 0) {
  102.     // we don't have triangles; only t-strips... do something about this
  103.     for (int i = 0; i < scans.size(); i++) {
  104.       mmResLevel& res = scans[i].meshes[whichRes];
  105.       triangulate(&scans[0] + i, &res, 1 << whichRes);
  106.     }
  107.   }
  108.   int numFragsSaved = 0;
  109.   
  110.   // get basename for ply files
  111.   
  112.   char buffer[PATH_MAX], *slash;
  113.   strcpy(buffer, get_name().c_str());
  114.   for (slash = buffer; *slash; slash++)
  115.      if (*slash == '/') *slash = '_';
  116.   char *pExt = strrchr(buffer, '.');
  117.   if (pExt == NULL)
  118.     pExt = buffer + strlen(buffer);
  119.   /*
  120.     okay so we don't really want confidence
  121.     
  122.     // build confidence if we don't have it
  123.     if (scans[0].meshes[0].confidence.size() == 0)
  124.     calcConfidence();
  125.   */
  126.   vector<Pnt3> scanVtx;
  127.   
  128.   Pnt3 axis;
  129.   float rotAngle, quat[4];
  130.   Xform<float> xf, invXF;
  131.   
  132.   // stuff for global alignment
  133.   Xform<float> meshXF;
  134.   Xform<float> comboXF;
  135.   float comboTrans[3];
  136.   
  137.   meshXF = this->getXform();
  138.   // set up conf strings
  139.   //confLines = new char *[scans.size()];
  140.   
  141.   // save each scan to a separate file
  142.   for(int i = 0; i < scans.size(); i++) {
  143.     // discard absurdly tiny meshes
  144.     if (scans[i].stripes.size() < 3) {
  145.       cout << "DISCARDING MESH WITH < 3 STRIPES " << endl;
  146.     }
  147.     else {
  148.        //cout << "Scan # " << i << ":" << endl;
  149.       
  150.       if (i < 10) sprintf(pExt, "_00%d.ply", i);
  151.       else if (i < 100) sprintf(pExt, "_0%d.ply", i);
  152.       else sprintf(pExt, "_%d.ply", i);
  153.       
  154. #if 0
  155.       // An effort to combat flipped view direction
  156.       Pnt3 nrm(0,0,0);
  157.       for(int j = 0; j < scans[i].meshes[whichRes].nrm.size(); j++) {
  158.  nrm[0] += scans[i].meshes[whichRes].nrm[j*3+0];
  159.  nrm[1] += scans[i].meshes[whichRes].nrm[j*3+1];
  160.  nrm[2] += scans[i].meshes[whichRes].nrm[j*3+2];
  161.       }
  162.       if (dot(nrm, scans[i].viewDir) < 0)
  163.  scans[i].viewDir = -scans[i].viewDir;
  164. #endif
  165.       // calculate transformation necessary to align viewDir with Z-axis
  166.       xf.identity();
  167.       axis.set(-1 * scans[i].viewDir[1], scans[i].viewDir[0], 0);
  168.       axis.normalize();
  169.       rotAngle = M_PI + acos(-1 * scans[i].viewDir[2]);
  170.       //cout << "rotating " << rotAngle << " rads around " << axis << endl;
  171.       xf.rot(rotAngle, axis[0], axis[1], axis[2]);
  172.       //cout << scans[i].num_vertices(whichRes) << " points" << endl;
  173.       
  174.       invXF = xf;
  175.       invXF.invert();
  176.       comboXF = meshXF * invXF;
  177.       comboXF.toQuaternion(quat);
  178.       comboXF.getTranslation(comboTrans);
  179.       if (applyXform) {
  180. char line[PATH_MAX + 100];
  181. // save transformation to conf string
  182. sprintf(line, "{bmesh %s %g %g %g %g %g %g %g}",
  183. buffer, comboTrans[0], comboTrans[1], comboTrans[2],
  184. -1 * quat[1], -1 * quat[2], -1 * quat[3], quat[0]);
  185. //confLines[numFragsSaved] = new char[strlen(buffer)];
  186. //strcpy(confLines[numFragsSaved], buffer);
  187. if (!confLines.empty()) {
  188.    confLines += " ";
  189. }
  190. confLines += line;
  191.       }
  192.       
  193.       scanVtx.reserve(scans[i].meshes[whichRes].vtx.size());
  194.       
  195.       // apply transformation to points
  196.       for(int k = 0; k < scans[i].meshes[whichRes].vtx.size(); k++) {
  197. Pnt3 pt = scans[i].meshes[whichRes].vtx[k];
  198. if (applyXform) 
  199.   xf(pt);
  200. scanVtx.push_back(pt);
  201.       }
  202.       char full_path[PATH_MAX];
  203.       sprintf(full_path, "%s/%s", directory, buffer);
  204.       write_ply_file(full_path, scanVtx, 
  205.      scans[i].meshes[whichRes].tris, false
  206.      );
  207.       scanVtx.clear();
  208.       
  209.       // write xf
  210.       strcpy (full_path + strlen(full_path) - 3, "xf");
  211.       cout << "Writing " << full_path << " ... " << flush;
  212.       ofstream xffile (full_path);
  213.       if (applyXform)
  214.  xffile << comboXF;
  215.       else
  216.  xffile << meshXF;
  217.       if (xffile.fail()) {
  218.  cerr << "Scan " << buffer 
  219.       << " failed to write xform!" << endl;
  220.  break;
  221.       }
  222.       numFragsSaved++;
  223.     }
  224.   }
  225.   return numFragsSaved;
  226. }
  227. MeshTransport*
  228. MMScan::mesh(bool perVertex, bool stripped,
  229.      ColorSource color, int colorSize)
  230. {
  231.   if (stripped && !perVertex) {
  232.     cerr << "No t-strips without per-vertex properties";
  233.     return NULL;
  234.   }
  235.   int resNum = current_resolution_index();
  236.   if (!resolutions[resNum].in_memory) load_resolution(resNum);
  237.   int numVerts = num_vertices(resNum);
  238.   MeshTransport* mt = new MeshTransport;
  239.   for (int i = 0; i < scans.size(); i++) {
  240.     if (scans[i].isVisible) {
  241.       mmResLevel *res = &(scans[i].meshes[0]) + resNum;
  242.       mt->setVtx (&res->vtx, MeshTransport::share);
  243.       if (perVertex) {
  244. mt->setNrm (&res->nrm, MeshTransport::share);
  245.       } else {
  246. return NULL;
  247. /* no support now 
  248. if (!res->triNrm.size()) {
  249.   if (!res->tris.size()) strips_to_tris(res->tstrips, res->tris);
  250.   calcTriNormals (res->tris, res->triNrm);
  251. }
  252. mt->setNrm (&res->triNrm, MeshTransport::share);
  253. */
  254.       }
  255.       if (stripped) {
  256. if (!res->tstrips.size()) {
  257.   int subSamp = 1 << resNum;
  258.   make_tstrips(&scans[0] + i, res, subSamp);
  259. }
  260. mt->setTris (&res->tstrips, MeshTransport::share);
  261.       } else { // regular triangles
  262. if (!res->tris.size() && res->tstrips.size())
  263.   strips_to_tris(res->tstrips, res->tris);
  264. mt->setTris (&res->tris, MeshTransport::share);
  265.       }
  266.       if (color != colorNone)
  267. setMTColor (mt, i, perVertex, color, colorSize);
  268.     }
  269.   }
  270.   return mt;
  271. }
  272. void
  273. MMScan::setMTColor (MeshTransport* mt, int iScan, bool perVertex,
  274.     ColorSource source, int colorsize)
  275. {
  276.   int resNum = current_resolution_index();
  277.   mmResLevel* res = &(scans[iScan].meshes[resNum]);
  278.   /* don't know how to check ahead of time yet
  279.   if ((!conf_col) && (vtxIntensity.size() == 0) && (colorsize != 3))
  280.     return false;   // if we have no intensity data for some unknown reason
  281.                     // and we're not looking for per-scan color or confidence
  282.   */
  283.   vector<uchar>* colors = new vector<uchar>;
  284.   mt->setColor (colors, MeshTransport::steal);
  285.   
  286.   if (perVertex)
  287.     colors->reserve (res->vtx.size() * colorsize);
  288.   else return;
  289.     /* no support now 
  290.     colors->reserve (num_tris(resNum) / 3 * colorsize);
  291.     */
  292.   int j;
  293.   switch (source) {
  294.   case colorConf:
  295.     // confidence zone
  296.     if (perVertex) {
  297.       // per-vertex confidence zone
  298.       if (res->confidence.size() == 0) return;
  299.       
  300.       for (j = 0; j < res->confidence.size(); j++)
  301. pushColor(*colors, colorsize, res->confidence[j]);
  302.     }
  303.     else {
  304.       return;
  305.       /* no support now
  306.       // per-face confidence zone
  307.       if (res->confidence.size() == 0) return;
  308.       
  309.       for (j = 0; j < res->tris.size(); j+=3)
  310. pushColor(*colors, colorsize,
  311.   res->confidence[res->tris[j+0]],
  312.   res->confidence[res->tris[j+1]],
  313.   res->confidence[res->tris[j+2]]);
  314.       */
  315.     }
  316.     break; // end confidence color zone
  317.   
  318.   case colorTrue:
  319.     // MMScan doesn't have true-color information, so it interprets this
  320.     // flag as a request for per-fragment coloring.
  321.     // begin per-scan coloring to replace diffuse color
  322.     pushColor(*colors, colorsize, scans[iScan].falseColor);
  323.     break;
  324.   case colorIntensity:
  325.   default:
  326.     // intensity coloring
  327.     // on filtered vertex sets, i'm not sure how the intensity
  328.     // is going to be derived, so check and see where that data
  329.     // is coming from if you're concerned.
  330.     
  331.     if (perVertex) {
  332.       // per-vertex intensities
  333.       
  334.       if (res->intensity.size() == 0) return;
  335.       for (j = 0; j < res->vtx.size(); j++)
  336. pushColor(*colors, colorsize, res->intensity[j]);
  337.     }
  338.     else {
  339.       // per-face intensities
  340.       return;
  341.       /* no support now
  342.       if (res->intensity.size() == 0) return;
  343.       for (j = 0; j < res->tris.size(); j+=3)
  344. pushColor(*colors, colorsize,
  345.   res->intensity[res->tris[j+0]],
  346.   res->intensity[res->tris[j+1]],
  347.   res->intensity[res->tris[j+2]]);
  348.       */
  349.     } // end intensity-coloring zone
  350.   } // end switch
  351. }
  352. crope
  353. MMScan::getInfo(void)
  354. {
  355.   char buf[1000];
  356.   sprintf(buf, "MMScan: %d scans, %d stripes, %d points,"
  357.   " %d resolutionsnn",
  358.   num_scans(), num_stripes(), num_vertices(0), num_resolutions());
  359.   return crope (buf) + RigidScan::getInfo();
  360. }
  361. int
  362. MMScan::num_tris(int res)
  363. {
  364.   if (scans.size() == 0) return 0;
  365.   int numResolutions = scans[0].meshes.size();
  366.   if (numResolutions == 0) return 0;
  367.   if ((res >= numResolutions) || (res < 0)) return 0;
  368.   int numTris = 0;
  369.   for (int i = 0; i < scans.size(); i++) {
  370.     if (scans[i].isVisible) 
  371.       numTris += scans[i].meshes[res].tris.size() / 3;
  372.   }
  373.   return numTris;
  374. }
  375. int
  376. MMScan::num_stripes()
  377. {
  378.   int sum = 0;
  379.   for (int i = 0; i < scans.size(); i++) {
  380.     sum += scans[i].stripes.size();
  381.   }
  382.   return sum;
  383. }
  384. int
  385. MMScan::num_vertices(void)
  386. {
  387.   int total = 0;
  388.   int resNum = current_resolution_index();
  389.   for (int i = 0; i < scans.size(); i++) {
  390.     if (scans[i].isVisible) {
  391.       if ((resNum < scans[i].meshes.size()) && (resNum >= 0))
  392. total += scans[i].meshes[resNum].vtx.size();
  393.     }
  394.   }
  395.   return total;
  396. }
  397. int
  398. MMScan::num_vertices(int resNum)
  399. {
  400.   int total = 0;
  401.   for (int i = 0; i < scans.size(); i++) {
  402.     if (scans[i].isVisible)
  403.       if ((resNum < scans[i].meshes.size()) && (resNum >= 0))
  404. total += scans[i].meshes[resNum].vtx.size();
  405.   }
  406.   return total;
  407. }
  408. int
  409. MMScan::create_resolution_absolute(int budget, Decimator dec)
  410. {
  411.   if (budget == 0) return 0;
  412.   int resNum = 0; // always decimate from the master copy, at least for now
  413.   int totalTris = num_tris(resNum);
  414.   int decimatedTris = 0;
  415.   mmResLevel *resolutions = new mmResLevel[scans.size()];
  416.   mmResLevel *newRes;
  417.   cerr << "Target size = " << budget << ": decimating... ";
  418.   for (int i = 0; i < scans.size(); i++) {
  419.     // check to see if we have triangles
  420.     mmResLevel *res = &(scans[i].meshes[0]) + resNum;
  421.     if (!res->tris.size()) strips_to_tris(res->tstrips, res->tris);
  422.     cerr << "mesh tris = " << scans[i].meshes[resNum].num_tris() << endl;;
  423.     int fragBudget = budget * ((double)(scans[i].meshes[resNum].num_tris())
  424.        / totalTris);
  425.     fprintf(stderr, "Mesh #%d:t%d tris...t", i, fragBudget);
  426.     newRes = resolutions + i;
  427.     quadric_simplify(scans[i].meshes[0].vtx, scans[i].meshes[0].tris,
  428.      newRes->vtx, newRes->tris,
  429.      fragBudget, PLACE_OPTIMAL, 0, 1000);
  430.     if (newRes->tris.size()/3 != fragBudget)
  431.       fprintf(stderr, "ended up with %ld trisn", newRes->tris.size()/3);
  432.     else fprintf(stderr, "donen");
  433.     decimatedTris += newRes->tris.size() / 3;
  434.     
  435.     getVertexNormals(newRes->vtx, newRes->tris, false, newRes->nrm, true);
  436.     
  437.   }
  438.   insert_resolution(decimatedTris, get_name(), true, true);
  439.   int iPos = findLevelForRes(decimatedTris);
  440.   for (i = 0; i < scans.size(); i++) {
  441.     scans[i].meshes.insert(&(scans[i].meshes[iPos]), resolutions[i]);
  442.   }
  443.   delete[] resolutions;
  444.   return decimatedTris;
  445. }
  446. void 
  447. MMScan::computeBBox (void)
  448. {
  449.   bbox.clear();
  450.   int resNum = current_resolution_index();
  451.   for (int k = 0; k < scans.size(); k++) {
  452.     if (scans[k].isVisible) {
  453.       for (int i = 0; i < scans[k].meshes[resNum].num_vertices(); i++) {
  454. bbox.add(scans[k].meshes[resNum].vtx[i]);
  455.       }
  456.     }
  457.   }
  458.   if (scans.size() == 0) {
  459.     rot_ctr = Pnt3();
  460.   } else {
  461.     rot_ctr = bbox.center();
  462.   }
  463. }  
  464. void
  465. MMScan::flipNormals (void)
  466. {
  467.   for (int i = 0; i < scans.size(); i++) {
  468.     for (int j = 0; j < scans[i].meshes.size(); j++) {
  469.       // triangle normals
  470.       for (int k = 0; k < scans[i].meshes[j].tris.size(); k+=3) {
  471. swap(scans[i].meshes[j].tris[k], scans[i].meshes[j].tris[k+1]);
  472.       }
  473.       // tstrip normals
  474.       flip_tris(scans[i].meshes[j].tstrips, true);
  475.       // per-vertex normals
  476.       for (k = 0; k < scans[i].meshes[j].nrm.size(); k++) {
  477. scans[i].meshes[j].nrm[k] *= -1;
  478.       }
  479.     }
  480.     for (j = 0; j < scans[i].stripes.size(); j++) {
  481.       // this isn't completely effective; causes z-axis align problems
  482.       scans[i].stripes[j].sensorVec *= -1;
  483.       if (scans[i].stripes[j].scanDir == 1) scans[i].stripes[j].scanDir = 2;
  484.       else scans[i].stripes[j].scanDir = 1;
  485.     }
  486.     scans[i].viewDir *= -1;
  487.   }
  488. }
  489. void
  490. MMScan::flipNormals (int scanNum)
  491. {
  492.   for (int j = 0; j < scans[scanNum].meshes.size(); j++) {
  493.     // triangle normals
  494.     for (int k = 0; k < scans[scanNum].meshes[j].tris.size(); k+=3) {
  495.       swap(scans[scanNum].meshes[j].tris[k],
  496.    scans[scanNum].meshes[j].tris[k+1]);
  497.     }
  498.     // tstrip normals
  499.     flip_tris(scans[scanNum].meshes[j].tstrips, true);
  500.     // per-vertex normals
  501.     for (k = 0; k < scans[scanNum].meshes[j].nrm.size(); k++) {
  502.       scans[scanNum].meshes[j].nrm[k] *= -1;
  503.     }
  504.   }
  505.   for (j = 0; j < scans[scanNum].stripes.size(); j++) {
  506.     // sensor vectors (so that it will triangulate flipped next time
  507.     scans[scanNum].stripes[j].sensorVec *= -1;
  508.     if (scans[scanNum].stripes[j].scanDir == 1)
  509.       scans[scanNum].stripes[j].scanDir = 2;
  510.     else scans[scanNum].stripes[j].scanDir = 1;
  511.   }
  512.   scans[scanNum].viewDir *= -1;
  513. }  
  514. bool
  515. MMScan::isValidPoint(int scanNum, int stripeNum, int colNum)
  516.   // returns value of bitmap of specified stripe in specified column
  517.   // of a specified scan
  518. {
  519.   if (scanNum >= scans.size()) return false;
  520.   if (stripeNum >= scans[scanNum].stripes.size()) return false;
  521.   if (colNum > STRIPE_PTS) return false;
  522.   return (scans[scanNum].stripes[stripeNum].validMap[colNum / 8]
  523.   & (1 << (colNum % 8)));
  524. }
  525. static void
  526. addTri(vector<int> &tris, int v1, int v2, int v3, char scanDir)
  527. {
  528.   // if it's normal or if we don't know the scan direction...
  529.   if ((scanDir == 1) || (scanDir == 0)) {
  530.     tris.push_back(v1);
  531.     tris.push_back(v2);
  532.     tris.push_back(v3);
  533.   }
  534.   // otherwise flip the beans out of it
  535.   else if (scanDir == 2) {
  536.     tris.push_back(v2);
  537.     tris.push_back(v1);
  538.     tris.push_back(v3);
  539.   }
  540. }
  541. void
  542. MMScan::calcScanDir(void)
  543. {
  544.   Pnt3 scanDir, stripeDir, crossDir;
  545.   int numPts, i, j, k;
  546.   // loop through all scans
  547.   for (k = 0; k < scans.size(); k++) {
  548.     if (scans[k].indices.size() == 0) calcIndices();
  549.     mmScanFrag *scan = &scans[0] + k;
  550.     mmResLevel *mesh = &(scan->meshes[0]);
  551.     // stop before last stripe since we look ahead one stripe
  552.     for (j = 0; j < scans[k].stripes.size() - 1; j++) {
  553.       scanDir.set(0,0,0);
  554.       stripeDir.set(0,0,0);
  555.       numPts = 0; 
  556.       for (i = 0; i < STRIPE_PTS - 1; i++) {
  557. // first get scan direction
  558. if (isValidPoint(k,j,i) && isValidPoint(k,j+1,i)) {
  559.   scanDir += mesh->vtx[scan->indices[i + (j+1) * STRIPE_PTS]];
  560.   scanDir -= mesh->vtx[scan->indices[i + j * STRIPE_PTS]];
  561.   numPts++;
  562. }
  563.       }
  564.       // then get stripe direction
  565.       stripeDir += mesh->vtx[scan->stripes[j].startIdx +
  566.        scan->stripes[j].numPoints - 1];
  567.       stripeDir -= mesh->vtx[scan->stripes[j].startIdx];
  568.       if (numPts == 0) {
  569. // not enough information to determine scanning direction
  570. scan->stripes[j].scanDir = 0;
  571. cout << "couldn't obtain scan direction for a stripe" << endl;
  572.       }
  573.       else {
  574. scanDir /= numPts;
  575. scanDir.normalize();
  576. stripeDir.normalize();
  577. // figure out where the scan direction is expected to be
  578. crossDir = cross(scan->stripes[j].sensorVec, stripeDir);
  579. // if the actual doesn't match expected, we need to flip the triangles
  580. // by marking the scanDir flag as 2 instead of 1
  581. if (dot(crossDir, scanDir) > 0) scan->stripes[j].scanDir = 1;
  582.    else scan->stripes[j].scanDir = 2;
  583.       }
  584.     }
  585.     // here we are in the last stripe of a scan, so set it's direction to 0
  586.     scan->stripes[j].scanDir = 0;
  587.   }
  588.       /*
  589.     cout << "stripe " << j << endl << "  stripe dir: " << stripeDir << endl;
  590.     cout << "  sensor vec: " << stripes[j].sensorVec << endl;
  591.     cout << "   cross vec: " << crossDir << endl;
  592.     cout << "    scan dir: " << scanDir << endl;
  593.     cout << "    num pts : " << numPts << endl;
  594.     if (stripes[j].scanDir == 1) cout << "normal" << endl;
  595.     else if (stripes[j].scanDir == 2) cout << "flipped" << endl;
  596.     else cout << "fucked!!" << endl;
  597.     */
  598.   haveScanDir = true;
  599. }
  600. void
  601. MMScan::calcIndices()
  602. {
  603.   int i, j, k, count;
  604.   fprintf(stderr, "Calculating triangulation indices...n");
  605.   for (k = 0; k < scans.size(); k++) {
  606.     mmScanFrag *scan = &(scans[0]) + k;
  607.     scan->indices.clear();
  608.     scan->indices.reserve(scan->stripes.size() * STRIPE_PTS);
  609.     count = 0;
  610.     for (i = 0; i < scan->stripes.size(); i++) {
  611.       for (j = 0; j < STRIPE_PTS; j++) {
  612. if (isValidPoint(k,i,j)) {
  613.   scan->indices.push_back(count++);
  614. }
  615. else
  616.   scan->indices.push_back(-1);
  617.       }
  618.     }
  619.   }
  620. }
  621. /* not needed anymore
  622. void
  623. MMScan::calcTriNormals(const vector<int> &tris, vector<short> &triNrm)
  624. {
  625.   int i, j, k;
  626.   for (i = 0; i < scans.size(); i++) {
  627.     for (j = 0; j < scans[i].meshes.size(); j++) {
  628.       mmResLevel *mesh = &(scans[i].meshes[j]);
  629.       mesh->triNrm.clear();
  630.       mesh->triNrm.reserve(3 * mesh->num_tris());
  631.       for(k = 0; k < mesh->tris.size(); k +=3) {
  632. Pnt3 n;
  633. n = mesh->nrm[mesh->tris[k+0]] +
  634.     mesh->nrm[mesh->tris[k+1]] +
  635.     mesh->nrm[mesh->tris[k+2]];
  636. n /= 3.0;
  637. n *= 32767;
  638. mesh->triNrm.push_back(n[0]);
  639. mesh->triNrm.push_back(n[1]);
  640. mesh->triNrm.push_back(n[2]);
  641.       }
  642.     }
  643.   }
  644. }  
  645. */
  646. static Random rnd;
  647. bool
  648. MMScan::load_resolution (int iRes)
  649. {
  650.   if (resolutions[iRes].in_memory)
  651.     return true;
  652.   int subSamp = 1 << iRes;
  653.   Progress progress(scans.size(), "%s: build mesh",
  654.     name.c_str());
  655.   int numTris = 0;
  656.   cerr << name << ": build mesh (~" << resolutions[iRes].abs_resolution
  657.        << ") from " << scans.size() << " fragments: " << flush;
  658.   for (int i = 0; i < scans.size(); i++) {
  659.     progress.update(i);
  660.     mmScanFrag *scan = &scans[0] + i;
  661.     mmResLevel& res = scan->meshes[iRes];
  662.     triangulate(scan, &res, subSamp);
  663.     /*    if (subSamp == 1) {
  664.       make_tstrips(scan, res.tstrips);
  665.       numTris += count_tris(res.tstrips);
  666.     }
  667.     else {
  668.       triangulate(scan, &res, subSamp);
  669.       tris_to_strips(res.vtx.size(), res.tris, res.tstrips);*/
  670.       res.nrm.reserve(scan->meshes[0].nrm.size() / subSamp);
  671.       getVertexNormals (res.vtx, res.tris, false, res.nrm);
  672.       numTris += res.tris.size()/3;
  673.       //    }
  674.   }
  675.   cerr << " done." << endl;
  676.   progress.update(i);
  677.   resolutions[iRes].abs_resolution = numTris;
  678.   resolutions[iRes].in_memory = true;
  679.   return true;
  680. }
  681. void
  682. MMScan::triangulate(mmScanFrag *scan, mmResLevel *res, int subSamp)
  683. {
  684.   int i,j,ii,jj;
  685.   int in1,in2,in3,in4,vin1,vin2,vin3,vin4;
  686.   int count;
  687.   int numStripes = scan->stripes.size();
  688.   // clear the list of triangles
  689.   res->tris.clear();
  690.   // i don't know what ltMin does. kari+curless do it, so i will too
  691.   int ltMin = (numStripes-1) - ((numStripes-1)/subSamp)*subSamp;
  692.   if (scan->indices.size() == 0) calcIndices();
  693.   if (!haveScanDir) calcScanDir();
  694.   
  695.   // create a list saying whether a vertex is going to be used
  696.   // int *vert_index = new int[vtx.size()];
  697.   // for (i = 0; i < vtx.size(); i++)
  698.   //   vert_index[i] = -1;
  699.   int *vert_remap;
  700.   bool alreadySubSampled = (res->vtx.size() > 0);
  701.   if (subSamp != 1) {
  702.     // see which vertices will be used in the new mesh
  703.     vert_remap = new int[scan->num_vertices(0)];
  704.     if (!alreadySubSampled) {
  705.       res->vtx.reserve(scan->num_vertices(0) / subSamp);
  706.       res->confidence.reserve(scan->meshes[0].confidence.size() / subSamp);
  707.       res->intensity.reserve(scan->meshes[0].intensity.size() / subSamp);
  708.     }
  709.     count = 0;
  710.     for (j = ltMin; j < numStripes; j += subSamp) {
  711.       for (i = 0; i < STRIPE_PTS; i += subSamp) {
  712. in1 = scan->indices[i + j * STRIPE_PTS];
  713. if (in1 >= 0) {
  714.   // vert_index[in1] = count;
  715.   vert_remap[in1] = count;
  716.   if (!alreadySubSampled) {
  717.     res->vtx.push_back(scan->meshes[0].vtx[in1]);
  718.     if (scan->meshes[0].confidence.size())
  719.       res->confidence.push_back(scan->meshes[0].confidence[in1]);
  720.     if (scan->meshes[0].intensity.size())
  721.       res->intensity.push_back(scan->meshes[0].intensity[in1]);
  722.   }
  723.   count++;
  724. }
  725.       }
  726.     }
  727.   }
  728.   else count = scan->num_vertices(0);
  729.   //if (subSamp == 1) fprintf(stderr, "%d verts... ", count);
  730.   int max_tris = count * 6;
  731.   res->tris.reserve(max_tris);
  732.   // create the triangles
  733.   for (j = ltMin; j < numStripes - subSamp; j += subSamp) {
  734.     //    if (scan->stripes[j].scanDir != scan->stripes[j+subSamp].scanDir) {
  735.     //      cout << "not triangulating across a gap" << endl;
  736.     //      continue;
  737.     //    }
  738.     for (i = 0; i < STRIPE_PTS - subSamp; i += subSamp) {
  739.       ii = (i + subSamp) % STRIPE_PTS;
  740.       jj = (j + subSamp) % numStripes;
  741.       // count the number of good vertices
  742.       // 2 3
  743.       // 1 4
  744.       in1 = scan->indices[ i +  j * STRIPE_PTS];
  745.       in2 = scan->indices[ i + jj * STRIPE_PTS];
  746.       in3 = scan->indices[ii + jj * STRIPE_PTS];
  747.       in4 = scan->indices[ii +  j * STRIPE_PTS];
  748.       count = (in1 >= 0) + (in2 >= 0) + (in3 >= 0) + (in4 >=0);
  749.       // note about vin_x vs. in_x :
  750.       // vin's should be used if new vertex lists are being generated.
  751.       // on subsamp == 1, we aren't remapping. otherwise, we are.
  752.       
  753.       if (in1 >= 0) {
  754. if (subSamp == 1) vin1 = in1;
  755.   else vin1 = vert_remap[in1];
  756.       }
  757.       if (in2 >= 0) {
  758. if (subSamp == 1) vin2 = in2;
  759.   else vin2 = vert_remap[in2];
  760.       }
  761.       if (in3 >= 0) {
  762. if (subSamp == 1) vin3 = in3;
  763.   else vin3 = vert_remap[in3];
  764.       }
  765.       if (in4 >= 0) {
  766. if (subSamp == 1) vin4 = in4;
  767.   else vin4 = vert_remap[in4];
  768.       }
  769.       // these are squared distances, let's not forget, scaled by subSamp
  770.       float maxLen1 = 1.0 * 1.0 * subSamp * subSamp;
  771.       float maxLen2 = 1.25 * 1.25 * subSamp * subSamp;
  772.       if (count == 4) { // all 4 vertices okay, so make 2 tris
  773. bool badTri = false;
  774. // check to make sure that stripe edges aren't too long
  775. if (dist2(res->vtx[vin2], res->vtx[vin3]) > maxLen1) badTri = true;
  776. if (dist2(res->vtx[vin1], res->vtx[vin4]) > maxLen1) badTri = true;
  777. // check to make sure that inter-stripe distances aren't too long
  778. if (dist2(res->vtx[vin1], res->vtx[vin2]) > maxLen2) badTri = true;
  779. if (dist2(res->vtx[vin3], res->vtx[vin4]) > maxLen2) badTri = true;
  780. if (!badTri) {
  781.   // compute lengths of cross-edges
  782.   float len1 = dist(res->vtx[vin1], res->vtx[vin3]);
  783.   float len2 = dist(res->vtx[vin2], res->vtx[vin4]);
  784.   if (len1 < len2) {
  785.     addTri(res->tris, vin2, vin1, vin3, scan->stripes[j].scanDir);
  786.     addTri(res->tris, vin1, vin4, vin3, scan->stripes[j].scanDir);
  787.   } else {
  788.     addTri(res->tris, vin2, vin1, vin4, scan->stripes[j].scanDir);
  789.     addTri(res->tris, vin2, vin4, vin3, scan->stripes[j].scanDir);
  790.   }
  791. }
  792.       }
  793.       else if (count == 3) { // only 3 vertices okay, so make 1 tri
  794. if        (in1 == -1) {
  795.   if ((dist2(res->vtx[vin2], res->vtx[vin3]) < maxLen1) &&
  796.       (dist2(res->vtx[vin3], res->vtx[vin4]) < maxLen2))
  797.   addTri(res->tris, vin2, vin4, vin3, scan->stripes[j].scanDir);
  798. } else if (in2 == -1) {
  799.   if ((dist2(res->vtx[vin1], res->vtx[vin4]) < maxLen1) &&
  800.       (dist2(res->vtx[vin3], res->vtx[vin4]) < maxLen2))
  801.   addTri(res->tris, vin1, vin4, vin3, scan->stripes[j].scanDir);
  802. } else if (in3 == -1) {
  803.   if ((dist2(res->vtx[vin1], res->vtx[vin4]) < maxLen1) &&
  804.       (dist2(res->vtx[vin1], res->vtx[vin2]) < maxLen2))
  805.   addTri(res->tris, vin2, vin1, vin4, scan->stripes[j].scanDir);
  806. } else { // in4 == -1
  807.   if ((dist2(res->vtx[vin2], res->vtx[vin3]) < maxLen1) &&
  808.       (dist2(res->vtx[vin1], res->vtx[vin2]) < maxLen2))
  809.   addTri(res->tris, vin2, vin1, vin3, scan->stripes[j].scanDir);
  810. }
  811.       }
  812.     }
  813.   }
  814.   // old solution before properly using vin's
  815.   /*
  816.   if (subSamp != 1) {
  817.     // re-map triangle indices
  818.     
  819.     for (i = 0; i < res->tris.size(); i++)
  820.       res->tris[i] = vert_remap[res->tris[i]];
  821.   }
  822.   */
  823.   if (subSamp != 1)
  824.     delete[] vert_remap;
  825.   // I originally called this with the last 2 parameters: 50, 8
  826.   // but that seems to be quite incorrect. changed on 10/19/98
  827.   // don't call anymore
  828.   //  remove_stepedges(res->vtx, res->tris, 4, 90);
  829.   cerr << "." << flush;
  830. }  
  831. void
  832. MMScan::make_tstrips(mmScanFrag *scan, mmResLevel *res, int subSamp)
  833. {
  834.   int i,j,ii,jj;
  835.   int in1,in2,in3,in4;
  836.   int vin1, vin2, vin3, vin4;
  837.   int count;
  838.   int numStripes = scan->stripes.size();
  839.   int numStrips = 0;
  840.   bool newStrip = true;
  841.   int inc, iStart, iFinish;
  842.   res->tstrips.clear();
  843.   // i don't know what ltMin does. kari+curless do it, so i will too
  844.   int ltMin = (numStripes-1) - ((numStripes-1)/subSamp)*subSamp;
  845.   // this flag is used to differentiate the 2 kinds of diagonals which occur
  846.   bool whichDiag = true;
  847.   if (scan->indices.size() == 0) calcIndices();
  848.   if (!haveScanDir) calcScanDir();
  849.   bool alreadySubSampled = (res->vtx.size() > 0);
  850.   int *vert_remap;
  851.   if (subSamp != 1) {
  852.     // see which vertices will be used in the new mesh
  853.     vert_remap = new int[scan->num_vertices(0)];
  854.     if (!alreadySubSampled) {
  855.       res->vtx.reserve(scan->num_vertices(0) / subSamp);
  856.       res->confidence.reserve(scan->meshes[0].confidence.size() / subSamp);
  857.       res->intensity.reserve(scan->meshes[0].intensity.size() / subSamp);
  858.     }
  859.     count = 0;
  860.     for (j = ltMin; j < numStripes; j += subSamp) {
  861.       for (i = 0; i < STRIPE_PTS; i += subSamp) {
  862. in1 = scan->indices[i + j * STRIPE_PTS];
  863. if (in1 >= 0) {
  864.   // vert_index[in1] = count;
  865.   vert_remap[in1] = count;
  866.   if (!alreadySubSampled) {
  867.     res->vtx.push_back(scan->meshes[0].vtx[in1]);
  868.     if (scan->meshes[0].confidence.size())
  869.       res->confidence.push_back(scan->meshes[0].confidence[in1]);
  870.     if (scan->meshes[0].intensity.size())
  871.       res->intensity.push_back(scan->meshes[0].intensity[in1]);
  872.   }
  873.   count++;
  874. }
  875.       }
  876.     }
  877.   }
  878.   else count = scan->num_vertices(0);
  879.   // usually about 2 * numVerts triangles, apply avg. length of 10
  880.   int max_strips = (count * 2) * 13 / 10;
  881.   res->tstrips.reserve(max_strips);
  882.   cout << numStripes << " stripes, " << count << " vertices." << endl;
  883.   // create the triangle strips
  884.   for (j = ltMin; j < numStripes - subSamp; j+= subSamp) {
  885.     int numSteps = (STRIPE_PTS / subSamp);
  886.     if (scan->stripes[j].scanDir == 1) {
  887.       // normal scan direction
  888.       inc = subSamp;
  889.       iStart = 0;
  890.       iFinish = (numSteps - 1) * subSamp;
  891.     }
  892.     else {
  893.       // reverse scan direction
  894.       inc = -1 * subSamp;
  895.       iStart = (numSteps - 1) * subSamp;
  896.       iFinish = 0;
  897.     }
  898.     for (i = iStart; i != iFinish; i+= inc) {
  899.       ii = (i + inc) % STRIPE_PTS;
  900.       jj = (j + subSamp) % numStripes;
  901.       // count the number of good vertices
  902.       // 2 3
  903.       // 1 4
  904.       in1 = scan->indices[ i +  j * STRIPE_PTS];
  905.       in2 = scan->indices[ i + jj * STRIPE_PTS];
  906.       in3 = scan->indices[ii + jj * STRIPE_PTS];
  907.       in4 = scan->indices[ii +  j * STRIPE_PTS];
  908.       count = (in1 >= 0) + (in2 >= 0) + (in3 >= 0) + (in4 >=0);
  909.       // note about vin_x vs. in_x :
  910.       // vin's should be used if new vertex lists are being generated.
  911.       // on subsamp == 1, we aren't remapping. otherwise, we are.
  912.       
  913.       if (in1 >= 0) {
  914. if (subSamp == 1) vin1 = in1;
  915.   else vin1 = vert_remap[in1];
  916.       }
  917.       if (in2 >= 0) {
  918. if (subSamp == 1) vin2 = in2;
  919.   else vin2 = vert_remap[in2];
  920.       }
  921.       if (in3 >= 0) {
  922. if (subSamp == 1) vin3 = in3;
  923.   else vin3 = vert_remap[in3];
  924.       }
  925.       if (in4 >= 0) {
  926. if (subSamp == 1) vin4 = in4;
  927.   else vin4 = vert_remap[in4];
  928.       }
  929.       // squared distances; don't forget
  930.       float maxLen1 = 1.0 * 1.0 * subSamp * subSamp;
  931.       float maxLen2 = 1.25 * 1.25 * subSamp * subSamp;
  932.       if (count == 4) { // all 4 vertices okay, so make 2 tris
  933. bool badTri = false;
  934. // note: these are crude checks... 1mm isn't always what we want
  935. // check to make sure that stripe edges aren't too long
  936. if (dist2(res->vtx[vin2], res->vtx[vin3]) > maxLen1) badTri = true;
  937. if (dist2(res->vtx[vin1], res->vtx[vin4]) > maxLen1) badTri = true;
  938. // check to make sure that inter-stripe distances aren't too long
  939. if (dist2(res->vtx[vin1], res->vtx[vin2]) > maxLen2) badTri = true;
  940. if (dist2(res->vtx[vin3], res->vtx[vin4]) > maxLen2) badTri = true;
  941. if (badTri) {
  942.     if (!newStrip) {
  943.       res->tstrips.push_back(-1);
  944.       newStrip = true;
  945.       numStrips++;
  946.     }
  947. else {
  948.   // compute lengths of cross-edges
  949.   float len1 = dist2(res->vtx[vin1], res->vtx[vin3]);
  950.   float len2 = dist2(res->vtx[vin2], res->vtx[vin4]);
  951.   
  952.   if (len1 < len2) {
  953.     // entering the normal-diagonal zone
  954.     // (meaning diagonal lies between 1 and 3, instead of 2 and 4)
  955.     
  956.     if (!(whichDiag || newStrip)) {
  957.       // if we're in the middle of a reverse-diagonal strip...
  958.       // end the strip
  959.       res->tstrips.push_back(-1);
  960.       newStrip = true;
  961.       numStrips++;
  962.     }
  963.     if (newStrip) {
  964.       // start a normal-diagonal strip
  965.       res->tstrips.push_back(vin2);
  966.       res->tstrips.push_back(vin1);
  967.       whichDiag = true;
  968.       newStrip = false;
  969.     }
  970.     // always add the two newest indices
  971.     res->tstrips.push_back(vin3);
  972.     res->tstrips.push_back(vin4);
  973.     
  974.   } else {
  975.     // we're in the reverse-diagonal zone now
  976.     
  977.     // if we're starting a new strip or ending a normal-diagonal,
  978.     // we add a single triangle and begin again
  979.     if (whichDiag || newStrip) {
  980.       if (newStrip) {
  981. // 1st 2 vertices of triangle needed for new strip
  982. res->tstrips.push_back(vin2);
  983. res->tstrips.push_back(vin1);
  984.       }
  985.       res->tstrips.push_back(vin4);
  986.       res->tstrips.push_back(-1);
  987.       // end the strip and the triangle, start the new strip
  988.       res->tstrips.push_back(vin2);
  989.       numStrips++;
  990.       newStrip = false;
  991.       whichDiag = false;
  992.     }
  993.     // always add the two newest indices
  994.     res->tstrips.push_back(vin4);
  995.     res->tstrips.push_back(vin3);
  996.   }
  997. }
  998.       }
  999.       else if (count == 3) { // only 3 vertices okay, so make 1 tri
  1000. if (in1 == -1) {
  1001.   // longedge check:
  1002.   if ((dist2(res->vtx[vin2], res->vtx[vin3]) > maxLen1) ||
  1003.       (dist2(res->vtx[vin3], res->vtx[vin4]) > maxLen2)) {
  1004.     if (!newStrip) {
  1005.       res->tstrips.push_back(-1);
  1006.       newStrip = true;
  1007.       numStrips++;
  1008.     }
  1009.   }
  1010.   else {
  1011.     if (!newStrip) {
  1012.       res->tstrips.push_back(-1);
  1013.       numStrips++;
  1014.     }
  1015.     res->tstrips.push_back(vin2);
  1016.     res->tstrips.push_back(vin4);
  1017.     res->tstrips.push_back(vin3);
  1018.     newStrip = false;
  1019.     whichDiag = false;
  1020.   }
  1021. }
  1022. else if (in2 == -1) {
  1023.   // longedge check:
  1024.   if ((dist2(res->vtx[vin1], res->vtx[vin4]) > maxLen1) ||
  1025.       (dist2(res->vtx[vin3], res->vtx[vin4]) > maxLen2)) {
  1026.     if (!newStrip) {
  1027.       res->tstrips.push_back(-1);
  1028.       newStrip = true;
  1029.       numStrips++;
  1030.     }
  1031.   }
  1032.   else {
  1033.     if (!newStrip) {
  1034.       res->tstrips.push_back(-1);
  1035.       numStrips++;
  1036.     }
  1037.     res->tstrips.push_back(vin1);
  1038.     res->tstrips.push_back(vin4);
  1039.     res->tstrips.push_back(vin3);
  1040.     res->tstrips.push_back(-1);
  1041.     numStrips++;
  1042.     newStrip = true;
  1043.     whichDiag = true;
  1044.   }
  1045. }
  1046. else if (in3 == -1) {
  1047.   // longedge check:
  1048.   if ((dist2(res->vtx[vin1], res->vtx[vin4]) > maxLen1) ||
  1049.       (dist2(res->vtx[vin1], res->vtx[vin2]) > maxLen2)) {
  1050.     if (!newStrip) {
  1051.       res->tstrips.push_back(-1);
  1052.       newStrip = true;
  1053.       numStrips++;
  1054.     }
  1055.   }
  1056.   else {
  1057.     if (newStrip) {
  1058.       res->tstrips.push_back(vin2);
  1059.       res->tstrips.push_back(vin1);
  1060.     }
  1061.     res->tstrips.push_back(vin4);
  1062.     res->tstrips.push_back(-1);
  1063.     numStrips++;
  1064.     newStrip = true;
  1065.     whichDiag = true;
  1066.   }
  1067. }
  1068. else { // in4 == -1
  1069.   // longedge check:
  1070.   if ((dist2(res->vtx[vin2], res->vtx[vin3]) > maxLen1) ||
  1071.       (dist2(res->vtx[vin1], res->vtx[vin2]) > maxLen2)) {
  1072.     if (!newStrip) {
  1073.       res->tstrips.push_back(-1);
  1074.       newStrip = true;
  1075.       numStrips++;
  1076.     }
  1077.   }
  1078.   else {
  1079.     if (newStrip) {
  1080.       res->tstrips.push_back(vin2);
  1081.       res->tstrips.push_back(vin1);
  1082.     }
  1083.     res->tstrips.push_back(vin3);
  1084.     res->tstrips.push_back(-1);
  1085.     numStrips++;
  1086.     newStrip = true;
  1087.     whichDiag = true;
  1088.   }
  1089. }
  1090.       }
  1091.       else if ((count == 2) || (count == 1)) {
  1092. // we need to end any current strips because there is going to be
  1093. // a hole in this row... fucking bug that now shall finally die
  1094. if (!newStrip) {
  1095.   res->tstrips.push_back(-1);
  1096.   newStrip = true;
  1097.   numStrips++;
  1098. }
  1099.       }
  1100.     }
  1101.     // at end of a stripe, so end any strip
  1102.     if (!newStrip) {
  1103.       res->tstrips.push_back(-1);
  1104.       newStrip = true;
  1105.       numStrips++;
  1106.     }
  1107.     
  1108.   }
  1109.   // if we haven't ended the current strip, end it
  1110.   if (!newStrip) {
  1111.     res->tstrips.push_back(-1);
  1112.     newStrip = true;
  1113.     numStrips++;
  1114.   }
  1115.   /*
  1116.   getVertexNormals (res->vtx, tstrips, true, res->nrm);
  1117.   */
  1118.   if (numStrips == 0) {
  1119.     cerr << "No triangle strips created." << endl;
  1120.     res->tstrips.push_back(-1);
  1121.   }
  1122.   else {
  1123.     fprintf(stderr, "%d t-strips (", numStrips);
  1124.     fprintf(stderr, "%5.2f avg length)n",
  1125.     (res->tstrips.size() - (3 * numStrips)) / (double) numStrips);
  1126.   }
  1127.   if (subSamp != 1) delete[] vert_remap;
  1128. }
  1129. void
  1130. MMScan::subsample_points(float rate, vector<Pnt3> &p, vector<Pnt3> &n)
  1131. {
  1132.   int nv = num_vertices(curr_res);
  1133.   int totalNum = (int)(rate * nv);
  1134.   if (totalNum > nv) totalNum = nv;
  1135.   
  1136.   p.clear(); p.reserve(totalNum);
  1137.   n.clear(); n.reserve(totalNum);
  1138.   for (int i=0; i < scans.size(); i++) {
  1139.     mmResLevel& res = scans[i].meshes[curr_res];
  1140.     int nv = res.vtx.size();
  1141.     int num = (int)(rate * nv);
  1142.     int end = nv;
  1143.     for (int j = 0; j < end; j++) {
  1144.       if (rnd(nv) <= num) {
  1145. p.push_back(res.vtx[j]);                  // save point
  1146. pushNormalAsPnt3 (n, res.nrm.begin(), j); // and norm
  1147. num--;
  1148.       }
  1149.       nv--;
  1150.     }
  1151.     assert(num == 0);
  1152.     if (p.size() > totalNum)
  1153.       printf("Selected too many points in the MMScan subsample proc.n");
  1154.   }
  1155. }
  1156. MMScan::mergedRegData&
  1157. MMScan::getRegData (void)
  1158. {
  1159.   mergedRegData& reg = regData[curr_res];
  1160.   if (!isDirty_mem && (reg.vtx.size() > 0)) return reg;
  1161.   cout << "Making new global vertex array" << endl;
  1162.   int numVerts = num_vertices(curr_res);
  1163.   reg.vtx.clear(); reg.vtx.reserve(numVerts);
  1164.   reg.nrm.clear(); reg.nrm.reserve(numVerts * 3);
  1165.   reg.tris.clear(); reg.tris.reserve(num_tris(curr_res) * 3);
  1166.   
  1167.   // used to reindex triangle vertices in the global array
  1168.   int reIndexFactor;
  1169.   for (int i = 0; i < scans.size(); i++) {
  1170.     reIndexFactor = reg.vtx.size();
  1171.     mmResLevel& res = scans[i].meshes[curr_res];
  1172.     for (int j = 0; j < res.vtx.size(); j++) {
  1173.       reg.vtx.push_back(res.vtx[j]);
  1174.       reg.nrm.push_back(res.nrm[3 * j + 0]);
  1175.       reg.nrm.push_back(res.nrm[3 * j + 1]);
  1176.       reg.nrm.push_back(res.nrm[3 * j + 2]);
  1177.     }
  1178.     for (j = 0; j < res.tris.size(); j++)
  1179.       reg.tris.push_back(res.tris[j] + reIndexFactor);
  1180.   }
  1181.   mark_boundary (reg);
  1182.   delete kdtree[curr_res];
  1183.   isDirty_mem = false;
  1184.   return reg;
  1185. }
  1186. void
  1187. MMScan::mark_boundary(mergedRegData& reg)
  1188. {
  1189.   if (!isDirty_mem && (reg.boundary.size() > 0)) return;
  1190.   reg.boundary.clear();
  1191.   int nVtx = reg.vtx.size();
  1192.   reg.boundary.reserve(nVtx);
  1193.   for (int j = 0; j < nVtx; j++) 
  1194.     reg.boundary.push_back(0);
  1195.   ::mark_boundary_verts(reg.boundary, reg.tris);
  1196.   cerr << "Marked boundary vertices for " << get_name() << endl;
  1197.   reg.tris.clear();     // not needed any more
  1198.   isDirty_mem = false;
  1199. }
  1200. KDindtree*
  1201. MMScan::get_kdtree()
  1202. {
  1203.   if ((!isDirty_mem) && (kdtree[curr_res] != NULL))
  1204.     return kdtree[curr_res];
  1205.   // necessary but evil step here: create global list of all
  1206.   // vertices and normals and triangles for this res,
  1207.   mergedRegData& reg = getRegData();
  1208.   delete kdtree[curr_res];
  1209.   kdtree[curr_res] = CreateKDindtree (reg.vtx.begin(),
  1210.       reg.nrm.begin(),
  1211.       reg.vtx.size());
  1212.   isDirty_mem = false;
  1213.   return kdtree[curr_res];
  1214. }
  1215. bool
  1216. MMScan::closest_point(const Pnt3 &p, const Pnt3 &n, 
  1217.       Pnt3 &cp, Pnt3 &cn,
  1218.       float thr, bool bdry_ok)
  1219. {
  1220.   int ind, ans;
  1221.   KDindtree* tree = get_kdtree();
  1222.   mergedRegData& reg = getRegData();
  1223.   ans = tree->search(reg.vtx.begin(), reg.nrm.begin(), p, n, ind, thr);
  1224.   if (ans) {
  1225.     if (bdry_ok == 0) {
  1226.       // disallow closest points that are on the mesh boundary
  1227.       if (reg.boundary[ind]) return 0;
  1228.     }
  1229.     cp = reg.vtx[ind];
  1230.     cn = reg.nrm[ind];
  1231.   }
  1232.   return ans;
  1233. }
  1234. void
  1235. MMScan::update_res_ctrl()
  1236. {
  1237.   for (int i = 0; i < resolutions.size(); i++) {
  1238.     resolutions[i].abs_resolution = num_tris (i);
  1239.   }
  1240. }
  1241. bool
  1242. MMScan::filter_inplace(const VertexFilter &filter)
  1243. {
  1244.   int i,j,k;
  1245.   mmScanFrag *scan;
  1246.   bool changedScan = false;
  1247.   
  1248.   // #1: loop through all scans
  1249.   for (j = 0; j < scans.size(); j++) {
  1250.     scan = &scans[0] + j;
  1251.     cout << "looking at scan #" << j << endl;
  1252.     if (scan->isVisible) {
  1253.       changedScan = false;      
  1254.       int maxVerts = scan->num_vertices(0);
  1255.       int *vert_remap = new int[maxVerts];
  1256.       for (i = 0; i < maxVerts; i++)
  1257. vert_remap[i] = -1;
  1258.       int count = 0, vtxIndex = 0;
  1259.       mmStripeInfo *stripe;
  1260.       for (k = 0; k < scan->stripes.size(); k++) {
  1261. stripe = &scan->stripes[0] + k;
  1262. for (i = 0; i < STRIPE_PTS; i++) {
  1263.   if (isValidPoint(j, k, i)) {
  1264.     if (filter.accept(scan->meshes[0].vtx[vtxIndex])) {
  1265.       vert_remap[vtxIndex] = count;
  1266.       count++;
  1267.       vtxIndex++;
  1268.     }
  1269.     else {
  1270.       stripe->validMap[i/8] &= ~(1 << (i % 8));
  1271.       stripe->numPoints--;
  1272.       vtxIndex++;
  1273.       changedScan = true;
  1274.     }
  1275.   }
  1276. }
  1277. if (stripe->numPoints > 0) {
  1278.   int newIndex = vert_remap[stripe->startIdx];
  1279.   while (newIndex == -1) {
  1280.     stripe->startIdx++;
  1281.     newIndex = vert_remap[stripe->startIdx];
  1282.   }
  1283.   stripe->startIdx = newIndex;
  1284. }
  1285. else {
  1286.   scan->stripes.erase(stripe);
  1287.   k--;
  1288. }
  1289.       }
  1290.       // either ditch the scan if it's now empty, or clip its resolutions
  1291.       // if it has been changed at all
  1292.       if (scan->stripes.size() == 0) {
  1293. cout << "scan #" << j << " didn't make it" << endl;
  1294. scans.erase(scan);
  1295. j--;
  1296.       }
  1297.       else if (changedScan) {
  1298. mmResLevel *res;
  1299. for (res = scan->meshes.begin(); res != scan->meshes.end(); res++) {
  1300.   
  1301.   if (res != scan->meshes.begin()) {
  1302.     cout << "res other than the first one" << endl;
  1303.     continue;
  1304.     // do something to find out about remapping
  1305.   }
  1306.   if (count == 0) {
  1307.     // no vertices made it... only applicable in lower res's i guess
  1308.     cout << "count equalled 0; scan bites the dust " << endl;
  1309.     scan->meshes.erase(res);
  1310.     res--;
  1311.     continue;
  1312.   }
  1313.   // delete the tstrips from the res since they are hard to clip
  1314.   res->tstrips.clear();
  1315.   vector<Pnt3> newVerts;
  1316.   vector<float> confidence;
  1317.   vector<uchar> intensity;
  1318.   vector<short> nrm;
  1319.   newVerts.reserve(count);
  1320.   if (res->confidence.size())
  1321.     confidence.reserve(count);
  1322.   if (res->intensity.size())
  1323.     intensity.reserve(count);
  1324.   if (res->nrm.size())
  1325.     nrm.reserve(3 * count);
  1326.   for (i = 0; i < res->vtx.size(); i++) {
  1327.     if (vert_remap[i] >= 0) {
  1328.       newVerts.push_back(res->vtx[i]);
  1329.       if (res->confidence.size()) {
  1330. confidence.push_back(res->confidence[i]);
  1331.       }
  1332.       if (res->intensity.size()) {
  1333. intensity.push_back(res->intensity[i]);
  1334.       }
  1335.       if (res->nrm.size()) {
  1336. nrm.push_back(res->nrm[i * 3 + 0]);
  1337. nrm.push_back(res->nrm[i * 3 + 1]);
  1338. nrm.push_back(res->nrm[i * 3 + 2]);
  1339.       }
  1340.     }
  1341.   }
  1342.   res->vtx.clear(); res->vtx = newVerts; newVerts.clear();
  1343.   res->confidence.clear(); res->confidence = confidence;
  1344.     confidence.clear();
  1345.   res->intensity.clear(); res->intensity = intensity;
  1346.     intensity.clear();
  1347.   res->nrm.clear(); res->nrm = nrm; nrm.clear();
  1348.   cout << "handling triangles " << endl;
  1349.   vector<int> newTris;
  1350.   // assume 2 times as many tris as points
  1351.   newTris.reserve(2 * count * 3);
  1352.   for (i = 0; i < res->tris.size(); i += 3) {
  1353.     int a, b, c;
  1354.     a = vert_remap[res->tris[i+0]];
  1355.     b = vert_remap[res->tris[i+1]];
  1356.     c = vert_remap[res->tris[i+2]];
  1357.     if ((a >= 0) && (b >= 0) && (c >= 0)) {
  1358.       newTris.push_back(a);
  1359.       newTris.push_back(b);
  1360.       newTris.push_back(c);
  1361.     }
  1362.   }
  1363.   res->tris.clear(); res->tris = newTris; newTris.clear();
  1364.   delete[] vert_remap;
  1365. }
  1366.       }
  1367.     }
  1368.   }
  1369.   update_res_ctrl();
  1370.   isDirty_mem = true;
  1371.   isDirty_disk = true;
  1372.   // important that we rebuild indices
  1373.   calcIndices();
  1374.   return true;
  1375. }
  1376. // copy the part of the mesh that is in the clip box
  1377. // into a new mmscan
  1378. RigidScan*
  1379. MMScan::filtered_copy(const VertexFilter& filter)
  1380. {
  1381.   int i, j, k;
  1382.   MMScan* newMesh = new MMScan;
  1383.   assert(newMesh != NULL);
  1384.   newMesh->setXform(getXform());
  1385.   newMesh->haveScanDir = false;
  1386.   // #1: loop through all scans
  1387.   for (j = 0; j < scans.size(); j++) {
  1388.     if (scans[j].isVisible) {
  1389.       mmScanFrag newScan;
  1390.       memcpy(newScan.falseColor, scans[j].falseColor, 3);
  1391.       // delete the auto-created mesh for our new scan
  1392.       newScan.meshes.pop_back();
  1393.       int vertIndex = 0;
  1394.       int vertCount = 0;
  1395.       vector<int> newIndices;
  1396.       
  1397.       // #2a: loop through each stripe in the scan,
  1398.       // to figure out which verts
  1399.       // make it and to generate valid stripe information
  1400.       // for the new mmscan
  1401.       for (k = 0; k < scans[j].stripes.size(); k++) {
  1402. mmStripeInfo stripe;
  1403. for (i = 0; i < 40; i++)
  1404.   stripe.validMap[i] = '';
  1405. for (i = 0; i < STRIPE_PTS; i++) {
  1406.   if (isValidPoint(j, k, i)) {
  1407.     if (filter.accept (scans[j].meshes[0].vtx[vertIndex])) {
  1408.       if (stripe.numPoints == 0) stripe.startIdx = vertCount;
  1409.       stripe.numPoints++;
  1410.       stripe.validMap[i/8] |= (1 << (i % 8));
  1411.       
  1412.       newIndices.push_back(1);
  1413.       vertCount++;
  1414.     }
  1415.     else newIndices.push_back(-1);
  1416.     vertIndex++;
  1417.   }
  1418. }
  1419. if (stripe.numPoints > 0) {
  1420.   stripe.sensorVec = scans[j].stripes[k].sensorVec;
  1421.   stripe.scanDir = 0;
  1422.   newScan.viewDir += stripe.scanDir;
  1423.   newScan.stripes.push_back(stripe);
  1424. }
  1425.       }
  1426.       if (newScan.stripes.size() > 0) {
  1427. // average and normalize current scan's view direction
  1428. newScan.viewDir /= (double)newScan.stripes.size();
  1429. newScan.viewDir.normalize();
  1430. // #2b: BEGIN looping through each mesh in the current scan.
  1431. // We're looking for resolutions that have their own vertices
  1432. // and tris based on those vertices.
  1433. // We basically clip and treat these exactly like the
  1434. // generic scan clips each of its meshes.
  1435. for (k = 0; k < scans[j].meshes.size(); k++) {
  1436.   mmResLevel newRes;
  1437.   mmResLevel *oldRes = &(scans[j].meshes[k]);
  1438.   
  1439.   int triCount = 0;
  1440.   
  1441.   // #3a: figure out which verts make the cut, except on the first
  1442.   // mesh where we already know
  1443.   if (k > 0) {
  1444.     vertCount = 0;
  1445.     for (i = 0; i < oldRes->vtx.size(); i++) {
  1446.       if (filter.accept (oldRes->vtx[i])) {
  1447. newIndices.push_back(1);
  1448. vertCount++;
  1449.       }
  1450.       else newIndices.push_back(-1);
  1451.     }
  1452.   }
  1453.   
  1454.   // #3b: figure out which tris make the cut
  1455.   
  1456.   for (i = 0; i < oldRes->tris.size(); i += 3) {
  1457.     if (newIndices[oldRes->tris[i  ]] >= 0 &&
  1458. newIndices[oldRes->tris[i+1]] >= 0 &&
  1459. newIndices[oldRes->tris[i+2]] >= 0) {
  1460.       triCount++;
  1461.     }
  1462.   }
  1463.   // #3c: copy the surviving vertices
  1464.   int count = 0;
  1465.   newRes.vtx.reserve (vertCount);
  1466.   if (oldRes->nrm.size())
  1467.     newRes.nrm.reserve (vertCount);
  1468.   if (oldRes->confidence.size())
  1469.     newRes.confidence.reserve (vertCount);
  1470.   if (oldRes->intensity.size())
  1471.     newRes.intensity.reserve (vertCount);
  1472.   for (i = 0; i < oldRes->vtx.size(); i++) {
  1473.     if (newIndices[i] > 0) {
  1474.       newIndices[i] = count;
  1475.       newRes.vtx.push_back(oldRes->vtx[i]);
  1476.       if (oldRes->nrm.size()) {
  1477. newRes.nrm.push_back(oldRes->nrm[i * 3 + 0]);
  1478. newRes.nrm.push_back(oldRes->nrm[i * 3 + 1]);
  1479. newRes.nrm.push_back(oldRes->nrm[i * 3 + 2]);
  1480.       }
  1481.       if (oldRes->confidence.size())
  1482. newRes.confidence.push_back(oldRes->confidence[i]);
  1483.       if (oldRes->intensity.size())
  1484. newRes.intensity.push_back(oldRes->intensity[i]);
  1485.     
  1486.       count++;
  1487.     }
  1488.   }
  1489.   // #3d: copy and reindex the surviving faces
  1490.   count = 0;
  1491.   newRes.tris.reserve (triCount * 3);
  1492.   for (i = 0; i < oldRes->tris.size(); i += 3) {
  1493.     if (newIndices[oldRes->tris[i  ]] >= 0 &&
  1494. newIndices[oldRes->tris[i+1]] >= 0 &&
  1495. newIndices[oldRes->tris[i+2]] >= 0) {
  1496.     
  1497.       for (int z = 0; z < 3; z++)
  1498. newRes.tris.push_back(-1);
  1499.       newRes.tris[count  ] = newIndices[oldRes->tris[i  ]];
  1500.       newRes.tris[count+1] = newIndices[oldRes->tris[i+1]];
  1501.       newRes.tris[count+2] = newIndices[oldRes->tris[i+2]];
  1502.     
  1503.       count += 3;
  1504.     }
  1505.   }
  1506.   // we're done with this resolution
  1507.   newScan.meshes.push_back(newRes);
  1508.   newIndices.clear();
  1509. } // end "for (k = 0; k < meshes.size(); k++)"
  1510. newMesh->scans.push_back(newScan);
  1511.       } // end "if (numStripes > 0)"
  1512.       
  1513.     } // end "if isVisible"
  1514.     else {
  1515.       // don't copy the scan... this line copies it if i change my mind
  1516.       // newMesh->scans.push_back(scans[j]);
  1517.     }
  1518.   } // end scan loop
  1519.   
  1520.   // seems like a bad idea, but we'll see
  1521.   if (newMesh->scans.size() == 0) return NULL;
  1522.   // finalize mmscan details
  1523.   for (i = 0; i < newMesh->scans[0].meshes.size(); i++) {
  1524.     int count = newMesh->num_tris(i);
  1525.     cerr << "mesh num " << i << " has " << count << " tris." << endl;
  1526.     char info[20];
  1527.     sprintf (info, ".clip%d", count);
  1528.     crope fragName (get_basename() + info);
  1529.     newMesh->insert_resolution(count, fragName, true, true);
  1530.   }
  1531.   newMesh->curr_res = curr_res;
  1532.   newMesh->isDirty_mem = newMesh->isDirty_disk = true;
  1533.   newMesh->computeBBox();
  1534.   crope clipName(get_basename());
  1535.   char info[20];
  1536.   sprintf(info, "clip.%d.mms", newMesh->num_vertices());
  1537.   clipName += info;
  1538.   newMesh->set_name (clipName);
  1539.   return newMesh;
  1540. }
  1541. //Apply filer... to every point in the highest resolution version
  1542. //of the file...
  1543. bool
  1544. MMScan::filter_vertices (const VertexFilter& filter, vector<Pnt3>& p)
  1545. {
  1546.   mmScanFrag *endScanFrag = scans.end();
  1547.     //for every mmScanFrag in scans vector
  1548.     for(mmScanFrag *curScanFrag = scans.begin();
  1549. curScanFrag < endScanFrag; curScanFrag++)
  1550.     {
  1551.       
  1552.       //get the current points vector (full resolution)
  1553.       vector<Pnt3> *curPtVector;
  1554.       curPtVector = &(curScanFrag->meshes[0].vtx);
  1555.       //for every point apply the function
  1556.       Pnt3 *vtxend = curPtVector->end();
  1557.       for(Pnt3 *pnt = curPtVector->begin(); pnt < vtxend; pnt++)
  1558. {
  1559.   if(filter.accept (*pnt))
  1560.     p.push_back(*pnt);
  1561. }
  1562.     }
  1563.   return true;
  1564. }
  1565. /* OLD_VERSION FROM GENERIC_SCAN
  1566. bool
  1567. MMScan::filter_vertices (const VertexFilter& filter, vector<Pnt3>& p)
  1568. {
  1569.   Mesh* mesh = currentMesh();
  1570.   Pnt3* vtxend = mesh->vtx.end();
  1571.   for (Pnt3* pnt = mesh->vtx.begin(); pnt < vtxend; pnt++) {
  1572.     if (filter.accept (*pnt))
  1573.       p.push_back (*pnt);
  1574.   }
  1575.   return true;
  1576. }
  1577. */
  1578. /*
  1579. // featherBoundary()
  1580. //
  1581. // takes a boundary-like array, containing 1 at boundary vertices, 2 at their
  1582. // adjacent vertices, etc.
  1583. // returns that same array, expanded to one more level
  1584. static void
  1585. featherBoundary(vector<char> &boundPlus, int level, vector<int> &tri_inds)
  1586. {
  1587.   for (int i = 0; i < tri_inds.size(); i+=3) {
  1588.     if ((boundPlus[tri_inds[i+0]] == level) ||
  1589. (boundPlus[tri_inds[i+1]] == level) ||
  1590. (boundPlus[tri_inds[i+2]] == level)) {
  1591.       for (int j = 0; j < 3; j++) {
  1592. if (boundPlus[tri_inds[i+j]] == 0)
  1593.   boundPlus[tri_inds[i+j]] = level + 1;
  1594.       }
  1595.     }
  1596.   }
  1597. }
  1598. */
  1599. #define FEASTEPS 15
  1600. #define FEARANGE 1.0
  1601. #define FEADIST  5.0
  1602. void
  1603. MMScan::calcConfidence()
  1604. {
  1605.   for (int k = 0; k < scans.size(); k++) {
  1606.     /*
  1607.     // method one: only connectivity
  1608.     vector<char> boundPlus = scans[k].boundary;
  1609.     for (int i = 1; i < FEASTEPS; i++)
  1610.       featherBoundary(boundPlus, i, scans[k].meshes[0].tris);
  1611.     scans[k].meshes[0].confidence.clear();
  1612.     scans[k].meshes[0].confidence.reserve(scans[k].num_vertices());
  1613.     for (i = 0; i < scans[k].num_vertices(); i++) {
  1614.       float conf = 1.0;
  1615.       if (boundPlus[i] > 0)
  1616. conf = (1.0 - FEARANGE) + (boundPlus[i] / (float)FEASTEPS) * FEARANGE;
  1617.       
  1618.       scans[k].meshes[0].confidence.push_back(conf);
  1619.     }
  1620.     boundPlus.clear();
  1621.     */
  1622.     // method two: kari
  1623.     vector<float> distances;
  1624.     cout << "calculating distances" << endl;
  1625.     distance_from_boundary(distances, scans[k].meshes[0].vtx,
  1626.    scans[k].meshes[0].tris);
  1627.     cout << "done" << endl << endl;
  1628.     mmResLevel& scan = scans[k].meshes[0];
  1629.     scan.confidence.clear();
  1630.     scan.confidence.reserve(scan.num_vertices());
  1631.     for (int i = 0; i < scan.num_vertices(); i++) {
  1632.       float conf;
  1633.       if (distances[i] < FEADIST)
  1634. conf = (distances[i] / FEADIST);
  1635.       else conf = 1.0;
  1636.       scan.confidence.push_back(conf);
  1637.     }
  1638.   }
  1639. }
  1640. // check whether some vertices in vtx are not being used in tri
  1641. // if so, remove them and also adjust the tri indices
  1642. // stolen from TriMeshUtils.cc and modified for stripe purposes
  1643. static void
  1644. remove_unused_vtxs(vector<Pnt3> &vtx,
  1645.    vector<int>  &tri, vector<int> &vtx_ind)
  1646. {
  1647.   // assume vtx_ind is initialized to -1's
  1648.   // march through the triangles
  1649.   // and mark the vertices that are actually used
  1650.   int n = tri.size();
  1651.   for (int i=0; i<n; i+=3) {
  1652.     vtx_ind[tri[i+0]] = tri[i+0];
  1653.     vtx_ind[tri[i+1]] = tri[i+1];
  1654.     vtx_ind[tri[i+2]] = tri[i+2];
  1655.   }
  1656.   // remove the vertices that were not marked,
  1657.   // also keep tab on how the indices change
  1658.   int cnt = 0;
  1659.   n = vtx.size();
  1660.   for (i=0; i<n; i++) {
  1661.     if (vtx_ind[i] != -1) {
  1662.       vtx_ind[i] = cnt;
  1663.       vtx[cnt] = vtx[i];
  1664.       cnt++;
  1665.     }
  1666.   }
  1667.   vtx.erase(&vtx[cnt], vtx.end());
  1668.   // march through triangles and correct the indices
  1669.   n = tri.size();
  1670.   for (i=0; i<n; i+=3) {
  1671.     tri[i+0] = vtx_ind[tri[i+0]];
  1672.     tri[i+1] = vtx_ind[tri[i+1]];
  1673.     tri[i+2] = vtx_ind[tri[i+2]];
  1674.     assert(tri[i+0] >=0 && tri[i+0] < vtx.size());
  1675.     assert(tri[i+1] >=0 && tri[i+1] < vtx.size());
  1676.     assert(tri[i+2] >=0 && tri[i+2] < vtx.size());
  1677.   }
  1678. }
  1679. /*
  1680. void
  1681. MMScan::filter_unused_vtx(mmScanFrag *scan)
  1682. {
  1683.   int numVerts = scan->num_vertices();
  1684.   int numStripes = scan->num_stripes();
  1685.   vector<int> vtx_ind(numVerts, -1);
  1686.   remove_unused_vtxs(scan->meshes[0]->vtx, scan->meshes[0]->tris, vtx_ind);
  1687.   int numChecked = 0, numKept = 0, expected = 0;
  1688.   for(int i = 0; i < numStripes; i++) {
  1689.     mmStripeInfo *stripe = scan->stripes + i;
  1690.     stripe->startIdx = numKept;
  1691.     for (int j = 0; j < STRIPE_PTS; j++) {
  1692.       if (scan->stripes[i].validMap[j / 8] & (1 << (j % 8))) {
  1693. // found a valid point in the map... check to see if it died
  1694. if (vtx_ind[numChecked] != expected) {
  1695.       stripe->validMap[j/8] &= ~(1 << (j % 8));
  1696.   
  1697.   
  1698. }
  1699. */
  1700. /*
  1701. void
  1702. MMScan::drawSensorVecs(vector<int> &tris)
  1703.   // draws a triangle at every 30th point in the mesh, where the triangle is
  1704.   // oriented towards the sensor vector at that point
  1705. {
  1706.   Pnt3 perp, p1, p2, dir;
  1707.   for(int i = 0; i < scans.size(); i++) {
  1708.     // loop through all scans
  1709.     int count = 0;
  1710.     for(int j = 0; j < scans[i].stripes.size(); j++) {
  1711.       for(int k = 0; k < STRIPE_PTS; k++) {
  1712. if (isValidPoint(i,j,k)) {
  1713.   if (count % 30 == 0) {
  1714.     dir = scans[i].stripes[j].sensorVec;
  1715.     perp.set(1 * dir[1], -1 * dir[0], 0.0);
  1716.     perp.normalize();
  1717.     perp /= 5.0;
  1718.     p2 = scans[i].meshes[0].vtx[count] + dir + perp;
  1719.     p1 = scans[i].meshes[0].vtx[count] + dir - perp;
  1720.     scans[i].meshes[0].vtx.push_back(p2);
  1721.     scans[i].meshes[0].vtx.push_back(p1);
  1722.     Pnt3 newnrm = cross(perp, dir).normalize();
  1723.     newnrm *= 32767;
  1724.     scans[i].meshes[0].nrm.push_back(newnrm[0]);
  1725.     scans[i].meshes[0].nrm.push_back(newnrm[1]);
  1726.     scans[i].meshes[0].nrm.push_back(newnrm[2]);
  1727.     scans[i].meshes[0].nrm.push_back(newnrm[0]);
  1728.     scans[i].meshes[0].nrm.push_back(newnrm[1]);
  1729.     scans[i].meshes[0].nrm.push_back(newnrm[2]);
  1730.     scans[i].meshes[0].tris.push_back(count);
  1731.     scans[i].meshes[0].tris.push_back(scans[i].num_vertices(0)-2);
  1732.     scans[i].meshes[0].tris.push_back(scans[i].num_vertices(0)-1);
  1733.   }
  1734.   count++;
  1735. }
  1736.       }
  1737.     }
  1738.   }
  1739. }
  1740. */
  1741. ////////////////////////////////////////////
  1742. // UTILITY I/O FUNCTIONS
  1743. ////////////////////////////////////////////
  1744. // --------------------------
  1745. // struct mmIO
  1746. //    o  used to organize data for input and output to CTA files
  1747. typedef struct {
  1748.   double vtx[3];
  1749.   double nrm[3];
  1750.   int inten;       // these two ints are just used to capture 8 bytes
  1751.   int mode;        // all of the info seems to be in bytes 7 and 8.
  1752. } mmIO;
  1753. // struct MMSio
  1754. //    o  used to organize data for i/o to the new MMS format files
  1755. typedef struct {
  1756.   float v[3];
  1757.   char  bytes[4];   // make struct word-aligned
  1758.                     // intensity is first byte, mode second
  1759. } MMSio;
  1760. typedef struct {
  1761.   unsigned char validMap[40];
  1762.   int    numPoints;
  1763.   double sensorVec[3];
  1764.   char   scanDir[4]; // 4 chars for word-alignment; scanDir is 1st byte
  1765. } MMSstripe;
  1766. static void 
  1767. CopyReverseWord (void* dest, void* src, int nWords)
  1768.   // like memcpy but copies 32-bit words instead of bytes,
  1769.   // and flips byte order
  1770.   // to convert endian-ness as it copies.  
  1771.   // ***NOTE***: this version is set-up to do nothing on win32 machines and
  1772.   // to swap on unix machines... should be used for modelmaker files only
  1773. {
  1774.   #ifdef WIN32
  1775.   if (src == dest) return;
  1776.   memcpy(dest, src, nWords * 4);
  1777.   return;
  1778.   #else
  1779.   for (int i = 0; i < nWords; i++) {
  1780.     unsigned int temp = *(unsigned int*)src;
  1781.     
  1782.     temp = (temp >> 24) | ((temp >> 8) & 0xFF00) | 
  1783.       ((temp << 8) & 0xFF0000) | (temp << 24);
  1784.     (*(unsigned int*)dest) = temp;
  1785.     src  = ((char*)src)  + 4;
  1786.     dest = ((char*)dest) + 4;
  1787.   }
  1788.   #endif
  1789. }
  1790. static double
  1791. WSwap(double in)
  1792. // switches the word-order in an 8-byte double
  1793. // DOES NOTHING on a win32 machine (for modelmaker conversions to unix only)
  1794. {
  1795.   #ifdef WIN32
  1796.   return in;
  1797.   #else
  1798.   double out;
  1799.   *((int *)&out) = *(((int *)&in) + 1);
  1800.   *(((int *)&out) + 1) = *((int *)&in);
  1801.   return out;
  1802.   #endif
  1803. }
  1804. // overloaded MMS version of the other ReversePoints
  1805. static void 
  1806. ReversePoints(MMSio *points, int numPoints) {
  1807.   // switches word-byte order for an array of inputted points
  1808.   // does nothing on win32 machines since the endian is correct there
  1809.   #ifdef WIN32
  1810.      return;
  1811.   #else
  1812.   CopyReverseWord(points, points, numPoints * sizeof(MMSio) / 4);
  1813.   // shouldn't need to swap word order since we're dealing with floats
  1814.   #endif
  1815. }
  1816. static void 
  1817. ReversePoints(mmIO *points, int numPoints) {
  1818.   // switches word-byte order for an array of inputted points
  1819.   // does nothing on win32 machines since the endian is correct there
  1820.   #ifdef WIN32
  1821.      return;
  1822.   #else
  1823.   CopyReverseWord(points, points, numPoints * sizeof(mmIO) / 4);
  1824.   for (int i = 0; i < numPoints; i++) {
  1825.     for (int j = 0; j < 3; j++) {
  1826.       points[i].vtx[j] = WSwap(points[i].vtx[j]);
  1827.       points[i].nrm[j] = WSwap(points[i].nrm[j]);
  1828.     }
  1829.   }
  1830.   #endif
  1831. }
  1832. static void 
  1833. triSet(float *dest, Pnt3 *src)
  1834.   // converts Pnt3 -> float[3]; used to store mms files
  1835.   // needs to be rewritten for doubles if we bring back cta writing
  1836. {
  1837.   dest[0] = (*src)[0];
  1838.   dest[1] = (*src)[1];
  1839.   dest[2] = (*src)[2];
  1840. }
  1841. // returns true if the indexed stripe and its successor are so similar
  1842. // that we can trash one of them
  1843. bool
  1844. MMScan::stripeCompare(int strNum, mmScanFrag *scan)
  1845. {
  1846.   if (strNum < 0) return false;
  1847.   mmStripeInfo *str1 = &scan->stripes[0] + strNum;
  1848.   mmStripeInfo *str2 = &scan->stripes[0] + strNum + 1;
  1849.   // if we're gaining more points as we go along, something interesting
  1850.   // is probably happening and we want to keep everything
  1851.   if (abs(str1->numPoints - str2->numPoints) > 5) return false;
  1852.   float avgDist = 0, numLargeDist = 0;
  1853.   int numPts = 0, count1 = 0, count2 = 0;
  1854.   for (int i = 0; i < STRIPE_PTS; i++) {
  1855.     bool valid1 = (str1->validMap[i / 8] & (1 << (i % 8)));
  1856.     bool valid2 = (str2->validMap[i / 8] & (1 << (i % 8)));
  1857.     if (valid1 && valid2) {
  1858.       // they have a point in common
  1859.       numPts++;
  1860.       float d = dist(scan->meshes[0].vtx[str1->startIdx + count1],
  1861.      scan->meshes[0].vtx[str2->startIdx + count2]);
  1862.       if (d > 0.25) {
  1863. numLargeDist++;
  1864.       }
  1865.       avgDist += d;
  1866.     }
  1867.     if (valid1) count1++;
  1868.     if (valid2) count2++;
  1869.   }
  1870.   // if less than 95% of the points are in common, something interesting
  1871.   // might be happening. this also catches the div by 0 on the next command
  1872.   if (numPts < (0.95 * str1->numPoints)) return false;
  1873.   avgDist /= numPts;
  1874.   
  1875.   if ((avgDist < 0.1) && (numLargeDist < 5)) return true;
  1876.   return false;
  1877. }
  1878.   
  1879. // *****************************************
  1880. // I/O FUNCTIONS: read and write
  1881. // *****************************************
  1882. bool
  1883. MMScan::read_mms(const crope &fname)
  1884. {
  1885.   mmStripeInfo stripe;
  1886.   mmScanFrag *scan;
  1887.   ColorSet cset;
  1888.   int numStripes, numPoints, numScans;
  1889.   int *numVerts; // tallies for each scanfrag for vertex allocs
  1890.   int i, j;
  1891.   MMSstripe *stripes;
  1892.   MMSio *points;
  1893.   //bool versionT = false, versionN = false;
  1894.   const char *filename = fname.c_str();
  1895.   FILE *pFile = fopen(filename, "rb");
  1896.   
  1897.   // check that file opened OK
  1898.   if( !pFile )
  1899.     return false;
  1900.   // read file version info
  1901.   char szFileID[10] = "";
  1902.   fread( szFileID, 10, 1, pFile );
  1903.   if ((strcmp(szFileID, "BinVer1.0") == 0) ||
  1904.       (strncmp(szFileID, "MMSBin", 6) == 0)) {
  1905.     cerr << "------------------" << endl;
  1906.     cerr << "This is an antiquated preliminary version of the MMS format."
  1907.  << endl << "We're not dealing with it anymore. My apologies."
  1908.  << endl;
  1909.     cerr << "------------------" << endl;
  1910.     return false;
  1911.   }
  1912.   else if (strncmp(szFileID, "MMScan", 6) == 0) {
  1913.     //versionT = versionN = false;
  1914.     for (int i = 6; i < 9; i++) {
  1915.       switch(szFileID[i]) {
  1916.         case 'T' : //versionT = true;
  1917.               cerr << "Found pretriangulation" << endl;
  1918.    break;
  1919.         case 'N' : //versionN = true;
  1920.            cerr << "Found per-vertex normals" << endl;
  1921.    break;
  1922.         case 'x' : break;
  1923.         default  : cerr << endl << "Unrecognized flag in MMScan string: "
  1924. << szFileID[i] << endl;
  1925.            return false;
  1926.       }
  1927.     }
  1928.   }
  1929.   else {
  1930.     cerr << "Bad version information for " << filename << ": string " <<
  1931.       szFileID << endl;
  1932.     return false;
  1933.   }
  1934.   // get number of stripes
  1935.   fread(&numStripes, sizeof( int ), 1, pFile );
  1936.   //  CopyReverseWord(&numStripes, &numStripes, 1);
  1937.   // get number of points
  1938.   fread(&numPoints, sizeof( int ), 1, pFile);
  1939.   //  CopyReverseWord(&numPoints, &numPoints, 1);
  1940.   // get number of scans
  1941.   fread(&numScans, sizeof( int ), 1, pFile);
  1942.   
  1943.   cout << "Reading " << numPoints << " points, " 
  1944.        << numStripes << " stripes, "
  1945.        << numScans << " scans." << endl;
  1946.   // get stripes
  1947.   Progress progress (numStripes, "%s: reading stripes", filename);
  1948.   stripes = new MMSstripe[numStripes];
  1949.   if (stripes == NULL) {
  1950.     cerr << "Couldn't allocate enough memory for " 
  1951.  << numStripes << " stripes" << endl;
  1952.     return false;
  1953.   }
  1954.   fread(stripes, sizeof (MMSstripe) * numStripes, 1, pFile);
  1955.   scans.reserve(numScans);
  1956.   // prepare first scan
  1957.   scan = new mmScanFrag;
  1958.   numVerts = new int[numScans];
  1959.   for (i = 0; i < numScans; i++)
  1960.     numVerts[i] = 0;
  1961.   // set up stripes and organize them into scan fragments (no points yet)
  1962.   for(i = 0; i < numStripes; i++ )
  1963.   {
  1964.     if (stripes[i].numPoints > 0) {
  1965.       // keep this stripe, add it to current scanfrag
  1966.       for (j = 0; j < 40; j++)
  1967. stripe.validMap[j] = stripes[i].validMap[j];
  1968.       stripe.numPoints = stripes[i].numPoints;
  1969.       stripe.scanDir = stripes[i].scanDir[0];
  1970.       stripe.sensorVec.set(stripes[i].sensorVec);
  1971.     
  1972.       stripe.startIdx = numVerts[scans.size()];
  1973.       numVerts[scans.size()] += stripe.numPoints;
  1974.       scan->stripes.push_back(stripe);
  1975.       scan->viewDir += stripe.sensorVec;
  1976.     }
  1977.     else if (scan->num_stripes() > 1) {
  1978.       // nothing in this stripe, but we need to end the scanfrag
  1979.       scan->viewDir /= (double)scan->num_stripes();
  1980.       scan->viewDir.normalize();
  1981.       cset.chooseNewColor(scan->falseColor);
  1982.       // reserve geometry and intensity space for our soon-to-arrive points
  1983.       scan->meshes[0].vtx.reserve(numVerts[scans.size()]);
  1984.       scan->meshes[0].intensity.reserve(numVerts[scans.size()]);
  1985.       // prepare for next scanfrag
  1986.       scans.push_back(*scan);
  1987.       delete scan;
  1988.       scan = new mmScanFrag;
  1989.     }
  1990.     else {
  1991.       // shouldn't ever be here if filtered properly... no points in stripe
  1992.       // and not enough stripes in scan to save it
  1993.       delete scan;
  1994.       scan = new mmScanFrag;
  1995.     }
  1996.     if ((i % 100) == 0) progress.update(i+1);
  1997.   }
  1998.   // get rid of i/o struct for stripes
  1999.   delete[] stripes;
  2000.   // set up points i/o
  2001.   points = new MMSio[numPoints];
  2002.   if (!points) {
  2003.     cerr << "Couldn't allocate memory for " << numPoints 
  2004.  << " points." << endl;
  2005.     return false;
  2006.   }
  2007.   fread(points, sizeof(MMSio) * numPoints, 1, pFile);
  2008.   // put points into scanfrags
  2009.   Progress progress2(numPoints, "%s: reading points", filename);
  2010.   int numSoFar = 0;
  2011.   for (i = 0; i < numScans; i++) {
  2012.     for (j = 0; j < numVerts[i]; j++, numSoFar++) {
  2013.       Pnt3 p;
  2014.       p.set(points[numSoFar].v);
  2015.       scans[i].meshes[0].vtx.push_back(p);
  2016.       scans[i].meshes[0].intensity.push_back(points[numSoFar].bytes[0]);
  2017.     }
  2018.     progress2.update(numSoFar);
  2019.   }
  2020.   // close file
  2021.   fclose( pFile );
  2022.   return true;
  2023. }  
  2024. bool
  2025. MMScan::read_cta(const crope &fname)
  2026. {
  2027.   mmIO points[STRIPE_PTS], sensorVec;
  2028.   mmStripeInfo stripe;
  2029.   mmScanFrag *scan;
  2030.   mmResLevel *mesh;
  2031.   Pnt3 point, norm;
  2032.   uchar intensity;
  2033.   int numStripes, numSkipped;
  2034.   ColorSet cset;
  2035.   const char *filename = fname.c_str();
  2036.   FILE *pFile = fopen(filename, "rb");
  2037.   
  2038.   // check that file opened OK
  2039.   if( !pFile )
  2040.     return false;
  2041.   // read file version info
  2042.   char szFileID[10] = "";
  2043.   fread( szFileID, 10, 1, pFile );
  2044.   
  2045.   // get number of stripes
  2046.   
  2047.   fread(&numStripes, sizeof( int ), 1, pFile );
  2048.   CopyReverseWord(&numStripes, &numStripes, 1);
  2049.   Progress progress (numStripes, "%s: read CTA file", filename);
  2050.   // prepare first scan
  2051.   scan = new mmScanFrag;
  2052.   mesh = &(scan->meshes[0]);
  2053.   bool doFilter = true;
  2054.   char *result =
  2055.     Tcl_GetVar(theScene->interp, "noMMFilter", TCL_GLOBAL_ONLY);
  2056.   if (result)
  2057.     if ((strcmp(result, "1") == 0) || (strcmp(result, "true") == 0)) {
  2058.       doFilter = false;
  2059.       cout << "NOT FILTERING CTA FILE AS REQUESTED IN .RC" << endl;
  2060.     }
  2061.   // load stripes
  2062.   for( int i = 0; i < numStripes; i++ )
  2063.   {
  2064.     // load map
  2065.     fread( &stripe.validMap, 40, 1, pFile );
  2066.     
  2067.     // load number of points in stripe
  2068.     fread(&stripe.numPoints, sizeof( int ), 1, pFile );
  2069.     CopyReverseWord(&stripe.numPoints, &stripe.numPoints, 1);
  2070.     
  2071.     stripe.startIdx = scan->num_vertices(0);
  2072.     // load points if there are any
  2073.     if(stripe.numPoints > 0 )
  2074.     {
  2075.       
  2076.       // load and reverse points
  2077.       fread(points, sizeof(mmIO)* stripe.numPoints, 1, pFile );
  2078.       ReversePoints(points, stripe.numPoints);
  2079.       // store points
  2080.       for (int j = 0; j < stripe.numPoints; j++) {
  2081. point.set(points[j].vtx);
  2082. // note: we're discarding normals in the cta file because
  2083. // they're not measured, just generated really poorly
  2084. // intensity is the 4th byte of the first variable
  2085. intensity = *((char *)(&points[j].inten)+3);
  2086. mesh->vtx.push_back(point);
  2087. mesh->intensity.push_back(intensity);
  2088.       }
  2089.     }
  2090.     // read sensor vector (using first 24 bytes of mmIO struct)
  2091.     fread(&sensorVec, 3 * sizeof(double), 1, pFile );
  2092.     ReversePoints(&sensorVec, 1);
  2093.     stripe.sensorVec.set(sensorVec.vtx);
  2094.     // save stripe ONLY if there are 5 points on the stripe.. otherwise end
  2095.     // the scan.
  2096.     if ((stripe.numPoints < 5) && (stripe.numPoints > 0)) {
  2097.       numSkipped++;
  2098.     }
  2099.     else if (stripe.numPoints > 0) {
  2100.       scan->stripes.push_back(stripe);
  2101.       if (doFilter && stripeCompare(scan->stripes.size() - 2, scan)) {
  2102. for (int j = 0; j < stripe.numPoints; j++) {
  2103.   mesh->vtx.pop_back();
  2104.   mesh->intensity.pop_back();
  2105. }
  2106. scan->stripes.pop_back();
  2107. numSkipped++;
  2108.       }
  2109.       else
  2110. scan->viewDir += stripe.sensorVec;
  2111.     }
  2112.     else if (scan->num_stripes() > 2) {
  2113.       // end current scan and save if it has at least 3 stripes
  2114.       scan->viewDir /= (double)scan->num_stripes();
  2115.       scan->viewDir.normalize();
  2116.       cset.chooseNewColor(scan->falseColor);
  2117.       scans.push_back(*scan);
  2118.       delete scan;
  2119.       scan = new mmScanFrag;
  2120.       mesh = &(scan->meshes[0]);
  2121.     }
  2122.     else { // no points on stripe and not enough information in scan
  2123.       numSkipped += scan->num_stripes();
  2124.       delete scan;
  2125.       scan = new mmScanFrag;
  2126.       mesh = &(scan->meshes[0]);
  2127.     }
  2128.     if ((i % 100) == 0) progress.update(i+1);
  2129.   }
  2130.   
  2131.   // close file
  2132.   fclose( pFile );
  2133.   if (numSkipped) cout << "SKIPPED " << numSkipped 
  2134.        << "STRIPES while loading." << endl;
  2135.   return true;
  2136. }
  2137.  
  2138. bool
  2139. MMScan::read(const crope &fname)
  2140. {
  2141.   set_name(fname);
  2142.   // can only read cta and mms files
  2143.   if (has_ending(".mms")) {
  2144.     if (!read_mms(fname)) return false;
  2145.   }
  2146.   else if (!(has_ending(".cta") && read_cta(fname)))
  2147.     return false;
  2148.   // should be OK here
  2149.   /* debug code
  2150.   for(i=0; i < scans.size(); i++) {
  2151.     printf("scan %d: %d stripesn", i, scans[i].stripes.size());
  2152.     printf("         (%5.2f, %5.2f, %5.2f) viewDirn", scans[i].viewDir[0],
  2153.    scans[i].viewDir[1], scans[i].viewDir[2]);
  2154.     printf("         %d pointsn", scans[i].vtx.size());
  2155.     for(int j=0; j < scans[i].stripes.size(); j++) {
  2156.       printf("  stripe %d: %d pointsn", j, scans[i].stripes[j].numPoints);
  2157.       printf("     %d pointIdxn", scans[i].stripes[j].startIdx);
  2158.       printf("     (%5.2f, %5.2f, %5.2f) sensorn",
  2159.      scans[i].stripes[j].sensorVec[0],
  2160.      scans[i].stripes[j].sensorVec[1],
  2161.      scans[i].stripes[j].sensorVec[2]);
  2162.     }
  2163.   }
  2164.   */
  2165.   // insert resolutions... real and subsampled
  2166.   int ntris = scans[0].num_tris();
  2167.   if (!ntris) { // compute estimate
  2168.     for (int ifrag = 0; ifrag < scans.size(); ifrag++)
  2169.       ntris += scans[ifrag].meshes[0].vtx.size() * 2;
  2170.   }
  2171.   for (int iss = 0; iss < SUBSAMPS; iss++) {
  2172.     insert_resolution (ntris / (1 << (2*iss)), fname, false, false);
  2173.     kdtree.push_back (NULL);
  2174.     regData.push_back(mergedRegData());
  2175.     if (iss > 0) {
  2176.       for (int ifrag = 0; ifrag < scans.size(); ifrag++)
  2177. scans[ifrag].meshes.push_back(mmResLevel());
  2178.     }
  2179.   }
  2180.   /*
  2181.   fprintf(stderr, "Calculating confidence...n");
  2182.   calcConfidence();
  2183.   */
  2184.   /*
  2185.   fprintf(stderr, "Removing unused vertices... ");
  2186.   for (int i = 0; i < scans.size(); i++) {
  2187.     filter_unused_vtx(scans[i]);
  2188.   }
  2189.   */
  2190.   // try to load .xf file
  2191.   TbObj::readXform (get_basename());
  2192.   // we just wiped out whatever was in memory, but it's identical to what's
  2193.   // on disk, so set the memory update flag on
  2194.   isDirty_mem = true;
  2195.   select_coarsest();
  2196.   computeBBox();
  2197.   return true;
  2198. }
  2199. // writes an mms file
  2200. bool
  2201. MMScan::write(const crope &fname)
  2202. {
  2203.   MMSstripe blankStripe;
  2204.   int i, j, k;
  2205.   MMSstripe *stripes;
  2206.   MMSio *points;
  2207.   if (fname.empty()) {
  2208.     // try to save to default name; quit if there isn't one
  2209.     if (name.empty()) return false;
  2210.   }
  2211.   else {
  2212.     if (name != fname) {
  2213.       cout << "Saving to filename " << fname << endl;
  2214.       set_name(fname);
  2215.     }
  2216.   }
  2217.   for (i=0; i < 3; i++) {
  2218.     blankStripe.sensorVec[i] = 0.0;
  2219.   }
  2220.   
  2221.   for (i=0; i < 40; i++)
  2222.     blankStripe.validMap[i] = '';
  2223.   blankStripe.numPoints = 0;
  2224.   blankStripe.scanDir[0] = 0;
  2225.   Progress progress (num_stripes(), "%s: writing stripes", name.c_str());
  2226.   FILE *pFile = fopen(name.c_str(), "wb");
  2227.   if (!pFile)
  2228.     return false;
  2229.   // file version
  2230.   char szFileID[10] = "MMScanxxx";
  2231.   if( !fwrite( szFileID, 10, 1, pFile ) )
  2232.   {
  2233.     fclose( pFile );
  2234.     return false;
  2235.   }
  2236.   int numStripes, numPoints, numScans;
  2237.   // number of stripes plus blank ones
  2238.   numStripes = num_stripes() + scans.size();
  2239.   numScans = num_scans();
  2240.   numPoints = num_vertices(0);
  2241.   //  CopyReverseWord(intBuf, &tmp, 1);
  2242.   if(!fwrite(&numStripes, sizeof(int), 1, pFile)) {
  2243.     fclose(pFile);
  2244.     return false;
  2245.   }
  2246.   if(!fwrite(&numPoints, sizeof(int), 1, pFile)) {
  2247.     fclose(pFile);
  2248.     return false;
  2249.   }
  2250.   if (!fwrite(&numScans, sizeof(int), 1, pFile)) {
  2251.     fclose(pFile);
  2252.     return false;
  2253.   }
  2254.   int numSoFar = 0;
  2255.   stripes = new MMSstripe[numStripes];
  2256.   // loop through all scans, build up master stripe list
  2257.   for (i = 0; i < numScans; i++) {
  2258.     for (j = 0; j < scans[i].stripes.size(); j++, numSoFar++) {
  2259.       for (k = 0; k < 40; k++)
  2260. stripes[numSoFar].validMap[k] = scans[i].stripes[j].validMap[k];
  2261.       stripes[numSoFar].numPoints = scans[i].stripes[j].numPoints;
  2262.       for (k = 0; k < 3; k++)
  2263. stripes[numSoFar].sensorVec[k] = scans[i].stripes[j].sensorVec[k];
  2264.       stripes[numSoFar].scanDir[0] = scans[i].stripes[j].scanDir;
  2265.       progress.update(numSoFar);
  2266.       if (numSoFar == numStripes)
  2267. cerr << "reached the end of our array " << endl;
  2268.       
  2269.     }
  2270.     stripes[numSoFar] = blankStripe;
  2271.     numSoFar++;
  2272.     progress.update(numSoFar);
  2273.   }
  2274.   if (numSoFar != numStripes) {
  2275.     cerr << "Mismatch happened while building stripe i/o array" << endl;
  2276.     cerr << "numSoFar = " << numSoFar << ", numStripes = " << numStripes <<
  2277.       endl;
  2278.     return false;
  2279.   }
  2280.   if (!fwrite(stripes, sizeof(MMSstripe) * numStripes, 1, pFile)) {
  2281.     fclose(pFile);
  2282.     cerr << "Couldn't write stripes to disk whilst saving. " << endl;
  2283.     return false;
  2284.   }
  2285.   delete[] stripes;
  2286.   points = new MMSio[numPoints];
  2287.   Progress progress2(numScans, "%s: writing points", name.c_str());
  2288.   numSoFar = 0;
  2289.   for (i = 0; i < numScans; i++) {
  2290.     progress2.update(i);
  2291.     for (j = 0; j < scans[i].meshes[0].vtx.size(); j++, numSoFar++) {
  2292.       for (k = 0; k < 3; k++)
  2293. points[numSoFar].v[k] = scans[i].meshes[0].vtx[j][k];
  2294.       points[numSoFar].bytes[0] = scans[i].meshes[0].intensity[j];
  2295.     }
  2296.   }
  2297.   if (numSoFar != numPoints) {
  2298.     cerr << "Mismatch whilst setting up vertex i/o arrays." << endl;
  2299.     return false;
  2300.   }
  2301.   if (!fwrite(points, sizeof(MMSio) * numPoints, 1, pFile)) {
  2302.     fclose(pFile);
  2303.     cerr << "Couldn't write points to disk whilst saving. " << endl;
  2304.     return false;
  2305.   }
  2306.   delete[] points;
  2307.   // close file
  2308.   fclose( pFile );
  2309.   return true;
  2310. }