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

3D图形编程

开发平台:

Visual C++

  1. //############################################################
  2. // 
  3. // SDfile.cc
  4. //
  5. // Kari Pulli
  6. // Tue Feb 23 13:09:27 CET 1999
  7. //
  8. // Read, write, and store the raw data of an *.sd file
  9. //
  10. //############################################################
  11. #include "SDfile.h"
  12. #include "VertexFilter.h"
  13. #include "Random.h"
  14. #include "Median.h"
  15. #include <algorithm>
  16. #ifdef WIN32
  17. # define __median _Median
  18. # define gzclose fclose
  19. int gzread (FILE* file, void* buf, int size)
  20. {
  21. return fread (buf, 1, size, file);
  22. }
  23. #else
  24. # include <zlib.h>
  25. #endif
  26. using std::__median;
  27. #if 1
  28. # include "plvGlobals.h"
  29. #else
  30. bool g_bNoIntensity = false;
  31. bool g_verbose = false;
  32. #endif
  33. #if defined(WIN32) || defined(i386)
  34. #define LITTLE_ENDIAN
  35. #endif
  36. #ifdef LITTLE_ENDIAN
  37. #define swap_short(x) ( (((x) & 0xff) << 8) | ((unsigned short)(x) >> 8) )
  38. #define swap_long(x) ( ((x) << 24) | 
  39.                        (((x) << 8) & 0x00ff0000) | 
  40.        (((x) >> 8) & 0x0000ff00) | 
  41.        ((x) >> 24) )
  42. static short sg_swapbuf_short;
  43. static float sg_swapbuf_float;
  44. static int sg_swapbuf_int;
  45. #define FIX_SHORT(x) (*(unsigned short *)&(x) = 
  46.       swap_short(*(unsigned short *)&(x)))
  47. #define FIX_LONG(x) (*(unsigned *)&(x) = 
  48.      swap_long(*(unsigned *)&(x)))
  49. #define FIX_FLOAT(x) FIX_LONG(x)
  50. #define WRITE_UINT(x) 
  51.  ((sg_swapbuf_int = x), FIX_LONG(sg_swapbuf_int) , (fwrite(&sg_swapbuf_int, sizeof(unsigned int),1,sdfile) != 1))
  52. #define WRITE_FLOAT(x) 
  53.  ((sg_swapbuf_float = x), FIX_FLOAT(sg_swapbuf_float) , (fwrite(&sg_swapbuf_float, sizeof(float),1,sdfile) != 1))
  54. #define WRITE_USHORT(x) 
  55.  ((sg_swapbuf_short = x), FIX_SHORT(sg_swapbuf_short) , (fwrite(&sg_swapbuf_short, sizeof(unsigned short),1,sdfile) != 1))
  56. #else
  57. #define FIX_SHORT(x) (x)
  58. #define FIX_LONG(x) (x)
  59. #define FIX_FLOAT(x) (x)
  60. #define WRITE_UINT(x) 
  61.  (fwrite(&x, sizeof(unsigned int),1,sdfile) != 1)
  62. #define WRITE_FLOAT(x) 
  63.  (fwrite(&x, sizeof(float),1,sdfile) != 1)
  64. #define WRITE_USHORT(x) 
  65.  (fwrite(&x, sizeof(unsigned short),1,sdfile) != 1)
  66. #endif
  67. // These return true on error
  68. #define READ_UINT(x) 
  69.  ((gzread(sdfile, &x, sizeof(unsigned int)) != sizeof(unsigned int)) || (FIX_LONG(x) && 0))
  70. #define READ_FLOAT(x) 
  71.  ((gzread(sdfile, &x, sizeof(float)) != sizeof(float)) || (FIX_FLOAT(x) && 0))
  72. #define READ_USHORT(x) 
  73.  ((gzread(sdfile, &x, sizeof(unsigned short)) != sizeof(unsigned short)) || (FIX_SHORT(x) && 0))
  74. void
  75. SDfile::prepare_axis_proj(void)
  76. {
  77.   if (axis_proj_done) return;
  78.   axis_proj_done = true;
  79.   axis_proj_min = axis_proj_max = 
  80.     xf.axis_project(first_good[0], z_data[0]);
  81.   for (int i=0; i<n_frames; i++) {
  82.     if (first_good[i] >= first_bad[i]) continue;
  83.     float pr = xf.axis_project(first_good[i],
  84.        z_data[row_start[i]]);
  85.     if      (pr < axis_proj_min) axis_proj_min = pr;
  86.     else if (pr > axis_proj_max) axis_proj_max = pr;
  87.     int cnt = first_bad[i] - first_good[i];
  88.     pr = xf.axis_project(first_bad[i]-1,
  89.  z_data[row_start[i]+cnt]);
  90.     if      (pr < axis_proj_min) axis_proj_min = pr;
  91.     else if (pr > axis_proj_max) axis_proj_max = pr;
  92.   }
  93. }    
  94. // The image below describes how the point indices are assumed
  95. // to be arranged. There's two index arrays, both n long.
  96. // 1 *---*---*...*---*
  97. //     /  / ... / 
  98. // 0   *---*---*...*---*
  99. // If the situation looks like 
  100. // 1   *---*...*---*---*
  101. //    /  / ... /  /
  102. // 0 *---*---*...*---*
  103. // the flag upper_row_starts should be set false.
  104. // This routine creates ccw triangles, but the strip can be 
  105. // flipped by setting a flag.
  106. static void
  107. create_strip(vector<int>        &tstrips,
  108.      const vector<int>  &p_inds_0,
  109.      const vector<int>  &p_inds_1,
  110.      bool               upper_row_starts = true,
  111.      bool               flipped = false)
  112. {
  113.   bool str_on = false;
  114.   // 1 *---*
  115.   //    1/2
  116.   // 0   *---*
  117.   int n = p_inds_0.size();
  118.   int end = n-1;
  119.   const int *p0 = &p_inds_0[0];
  120.   const int *p1 = &p_inds_1[0];
  121.   if (flipped) {
  122.     p0 = &p_inds_1[0];
  123.     p1 = &p_inds_0[0];
  124.     upper_row_starts = !upper_row_starts;
  125.   }
  126.   if (upper_row_starts == false) {
  127.     if (p0[0] != -1 &&
  128. p0[1] != -1 &&
  129. p1[0] != -1) {
  130.       tstrips.push_back(p1[0]);
  131.       tstrips.push_back(p0[0]);
  132.       tstrips.push_back(p0[1]);
  133.       tstrips.push_back(-1);
  134.     }
  135.     p0  = p0+1;
  136.     end = n-2;
  137.   }
  138.   for (int i=0; i<end; i++) {
  139.     // triangle 1
  140.     if (str_on) {
  141.       // push the index
  142.       int j = p1[i+1];
  143.       tstrips.push_back(j);
  144.       // still going along a strip?
  145.       str_on = (j != -1);
  146.     } else {
  147.       // should we start a strip?
  148.       if (p1[i  ] != -1 &&
  149.   p1[i+1] != -1 &&
  150.   p0[i  ] != -1) {
  151. tstrips.push_back(p1[i]);
  152. tstrips.push_back(p0[i]);
  153. tstrips.push_back(p1[i+1]);
  154. str_on = true;
  155.       }
  156.     }
  157.     // triangle 2
  158.     if (str_on) {
  159.       // push the index
  160.       int j = p0[i+1];
  161.       tstrips.push_back(j);
  162.       // still going along a strip?
  163.       str_on = (j != -1);
  164.     } else {
  165.       // bad place to start a strip, but a single tri?
  166.       if (p0[i  ] != -1 &&
  167.   p0[i+1] != -1 &&
  168.   p1[i+1] != -1) {
  169. tstrips.push_back(p1[i+1]);
  170. tstrips.push_back(p0[i]);
  171. tstrips.push_back(p0[i+1]);
  172. tstrips.push_back(-1);
  173.       }
  174.     }
  175.   }
  176.   if (upper_row_starts == false) {
  177.     if (p1[n-1] != -1) {
  178.       if (str_on) {
  179. tstrips.push_back(p1[n-1]);
  180.       } else {
  181. p0--; // p0 was shifted, shift it back!
  182. if (p1[n-2] != -1 && p0[n-1] != -1) {
  183.   // single triangle
  184.   tstrips.push_back(p1[n-1]);
  185.   tstrips.push_back(p1[n-2]);
  186.   tstrips.push_back(p0[n-1]);
  187.   tstrips.push_back(-1);
  188. }
  189.       }
  190.     }
  191.   }
  192.   // close strip?
  193.   if (str_on) tstrips.push_back(-1);
  194. }
  195.    
  196. inline void
  197. mark_all_empty(const vector<int> &curr, 
  198.        vector<char>      &bdry)
  199. {
  200.   vector<int>::const_iterator it = curr.begin();
  201.   for (;it != curr.end(); it++)
  202.     if (*it != -1) bdry[*it] = 1;
  203. }
  204. inline void
  205. mark_maybe_empty(const vector<int> &curr,
  206.  const vector<int> &prev, 
  207.  const vector<int> &next,
  208.  vector<char> &bdry) 
  209. {
  210.   int n = curr.size();
  211.   if (curr[0] != -1)   bdry[curr[0]] = 1;
  212.   int end = n-1;
  213.   if (curr[end] != -1) bdry[curr[end]] = 1;
  214.   for (int j=1; j<end; j++) {
  215.     int k = curr[j];
  216.     if (k != -1 && (curr[j-1] == -1 ||
  217.     curr[j+1] == -1 ||
  218.     prev[j]   == -1 ||
  219.     prev[j-1] == -1 ||
  220.     next[j]   == -1 ||
  221.     next[j-1] == -1)) {
  222.       bdry[k] = 1;
  223.     }
  224.   }
  225. }
  226. void
  227. SDfile::make_tstrip_horizontal(vector<int>  &tstrips,
  228.        vector<char> &bdry)
  229. {
  230.   // do horizontal stripping
  231.   int i,j,k;
  232.   assert(pts_per_frame % 2 == 0);
  233.   int n = pts_per_frame / 2;
  234.   // previous, current indices
  235.   vector<int> p_0(n), p_1(n);
  236.   vector<int> c_0(n), c_1(n);
  237.   fill(c_0.begin(), c_0.end(), -1);
  238.   fill(c_1.begin(), c_1.end(), -1);
  239.   int p_idx = 0;
  240.   // initialize the point indices
  241.   int end = first_bad[0] - first_good[0];
  242.   for (i=0; i<end; i++) {
  243.     if (z_data[row_start[0]+i]) {
  244.       j = first_good[0]+i;
  245.       if (j%2) c_1[j/2] = p_idx++;
  246.       else     c_0[j/2] = p_idx++;
  247.     }      
  248.   }
  249.   // first row: part of boundary
  250.   mark_all_empty(c_0, bdry);
  251.   bool flip = (frame_pitch > 0.0);
  252.   bool vscan = scanner_config & 0x00000001;
  253.   if (!vscan) flip = !flip;
  254.   // first frame, within the two fields
  255.   create_strip(tstrips, c_0, c_1, false, flip);
  256.   for (i=1; i<n_frames; i++) {
  257.     
  258.     end = first_bad[i] - first_good[i];
  259.     if (end == 0) {
  260.       if (first_good[i-1] != first_bad[i-1]) {
  261. mark_all_empty(c_1, bdry);
  262.       }
  263.       continue;
  264.     }
  265.     // initialize and copy
  266.     copy(c_0.begin(), c_0.end(), p_0.begin());
  267.     copy(c_1.begin(), c_1.end(), p_1.begin());
  268.     fill(c_0.begin(), c_0.end(), -1);
  269.     fill(c_1.begin(), c_1.end(), -1);
  270.     // fill with indices
  271.     for (j=0; j<end; j++) {
  272.       if (z_data[row_start[i]+j]) {
  273. k = first_good[i]+j;
  274. if (k%2) c_1[k/2] = p_idx++;
  275. else     c_0[k/2] = p_idx++;
  276.       }      
  277.     }
  278.     // between the first field and the previous frame's
  279.     // second field
  280.     if (first_good[i-1] != first_bad[i-1]) {
  281.       create_strip(tstrips, p_1, c_0, true, flip);
  282.       // check boundary status of p_inds[1]
  283.       mark_maybe_empty(p_1, p_0, c_0, bdry);
  284.     }
  285.     
  286.     // between the fields of this frame
  287.     create_strip(tstrips, c_0, c_1, false, flip);
  288.     // check boundary status of c_inds[0]
  289.     if (first_good[i-1] != first_bad[i-1]) {
  290.       mark_maybe_empty(c_0, p_1, c_1, bdry);
  291.     } else {
  292.       mark_all_empty(c_0, bdry);
  293.     }
  294.   }
  295.   
  296.   // last row: all valids are part of boundary
  297.   mark_all_empty(c_1, bdry);
  298. }
  299. static int
  300. get_index(int col, int idx, int n,
  301.   const vector<int> &indices, 
  302.   int good, int bad)
  303. {
  304.   
  305.   if (col < good || col >= bad || idx < 0 || idx >= n)
  306.     return -1;
  307.   return indices[idx];
  308. }
  309. #define IsValidTstripIndex(ind,base,range) 
  310.   (((ind)==-1) || ((ind)>=(base) && (ind)<((base)+(range))))
  311. // the comments make more sense for the make_tstrip_horizontal,
  312. // this was modified from it
  313. void
  314. SDfile::make_tstrip_vertical(vector<int>  &tstrips,
  315.      vector<char> &bdry)
  316. {
  317.   // do vertical stripping
  318.   int i,j,k;
  319.   assert(pts_per_frame % 2 == 0);
  320.   int n = n_frames;
  321.   // previous, current indices
  322.   vector<int> p_0(n), p_1(n);
  323.   vector<int> c_0(n), c_1(n);
  324.   fill(c_0.begin(), c_0.end(), -1);
  325.   fill(c_1.begin(), c_1.end(), -1);
  326.   vector<int> indices(n_pts);
  327.   k = 0;
  328.   int p_idx = 0;
  329.   for (i=0; i<n; i++) {
  330.     int end = first_bad[i] - first_good[i];
  331.     assert(k == row_start[i]);
  332.     for (j=0; j<end; j++) {
  333.       if (z_data[k]) indices[k++] = p_idx++;
  334.       else           indices[k++] = -1;
  335.     }
  336.   }
  337.   // initialize the point indices
  338.   for (i=0; i<n; i++) {
  339.     c_0[i] = get_index(0, row_start[i], n_pts, indices, 
  340.        first_good[i], first_bad[i]);
  341.     c_1[i] = get_index(1, row_start[i]+1, n_pts, indices,
  342.        first_good[i], first_bad[i]);
  343.   }
  344. # ifndef NDEBUG
  345.   for (i=0; i<n_pts; i++) {
  346.     assert (IsValidTstripIndex (indices[i], 0, k));
  347.   }
  348.   for (i=0; i<n; i++) {
  349.     assert (IsValidTstripIndex (c_0[i], 0, k));
  350.     assert (IsValidTstripIndex (c_1[i], 0, k));
  351.   }
  352. # endif
  353.   bool flip = (frame_pitch > 0.0);
  354.   bool vscan = scanner_config & 0x00000001;
  355.   if (!vscan) flip = !flip;
  356.   // first column: part of boundary
  357.   mark_all_empty(c_0, bdry);
  358.   // first frame, within the two fields
  359.   create_strip(tstrips, c_1, c_0, true, flip);
  360.   for (i=2; i<pts_per_frame; i+=2) {
  361.     int oddi = i+1;
  362.     // copy
  363.     copy(c_0.begin(), c_0.end(), p_0.begin());
  364.     copy(c_1.begin(), c_1.end(), p_1.begin());
  365.     // fill with indices
  366.     for (j=0; j<n; j++) {
  367.       int tmp = row_start[j]-first_good[j];
  368.       c_0[j] = get_index(i, tmp+i, n_pts, indices,
  369.  first_good[j], first_bad[j]);
  370.       c_1[j] = get_index(oddi, tmp+oddi, n_pts, indices,
  371.  first_good[j], first_bad[j]);
  372.       assert(IsValidTstripIndex (c_0[j], 0, k));
  373.       assert(IsValidTstripIndex (c_1[j], 0, k));
  374.     }
  375.     // between the first field and the previous frame's
  376.     // second field
  377.     create_strip(tstrips, c_0, p_1, false, flip);
  378.     // check boundary status of p_inds[1]
  379.     mark_maybe_empty(p_1, p_0, c_0, bdry);
  380.     
  381.     // between the fields of this frame
  382.     create_strip(tstrips, c_1, c_0, true, flip);
  383.     // check boundary status of c_inds[0]
  384.     mark_maybe_empty(c_0, p_1, c_1, bdry);
  385.   }
  386.   
  387.   // last row: all valids are part of boundary
  388.   mark_all_empty(c_1, bdry);
  389. }
  390. void
  391. SDfile::fill_index_array(int step, 
  392.  int row,
  393.  SubSampMode subSampMode,
  394.  vector<int> &p,
  395.  vector<Pnt3>  &pnts,
  396.  vector<int>   &ssmap,
  397.  vector<uchar> &intensity,
  398.  vector<uchar> &confidence)
  399. {
  400.   int half_step = step/2;
  401.   int i,j,k;
  402.   int zAccum;
  403.  
  404.   i = row * half_step;
  405.   set_xf(i, false);
  406.   unsigned short *z = &z_data[row_start[i]];
  407.   int firstrow = max(0, i - half_step / 2);
  408.   int lastrow  = min(int(n_frames), i + (half_step+1) / 2);
  409.   int end = first_bad[i] - first_good[i];
  410.   if (subSampMode == holesGrow) {
  411.     for (j=0; j<end;) {
  412.       if (z[j]) {
  413. k = first_good[i]+j;
  414. if (k % step == 0) {
  415.   // now need to search other rows to see how many
  416.   // samples are ok
  417.   int mincol = k - half_step;
  418.   int maxcol = k + half_step;
  419.   for (int irow = firstrow; irow < lastrow; irow++) {
  420.     if (mincol <  first_good[irow] ||
  421. maxcol >= first_bad[irow]) {
  422.       goto loop_exit;
  423.     }
  424.     int off = row_start[irow] - first_good[irow];
  425.     unsigned short *zz   = &z_data[mincol + off];
  426.     unsigned short *zend = &z_data[maxcol + off];
  427.     for (; zz != zend; zz++) {
  428.       if (*zz == 0) goto loop_exit;
  429.     }
  430.   }
  431.     
  432.   // keep the point
  433.   p[k/step] = pnts.size();
  434.   pnts.push_back(xf.apply_xform(k, z[j]));
  435.   ssmap.push_back(row_start[i]+j);
  436.   if (!g_bNoIntensity)
  437.     intensity.push_back (intensity_data[row_start[i]+j]);
  438. }
  439.       }
  440.     loop_exit: j++;
  441.     }
  442.   } else { // don't conserve holes
  443.     for (j=0; j<end; j++) {
  444.       if (z[j]) {
  445. k = first_good[i]+j;
  446. if (k % step == 0) {
  447.   if (subSampMode == conf || subSampMode == filterAvg) {
  448.     // if filtering, keep totals to average:
  449.     int iAccum = 0, kAccum = 0;
  450.     zAccum = 0;
  451.     // now need to search other rows to see how many
  452.     // samples are ok
  453.     int mincol = k - half_step;
  454.     int maxcol = k + half_step;
  455.     int nPossibleContrib = 
  456.       (maxcol - mincol) * (lastrow - firstrow);
  457.     int nContrib = 0;
  458.     for (int irow = firstrow; irow < lastrow; irow++) {
  459.       int fg = first_good[irow];
  460.       int rs = row_start[irow];
  461.       int firstcol = max(0, mincol - fg) + rs;
  462.       int lastcol = min(maxcol, int(first_bad[irow]))+rs-fg;
  463.       unsigned short *zbeg = &z_data[firstcol],
  464. *zend = &z_data[lastcol];
  465.       int _k = mincol;
  466.       for (unsigned short* zz = zbeg; zz < zend; zz++) {
  467. if (*zz) {
  468.   nContrib++;
  469.   if (subSampMode == filterAvg) {
  470.     iAccum += irow;
  471.     kAccum += _k++;
  472.     zAccum += *zz;
  473.   }
  474. }
  475.       }
  476.     }
  477.     // exaggerate distance from full confidence
  478.     float conf = float(nContrib) / float(nPossibleContrib);
  479.     conf = 1.0 - 4.0*(1.0 - conf);
  480.     confidence.push_back (255.0*max(0.0f, conf));
  481.     if (subSampMode == filterAvg) {
  482.       set_xf (iAccum / nContrib, true);
  483.       k = kAccum / nContrib;
  484.       zAccum /= nContrib;
  485.     }
  486.   }
  487.     
  488.   // keep the point
  489.   p[k/step] = pnts.size();
  490.   if (subSampMode == filterAvg)
  491.     pnts.push_back(xf.apply_xform(k, zAccum));
  492.   else
  493.     pnts.push_back(xf.apply_xform(k, z[j]));
  494.   ssmap.push_back(row_start[i]+j);
  495.   if (!g_bNoIntensity)
  496.     intensity.push_back (intensity_data[row_start[i]+j]);
  497. }
  498.       }
  499.     }
  500.   }
  501. }
  502. // return false if fully out of frustum
  503. bool
  504. SDfile::find_row_range(float screw, float radius, const Pnt3 &ctr,
  505.        int rowrange[2])
  506. {
  507.   float rowf = (screw - scan_screw) / frame_pitch + .5*n_frames-.25;
  508.   if (rowf < 0) {
  509.     // check whether the first row intersects sphere
  510.     if (1) {
  511.       // intersect
  512.       rowrange[0] = rowrange[1] = 0;
  513.       return true;
  514.     } else {
  515.       return false;
  516.     }
  517.   }
  518.   if (rowf >= n_frames) {
  519.     // check whether the last row intersects sphere
  520.     if (1) {
  521.       // intersect
  522.       rowrange[0] = rowrange[1] = 0;
  523.       return true;
  524.     } else {
  525.       return false;
  526.     }
  527.   }
  528.   return true;
  529. }
  530. SDfile::SDfile(void)
  531.   : row_start(NULL), first_good(NULL), first_bad(NULL),
  532.     z_data(NULL), intensity_data(NULL), n_valid_pts(0),
  533.     axis_proj_done(false)
  534. {
  535. }
  536. SDfile::~SDfile(void)
  537.   if (row_start)
  538.     delete[] row_start;
  539.   if (first_good)
  540.     delete[] first_good;
  541.   if (first_bad)
  542.     delete[] first_bad;
  543.   if (z_data)
  544.     delete[] z_data;
  545.   if (intensity_data)
  546.     delete[] intensity_data;
  547. }
  548. bool
  549. SDfile::read(const crope &fname)
  550. {
  551.   if(g_verbose) cout << "SDfile::read(" << fname << ")... ";
  552.   //
  553.   // Open the .sd file for reading
  554.   //
  555. #ifdef WIN32
  556.   FILE* sdfile;
  557.   if (!(sdfile = fopen (fname.c_str(), "rb"))) {
  558. #else
  559.   gzFile sdfile;
  560.   if (!(sdfile = gzopen(fname.c_str(), "rb"))) {
  561. #endif
  562.     cerr << "Can't open file " << fname << endl;
  563.     return false;
  564.   }
  565.   //
  566.   // Read and check the magic number
  567.   //
  568.   unsigned int magic_num;
  569.   if (READ_UINT(magic_num)) {
  570.     cerr << "Can't read magic number" << endl;
  571.     return false;
  572.   }
  573.   if (magic_num == 0x444d5001)
  574.     version = 1;
  575.   else if (magic_num == 0x444d5002)
  576.     version = 2;
  577.   else if (magic_num == 0x444d5003)
  578.     version = 3;
  579.   else if (magic_num == 0x444d5004)
  580.     version = 4;
  581.   else if (magic_num == 0x444d5005)
  582.     version = 5;
  583.   else if (magic_num == 0x444d5006)
  584.     version = 6;
  585.   else if (magic_num == 0x444d5007)
  586.     version = 7;
  587.   else  {
  588.     cerr << "Invalid magic number" << endl;
  589.     return false;
  590.   }
  591.   if (version != 7 && version != 6 && version != 5) {
  592.     cerr << "Only versions 5, 6, and 7 of sd supported..." << endl;
  593.     gzclose(sdfile);
  594.     return false;
  595.   }
  596.   
  597.   if(g_verbose) cout << "v" << version << "... " << flush;
  598.   scanner_vert = 0;
  599.   if (version == 7 || version == 6) {
  600.     //
  601.     // Read the rest of the .sd header information
  602.     //
  603.     if (READ_UINT(header_size) ||
  604. READ_UINT(n_frames) ||
  605. READ_UINT(pts_per_frame) ||
  606. READ_UINT(n_pts) ||
  607. READ_FLOAT(frame_pitch) ||
  608. READ_FLOAT(scan_screw) ||
  609. READ_FLOAT(other_screw) ||
  610. READ_FLOAT(scanner_trans)) {
  611.       cerr << "Can't read sd file header" << endl;
  612.       return false;
  613.     }
  614.     if (version == 7)  {
  615.       if (READ_FLOAT(scanner_vert))  {
  616.         cerr << "Can't read sd file header" << endl;
  617.         return false;
  618.       }
  619.     }
  620.     if (READ_UINT(scanner_config) ||
  621. READ_FLOAT(laser_intensity) ||
  622. READ_FLOAT(camera_sensitivity)) {
  623.       cerr << "Can't read sd file header" << endl;
  624.       return false;
  625.     }
  626.     first_good = new unsigned short[n_frames];
  627.     first_bad  = new unsigned short[n_frames];
  628.     z_data     = new unsigned short[n_pts];
  629.     if (!g_bNoIntensity)
  630.       intensity_data = new unsigned char[n_pts];
  631.     //
  632.     // Read the block of start/stop indices
  633.     //
  634.     for (int i=0; i<n_frames; ++i) {
  635.       if (READ_USHORT(first_good[i]) || 
  636.   READ_USHORT(first_bad[i]) ) {
  637. cerr << "Can't read sd file row indices" << endl;
  638. return false;
  639.       }
  640.     }
  641.     //
  642.     // Read the block of range data values
  643.     //
  644.     if (gzread(sdfile, z_data, sizeof(unsigned short) * n_pts) !=
  645. sizeof(unsigned short) * n_pts) { 
  646.       cerr << "Can't read sd file range data values" << endl;
  647.       gzclose(sdfile);
  648.       return false;
  649.     }
  650.     //
  651.     // Read the block of intensity data values
  652.     //
  653.     if (!g_bNoIntensity) {
  654.       if (gzread(sdfile, intensity_data, sizeof(unsigned char) * n_pts) !=
  655.        sizeof(unsigned char) * n_pts) {
  656. cerr << "Can't read sd file intensity data values" << endl;
  657. gzclose(sdfile);
  658. return false;
  659.       }
  660.     }
  661.   } else { // version 5
  662.     //
  663.     // Read the rest of the .sd header information
  664.     //
  665.     if (READ_UINT(n_frames) ||
  666. READ_UINT(pts_per_frame) ||
  667. READ_UINT(n_pts) ||
  668. READ_FLOAT(frame_pitch) ||
  669. READ_FLOAT(scan_screw) ||
  670. READ_FLOAT(other_screw) ||
  671. READ_FLOAT(scanner_trans) ||
  672. READ_UINT(scanner_config)) {
  673.       cerr << "Can't read sd file header" << endl;
  674.       return false;
  675.     }
  676.     //
  677.     // Read data a frame at a time
  678.     //
  679.     first_good = new unsigned short[n_frames];
  680.     first_bad  = new unsigned short[n_frames];
  681.     z_data     = new unsigned short[n_pts];
  682.     int cnt = 0;
  683.     for (int i=0; i<n_frames; ++i) {
  684.       if (READ_USHORT(first_good[i]) || 
  685.   READ_USHORT(first_bad[i]) ) {
  686. cerr << "Can't read sd file row indices" << endl;
  687. return false;
  688.       }
  689.       int toread = first_bad[i] - first_good[i];
  690.       if (gzread(sdfile, &z_data[cnt], sizeof(unsigned short) * toread) !=
  691.        sizeof(unsigned short) * toread)  {
  692. cerr << "Can't read sd file data values" << endl;
  693. gzclose(sdfile);
  694. return false;
  695.       }
  696.       cnt += toread;
  697.     }
  698.   }
  699.   gzclose(sdfile);
  700. #ifdef LITTLE_ENDIAN
  701.     for (int z = 0; z < n_pts; z++)
  702.      FIX_SHORT(z_data[z]);
  703. #endif
  704.   // initialize the CyberXform member variable
  705.   // we would REALLY like to do the following:
  706.   //xf.setup(scanner_config, scanner_trans, other_screw, scanner_vert);
  707.   // but that hoses things that were already registered before
  708.   // scanner_vert was taken into account, so we won't yet.
  709.   xf.setup(scanner_config, scanner_trans, other_screw);
  710.   
  711.   // initialize the row_start array
  712.   row_start  = new unsigned int[n_frames];
  713.   row_start[0] = 0;
  714.   for (int i=1; i<n_frames; ++i) {
  715.     int j = i-1;
  716.     row_start[i] = row_start[j] + first_bad[j] - first_good[j];
  717.   }
  718.   return true;
  719. }
  720. bool
  721. SDfile::write(const crope &fname)
  722. {
  723.   FILE *sdfile;
  724.   unsigned int magic_num =  0x444d5007;
  725.   unsigned int header_size = 52;
  726.   
  727.   if (!(sdfile = fopen(fname.c_str(), "wb")))
  728.     return false;
  729.   //
  730.   // Write the header block
  731.   //
  732.   if (WRITE_UINT(magic_num) ||
  733.       WRITE_UINT(header_size) ||
  734.       WRITE_UINT(n_frames) ||
  735.       WRITE_UINT(pts_per_frame) ||
  736.       WRITE_UINT(n_pts) ||
  737.       WRITE_FLOAT(frame_pitch) ||
  738.       WRITE_FLOAT(scan_screw) ||
  739.       WRITE_FLOAT(other_screw) ||
  740.       WRITE_FLOAT(scanner_trans) ||
  741.       WRITE_FLOAT(scanner_vert) ||
  742.       WRITE_UINT(scanner_config) ||
  743.       WRITE_FLOAT(laser_intensity) ||
  744.       WRITE_FLOAT(camera_sensitivity)) {
  745.     cerr << "Can't write sd file header" << endl;
  746.     fclose(sdfile);
  747.     return false;
  748.   }
  749.   //
  750.   // Write the block of start/stop indices
  751.   //
  752.   
  753.   for (int i=0; i<n_frames; ++i) {
  754.     if (WRITE_USHORT(first_good[i]) ||
  755. WRITE_USHORT(first_bad[i])) {
  756.       cerr << "Can't write sd file row indices" << endl;
  757.       fclose(sdfile);
  758.       return false;
  759.     }
  760.   }
  761.   //
  762.   // Write the block of range data values
  763.   //
  764. #ifdef LITTLE_ENDIAN
  765.   unsigned short *fixed_z = new unsigned short[n_pts];
  766.   for (int z = 0; z < n_pts; z++)
  767.     fixed_z[z] = swap_short(z_data[z]);
  768.   if (fwrite(fixed_z, sizeof(unsigned short), n_pts, sdfile) != n_pts)  {
  769.     delete [] fixed_z;
  770.     cerr << "Can't write sd file range data values" << endl;
  771.     fclose(sdfile);
  772.     return false;
  773.   }
  774.   delete [] fixed_z;
  775. #else
  776.   if (fwrite(z_data, sizeof(unsigned short), n_pts, sdfile) != n_pts)  {
  777.     cerr << "Can't write sd file range data values" << endl;
  778.     fclose(sdfile);
  779.     return false;
  780.   }
  781. #endif
  782.   //
  783.   // Write the block of intensity data values
  784.   //
  785.   
  786.   if (g_bNoIntensity) {
  787.     cerr << "No intensity data in memory, writing zeros..." << endl;
  788.     char c = 0;
  789.     for (i=0; i<n_pts; i++) {
  790.       fwrite(&c, sizeof(unsigned char), 1, sdfile);
  791.     }
  792.   } else {
  793.     if (fwrite(intensity_data, sizeof(unsigned char), n_pts, sdfile) !=
  794. n_pts) {
  795.       cerr << "Can't write sd file intensity data values" << endl;
  796.       fclose(sdfile);
  797.       return false;
  798.     }
  799.   }
  800.   fclose(sdfile);
  801.   return true;
  802. }
  803. // Fill single-sample holes in .sd files
  804. void
  805. SDfile::fill_holes(int max_missing, int thresh)
  806. {
  807.   //Median<unsigned short> m;
  808.   Median<float> m;
  809.   for (int row = 0; row < n_frames; row++) {
  810.     int numcols = first_bad[row]-first_good[row];
  811.     if (!numcols)
  812.       continue;
  813.     for (int col = max_missing; col < numcols-max_missing; col++) {
  814.       int index = row_start[row]+col;
  815.       unsigned short me = z_data[index];
  816.       unsigned short med;
  817.       if (max_missing == 1) {
  818. med = __median(z_data[index-1],
  819.        me,
  820.        z_data[index+1]);
  821. #if 1
  822.       } else if (max_missing == 2) {
  823. // Fast approx. to median of 5
  824. med = __median(z_data[index-1],
  825.        me,
  826.        z_data[index+1]);
  827. med = __median(z_data[index-2],
  828.        med,
  829.        z_data[index+2]);
  830. #endif
  831.       } else {
  832. // Slow general-case code
  833. for (int i = index-max_missing; i <= index+max_missing; i++)
  834.   m += z_data[i];
  835. med = m.find();
  836. m.zap();
  837.       }
  838.       if (med && (abs(med - me) > thresh)) {
  839. int tot = 0;
  840. int num = 0;
  841. for (int i = index-max_missing; i <= index+max_missing; i++)
  842.   if (abs(z_data[i] - med) < thresh) {
  843.     tot += z_data[i];
  844.     num++;
  845.   }
  846. if (num)
  847.   z_data[index] = tot / num;
  848.       }
  849.     }
  850.   }
  851. }
  852. void
  853. SDfile::make_tstrip(vector<int>  &tstrips,
  854.     vector<char> &bdry)
  855. {
  856.   if (fabs(frame_pitch) > .07) 
  857.     make_tstrip_horizontal(tstrips, bdry);
  858.   else 
  859.     make_tstrip_vertical(tstrips, bdry);
  860. }
  861. void
  862. SDfile::subsampled_tstrip(int            step,
  863.   char          *behavior,
  864.   vector<int>   &tstrips,
  865.   vector<char>  &bdry,
  866.   vector<Pnt3>  &pnts,
  867.   vector<uchar> &intensity,
  868.   vector<uchar> &confidence,
  869.   vector<int>   &ssmap)
  870. {
  871.   int n_s = pts_per_frame / step;
  872.   int end = 2*n_frames/step;
  873.   SubSampMode subSampMode = !strcmp (behavior, "holes") 
  874.     ? holesGrow
  875.     : !strcmp (behavior, "conf") ? conf
  876.     : !strcmp (behavior, "filter") ? filterAvg
  877.     : fast;
  878.   if (n_s > 1 && end > 1) {
  879.     // do horizontal stripping
  880.     
  881.     vector<int> p_inds[2], old_inds(n_s);
  882.     p_inds[0].reserve(n_s); 
  883.     p_inds[0].insert(p_inds[0].begin(), n_s, -1);
  884.     p_inds[1].reserve(n_s); 
  885.     p_inds[1].insert(p_inds[1].begin(), n_s, -1);
  886.     
  887.     vector<char> tmp_bdry(end*n_s); // a temporary bdry vector
  888.     // first row
  889.     fill_index_array(step, 0, subSampMode, p_inds[0],
  890.      pnts, ssmap, intensity, confidence);
  891.     mark_all_empty(p_inds[0], tmp_bdry);
  892.     bool flip = (frame_pitch > 0.0);
  893.     bool vscan = scanner_config & 0x00000001;
  894.     if (!vscan) flip = !flip;
  895.     // second row and first strip
  896.     fill_index_array(step, 1, subSampMode, p_inds[1],
  897.      pnts, ssmap, intensity, confidence);
  898.     create_strip(tstrips, p_inds[0], p_inds[1],
  899.  true, flip);
  900.     // rest of the rows
  901.     int i,j;
  902.     for (i=2,j=0; i<end; i++, j^=1) {
  903.       copy(p_inds[j].begin(), p_inds[j].end(),old_inds.begin());
  904.       fill(p_inds[j].begin(), p_inds[j].end(), -1);
  905.       fill_index_array(step, i, subSampMode, p_inds[j],
  906.        pnts, ssmap, intensity, confidence);
  907.       mark_maybe_empty(p_inds[!j], old_inds, p_inds[j], tmp_bdry);
  908.       create_strip(tstrips, p_inds[!j], p_inds[j],
  909.    true, flip);
  910.     }
  911.     mark_all_empty(p_inds[!j], tmp_bdry);
  912.     // copy the boundary info
  913.     copy(tmp_bdry.begin(), &tmp_bdry[pnts.size()],
  914.  back_insert_iterator<vector<char> > (bdry));
  915.   }
  916. }
  917. void 
  918. SDfile::set_xf(int row, bool both)
  919. {
  920.   if (both) {
  921.     // get the average screw length for the given row
  922.     float scr = scan_screw + (row - .5*n_frames+.5) * frame_pitch;
  923.     // the even field is a quarter pitch down, odd field up
  924.     xf.set_screw(scr - 0.25*frame_pitch, scr + 0.25*frame_pitch);
  925.   } else {
  926.     // only even screw
  927.     float scr = scan_screw + (row -.5*n_frames+.25) * frame_pitch;
  928.     xf.set_screw(scr);
  929.   }
  930. }
  931. void
  932. SDfile::get_pnts_and_intensities(vector<Pnt3>  &pnts,
  933.  vector<uchar> &intensity)
  934. {
  935.   int cnt = 0;
  936.   for (int i = 0; i < n_frames; ++i) {
  937.     set_xf(i);
  938.     for (int j=first_good[i]; j<first_bad[i]; j++, cnt++)  {
  939.       if (z_data[cnt] == 0)
  940. continue; // missing data marked by zero
  941.       pnts.push_back(xf.apply_xform(j, z_data[cnt]));
  942.       if (!g_bNoIntensity) 
  943. intensity.push_back (intensity_data[cnt]);
  944.     }
  945.   }
  946. }
  947. // access a data point, transformed or in laser coords
  948. // row is the frame, col is a point on scanline,
  949. // col even: frame 0; col odd: frame 1
  950. // returns false if there is no such point
  951. bool
  952. SDfile::get_point(int row, int col, Pnt3 &p, 
  953.   bool transformed)
  954. {
  955.   // row within range?
  956.   if (row < 0 || row >= n_frames) 
  957.     return false;
  958.   // column within range?
  959.   if (first_good[row] > col || first_bad[row] <= col)
  960.     return false;
  961.   // valid point?
  962.   short z = z_data[row_start[row] + col - first_good[row]];
  963.   if (z == 0) return false;
  964.   if (transformed) {
  965.     set_xf(row);  // should check whether this already is valid
  966.     p = xf.apply_xform(col, z);
  967.   } else {
  968.     p = xf.apply_raw_to_laser(col, z);
  969.   }
  970.   return true;
  971. }
  972. // Calculate the laser direction at the middle frame,
  973. // find also the rotation axis, and create a frame such
  974. // that the laser direction is aligned with negative z
  975. // and the scanning axis is aligned with x (pos or neg irrelevant)
  976. Xform<float>
  977. SDfile::vrip_reorientation_frame(void)
  978. {
  979.   set_xf(n_frames/2);
  980.   
  981.   // get the laser direction
  982.   short mid_column = 480/2;
  983.   short front = 60;
  984.   short back  = 2940;
  985.   Pnt3 p1 = xf.apply_xform(mid_column, front);
  986.   Pnt3 p2 = xf.apply_xform(mid_column, back);
  987.   Pnt3 laser_dir = (p2 - p1).normalize();
  988.   // get the center point
  989.   short mid_z = (front + back) / 2;
  990.   Pnt3 ctr = xf.apply_xform(mid_column, mid_z);
  991.   // assume that a constant z-row is aligned in 3D with
  992.   // scan axis
  993.   p1 = xf.apply_xform(  0, mid_z);
  994.   p2 = xf.apply_xform(480, mid_z);
  995.   Pnt3 new_x = (p2-p1).normalize();
  996.   // create the frame
  997.   Pnt3 new_z = laser_dir;
  998.   Pnt3 new_y = cross(new_z, new_x);
  999.   new_x = cross(new_y, new_z);
  1000.   Xform<float> a,b;
  1001.   a.translate(-ctr);
  1002.   b.fromFrame(new_x, new_y, new_z, Pnt3());
  1003.   return b * a;
  1004. }
  1005. // given a screw length and a position on the scanline
  1006. // find the closest data point in the sweep
  1007. // return false if that data point is invalid
  1008. // 
  1009. // a preliminary version, should be optimized and 
  1010. // the logic should be improved...
  1011. bool
  1012. SDfile::find_data(float screw, float y_in, 
  1013.   int            &row,
  1014.   unsigned short &y, 
  1015.   unsigned short &z)
  1016. {
  1017.   if (y_in < 0.0) { 
  1018.     //SHOW(y_in);
  1019.     return false;
  1020.   }
  1021.   // first, calculate row
  1022.   // invert the equation in set_xf()
  1023.   // treat the screw input as the "average screw of the frame"
  1024.   // change it to the even field screw...
  1025.   float rowf = (screw - scan_screw) / frame_pitch + .5*n_frames-.25;
  1026.   //SHOW(screw / frame_pitch);
  1027.   //SHOW(25*frame_pitch);
  1028.   //rowf -= 25;
  1029.   float rowfloor = floor(row);
  1030.   float frac = row - rowfloor;
  1031.   // if frac: [0.0,.25] -> even field
  1032.   //          (.25,.75] -> odd field
  1033.   //          (.75,1.0) -> next row even field
  1034.   bool field_even;
  1035.   if (frac > .75) {
  1036.     row = int(rowf) + 1;
  1037.     field_even = true;
  1038.   } else {
  1039.     row = int(rowf);
  1040.     field_even = (frac <= .25);
  1041.   }
  1042.   if (row < 0 || row >= n_frames) 
  1043.     return false;
  1044.   // if even field, snap to closest even integer,
  1045.   // similarly for odd
  1046.   if (field_even) {
  1047.     y = int(floor(y_in*.5+.5)) * 2;
  1048.   } else {
  1049.     y = int(floor(y_in*.5)) * 2 + 1;
  1050.   }
  1051.   if (y < first_good[row] || y >= first_bad[row]) {
  1052.     //SHOW(row);
  1053.     //SHOW(y);
  1054.     //SHOW(first_good[row]);
  1055.     //SHOW(first_bad[row]);
  1056.     return false;
  1057.   }
  1058.   z = z_data[row_start[row]+y-first_good[row]];
  1059.   return (z != 0);  
  1060. }
  1061. int
  1062. SDfile::count_valid_pnts(void)
  1063. {
  1064.   if (n_valid_pts == 0) {
  1065.     unsigned short *end = z_data+n_pts;
  1066.     for (unsigned short *sp = z_data; sp != end; sp++) {
  1067.       if (*sp) n_valid_pts++;
  1068.     }
  1069.   }
  1070.   return n_valid_pts;
  1071. }
  1072. void
  1073. SDfile::filtered_copy(const VertexFilter &filter,
  1074.       SDfile &newsd)
  1075. {
  1076.   // copy the data, first shallow copy
  1077.   newsd = *this;
  1078.   // then do a deeper, filtered copy
  1079.   newsd.row_start  = new unsigned int[n_frames];
  1080.   newsd.first_good = new unsigned short[n_frames];
  1081.   newsd.first_bad  = new unsigned short[n_frames];
  1082.   
  1083.   // initialize these to null
  1084.   newsd.intensity_data = NULL;
  1085.   newsd.z_data = NULL;
  1086.   // for z_data and intensity data, we need temporary
  1087.   // buffers, we don't know how big they'll be
  1088.   unsigned short *_z_data = new unsigned short[n_pts];
  1089.   unsigned char  *_bw_data = new unsigned char[n_pts];
  1090.   int cnt = 0;
  1091.   // march over all the points, apply transformations,
  1092.   // test for filtering, update the arrays above
  1093.   for (int i=0; i<n_frames; i++) {
  1094.     // initialize
  1095.     newsd.row_start[i] = cnt;
  1096.     int  FirstGood, LastGood;
  1097.     bool empty_row = true;
  1098.     newsd.set_xf(i);
  1099.     // check all valid ones of a row...
  1100.     for (int j=first_good[i]; j<first_bad[i]; j++) {
  1101.       int k = row_start[i] + j - first_good[i];
  1102.       // valid data, filter it
  1103.       if (z_data[k] != 0 &&
  1104.   filter.accept(newsd.xf.apply_xform(j, z_data[k]))) {
  1105. // accepted
  1106. if (empty_row) { FirstGood = j; empty_row = false; }
  1107. LastGood = j;
  1108. _z_data[cnt]    = z_data[k];
  1109. if (!g_bNoIntensity) 
  1110.   _bw_data[cnt] = intensity_data[k];
  1111. cnt++;
  1112.       } else if (!empty_row) {
  1113. // rejected
  1114. _z_data[cnt]    = 0;
  1115. _bw_data[cnt++] = 0;
  1116.       }
  1117.     }
  1118.     if (empty_row) {
  1119.       // row has no data
  1120.       newsd.first_good[i] = 0;
  1121.       newsd.first_bad[i]  = 0;
  1122.     } else {
  1123.       // row has filtered data
  1124.       newsd.first_good[i] = FirstGood;
  1125.       newsd.first_bad[i]  = LastGood+1;
  1126.       // remove the last bad entries from _z_data and _bw_data
  1127.       cnt -= (first_bad[i] - newsd.first_bad[i]);
  1128.     }
  1129.   }
  1130.   // copy the z and intensity data to the new copy
  1131.   newsd.n_pts  = cnt;
  1132.   if (cnt) {
  1133.     newsd.z_data = new unsigned short[cnt];
  1134.     memcpy(newsd.z_data, _z_data, sizeof(unsigned short) * cnt);
  1135.     if (!g_bNoIntensity) {
  1136.       newsd.intensity_data = new unsigned char[cnt];
  1137.       memcpy(newsd.intensity_data, _bw_data, cnt);
  1138.     }
  1139.   }
  1140.   delete[] _z_data;
  1141.   delete[] _bw_data;
  1142. }
  1143. void
  1144. SDfile::get_piece(int firstFrame, int lastFrame,
  1145.   SDfile &newsd)
  1146. {
  1147.   // copy the data, first shallow copy
  1148.   newsd = *this;
  1149.   newsd.n_frames = lastFrame - firstFrame + 1;
  1150.   // then do a deeper, filtered copy
  1151.   newsd.row_start  = new unsigned int[newsd.n_frames];
  1152.   newsd.first_good = new unsigned short[newsd.n_frames];
  1153.   newsd.first_bad  = new unsigned short[newsd.n_frames];
  1154.   newsd.scan_screw = scan_screw + 
  1155.     (firstFrame + (int(newsd.n_frames) - int(n_frames))*0.5)*frame_pitch;
  1156.   int offset = row_start[firstFrame];
  1157.   for (int i = firstFrame; i <= lastFrame; i++) {
  1158.     newsd.row_start[i-firstFrame]  = row_start[i] - offset;
  1159.     newsd.first_good[i-firstFrame] = first_good[i];
  1160.     newsd.first_bad[i-firstFrame]  = first_bad[i];
  1161.   }
  1162.   newsd.n_pts = newsd.row_start[newsd.n_frames-1] + 
  1163.     newsd.first_bad[newsd.n_frames-1] - 
  1164.     newsd.first_good[newsd.n_frames-1];
  1165.   if (newsd.n_pts) {
  1166.     // copy the z and intensity data to the new copy
  1167.     newsd.z_data = new unsigned short[newsd.n_pts];
  1168.     memcpy(newsd.z_data, z_data + row_start[firstFrame], 
  1169.    sizeof(unsigned short) * newsd.n_pts);
  1170.     if (!g_bNoIntensity) {
  1171.       newsd.intensity_data = new unsigned char[newsd.n_pts];
  1172.       memcpy(newsd.intensity_data,
  1173.      intensity_data+row_start[firstFrame], 
  1174.      newsd.n_pts);
  1175.     }
  1176.   }
  1177. }
  1178. Bbox
  1179. SDfile::get_bbox(void)
  1180. {
  1181.   int cnt = 0;
  1182.   Bbox bb;
  1183.   for (int i = 0; i < n_frames; ++i) {
  1184.     set_xf(i);
  1185.     for (int j=first_good[i]; j<first_bad[i]; j++, cnt++)  {
  1186.       if (z_data[cnt] == 0)
  1187. continue; // missing data marked by zero
  1188.       bb.add(xf.apply_xform(j, z_data[cnt]));
  1189.     }
  1190.   }
  1191.   return bb;
  1192. }
  1193. static int inside = 0;
  1194. static int outside = 0;
  1195. static int status_cnt = 0;
  1196. int
  1197. SDfile::sphere_status(const Pnt3 &ctr, float r)
  1198. {
  1199.   float screw, swin[2];
  1200.   short ywin[2], zwin[2];
  1201.   prepare_axis_proj();
  1202.   int ans = xf.sphere_status(ctr, r, screw, 
  1203.      axis_proj_min, axis_proj_max,
  1204.      ywin, zwin, swin);
  1205.   
  1206.   status_cnt++;
  1207.   if (ans == 0) {
  1208.     return 4; // NOT_IN_FRUSTUM
  1209.   }
  1210.   if (ans == 1) {
  1211.     return 1; // BOUNDARY;
  1212.   }
  1213.   cout << ywin[0] << " " 
  1214.        << ywin[1] << " " 
  1215.        << zwin[0] << " " 
  1216.        << zwin[1] << " " 
  1217.        << swin[0] << " " 
  1218.        << swin[1] << " " << r << endl;
  1219.   
  1220.   int start_row = (swin[0] - scan_screw) / frame_pitch + .5*n_frames-.25;
  1221.   int end_row   = (swin[1] - scan_screw) / frame_pitch + .5*n_frames-.25;
  1222.   if (end_row < 0 || start_row >= n_frames) {
  1223.     return 4; // NOT_IN_FRUSTUM
  1224.   }
  1225.   if (start_row < 0 || end_row >= n_frames) {
  1226.     // partially within frustum
  1227.     return 1; // BOUNDARY (force subdivision)
  1228.   }
  1229.   // really check the status
  1230.   bool all_behind = true;
  1231.   bool all_front  = true;
  1232.   bool all_within = true;
  1233.   SHOW(start_row);
  1234.   SHOW(end_row);
  1235.   int span = ywin[1] - ywin[0] + 1;
  1236.   for (int i=start_row; i<=end_row; i++) {
  1237.     if (first_good[i] >  ywin[0]) return 1; // invalid, force subdiv
  1238.     if (first_bad[i]  <= ywin[1]) return 1; // invalid, force subdiv
  1239.     unsigned short *z = &z_data[row_start[i] + ywin[0] - first_good[i]];
  1240.     for (int j=0; j<span; j++) {
  1241.       if      (z[j] < zwin[0]) { all_front  = all_within = false; }
  1242.       else if (z[j] > zwin[1]) { all_behind = all_within = false; }
  1243.       else                     { all_front  = all_behind = false; }
  1244.     }
  1245.     if (!all_behind && !all_front && !all_within)
  1246.       break;
  1247.   }
  1248.   if (all_behind) { cout << "OUTSIDE" << ++outside << endl; }
  1249.   if (all_front)  { cout << "INSIDE" << ++inside << endl; }
  1250.   if (all_within) return 1; // BOUNDARY
  1251.   if (all_behind) return 0; // OUTSIDE
  1252.   if (all_front)  return 3; // INSIDE
  1253.   return 2; // SILHOETTE
  1254. }
  1255. int
  1256. SDfile::dump_pts_laser_subsampled(ofstream &out, int nPnts)
  1257. {
  1258.   // go through all the valid points, do a uniform
  1259.   // subsampling
  1260.   int valids_left = n_valid_pts;
  1261.   int still_need  = nPnts;
  1262.   Random rnd;
  1263.   int cnt = 0;
  1264.   for (int i=0; i<n_frames; i++) {
  1265.     // see set_xf()
  1266.     float scr = scan_screw + (i - .5*n_frames+.5) * frame_pitch;
  1267.     float evenscr = scr - 0.25*frame_pitch;
  1268.     float oddscr  = scr + 0.25*frame_pitch;
  1269.     set_xf(i);
  1270.     // check all valid ones of a row...
  1271.     for (int j=first_good[i]; j<first_bad[i]; j++) {
  1272.       int k = row_start[i] + j - first_good[i];
  1273.       // valid data, filter it
  1274.       if (z_data[k]) {
  1275. if (rnd() < float(still_need)/float(valids_left)) {
  1276.   cnt++;
  1277.   still_need--;
  1278.   // transform to laser coords
  1279.   Pnt3 p(0, j, z_data[k]);
  1280.   xf.raw_to_laser(p);
  1281.   assert(fabs(p[0]) < 1e-5);
  1282.   out.write((char*)&p[1], sizeof(float));
  1283.   out.write((char*)&p[2], sizeof(float));
  1284.   if (j%2) out.write((char*)&oddscr,  sizeof(float));
  1285.   else     out.write((char*)&evenscr, sizeof(float));
  1286.   out.write((char*)&other_screw, sizeof(float));
  1287.   out.write((char*)&scanner_trans, sizeof(float));
  1288.   /*
  1289.   // DELETE FROM HERE
  1290.   if (j%2) SHOW(oddscr);
  1291.   else     SHOW(evenscr);
  1292.   SHOW(other_screw);
  1293.   Pnt3 pp(0, j, z_data[k]);
  1294.   SHOW(pp);
  1295.   xf.raw_to_laser(pp);
  1296.   SHOW(pp);
  1297.   xf.laser_to_scanaxis(pp);
  1298.   SHOW(pp);
  1299.   SHOW(xf.apply_xform(j, z_data[k]));
  1300.   return cnt;
  1301.   // DELETE UP TO HERE
  1302.   */
  1303. }
  1304. valids_left--;
  1305.       }
  1306.     }
  1307.   }
  1308.   return cnt;
  1309. }
  1310. Pnt3
  1311. SDfile::raw_for_ith(int   j, sd_raw_pnt &data)
  1312. {
  1313.   assert(j < n_pts);
  1314.   // find the row
  1315.   int bot = 0;
  1316.   int top = n_frames;
  1317.   while (top - bot > 1) {
  1318.     int i = (bot + top) / 2;
  1319.     if (row_start[i] > j) top = i;
  1320.     else                  bot = i;
  1321.   }
  1322.   int row = bot;
  1323.   // find the column
  1324.   int col = j - row_start[row] + first_good[row];
  1325.   
  1326.   data.y = col;
  1327.   data.z = z_data[j];
  1328.   data.config = scanner_config;
  1329.   float scr = scan_screw + (row - .5*n_frames+.5) * frame_pitch;
  1330.   if (j%2) scr += .25*frame_pitch;
  1331.   else     scr -= .25*frame_pitch;
  1332.   if (data.config & 0x00000001) {
  1333.     // vertical
  1334.     data.nod  = scr;
  1335.     data.turn = other_screw;
  1336.   } else {
  1337.     // horizontal
  1338.     data.turn = scr;
  1339.     data.nod  = other_screw;
  1340.   }
  1341.   data.tr_h = scanner_trans;
  1342.   // now, convert the raw to 3D for verification
  1343.   set_xf(row);
  1344.   return xf.apply_xform(data.y,data.z);
  1345. }
  1346. Pnt3
  1347. SDfile::raw_for_ith_valid(int   i, sd_raw_pnt &data)
  1348. {
  1349.   assert(i < n_valid_pts);
  1350.   // first, find the index for the ith valid point
  1351.   unsigned short *z = z_data;
  1352.   i++;
  1353.   while (i) { if (*(z++)) i--; }
  1354.   z--;
  1355.   return raw_for_ith(int(z-z_data), data);
  1356. }