zsig 1.0.0
|
00001 00008 #ifndef ZSIG_SIGNATURET_HH 00009 #define ZSIG_SIGNATURET_HH 00010 00011 //== INCLUDES ================================================================= 00012 00013 #include <set> 00014 #include <vector> 00015 #include <limits> 00016 #include <fstream> 00017 #include <iostream> 00018 00019 #include <vec.hh> 00020 00021 //== NAMESPACES =============================================================== 00022 00023 namespace zsig { 00024 00025 //== CLASS DEFINITION ========================================================= 00026 00038 template< unsigned R, unsigned C, class T > 00039 class SignatureT { 00040 00041 public: 00042 00043 typedef SignatureT< R, C, T > signature_type; 00044 00046 SignatureT() { 00047 sig = new T*[R]; 00048 for (unsigned i = 0; i < R; ++i) 00049 sig[i] = new T[C]; 00050 this->clear(); 00051 } 00052 00056 SignatureT( const SignatureT& _sig ) { 00057 sig = new T*[R]; 00058 for (unsigned i = 0; i < R; ++i) 00059 sig[i] = new T[C]; 00060 *this = _sig; 00061 } 00062 00064 ~SignatureT() { 00065 for (unsigned i = 0; i < R; ++i) 00066 delete [] sig[i]; 00067 delete [] sig; 00068 } 00069 00071 void clear( void ) { 00072 for (unsigned i = 0; i < R; ++i) 00073 for (unsigned j = 0; j < C; ++j) 00074 sig[i][j] = T(); 00075 } 00076 00081 signature_type& operator = ( const signature_type& _sig ) { 00082 for (unsigned i = 0; i < R; ++i) 00083 for (unsigned j = 0; j < C; ++j) 00084 sig[i][j] = _sig[i][j]; 00085 return *this; 00086 } 00087 00093 T* operator [] ( const unsigned& _i ) { return this->sig[_i]; } 00094 00100 const T* operator [] ( const unsigned& _i ) const { return this->sig[_i]; } 00101 00108 friend std::ostream& operator << ( std::ostream& out, 00109 const signature_type& _s ) { 00110 for (unsigned i = 0; i < R; ++i) { 00111 out << _s[i][0]; 00112 for (unsigned j = 1; j < C; ++j) 00113 out << " " << _s[i][j]; 00114 if( i < R-1 ) out << "\n"; 00115 } 00116 return out; 00117 } 00118 00125 friend std::istream& operator >> ( std::istream& in, 00126 signature_type& _s ) { 00127 for (unsigned i = 0; i < R; ++i) 00128 for (unsigned j = 0; j < C; ++j) 00129 in >> _s[i][j]; 00130 return in; 00131 } 00132 00137 T** operator &( void ) { return (T**)this->sig; } 00138 00143 const T** operator &( void ) const { return (const T**)this->sig; } 00144 00145 private: 00146 00147 T **sig; 00148 00149 }; 00158 //== CLASS DEFINITION ========================================================= 00159 00170 template< class T > 00171 class SignatureMeshT { 00172 00173 public: 00174 00175 typedef vec< 3, T > vec3; 00176 typedef vec< 3, unsigned > uvec3; 00177 typedef SignatureMeshT< T > mesh_type; 00178 typedef std::vector< unsigned > index_list; 00179 typedef vec3 bbox_type [2]; 00180 typedef vec3 sigplane_type [4]; 00181 00183 SignatureMeshT() : nv(0), nf(0), gd(0), va(0), fa(0), gfa(0), fna(0) { } 00184 00188 SignatureMeshT( const mesh_type& _m ) : nv(0), nf(0), gd(0), va(0), fa(0), gfa(0), fna(0) { *this = _m; } 00189 00191 ~SignatureMeshT() { this->clear(); } 00192 00194 void clear( void ) { 00195 nv = nf = gd = 0; msd = (T)0; 00196 if( va ) { delete [] va; va = 0; } 00197 if( fa ) { delete [] fa; fa = 0; } 00198 if( gfa ) { delete [] gfa; gfa = 0; } 00199 if( fna ) { delete [] fna; fna = 0; } 00200 nfv.clear(); 00201 bb[0].clear(); 00202 bb[1].clear(); 00203 diag.clear(); 00204 } 00205 00210 mesh_type& operator = ( const mesh_type& _m ) { 00211 this->clear(); 00212 this->set_vertices( _m.size_of_vertices(), _m.vertices() ); 00213 this->set_faces( _m.size_of_faces(), _m.faces() ); 00214 this->set_grid( _m.grid_dimension(), _m.grid(), _m.maximum_search_distance() ); 00215 this->set_fnormals( _m.size_of_faces(), _m.fnormals() ); 00216 this->set_neighborhood( _m.neighborhood() ); 00217 this->set_bbox( _m.bounding_box(), _m.diagonal() ); 00218 return *this; 00219 } 00220 00221 // @name I/O functions 00223 00227 void read_off( std::istream& _in ) { 00228 std::string h; // (unused) header line 00229 unsigned ne; // (unused) number of edges 00230 this->clear(); 00231 _in >> h >> nv >> nf >> ne; 00232 va = new vec3[ nv ]; 00233 fa = new uvec3[ nf ]; 00234 unsigned nvf; // (unused) number of vertices per face 00235 for (unsigned i = 0; i < nv; ++i) 00236 _in >> va[i]; 00237 for (unsigned i = 0; i < nf; ++i) 00238 _in >> nvf >> fa[i]; 00239 } 00240 00244 void read_off( const char* fn ) { 00245 std::fstream in( fn, std::ios::in ); 00246 read_off( in ); 00247 in.close(); 00248 } 00249 00253 void write_off( std::ostream& _out ) const { 00254 _out << "OFF\n" << nv << " " << nf << " 0\n"; 00255 for (unsigned i = 0; i < nv; ++i) 00256 _out << va[i] << "\n"; 00257 for (unsigned i = 0; i < nf; ++i) 00258 _out << "3 " << fa[i] << "\n"; 00259 } 00260 00264 void write_off( const char* fn ) const { 00265 std::fstream out( fn, std::ios::out ); 00266 write_off( out ); 00267 out.close(); 00268 } 00269 00274 void write_ply( std::ostream& _out, const uvec3 *_colors ) const { 00275 _out << "ply\nformat ascii 1.0\n"; 00276 _out << "element vertex " << nv << " \n"; 00277 _out << "property float x\nproperty float y\nproperty float z\n"; 00278 _out << "property uchar red\nproperty uchar green\nproperty uchar blue\n"; 00279 _out << "element face " << nf << " \n"; 00280 _out << "property list uchar int vertex_indices\n"; 00281 _out << "end_header\n"; 00282 for (unsigned i = 0; i < nv; ++i) 00283 _out << va[i] << " " << _colors[i] << "\n"; 00284 for (unsigned i = 0; i < nf; ++i) 00285 _out << "3 " << fa[i] << "\n"; 00286 } 00287 00292 void write_ply( const char* fn, const uvec3 *_colors ) const { 00293 std::fstream out( fn, std::ios::out ); 00294 write_ply( out, _colors ); 00295 out.close(); 00296 } 00297 00299 00300 // @name Build functions 00302 00310 void build_all( void ) { 00311 build_bbox(); 00312 build_neighborhood(); 00313 build_fnormals(); 00314 build_grid(); 00315 } 00316 00320 void build_grid( T& _msd ) { 00321 if( gfa ) delete [] gfa; 00322 T msl = diag[0]; // maximum side length 00323 msl = std::max( msl, diag[1] ); 00324 msl = std::max( msl, diag[2] ); 00325 gd = ceil( msl / _msd ); 00326 gfa = new std::vector< unsigned >[ gd * gd * gd ]; 00327 uvec3 gp; // grid position 00328 for (unsigned i = 0; i < nf; ++i) { 00329 for (unsigned j = 0; j < 3; ++j) { 00330 convert_to_grid( va[ fa[i][j] ], gp ); 00331 gfa[ gp[0]*gd*gd + gp[1]*gd + gp[2] ].push_back( i ); 00332 } // j 00333 } // i 00334 msd = _msd; 00335 } 00336 00344 void build_grid( void ) { 00345 msd = diagonal_distance() / (T)40; // _msd = 2.5 % of diagonal bounding box 00346 if( msd ) build_grid( msd ); 00347 } 00348 00350 void build_fnormals( void ) { 00351 if( fna ) delete [] fna; 00352 fna = new vec3[ nf ]; 00353 vec3 fv[3]; // face vertices 00354 for (unsigned i = 0; i < nf; ++i) { 00355 for (unsigned k = 0; k < 3; ++k) 00356 fv[k] = va[ fa[i][k] ]; 00357 // considering counter-clockwise orientation 00358 // in faces when computing face normal 00359 fna[i] = ( fv[1] - fv[0] ) % ( fv[2] - fv[0] ); 00360 } 00361 } 00362 00364 void build_neighborhood( void ) { 00365 nfv.clear(); 00366 nfv.resize( nv ); 00367 for (unsigned i = 0; i < nf; ++i) { 00368 nfv[ fa[i][0] ].push_back( i ); 00369 nfv[ fa[i][1] ].push_back( i ); 00370 nfv[ fa[i][2] ].push_back( i ); 00371 } 00372 } 00373 00375 void build_bbox( void ) { 00376 if( !va ) { bb[0].clear(); bb[1].clear(); diag.clear(); return; } 00377 bb[1] = bb[0] = va[0]; 00378 for (unsigned i = 1; i < nv; ++i) { 00379 for (unsigned k = 0; k < 3; ++k) { 00380 if( va[i][k] < bb[0][k] ) bb[0][k] = va[i][k]; 00381 if( va[i][k] > bb[1][k] ) bb[1][k] = va[i][k]; 00382 } 00383 } 00384 diag = bb[1] - bb[0]; 00385 } 00386 00388 00389 // @name Compute functions 00391 00402 void compute_neighborhood( const unsigned& _i, 00403 std::set< unsigned >& _nb, 00404 const bool& _v = false ) const { 00405 vec3 v = va[ _i ]; // vertex position 00406 uvec3 gp; // grid position of vertex 00407 convert_to_grid( v, gp ); 00408 _nb.clear(); 00409 for (unsigned ci = std::max((int)gp[0]-1, 0); ci <= std::min((int)gp[0]+1, (int)gd-1); ++ci) { 00410 for (unsigned cj = std::max((int)gp[1]-1, 0); cj <= std::min((int)gp[1]+1, (int)gd-1); ++cj) { 00411 for (unsigned ck = std::max((int)gp[2]-1, 0); ck <= std::min((int)gp[2]+1, (int)gd-1); ++ck) { 00412 for (unsigned i = 0; i < gfa[ci*gd*gd+cj*gd+ck].size(); ++i) { 00413 unsigned fi = gfa[ci*gd*gd+cj*gd+ck][i]; 00414 for (unsigned vi = 0; vi < 3; ++vi) { 00415 vec3 ov = va[ fa[fi][vi] ]; 00416 if( (ov - v).length() <= msd ) { 00417 if( _v ) { 00418 _nb.insert( fa[fi][vi] ); 00419 } else { 00420 _nb.insert( fi ); 00421 break; 00422 } // else 00423 } // if 00424 } // vi 00425 } // i 00426 } // ck 00427 } // cj 00428 } // ci 00429 } 00430 00439 void compute_sigplane( const unsigned& _i, sigplane_type& _sp ) const { 00440 _sp[0] = va[ _i ]; 00441 compute_normal( _i, _sp[3] ); 00442 _sp[3].normalize(); 00443 // get any vertex connected to the given vertex, 00444 // project it onto the tangent plane, and use it to 00445 // stipulate the vector Y of the LCF; it does not 00446 // matter which vector Y is since the signature will 00447 // be converted to Zernike coefficients becoming 00448 // rotationally invariant 00449 unsigned k = 0; 00450 while( k < 2 and fa[ nfv[ _i ][0] ][k] == _i ) ++k; 00451 _sp[2] = va[ fa[ nfv[ _i ][0] ][k] ]; // other vertex 00452 project_vertex( _sp[2], _sp[3], _sp[0] ); 00453 _sp[2] -= _sp[0]; 00454 _sp[2].normalize(); 00455 _sp[1] = _sp[2] % _sp[3]; 00456 } 00457 00466 void compute_normal( const unsigned& _i, vec3& _n ) const { 00467 _n.clear(); 00468 for (unsigned fi = 0; fi < nfv[_i].size(); ++fi) 00469 _n += fna[ nfv[_i][fi] ]; 00470 _n /= nfv[_i].size(); 00471 } 00472 00474 00475 // @name Set functions 00477 00482 void set_vertices( const unsigned& _nv, const vec3 *_va ) { 00483 if( !_va ) return; 00484 nv = _nv; 00485 if( va ) delete [] va; 00486 va = new vec3[ nv ]; 00487 for (unsigned i = 0; i < nv; ++i) 00488 va[i] = _va[i]; 00489 } 00490 00495 void set_faces( const unsigned& _nf, const uvec3 *_fa ) { 00496 if( !_fa ) return; 00497 nf = _nf; 00498 if( fa ) delete [] fa; 00499 fa = new uvec3[ nf ]; 00500 for (unsigned i = 0; i < nf; ++i) 00501 fa[i] = _fa[i]; 00502 } 00503 00509 void set_grid( const unsigned& _gd, const index_list *_gfa, const T& _msd ) { 00510 if( !_gfa ) return; 00511 gd = _gd; 00512 if( gfa ) delete [] gfa; 00513 gfa = new index_list[ gd * gd * gd ]; 00514 for (unsigned i = 0; i < gd; ++i) 00515 for (unsigned j = 0; j < gd; ++j) 00516 for (unsigned k = 0; k < gd; ++k) 00517 gfa[ i*gd*gd + j*gd + k ] = _gfa[ i*gd*gd + j*gd + k ]; 00518 msd = _msd; 00519 } 00520 00525 void set_fnormals( const unsigned& _nf, const vec3 *_fna ) { 00526 if( !_fna ) return; 00527 if( fna ) delete [] fna; 00528 fna = new vec3[ _nf ]; 00529 for (unsigned i = 0; i < _nf; ++i) 00530 fna[i] = _fna[i]; 00531 } 00532 00536 void set_neighborhood( const std::vector< index_list >& _nfv ) { 00537 nfv = _nfv; 00538 } 00539 00544 void set_bbox( const bbox_type& _bb, const vec3& _diag ) { 00545 bb[0] = _bb[0]; 00546 bb[1] = _bb[1]; 00547 diag = _diag; 00548 } 00549 00551 00552 // @name Get functions 00554 00558 unsigned size_of_vertices( void ) const { return nv; } 00559 00563 unsigned size_of_faces( void ) const { return nf; } 00564 00568 unsigned grid_dimension( void ) const { return gd; } 00569 00573 vec3 *vertices( void ) { return va; } 00574 00578 const vec3 *vertices( void ) const { return va; } 00579 00583 uvec3 *faces( void ) { return fa; } 00584 00588 const uvec3 *faces( void ) const { return fa; } 00589 00593 index_list *grid( void ) { return gfa; } 00594 00598 const index_list *grid( void ) const { return gfa; } 00599 00603 T& maximum_search_distance( void ) { return msd; } 00604 00608 const T& maximum_search_distance( void ) const { return msd; } 00609 00613 vec3 *fnormals( void ) { return fna; } 00614 00618 const vec3 *fnormals( void ) const { return fna; } 00619 00623 std::vector< index_list >& neighborhood( void ) { return nfv; } 00624 00628 const std::vector< index_list >& neighborhood( void ) const { return nfv; } 00629 00633 bbox_type& bounding_box( void ) { return bb; } 00634 00638 const bbox_type& bounding_box( void ) const { return bb; } 00639 00643 vec3& diagonal( void ) { return diag; } 00644 00648 const vec3& diagonal( void ) const { return diag; } 00649 00653 T diagonal_distance( void ) const { return diag.length(); } 00654 00656 00657 protected: 00658 00663 void convert_to_grid( const vec3& _p, uvec3& _g ) const { 00664 vec3 bp = (_p - bb[0]) / diag; // bounding box relative position 00665 _g[0] = std::min( (unsigned)(bp[0] * gd), gd-1 ); 00666 _g[1] = std::min( (unsigned)(bp[1] * gd), gd-1 ); 00667 _g[2] = std::min( (unsigned)(bp[2] * gd), gd-1 ); 00668 } 00669 00670 private: 00671 00672 unsigned nv, nf, gd; 00673 vec3 *va; 00674 uvec3 *fa; 00675 index_list *gfa; 00676 T msd; 00677 vec3 *fna; 00678 std::vector< index_list > nfv; 00679 bbox_type bb; 00680 vec3 diag; 00681 00682 }; 00691 //=== IMPLEMENTATION ========================================================== 00692 00709 template< unsigned R, unsigned C, class T > 00710 void compute_signature( SignatureT< R, C, T >& _sig, 00711 const SignatureMeshT< T >& _m, 00712 const unsigned& _i ) { 00713 00714 typedef typename SignatureMeshT< T >::vec3 vec3; 00715 typedef typename SignatureMeshT< T >::sigplane_type sigplane_type; 00716 00717 sigplane_type sp; // tangent plane on top of the vertex 00718 00719 _m.compute_sigplane( _i, sp ); 00720 00721 T hmr = _m.maximum_search_distance(); // heightmap radius 00722 T inf = 1.5 * hmr; // heightmap infinity value 00723 vec3 vX, vY, vZ; // three generic vectors used throughout this function 00724 00725 vX = sp[1] * hmr; // vector base of tangent plane in X 00726 vY = sp[2] * hmr; // vector base of tangent plane in Y 00727 00728 vec3 pq[4]; // tangent plane quad border points 00729 00730 pq[0] = sp[0] - vX - vY; 00731 pq[1] = sp[0] + vX - vY; 00732 pq[2] = sp[0] + vX + vY; 00733 pq[3] = sp[0] - vX + vY; 00734 00735 vX = pq[1] - pq[0]; 00736 vY = pq[3] - pq[0]; 00737 00738 T lx = vX.sqrl(); // squared length of vector X 00739 T ly = vY.sqrl(); // squared length of vector Y 00740 00741 vec3 di, dj; // tangent plane cell supporting vectors 00742 00743 di = vY / (T)R; 00744 dj = vX / (T)C; 00745 00746 std::set< unsigned > nf; // neighborhood of faces to be consider around vertex 00747 _m.compute_neighborhood( _i, nf ); 00748 00749 // auxiliary data structure storing faces to be considered for each cell 00750 std::vector< unsigned > grid_faces[ R ][ C ]; 00751 unsigned fi; // current face index 00752 int bb[2][2]; // face bounding box over the plane 00753 vec3 bp, lp; // base and line points 00754 T u, v; // (u, v) position over the plane 00755 int gi, gj; // (i, j) grid discrete position 00756 00757 // build auxiliary grid cell faces data structure 00758 for (std::set< unsigned >::iterator sit = nf.begin(); sit != nf.end(); ++sit) { 00759 00760 fi = *sit; 00761 bb[0][0] = R; bb[0][1] = C; bb[1][0] = bb[1][1] = -1; // reset bounding box 00762 00763 // compute the current face's bounding box over the plane 00764 for (unsigned vi = 0; vi < 3; ++vi) { 00765 00766 bp = _m.vertices()[ _m.faces()[fi][vi] ]; // face vertex position = base point 00767 00768 project_vertex( bp, sp[3], sp[0] ); // project point onto tangent plane 00769 00770 bp -= pq[0]; // converting projected base point to plane vector 00771 00772 u = ( bp ^ vX ) / lx; // computing (u, v) position over the plane 00773 v = ( bp ^ vY ) / ly; 00774 00775 gi = (int)( v * R ); // discretizing (u, v) 00776 gj = (int)( u * C ); 00777 00778 // [0, 1] -> |--|-..-| last bar (1) is the last grid cell also 00779 if( gi >= R ) gi = R - 1; 00780 if( gj >= C ) gj = C - 1; 00781 if( gi < 0 ) gi = 0; 00782 if( gj < 0 ) gj = 0; 00783 00784 if( gi < bb[0][0] ) bb[0][0] = gi; // update bounding box 00785 if( gi > bb[1][0] ) bb[1][0] = gi; 00786 if( gj < bb[0][1] ) bb[0][1] = gj; 00787 if( gj > bb[1][1] ) bb[1][1] = gj; 00788 00789 } 00790 00791 // insert face on all grid cells inside the face bounding box 00792 for (gi = bb[0][0]; gi <= bb[1][0]; ++gi) 00793 for (gj = bb[0][1]; gj <= bb[1][1]; ++gj) 00794 grid_faces[gi][gj].push_back( *sit ); 00795 00796 } // sit 00797 00798 T x, y; // (x, y) position over the plane 00799 T hitt; // hitted t line parameter 00800 T det; // determinant of intersection matrix 00801 vec< 3, vec3 > inv; // inverse of intersection matrix 00802 vec3 fn; // current face normal 00803 vec3 p0, p1, p2; // current face vertices 00804 vec3 b, ipoint; // target vector and intersection point 00805 T t; // intersection line parameter 00806 00807 bp = pq[0] + ( di * 0.5 ) + ( dj * 0.5 ); // base point at the center of cell 00808 vZ = sp[3]; // tangent normal 00809 00810 _sig.clear(); 00811 00812 for (gi = 0; gi < R; ++gi) { // for each grid row 00813 00814 y = ( (T)2 * gi + (T)1 ) / (T)R - (T)1; 00815 00816 for (gj = 0; gj < C; ++gj) { // for each grid column 00817 00818 _sig[gi][gj] = inf; // set the current grid cell to infinity height 00819 00820 hitt = std::numeric_limits< T >::max(); // set the current hit t to infinity 00821 00822 x = ( (T)2 * gj + (T)1 ) / (T)C - (T)1; 00823 00824 if( sqrt( x*x + y*y ) > (T)1 ) continue; // compute heightmap signature only inside unit disk 00825 00826 lp = bp + ( di * gi ) + ( dj * gj ); // define cell's line by the current grid cell center point 00827 00828 // shoot rays in both direction (over the cell's line) to find intersections 00829 for (std::vector< unsigned >::iterator vit = grid_faces[gi][gj].begin(); vit != grid_faces[gi][gj].end(); ++vit) { 00830 00831 fi = *vit; 00832 00833 fn = _m.fnormals()[ fi ]; // current face normal 00834 00835 // define three vertices of the current triangular face 00836 p0 = _m.vertices()[ _m.faces()[fi][0] ]; 00837 p1 = _m.vertices()[ _m.faces()[fi][1] ]; 00838 p2 = _m.vertices()[ _m.faces()[fi][2] ]; 00839 00840 // the intersection matrix A is defined by three vectors: 00841 // vX vector from p0 to p1; vY vector from p0 to p2; vZ the tangent-plane normal 00842 vX = p1 - p0; 00843 vY = p2 - p0; 00844 00845 // compute the determinant of the intersection matrix: 00846 // A = | vZ vX vY | 00847 det = vZ[0] * vX[1] * vY[2] - vZ[0] * vY[1] * vX[2] 00848 + vX[0] * vY[1] * vZ[2] - vX[0] * vZ[1] * vY[2] 00849 + vY[0] * vZ[1] * vX[2] - vY[0] * vX[1] * vZ[2]; 00850 00851 // if the intersection matrix is linearly dependent.. 00852 if( fabs(det) < 1e-5 ) continue; //.. skip this face 00853 00854 // compute the inverse intersection matrix: 00855 // A^-1 = ( 1 / det ) * transpose of cofactor matrix 00856 inv[0][0] = ( vX[1] * vY[2] - vY[1] * vX[2] ) / det; 00857 inv[0][1] = ( vY[0] * vX[2] - vX[0] * vY[2] ) / det; 00858 inv[0][2] = ( vX[0] * vY[1] - vY[0] * vX[1] ) / det; 00859 00860 inv[1][0] = ( vY[1] * vZ[2] - vZ[1] * vY[2] ) / det; 00861 inv[1][1] = ( vZ[0] * vY[2] - vY[0] * vZ[2] ) / det; 00862 inv[1][2] = ( vY[0] * vZ[1] - vZ[0] * vY[1] ) / det; 00863 00864 inv[2][0] = ( vZ[1] * vX[2] - vX[1] * vZ[2] ) / det; 00865 inv[2][1] = ( vX[0] * vZ[2] - vZ[0] * vX[2] ) / det; 00866 inv[2][2] = ( vZ[0] * vX[1] - vX[0] * vZ[1] ) / det; 00867 00868 // target vector b of the intersection linear system: A x = b 00869 // x = | t u v |^T 00870 // b = | point in line - point in triangle | 00871 b = lp - p0; 00872 00873 // compute intersection point (u, v) parameters by x = A^-1 * b 00874 u = inv[1] ^ b; 00875 v = inv[2] ^ b; 00876 00877 // test if the intersection point is inside triangle 00878 if( u >= 0.0 and u <= 1.0 and v >= 0.0 and v <= 1.0 and (u+v) <= 1.0 ) { 00879 00880 // compute intersection point line parameter t 00881 t = inv[0] ^ b; 00882 00883 if( fabs(t) > fabs(hitt) ) continue; 00884 00885 hitt = t; 00886 00887 _sig[gi][gj] = t; 00888 00889 } // if 00890 00891 } // vit 00892 00893 } // gj 00894 00895 } // gi 00896 00897 } 00898 00899 //============================================================================= 00900 } // namespace zsig 00901 //============================================================================= 00902 #endif // ZSIG_SIGNATURET_HH 00903 //=============================================================================