29 #ifndef DOXY_IGNORE_THIS
33 #include "MemoryUsage.h"
34 #include "PointStream.h"
37 #define ITERATION_POWER 1.0/3
38 #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12
42 const Real MATRIX_ENTRY_EPSILON = Real(0);
43 const Real EPSILON=Real(1e-6);
44 const Real ROUND_EPS=Real(1e-5);
51 SortedTreeNodes::SortedTreeNodes(
void )
54 treeNodes = NullPointer< TreeOctNode* >();
57 SortedTreeNodes::~SortedTreeNodes(
void )
59 if( nodeCount )
delete[] nodeCount;
61 if( treeNodes ) DeletePointer( treeNodes );
66 if( nodeCount )
delete[] nodeCount;
67 if( treeNodes ) DeletePointer( treeNodes );
68 maxDepth = root.maxDepth()+1;
69 nodeCount =
new int[ maxDepth+1 ];
70 treeNodes = NewPointer< TreeOctNode* >( root.nodes() );
74 nodeCount[0] = 0 , nodeCount[1] = 1;
76 for(
TreeOctNode* node=root.nextNode() ; node ; node=root.nextNode( node ) ) node->nodeData.nodeIndex = -1;
77 for(
int d=startDepth+1 ; d<maxDepth ; d++ )
79 nodeCount[d+1] = nodeCount[d];
80 for(
int i=nodeCount[d-1] ; i<nodeCount[d] ; i++ )
83 if( temp->children )
for(
int c=0 ; c<8 ; c++ ) treeNodes[ nodeCount[d+1]++ ] = temp->children + c;
86 for(
int i=0 ; i<nodeCount[maxDepth] ; i++ ) treeNodes[i]->nodeData.nodeIndex = i;
92 void SortedTreeNodes::setCornerTable( CornerTableData& cData ,
const TreeOctNode* rootNode ,
int maxDepth ,
int threads )
const
94 if( threads<=0 ) threads = 1;
96 std::vector< std::pair< int , int > > spans( this->maxDepth , std::pair< int , int >( -1 , -1 ) );
97 int minDepth , off[3];
98 cData.offsets.resize( this->maxDepth , -1 );
102 if( rootNode ) rootNode->depthAndOffset( minDepth , off ) , start = end = rootNode->nodeData.nodeIndex;
106 for( minDepth=0 ; minDepth<=this->maxDepth ; minDepth++ )
if( nodeCount[minDepth+1] ){ end = nodeCount[minDepth+1]-1 ;
break; }
109 for(
int d=minDepth ; d<=maxDepth ; d++ )
111 spans[d] = std::pair< int , int >( start , end+1 );
112 cData.offsets[d] = nodeCount - spans[d].first;
113 nodeCount += spans[d].second - spans[d].first;
116 while( start< end && !treeNodes[start]->children ) start++;
117 while( end> start && !treeNodes[end ]->children ) end--;
118 if( start==end && !treeNodes[start]->children )
break;
119 start = treeNodes[start]->children[0].nodeData.nodeIndex;
120 end = treeNodes[end ]->children[7].nodeData.nodeIndex;
124 cData.cTable.resize( nodeCount );
125 std::vector< int > count( threads );
127 #pragma omp parallel for num_threads( threads )
129 for(
int t=0 ; t<threads ; t++ )
131 TreeOctNode::ConstNeighborKey3 neighborKey;
132 neighborKey.set( maxDepth );
133 int offset = nodeCount * t * Cube::CORNERS;
135 for(
int d=minDepth ; d<=maxDepth ; d++ )
137 int start = spans[d].first , end = spans[d].second , width = end-start;
138 for(
int i=start + (width*t)/threads ; i<start + (width*(t+1))/threads ; i++ )
141 if( d<maxDepth && node->children )
continue;
142 const TreeOctNode::ConstNeighbors3& neighbors = neighborKey.getNeighbors( node , minDepth );
143 for(
unsigned int c=0 ; c<Cube::CORNERS ; c++ )
145 bool cornerOwner =
true;
147 int ac = Cube::AntipodalCornerIndex( c );
148 Cube::FactorCornerIndex( c , x , y , z );
149 for(
int cc=0 ; cc< int(Cube::CORNERS) ; cc++ )
152 Cube::FactorCornerIndex( cc , xx , yy , zz );
153 xx += x , yy += y , zz += z;
154 if( neighbors.neighbors[xx][yy][zz] && neighbors.neighbors[xx][yy][zz]->nodeData.nodeIndex!=-1 )
155 if( cc<ac || ( d<maxDepth && neighbors.neighbors[xx][yy][zz]->children ) )
158 neighbors.neighbors[xx][yy][zz]->depthAndOffset( _d , _off );
159 _off[0] >>= (d-minDepth) , _off[1] >>= (d-minDepth) , _off[2] >>= (d-minDepth);
160 if( !rootNode || (_off[0]==off[0] && _off[1]==off[1] && _off[2]==off[2]) )
165 else fprintf( stderr ,
"[WARNING] How did we leave the subtree?\n" );
174 const TreeOctNode::ConstNeighbors3& neighbors = neighborKey.neighbors[d];
176 for(
unsigned int cc=0 ; cc<Cube::CORNERS ; cc++ )
179 Cube::FactorCornerIndex( cc , xx , yy , zz );
180 xx += x , yy += y , zz += z;
181 if( neighborKey.neighbors[d].neighbors[xx][yy][zz] && neighborKey.neighbors[d].neighbors[xx][yy][zz]->nodeData.nodeIndex!=-1 )
182 cData[ neighbors.neighbors[xx][yy][zz] ][ Cube::AntipodalCornerIndex(cc) ] = count[t] + offset;
185 if( d==minDepth || n!=(n->parent->children+c) )
break;
197 std::vector< int > offsets( threads+1 );
199 for(
int t=0 ; t<threads ; t++ ) cData.cCount += count[t] , offsets[t+1] = offsets[t] + count[t];
202 #pragma omp parallel
for num_threads( threads )
204 for(
int t=0 ; t<threads ; t++ )
205 for(
int d=minDepth ; d<=maxDepth ; d++ )
207 int start = spans[d].first , end = spans[d].second , width = end - start;
208 for(
int i=start + (width*t)/threads ; i<start+(width*(t+1))/threads ; i++ )
209 for(
unsigned int c=0 ; c<Cube::CORNERS ; c++ )
211 int& idx = cData[ treeNodes[i] ][c];
214 fprintf( stderr ,
"[ERROR] Found unindexed corner nodes[%d][%u] = %d (%d,%d)\n" , treeNodes[i]->nodeData.nodeIndex , c , idx , minDepth , maxDepth );
216 treeNodes[i]->depthAndOffset( _d , _off );
218 printf(
"(%d [%d %d %d) <-> (%d [%d %d %d])\n" , minDepth , off[0] , off[1] , off[2] , _d , _off[0] , _off[1] , _off[2] );
220 std::cerr <<
"NULL <-> ( " << minDepth <<
" [ " << off[0] <<
" " << off[1] <<
" " << off[2] <<
" ]) " << _d << std::endl;
221 printf(
"[%d %d]\n" , spans[d].first , spans[d].second );
226 int div = idx / ( nodeCount*Cube::CORNERS );
227 int rem = idx % ( nodeCount*Cube::CORNERS );
228 idx = rem + offsets[div];
233 int SortedTreeNodes::getMaxCornerCount(
int depth ,
int maxDepth ,
int threads )
const
235 if( threads<=0 ) threads = 1;
237 std::vector< std::vector< int > > cornerCount( threads );
238 for(
int t=0 ; t<threads ; t++ ) cornerCount[t].resize( res*res*res , 0 );
241 #pragma omp parallel for num_threads( threads )
243 for(
int t=0 ; t<threads ; t++ )
245 std::vector< int >& _cornerCount = cornerCount[t];
246 TreeOctNode::ConstNeighborKey3 neighborKey;
247 neighborKey.set( maxDepth );
248 int start = nodeCount[depth] , end = nodeCount[maxDepth+1] , range = end-start;
249 for(
int i=(range*t)/threads ; i<(range*(t+1))/threads ; i++ )
253 node->depthAndOffset( d , off );
254 if( d<maxDepth && node->children )
continue;
256 const TreeOctNode::ConstNeighbors3& neighbors = neighborKey.getNeighbors( node , depth );
257 for(
unsigned int c=0 ; c<Cube::CORNERS ; c++ )
259 bool cornerOwner =
true;
261 int ac = Cube::AntipodalCornerIndex( c );
262 Cube::FactorCornerIndex( c , x , y , z );
263 for(
int cc=0 ; cc<int(Cube::CORNERS) ; cc++ )
266 Cube::FactorCornerIndex( cc , xx , yy , zz );
267 xx += x , yy += y , zz += z;
268 if( neighbors.neighbors[xx][yy][zz] && neighbors.neighbors[xx][yy][zz]->nodeData.nodeIndex!=-1 )
269 if( cc<ac || ( d<maxDepth && neighbors.neighbors[xx][yy][zz]->children ) )
275 if( cornerOwner ) _cornerCount[ ( ( off[0]>>(d-depth) ) * res * res) + ( ( off[1]>>(d-depth) ) * res) + ( off[2]>>(d-depth) ) ]++;
280 for(
int i=0 ; i<res*res*res ; i++ )
283 for(
int t=0 ; t<threads ; t++ ) c += cornerCount[t][i];
284 maxCount = std::max< int >( maxCount , c );
292 void SortedTreeNodes::setEdgeTable( EdgeTableData& eData ,
const TreeOctNode* rootNode ,
int maxDepth ,
int threads )
294 if( threads<=0 ) threads = 1;
295 std::vector< std::pair< int , int > > spans( this->maxDepth , std::pair< int , int >( -1 , -1 ) );
298 eData.offsets.resize( this->maxDepth , -1 );
302 if( rootNode ) minDepth = rootNode->depth() , start = end = rootNode->nodeData.nodeIndex;
306 for( minDepth=0 ; minDepth<=this->maxDepth ; minDepth++ )
if( nodeCount[minDepth+1] ){ end = nodeCount[minDepth+1]-1 ;
break; }
311 for(
int d=minDepth ; d<=maxDepth ; d++ )
313 spans[d] = std::pair< int , int >( start , end+1 );
314 eData.offsets[d] = nodeCount - spans[d].first;
315 nodeCount += spans[d].second - spans[d].first;
318 while( start< end && !treeNodes[start]->children ) start++;
319 while( end> start && !treeNodes[end ]->children ) end--;
320 if( start==end && !treeNodes[start]->children )
break;
321 start = treeNodes[start]->children[0].nodeData.nodeIndex;
322 end = treeNodes[end ]->children[7].nodeData.nodeIndex;
326 eData.eTable.resize( nodeCount );
327 std::vector< int > count( threads );
330 #pragma omp parallel for num_threads( threads )
332 for(
int t=0 ; t<threads ; t++ )
334 TreeOctNode::ConstNeighborKey3 neighborKey;
335 neighborKey.set( maxDepth );
336 int offset = nodeCount * t * Cube::EDGES;
338 for(
int d=minDepth ; d<=maxDepth ; d++ )
340 int start = spans[d].first , end = spans[d].second , width = end-start;
341 for(
int i=start + (width*t)/threads ; i<start + (width*(t+1))/threads ; i++ )
344 const TreeOctNode::ConstNeighbors3& neighbors = neighborKey.getNeighbors( node , minDepth );
346 for(
unsigned int e=0 ; e<Cube::EDGES ; e++ )
348 bool edgeOwner =
true;
350 Cube::FactorEdgeIndex( e , o , i , j );
351 int ac = Square::AntipodalCornerIndex( Square::CornerIndex( i , j ) );
352 for(
int cc=0 ; cc<int(Square::CORNERS) ; cc++ )
360 Square::FactorCornerIndex( cc , ii , jj );
364 case 0: y = ii , z = jj , x = 1 ;
break;
365 case 1: x = ii , z = jj , y = 1 ;
break;
366 case 2: x = ii , y = jj , z = 1 ;
break;
368 if( neighbors.neighbors[x][y][z] && neighbors.neighbors[x][y][z]->nodeData.nodeIndex!=-1 && cc<ac ) { edgeOwner = false ;
break; }
373 for(
unsigned int cc=0 ; cc<Square::CORNERS ; cc++ )
383 Square::FactorCornerIndex( cc , ii , jj );
384 Square::FactorCornerIndex( Square::AntipodalCornerIndex( cc ) , aii , ajj );
388 case 0: y = ii , z = jj , x = 1 ;
break;
389 case 1: x = ii , z = jj , y = 1 ;
break;
390 case 2: x = ii , y = jj , z = 1 ;
break;
392 if( neighbors.neighbors[x][y][z] && neighbors.neighbors[x][y][z]->nodeData.nodeIndex!=-1 )
393 eData[ neighbors.neighbors[x][y][z] ][ Cube::EdgeIndex( o , aii , ajj ) ] = count[t]+offset;
402 std::vector< int > offsets( threads+1 );
404 for(
int t=0 ; t<threads ; t++ ) eData.eCount += count[t] , offsets[t+1] = offsets[t] + count[t];
407 #pragma omp parallel
for num_threads( threads )
409 for(
int t=0 ; t<threads ; t++ )
410 for(
int d=minDepth ; d<=maxDepth ; d++ )
412 int start = spans[d].first , end = spans[d].second , width = end - start;
413 for(
int i=start + (width*t)/threads ; i<start+(width*(t+1))/threads ; i++ )
414 for(
unsigned int e=0 ; e<Cube::EDGES ; e++ )
416 int& idx = eData[ treeNodes[i] ][e];
417 if( idx<0 ) fprintf( stderr ,
"[ERROR] Found unindexed edge %d (%d,%d)\n" , idx , minDepth , maxDepth ) , exit( 0 );
420 int div = idx / ( nodeCount*Cube::EDGES );
421 int rem = idx % ( nodeCount*Cube::EDGES );
422 idx = rem + offsets[div];
427 int SortedTreeNodes::getMaxEdgeCount(
const TreeOctNode* rootNode ,
int depth ,
int threads )
const
429 if( threads<=0 ) threads = 1;
431 std::vector< std::vector< int > > edgeCount( threads );
432 for(
int t=0 ; t<threads ; t++ ) edgeCount[t].resize( res*res*res , 0 );
435 #pragma omp parallel for num_threads( threads )
437 for(
int t=0 ; t<threads ; t++ )
439 std::vector< int >& _edgeCount = edgeCount[t];
440 TreeOctNode::ConstNeighborKey3 neighborKey;
441 neighborKey.set( maxDepth-1 );
442 int start = nodeCount[depth] , end = nodeCount[maxDepth] , range = end-start;
443 for(
int i=(range*t)/threads ; i<(range*(t+1))/threads ; i++ )
446 const TreeOctNode::ConstNeighbors3& neighbors = neighborKey.getNeighbors( node , depth );
448 node->depthAndOffset( d , off );
450 for(
unsigned int e=0 ; e<Cube::EDGES ; e++ )
452 bool edgeOwner =
true;
454 Cube::FactorEdgeIndex( e , o , i , j );
455 int ac = Square::AntipodalCornerIndex( Square::CornerIndex( i , j ) );
456 for(
int cc=0 ; cc<int(Square::CORNERS) ; cc++ )
464 Square::FactorCornerIndex( cc , ii , jj );
468 case 0: y = ii , z = jj , x = 1 ;
break;
469 case 1: x = ii , z = jj , y = 1 ;
break;
470 case 2: x = ii , y = jj , z = 1 ;
break;
472 if( neighbors.neighbors[x][y][z] && neighbors.neighbors[x][y][z]->nodeData.nodeIndex!=-1 && cc<ac ) { edgeOwner = false ;
break; }
474 if( edgeOwner ) _edgeCount[ ( ( off[0]>>(d-depth) ) * res * res) + ( ( off[1]>>(d-depth) ) * res) + ( off[2]>>(d-depth) ) ]++;
479 for(
int i=0 ; i<res*res*res ; i++ )
482 for(
int t=0 ; t<threads ; t++ ) c += edgeCount[t][i];
483 maxCount = std::max< int >( maxCount , c );
493 TreeNodeData::TreeNodeData(
void )
496 centerWeightContribution=0;
498 constraint = solution = 0;
501 TreeNodeData::~TreeNodeData(
void ) { }
512 double mem = double( MemoryInfo::Usage() ) / (1<<20);
513 if( mem>maxMemoryUsage ) maxMemoryUsage=mem;
523 postDerivativeSmooth = 0;
525 _constrainValues =
false;
531 template<
int Degree >
535 node->depthAndOffset( d , off );
536 int res = 1<<d , o = 1<<(d-2);
537 return ( off[0]>=o && off[0]<res-o && off[1]>=o && off[1]<res-o && off[2]>=o && off[2]<res-o );
539 template<
int Degree >
543 node->depthAndOffset( d , off );
544 int res = 1<<d , o = (1<<(d-2))-1;
545 return ( off[0]>=o && off[0]<res-o && off[1]>=o && off[1]<res-o && off[2]>=o && off[2]<res-o );
551 double x , dxdy , dxdydz , dx[DIMENSION][SPLAT_ORDER+1];
554 TreeOctNode::Neighbors3& neighbors = neighborKey.setNeighbors( node );
557 node->centerAndWidth( center , w );
559 for(
int i=0 ; i<3 ; i++ )
563 x = ( center[i] - position[i] - width ) / width;
564 dx[i][0] = 1.125+1.500*x+0.500*x*x;
565 x = ( center[i] - position[i] ) / width;
566 dx[i][1] = 0.750 - x*x;
568 dx[i][2] = 1. - dx[i][1] - dx[i][0];
570 x = ( position[i] - center[i] ) / width;
581 dx[i][1] = 1. - dx[i][0];
586 # error Splat order not supported
587 #endif // SPLAT_ORDER
589 for(
int i=off[0] ; i<=off[0]+SPLAT_ORDER ; i++ )
for(
int j=off[1] ; j<=off[1]+SPLAT_ORDER ; j++ )
591 dxdy = dx[0][i] * dx[1][j];
592 for(
int k=off[2] ; k<=off[2]+SPLAT_ORDER ; k++ )
593 if( neighbors.neighbors[i][j][k] )
595 dxdydz = dxdy * dx[2][k];
597 int idx =_node->nodeData.normalIndex;
601 n[0] = n[1] = n[2] = 0;
602 _node->nodeData.nodeIndex = 0;
603 idx = _node->nodeData.normalIndex = int(normals->size());
604 normals->push_back(n);
606 (*normals)[idx] += normal * Real( dxdydz );
611 template<
int Degree >
619 Real myWidth = Real(1.0);
622 while( temp->depth()<splatDepth )
624 if( !temp->children )
626 fprintf( stderr ,
"Octree<Degree>::SplatOrientedPoint error\n" );
629 int cIndex=TreeOctNode::CornerIndex(myCenter,position);
630 temp=&temp->children[cIndex];
632 if(cIndex&1) myCenter[0] += myWidth/2;
633 else myCenter[0] -= myWidth/2;
634 if(cIndex&2) myCenter[1] += myWidth/2;
635 else myCenter[1] -= myWidth/2;
636 if(cIndex&4) myCenter[2] += myWidth/2;
637 else myCenter[2] -= myWidth/2;
640 GetSampleDepthAndWeight( temp , position , neighborKey3 , samplesPerNode , depth , weight );
642 if( depth<minDepth ) depth = Real(minDepth);
643 if( depth>maxDepth ) depth = Real(maxDepth);
644 int topDepth=int(ceil(depth));
646 dx = 1.0-(topDepth-depth);
647 if( topDepth<=minDepth )
652 else if( topDepth>maxDepth )
657 while( temp->depth()>topDepth ) temp=temp->parent;
658 while( temp->depth()<topDepth )
660 if(!temp->children) temp->initChildren();
661 int cIndex = TreeOctNode::CornerIndex(myCenter,position);
662 temp = &temp->children[cIndex];
664 if( cIndex&1 ) myCenter[0] += myWidth/2;
665 else myCenter[0] -= myWidth/2;
666 if( cIndex&2 ) myCenter[1] += myWidth/2;
667 else myCenter[1] -= myWidth/2;
668 if( cIndex&4 ) myCenter[2] += myWidth/2;
669 else myCenter[2] -= myWidth/2;
671 width = 1.0 / ( 1<<temp->depth() );
672 n = normal * weight / Real( width*width*width ) * Real( dx );
673 SplatOrientedPoint( temp , position , n , neighborKey5 );
674 if( fabs(1.0-dx) > EPSILON )
678 width = 1.0 / ( 1<<temp->depth() );
679 n = normal * weight / Real( width*width*width ) * Real( dx );
680 SplatOrientedPoint( temp , position , n , neighborKey5 );
687 double x , dxdy , dxdydz , dx[DIMENSION][SPLAT_ORDER+1];
690 TreeOctNode::Neighbors5& neighbors = neighborKey.setNeighbors( node );
693 node->centerAndWidth( center , w );
695 for(
int i=0 ; i<3 ; i++ )
699 x = ( center[i] - position[i] - width ) / width;
700 dx[i][0] = 1.125+1.500*x+0.500*x*x;
701 x = ( center[i] - position[i] ) / width;
702 dx[i][1] = 0.750 - x*x;
704 dx[i][2] = 1. - dx[i][1] - dx[i][0];
706 x = ( position[i] - center[i] ) / width;
717 dx[i][1] = 1. - dx[i][0];
722 # error Splat order not supported
723 #endif // SPLAT_ORDER
725 for(
int i=off[0] ; i<=off[0]+SPLAT_ORDER ; i++ )
for(
int j=off[1] ; j<=off[1]+SPLAT_ORDER ; j++ )
727 dxdy = dx[0][i] * dx[1][j];
728 for(
int k=off[2] ; k<=off[2]+SPLAT_ORDER ; k++ )
729 if( neighbors.neighbors[i+1][j+1][k+1] )
731 dxdydz = dxdy * dx[2][k];
732 TreeOctNode* _node = neighbors.neighbors[i+1][j+1][k+1];
733 int idx =_node->nodeData.normalIndex;
737 n[0] = n[1] = n[2] = 0;
738 _node->nodeData.nodeIndex = 0;
739 idx = _node->nodeData.normalIndex = int(normals->size());
740 normals->push_back(n);
742 (*normals)[idx] += normal * Real( dxdydz );
747 template<
int Degree >
756 myCenter[0] = myCenter[1] = myCenter[2] = Real(0.5);
760 while( temp->depth()<splatDepth )
762 if( !temp->children )
764 fprintf( stderr ,
"Octree<Degree>::SplatOrientedPoint error\n" );
767 int cIndex=TreeOctNode::CornerIndex(myCenter,position);
768 temp=&temp->children[cIndex];
770 if(cIndex&1) myCenter[0] += myWidth/2;
771 else myCenter[0] -= myWidth/2;
772 if(cIndex&2) myCenter[1] += myWidth/2;
773 else myCenter[1] -= myWidth/2;
774 if(cIndex&4) myCenter[2] += myWidth/2;
775 else myCenter[2] -= myWidth/2;
778 GetSampleDepthAndWeight( temp , position , neighborKey , samplesPerNode , depth , weight );
780 if( depth<minDepth ) depth=Real(minDepth);
781 if( depth>maxDepth ) depth=Real(maxDepth);
782 int topDepth=int(ceil(depth));
784 dx = 1.0-(topDepth-depth);
785 if( topDepth<=minDepth )
790 else if( topDepth>maxDepth )
795 while( temp->depth()>topDepth ) temp=temp->parent;
796 while( temp->depth()<topDepth )
798 if(!temp->children) temp->initChildren();
799 int cIndex=TreeOctNode::CornerIndex(myCenter,position);
800 temp=&temp->children[cIndex];
802 if(cIndex&1) myCenter[0] += myWidth/2;
803 else myCenter[0] -= myWidth/2;
804 if(cIndex&2) myCenter[1] += myWidth/2;
805 else myCenter[1] -= myWidth/2;
806 if(cIndex&4) myCenter[2] += myWidth/2;
807 else myCenter[2] -= myWidth/2;
809 width = 1.0 / ( 1<<temp->depth() );
810 n = normal * weight / Real( pow( width , 3 ) ) * Real( dx );
811 SplatOrientedPoint( temp , position , n , neighborKey );
812 if( fabs(1.0-dx) > EPSILON )
816 width = 1.0 / ( 1<<temp->depth() );
818 n = normal * weight / Real( pow( width , 3 ) ) * Real( dx );
819 SplatOrientedPoint( temp , position , n , neighborKey );
828 weight = Real(1.0)/GetSampleWeight( temp , position , neighborKey );
829 if( weight>=samplesPerNode ) depth = Real( temp->depth() + log( weight / samplesPerNode ) / log(
double(1<<(DIMENSION-1))) );
832 Real oldWeight , newWeight;
833 oldWeight = newWeight = weight;
834 while( newWeight<samplesPerNode && temp->parent )
837 oldWeight = newWeight;
838 newWeight = Real(1.0)/GetSampleWeight( temp , position, neighborKey );
840 depth = Real( temp->depth() + log( newWeight / samplesPerNode ) / log( newWeight / oldWeight ) );
842 weight = Real( pow(
double(1<<(DIMENSION-1)) , -
double(depth) ) );
849 double x,dxdy,dx[DIMENSION][3];
851 TreeOctNode::Neighbors3& neighbors=neighborKey.setNeighbors( node );
854 node->centerAndWidth(center,w);
857 for(
int i=0 ; i<DIMENSION ; i++ )
859 x = ( center[i] - position[i] - width ) / width;
860 dx[i][0] = 1.125 + 1.500*x + 0.500*x*x;
861 x = ( center[i] - position[i] ) / width;
862 dx[i][1] = 0.750 - x*x;
864 dx[i][2] = 1.0 - dx[i][1] - dx[i][0];
867 for(
int i=0 ; i<3 ; i++ )
for(
int j=0 ; j<3 ; j++ )
869 dxdy = dx[0][i] * dx[1][j];
870 for(
int k=0 ; k<3 ; k++ )
if( neighbors.neighbors[i][j][k] )
871 weight += Real( dxdy * dx[2][k] * neighbors.neighbors[i][j][k]->nodeData.centerWeightContribution );
873 return Real( 1.0 / weight );
879 TreeOctNode::Neighbors3& neighbors = neighborKey.setNeighbors( node );
880 double x , dxdy , dx[DIMENSION][3] , width;
883 node->centerAndWidth( center , w );
885 const double SAMPLE_SCALE = 1. / ( 0.125 * 0.125 + 0.75 * 0.75 + 0.125 * 0.125 );
887 for(
int i=0 ; i<DIMENSION ; i++ )
889 x = ( center[i] - position[i] - width ) / width;
890 dx[i][0] = 1.125 + 1.500*x + 0.500*x*x;
891 x = ( center[i] - position[i] ) / width;
892 dx[i][1] = 0.750 - x*x;
893 dx[i][2] = 1. - dx[i][1] - dx[i][0];
896 dx[i][0] *= SAMPLE_SCALE;
899 for(
int i=0 ; i<3 ; i++ )
for(
int j=0 ; j<3 ; j++ )
901 dxdy = dx[0][i] * dx[1][j] * weight;
902 for(
int k=0 ; k<3 ; k++ )
if( neighbors.neighbors[i][j][k] )
903 neighbors.neighbors[i][j][k]->nodeData.centerWeightContribution += Real( dxdy * dx[2][k] );
908 template<
int Degree >
911 if( _boundaryType==0 ){
if( p[0]<Real(0.25) || p[0]>Real(0.75) || p[1]<Real(0.25) || p[1]>Real(0.75) || p[2]<Real(0.25) || p[2]>Real(0.75) )
return false; }
912 else {
if( p[0]<Real(0.00) || p[0]>Real(1.00) || p[1]<Real(0.00) || p[1]>Real(1.00) || p[2]<Real(0.00) || p[2]>Real(1.00) )
return false; }
915 template<
int Degree >
917 int splatDepth , Real samplesPerNode , Real scaleFactor ,
918 int useConfidence , Real constraintWeight ,
int adaptiveExponent ,
XForm4x4< Real > xForm )
920 if( splatDepth<0 ) splatDepth = 0;
922 for(
int i=0 ; i<3 ; i++ )
for(
int j=0 ; j<3 ; j++ ) xFormN(i,j) = xForm(i,j);
923 xFormN = xFormN.transpose().inverse();
924 if( _boundaryType==0 ) maxDepth++ , minDepth = std::max< int >( 1 , minDepth )+1;
925 else minDepth = std::max< int >( 0 , minDepth );
926 if( _boundaryType==0 && splatDepth>0 ) splatDepth++;
927 _minDepth = std::min< int >( minDepth , maxDepth );
928 _constrainValues = (constraintWeight>0);
929 double pointWeightSum = 0;
935 TreeOctNode::NeighborKey3 neighborKey;
936 neighborKey.set( maxDepth );
939 const char ext[] =
" ";
943 tree.setFullDepth( _minDepth );
948 while( pointStream->nextPoint( p , n ) )
951 for( i=0 ; i<DIMENSION ; i++ )
953 if( !cnt || p[i]<min[i] ) min[i] = p[i];
954 if( !cnt || p[i]>max[i] ) max[i] = p[i];
959 if( _boundaryType==0 ) _scale = std::max< Real >( max[0]-min[0] , std::max< Real >( max[1]-min[1] , max[2]-min[2] ) ) * 2;
960 else _scale = std::max< Real >( max[0]-min[0] , std::max< Real >( max[1]-min[1] , max[2]-min[2] ) );
961 _center = ( max+min ) /2;
964 _scale *= scaleFactor;
965 for( i=0 ; i<DIMENSION ; i++ ) _center[i] -= _scale/2;
970 pointStream->reset();
972 while( pointStream->nextPoint( p , n ) )
974 p = xForm * p , n = xFormN * n;
975 p = ( p - _center ) / _scale;
976 if( !_inBounds(p) )
continue;
979 Real weight=Real( 1. );
980 if( useConfidence ) weight = Real( Length(n) );
983 while( d<splatDepth )
985 UpdateWeightContribution( temp , p , neighborKey , weight );
986 if( !temp->children ) temp->initChildren();
987 int cIndex=TreeOctNode::CornerIndex( myCenter , p );
988 temp = temp->children + cIndex;
990 if( cIndex&1 ) myCenter[0] += myWidth/2;
991 else myCenter[0] -= myWidth/2;
992 if( cIndex&2 ) myCenter[1] += myWidth/2;
993 else myCenter[1] -= myWidth/2;
994 if( cIndex&4 ) myCenter[2] += myWidth/2;
995 else myCenter[2] -= myWidth/2;
998 UpdateWeightContribution( temp , p , neighborKey , weight );
1003 normals =
new std::vector< Point3D<Real> >();
1005 pointStream->reset();
1007 while( pointStream->nextPoint( p , n ) )
1010 p = xForm * p , n = xFormN * n;
1011 p = ( p - _center ) / _scale;
1012 if( !_inBounds(p) )
continue;
1014 myWidth = Real(1.0);
1015 Real l = Real( Length( n ) );
1016 if( l!=l || l<=EPSILON )
continue;
1017 if( !useConfidence ) n /= l;
1020 Real pointWeight = Real(1.f);
1021 if( samplesPerNode>0 && splatDepth )
1023 pointWeight = SplatOrientedPoint( p , n , neighborKey , splatDepth , samplesPerNode , _minDepth , maxDepth );
1031 while( d<splatDepth )
1033 int cIndex=TreeOctNode::CornerIndex(myCenter,p);
1034 temp = &temp->children[cIndex];
1036 if(cIndex&1) myCenter[0] += myWidth/2;
1037 else myCenter[0] -= myWidth/2;
1038 if(cIndex&2) myCenter[1] += myWidth/2;
1039 else myCenter[1] -= myWidth/2;
1040 if(cIndex&4) myCenter[2] += myWidth/2;
1041 else myCenter[2] -= myWidth/2;
1044 pointWeight = GetSampleWeight( temp , p , neighborKey );
1046 for( i=0 ; i<DIMENSION ; i++ ) n[i] *= pointWeight;
1049 if( !temp->children ) temp->initChildren();
1050 int cIndex=TreeOctNode::CornerIndex(myCenter,p);
1051 temp=&temp->children[cIndex];
1053 if(cIndex&1) myCenter[0] += myWidth/2;
1054 else myCenter[0] -= myWidth/2;
1055 if(cIndex&2) myCenter[1] += myWidth/2;
1056 else myCenter[1] -= myWidth/2;
1057 if(cIndex&4) myCenter[2] += myWidth/2;
1058 else myCenter[2] -= myWidth/2;
1061 SplatOrientedPoint( temp , p , n , neighborKey );
1063 pointWeightSum += pointWeight;
1064 if( _constrainValues )
1069 myWidth = Real(1.0);
1072 int idx = temp->nodeData.pointIndex;
1075 idx = int( _points.size() );
1076 _points.push_back( PointData( p , Real(1.) ) );
1077 temp->nodeData.pointIndex = idx;
1081 _points[idx].weight += Real(1.);
1082 _points[idx].position += p;
1085 int cIndex = TreeOctNode::CornerIndex( myCenter , p );
1086 if( !temp->children )
break;
1087 temp = &temp->children[cIndex];
1089 if( cIndex&1 ) myCenter[0] += myWidth/2;
1090 else myCenter[0] -= myWidth/2;
1091 if( cIndex&2 ) myCenter[1] += myWidth/2;
1092 else myCenter[1] -= myWidth/2;
1093 if( cIndex&4 ) myCenter[2] += myWidth/2;
1094 else myCenter[2] -= myWidth/2;
1101 if( _boundaryType==0 ) pointWeightSum *= Real(4.);
1102 constraintWeight *= Real( pointWeightSum );
1103 constraintWeight /= cnt;
1107 if( _constrainValues )
1108 for(
TreeOctNode* node=tree.nextNode() ; node ; node=tree.nextNode(node) )
1109 if( node->nodeData.pointIndex!=-1 )
1111 int idx = node->nodeData.pointIndex;
1112 _points[idx].position /= _points[idx].weight;
1113 int e = ( _boundaryType==0 ? node->d-1 : node->d ) * adaptiveExponent - ( _boundaryType==0 ? maxDepth-1 : maxDepth ) * (adaptiveExponent-1);
1114 if( e<0 ) _points[idx].weight /= Real( 1<<(-e) );
1115 else _points[idx].weight *= Real( 1<< e );
1116 _points[idx].weight *= Real( constraintWeight );
1118 #if FORCE_NEUMANN_FIELD
1119 if( _boundaryType==1 )
1120 for(
TreeOctNode* node=tree.nextNode() ; node ; node=tree.nextNode( node ) )
1122 int d , off[3] , res;
1123 node->depthAndOffset( d , off );
1125 if( node->nodeData.normalIndex<0 )
continue;
1127 for(
int d=0 ; d<3 ; d++ )
if( off[d]==0 || off[d]==res-1 ) normal[d] = 0;
1129 #endif // FORCE_NEUMANN_FIELD
1135 template<
int Degree >
1137 int splatDepth , Real samplesPerNode , Real scaleFactor ,
1138 int useConfidence , Real constraintWeight ,
int adaptiveExponent ,
XForm4x4< Real > xForm )
1140 if( splatDepth<0 ) splatDepth = 0;
1142 for(
int i=0 ; i<3 ; i++ )
for(
int j=0 ; j<3 ; j++ ) xFormN(i,j) = xForm(i,j);
1143 xFormN = xFormN.transpose().inverse();
1144 if( _boundaryType==0 ) maxDepth++ , minDepth = std::max< int >( 1 , minDepth )+1;
1145 else minDepth = std::max< int >( 0 , minDepth );
1146 if( _boundaryType==0 && splatDepth>0 ) splatDepth++;
1147 _minDepth = std::min< int >( minDepth , maxDepth );
1148 _constrainValues = (constraintWeight>0);
1149 double pointWeightSum = 0;
1155 TreeOctNode::NeighborKey3 neighborKey;
1156 neighborKey.set( maxDepth );
1164 tree.setFullDepth( _minDepth );
1170 while ( cnt < _pts_stream.size()/(2*DIMENSION) )
1173 for (
int i = 0; i < DIMENSION; ++i )
1175 p[i] = _pts_stream[2*DIMENSION*cnt + i];
1176 n[i] = _pts_stream[2*DIMENSION*cnt + DIMENSION + i];
1180 for(
int i=0 ; i<DIMENSION ; i++ )
1182 if( !cnt || p[i]<min[i] ) min[i] = p[i];
1183 if( !cnt || p[i]>max[i] ) max[i] = p[i];
1188 if( _boundaryType==0 ) _scale = std::max< Real >( max[0]-min[0] , std::max< Real >( max[1]-min[1] , max[2]-min[2] ) ) * 2;
1189 else _scale = std::max< Real >( max[0]-min[0] , std::max< Real >( max[1]-min[1] , max[2]-min[2] ) );
1190 _center = ( max+min ) /2;
1193 _scale *= scaleFactor;
1194 for(
int i=0 ; i<DIMENSION ; i++ ) _center[i] -= _scale/2;
1201 while ( cnt < _pts_stream.size()/(2*DIMENSION) )
1204 for (
int i = 0; i < DIMENSION; ++i )
1206 p[i] = _pts_stream[2*DIMENSION*cnt + i];
1207 n[i] = _pts_stream[2*DIMENSION*cnt + DIMENSION + i];
1210 p = xForm * p , n = xFormN * n;
1211 p = ( p - _center ) / _scale;
1212 if( !_inBounds(p) )
continue;
1214 myWidth = Real(1.0);
1215 Real weight=Real( 1. );
1216 if( useConfidence ) weight = Real( Length(n) );
1219 while( d<splatDepth )
1221 UpdateWeightContribution( temp , p , neighborKey , weight );
1222 if( !temp->children ) temp->initChildren();
1223 int cIndex=TreeOctNode::CornerIndex( myCenter , p );
1224 temp = temp->children + cIndex;
1226 if( cIndex&1 ) myCenter[0] += myWidth/2;
1227 else myCenter[0] -= myWidth/2;
1228 if( cIndex&2 ) myCenter[1] += myWidth/2;
1229 else myCenter[1] -= myWidth/2;
1230 if( cIndex&4 ) myCenter[2] += myWidth/2;
1231 else myCenter[2] -= myWidth/2;
1234 UpdateWeightContribution( temp , p , neighborKey , weight );
1239 normals =
new std::vector< Point3D<Real> >();
1240 unsigned int curPt = 0;
1244 while (curPt < _pts_stream.size()/(2*DIMENSION) )
1247 for (
int i = 0; i < DIMENSION; ++i )
1249 p[i] = _pts_stream[2*DIMENSION*curPt + i];
1250 n[i] = _pts_stream[2*DIMENSION*curPt + DIMENSION + i];
1254 p = xForm * p , n = xFormN * n;
1255 p = ( p - _center ) / _scale;
1263 myWidth = Real(1.0);
1264 Real l = Real( Length( n ) );
1265 if (l != l || l <= EPSILON)
1271 if( !useConfidence ) n /= l;
1274 Real pointWeight = Real(1.f);
1275 if( samplesPerNode>0 && splatDepth )
1277 pointWeight = SplatOrientedPoint( p , n , neighborKey , splatDepth , samplesPerNode , _minDepth , maxDepth );
1285 while( d<splatDepth )
1287 int cIndex=TreeOctNode::CornerIndex(myCenter,p);
1288 temp = &temp->children[cIndex];
1290 if(cIndex&1) myCenter[0] += myWidth/2;
1291 else myCenter[0] -= myWidth/2;
1292 if(cIndex&2) myCenter[1] += myWidth/2;
1293 else myCenter[1] -= myWidth/2;
1294 if(cIndex&4) myCenter[2] += myWidth/2;
1295 else myCenter[2] -= myWidth/2;
1298 pointWeight = GetSampleWeight( temp , p , neighborKey );
1300 for(
int i=0 ; i<DIMENSION ; i++ ) n[i] *= pointWeight;
1303 if( !temp->children ) temp->initChildren();
1304 int cIndex=TreeOctNode::CornerIndex(myCenter,p);
1305 temp=&temp->children[cIndex];
1307 if(cIndex&1) myCenter[0] += myWidth/2;
1308 else myCenter[0] -= myWidth/2;
1309 if(cIndex&2) myCenter[1] += myWidth/2;
1310 else myCenter[1] -= myWidth/2;
1311 if(cIndex&4) myCenter[2] += myWidth/2;
1312 else myCenter[2] -= myWidth/2;
1315 SplatOrientedPoint( temp , p , n , neighborKey );
1317 pointWeightSum += pointWeight;
1318 if( _constrainValues )
1323 myWidth = Real(1.0);
1326 int idx = temp->nodeData.pointIndex;
1329 idx = int( _points.size() );
1330 _points.push_back( PointData( p , Real(1.) ) );
1331 temp->nodeData.pointIndex = idx;
1335 _points[idx].weight += Real(1.);
1336 _points[idx].position += p;
1339 int cIndex = TreeOctNode::CornerIndex( myCenter , p );
1340 if( !temp->children )
break;
1341 temp = &temp->children[cIndex];
1343 if( cIndex&1 ) myCenter[0] += myWidth/2;
1344 else myCenter[0] -= myWidth/2;
1345 if( cIndex&2 ) myCenter[1] += myWidth/2;
1346 else myCenter[1] -= myWidth/2;
1347 if( cIndex&4 ) myCenter[2] += myWidth/2;
1348 else myCenter[2] -= myWidth/2;
1356 if( _boundaryType==0 ) pointWeightSum *= Real(4.);
1357 constraintWeight *= Real( pointWeightSum );
1358 constraintWeight /= cnt;
1362 if( _constrainValues )
1363 for(
TreeOctNode* node=tree.nextNode() ; node ; node=tree.nextNode(node) )
1364 if( node->nodeData.pointIndex!=-1 )
1366 int idx = node->nodeData.pointIndex;
1367 _points[idx].position /= _points[idx].weight;
1368 int e = ( _boundaryType==0 ? node->d-1 : node->d ) * adaptiveExponent - ( _boundaryType==0 ? maxDepth-1 : maxDepth ) * (adaptiveExponent-1);
1369 if( e<0 ) _points[idx].weight /= Real( 1<<(-e) );
1370 else _points[idx].weight *= Real( 1<< e );
1371 _points[idx].weight *= Real( constraintWeight );
1373 #if FORCE_NEUMANN_FIELD
1374 if( _boundaryType==1 )
1375 for(
TreeOctNode* node=tree.nextNode() ; node ; node=tree.nextNode( node ) )
1377 int d , off[3] , res;
1378 node->depthAndOffset( d , off );
1380 if( node->nodeData.normalIndex<0 )
continue;
1382 for(
int d=0 ; d<3 ; d++ )
if( off[d]==0 || off[d]==res-1 ) normal[d] = 0;
1384 #endif // FORCE_NEUMANN_FIELD
1390 template<
int Degree >
1393 _boundaryType = boundaryType;
1394 if ( _boundaryType<0 ) _boundaryType = -1;
1395 else if( _boundaryType>0 ) _boundaryType = 1;
1397 radius = 0.5 + 0.5 * Degree;
1398 width = int(
double(radius+0.5-EPSILON)*2);
1399 postDerivativeSmooth = Real(1.0)/(1<<maxDepth);
1400 fData.set( maxDepth ,
true , boundaryType );
1403 template<
int Degree>
1406 int maxDepth = tree.maxDepth( );
1407 TreeOctNode::NeighborKey5 nKey;
1408 nKey.set( maxDepth );
1409 for(
int d=maxDepth ; d>0 ; d-- )
1410 for(
TreeOctNode* node=tree.nextNode() ; node ; node=tree.nextNode( node ) )
1413 int xStart=0 , xEnd=5 , yStart=0 , yEnd=5 , zStart=0 , zEnd=5;
1414 int c = int( node - node->parent->children );
1416 Cube::FactorCornerIndex( c , x , y , z );
1423 nKey.setNeighbors( node->parent , xStart , xEnd , yStart , yEnd , zStart , zEnd );
1425 refineBoundary( subdivideDepth );
1427 template<
int Degree>
1430 return Real( fData.vvDotTable[idx[0]] * fData.vvDotTable[idx[1]] * fData.vvDotTable[idx[2]] * (fData.ddDotTable[idx[0]]+fData.ddDotTable[idx[1]]+fData.ddDotTable[idx[2]] ) );
1432 template<
int Degree >
1441 return GetLaplacian( symIndex );
1443 template<
int Degree >
1454 #if GRADIENT_DOMAIN_SOLUTION
1456 fData.Index( node2->off[0] , node1->off[0] ) ,
1457 fData.Index( node2->off[1] , node1->off[1] ) ,
1458 fData.Index( node2->off[2] , node1->off[2] )
1459 #else // !GRADIENT_DOMAIN_SOLUTION
1461 fData.Index( node1->off[0] , node2->off[0] ) ,
1462 fData.Index( node1->off[1] , node2->off[1] ) ,
1463 fData.Index( node1->off[2] , node2->off[2] )
1464 #endif // GRADIENT_DOMAIN_SOLUTION
1466 double dot = fData.vvDotTable[symIndex[0]] * fData.vvDotTable[symIndex[1]] * fData.vvDotTable[symIndex[2]];
1467 #if GRADIENT_DOMAIN_SOLUTION
1468 return Real( dot * ( fData.dvDotTable[aSymIndex[0]]*normal1[0] + fData.dvDotTable[aSymIndex[1]]*normal1[1] + fData.dvDotTable[aSymIndex[2]]*normal1[2] ) );
1469 #else // !GRADIENT_DOMAIN_SOLUTION
1470 return -Real( dot * ( fData.dvDotTable[aSymIndex[0]]*normal1[0] + fData.dvDotTable[aSymIndex[1]]*normal1[1] + fData.dvDotTable[aSymIndex[2]]*normal1[2] ) );
1471 #endif // GRADIENT_DOMAIN_SOLUTION
1473 template<
int Degree >
1484 #if GRADIENT_DOMAIN_SOLUTION
1486 fData.Index( node2->off[0] , node1->off[0] ) ,
1487 fData.Index( node2->off[1] , node1->off[1] ) ,
1488 fData.Index( node2->off[2] , node1->off[2] )
1489 #else // !GRADIENT_DOMAIN_SOLUTION
1491 fData.Index( node1->off[0] , node2->off[0] ) ,
1492 fData.Index( node1->off[1] , node2->off[1] ) ,
1493 fData.Index( node1->off[2] , node2->off[2] )
1494 #endif // GRADIENT_DOMAIN_SOLUTION
1496 double dot = fData.vvDotTable[symIndex[0]] * fData.vvDotTable[symIndex[1]] * fData.vvDotTable[symIndex[2]];
1499 #
if GRADIENT_DOMAIN_SOLUTION
1500 - ( fData.ddDotTable[ symIndex[0]] + fData.ddDotTable[ symIndex[1]] + fData.ddDotTable[ symIndex[2]] ) * value1
1501 + ( fData.dvDotTable[aSymIndex[0]]*normal1[0] + fData.dvDotTable[aSymIndex[1]]*normal1[1] + fData.dvDotTable[aSymIndex[2]]*normal1[2] )
1503 - ( fData.ddDotTable[ symIndex[0]] + fData.ddDotTable[ symIndex[1]] + fData.ddDotTable[ symIndex[2]] ) * value1
1504 - ( fData.dvDotTable[aSymIndex[0]]*normal1[0] + fData.dvDotTable[aSymIndex[1]]*normal1[1] + fData.dvDotTable[aSymIndex[2]]*normal1[2] )
1509 template<
int Degree >
1512 xStart = 0 , yStart = 0 , zStart = 0 , xEnd = 5 , yEnd = 5 , zEnd = 5;
1514 node->depthAndOffset( depth , off );
1515 int width = 1 << ( depth-rDepth );
1516 off[0] -= rOff[0] << ( depth-rDepth ) , off[1] -= rOff[1] << ( depth-rDepth ) , off[2] -= rOff[2] << ( depth-rDepth );
1517 if( off[0]<0 ) xStart = -off[0];
1518 if( off[1]<0 ) yStart = -off[1];
1519 if( off[2]<0 ) zStart = -off[2];
1520 if( off[0]>=width ) xEnd = 4 - ( off[0]-width );
1521 if( off[1]>=width ) yEnd = 4 - ( off[1]-width );
1522 if( off[2]>=width ) zEnd = 4 - ( off[2]-width );
1524 template<
int Degree >
1526 template<
int Degree >
1530 for(
int x=xStart ; x<=2 ; x++ )
1531 for(
int y=yStart ; y<yEnd ; y++ )
1532 if( x==2 && y>2 )
continue;
1533 else for(
int z=zStart ; z<zEnd ; z++ )
1534 if( x==2 && y==2 && z>2 )
continue;
1535 else if( neighbors5.neighbors[x][y][z] && neighbors5.neighbors[x][y][z]->nodeData.nodeIndex>=0 )
1539 template<
int Degree >
1542 return SetMatrixRow( neighbors5 , row , offset , stencil , 0 , 5 , 0 , 5 , 0 , 5 );
1545 template<
int Degree >
1546 int Octree< Degree >::SetMatrixRow(
const OctNode< TreeNodeData , Real >::Neighbors5& neighbors5 , Pointer(
MatrixEntry< MatrixReal > ) row ,
int offset ,
const double stencil[5][5][5] ,
int xStart ,
int xEnd ,
int yStart ,
int yEnd ,
int zStart ,
int zEnd )
const
1548 bool hasYZPoints[3] , hasZPoints[3][3];
1550 Real splineValues[3*3*3*3*3];
1551 memset( splineValues , 0 ,
sizeof( Real ) * 3 * 3 * 3 * 3 * 3 );
1554 const TreeOctNode* node = neighbors5.neighbors[2][2][2];
1559 neighbors5.neighbors[2][2][2]->depthAndOffset( d , off );
1561 int o = _boundaryType==0 ? ( 1<<(d-2) ) : 0;
1562 int mn = 2+o , mx = (1<<d)-2-o;
1563 isInterior = ( off[0]>=mn && off[0]<mx && off[1]>=mn && off[1]<mx && off[2]>=mn && off[2]<mx );
1565 if( _constrainValues )
1568 node->depthAndOffset( d , idx );
1572 for(
int j=0 ; j<3 ; j++ )
1574 hasYZPoints[j] =
false;
1575 for(
int k=0 ; k<3 ; k++ )
1577 hasZPoints[j][k] =
false;
1578 for(
int l=0 ; l<3 ; l++ )
1580 const TreeOctNode* _node = neighbors5.neighbors[j+1][k+1][l+1];
1581 if( _node && _node->nodeData.pointIndex!=-1 )
1583 const PointData& pData = _points[ _node->nodeData.pointIndex ];
1584 Real* _splineValues = splineValues + 3*3*(3*(3*j+k)+l);
1585 Real weight = pData.weight;
1587 for(
int s=0 ; s<3 ; s++ )
1589 #if ROBERTO_TOLDO_FIX
1590 if( idx[0]+j-s>=0 && idx[0]+j-s<((2<<node->d)-1) ) _splineValues[3*0+s] = Real( fData.baseBSplines[ idx[0]+j-s][s]( p[0] ) );
1591 if( idx[1]+k-s>=0 && idx[1]+k-s<((2<<node->d)-1) ) _splineValues[3*1+s] = Real( fData.baseBSplines[ idx[1]+k-s][s]( p[1] ) );
1592 if( idx[2]+l-s>=0 && idx[2]+l-s<((2<<node->d)-1) ) _splineValues[3*2+s] = Real( fData.baseBSplines[ idx[2]+l-s][s]( p[2] ) );
1593 #else // !ROBERTO_TOLDO_FIX
1594 _splineValues[3*0+s] = Real( fData.baseBSplines[ idx[0]+j-s][s]( p[0] ) );
1595 _splineValues[3*1+s] = Real( fData.baseBSplines[ idx[1]+k-s][s]( p[1] ) );
1596 _splineValues[3*2+s] = Real( fData.baseBSplines[ idx[2]+l-s][s]( p[2] ) );
1597 #endif // ROBERTO_TOLDO_FIX
1599 Real value = _splineValues[3*0+j] * _splineValues[3*1+k] * _splineValues[3*2+l];
1600 Real weightedValue = value * weight;
1601 for(
int s=0 ; s<3 ; s++ ) _splineValues[3*0+s] *= weightedValue;
1602 diagonal += value * value * weight;
1603 hasYZPoints[j] = hasZPoints[j][k] =
true;
1610 Real pointValues[5][5][5];
1611 if( _constrainValues )
1613 memset( pointValues , 0 ,
sizeof(Real)*5*5*5 );
1614 for(
int i=0 ; i<3 ; i++ )
if( hasYZPoints[i] )
1615 for(
int j=0 ; j<3 ; j++ )
if( hasZPoints[i][j] )
1616 for(
int k=0 ; k<3 ; k++ )
1618 const Real* _splineValuesX = splineValues + 3*(3*(3*(3*i+j)+k)+0)+2;
1619 const Real* _splineValuesY = splineValues + 3*(3*(3*(3*i+j)+k)+1)+2;
1620 const Real* _splineValuesZ = splineValues + 3*(3*(3*(3*i+j)+k)+2)+2;
1621 const TreeOctNode* _node = neighbors5.neighbors[i+1][j+1][k+1];
1622 if( _node && _node->nodeData.pointIndex!=-1 )
1623 for(
int ii=0 ; ii<=2 ; ii++ )
1625 Real splineValue = _splineValuesX[-ii];
1626 for(
int jj=0 ; jj<=2 ; jj++ )
1628 Real* _pointValues = pointValues[i+ii][j+jj]+k;
1629 Real _splineValue = splineValue * _splineValuesY[-jj];
1630 for(
int kk=0 ; kk<=2 ; kk++ ) _pointValues[kk] += _splineValue * _splineValuesZ[-kk];
1635 for(
int x=xStart ; x<=2 ; x++ )
1640 for(
int y=yStart ; y<yEnd ; y++ )
1643 if( x==2 && y>2 )
continue;
1646 for(
int z=zStart ; z<zEnd ; z++ )
1648 if( x==2 && y==2 && z>2 )
continue;
1650 if( neighbors5.neighbors[x][y][z] && neighbors5.neighbors[x][y][z]->nodeData.nodeIndex>=0 )
1652 const TreeOctNode* _node = neighbors5.neighbors[x][y][z];
1654 if( isInterior ) temp = Real( stencil[x][y][z] );
1655 else temp = GetLaplacian( node , _node );
1656 if( _constrainValues )
1658 if( x==2 && y==2 && z==2 ) temp += diagonal;
1661 temp += pointValues[x][y][z];
1664 if( x==2 && y==2 && z==2 ) temp /= 2;
1665 if( fabs(temp)>MATRIX_ENTRY_EPSILON )
1667 row[count].N = _node->nodeData.nodeIndex-offset;
1668 row[count].Value = temp;
1677 template<
int Degree >
1680 if( depth<2 )
return;
1681 int center = 1<<(depth-1);
1682 int offset[] = { center , center , center };
1684 TreeOctNode::Index( depth , offset , d , off );
1685 int index1[3] , index2[3];
1686 if( scatter ) index2[0] = int( off[0] ) , index2[1] = int( off[1] ) , index2[2] = int( off[2] );
1687 else index1[0] = int( off[0] ) , index1[1] = int( off[1] ) , index1[2] = int( off[2] );
1688 for(
int x=0 ; x<5 ; x++ )
for(
int y=0 ; y<5 ; y++ )
for(
int z=0 ; z<5 ; z++ )
1690 int _offset[] = { x+center-2 , y+center-2 , z+center-2 };
1691 TreeOctNode::Index( depth , _offset , d , off );
1692 if( scatter ) index1[0] = int( off[0] ) , index1[1] = int( off[1] ) , index1[2] = int( off[2] );
1693 else index2[0] = int( off[0] ) , index2[1] = int( off[1] ) , index2[2] = int( off[2] );
1702 #if GRADIENT_DOMAIN_SOLUTION
1704 fData.Index( index1[0] , index2[0] ) ,
1705 fData.Index( index1[1] , index2[1] ) ,
1706 fData.Index( index1[2] , index2[2] )
1707 #else // !GRADIENT_DOMAIN_SOLUTION
1709 fData.Index( index2[0] , index1[0] ) ,
1710 fData.Index( index2[1] , index1[1] ) ,
1711 fData.Index( index2[2] , index1[2] )
1712 #endif // GRADIENT_DOMAIN_SOLUTION
1715 double dot = fData.vvDotTable[symIndex[0]] * fData.vvDotTable[symIndex[1]] * fData.vvDotTable[symIndex[2]];
1717 #if GRADIENT_DOMAIN_SOLUTION
1718 stencil[x][y][z][0] = fData.dvDotTable[aSymIndex[0]] * dot;
1719 stencil[x][y][z][1] = fData.dvDotTable[aSymIndex[1]] * dot;
1720 stencil[x][y][z][2] = fData.dvDotTable[aSymIndex[2]] * dot;
1721 #else // !GRADIENT_DOMAIN_SOLUTION
1722 stencil[x][y][z][0] = -fData.dvDotTable[aSymIndex[0]] * dot;
1723 stencil[x][y][z][1] = -fData.dvDotTable[aSymIndex[1]] * dot;
1724 stencil[x][y][z][2] = -fData.dvDotTable[aSymIndex[2]] * dot;
1725 #endif // GRADIENT_DOMAIN_SOLUTION
1728 template<
int Degree >
1731 if( depth<2 )
return;
1732 int center = 1<<(depth-1);
1733 int index1[3] , index2[3];
1734 for(
int i=0 ; i<2 ; i++ )
for(
int j=0 ; j<2 ; j++ )
for(
int k=0 ; k<2 ; k++ )
1737 int offset[] = { center+i , center+j , center+k };
1738 TreeOctNode::Index( depth , offset , d , off );
1739 if( scatter ) index2[0] = int( off[0] ) , index2[1] = int( off[1] ) , index2[2] = int( off[2] );
1740 else index1[0] = int( off[0] ) , index1[1] = int( off[1] ) , index1[2] = int( off[2] );
1741 for(
int x=0 ; x<5 ; x++ )
for(
int y=0 ; y<5 ; y++ )
for(
int z=0 ; z<5 ; z++ )
1743 int _offset[] = { x-2+center/2 , y-2+center/2 , z-2+center/2 };
1744 TreeOctNode::Index( depth-1 , _offset , d , off );
1745 if( scatter ) index1[0] = int( off[0] ) , index1[1] = int( off[1] ) , index1[2] = int( off[2] );
1746 else index2[0] = int( off[0] ) , index2[1] = int( off[1] ) , index2[2] = int( off[2] );
1756 #if GRADIENT_DOMAIN_SOLUTION
1758 fData.Index( index1[0] , index2[0] ) ,
1759 fData.Index( index1[1] , index2[1] ) ,
1760 fData.Index( index1[2] , index2[2] )
1761 #else // !GRADIENT_DOMAIN_SOLUTION
1763 fData.Index( index2[0] , index1[0] ) ,
1764 fData.Index( index2[1] , index1[1] ) ,
1765 fData.Index( index2[2] , index1[2] )
1766 #endif // GRADIENT_DOMAIN_SOLUTION
1768 double dot = fData.vvDotTable[symIndex[0]] * fData.vvDotTable[symIndex[1]] * fData.vvDotTable[symIndex[2]];
1769 #if GRADIENT_DOMAIN_SOLUTION
1770 stencils[i][j][k].values[x][y][z][0] = fData.dvDotTable[aSymIndex[0]] * dot;
1771 stencils[i][j][k].values[x][y][z][1] = fData.dvDotTable[aSymIndex[1]] * dot;
1772 stencils[i][j][k].values[x][y][z][2] = fData.dvDotTable[aSymIndex[2]] * dot;
1773 #else // !GRADIENT_DOMAIN_SOLUTION
1774 stencils[i][j][k].values[x][y][z][0] = -fData.dvDotTable[aSymIndex[0]] * dot;
1775 stencils[i][j][k].values[x][y][z][1] = -fData.dvDotTable[aSymIndex[1]] * dot;
1776 stencils[i][j][k].values[x][y][z][2] = -fData.dvDotTable[aSymIndex[2]] * dot;
1777 #endif // GRADIENT_DOMAIN_SOLUTION
1781 template<
int Degree >
1784 if( depth<2 )
return;
1785 int center = 1<<(depth-1);
1786 int offset[] = { center , center , center };
1788 TreeOctNode::Index( depth , offset , d , off );
1789 int index[] = { int( off[0] ) , int( off[1] ) , int( off[2] ) };
1790 for(
int x=-2 ; x<=2 ; x++ )
for(
int y=-2 ; y<=2 ; y++ )
for(
int z=-2 ; z<=2 ; z++ )
1792 int _offset[] = { x+center , y+center , z+center };
1794 TreeOctNode::Index( depth , _offset , _d , _off );
1795 int _index[] = { int( _off[0] ) , int( _off[1] ) , int( _off[2] ) };
1800 stencil[x+2][y+2][z+2] = GetLaplacian( symIndex );
1803 template<
int Degree >
1806 if( depth<2 )
return;
1807 int center = 1<<(depth-1);
1808 for(
int i=0 ; i<2 ; i++ )
for(
int j=0 ; j<2 ; j++ )
for(
int k=0 ; k<2 ; k++ )
1811 int offset[] = { center+i , center+j , center+k };
1812 TreeOctNode::Index( depth , offset , d , off );
1813 int index[] = { int( off[0] ) , int( off[1] ) , int( off[2] ) };
1814 for(
int x=-2 ; x<=2 ; x++ )
for(
int y=-2 ; y<=2 ; y++ )
for(
int z=-2 ; z<=2 ; z++ )
1816 int _offset[] = { x+center/2 , y+center/2 , z+center/2 };
1818 TreeOctNode::Index( depth-1 , _offset , _d , _off );
1819 int _index[] = { int( _off[0] ) , int( _off[1] ) , int( _off[2] ) };
1824 stencils[i][j][k].values[x+2][y+2][z+2] = GetLaplacian( symIndex );
1828 template<
int Degree >
1834 int off[] = { 2 , 2 , 2 };
1835 for(
int c=0 ; c<8 ; c++ )
1837 VertexData::CornerIndex( depth , off , c , fData.depth , idx );
1838 idx[0] *= fData.functionCount , idx[1] *= fData.functionCount , idx[2] *= fData.functionCount;
1839 for(
int x=0 ; x<3 ; x++ )
for(
int y=0 ; y<3 ; y++ )
for(
int z=0 ; z<3 ; z++ )
1842 int _offset[] = { x+1 , y+1 , z+1 };
1843 TreeOctNode::Index( depth , _offset , _d , _off );
1844 stencil1[c].values[x][y][z] = Real( fData.valueTables[ idx[0]+
int(_off[0]) ] * fData.valueTables[ idx[1]+
int(_off[1]) ] * fData.valueTables[ idx[2]+
int(_off[2]) ] );
1849 for(
int _c=0 ; _c<8 ; _c++ )
1852 int _cx , _cy , _cz;
1853 Cube::FactorCornerIndex( _c , _cx , _cy , _cz );
1854 int off[] = { 4+_cx , 4+_cy , 4+_cz };
1855 for(
int c=0 ; c<8 ; c++ )
1857 VertexData::CornerIndex( depth , off , c , fData.depth , idx );
1858 idx[0] *= fData.functionCount , idx[1] *= fData.functionCount , idx[2] *= fData.functionCount;
1859 for(
int x=0 ; x<3 ; x++ )
for(
int y=0 ; y<3 ; y++ )
for(
int z=0 ; z<3 ; z++ )
1862 int _offset[] = { x+1 , y+1 , z+1 };
1863 TreeOctNode::Index( depth-1 , _offset , _d , _off );
1864 stencil2[_c][c].values[x][y][z] = Real( fData.valueTables[ idx[0]+
int(_off[0]) ] * fData.valueTables[ idx[1]+
int(_off[1]) ] * fData.valueTables[ idx[2]+
int(_off[2]) ] );
1869 template<
int Degree >
1874 int x , y , z , c = int( node - node->parent->children );
1875 Cube::FactorCornerIndex( c , x , y , z );
1876 if( x==0 ) endX = 4;
1878 if( y==0 ) endY = 4;
1880 if( z==0 ) endZ = 4;
1885 template<
int Degree >
1891 node->depthAndOffset( d , off );
1892 int o = _boundaryType==0 ? (1<<(d-2) ) : 0;
1893 int mn = 4+o , mx = (1<<d)-4-o;
1894 isInterior = ( off[0]>=mn && off[0]<mx && off[1]>=mn && off[1]<mx && off[2]>=mn && off[2]<mx );
1897 int depth = node->depth();
1898 if( depth<=_minDepth )
return;
1900 int startX = 0 , endX = 5 , startY = 0 , endY = 5 , startZ = 0 , endZ = 5;
1901 UpdateCoarserSupportBounds( node , startX , endX , startY , endY , startZ , endZ );
1903 const TreeOctNode::Neighbors5& neighbors5 = neighborKey5.neighbors[depth-1];
1904 for(
int x=startX ; x<endX ; x++ )
for(
int y=startY ; y<endY ; y++ )
for(
int z=startZ ; z<endZ ; z++ )
1905 if( neighbors5.neighbors[x][y][z] && neighbors5.neighbors[x][y][z]->nodeData.nodeIndex>=0 )
1907 const TreeOctNode* _node = neighbors5.neighbors[x][y][z];
1908 Real _solution = metSolution[ _node->nodeData.nodeIndex ];
1910 if( isInterior ) node->nodeData.constraint -= Real( lapStencil.values[x][y][z] * _solution );
1911 else node->nodeData.constraint -= GetLaplacian( _node , node ) * _solution;
1914 if( _constrainValues )
1916 double constraint = 0;
1918 node->depthAndOffset( d, idx );
1922 const TreeOctNode::Neighbors5& neighbors5 = neighborKey5.neighbors[depth];
1923 for(
int x=1 ; x<4 ; x++ )
for(
int y=1 ; y<4 ; y++ )
for(
int z=1 ; z<4 ; z++ )
1924 if( neighbors5.neighbors[x][y][z] && neighbors5.neighbors[x][y][z]->nodeData.pointIndex!=-1 )
1926 const PointData& pData = _points[ neighbors5.neighbors[x][y][z]->nodeData.pointIndex ];
1927 Real pointValue = pData.coarserValue;
1930 fData.baseBSplines[idx[0]][x-1]( p[0] ) *
1931 fData.baseBSplines[idx[1]][y-1]( p[1] ) *
1932 fData.baseBSplines[idx[2]][z-1]( p[2] ) *
1935 node->nodeData.constraint -= Real( constraint );
1942 UpSampleData(
void ) { start = 0 , v[0] = v[1] = 0.; }
1943 UpSampleData(
int s ,
double v1 ,
double v2 ) { start = s , v[0] = v1 , v[1] = v2; }
1945 template<
int Degree >
1948 int start = sNodes.nodeCount[depth] , end = sNodes.nodeCount[depth+1] , range = end-start;
1949 Solution.Resize( range );
1951 if ( _boundaryType==-1 ) cornerValue = 0.50;
1952 else if( _boundaryType== 1 ) cornerValue = 1.00;
1953 else cornerValue = 0.75;
1954 if( (_boundaryType!=0 && depth==0) || (_boundaryType==0 && depth<=2) )
return;
1959 #pragma omp parallel for num_threads( threads )
1961 for(
int t=0 ; t<threads ; t++ )
1963 TreeOctNode::NeighborKey3 neighborKey;
1964 neighborKey.set( depth );
1965 for(
int i=start+(range*t)/threads ; i<start+(range*(t+1))/threads ; i++ )
1968 UpSampleData usData[3];
1969 sNodes.treeNodes[i]->depthAndOffset( d , off );
1970 for(
int dd=0 ; dd<3 ; dd++ )
1972 if ( off[dd] ==0 ) usData[dd] = UpSampleData( 1 , cornerValue , 0.00 );
1973 else if( off[dd]+1==(1<<depth) ) usData[dd] = UpSampleData( 0 , 0.00 , cornerValue );
1974 else if( off[dd]%2 ) usData[dd] = UpSampleData( 1 , 0.75 , 0.25 );
1975 else usData[dd] = UpSampleData( 0 , 0.25 , 0.75 );
1977 neighborKey.getNeighbors( sNodes.treeNodes[i]->parent );
1978 for(
int ii=0 ; ii<2 ; ii++ )
1980 int _ii = ii + usData[0].start;
1981 double dx = usData[0].v[ii];
1982 for(
int jj=0 ; jj<2 ; jj++ )
1984 int _jj = jj + usData[1].start;
1985 double dxy = dx * usData[1].v[jj];
1986 for(
int kk=0 ; kk<2 ; kk++ )
1988 int _kk = kk + usData[2].start;
1989 double dxyz = dxy * usData[2].v[kk];
1990 if( neighborKey.neighbors[depth-1].neighbors[_ii][_jj][_kk] && neighborKey.neighbors[depth-1].neighbors[_ii][_jj][_kk]->nodeData.nodeIndex!=-1 )
1991 Solution[i-start] += Real( neighborKey.neighbors[depth-1].neighbors[_ii][_jj][_kk]->nodeData.solution * dxyz );
1999 start = sNodes.nodeCount[depth-1] , end = sNodes.nodeCount[depth] , range = end-start;
2001 #pragma omp parallel for num_threads( threads )
2003 for(
int i=start ; i<end ; i++ ) sNodes.treeNodes[i]->nodeData.solution = Real( 0. );
2005 template<
int Degree >
2009 if ( _boundaryType==-1 ) cornerValue = 0.50;
2010 else if( _boundaryType== 1 ) cornerValue = 1.00;
2011 else cornerValue = 0.75;
2012 if( !depth )
return;
2014 #pragma omp parallel for num_threads( threads )
2016 for(
int i=sNodes.nodeCount[depth-1] ; i<sNodes.nodeCount[depth] ; i++ )
2017 sNodes.treeNodes[i]->nodeData.constraint = Real( 0 );
2021 sNodes.treeNodes[0]->nodeData.constraint = Real( 0 );
2022 for(
int i=sNodes.nodeCount[depth] ; i<sNodes.nodeCount[depth+1] ; i++ ) sNodes.treeNodes[0]->nodeData.constraint += sNodes.treeNodes[i]->nodeData.constraint;
2025 std::vector< PoissonVector< double > > constraints( threads );
2026 for(
int t=0 ; t<threads ; t++ ) constraints[t].Resize( sNodes.nodeCount[depth] - sNodes.nodeCount[depth-1] ) , constraints[t].SetZero();
2027 int start = sNodes.nodeCount[depth] , end = sNodes.nodeCount[depth+1] , range = end-start;
2028 int lStart = sNodes.nodeCount[depth-1] , lEnd = sNodes.nodeCount[depth];
2031 #pragma omp parallel for num_threads( threads )
2033 for(
int t=0 ; t<threads ; t++ )
2035 TreeOctNode::NeighborKey3 neighborKey;
2036 neighborKey.set( depth );
2037 for(
int i=start+(range*t)/threads ; i<start+(range*(t+1))/threads ; i++ )
2040 UpSampleData usData[3];
2041 sNodes.treeNodes[i]->depthAndOffset( d , off );
2042 for(
int d=0 ; d<3 ; d++ )
2044 if ( off[d] ==0 ) usData[d] = UpSampleData( 1 , cornerValue , 0.00 );
2045 else if( off[d]+1==(1<<depth) ) usData[d] = UpSampleData( 0 , 0.00 , cornerValue );
2046 else if( off[d]%2 ) usData[d] = UpSampleData( 1 , 0.75 , 0.25 );
2047 else usData[d] = UpSampleData( 0 , 0.25 , 0.75 );
2049 neighborKey.getNeighbors( sNodes.treeNodes[i]->parent );
2050 TreeOctNode::Neighbors3& neighbors = neighborKey.neighbors[depth-1];
2051 for(
int ii=0 ; ii<2 ; ii++ )
2053 int _ii = ii + usData[0].start;
2054 double dx = usData[0].v[ii];
2055 for(
int jj=0 ; jj<2 ; jj++ )
2057 int _jj = jj + usData[1].start;
2058 double dxy = dx * usData[1].v[jj];
2059 for(
int kk=0 ; kk<2 ; kk++ )
2061 int _kk = kk + usData[2].start;
2062 double dxyz = dxy * usData[2].v[kk];
2063 if( neighbors.neighbors[_ii][_jj][_kk]->nodeData.nodeIndex!=-1 )
2064 constraints[t][neighbors.neighbors[_ii][_jj][_kk]->nodeData.nodeIndex-lStart] += sNodes.treeNodes[i]->nodeData.constraint * dxyz;
2071 #pragma omp parallel for num_threads( threads )
2073 for(
int i=lStart ; i<lEnd ; i++ )
2075 Real cSum = Real(0.);
2076 for(
int t=0 ; t<threads ; t++ ) cSum += constraints[t][i-lStart];
2077 sNodes.treeNodes[i]->nodeData.constraint += cSum;
2080 template<
int Degree >
2085 if ( _boundaryType==-1 ) cornerValue = 0.50;
2086 else if( _boundaryType== 1 ) cornerValue = 1.00;
2087 else cornerValue = 0.75;
2088 if( depth==0 )
return;
2089 std::vector< PoissonVector< C > > _constraints( threads );
2090 for(
int t=0 ; t<threads ; t++ ) _constraints[t].Resize( sNodes.nodeCount[depth] - sNodes.nodeCount[depth-1] );
2091 int start = sNodes.nodeCount[depth] , end = sNodes.nodeCount[depth+1] , range = end-start , lStart = sNodes.nodeCount[depth-1] , lEnd = sNodes.nodeCount[depth];
2094 #pragma omp parallel for num_threads( threads )
2096 for(
int t=0 ; t<threads ; t++ )
2098 TreeOctNode::NeighborKey3 neighborKey;
2099 neighborKey.set( depth );
2100 for(
int i=start+(range*t)/threads ; i<start+(range*(t+1))/threads ; i++ )
2103 UpSampleData usData[3];
2104 sNodes.treeNodes[i]->depthAndOffset( d , off );
2105 for(
int d=0 ; d<3 ; d++ )
2107 if ( off[d] ==0 ) usData[d] = UpSampleData( 1 , cornerValue , 0.00 );
2108 else if( off[d]+1==(1<<depth) ) usData[d] = UpSampleData( 0 , 0.00 , cornerValue );
2109 else if( off[d]%2 ) usData[d] = UpSampleData( 1 , 0.75 , 0.25 );
2110 else usData[d] = UpSampleData( 0 , 0.25 , 0.75 );
2112 TreeOctNode::Neighbors3& neighbors = neighborKey.getNeighbors( sNodes.treeNodes[i]->parent );
2113 C c = constraints[i];
2114 for(
int ii=0 ; ii<2 ; ii++ )
2116 int _ii = ii + usData[0].start;
2117 C cx = C( c*usData[0].v[ii] );
2118 for(
int jj=0 ; jj<2 ; jj++ )
2120 int _jj = jj + usData[1].start;
2121 C cxy = C( cx*usData[1].v[jj] );
2122 for(
int kk=0 ; kk<2 ; kk++ )
2124 int _kk = kk + usData[2].start;
2125 TreeOctNode* node = neighbors.neighbors[_ii][_jj][_kk];
2126 if( node && node->nodeData.nodeIndex!=-1 )
2127 _constraints[t][node->nodeData.nodeIndex-lStart] += C( cxy*usData[2].v[kk] );
2134 #pragma omp parallel for num_threads( threads )
2136 for(
int i=lStart ; i<lEnd ; i++ )
2139 for(
int t=0 ; t<threads ; t++ ) cSum += _constraints[t][i-lStart];
2140 constraints[i] += cSum;
2143 template<
int Degree >
2148 if ( _boundaryType==-1 ) cornerValue = 0.50;
2149 else if( _boundaryType== 1 ) cornerValue = 1.00;
2150 else cornerValue = 0.75;
2151 if ( (_boundaryType!=0 && depth==0) || (_boundaryType==0 && depth<=2) )
return;
2153 int start = sNodes.nodeCount[depth] , end = sNodes.nodeCount[depth+1] , range = end-start;
2156 #pragma omp parallel for num_threads( threads )
2158 for(
int t=0 ; t<threads ; t++ )
2160 TreeOctNode::NeighborKey3 neighborKey;
2161 neighborKey.set( depth-1 );
2162 for(
int i=start+(range*t)/threads ; i<start+(range*(t+1))/threads ; i++ )
2164 bool isInterior =
true;
2167 UpSampleData usData[3];
2168 node->depthAndOffset( d , off );
2169 for(
int d=0 ; d<3 ; d++ )
2171 if ( off[d] ==0 ) usData[d] = UpSampleData( 1 , cornerValue , 0.00 ) , isInterior =
false;
2172 else if( off[d]+1==(1<<depth) ) usData[d] = UpSampleData( 0 , 0.00 , cornerValue ) , isInterior =
false;
2173 else if( off[d]%2 ) usData[d] = UpSampleData( 1 , 0.75 , 0.25 );
2174 else usData[d] = UpSampleData( 0 , 0.25 , 0.75 );
2176 TreeOctNode::Neighbors3& neighbors = neighborKey.getNeighbors( node->parent );
2177 for(
int ii=0 ; ii<2 ; ii++ )
2179 int _ii = ii + usData[0].start;
2180 double dx = usData[0].v[ii];
2181 for(
int jj=0 ; jj<2 ; jj++ )
2183 int _jj = jj + usData[1].start;
2184 double dxy = dx * usData[1].v[jj];
2185 for(
int kk=0 ; kk<2 ; kk++ )
2187 int _kk = kk + usData[2].start;
2188 TreeOctNode* node = neighbors.neighbors[_ii][_jj][_kk];
2189 if( node && node->nodeData.nodeIndex!=-1 )
2191 double dxyz = dxy * usData[2].v[kk];
2192 int _i = node->nodeData.nodeIndex;
2193 coefficients[i] += coefficients[_i] * Real( dxyz );
2201 template<
int Degree >
2204 int start = sNodes.nodeCount[depth] , end = sNodes.nodeCount[depth+1] , range = end-start;
2207 #pragma omp parallel for num_threads( threads )
2209 for(
int t=0 ; t<threads ; t++ )
2211 TreeOctNode::NeighborKey3 neighborKey;
2212 neighborKey.set( depth );
2213 for(
int i=start+(range*t)/threads ; i<start+(range*(t+1))/threads ; i++ )
2215 int pIdx = sNodes.treeNodes[i]->nodeData.pointIndex;
2218 neighborKey.getNeighbors( sNodes.treeNodes[i] );
2219 _points[ pIdx ].coarserValue = WeightedCoarserFunctionValue( neighborKey , sNodes.treeNodes[i] , metSolution );
2224 template<
int Degree >
2227 double pointValue = 0;
2228 int depth = pointNode->depth();
2229 if( _boundaryType==-1 && depth==0 && pointNode->nodeData.pointIndex!=-1 )
return Real(-0.5) * _points[ pointNode->nodeData.pointIndex ].weight;
2231 if( (_boundaryType!=0 && depth==0) || (_boundaryType==0 && depth<=2) || pointNode->nodeData.pointIndex==-1 )
return Real(0.);
2233 Real weight = _points[ pointNode->nodeData.pointIndex ].weight;
2234 Point3D< Real > p = _points[ pointNode->nodeData.pointIndex ].position;
2239 const TreeOctNode::Neighbors3& neighbors = neighborKey.neighbors[depth-1];
2240 neighbors.neighbors[1][1][1]->depthAndOffset( d , _idx );
2245 for(
int j=0 ; j<3 ; j++ )
2247 #if ROBERTO_TOLDO_FIX
2249 if( _idx[0]+j>=0 && _idx[0]+j<((1<<depth)-1) ) xValue = fData.baseBSplines[ _idx[0]+j ][2-j]( p[0] );
2251 #else // !ROBERTO_TOLDO_FIX
2252 double xValue = fData.baseBSplines[ _idx[0]+j ][2-j]( p[0] );
2253 #endif // ROBERTO_TOLDO_FIX
2254 for(
int k=0 ; k<3 ; k++ )
2256 #if ROBERTO_TOLDO_FIX
2258 if( _idx[1]+k>=0 && _idx[1]+k<((1<<depth)-1) ) xyValue = xValue * fData.baseBSplines[ _idx[1]+k ][2-k]( p[1] );
2260 #else // !ROBERTO_TOLDO_FIX
2261 double xyValue = xValue * fData.baseBSplines[ _idx[1]+k ][2-k]( p[1] );
2262 #endif // ROBERTO_TOLDO_FIX
2263 double _pointValue = 0;
2264 for(
int l=0 ; l<3 ; l++ )
2266 const TreeOctNode* basisNode = neighbors.neighbors[j][k][l];
2267 #if ROBERTO_TOLDO_FIX
2268 if( basisNode && basisNode->nodeData.nodeIndex>=0 && _idx[2]+l>=0 && _idx[2]+l<((1<<depth)-1) )
2269 _pointValue += fData.baseBSplines[ _idx[2]+l ][2-l]( p[2] ) *
double( metSolution[basisNode->nodeData.nodeIndex] );
2270 #else // !ROBERTO_TOLDO_FIX
2271 if( basisNode && basisNode->nodeData.nodeIndex>=0 )
2272 _pointValue += fData.baseBSplines[ _idx[2]+l ][2-l]( p[2] ) *
double( metSolution[basisNode->nodeData.nodeIndex] );
2273 #endif // ROBERTO_TOLDO_FIX
2275 pointValue += _pointValue * xyValue;
2279 if( _boundaryType==-1 ) pointValue -= Real(0.5);
2280 return Real( pointValue * weight );
2282 template<
int Degree >
2285 int start = sNodes.nodeCount[depth] , end = sNodes.nodeCount[depth+1] , range = end-start;
2286 double stencil[5][5][5];
2287 SetLaplacianStencil( depth , stencil );
2288 Stencil< double , 5 > stencils[2][2][2];
2289 SetLaplacianStencils( depth , stencils );
2290 matrix.Resize( range );
2292 #pragma omp parallel for num_threads( threads )
2294 for(
int t=0 ; t<threads ; t++ )
2296 TreeOctNode::NeighborKey5 neighborKey5;
2297 neighborKey5.set( depth );
2298 for(
int i=(range*t)/threads ; i<(range*(t+1))/threads ; i++ )
2301 neighborKey5.getNeighbors( node );
2303 bool insetSupported = _boundaryType!=0 || _IsInsetSupported( node );
2304 int count = insetSupported ? GetMatrixRowSize( neighborKey5.neighbors[depth] ) : 1;
2308 #pragma omp critical (matrix_set_row_size)
2311 matrix.SetRowSize( i , count );
2315 if( insetSupported ) matrix.rowSizes[i] = SetMatrixRow( neighborKey5.neighbors[depth] , matrix[i] , start , stencil );
2319 matrix.rowSizes[i] = 1;
2326 int c = int( node - node->parent->children );
2327 Cube::FactorCornerIndex( c , x , y , z );
2330 if( insetSupported ) UpdateConstraintsFromCoarser( neighborKey5 , node , metSolution , stencils[x][y][z] );
2335 template<
int Degree>
2340 for(
int i=0 ; i<entryCount ; i++ ) sNodes.treeNodes[ entries[i] ]->nodeData.nodeIndex = i;
2341 double stencil[5][5][5];
2342 int rDepth , rOff[3];
2343 rNode->depthAndOffset( rDepth , rOff );
2344 matrix.Resize( entryCount );
2345 SetLaplacianStencil( depth , stencil );
2346 Stencil< double , 5 > stencils[2][2][2];
2347 SetLaplacianStencils( depth , stencils );
2349 #pragma omp parallel for num_threads( threads )
2351 for(
int t=0 ; t<threads ; t++ )
2353 TreeOctNode::NeighborKey5 neighborKey5;
2354 neighborKey5.set( depth );
2355 for(
int i=(entryCount*t)/threads ; i<(entryCount*(t+1))/threads ; i++ )
2357 TreeOctNode* node = sNodes.treeNodes[ entries[i] ];
2359 node->depthAndOffset( d , off );
2360 off[0] >>= (depth-rDepth) , off[1] >>= (depth-rDepth) , off[2] >>= (depth-rDepth);
2361 bool isInterior = ( off[0]==rOff[0] && off[1]==rOff[1] && off[2]==rOff[2] );
2363 neighborKey5.getNeighbors( node );
2365 int xStart=0 , xEnd=5 , yStart=0 , yEnd=5 , zStart=0 , zEnd=5;
2366 if( !isInterior ) SetMatrixRowBounds( neighborKey5.neighbors[depth].neighbors[2][2][2] , rDepth , rOff , xStart , xEnd , yStart , yEnd , zStart , zEnd );
2369 bool insetSupported = _boundaryType!=0 || _IsInsetSupported( node );
2370 int count = insetSupported ? GetMatrixRowSize( neighborKey5.neighbors[depth] , xStart , xEnd , yStart , yEnd , zStart , zEnd ) : 1;
2374 #pragma omp critical (matrix_set_row_size)
2377 matrix.SetRowSize( i , count );
2381 if( insetSupported ) matrix.rowSizes[i] = SetMatrixRow( neighborKey5.neighbors[depth] , matrix[i] , 0 , stencil , xStart , xEnd , yStart , yEnd , zStart , zEnd );
2385 matrix.rowSizes[i] = 1;
2392 int c = int( node - node->parent->children );
2393 Cube::FactorCornerIndex( c , x , y , z );
2396 if( insetSupported ) UpdateConstraintsFromCoarser( neighborKey5 , node , metSolution , stencils[x][y][z] );
2399 for(
int i=0 ; i<entryCount ; i++ ) sNodes.treeNodes[entries[i]]->nodeData.nodeIndex = entries[i];
2403 template<
int Degree>
2407 fData.setDotTables( fData.DD_DOT_FLAG | fData.DV_DOT_FLAG , _boundaryType==0 );
2408 if( _boundaryType==0 ) subdivideDepth++ , maxSolveDepth++;
2410 _sNodes.treeNodes[0]->nodeData.solution = 0;
2412 std::vector< Real > metSolution( _sNodes.nodeCount[ _sNodes.maxDepth ] , 0 );
2413 for(
int d=(_boundaryType==0?2:0) ; d<_sNodes.maxDepth ; d++ )
2415 DumpOutput(
"Depth[%d/%d]: %d\n" , _boundaryType==0 ? d-1 : d , _boundaryType==0 ? _sNodes.maxDepth-2 : _sNodes.maxDepth-1 , _sNodes.nodeCount[d+1]-_sNodes.nodeCount[d] );
2416 if( subdivideDepth>0 ) iter += _SolveFixedDepthMatrix( d , _sNodes , &metSolution[0] , subdivideDepth , showResidual , minIters , accuracy , d>maxSolveDepth , fixedIters );
2417 else iter += _SolveFixedDepthMatrix( d , _sNodes , &metSolution[0] , showResidual , minIters , accuracy , d>maxSolveDepth , fixedIters );
2419 fData.clearDotTables( fData.VV_DOT_FLAG | fData.DV_DOT_FLAG | fData.DD_DOT_FLAG );
2424 template<
int Degree>
2427 double _maxMemoryUsage = maxMemoryUsage;
2432 double systemTime=0. , solveTime=0. , evaluateTime = 0.;
2433 X.Resize( sNodes.nodeCount[depth+1]-sNodes.nodeCount[depth] );
2434 if( depth<=_minDepth ) UpSampleCoarserSolution( depth , sNodes , X );
2438 UpSample( depth-1 , sNodes , metSolution );
2442 #pragma omp parallel for num_threads( threads )
2444 for(
int i=_sNodes.nodeCount[depth-1] ; i<_sNodes.nodeCount[depth] ; i++ ) metSolution[i] += _sNodes.treeNodes[i]->nodeData.solution;
2446 if( _constrainValues )
2448 evaluateTime = Time();
2449 SetCoarserPointValues( depth , sNodes , metSolution );
2450 evaluateTime = Time() - evaluateTime;
2453 systemTime = Time();
2456 GetFixedDepthLaplacian( M , depth , sNodes , metSolution );
2458 B.Resize( sNodes.nodeCount[depth+1]-sNodes.nodeCount[depth] );
2459 for(
int i=sNodes.nodeCount[depth] ; i<sNodes.nodeCount[depth+1] ; i++ )
2460 if( _boundaryType!=0 || _IsInsetSupported( sNodes.treeNodes[i] ) ) B[i-sNodes.nodeCount[depth]] = sNodes.treeNodes[i]->nodeData.constraint;
2461 else B[i-sNodes.nodeCount[depth]] = Real(0);
2463 systemTime = Time()-systemTime;
2468 Real _accuracy = Real( accuracy / 100000 ) * M.rows;
2472 mrVector.resize( threads , M.rows );
2474 if( _boundaryType==0 && depth>3 ) res -= 1<<(depth-2);
2477 if( fixedIters>=0 ) iter +=
SparseSymmetricMatrix< Real >::Solve( M , B , fixedIters , X , mrVector , Real(1e-10) , 0 , M.rows==res*res*res && !_constrainValues && _boundaryType!=-1 );
2478 else iter +=
SparseSymmetricMatrix< Real >::Solve( M , B , std::max< int >(
int( pow( M.rows , ITERATION_POWER ) ) , minIters ) , X , mrVector ,_accuracy , 0 , M.rows==res*res*res && !_constrainValues && _boundaryType!=-1 );
2480 solveTime = Time()-solveTime;
2484 for(
int i=0 ; i<M.rows ; i++ )
for(
int j=0 ; j<M.rowSizes[i] ; j++ ) mNorm += M[i][j].Value * M[i][j].Value;
2485 double bNorm = B.Norm( 2 ) , rNorm = ( B - M * X ).Norm( 2 );
2486 DumpOutput(
"\tResidual: (%d %g) %g -> %g (%f) [%d]\n" , M.Entries() , sqrt(mNorm) , bNorm , rNorm , rNorm/bNorm , iter );
2490 for(
int i=sNodes.nodeCount[depth] ; i<sNodes.nodeCount[depth+1] ; i++ ) sNodes.treeNodes[i]->nodeData.solution = Real( X[i-sNodes.nodeCount[depth]] );
2493 DumpOutput(
"\tEvaluated / Got / Solved in: %6.3f / %6.3f / %6.3f\t(%.3f MB)\n" , evaluateTime , systemTime , solveTime ,
float( maxMemoryUsage ) );
2494 maxMemoryUsage = std::max< double >( maxMemoryUsage , _maxMemoryUsage );
2497 template<
int Degree>
2500 double _maxMemoryUsage = maxMemoryUsage;
2501 if( startingDepth>=depth )
return _SolveFixedDepthMatrix( depth , sNodes , metSolution , showResidual , minIters , accuracy , noSolve , fixedIters );
2502 int i , j , d , tIter=0;
2505 AdjacencySetFunction asf;
2506 AdjacencyCountFunction acf;
2507 double systemTime = 0 , solveTime = 0 , memUsage = 0 , evaluateTime = 0 , gTime , sTime;
2510 if( depth>_minDepth )
2513 UpSample( depth-1 , sNodes , metSolution );
2517 #pragma omp parallel for num_threads( threads )
2519 for(
int i=_sNodes.nodeCount[depth-1] ; i<_sNodes.nodeCount[depth] ; i++ ) metSolution[i] += _sNodes.treeNodes[i]->nodeData.solution;
2522 if( _constrainValues )
2524 evaluateTime = Time();
2525 SetCoarserPointValues( depth , sNodes , metSolution );
2526 evaluateTime = Time() - evaluateTime;
2528 B.Resize( sNodes.nodeCount[depth+1] - sNodes.nodeCount[depth] );
2531 for( i=sNodes.nodeCount[depth] ; i<sNodes.nodeCount[depth+1] ; i++ )
2533 if( _boundaryType!=0 || _IsInsetSupported( sNodes.treeNodes[i] ) ) B[i-sNodes.nodeCount[depth]] = sNodes.treeNodes[i]->nodeData.constraint;
2534 else B[i-sNodes.nodeCount[depth]] = Real(0);
2535 sNodes.treeNodes[i]->nodeData.constraint = 0;
2538 myRadius = 2*radius-Real(0.5);
2539 myRadius = int(myRadius-ROUND_EPS)+ROUND_EPS;
2540 d = depth-startingDepth;
2541 if( _boundaryType==0 ) d++;
2542 std::vector< int > subDimension( sNodes.nodeCount[d+1]-sNodes.nodeCount[d] );
2543 int maxDimension = 0;
2544 for( i=sNodes.nodeCount[d] ; i<sNodes.nodeCount[d+1] ; i++ )
2547 acf.adjacencyCount = 0;
2548 for(
TreeOctNode* temp=sNodes.treeNodes[i]->nextNode() ; temp ; )
2550 if( temp->depth()==depth ) acf.adjacencyCount++ , temp = sNodes.treeNodes[i]->nextBranch( temp );
2551 else temp = sNodes.treeNodes[i]->nextNode ( temp );
2553 for( j=sNodes.nodeCount[d] ; j<sNodes.nodeCount[d+1] ; j++ )
2555 if( i==j )
continue;
2556 TreeOctNode::ProcessFixedDepthNodeAdjacentNodes( fData.depth , sNodes.treeNodes[i] , 1 , sNodes.treeNodes[j] , 2*width-1 , depth , &acf );
2558 subDimension[i-sNodes.nodeCount[d]] = acf.adjacencyCount;
2559 maxDimension = std::max< int >( maxDimension , subDimension[i-sNodes.nodeCount[d]] );
2561 asf.adjacencies =
new int[maxDimension];
2563 mrVector.resize( threads , maxDimension );
2565 for( i=sNodes.nodeCount[d] ; i<sNodes.nodeCount[d+1] ; i++ )
2570 acf.adjacencyCount = subDimension[i-sNodes.nodeCount[d]];
2571 if( !acf.adjacencyCount )
continue;
2574 asf.adjacencyCount = 0;
2575 for(
TreeOctNode* temp=sNodes.treeNodes[i]->nextNode() ; temp ; )
2577 if( temp->depth()==depth && temp->nodeData.nodeIndex!=-1 ) asf.adjacencies[ asf.adjacencyCount++ ] = temp->nodeData.nodeIndex , temp = sNodes.treeNodes[i]->nextBranch( temp );
2578 else temp = sNodes.treeNodes[i]->nextNode ( temp );
2580 for( j=sNodes.nodeCount[d] ; j<sNodes.nodeCount[d+1] ; j++ )
2582 if( i==j )
continue;
2583 TreeOctNode::ProcessFixedDepthNodeAdjacentNodes( fData.depth , sNodes.treeNodes[i] , 1 , sNodes.treeNodes[j] , 2*width-1 , depth , &asf );
2587 _B.Resize( asf.adjacencyCount );
2588 for( j=0 ; j<asf.adjacencyCount ; j++ ) _B[j] = B[ asf.adjacencies[j]-sNodes.nodeCount[depth] ];
2590 _X.Resize( asf.adjacencyCount );
2592 #pragma omp parallel for num_threads( threads ) schedule( static )
2594 for( j=0 ; j<asf.adjacencyCount ; j++ ) _X[j] = sNodes.treeNodes[ asf.adjacencies[j] ]->nodeData.solution;
2596 GetRestrictedFixedDepthLaplacian( _M , depth , asf.adjacencies , asf.adjacencyCount , sNodes.treeNodes[i] , myRadius , sNodes , metSolution );
2598 #pragma omp parallel for num_threads( threads ) schedule( static )
2600 for( j=0 ; j<asf.adjacencyCount ; j++ )
2602 _B[j] += sNodes.treeNodes[asf.adjacencies[j]]->nodeData.constraint;
2603 sNodes.treeNodes[ asf.adjacencies[j] ]->nodeData.constraint = 0;
2605 gTime = Time()-gTime;
2610 Real _accuracy = Real( accuracy / 100000 ) * _M.rows;
2621 for(
int i=0 ; i<_M.rows ; i++ )
for(
int j=0 ; j<_M.rowSizes[i] ; j++ ) mNorm += _M[i][j].Value * _M[i][j].Value;
2622 double bNorm = _B.Norm( 2 ) , rNorm = ( _B - _M * _X ).Norm( 2 );
2623 DumpOutput(
"\t\tResidual: (%d %g) %g -> %g (%f) [%d]\n" , _M.Entries() , sqrt(mNorm) , bNorm , rNorm , rNorm/bNorm , iter );
2628 #pragma omp parallel for num_threads( threads )
2630 for( j=0 ; j<asf.adjacencyCount ; j++ )
2632 TreeOctNode* temp=sNodes.treeNodes[ asf.adjacencies[j] ];
2633 while( temp->depth()>sNodes.treeNodes[i]->depth() ) temp=temp->parent;
2634 if( temp->nodeData.nodeIndex>=sNodes.treeNodes[i]->nodeData.nodeIndex ) sNodes.treeNodes[ asf.adjacencies[j] ]->nodeData.solution = Real( _X[j] );
2636 systemTime += gTime;
2638 memUsage = std::max< double >( MemoryUsage() , memUsage );
2641 delete[] asf.adjacencies;
2643 DumpOutput(
"\tEvaluated / Got / Solved in: %6.3f / %6.3f / %6.3f\t(%.3f MB)\n" , evaluateTime , systemTime , solveTime ,
float( maxMemoryUsage ) );
2644 maxMemoryUsage = std::max< double >( maxMemoryUsage , _maxMemoryUsage );
2647 template<
int Degree>
2651 if( node->nodeData.normalIndex>=0 && ( (*normals)[node->nodeData.normalIndex][0]!=0 || (*normals)[node->nodeData.normalIndex][1]!=0 || (*normals)[node->nodeData.normalIndex][2]!=0 ) ) hasNormals=1;
2652 if( node->children )
for(
unsigned int i=0;i<Cube::CORNERS && !hasNormals;i++) hasNormals |= HasNormals(&node->children[i],epsilon);
2656 template<
int Degree>
2659 int maxDepth = tree.maxDepth();
2660 for(
TreeOctNode* temp=tree.nextNode() ; temp ; temp=tree.nextNode(temp) )
2661 if( temp->children && temp->d>=_minDepth )
2664 for(
unsigned int i=0 ; i<Cube::CORNERS && !hasNormals ; i++ ) hasNormals = HasNormals( &temp->children[i] , EPSILON/(1<<maxDepth) );
2665 if( !hasNormals ) temp->children=NULL;
2669 template<
int Degree>
2677 fData.setDotTables( fData.VV_DOT_FLAG | fData.DV_DOT_FLAG , _boundaryType==0 );
2678 int maxDepth = _sNodes.maxDepth-1;
2680 zeroPoint[0] = zeroPoint[1] = zeroPoint[2] = 0;
2681 std::vector< Real > constraints( _sNodes.nodeCount[maxDepth] , Real(0) );
2685 #pragma omp parallel for num_threads( threads )
2687 for(
int i=0 ; i<_sNodes.nodeCount[maxDepth+1] ; i++ ) _sNodes.treeNodes[i]->nodeData.constraint = Real( 0. );
2689 for(
int d=maxDepth ; d>=(_boundaryType==0?2:0) ; d-- )
2692 int sz = d>0 ? _sNodes.nodeCount[d] - _sNodes.nodeCount[d-1] : _sNodes.nodeCount[d] - 0;
2693 int offset = d>0 ? _sNodes.treeNodes[ _sNodes.nodeCount[d-1] ]->nodeData.nodeIndex : 0;
2694 std::vector< std::vector< Real > > _constraints( threads );
2695 for(
int t=0 ; t<threads ; t++ ) _constraints[t].resize( sz , 0 );
2697 SetDivergenceStencil( d , stencil ,
false );
2698 Stencil< Point3D< double > , 5 > stencils[2][2][2];
2699 SetDivergenceStencils( d , stencils ,
true );
2701 #pragma omp parallel for num_threads( threads )
2703 for(
int t=0 ; t<threads ; t++ )
2705 TreeOctNode::NeighborKey5 neighborKey5;
2706 neighborKey5.set( fData.depth );
2707 int start = _sNodes.nodeCount[d] , end = _sNodes.nodeCount[d+1] , range = end-start;
2708 for(
int i=start+(range*t)/threads ; i<start+(range*(t+1))/threads ; i++ )
2711 int startX=0 , endX=5 , startY=0 , endY=5 , startZ=0 , endZ=5;
2712 int depth = node->depth();
2713 neighborKey5.getNeighbors( node );
2715 bool isInterior , isInterior2;
2718 node->depthAndOffset( d , off );
2719 int o = _boundaryType==0 ? (1<<(d-2)) : 0;
2720 int mn = 2+o , mx = (1<<d)-2-o;
2721 isInterior = ( off[0]>=mn && off[0]<mx && off[1]>=mn && off[1]<mx && off[2]>=mn && off[2]<mx );
2723 isInterior2 = ( off[0]>=mn && off[0]<mx && off[1]>=mn && off[1]<mx && off[2]>=mn && off[2]<mx );
2728 int c = int( node - node->parent->children );
2729 Cube::FactorCornerIndex( c , cx , cy , cz );
2731 else cx = cy = cz = 0;
2732 Stencil< Point3D< double > , 5 >& _stencil = stencils[cx][cy][cz];
2736 const TreeOctNode::Neighbors5& neighbors5 = neighborKey5.neighbors[depth];
2739 for(
int x=startX ; x<endX ; x++ )
for(
int y=startY ; y<endY ; y++ )
for(
int z=startZ ; z<endZ ; z++ )
2741 const TreeOctNode* _node = neighbors5.neighbors[x][y][z];
2742 if( _node && _node->nodeData.normalIndex>=0 )
2744 const Point3D< Real >& _normal = (*normals)[_node->nodeData.normalIndex];
2745 node->nodeData.constraint += Real( stencil[x][y][z][0] * _normal[0] + stencil[x][y][z][1] * _normal[1] + stencil[x][y][z][2] * _normal[2] );
2749 for(
int x=startX ; x<endX ; x++ )
for(
int y=startY ; y<endY ; y++ )
for(
int z=startZ ; z<endZ ; z++ )
2751 const TreeOctNode* _node = neighbors5.neighbors[x][y][z];
2752 if( _node && _node->nodeData.normalIndex>=0 )
2754 const Point3D< Real >& _normal = (*normals)[_node->nodeData.normalIndex];
2755 node->nodeData.constraint += GetDivergence( _node , node , _normal );
2758 UpdateCoarserSupportBounds( neighbors5.neighbors[2][2][2] , startX , endX , startY , endY , startZ , endZ );
2760 if( node->nodeData.nodeIndex<0 || node->nodeData.normalIndex<0 )
continue;
2761 const Point3D< Real >& normal = (*normals)[node->nodeData.normalIndex];
2762 if( normal[0]==0 && normal[1]==0 && normal[2]==0 )
continue;
2766 const TreeOctNode::Neighbors5& neighbors5 = neighborKey5.neighbors[depth-1];
2768 for(
int x=startX ; x<endX ; x++ )
for(
int y=startY ; y<endY ; y++ )
for(
int z=startZ ; z<endZ ; z++ )
2769 if( neighbors5.neighbors[x][y][z] && neighbors5.neighbors[x][y][z]->nodeData.nodeIndex!=-1 )
2771 TreeOctNode* _node = neighbors5.neighbors[x][y][z];
2775 _constraints[t][ _node->nodeData.nodeIndex-offset ] += Real( div[0] * normal[0] + div[1] * normal[1] + div[2] * normal[2] );
2777 else _constraints[t][ _node->nodeData.nodeIndex-offset ] += GetDivergence( node , _node , normal );
2783 #pragma omp parallel for num_threads( threads ) schedule( static )
2785 for(
int i=0 ; i<sz ; i++ )
2787 Real cSum = Real(0.);
2788 for(
int t=0 ; t<threads ; t++ ) cSum += _constraints[t][i];
2789 constraints[i+offset] = cSum;
2793 std::vector< Point3D< Real > > coefficients( _sNodes.nodeCount[maxDepth] , zeroPoint );
2794 for(
int d=maxDepth-1 ; d>=0 ; d-- )
2797 #pragma omp parallel for num_threads( threads )
2799 for(
int t=0 ; t<threads ; t++ )
2801 int start = _sNodes.nodeCount[d] , end = _sNodes.nodeCount[d+1] , range = end-start;
2802 for(
int i=start+(range*t)/threads ; i<start+(range*(t+1))/threads ; i++ )
2805 if( node->nodeData.nodeIndex<0 || node->nodeData.normalIndex<0 )
continue;
2806 const Point3D< Real >& normal = (*normals)[node->nodeData.normalIndex];
2807 if( normal[0]==0 && normal[1]==0 && normal[2]==0 )
continue;
2808 coefficients[i] += normal;
2814 for(
int d=maxDepth-1 ; d>=(_boundaryType==0?2:0) ; d-- ) DownSample( d , _sNodes , &constraints[0] );
2817 for(
int d=(_boundaryType==0?2:0) ; d<maxDepth ; d++ ) UpSample( d , _sNodes , &coefficients[0] );
2821 #pragma omp parallel for num_threads( threads )
2823 for(
int i=0 ; i<_sNodes.nodeCount[maxDepth] ; i++ ) _sNodes.treeNodes[i]->nodeData.constraint += constraints[i];
2826 for(
int d=0 ; d<=maxDepth ; d++ )
2828 int start = _sNodes.nodeCount[d] , end = _sNodes.nodeCount[d+1] , range = end - start;
2829 Stencil< Point3D< double > , 5 > stencils[2][2][2];
2830 SetDivergenceStencils( d , stencils ,
false );
2832 #pragma omp parallel for num_threads( threads )
2834 for(
int t=0 ; t<threads ; t++ )
2836 TreeOctNode::NeighborKey5 neighborKey5;
2837 neighborKey5.set( maxDepth );
2838 for(
int i=start+(range*t)/threads ; i<start+(range*(t+1))/threads ; i++ )
2841 int depth = node->depth();
2842 if( !depth )
continue;
2843 int startX=0 , endX=5 , startY=0 , endY=5 , startZ=0 , endZ=5;
2844 UpdateCoarserSupportBounds( node , startX , endX , startY , endY , startZ , endZ );
2845 const TreeOctNode::Neighbors5& neighbors5 = neighborKey5.getNeighbors( node->parent );
2850 node->depthAndOffset( d , off );
2851 int o = _boundaryType==0 ? (1<<(d-2)) : 0;
2852 int mn = 4+o , mx = (1<<d)-4-o;
2853 isInterior = ( off[0]>=mn && off[0]<mx && off[1]>=mn && off[1]<mx && off[2]>=mn && off[2]<mx );
2858 int c = int( node - node->parent->children );
2859 Cube::FactorCornerIndex( c , cx , cy , cz );
2861 else cx = cy = cz = 0;
2862 Stencil< Point3D< double > , 5 >& _stencil = stencils[cx][cy][cz];
2864 Real constraint = Real(0);
2865 for(
int x=startX ; x<endX ; x++ )
for(
int y=startY ; y<endY ; y++ )
for(
int z=startZ ; z<endZ ; z++ )
2866 if( neighbors5.neighbors[x][y][z] && neighbors5.neighbors[x][y][z]->nodeData.nodeIndex!=-1 )
2868 TreeOctNode* _node = neighbors5.neighbors[x][y][z];
2869 int _i = _node->nodeData.nodeIndex;
2874 constraint += Real( div[0] * normal[0] + div[1] * normal[1] + div[2] * normal[2] );
2876 else constraint += GetDivergence( _node , node , coefficients[_i] );
2878 node->nodeData.constraint += constraint;
2883 fData.clearDotTables( fData.DV_DOT_FLAG );
2887 #pragma omp parallel for num_threads( threads )
2889 for(
int t=0 ; t<threads ; t++ )
2890 for(
int i=(_sNodes.nodeCount[maxDepth+1]*t)/threads ; i<(_sNodes.nodeCount[maxDepth+1]*(t+1))/threads ; i++ )
2893 if( temp->nodeData.nodeIndex<0 || temp->nodeData.normalIndex<0 ) temp->nodeData.centerWeightContribution = 0;
2894 else temp->nodeData.centerWeightContribution = Real( Length((*normals)[temp->nodeData.normalIndex]) );
2900 template<
int Degree>
2902 template<
int Degree>
2904 template<
int Degree>
2907 if( !node1->children && node1->depth()<depth ) node1->initChildren();
2909 template<
int Degree >
2912 if( !node1->children && MarchingCubes::HasRoots( node1->nodeData.mcIndex ) )
2915 hash_map< long long , std::pair< RootInfo , int > >::iterator iter;
2916 int isoTri[DIMENSION*MarchingCubes::MAX_TRIANGLES];
2917 int count=MarchingCubes::AddTriangleIndices( node1->nodeData.mcIndex , isoTri );
2919 for(
int j=0 ; j<count ; j++ )
2920 for(
int k=0 ; k<3 ; k++ )
2921 if( fIndex==Cube::FaceAdjacentToEdges( isoTri[j*3+k] , isoTri[j*3+((k+1)%3)] ) )
2923 if( GetRootIndex( node1 , isoTri[j*3+k] , maxDepth , ri1 ) && GetRootIndex( node1 , isoTri[j*3+((k+1)%3)] , maxDepth , ri2 ) )
2925 long long key1=ri1.key , key2=ri2.key;
2926 edges->push_back( std::pair< RootInfo , RootInfo >( ri2 , ri1 ) );
2927 iter = vertexCount->find( key1 );
2928 if( iter==vertexCount->end() )
2930 (*vertexCount)[key1].first = ri1;
2931 (*vertexCount)[key1].second=0;
2933 iter=vertexCount->find(key2);
2934 if( iter==vertexCount->end() )
2936 (*vertexCount)[key2].first = ri2;
2937 (*vertexCount)[key2].second=0;
2939 (*vertexCount)[key1].second--;
2940 (*vertexCount)[key2].second++;
2943 std::cerr <<
"Bad Edge 1:" << ri1.key <<
" " << ri2.key << std::endl;
2948 template<
int Degree >
2958 bool flags[3][3][3];
2959 int maxDepth = tree.maxDepth();
2961 subdivideDepth = std::max< int >( subdivideDepth , 0 );
2962 if( _boundaryType==0 ) subdivideDepth += 2;
2963 subdivideDepth = std::min< int >( subdivideDepth , maxDepth );
2964 int sDepth = maxDepth - subdivideDepth;
2965 if( _boundaryType==0 ) sDepth = std::max< int >( 2 , sDepth );
2968 _sNodes.set( tree );
2974 TreeOctNode::NeighborKey3 nKey;
2975 nKey.set( maxDepth );
2976 for(
TreeOctNode* leaf=tree.nextLeaf() ; leaf ; leaf=tree.nextLeaf( leaf ) )
2977 if( leaf->depth()>sDepth )
2979 int d , off[3] , _off[3];
2980 leaf->depthAndOffset( d , off );
2981 int res = (1<<d)-1 , _res = ( 1<<(d-sDepth) )-1;
2982 _off[0] = off[0]&_res , _off[1] = off[1]&_res , _off[2] = off[2]&_res;
2983 bool boundary[3][2] =
2985 { (off[0]!=0 && _off[0]==0) , (off[0]!=res && _off[0]==_res) } ,
2986 { (off[1]!=0 && _off[1]==0) , (off[1]!=res && _off[1]==_res) } ,
2987 { (off[2]!=0 && _off[2]==0) , (off[2]!=res && _off[2]==_res) }
2990 if( boundary[0][0] || boundary[0][1] || boundary[1][0] || boundary[1][1] || boundary[2][0] || boundary[2][1] )
2992 TreeOctNode::Neighbors3& neighbors = nKey.getNeighbors( leaf );
2993 for(
int i=0 ; i<3 ; i++ )
for(
int j=0 ; j<3 ; j++ )
for(
int k=0 ; k<3 ; k++ ) flags[i][j][k] =
false;
2994 int x=0 , y=0 , z=0;
2995 if ( boundary[0][0] && !neighbors.neighbors[0][1][1] ) x = -1;
2996 else if( boundary[0][1] && !neighbors.neighbors[2][1][1] ) x = 1;
2997 if ( boundary[1][0] && !neighbors.neighbors[1][0][1] ) y = -1;
2998 else if( boundary[1][1] && !neighbors.neighbors[1][2][1] ) y = 1;
2999 if ( boundary[2][0] && !neighbors.neighbors[1][1][0] ) z = -1;
3000 else if( boundary[2][1] && !neighbors.neighbors[1][1][2] ) z = 1;
3005 if( x && y && z ) flags[1+x][1+y][1+z] =
true;
3007 if( x && y ) flags[1+x][1+y][1 ] =
true;
3008 if( x && z ) flags[1+x][1 ][1+z] =
true;
3009 if( y && z ) flags[1 ][1+y][1+1] =
true;
3011 if( x ) flags[1+x][1 ][1 ] =
true;
3012 if( y ) flags[1 ][1+y][1 ] =
true;
3013 if( z ) flags[1 ][1 ][1+z] =
true;
3014 nKey.setNeighbors( leaf , flags );
3018 _sNodes.set( tree );
3022 template<
int Degree>
3025 fData.setValueTables( fData.VALUE_FLAG | fData.D_VALUE_FLAG , 0 , postDerivativeSmooth );
3027 int sDepth = refineBoundary( subdivideDepth );
3029 RootData rootData , coarseRootData;
3030 std::vector< Point3D< Real > >* interiorPoints;
3031 int maxDepth = tree.maxDepth();
3033 std::vector< Real > metSolution( _sNodes.nodeCount[maxDepth] , 0 );
3035 #pragma omp parallel for num_threads( threads )
3037 for(
int i=_sNodes.nodeCount[_minDepth] ; i<_sNodes.nodeCount[maxDepth] ; i++ ) metSolution[i] = _sNodes.treeNodes[i]->nodeData.solution;
3038 for(
int d=_minDepth ; d<maxDepth ; d++ ) UpSample( d , _sNodes , &metSolution[0] );
3042 #pragma omp parallel for num_threads( threads )
3044 for(
int i=0 ; i<_sNodes.nodeCount[maxDepth+1] ; i++ ) _sNodes.treeNodes[i]->nodeData.mcIndex = 0;
3046 rootData.boundaryValues =
new hash_map<
long long , std::pair< Real ,
Point3D< Real > > >();
3049 int maxCCount = _sNodes.getMaxCornerCount( sDepth , maxDepth , threads );
3050 int maxECount = _sNodes.getMaxEdgeCount ( &tree , sDepth , threads );
3051 rootData.cornerValues = NewPointer< Real >( maxCCount );
3052 rootData.cornerNormals = NewPointer< Point3D< Real > >( maxCCount );
3053 rootData.interiorRoots = NewPointer< int >( maxECount );
3054 rootData.cornerValuesSet = NewPointer< char >( maxCCount );
3055 rootData.cornerNormalsSet = NewPointer< char >( maxCCount );
3056 rootData.edgesSet = NewPointer< char >( maxECount );
3057 _sNodes.setCornerTable( coarseRootData , NULL , sDepth , threads );
3058 coarseRootData.cornerValues = NewPointer< Real >( coarseRootData.cCount );
3059 coarseRootData.cornerNormals = NewPointer< Point3D< Real > >( coarseRootData.cCount );
3060 coarseRootData.cornerValuesSet = NewPointer< char >( coarseRootData.cCount );
3061 coarseRootData.cornerNormalsSet = NewPointer< char >( coarseRootData.cCount );
3062 memset( coarseRootData.cornerValuesSet , 0 ,
sizeof(
char ) * coarseRootData.cCount );
3063 memset( coarseRootData.cornerNormalsSet , 0 ,
sizeof(
char ) * coarseRootData.cCount );
3066 std::vector< TreeOctNode::ConstNeighborKey3 > nKeys( threads );
3067 for(
int t=0 ; t<threads ; t++ ) nKeys[t].set( maxDepth );
3068 TreeOctNode::ConstNeighborKey3 nKey;
3069 std::vector< TreeOctNode::ConstNeighborKey5 > nKeys5( threads );
3070 for(
int t=0 ; t<threads ; t++ ) nKeys5[t].set( maxDepth );
3071 TreeOctNode::ConstNeighborKey5 nKey5;
3072 nKey5.set( maxDepth ) , nKey.set( maxDepth );
3074 for(
int i=_sNodes.nodeCount[sDepth] ; i<_sNodes.nodeCount[sDepth+1] ; i++ )
3076 if( !_sNodes.treeNodes[i]->children )
continue;
3078 _sNodes.setCornerTable( rootData , _sNodes.treeNodes[i] , threads );
3079 _sNodes.setEdgeTable ( rootData , _sNodes.treeNodes[i] , threads );
3080 memset( rootData.cornerValuesSet , 0 ,
sizeof(
char ) * rootData.cCount );
3081 memset( rootData.cornerNormalsSet , 0 ,
sizeof(
char ) * rootData.cCount );
3082 memset( rootData.edgesSet , 0 ,
sizeof(
char ) * rootData.eCount );
3083 interiorPoints =
new std::vector< Point3D< Real > >();
3084 for(
int d=maxDepth ; d>sDepth ; d-- )
3086 int leafNodeCount = 0;
3087 std::vector< TreeOctNode* > leafNodes;
3088 for(
TreeOctNode* node=_sNodes.treeNodes[i]->nextLeaf() ; node ; node=_sNodes.treeNodes[i]->nextLeaf( node ) )
if( node->d==d && node->nodeData.nodeIndex!=-1 ) leafNodeCount++;
3089 leafNodes.reserve( leafNodeCount );
3090 for(
TreeOctNode* node=_sNodes.treeNodes[i]->nextLeaf() ; node ; node=_sNodes.treeNodes[i]->nextLeaf( node ) )
if( node->d==d && node->nodeData.nodeIndex!=-1 ) leafNodes.push_back( node );
3091 Stencil< Real , 3 > stencil1[8] , stencil2[8][8];
3092 SetEvaluationStencils( d , stencil1 , stencil2 );
3096 #pragma omp parallel for num_threads( threads )
3098 for(
int t=0 ; t<threads ; t++ )
for(
int i=(leafNodeCount*t)/threads ; i<(leafNodeCount*(t+1))/threads ; i++ )
3101 SetIsoCorners( isoValue , leaf , rootData , rootData.cornerValuesSet , rootData.cornerValues , nKeys[t] , &metSolution[0] , stencil1 , stencil2 );
3105 leaf->depthAndOffset( d , off );
3106 int res = 1<<(d-sDepth);
3107 off[0] %= res , off[1] %=res , off[2] %= res;
3109 if( !(off[0]%res) && !(off[1]%res) && !(off[2]%res) )
3112 while( temp->d!=sDepth ) temp = temp->parent;
3113 int x = off[0]==0 ? 0 : 1 , y = off[1]==0 ? 0 : 1 , z = off[2]==0 ? 0 : 1;
3114 int c = Cube::CornerIndex( x , y , z );
3115 int idx = coarseRootData.cornerIndices( temp )[ c ];
3116 coarseRootData.cornerValues[ idx ] = rootData.cornerValues[ rootData.cornerIndices( leaf )[c] ];
3117 coarseRootData.cornerValuesSet[ idx ] =
true;
3122 if( _boundaryType!=0 || _IsInset( leaf ) ) SetMCRootPositions( leaf , sDepth , isoValue , nKeys5[t] , rootData , interiorPoints , mesh , &metSolution[0] , nonLinearFit );
3127 std::vector< Point3D< Real > > barycenters;
3128 std::vector< Point3D< Real > >* barycenterPtr = addBarycenter ? & barycenters : NULL;
3130 #pragma omp parallel for num_threads( threads )
3132 for(
int t=0 ; t<threads ; t++ )
for(
int i=(leafNodeCount*t)/threads ; i<(leafNodeCount*(t+1))/threads ; ++i )
3135 if( _boundaryType!=0 || _IsInset( leaf ) ) GetMCIsoTriangles( leaf , mesh , rootData , interiorPoints , offSet , sDepth , polygonMesh , barycenterPtr );
3137 for(
size_t i=0 ; i<barycenters.size() ; i++ ) interiorPoints->push_back( barycenters[i] );
3139 offSet = mesh->outOfCorePointCount();
3140 delete interiorPoints;
3144 DeletePointer( rootData.cornerValues ) ; DeletePointer( rootData.cornerNormals );
3145 DeletePointer( rootData.cornerValuesSet ) ; DeletePointer( rootData.cornerNormalsSet );
3146 DeletePointer( rootData.interiorRoots );
3147 DeletePointer( rootData.edgesSet );
3148 coarseRootData.interiorRoots = NullPointer< int >();
3149 coarseRootData.boundaryValues = rootData.boundaryValues;
3150 for( hash_map< long long , int >::iterator iter=rootData.boundaryRoots.begin() ; iter!=rootData.boundaryRoots.end() ; ++iter )
3151 coarseRootData.boundaryRoots[iter->first] = iter->second;
3153 for(
int d=sDepth ; d>=0 ; d-- )
3155 Stencil< Real , 3 > stencil1[8] , stencil2[8][8];
3156 SetEvaluationStencils( d , stencil1 , stencil2 );
3157 std::vector< Point3D< Real > > barycenters;
3158 std::vector< Point3D< Real > >* barycenterPtr = addBarycenter ? &barycenters : NULL;
3159 for(
int i=_sNodes.nodeCount[d] ; i<_sNodes.nodeCount[d+1] ; i++ )
3162 if( leaf->children )
continue;
3165 SetIsoCorners( isoValue , leaf , coarseRootData , coarseRootData.cornerValuesSet , coarseRootData.cornerValues , nKey , &metSolution[0] , stencil1 , stencil2 );
3169 if( _boundaryType!=0 || _IsInset( leaf ) )
3171 SetMCRootPositions( leaf , 0 , isoValue , nKey5 , coarseRootData , NULL , mesh , &metSolution[0] , nonLinearFit );
3172 GetMCIsoTriangles( leaf , mesh , coarseRootData , NULL , 0 , 0 , polygonMesh , barycenterPtr );
3179 DeletePointer( coarseRootData.cornerValues ) ; DeletePointer( coarseRootData.cornerNormals );
3180 DeletePointer( coarseRootData.cornerValuesSet ) ; DeletePointer( coarseRootData.cornerNormalsSet );
3181 delete rootData.boundaryValues;
3183 template<
int Degree>
3189 VertexData::CenterIndex( node , fData.depth , idx );
3190 idx[0] *= fData.functionCount;
3191 idx[1] *= fData.functionCount;
3192 idx[2] *= fData.functionCount;
3193 int minDepth = std::max< int >( 0 , std::min< int >( _minDepth , node->depth()-1 ) );
3194 for(
int i=minDepth ; i<=node->depth() ; i++ )
3195 for(
int j=0 ; j<3 ; j++ )
for(
int k=0 ; k<3 ; k++ )
for(
int l=0 ; l<3 ; l++ )
3197 const TreeOctNode* n=neighborKey.neighbors[i].neighbors[j][k][l];
3200 n->nodeData.solution * Real(
3201 fData.valueTables[idx[0]+
int(n->off[0])]*
3202 fData.valueTables[idx[1]+
int(n->off[1])]*
3203 fData.valueTables[idx[2]+
int(n->off[2])]);
3205 if( node->children )
3207 for(
unsigned int i=0;i<Cube::CORNERS;i++){
3208 int ii=Cube::AntipodalCornerIndex(i);
3212 value+=n->nodeData.solution*Real(
3213 fData.valueTables[idx[0]+
int(n->off[0])]*
3214 fData.valueTables[idx[1]+
int(n->off[1])]*
3215 fData.valueTables[idx[2]+
int(n->off[2])]);
3216 if( n->children ) n=&n->children[ii];
3223 template<
int Degree >
3228 if( _boundaryType==-1 ) value = -0.5;
3230 VertexData::CornerIndex( node , corner , fData.depth , idx );
3231 idx[0] *= fData.functionCount;
3232 idx[1] *= fData.functionCount;
3233 idx[2] *= fData.functionCount;
3235 int d = node->depth();
3237 int startX = 0 , endX = 3 , startY = 0 , endY = 3 , startZ = 0 , endZ = 3;
3238 Cube::FactorCornerIndex( corner , cx , cy , cz );
3240 TreeOctNode::ConstNeighbors3& neighbors = neighborKey3.neighbors[d];
3241 if( cx==0 ) endX = 2;
3243 if( cy==0 ) endY = 2;
3245 if( cz==0 ) endZ = 2;
3247 for(
int x=startX ; x<endX ; x++ )
for(
int y=startY ; y<endY ; y++ )
for(
int z=startZ ; z<endZ ; z++ )
3249 const TreeOctNode* n=neighbors.neighbors[x][y][z];
3252 fData.valueTables[ idx[0]+int(n->off[0]) ]*
3253 fData.valueTables[ idx[1]+int(n->off[1]) ]*
3254 fData.valueTables[ idx[2]+int(n->off[2]) ]*
3255 n->nodeData.solution;
3258 if( d>0 && d>_minDepth )
3260 int _corner = int( node - node->parent->children );
3261 int _cx , _cy , _cz;
3262 Cube::FactorCornerIndex( _corner , _cx , _cy , _cz );
3263 if( cx!=_cx ) startX = 0 , endX = 3;
3264 if( cy!=_cy ) startY = 0 , endY = 3;
3265 if( cz!=_cz ) startZ = 0 , endZ = 3;
3266 TreeOctNode::ConstNeighbors3& neighbors = neighborKey3.neighbors[d-1];
3267 for(
int x=startX ; x<endX ; x++ )
for(
int y=startY ; y<endY ; y++ )
for(
int z=startZ ; z<endZ ; z++ )
3269 const TreeOctNode* n=neighbors.neighbors[x][y][z];
3272 fData.valueTables[ idx[0]+int(n->off[0]) ]*
3273 fData.valueTables[ idx[1]+int(n->off[1]) ]*
3274 fData.valueTables[ idx[2]+int(n->off[2]) ]*
3275 metSolution[ n->nodeData.nodeIndex ];
3278 return Real( value );
3280 template<
int Degree >
3284 if( _boundaryType==-1 ) value = -0.5;
3285 int d = node->depth();
3287 int startX = 0 , endX = 3 , startY = 0 , endY = 3 , startZ = 0 , endZ = 3;
3288 Cube::FactorCornerIndex( corner , cx , cy , cz );
3290 TreeOctNode::ConstNeighbors3& neighbors = neighborKey3.neighbors[d];
3291 if( cx==0 ) endX = 2;
3293 if( cy==0 ) endY = 2;
3295 if( cz==0 ) endZ = 2;
3297 for(
int x=startX ; x<endX ; x++ )
for(
int y=startY ; y<endY ; y++ )
for(
int z=startZ ; z<endZ ; z++ )
3299 const TreeOctNode* n=neighbors.neighbors[x][y][z];
3300 if( n ) value += n->nodeData.solution * stencil1[x][y][z];
3303 if( d>0 && d>_minDepth )
3305 int _corner = int( node - node->parent->children );
3306 int _cx , _cy , _cz;
3307 Cube::FactorCornerIndex( _corner , _cx , _cy , _cz );
3308 if( cx!=_cx ) startX = 0 , endX = 3;
3309 if( cy!=_cy ) startY = 0 , endY = 3;
3310 if( cz!=_cz ) startZ = 0 , endZ = 3;
3311 TreeOctNode::ConstNeighbors3& neighbors = neighborKey3.neighbors[d-1];
3312 for(
int x=startX ; x<endX ; x++ )
for(
int y=startY ; y<endY ; y++ )
for(
int z=startZ ; z<endZ ; z++ )
3314 const TreeOctNode* n=neighbors.neighbors[x][y][z];
3315 if( n ) value += metSolution[ n->nodeData.nodeIndex ] * stencil2[x][y][z];
3318 return Real( value );
3320 template<
int Degree >
3325 normal[0] = normal[1] = normal[2] = 0.;
3327 VertexData::CornerIndex( node , corner , fData.depth , idx );
3328 idx[0] *= fData.functionCount;
3329 idx[1] *= fData.functionCount;
3330 idx[2] *= fData.functionCount;
3332 int d = node->depth();
3335 TreeOctNode::ConstNeighbors5& neighbors = neighborKey5.neighbors[d];
3336 for(
int j=0 ; j<5 ; j++ )
for(
int k=0 ; k<5 ; k++ )
for(
int l=0 ; l<5 ; l++ )
3338 const TreeOctNode* n=neighbors.neighbors[j][k][l];
3341 int _idx[] = { idx[0] + n->off[0] , idx[1] + n->off[1] , idx[2] + n->off[2] };
3342 double values[] = { fData.valueTables[_idx[0]] , fData.valueTables[_idx[1]] , fData.valueTables[_idx[2]] };
3343 double dValues[] = { fData.dValueTables[_idx[0]] , fData.dValueTables[_idx[1]] , fData.dValueTables[_idx[2]] };
3344 Real solution = n->nodeData.solution;
3345 normal[0] += Real( dValues[0] * values[1] * values[2] * solution );
3346 normal[1] += Real( values[0] * dValues[1] * values[2] * solution );
3347 normal[2] += Real( values[0] * values[1] * dValues[2] * solution );
3351 if( d>0 && d>_minDepth )
3353 TreeOctNode::ConstNeighbors5& neighbors = neighborKey5.neighbors[d-1];
3354 for(
int j=0 ; j<5 ; j++ )
for(
int k=0 ; k<5 ; k++ )
for(
int l=0 ; l<5 ; l++ )
3356 const TreeOctNode* n=neighbors.neighbors[j][k][l];
3359 int _idx[] = { idx[0] + n->off[0] , idx[1] + n->off[1] , idx[2] + n->off[2] };
3360 double values[] = { fData.valueTables[_idx[0]] , fData.valueTables[_idx[1]] , fData.valueTables[_idx[2]] };
3361 double dValues[] = { fData.dValueTables[_idx[0]] , fData.dValueTables[_idx[1]] , fData.dValueTables[_idx[2]] };
3362 Real solution = metSolution[ n->nodeData.nodeIndex ];
3363 normal[0] += Real( dValues[0] * values[1] * values[2] * solution );
3364 normal[1] += Real( values[0] * dValues[1] * values[2] * solution );
3365 normal[2] += Real( values[0] * values[1] * dValues[2] * solution );
3371 template<
int Degree >
3374 Real isoValue , weightSum;
3376 fData.setValueTables( fData.VALUE_FLAG , 0 );
3378 isoValue = weightSum = 0;
3380 #pragma omp parallel for num_threads( threads ) reduction( + : isoValue , weightSum )
3382 for(
int t=0 ; t<threads ; t++)
3384 TreeOctNode::ConstNeighborKey3 nKey;
3385 nKey.set( _sNodes.maxDepth-1 );
3386 int nodeCount = _sNodes.nodeCount[ _sNodes.maxDepth ];
3387 for(
int i=(nodeCount*t)/threads ; i<(nodeCount*(t+1))/threads ; i++ )
3390 nKey.getNeighbors( temp );
3391 Real w = temp->nodeData.centerWeightContribution;
3394 isoValue += getCenterValue( nKey , temp ) * w;
3399 if( _boundaryType==-1 )
return isoValue/weightSum - Real(0.5);
3400 else return isoValue/weightSum;
3403 template<
int Degree >
3404 void Octree< Degree >::SetIsoCorners( Real isoValue ,
TreeOctNode* leaf ,
SortedTreeNodes::CornerTableData& cData , Pointer(
char ) valuesSet , Pointer( Real ) values , TreeOctNode::ConstNeighborKey3& nKey ,
const Real* metSolution ,
const Stencil< Real , 3 > stencil1[8] ,
const Stencil< Real , 3 > stencil2[8][8] )
3406 Real cornerValues[ Cube::CORNERS ];
3411 leaf->depthAndOffset( d , off );
3412 int o = _boundaryType==0 ? (1<<(d-2)) : 0;
3413 int mn = 2+o , mx = (1<<d)-2-o;
3414 isInterior = ( off[0]>=mn && off[0]<mx && off[1]>=mn && off[1]<mx && off[2]>=mn && off[2]<mx );
3415 nKey.getNeighbors( leaf );
3416 for(
unsigned int c=0 ; c<Cube::CORNERS ; c++ )
3418 int vIndex = cIndices[c];
3419 if( valuesSet[vIndex] ) cornerValues[c] = values[vIndex];
3422 if( isInterior && 0 ) cornerValues[c] = getCornerValue( nKey , leaf , c , metSolution , stencil1[c].values , stencil2[
int(leaf - leaf->parent->children)][c].values );
3423 else cornerValues[c] = getCornerValue( nKey , leaf , c , metSolution );
3424 values[vIndex] = cornerValues[c];
3425 valuesSet[vIndex] = 1;
3428 leaf->nodeData.mcIndex = MarchingCubes::GetIndex( cornerValues , isoValue );
3434 int c = int( leaf - leaf->parent->children );
3435 int mcid = leaf->nodeData.mcIndex & (1<<MarchingCubes::cornerMap[c]);
3440 InterlockedOr( (
volatile unsigned long long*)&(parent->nodeData.mcIndex) , mcid );
3447 parent->nodeData.mcIndex |= mcid;
3451 if( parent->parent && parent->parent->d>=_minDepth && (parent-parent->parent->children)==c )
3454 InterlockedOr( (
volatile unsigned long long*)&(parent->parent->nodeData.mcIndex) , mcid );
3460 parent->parent->nodeData.mcIndex |= mcid;
3462 parent = parent->parent;
3471 template<
int Degree>
3475 int corners[Cube::CORNERS/2];
3477 int c1,c2,e1,e2,dir,off;
3478 Cube::FaceCorners(faceIndex,corners[0],corners[1],corners[2],corners[3]);
3479 Cube::FactorFaceIndex(faceIndex,dir,off);
3484 e1=Cube::EdgeIndex(1,off,1);
3485 e2=Cube::EdgeIndex(2,off,1);
3488 e1=Cube::EdgeIndex(0,off,1);
3489 e2=Cube::EdgeIndex(2,1,off);
3492 e1=Cube::EdgeIndex(0,1,off);
3493 e2=Cube::EdgeIndex(1,1,off);
3496 cnt+=EdgeRootCount(&node->children[c1],e1,maxDepth)+EdgeRootCount(&node->children[c1],e2,maxDepth);
3499 e1=Cube::EdgeIndex(1,off,0);
3500 e2=Cube::EdgeIndex(2,off,0);
3503 e1=Cube::EdgeIndex(0,off,0);
3504 e2=Cube::EdgeIndex(2,0,off);
3507 e1=Cube::EdgeIndex(0,0,off);
3508 e2=Cube::EdgeIndex(1,0,off);
3511 cnt+=EdgeRootCount(&node->children[c2],e1,maxDepth)+EdgeRootCount(&node->children[c2],e2,maxDepth);
3512 for(
unsigned int i=0;i<Cube::CORNERS/2;i++){
if(node->children[corners[i]].children){cnt+=InteriorFaceRootCount(&node->children[corners[i]],faceIndex,maxDepth);}}
3517 template<
int Degree>
3521 Cube::FacesAdjacentToEdge(edgeIndex,f1,f2);
3526 if(node->depth()<maxDepth){
3527 temp=node->faceNeighbor(f1);
3528 if(temp && temp->children){
3530 eIndex=Cube::FaceReflectEdgeIndex(edgeIndex,f1);
3533 temp=node->faceNeighbor(f2);
3534 if(temp && temp->children){
3536 eIndex=Cube::FaceReflectEdgeIndex(edgeIndex,f2);
3539 temp=node->edgeNeighbor(edgeIndex);
3540 if(temp && temp->children){
3542 eIndex=Cube::EdgeReflectEdgeIndex(edgeIndex);
3548 Cube::EdgeCorners(eIndex,c1,c2);
3549 if(finest->children)
return EdgeRootCount(&finest->children[c1],eIndex,maxDepth)+EdgeRootCount(&finest->children[c2],eIndex,maxDepth);
3550 else return MarchingCubes::HasEdgeRoots(finest->nodeData.mcIndex,eIndex);
3552 template<
int Degree>
3554 int dir,offset,d,o[3],idx;
3556 if(subdivideDepth<0){
return 0;}
3557 if(node->d<=subdivideDepth){
return 1;}
3558 Cube::FactorFaceIndex(faceIndex,dir,offset);
3559 node->depthAndOffset(d,o);
3561 idx=(int(o[dir])<<1) + (offset<<1);
3562 return !(idx%(2<<(int(node->d)-subdivideDepth)));
3564 template<
int Degree>
3567 Cube::FactorEdgeIndex(edgeIndex,dir,x,y);
3568 return IsBoundaryEdge(node,dir,x,y,subdivideDepth);
3570 template<
int Degree>
3577 if( subdivideDepth<0 )
return 0;
3578 if( node->d<=subdivideDepth )
return 1;
3579 node->depthAndOffset( d , o );
3596 int mask = 1<<( int(node->d) - subdivideDepth );
3597 return !(idx1%(mask)) || !(idx2%(mask));
3599 template<
int Degree >
3606 Cube::FactorEdgeIndex( ri.edgeIndex , o , i1 , i2 );
3607 ri.node->centerAndWidth( c , width );
3611 start[0] = c[0] - width/2;
3612 end [0] = c[0] + width/2;
3613 start[1] = end[1] = c[1] - width/2 + width*i1;
3614 start[2] = end[2] = c[2] - width/2 + width*i2;
3617 start[0] = end[0] = c[0] - width/2 + width*i1;
3618 start[1] = c[1] - width/2;
3619 end [1] = c[1] + width/2;
3620 start[2] = end[2] = c[2] - width/2 + width*i2;
3623 start[0] = end[0] = c[0] - width/2 + width*i1;
3624 start[1] = end[1] = c[1] - width/2 + width*i2;
3625 start[2] = c[2] - width/2;
3626 end [2] = c[2] + width/2;
3633 template<
int Degree >
3636 if( !MarchingCubes::HasRoots( ri.node->nodeData.mcIndex ) )
return 0;
3638 Cube::EdgeCorners( ri.edgeIndex , c1 , c2 );
3639 if( !MarchingCubes::HasEdgeRoots( ri.node->nodeData.mcIndex , ri.edgeIndex ) )
return 0;
3641 long long key1 , key2;
3644 int i , o , i1 , i2 , rCount=0;
3646 std::vector< double > roots;
3648 Real center , width;
3650 Cube::FactorEdgeIndex( ri.edgeIndex , o , i1 , i2 );
3651 int idx1[3] , idx2[3];
3652 key1 = VertexData::CornerIndex( ri.node , c1 , fData.depth , idx1 );
3653 key2 = VertexData::CornerIndex( ri.node , c2 , fData.depth , idx2 );
3655 bool isBoundary = ( IsBoundaryEdge( ri.node , ri.edgeIndex , sDepth )!=0 );
3656 bool haveKey1 , haveKey2;
3657 std::pair< Real , Point3D< Real > > keyValue1 , keyValue2;
3660 iter1 = rootData.cornerIndices( ri.node )[ c1 ];
3661 iter2 = rootData.cornerIndices( ri.node )[ c2 ];
3662 keyValue1.first = rootData.cornerValues[iter1];
3663 keyValue2.first = rootData.cornerValues[iter2];
3667 #pragma omp critical (normal_hash_access)
3670 haveKey1 = ( rootData.boundaryValues->find( key1 )!=rootData.boundaryValues->end() );
3671 haveKey2 = ( rootData.boundaryValues->find( key2 )!=rootData.boundaryValues->end() );
3672 if( haveKey1 ) keyValue1 = (*rootData.boundaryValues)[key1];
3673 if( haveKey2 ) keyValue2 = (*rootData.boundaryValues)[key2];
3678 haveKey1 = ( rootData.cornerNormalsSet[ iter1 ] != 0 );
3679 haveKey2 = ( rootData.cornerNormalsSet[ iter2 ] != 0 );
3680 keyValue1.first = rootData.cornerValues[iter1];
3681 keyValue2.first = rootData.cornerValues[iter2];
3682 if( haveKey1 ) keyValue1.second = rootData.cornerNormals[iter1];
3683 if( haveKey2 ) keyValue2.second = rootData.cornerNormals[iter2];
3686 if( !haveKey1 || !haveKey2 ) neighborKey5.getNeighbors( ri.node );
3687 if( !haveKey1 ) keyValue1.second = getCornerNormal( neighborKey5 , ri.node , c1 , metSolution );
3688 x0 = keyValue1.first;
3689 n[0] = keyValue1.second;
3691 if( !haveKey2 ) keyValue2.second = getCornerNormal( neighborKey5 , ri.node , c2 , metSolution );
3692 x1 = keyValue2.first;
3693 n[1] = keyValue2.second;
3695 if( !haveKey1 || !haveKey2 )
3700 #pragma omp critical (normal_hash_access)
3703 if( !haveKey1 ) (*rootData.boundaryValues)[key1] = keyValue1;
3704 if( !haveKey2 ) (*rootData.boundaryValues)[key2] = keyValue2;
3709 if( !haveKey1 ) rootData.cornerNormals[iter1] = keyValue1.second , rootData.cornerNormalsSet[ iter1 ] = 1;
3710 if( !haveKey2 ) rootData.cornerNormals[iter2] = keyValue2.second , rootData.cornerNormalsSet[ iter2 ] = 1;
3715 ri.node->centerAndWidth(c,width);
3717 for( i=0 ; i<DIMENSION ; i++ ) n[0][i] *= width , n[1][i] *= width;
3722 position[1] = c[1]-width/2+width*i1;
3723 position[2] = c[2]-width/2+width*i2;
3726 position[0] = c[0]-width/2+width*i1;
3727 position[2] = c[2]-width/2+width*i2;
3730 position[0] = c[0]-width/2+width*i1;
3731 position[1] = c[1]-width/2+width*i2;
3739 double scl=(x1-x0)/((dx1+dx0)/2);
3744 P.coefficients[0] = x0;
3745 P.coefficients[1] = dx0;
3746 P.coefficients[2] = 3*(x1-x0)-dx1-2*dx0;
3748 P.getSolutions( isoValue , roots , EPSILON );
3749 for( i=0 ; i<int(roots.size()) ; i++ )
3750 if( roots[i]>=0 && roots[i]<=1 )
3752 averageRoot += Real( roots[i] );
3755 if( rCount && nonLinearFit ) averageRoot /= rCount;
3756 else averageRoot = Real((x0-isoValue)/(x0-x1));
3757 if( averageRoot<0 || averageRoot>1 )
3759 fprintf( stderr ,
"[WARNING] Bad average root: %f\n" , averageRoot );
3760 fprintf( stderr ,
"\t(%f %f) , (%f %f) (%f)\n" , x0 , x1 , dx0 , dx1 , isoValue );
3761 if( averageRoot<0 ) averageRoot = 0;
3762 if( averageRoot>1 ) averageRoot = 1;
3764 position[o] = Real(center-width/2+width*averageRoot);
3767 template<
int Degree >
3774 Cube::FacesAdjacentToEdge(edgeIndex,f1,f2);
3777 finestIndex=edgeIndex;
3778 if(node->depth()<maxDepth){
3779 if( IsBoundaryFace( node , f1 , sDepth ) ) temp=NULL;
3780 else temp=node->faceNeighbor(f1);
3781 if( temp && temp->nodeData.nodeIndex!=-1 && temp->children )
3782 finest = temp , finestIndex = Cube::FaceReflectEdgeIndex( edgeIndex , f1 );
3785 if( IsBoundaryFace( node , f2 , sDepth ) ) temp=NULL;
3786 else temp = node->faceNeighbor(f2);
3787 if( temp && temp->nodeData.nodeIndex!=-1 && temp->children )
3788 finest = temp , finestIndex = Cube::FaceReflectEdgeIndex( edgeIndex , f2 );
3791 if( IsBoundaryEdge( node , edgeIndex , sDepth ) ) temp=NULL;
3792 else temp = node->edgeNeighbor(edgeIndex);
3793 if( temp && temp->nodeData.nodeIndex!=-1 && temp->children )
3794 finest = temp , finestIndex = Cube::EdgeReflectEdgeIndex( edgeIndex );
3799 Cube::EdgeCorners( finestIndex , c1 , c2 );
3800 if( finest->children )
3802 if ( GetRootIndex( &finest->children[c1] , finestIndex , maxDepth , sDepth , ri ) )
return 1;
3803 else if ( GetRootIndex( &finest->children[c2] , finestIndex , maxDepth , sDepth , ri ) )
return 1;
3806 fprintf( stderr ,
"[WARNING] Couldn't find root index with either child\n" );
3812 if( !(MarchingCubes::edgeMask[finest->nodeData.mcIndex] & (1<<finestIndex)) )
3814 fprintf( stderr ,
"[WARNING] Finest node does not have iso-edge\n" );
3819 Cube::FactorEdgeIndex(finestIndex,o,i1,i2);
3821 finest->depthAndOffset(d,off);
3823 ri.edgeIndex=finestIndex;
3824 int eIndex[2],offset;
3841 ri.key = (
long long)(o) | (
long long)(eIndex[0])<<5 | (
long long)(eIndex[1])<<25 | (
long long)(offset)<<45;
3845 template<
int Degree>
3848 int c1 , c2 , f1 , f2;
3852 if( node->nodeData.nodeIndex==-1 ) fprintf( stderr ,
"[WARNING] Called GetRootIndex with bad node\n" );
3854 if( !(MarchingCubes::edgeMask[node->nodeData.mcIndex] & (1<<edgeIndex) ) )
return 0;
3856 Cube::FacesAdjacentToEdge( edgeIndex , f1 , f2 );
3859 finestIndex = edgeIndex;
3860 if( node->depth()<maxDepth && !node->children )
3862 temp=node->faceNeighbor( f1 );
3863 if( temp && temp->nodeData.nodeIndex!=-1 && temp->children ) finest = temp , finestIndex = Cube::FaceReflectEdgeIndex( edgeIndex , f1 );
3866 temp = node->faceNeighbor( f2 );
3867 if( temp && temp->nodeData.nodeIndex!=-1 && temp->children ) finest = temp , finestIndex = Cube::FaceReflectEdgeIndex( edgeIndex , f2 );
3870 temp = node->edgeNeighbor( edgeIndex );
3871 if( temp && temp->nodeData.nodeIndex!=-1 && temp->children ) finest = temp , finestIndex = Cube::EdgeReflectEdgeIndex( edgeIndex );
3876 Cube::EdgeCorners( finestIndex , c1 , c2 );
3877 if( finest->children )
3879 if ( GetRootIndex( finest->children + c1 , finestIndex , maxDepth , ri ) )
return 1;
3880 else if( GetRootIndex( finest->children + c2 , finestIndex , maxDepth , ri ) )
return 1;
3883 int d1 , off1[3] , d2 , off2[3];
3884 node->depthAndOffset( d1 , off1 );
3885 finest->depthAndOffset( d2 , off2 );
3886 fprintf( stderr ,
"[WARNING] Couldn't find root index with either child [%d] (%d %d %d) -> [%d] (%d %d %d) (%d %d)\n" , d1 , off1[0] , off1[1] , off1[2] , d2 , off2[0] , off2[1] , off2[2] , node->children!=NULL , finest->children!=NULL );
3888 for(
int i=0 ; i<8 ; i++ )
if( node->nodeData.mcIndex & (1<<i) ) printf(
"1" );
else printf(
"0" );
3890 for(
int i=0 ; i<8 ; i++ )
if( finest->nodeData.mcIndex & (1<<i) ) printf(
"1" );
else printf(
"0" );
3898 Cube::FactorEdgeIndex(finestIndex,o,i1,i2);
3900 finest->depthAndOffset(d,off);
3902 ri.edgeIndex = finestIndex;
3904 int eIndex[2] = {0,0};
3921 ri.key= (
long long)(o) | (
long long)(eIndex[0])<<5 | (
long long)(eIndex[1])<<25 | (
long long)(offset)<<45;
3925 template<
int Degree>
3930 Cube::EdgeCorners( ri.edgeIndex , c1 , c2 );
3931 while( node->parent )
3933 c = int(node-node->parent->children);
3934 if( c!=c1 && c!=c2 )
return 0;
3935 if( !MarchingCubes::HasEdgeRoots( node->parent->nodeData.mcIndex , ri.edgeIndex ) )
3937 if(c==c1)
return GetRootIndex( &node->parent->children[c2] , ri.edgeIndex , maxDepth , pair );
3938 else return GetRootIndex( &node->parent->children[c1] , ri.edgeIndex , maxDepth , pair );
3940 node = node->parent;
3945 template<
int Degree>
3948 long long key = ri.key;
3949 hash_map< long long , int >::iterator rootIter;
3950 rootIter = rootData.boundaryRoots.find( key );
3951 if( rootIter!=rootData.boundaryRoots.end() )
3954 index.index = rootIter->second;
3957 else if( rootData.interiorRoots )
3959 int eIndex = rootData.edgeIndices( ri.node )[ ri.edgeIndex ];
3960 if( rootData.edgesSet[ eIndex ] )
3963 index.index = rootData.interiorRoots[ eIndex ];
3969 template<
int Degree >
3977 if( !MarchingCubes::HasRoots( node->nodeData.mcIndex ) )
return 0;
3978 for(
int i=0 ; i<DIMENSION ; i++ )
for(
int j=0 ; j<2 ; j++ )
for(
int k=0 ; k<2 ; k++ )
3981 eIndex = Cube::EdgeIndex( i , j , k );
3982 if( GetRootIndex( node , eIndex , fData.depth , ri ) )
3984 long long key = ri.key;
3985 if( !rootData.interiorRoots || IsBoundaryEdge( node , i , j , k , sDepth ) )
3987 hash_map< long long , int >::iterator iter , end;
3990 #pragma omp critical (boundary_roots_hash_access)
3993 iter = rootData.boundaryRoots.find( key );
3994 end = rootData.boundaryRoots.end();
3999 GetRoot( ri , isoValue , neighborKey5 , position , rootData , sDepth , metSolution , nonLinearFit );
4000 position = position * _scale + _center;
4003 #pragma omp critical (boundary_roots_hash_access)
4006 iter = rootData.boundaryRoots.find( key );
4007 end = rootData.boundaryRoots.end();
4010 mesh->inCorePoints.push_back( position );
4011 rootData.boundaryRoots[key] = int( mesh->inCorePoints.size() ) - 1;
4014 if( iter==end ) count++;
4019 int nodeEdgeIndex = rootData.edgeIndices( ri.node )[ ri.edgeIndex ];
4020 if( !rootData.edgesSet[ nodeEdgeIndex ] )
4023 GetRoot( ri , isoValue , neighborKey5 , position , rootData , sDepth , metSolution , nonLinearFit );
4024 position = position * _scale + _center;
4027 #pragma omp critical (add_point_access)
4030 if( !rootData.edgesSet[ nodeEdgeIndex ] )
4032 rootData.interiorRoots[ nodeEdgeIndex ] = mesh->addOutOfCorePoint( position );
4033 interiorPositions->push_back( position );
4034 rootData.edgesSet[ nodeEdgeIndex ] = 1;
4044 template<
int Degree>
4048 int i,j,k,eIndex,hits=0;
4053 node = tree.nextLeaf();
4056 if( MarchingCubes::HasRoots( node->nodeData.mcIndex ) )
4059 for( i=0 ; i<DIMENSION ; i++ )
4060 for( j=0 ; j<2 ; j++ )
4061 for( k=0 ; k<2 ; k++ )
4062 if( IsBoundaryEdge( node , i , j , k , sDepth ) )
4065 eIndex = Cube::EdgeIndex( i , j , k );
4066 if( GetRootIndex( node , eIndex , fData.depth , ri ) )
4068 long long key = ri.key;
4069 if( rootData.boundaryRoots.find(key)==rootData.boundaryRoots.end() )
4071 GetRoot( ri , isoValue , position , rootData , sDepth , nonLinearFit );
4072 position = position * _scale + _center;
4073 mesh->inCorePoints.push_back( position );
4074 rootData.boundaryRoots[key] = int( mesh->inCorePoints.size() )-1;
4080 if( hits ) node=tree.nextLeaf(node);
4081 else node=tree.nextBranch(node);
4085 template<
int Degree>
4090 int isoTri[ DIMENSION * MarchingCubes::MAX_TRIANGLES ];
4091 FaceEdgesFunction fef;
4093 hash_map< long long , std::pair< RootInfo , int > >::iterator iter;
4094 hash_map< long long , std::pair< RootInfo , int > > vertexCount;
4097 fef.maxDepth = fData.depth;
4098 fef.vertexCount = &vertexCount;
4099 count = MarchingCubes::AddTriangleIndices( node->nodeData.mcIndex , isoTri );
4100 for( fIndex=0 ; fIndex<int(Cube::NEIGHBORS) ; fIndex++ )
4102 ref = Cube::FaceReflectFaceIndex( fIndex , fIndex );
4104 temp = node->faceNeighbor( fIndex );
4107 if( temp && temp->nodeData.nodeIndex!=-1 && temp->children && !IsBoundaryFace( node , fIndex , sDepth ) ) temp->processNodeFaces( temp , &fef , ref );
4112 for(
int j=0 ; j<count ; j++ )
4113 for(
int k=0 ; k<3 ; k++ )
4114 if( fIndex==Cube::FaceAdjacentToEdges( isoTri[j*3+k] , isoTri[j*3+((k+1)%3)] ) )
4116 if( GetRootIndex( node , isoTri[j*3+k] , fData.depth , ri1 ) && GetRootIndex( node , isoTri[j*3+((k+1)%3)] , fData.depth , ri2 ) )
4118 long long key1 = ri1.key , key2 = ri2.key;
4119 edges.push_back( std::pair< RootInfo , RootInfo >( ri1 , ri2 ) );
4120 iter=vertexCount.find( key1 );
4121 if( iter==vertexCount.end() )
4123 vertexCount[key1].first = ri1;
4124 vertexCount[key1].second = 0;
4126 iter=vertexCount.find( key2 );
4127 if( iter==vertexCount.end() )
4129 vertexCount[key2].first = ri2;
4130 vertexCount[key2].second = 0;
4132 vertexCount[key1].second++;
4133 vertexCount[key2].second--;
4137 int r1 = MarchingCubes::HasEdgeRoots( node->nodeData.mcIndex , isoTri[j*3+k] );
4138 int r2 = MarchingCubes::HasEdgeRoots( node->nodeData.mcIndex , isoTri[j*3+((k+1)%3)] );
4139 std::cerr <<
"Bad Edge 2:" << ri1.key <<
" " << ri2.key <<
"\t" << r1 <<
" " << r2 << std::endl;
4144 for(
int i=0 ; i<int(edges.size()) ; i++ )
4146 iter = vertexCount.find( edges[i].first.key );
4147 if( iter==vertexCount.end() )
4148 std::cerr <<
"Could not find vertex! EIndex: " << edges[i].first.edgeIndex <<
", Key: " << edges[i].first.key << std::endl;
4150 else if( vertexCount[ edges[i].first.key ].second )
4153 GetRootPair( vertexCount[edges[i].first.key].first , fData.depth , ri );
4154 long long key = ri.key;
4155 iter = vertexCount.find( key );
4156 if( iter==vertexCount.end() )
4159 node->depthAndOffset( d , off );
4160 printf(
"Vertex pair not in list 1 (%lld) %d\t[%d] (%d %d %d)\n" , key , IsBoundaryEdge( ri.node , ri.edgeIndex , sDepth ) , d , off[0] , off[1] , off[2] );
4164 edges.push_back( std::pair< RootInfo , RootInfo >( ri , edges[i].first ) );
4165 vertexCount[ key ].second++;
4166 vertexCount[ edges[i].first.key ].second--;
4170 iter = vertexCount.find( edges[i].second.key );
4171 if( iter==vertexCount.end() )
4172 std::cerr <<
"Could not find vertex! EIndex: " << edges[i].second.edgeIndex <<
", Key: " << edges[i].second.key << std::endl;
4174 else if( vertexCount[edges[i].second.key].second )
4177 GetRootPair( vertexCount[edges[i].second.key].first , fData.depth , ri );
4178 long long key = ri.key;
4179 iter=vertexCount.find( key );
4180 if( iter==vertexCount.end() )
4183 node->depthAndOffset( d , off );
4184 printf(
"Vertex pair not in list 2\t[%d] (%d %d %d)\n" , d , off[0] , off[1] , off[2] );
4188 edges.push_back( std::pair< RootInfo , RootInfo >( edges[i].second , ri ) );
4189 vertexCount[key].second--;
4190 vertexCount[ edges[i].second.key ].second++;
4195 template<
int Degree>
4199 std::vector< std::pair< RootInfo , RootInfo > > edges;
4200 std::vector< std::vector< std::pair< RootInfo , RootInfo > > > edgeLoops;
4201 GetMCIsoEdges( node , sDepth , edges );
4203 GetEdgeLoops( edges , edgeLoops );
4204 for(
int i=0 ; i<int(edgeLoops.size()) ; i++ )
4207 std::vector<CoredPointIndex> edgeIndices;
4208 for(
int j=
int(edgeLoops[i].size())-1 ; j>=0 ; j-- )
4210 if( !GetRootIndex( edgeLoops[i][j].first , rootData , p ) ) printf(
"Bad Point Index\n" );
4211 else edgeIndices.push_back( p );
4213 tris += AddTriangles( mesh , edgeIndices , interiorPositions , offSet , polygonMesh , barycenters );
4218 template<
int Degree >
4219 int Octree< Degree >::GetEdgeLoops( std::vector< std::pair< RootInfo , RootInfo > >& edges , std::vector< std::vector< std::pair< RootInfo , RootInfo > > >& loops )
4222 long long frontIdx , backIdx;
4223 std::pair< RootInfo , RootInfo > e , temp;
4226 while( !edges.empty() )
4228 std::vector< std::pair< RootInfo , RootInfo > > front , back;
4230 loops.resize( loopSize+1 );
4231 edges[0] = edges.back();
4233 frontIdx = e.second.key;
4234 backIdx = e.first.key;
4235 for(
int j=
int(edges.size())-1 ; j>=0 ; j-- )
4237 if( edges[j].first.key==frontIdx || edges[j].second.key==frontIdx )
4239 if( edges[j].first.key==frontIdx ) temp = edges[j];
4240 else temp.first = edges[j].second , temp.second = edges[j].first;
4241 frontIdx = temp.second.key;
4242 front.push_back(temp);
4243 edges[j] = edges.back();
4245 j = int(edges.size());
4247 else if( edges[j].first.key==backIdx || edges[j].second.key==backIdx )
4249 if( edges[j].second.key==backIdx ) temp = edges[j];
4250 else temp.first = edges[j].second , temp.second = edges[j].first;
4251 backIdx = temp.first.key;
4252 back.push_back(temp);
4253 edges[j] = edges.back();
4255 j = int(edges.size());
4258 for(
int j=
int(back.size())-1 ; j>=0 ; j-- ) loops[loopSize].push_back( back[j] );
4259 loops[loopSize].push_back(e);
4260 for(
int j=0 ; j<int(front.size()) ; j++ ) loops[loopSize].push_back( front[j] );
4263 return int(loops.size());
4265 template<
int Degree>
4269 std::vector< Point3D< Real > > vertices;
4270 std::vector< TriangleIndex > triangles;
4273 std::vector< CoredVertexIndex > vertices( edges.size() );
4274 for(
int i=0 ; i<int(edges.size()) ; i++ )
4276 vertices[i].idx = edges[i].index;
4277 vertices[i].inCore = (edges[i].inCore!=0);
4280 #pragma omp critical (add_polygon_access)
4283 mesh->addPolygon( vertices );
4287 if( edges.size()>3 )
4289 bool isCoplanar =
false;
4292 for(
unsigned int i=0 ; i< edges.size() ; i++ )
4293 for(
unsigned int j=0 ; j<i ; j++ )
4294 if( (i+1)%edges.size()!=j && (j+1)%edges.size()!=i )
4297 if( edges[i].inCore ) v1 = mesh->inCorePoints[ edges[i].index ];
4298 else v1 = (*interiorPositions)[ edges[i].index-offSet ];
4299 if( edges[j].inCore ) v2 = mesh->inCorePoints[ edges[j].index ];
4300 else v2 = (*interiorPositions)[ edges[j].index-offSet ];
4301 for(
int k=0 ; k<3 ; k++ )
if( v1[k]==v2[k] ) isCoplanar =
true;
4306 c[0] = c[1] = c[2] = 0;
4307 for(
int i=0 ; i<int(edges.size()) ; i++ )
4310 if(edges[i].inCore) p = mesh->inCorePoints[edges[i].index ];
4311 else p = (*interiorPositions)[edges[i].index-offSet];
4314 c /= Real( edges.size() );
4317 #pragma omp critical (add_point_access)
4320 cIdx = mesh->addOutOfCorePoint( c );
4321 barycenters->push_back( c );
4323 for(
int i=0 ; i<int(edges.size()) ; i++ )
4325 std::vector< CoredVertexIndex > vertices( 3 );
4326 vertices[0].idx = edges[i ].index;
4327 vertices[1].idx = edges[(i+1)%edges.size()].index;
4328 vertices[2].idx = cIdx;
4329 vertices[0].inCore = (edges[i ].inCore!=0);
4330 vertices[1].inCore = (edges[(i+1)%edges.size()].inCore!=0);
4331 vertices[2].inCore = 0;
4333 #pragma omp critical (add_polygon_access)
4336 mesh->addPolygon( vertices );
4339 return int( edges.size() );
4343 vertices.resize( edges.size() );
4345 for(
int i=0 ; i<int(edges.size()) ; i++ )
4348 if( edges[i].inCore ) p = mesh->inCorePoints[edges[i].index ];
4349 else p = (*interiorPositions)[edges[i].index-offSet];
4352 MAT.GetTriangulation( vertices , triangles );
4353 for(
int i=0 ; i<int(triangles.size()) ; i++ )
4355 std::vector< CoredVertexIndex > _vertices( 3 );
4356 for(
int j=0 ; j<3 ; j++ )
4358 _vertices[j].idx = edges[ triangles[i].idx[j] ].index;
4359 _vertices[j].inCore = (edges[ triangles[i].idx[j] ].inCore!=0);
4362 #pragma omp critical (add_polygon_access)
4365 mesh->addPolygon( _vertices );
4370 else if( edges.size()==3 )
4372 std::vector< CoredVertexIndex > vertices( 3 );
4373 for(
int i=0 ; i<3 ; i++ )
4375 vertices[i].idx = edges[i].index;
4376 vertices[i].inCore = (edges[i].inCore!=0);
4379 #pragma omp critical (add_polygon_access)
4381 mesh->addPolygon( vertices );
4383 return int(edges.size())-2;
4385 template<
int Degree >
4386 Pointer( Real )
Octree< Degree >::GetSolutionGrid(
int& res , Real isoValue ,
int depth )
4388 int maxDepth = _boundaryType==0 ? tree.maxDepth()-1 : tree.maxDepth();
4389 if( depth<=0 || depth>maxDepth ) depth = maxDepth;
4391 fData.set( _boundaryType==0 ? depth+1 : depth ,
true , _boundaryType );
4393 fData.setValueTables( fData.VALUE_FLAG );
4394 Pointer( Real ) values = NewPointer< Real >( res * res * res );
4395 memset( values , 0 , sizeof( Real ) * res * res * res );
4397 for(
TreeOctNode* n=tree.nextNode() ; n ; n=tree.nextNode( n ) )
4399 if( n->d>(_boundaryType==0?depth+1:depth) )
continue;
4400 if( n->d<_minDepth )
continue;
4401 int d , idx[3] , start[3] , end[3];
4402 n->depthAndOffset( d , idx );
4404 for(
int i=0 ; i<3 ; i++ )
4409 fData.setSampleSpan( idx[i] , start[i] , end[i] );
4411 if( !(start[i]&1) ) start[i]++;
4412 if( !( end[i]&1) ) end[i]--;
4413 if( _boundaryType==0 )
4417 start[i] = std::max< int >( start[i] , res+1 );
4418 end [i] = std::min< int >( end [i] , 3*res-1 );
4421 if( skip )
continue;
4422 Real coefficient = n->nodeData.solution;
4423 for(
int x=start[0] ; x<=end[0] ; x+=2 )
4424 for(
int y=start[1] ; y<=end[1] ; y+=2 )
4425 for(
int z=start[2] ; z<=end[2] ; z+=2 )
4427 int xx = (x-1)>>1 , yy=(y-1)>>1 , zz = (z-1)>>1;
4428 if( _boundaryType==0 ) xx -= res/2 , yy -= res/2 , zz -= res/2;
4429 values[ zz*res*res + yy*res + xx ] +=
4431 fData.valueTables[ idx[0]+x*fData.functionCount ] *
4432 fData.valueTables[ idx[1]+y*fData.functionCount ] *
4433 fData.valueTables[ idx[2]+z*fData.functionCount ];
4436 if( _boundaryType==-1 )
for(
int i=0 ; i<res*res*res ; i++ ) values[i] -= Real(0.5);
4437 for(
int i=0 ; i<res*res*res ; i++ ) values[i] -= isoValue;
4445 long long VertexData::CenterIndex(
const TreeOctNode* node,
int maxDepth){
4447 return CenterIndex(node,maxDepth,idx);
4449 long long VertexData::CenterIndex(
const TreeOctNode* node,
int maxDepth,
int idx[DIMENSION]){
4451 node->depthAndOffset(d,o);
4453 return (
long long)(idx[0]) | (
long long)(idx[1])<<15 | (
long long)(idx[2])<<30;
4455 long long VertexData::CenterIndex(
int depth,
const int offSet[DIMENSION],
int maxDepth,
int idx[DIMENSION]){
4457 return (
long long)(idx[0]) | (
long long)(idx[1])<<15 | (
long long)(idx[2])<<30;
4459 long long VertexData::CornerIndex(
const TreeOctNode* node,
int cIndex,
int maxDepth){
4461 return CornerIndex(node,cIndex,maxDepth,idx);
4463 long long VertexData::CornerIndex(
const TreeOctNode* node ,
int cIndex ,
int maxDepth ,
int idx[DIMENSION] )
4466 Cube::FactorCornerIndex( cIndex , x[0] , x[1] , x[2] );
4468 node->depthAndOffset( d , o );
4469 for(
int i=0 ; i<DIMENSION ; i++ ) idx[i] = BinaryNode<Real>::CornerIndex( maxDepth+1 , d , o[i] , x[i] );
4470 return CornerIndexKey( idx );
4472 long long VertexData::CornerIndex(
int depth ,
const int offSet[DIMENSION] ,
int cIndex ,
int maxDepth ,
int idx[DIMENSION] )
4475 Cube::FactorCornerIndex( cIndex , x[0] , x[1] , x[2] );
4476 for(
int i=0 ; i<DIMENSION ; i++ ) idx[i] = BinaryNode<Real>::CornerIndex( maxDepth+1 , depth , offSet[i] , x[i] );
4477 return CornerIndexKey( idx );
4479 long long VertexData::CornerIndexKey(
const int idx[DIMENSION] )
4481 return (
long long)(idx[0]) | (
long long)(idx[1])<<15 | (
long long)(idx[2])<<30;
4483 long long VertexData::FaceIndex(
const TreeOctNode* node,
int fIndex,
int maxDepth){
4485 return FaceIndex(node,fIndex,maxDepth,idx);
4487 long long VertexData::FaceIndex(
const TreeOctNode* node,
int fIndex,
int maxDepth,
int idx[DIMENSION]){
4489 Cube::FactorFaceIndex(fIndex,dir,offset);
4491 node->depthAndOffset(d,o);
4494 return (
long long)(idx[0]) | (
long long)(idx[1])<<15 | (
long long)(idx[2])<<30;
4496 long long VertexData::EdgeIndex(
const TreeOctNode* node,
int eIndex,
int maxDepth){
4498 return EdgeIndex(node,eIndex,maxDepth,idx);
4500 long long VertexData::EdgeIndex(
const TreeOctNode* node,
int eIndex,
int maxDepth,
int idx[DIMENSION]){
4503 node->depthAndOffset(d,off);
4505 Cube::FactorEdgeIndex(eIndex,o,i1,i2);
4520 return (
long long)(idx[0]) | (
long long)(idx[1])<<15 | (
long long)(idx[2])<<30;
osg::Vec3f::ValueType dot(const osg::Vec3f &_v1, const osg::Vec3f &_v2)
Adapter for osg vector member computing a scalar product.