Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
MultiGridOctreeData.inl
1 /*
2 Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7 
8 Redistributions of source code must retain the above copyright notice, this list of
9 conditions and the following disclaimer. Redistributions in binary form must reproduce
10 the above copyright notice, this list of conditions and the following disclaimer
11 in the documentation and/or other materials provided with the distribution.
12 
13 Neither the name of the Johns Hopkins University nor the names of its contributors
14 may be used to endorse or promote products derived from this software without specific
15 prior written permission.
16 
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
18 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES
19 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
20 SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26 DAMAGE.
27 */
28 
29 #ifndef DOXY_IGNORE_THIS
30 
31 #include "Octree.h"
32 #include "Time.h"
33 #include "MemoryUsage.h"
34 #include "PointStream.h"
35 #include "MAT.h"
36 
37 #define ITERATION_POWER 1.0/3
38 #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12
39 //#define MEMORY_ALLOCATOR_BLOCK_SIZE 0
40 #define SPLAT_ORDER 2
41 
42 const Real MATRIX_ENTRY_EPSILON = Real(0);
43 const Real EPSILON=Real(1e-6);
44 const Real ROUND_EPS=Real(1e-5);
45 
46 
47 
49 // SortedTreeNodes //
51 SortedTreeNodes::SortedTreeNodes( void )
52 {
53  nodeCount = NULL;
54  treeNodes = NullPointer< TreeOctNode* >();
55  maxDepth = 0;
56 }
57 SortedTreeNodes::~SortedTreeNodes( void )
58 {
59  if( nodeCount ) delete[] nodeCount;
60  nodeCount = NULL;
61  if( treeNodes ) DeletePointer( treeNodes );
62 }
63 
64 void SortedTreeNodes::set( TreeOctNode& root )
65 {
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() );
71 
72  int startDepth = 0;
73  startDepth = 0;
74  nodeCount[0] = 0 , nodeCount[1] = 1;
75  treeNodes[0] = &root;
76  for( TreeOctNode* node=root.nextNode() ; node ; node=root.nextNode( node ) ) node->nodeData.nodeIndex = -1;
77  for( int d=startDepth+1 ; d<maxDepth ; d++ )
78  {
79  nodeCount[d+1] = nodeCount[d];
80  for( int i=nodeCount[d-1] ; i<nodeCount[d] ; i++ )
81  {
82  TreeOctNode* temp = treeNodes[i];
83  if( temp->children ) for( int c=0 ; c<8 ; c++ ) treeNodes[ nodeCount[d+1]++ ] = temp->children + c;
84  }
85  }
86  for( int i=0 ; i<nodeCount[maxDepth] ; i++ ) treeNodes[i]->nodeData.nodeIndex = i;
87 }
88 SortedTreeNodes::CornerIndices& SortedTreeNodes::CornerTableData::operator[] ( const TreeOctNode* node ) { return cTable[ node->nodeData.nodeIndex + offsets[node->d] ]; }
89 const SortedTreeNodes::CornerIndices& SortedTreeNodes::CornerTableData::operator[] ( const TreeOctNode* node ) const { return cTable[ node->nodeData.nodeIndex + offsets[node->d] ]; }
90 SortedTreeNodes::CornerIndices& SortedTreeNodes::CornerTableData::cornerIndices( const TreeOctNode* node ) { return cTable[ node->nodeData.nodeIndex + offsets[node->d] ]; }
91 const SortedTreeNodes::CornerIndices& SortedTreeNodes::CornerTableData::cornerIndices( const TreeOctNode* node ) const { return cTable[ node->nodeData.nodeIndex + offsets[node->d] ]; }
92 void SortedTreeNodes::setCornerTable( CornerTableData& cData , const TreeOctNode* rootNode , int maxDepth , int threads ) const
93 {
94  if( threads<=0 ) threads = 1;
95  // The vector of per-depth node spans
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 );
99  int start = 0;
100  int end = 0;
101 
102  if( rootNode ) rootNode->depthAndOffset( minDepth , off ) , start = end = rootNode->nodeData.nodeIndex;
103  else
104  {
105  start = 0;
106  for( minDepth=0 ; minDepth<=this->maxDepth ; minDepth++ ) if( nodeCount[minDepth+1] ){ end = nodeCount[minDepth+1]-1 ; break; }
107  }
108  int nodeCount = 0;
109  for( int d=minDepth ; d<=maxDepth ; d++ )
110  {
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;
114  if( d<maxDepth )
115  {
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;
121  }
122  }
123 
124  cData.cTable.resize( nodeCount );
125  std::vector< int > count( threads );
126 #ifdef USE_OPENMP
127 #pragma omp parallel for num_threads( threads )
128 #endif
129  for( int t=0 ; t<threads ; t++ )
130  {
131  TreeOctNode::ConstNeighborKey3 neighborKey;
132  neighborKey.set( maxDepth );
133  int offset = nodeCount * t * Cube::CORNERS;
134  count[t] = 0;
135  for( int d=minDepth ; d<=maxDepth ; d++ )
136  {
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++ )
139  {
140  TreeOctNode* node = treeNodes[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++ ) // Iterate over the cell's corners
144  {
145  bool cornerOwner = true;
146  int x , y , z;
147  int ac = Cube::AntipodalCornerIndex( c ); // The index of the node relative to the corner
148  Cube::FactorCornerIndex( c , x , y , z );
149  for( int cc=0 ; cc< int(Cube::CORNERS) ; cc++ ) // Iterate over the corner's cells
150  {
151  int xx , yy , zz;
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 ) )
156  {
157  int _d , _off[3];
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]) )
161  {
162  cornerOwner = false;
163  break;
164  }
165  else fprintf( stderr , "[WARNING] How did we leave the subtree?\n" );
166  }
167  }
168  if( cornerOwner )
169  {
170  const TreeOctNode* n = node;
171  int d = n->depth();
172  do
173  {
174  const TreeOctNode::ConstNeighbors3& neighbors = neighborKey.neighbors[d];
175  // Set all the corner indices at the current depth
176  for( unsigned int cc=0 ; cc<Cube::CORNERS ; cc++ )
177  {
178  int xx , yy , zz;
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;
183  }
184  // If we are not at the root and the parent also has the corner
185  if( d==minDepth || n!=(n->parent->children+c) ) break;
186  n = n->parent;
187  d--;
188  }
189  while( 1 );
190  count[t]++;
191  }
192  }
193  }
194  }
195  }
196  cData.cCount = 0;
197  std::vector< int > offsets( threads+1 );
198  offsets[0] = 0;
199  for( int t=0 ; t<threads ; t++ ) cData.cCount += count[t] , offsets[t+1] = offsets[t] + count[t];
200 
201 #ifdef USE_OPENMP
202 #pragma omp parallel for num_threads( threads )
203 #endif
204  for( int t=0 ; t<threads ; t++ )
205  for( int d=minDepth ; d<=maxDepth ; d++ )
206  {
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++ )
210  {
211  int& idx = cData[ treeNodes[i] ][c];
212  if( idx<0 )
213  {
214  fprintf( stderr , "[ERROR] Found unindexed corner nodes[%d][%u] = %d (%d,%d)\n" , treeNodes[i]->nodeData.nodeIndex , c , idx , minDepth , maxDepth );
215  int _d , _off[3];
216  treeNodes[i]->depthAndOffset( _d , _off );
217  if( rootNode )
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] );
219  else
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 );
222  exit( 0 );
223  }
224  else
225  {
226  int div = idx / ( nodeCount*Cube::CORNERS );
227  int rem = idx % ( nodeCount*Cube::CORNERS );
228  idx = rem + offsets[div];
229  }
230  }
231  }
232 }
233 int SortedTreeNodes::getMaxCornerCount( int depth , int maxDepth , int threads ) const
234 {
235  if( threads<=0 ) threads = 1;
236  int res = 1<<depth;
237  std::vector< std::vector< int > > cornerCount( threads );
238  for( int t=0 ; t<threads ; t++ ) cornerCount[t].resize( res*res*res , 0 );
239 
240 #ifdef USE_OPENMP
241 #pragma omp parallel for num_threads( threads )
242 #endif
243  for( int t=0 ; t<threads ; t++ )
244  {
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++ )
250  {
251  TreeOctNode* node = treeNodes[start+i];
252  int d , off[3];
253  node->depthAndOffset( d , off );
254  if( d<maxDepth && node->children ) continue;
255 
256  const TreeOctNode::ConstNeighbors3& neighbors = neighborKey.getNeighbors( node , depth );
257  for( unsigned int c=0 ; c<Cube::CORNERS ; c++ ) // Iterate over the cell's corners
258  {
259  bool cornerOwner = true;
260  int x , y , z;
261  int ac = Cube::AntipodalCornerIndex( c ); // The index of the node relative to the corner
262  Cube::FactorCornerIndex( c , x , y , z );
263  for( int cc=0 ; cc<int(Cube::CORNERS) ; cc++ ) // Iterate over the corner's cells
264  {
265  int xx , yy , zz;
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 ) )
270  {
271  cornerOwner = false;
272  break;
273  }
274  }
275  if( cornerOwner ) _cornerCount[ ( ( off[0]>>(d-depth) ) * res * res) + ( ( off[1]>>(d-depth) ) * res) + ( off[2]>>(d-depth) ) ]++;
276  }
277  }
278  }
279  int maxCount = 0;
280  for( int i=0 ; i<res*res*res ; i++ )
281  {
282  int c = 0;
283  for( int t=0 ; t<threads ; t++ ) c += cornerCount[t][i];
284  maxCount = std::max< int >( maxCount , c );
285  }
286  return maxCount;
287 }
288 SortedTreeNodes::EdgeIndices& SortedTreeNodes::EdgeTableData::operator[] ( const TreeOctNode* node ) { return eTable[ node->nodeData.nodeIndex + offsets[node->d] ]; }
289 const SortedTreeNodes::EdgeIndices& SortedTreeNodes::EdgeTableData::operator[] ( const TreeOctNode* node ) const { return eTable[ node->nodeData.nodeIndex + offsets[node->d] ]; }
290 SortedTreeNodes::EdgeIndices& SortedTreeNodes::EdgeTableData::edgeIndices( const TreeOctNode* node ) { return eTable[ node->nodeData.nodeIndex + offsets[node->d] ]; }
291 const SortedTreeNodes::EdgeIndices& SortedTreeNodes::EdgeTableData::edgeIndices( const TreeOctNode* node ) const { return eTable[ node->nodeData.nodeIndex + offsets[node->d] ]; }
292 void SortedTreeNodes::setEdgeTable( EdgeTableData& eData , const TreeOctNode* rootNode , int maxDepth , int threads )
293 {
294  if( threads<=0 ) threads = 1;
295  std::vector< std::pair< int , int > > spans( this->maxDepth , std::pair< int , int >( -1 , -1 ) );
296 
297  int minDepth;
298  eData.offsets.resize( this->maxDepth , -1 );
299  int start = 0;
300  int end = 0;
301 
302  if( rootNode ) minDepth = rootNode->depth() , start = end = rootNode->nodeData.nodeIndex;
303  else
304  {
305  start = 0;
306  for( minDepth=0 ; minDepth<=this->maxDepth ; minDepth++ ) if( nodeCount[minDepth+1] ){ end = nodeCount[minDepth+1]-1 ; break; }
307  }
308 
309  int nodeCount = 0;
310  {
311  for( int d=minDepth ; d<=maxDepth ; d++ )
312  {
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;
316  if( d<maxDepth )
317  {
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;
323  }
324  }
325  }
326  eData.eTable.resize( nodeCount );
327  std::vector< int > count( threads );
328 
329 #ifdef USE_OPENMP
330 #pragma omp parallel for num_threads( threads )
331 #endif
332  for( int t=0 ; t<threads ; t++ )
333  {
334  TreeOctNode::ConstNeighborKey3 neighborKey;
335  neighborKey.set( maxDepth );
336  int offset = nodeCount * t * Cube::EDGES;
337  count[t] = 0;
338  for( int d=minDepth ; d<=maxDepth ; d++ )
339  {
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++ )
342  {
343  TreeOctNode* node = treeNodes[i];
344  const TreeOctNode::ConstNeighbors3& neighbors = neighborKey.getNeighbors( node , minDepth );
345 
346  for( unsigned int e=0 ; e<Cube::EDGES ; e++ )
347  {
348  bool edgeOwner = true;
349  int o , i , j;
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++ )
353  {
354  int ii = 0;
355  int jj = 0;
356  int x = 0;
357  int y = 0;
358  int z = 0;
359 
360  Square::FactorCornerIndex( cc , ii , jj );
361  ii += i , jj += j;
362  switch( o )
363  {
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;
367  }
368  if( neighbors.neighbors[x][y][z] && neighbors.neighbors[x][y][z]->nodeData.nodeIndex!=-1 && cc<ac ) { edgeOwner = false ; break; }
369  }
370  if( edgeOwner )
371  {
372  // Set all edge indices
373  for( unsigned int cc=0 ; cc<Square::CORNERS ; cc++ )
374  {
375  int ii = 0;
376  int jj = 0;
377  int aii = 0;
378  int ajj = 0;
379  int x = 0;
380  int y = 0;
381  int z = 0;
382 
383  Square::FactorCornerIndex( cc , ii , jj );
384  Square::FactorCornerIndex( Square::AntipodalCornerIndex( cc ) , aii , ajj );
385  ii += i , jj += j;
386  switch( o )
387  {
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;
391  }
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;
394  }
395  count[t]++;
396  }
397  }
398  }
399  }
400  }
401  eData.eCount = 0;
402  std::vector< int > offsets( threads+1 );
403  offsets[0] = 0;
404  for( int t=0 ; t<threads ; t++ ) eData.eCount += count[t] , offsets[t+1] = offsets[t] + count[t];
405 
406 #ifdef USE_OPENMP
407 #pragma omp parallel for num_threads( threads )
408 #endif
409  for( int t=0 ; t<threads ; t++ )
410  for( int d=minDepth ; d<=maxDepth ; d++ )
411  {
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++ )
415  {
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 );
418  else
419  {
420  int div = idx / ( nodeCount*Cube::EDGES );
421  int rem = idx % ( nodeCount*Cube::EDGES );
422  idx = rem + offsets[div];
423  }
424  }
425  }
426 }
427 int SortedTreeNodes::getMaxEdgeCount( const TreeOctNode* rootNode , int depth , int threads ) const
428 {
429  if( threads<=0 ) threads = 1;
430  int res = 1<<depth;
431  std::vector< std::vector< int > > edgeCount( threads );
432  for( int t=0 ; t<threads ; t++ ) edgeCount[t].resize( res*res*res , 0 );
433 
434 #ifdef USE_OPENMP
435 #pragma omp parallel for num_threads( threads )
436 #endif
437  for( int t=0 ; t<threads ; t++ )
438  {
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++ )
444  {
445  TreeOctNode* node = treeNodes[start+i];
446  const TreeOctNode::ConstNeighbors3& neighbors = neighborKey.getNeighbors( node , depth );
447  int d , off[3];
448  node->depthAndOffset( d , off );
449 
450  for( unsigned int e=0 ; e<Cube::EDGES ; e++ )
451  {
452  bool edgeOwner = true;
453  int o , i , j;
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++ )
457  {
458  int ii = 0;
459  int jj = 0;
460  int x = 0;
461  int y = 0;
462  int z = 0;
463 
464  Square::FactorCornerIndex( cc , ii , jj );
465  ii += i , jj += j;
466  switch( o )
467  {
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;
471  }
472  if( neighbors.neighbors[x][y][z] && neighbors.neighbors[x][y][z]->nodeData.nodeIndex!=-1 && cc<ac ) { edgeOwner = false ; break; }
473  }
474  if( edgeOwner ) _edgeCount[ ( ( off[0]>>(d-depth) ) * res * res) + ( ( off[1]>>(d-depth) ) * res) + ( off[2]>>(d-depth) ) ]++;
475  }
476  }
477  }
478  int maxCount = 0;
479  for( int i=0 ; i<res*res*res ; i++ )
480  {
481  int c = 0;
482  for( int t=0 ; t<threads ; t++ ) c += edgeCount[t][i];
483  maxCount = std::max< int >( maxCount , c );
484  }
485  return maxCount;
486 }
487 
488 
489 
491 // TreeNodeData //
493 TreeNodeData::TreeNodeData( void )
494 {
495  nodeIndex = -1;
496  centerWeightContribution=0;
497  normalIndex = -1;
498  constraint = solution = 0;
499  pointIndex = -1;
500 }
501 TreeNodeData::~TreeNodeData( void ) { }
502 
503 
505 // Octree //
507 template< int Degree > double Octree< Degree >::maxMemoryUsage=0;
508 
509 template<int Degree>
510 double Octree<Degree>::MemoryUsage(void)
511 {
512  double mem = double( MemoryInfo::Usage() ) / (1<<20);
513  if( mem>maxMemoryUsage ) maxMemoryUsage=mem;
514  return mem;
515 }
516 
517 template<int Degree>
519 {
520  threads = 1;
521  radius = 0;
522  width = 0;
523  postDerivativeSmooth = 0;
524  _minDepth = 0;
525  _constrainValues = false;
526  _boundaryType = 0;
527  _scale = Real(0);
528  normals = NULL;
529 }
530 
531 template< int Degree >
532 bool Octree< Degree >::_IsInset( const TreeOctNode* node )
533 {
534  int d , off[3];
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 );
538 }
539 template< int Degree >
541 {
542  int d , off[3];
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 );
546 }
547 
548 template<int Degree>
549 int Octree<Degree>::SplatOrientedPoint( TreeOctNode* node , const Point3D<Real>& position , const Point3D<Real>& normal , TreeOctNode::NeighborKey3& neighborKey )
550 {
551  double x , dxdy , dxdydz , dx[DIMENSION][SPLAT_ORDER+1];
552  double width;
553  int off[3];
554  TreeOctNode::Neighbors3& neighbors = neighborKey.setNeighbors( node );
555  Point3D<Real> center;
556  Real w;
557  node->centerAndWidth( center , w );
558  width=w;
559  for( int i=0 ; i<3 ; i++ )
560  {
561 #if SPLAT_ORDER==2
562  off[i] = 0;
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;
567 
568  dx[i][2] = 1. - dx[i][1] - dx[i][0];
569 #elif SPLAT_ORDER==1
570  x = ( position[i] - center[i] ) / width;
571  if( x<0 )
572  {
573  off[i] = 0;
574  dx[i][0] = -x;
575  }
576  else
577  {
578  off[i] = 1;
579  dx[i][0] = 1. - x;
580  }
581  dx[i][1] = 1. - dx[i][0];
582 #elif SPLAT_ORDER==0
583  off[i] = 1;
584  dx[i][0] = 1.;
585 #else
586 # error Splat order not supported
587 #endif // SPLAT_ORDER
588  }
589  for( int i=off[0] ; i<=off[0]+SPLAT_ORDER ; i++ ) for( int j=off[1] ; j<=off[1]+SPLAT_ORDER ; j++ )
590  {
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] )
594  {
595  dxdydz = dxdy * dx[2][k];
596  TreeOctNode* _node = neighbors.neighbors[i][j][k];
597  int idx =_node->nodeData.normalIndex;
598  if( idx<0 )
599  {
600  Point3D<Real> n;
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);
605  }
606  (*normals)[idx] += normal * Real( dxdydz );
607  }
608  }
609  return 0;
610 }
611 template< int Degree >
612 Real Octree< Degree >::SplatOrientedPoint( const Point3D<Real>& position , const Point3D<Real>& normal , TreeOctNode::NeighborKey3& neighborKey3 , TreeOctNode::NeighborKey5& neighborKey5 , int splatDepth , Real samplesPerNode , int minDepth , int maxDepth )
613 {
614  double dx;
615  Point3D<Real> n;
616  TreeOctNode* temp;
617  double width;
618  Point3D< Real > myCenter( Real(0.5) , Real(0.5) , Real(0.5) );
619  Real myWidth = Real(1.0);
620 
621  temp = &tree;
622  while( temp->depth()<splatDepth )
623  {
624  if( !temp->children )
625  {
626  fprintf( stderr , "Octree<Degree>::SplatOrientedPoint error\n" );
627  return -1;
628  }
629  int cIndex=TreeOctNode::CornerIndex(myCenter,position);
630  temp=&temp->children[cIndex];
631  myWidth/=2;
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;
638  }
639  Real weight , depth;
640  GetSampleDepthAndWeight( temp , position , neighborKey3 , samplesPerNode , depth , weight );
641 
642  if( depth<minDepth ) depth = Real(minDepth);
643  if( depth>maxDepth ) depth = Real(maxDepth);
644  int topDepth=int(ceil(depth));
645 
646  dx = 1.0-(topDepth-depth);
647  if( topDepth<=minDepth )
648  {
649  topDepth=minDepth;
650  dx=1;
651  }
652  else if( topDepth>maxDepth )
653  {
654  topDepth=maxDepth;
655  dx=1;
656  }
657  while( temp->depth()>topDepth ) temp=temp->parent;
658  while( temp->depth()<topDepth )
659  {
660  if(!temp->children) temp->initChildren();
661  int cIndex = TreeOctNode::CornerIndex(myCenter,position);
662  temp = &temp->children[cIndex];
663  myWidth/=2;
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;
670  }
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 )
675  {
676  dx = Real(1.0-dx);
677  temp = temp->parent;
678  width = 1.0 / ( 1<<temp->depth() );
679  n = normal * weight / Real( width*width*width ) * Real( dx );
680  SplatOrientedPoint( temp , position , n , neighborKey5 );
681  }
682  return weight;
683 }
684 template<int Degree>
685 int Octree<Degree>::SplatOrientedPoint( TreeOctNode* node , const Point3D<Real>& position , const Point3D<Real>& normal , TreeOctNode::NeighborKey5& neighborKey )
686 {
687  double x , dxdy , dxdydz , dx[DIMENSION][SPLAT_ORDER+1];
688  double width;
689  int off[3];
690  TreeOctNode::Neighbors5& neighbors = neighborKey.setNeighbors( node );
691  Point3D< Real > center;
692  Real w;
693  node->centerAndWidth( center , w );
694  width=w;
695  for( int i=0 ; i<3 ; i++ )
696  {
697 #if SPLAT_ORDER==2
698  off[i] = 0;
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;
703 
704  dx[i][2] = 1. - dx[i][1] - dx[i][0];
705 #elif SPLAT_ORDER==1
706  x = ( position[i] - center[i] ) / width;
707  if( x<0 )
708  {
709  off[i] = 0;
710  dx[i][0] = -x;
711  }
712  else
713  {
714  off[i] = 1;
715  dx[i][0] = 1. - x;
716  }
717  dx[i][1] = 1. - dx[i][0];
718 #elif SPLAT_ORDER==0
719  off[i] = 1;
720  dx[i][0] = 1.;
721 #else
722 # error Splat order not supported
723 #endif // SPLAT_ORDER
724  }
725  for( int i=off[0] ; i<=off[0]+SPLAT_ORDER ; i++ ) for( int j=off[1] ; j<=off[1]+SPLAT_ORDER ; j++ )
726  {
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] )
730  {
731  dxdydz = dxdy * dx[2][k];
732  TreeOctNode* _node = neighbors.neighbors[i+1][j+1][k+1];
733  int idx =_node->nodeData.normalIndex;
734  if( idx<0 )
735  {
736  Point3D<Real> n;
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);
741  }
742  (*normals)[idx] += normal * Real( dxdydz );
743  }
744  }
745  return 0;
746 }
747 template< int Degree >
748 Real Octree< Degree >::SplatOrientedPoint( const Point3D<Real>& position , const Point3D<Real>& normal , TreeOctNode::NeighborKey3& neighborKey , int splatDepth , Real samplesPerNode , int minDepth , int maxDepth )
749 {
750  double dx;
751  Point3D<Real> n;
752  TreeOctNode* temp;
753  double width;
754  Point3D< Real > myCenter;
755  Real myWidth;
756  myCenter[0] = myCenter[1] = myCenter[2] = Real(0.5);
757  myWidth = Real(1.0);
758 
759  temp = &tree;
760  while( temp->depth()<splatDepth )
761  {
762  if( !temp->children )
763  {
764  fprintf( stderr , "Octree<Degree>::SplatOrientedPoint error\n" );
765  return -1;
766  }
767  int cIndex=TreeOctNode::CornerIndex(myCenter,position);
768  temp=&temp->children[cIndex];
769  myWidth/=2;
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;
776  }
777  Real weight , depth;
778  GetSampleDepthAndWeight( temp , position , neighborKey , samplesPerNode , depth , weight );
779 
780  if( depth<minDepth ) depth=Real(minDepth);
781  if( depth>maxDepth ) depth=Real(maxDepth);
782  int topDepth=int(ceil(depth));
783 
784  dx = 1.0-(topDepth-depth);
785  if( topDepth<=minDepth )
786  {
787  topDepth=minDepth;
788  dx=1;
789  }
790  else if( topDepth>maxDepth )
791  {
792  topDepth=maxDepth;
793  dx=1;
794  }
795  while( temp->depth()>topDepth ) temp=temp->parent;
796  while( temp->depth()<topDepth )
797  {
798  if(!temp->children) temp->initChildren();
799  int cIndex=TreeOctNode::CornerIndex(myCenter,position);
800  temp=&temp->children[cIndex];
801  myWidth/=2;
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;
808  }
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 )
813  {
814  dx = Real(1.0-dx);
815  temp = temp->parent;
816  width = 1.0 / ( 1<<temp->depth() );
817 
818  n = normal * weight / Real( pow( width , 3 ) ) * Real( dx );
819  SplatOrientedPoint( temp , position , n , neighborKey );
820  }
821  return weight;
822 }
823 
824 template<int Degree>
825 void Octree<Degree>::GetSampleDepthAndWeight( TreeOctNode* node , const Point3D<Real>& position , TreeOctNode::NeighborKey3& neighborKey , Real samplesPerNode , Real& depth , Real& weight )
826 {
827  TreeOctNode* temp=node;
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))) );
830  else
831  {
832  Real oldWeight , newWeight;
833  oldWeight = newWeight = weight;
834  while( newWeight<samplesPerNode && temp->parent )
835  {
836  temp=temp->parent;
837  oldWeight = newWeight;
838  newWeight = Real(1.0)/GetSampleWeight( temp , position, neighborKey );
839  }
840  depth = Real( temp->depth() + log( newWeight / samplesPerNode ) / log( newWeight / oldWeight ) );
841  }
842  weight = Real( pow( double(1<<(DIMENSION-1)) , -double(depth) ) );
843 }
844 
845 template<int Degree>
846 Real Octree<Degree>::GetSampleWeight( TreeOctNode* node , const Point3D<Real>& position , TreeOctNode::NeighborKey3& neighborKey )
847 {
848  Real weight=0;
849  double x,dxdy,dx[DIMENSION][3];
850  double width;
851  TreeOctNode::Neighbors3& neighbors=neighborKey.setNeighbors( node );
852  Point3D<Real> center;
853  Real w;
854  node->centerAndWidth(center,w);
855  width=w;
856 
857  for( int i=0 ; i<DIMENSION ; i++ )
858  {
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;
863 
864  dx[i][2] = 1.0 - dx[i][1] - dx[i][0];
865  }
866 
867  for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ )
868  {
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 );
872  }
873  return Real( 1.0 / weight );
874 }
875 
876 template<int Degree>
877 int Octree<Degree>::UpdateWeightContribution( TreeOctNode* node , const Point3D<Real>& position , TreeOctNode::NeighborKey3& neighborKey , Real weight )
878 {
879  TreeOctNode::Neighbors3& neighbors = neighborKey.setNeighbors( node );
880  double x , dxdy , dx[DIMENSION][3] , width;
881  Point3D< Real > center;
882  Real w;
883  node->centerAndWidth( center , w );
884  width=w;
885  const double SAMPLE_SCALE = 1. / ( 0.125 * 0.125 + 0.75 * 0.75 + 0.125 * 0.125 );
886 
887  for( int i=0 ; i<DIMENSION ; i++ )
888  {
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];
894  // Note that we are splatting along a co-dimension one manifold, so uniform point samples
895  // do not generate a unit sample weight.
896  dx[i][0] *= SAMPLE_SCALE;
897  }
898 
899  for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ )
900  {
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] );
904  }
905  return 0;
906 }
907 
908 template< int Degree >
910 {
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; }
913  return true;
914 }
915 template< int Degree >
916 int Octree<Degree>::setTree( char* fileName , int maxDepth , int minDepth ,
917  int splatDepth , Real samplesPerNode , Real scaleFactor ,
918  int useConfidence , Real constraintWeight , int adaptiveExponent , XForm4x4< Real > xForm )
919 {
920  if( splatDepth<0 ) splatDepth = 0;
921  XForm3x3< Real > xFormN;
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;
930  Point3D< Real > min , max , myCenter;
931  Real myWidth;
932  int i , cnt=0;
933  TreeOctNode* temp;
934 
935  TreeOctNode::NeighborKey3 neighborKey;
936  neighborKey.set( maxDepth );
937  PointStream< Real >* pointStream;
938 
939  const char ext[] = " ";
940  if ( !strcasecmp( &ext[0] , "bnpts" ) ) pointStream = new BinaryPointStream< Real >( fileName );
941  else pointStream = new ASCIIPointStream< Real >( fileName );
942 
943  tree.setFullDepth( _minDepth );
944  // Read through once to get the center and scale
945  {
946  //double t = Time();
947  Point3D< Real > p , n;
948  while( pointStream->nextPoint( p , n ) )
949  {
950  p = xForm * p;
951  for( i=0 ; i<DIMENSION ; i++ )
952  {
953  if( !cnt || p[i]<min[i] ) min[i] = p[i];
954  if( !cnt || p[i]>max[i] ) max[i] = p[i];
955  }
956  cnt++;
957  }
958 
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;
962  }
963 
964  _scale *= scaleFactor;
965  for( i=0 ; i<DIMENSION ; i++ ) _center[i] -= _scale/2;
966  if( splatDepth>0 )
967  {
968  //double t = Time();
969  cnt = 0;
970  pointStream->reset();
971  Point3D< Real > p , n;
972  while( pointStream->nextPoint( p , n ) )
973  {
974  p = xForm * p , n = xFormN * n;
975  p = ( p - _center ) / _scale;
976  if( !_inBounds(p) ) continue;
977  myCenter = Point3D< Real >( Real(0.5) , Real(0.5) , Real(0.5) );
978  myWidth = Real(1.0);
979  Real weight=Real( 1. );
980  if( useConfidence ) weight = Real( Length(n) );
981  temp = &tree;
982  int d=0;
983  while( d<splatDepth )
984  {
985  UpdateWeightContribution( temp , p , neighborKey , weight );
986  if( !temp->children ) temp->initChildren();
987  int cIndex=TreeOctNode::CornerIndex( myCenter , p );
988  temp = temp->children + cIndex;
989  myWidth/=2;
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;
996  d++;
997  }
998  UpdateWeightContribution( temp , p , neighborKey , weight );
999  cnt++;
1000  }
1001  }
1002 
1003  normals = new std::vector< Point3D<Real> >();
1004  cnt = 0;
1005  pointStream->reset();
1006  Point3D< Real > p , n;
1007  while( pointStream->nextPoint( p , n ) )
1008  {
1009  n *= Real(-1.);
1010  p = xForm * p , n = xFormN * n;
1011  p = ( p - _center ) / _scale;
1012  if( !_inBounds(p) ) continue;
1013  myCenter = Point3D< Real >( Real(0.5) , Real(0.5) , Real(0.5) );
1014  myWidth = Real(1.0);
1015  Real l = Real( Length( n ) );
1016  if( l!=l || l<=EPSILON ) continue;
1017  if( !useConfidence ) n /= l;
1018 
1019  l = Real(1.);
1020  Real pointWeight = Real(1.f);
1021  if( samplesPerNode>0 && splatDepth )
1022  {
1023  pointWeight = SplatOrientedPoint( p , n , neighborKey , splatDepth , samplesPerNode , _minDepth , maxDepth );
1024  }
1025  else
1026  {
1027  temp = &tree;
1028  int d=0;
1029  if( splatDepth )
1030  {
1031  while( d<splatDepth )
1032  {
1033  int cIndex=TreeOctNode::CornerIndex(myCenter,p);
1034  temp = &temp->children[cIndex];
1035  myWidth /= 2;
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;
1042  d++;
1043  }
1044  pointWeight = GetSampleWeight( temp , p , neighborKey );
1045  }
1046  for( i=0 ; i<DIMENSION ; i++ ) n[i] *= pointWeight;
1047  while( d<maxDepth )
1048  {
1049  if( !temp->children ) temp->initChildren();
1050  int cIndex=TreeOctNode::CornerIndex(myCenter,p);
1051  temp=&temp->children[cIndex];
1052  myWidth/=2;
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;
1059  d++;
1060  }
1061  SplatOrientedPoint( temp , p , n , neighborKey );
1062  }
1063  pointWeightSum += pointWeight;
1064  if( _constrainValues )
1065  {
1066  int d = 0;
1067  TreeOctNode* temp = &tree;
1068  myCenter = Point3D< Real >( Real(0.5) , Real(0.5) , Real(0.5) );
1069  myWidth = Real(1.0);
1070  while( 1 )
1071  {
1072  int idx = temp->nodeData.pointIndex;
1073  if( idx==-1 )
1074  {
1075  idx = int( _points.size() );
1076  _points.push_back( PointData( p , Real(1.) ) );
1077  temp->nodeData.pointIndex = idx;
1078  }
1079  else
1080  {
1081  _points[idx].weight += Real(1.);
1082  _points[idx].position += p;
1083  }
1084 
1085  int cIndex = TreeOctNode::CornerIndex( myCenter , p );
1086  if( !temp->children ) break;
1087  temp = &temp->children[cIndex];
1088  myWidth /= 2;
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;
1095  d++;
1096  }
1097  }
1098  cnt++;
1099  }
1100 
1101  if( _boundaryType==0 ) pointWeightSum *= Real(4.);
1102  constraintWeight *= Real( pointWeightSum );
1103  constraintWeight /= cnt;
1104 
1105  MemoryUsage( );
1106  delete pointStream;
1107  if( _constrainValues )
1108  for( TreeOctNode* node=tree.nextNode() ; node ; node=tree.nextNode(node) )
1109  if( node->nodeData.pointIndex!=-1 )
1110  {
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 );
1117  }
1118 #if FORCE_NEUMANN_FIELD
1119  if( _boundaryType==1 )
1120  for( TreeOctNode* node=tree.nextNode() ; node ; node=tree.nextNode( node ) )
1121  {
1122  int d , off[3] , res;
1123  node->depthAndOffset( d , off );
1124  res = 1<<d;
1125  if( node->nodeData.normalIndex<0 ) continue;
1126  Point3D< Real >& normal = (*normals)[node->nodeData.normalIndex];
1127  for( int d=0 ; d<3 ; d++ ) if( off[d]==0 || off[d]==res-1 ) normal[d] = 0;
1128  }
1129 #endif // FORCE_NEUMANN_FIELD
1130  MemoryUsage();
1131  return cnt;
1132 }
1133 
1134 
1135 template< int Degree >
1136 int Octree<Degree>::setTreeMemory( std::vector< Real >& _pts_stream, int maxDepth , int minDepth ,
1137  int splatDepth , Real samplesPerNode , Real scaleFactor ,
1138  int useConfidence , Real constraintWeight , int adaptiveExponent , XForm4x4< Real > xForm )
1139 {
1140  if( splatDepth<0 ) splatDepth = 0;
1141  XForm3x3< Real > xFormN;
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;
1150  Point3D< Real > min , max , myCenter;
1151  Real myWidth;
1152  unsigned int cnt=0;
1153  TreeOctNode* temp;
1154 
1155  TreeOctNode::NeighborKey3 neighborKey;
1156  neighborKey.set( maxDepth );
1157  // PointStream< Real >* pointStream;
1158  // char* ext = GetFileExtension( fileName );
1159  // if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryPointStream< Real >( fileName );
1160  // else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYPointStream< Real >( fileName );
1161  // else pointStream = new ASCIIPointStream< Real >( fileName );
1162  // delete[] ext;
1163 
1164  tree.setFullDepth( _minDepth );
1165  // Read through once to get the center and scale
1166  {
1167  //double t = Time();
1168  Point3D< Real > p , n;
1169 
1170  while ( cnt < _pts_stream.size()/(2*DIMENSION) )
1171  // while( pointStream->nextPoint( p , n ) )
1172  {
1173  for ( int i = 0; i < DIMENSION; ++i )
1174  {
1175  p[i] = _pts_stream[2*DIMENSION*cnt + i];
1176  n[i] = _pts_stream[2*DIMENSION*cnt + DIMENSION + i];
1177  }
1178 
1179  p = xForm * p;
1180  for( int i=0 ; i<DIMENSION ; i++ )
1181  {
1182  if( !cnt || p[i]<min[i] ) min[i] = p[i];
1183  if( !cnt || p[i]>max[i] ) max[i] = p[i];
1184  }
1185  cnt++;
1186  }
1187 
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;
1191  }
1192 
1193  _scale *= scaleFactor;
1194  for( int i=0 ; i<DIMENSION ; i++ ) _center[i] -= _scale/2;
1195 
1196  if( splatDepth>0 )
1197  {
1198  //double t = Time();
1199  cnt = 0;
1200  Point3D< Real > p , n;
1201  while ( cnt < _pts_stream.size()/(2*DIMENSION) )
1202  // while( pointStream->nextPoint( p , n ) )
1203  {
1204  for ( int i = 0; i < DIMENSION; ++i )
1205  {
1206  p[i] = _pts_stream[2*DIMENSION*cnt + i];
1207  n[i] = _pts_stream[2*DIMENSION*cnt + DIMENSION + i];
1208  }
1209 
1210  p = xForm * p , n = xFormN * n;
1211  p = ( p - _center ) / _scale;
1212  if( !_inBounds(p) ) continue;
1213  myCenter = Point3D< Real >( Real(0.5) , Real(0.5) , Real(0.5) );
1214  myWidth = Real(1.0);
1215  Real weight=Real( 1. );
1216  if( useConfidence ) weight = Real( Length(n) );
1217  temp = &tree;
1218  int d=0;
1219  while( d<splatDepth )
1220  {
1221  UpdateWeightContribution( temp , p , neighborKey , weight );
1222  if( !temp->children ) temp->initChildren();
1223  int cIndex=TreeOctNode::CornerIndex( myCenter , p );
1224  temp = temp->children + cIndex;
1225  myWidth/=2;
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;
1232  d++;
1233  }
1234  UpdateWeightContribution( temp , p , neighborKey , weight );
1235  cnt++;
1236  }
1237  }
1238 
1239  normals = new std::vector< Point3D<Real> >();
1240  unsigned int curPt = 0;
1241  cnt = 0;
1242 // pointStream->reset();
1243  Point3D< Real > p , n;
1244  while (curPt < _pts_stream.size()/(2*DIMENSION) )
1245 // while( pointStream->nextPoint( p , n ) )
1246  {
1247  for ( int i = 0; i < DIMENSION; ++i )
1248  {
1249  p[i] = _pts_stream[2*DIMENSION*curPt + i];
1250  n[i] = _pts_stream[2*DIMENSION*curPt + DIMENSION + i];
1251  }
1252 
1253  n *= Real(-1.);
1254  p = xForm * p , n = xFormN * n;
1255  p = ( p - _center ) / _scale;
1256  if (!_inBounds(p))
1257  {
1258  // skip point
1259  ++curPt;
1260  continue;
1261  }
1262  myCenter = Point3D< Real >( Real(0.5) , Real(0.5) , Real(0.5) );
1263  myWidth = Real(1.0);
1264  Real l = Real( Length( n ) );
1265  if (l != l || l <= EPSILON)
1266  {
1267  // skip point
1268  ++curPt;
1269  continue;
1270  }
1271  if( !useConfidence ) n /= l;
1272 
1273  l = Real(1.);
1274  Real pointWeight = Real(1.f);
1275  if( samplesPerNode>0 && splatDepth )
1276  {
1277  pointWeight = SplatOrientedPoint( p , n , neighborKey , splatDepth , samplesPerNode , _minDepth , maxDepth );
1278  }
1279  else
1280  {
1281  temp = &tree;
1282  int d=0;
1283  if( splatDepth )
1284  {
1285  while( d<splatDepth )
1286  {
1287  int cIndex=TreeOctNode::CornerIndex(myCenter,p);
1288  temp = &temp->children[cIndex];
1289  myWidth /= 2;
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;
1296  d++;
1297  }
1298  pointWeight = GetSampleWeight( temp , p , neighborKey );
1299  }
1300  for( int i=0 ; i<DIMENSION ; i++ ) n[i] *= pointWeight;
1301  while( d<maxDepth )
1302  {
1303  if( !temp->children ) temp->initChildren();
1304  int cIndex=TreeOctNode::CornerIndex(myCenter,p);
1305  temp=&temp->children[cIndex];
1306  myWidth/=2;
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;
1313  d++;
1314  }
1315  SplatOrientedPoint( temp , p , n , neighborKey );
1316  }
1317  pointWeightSum += pointWeight;
1318  if( _constrainValues )
1319  {
1320  int d = 0;
1321  TreeOctNode* temp = &tree;
1322  myCenter = Point3D< Real >( Real(0.5) , Real(0.5) , Real(0.5) );
1323  myWidth = Real(1.0);
1324  while( 1 )
1325  {
1326  int idx = temp->nodeData.pointIndex;
1327  if( idx==-1 )
1328  {
1329  idx = int( _points.size() );
1330  _points.push_back( PointData( p , Real(1.) ) );
1331  temp->nodeData.pointIndex = idx;
1332  }
1333  else
1334  {
1335  _points[idx].weight += Real(1.);
1336  _points[idx].position += p;
1337  }
1338 
1339  int cIndex = TreeOctNode::CornerIndex( myCenter , p );
1340  if( !temp->children ) break;
1341  temp = &temp->children[cIndex];
1342  myWidth /= 2;
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;
1349  d++;
1350  }
1351  }
1352  curPt++;
1353  cnt++;
1354  }
1355 
1356  if( _boundaryType==0 ) pointWeightSum *= Real(4.);
1357  constraintWeight *= Real( pointWeightSum );
1358  constraintWeight /= cnt;
1359 
1360  MemoryUsage( );
1361 // delete pointStream;
1362  if( _constrainValues )
1363  for( TreeOctNode* node=tree.nextNode() ; node ; node=tree.nextNode(node) )
1364  if( node->nodeData.pointIndex!=-1 )
1365  {
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 );
1372  }
1373 #if FORCE_NEUMANN_FIELD
1374  if( _boundaryType==1 )
1375  for( TreeOctNode* node=tree.nextNode() ; node ; node=tree.nextNode( node ) )
1376  {
1377  int d , off[3] , res;
1378  node->depthAndOffset( d , off );
1379  res = 1<<d;
1380  if( node->nodeData.normalIndex<0 ) continue;
1381  Point3D< Real >& normal = (*normals)[node->nodeData.normalIndex];
1382  for( int d=0 ; d<3 ; d++ ) if( off[d]==0 || off[d]==res-1 ) normal[d] = 0;
1383  }
1384 #endif // FORCE_NEUMANN_FIELD
1385  MemoryUsage();
1386  return cnt;
1387 }
1388 
1389 
1390 template< int Degree >
1391 void Octree<Degree>::setBSplineData( int maxDepth , int boundaryType )
1392 {
1393  _boundaryType = boundaryType;
1394  if ( _boundaryType<0 ) _boundaryType = -1;
1395  else if( _boundaryType>0 ) _boundaryType = 1;
1396  else maxDepth++;
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 );
1401 }
1402 
1403 template<int Degree>
1404 void Octree<Degree>::finalize( int subdivideDepth )
1405 {
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 ) )
1411  if( node->d==d )
1412  {
1413  int xStart=0 , xEnd=5 , yStart=0 , yEnd=5 , zStart=0 , zEnd=5;
1414  int c = int( node - node->parent->children );
1415  int x , y , z;
1416  Cube::FactorCornerIndex( c , x , y , z );
1417  if( x ) xStart = 1;
1418  else xEnd = 4;
1419  if( y ) yStart = 1;
1420  else yEnd = 4;
1421  if( z ) zStart = 1;
1422  else zEnd = 4;
1423  nKey.setNeighbors( node->parent , xStart , xEnd , yStart , yEnd , zStart , zEnd );
1424  }
1425  refineBoundary( subdivideDepth );
1426 }
1427 template<int Degree>
1428 Real Octree<Degree>::GetLaplacian( const int idx[DIMENSION] ) const
1429 {
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]] ) );
1431 }
1432 template< int Degree >
1433 Real Octree< Degree >::GetLaplacian( const TreeOctNode* node1 , const TreeOctNode* node2 ) const
1434 {
1435  int symIndex[] =
1436  {
1437  BSplineData< Degree , Real >::SymmetricIndex( node1->off[0] , node2->off[0] ) ,
1438  BSplineData< Degree , Real >::SymmetricIndex( node1->off[1] , node2->off[1] ) ,
1439  BSplineData< Degree , Real >::SymmetricIndex( node1->off[2] , node2->off[2] )
1440  };
1441  return GetLaplacian( symIndex );
1442 }
1443 template< int Degree >
1444 Real Octree< Degree >::GetDivergence( const TreeOctNode* node1 , const TreeOctNode* node2 , const Point3D< Real >& normal1 ) const
1445 {
1446  int symIndex[] =
1447  {
1448  BSplineData< Degree , Real >::SymmetricIndex( node1->off[0] , node2->off[0] ) ,
1449  BSplineData< Degree , Real >::SymmetricIndex( node1->off[1] , node2->off[1] ) ,
1450  BSplineData< Degree , Real >::SymmetricIndex( node1->off[2] , node2->off[2] ) ,
1451  };
1452  int aSymIndex[] =
1453  {
1454  #if GRADIENT_DOMAIN_SOLUTION
1455  // Take the dot-product of the vector-field with the gradient of the basis function
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
1460  // Take the dot-product of the divergence of the vector-field with the basis function
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
1465  };
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
1472 }
1473 template< int Degree >
1474 Real Octree< Degree >::GetDivergenceMinusLaplacian( const TreeOctNode* node1 , const TreeOctNode* node2 , Real value1 , const Point3D<Real>& normal1 ) const
1475 {
1476  int symIndex[] =
1477  {
1478  BSplineData< Degree , Real >::SymmetricIndex( node1->off[0] , node2->off[0] ) ,
1479  BSplineData< Degree , Real >::SymmetricIndex( node1->off[1] , node2->off[1] ) ,
1480  BSplineData< Degree , Real >::SymmetricIndex( node1->off[2] , node2->off[2] )
1481  };
1482  int aSymIndex[] =
1483  {
1484  #if GRADIENT_DOMAIN_SOLUTION
1485  // Take the dot-product of the vector-field with the gradient of the basis function
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
1490  // Take the dot-product of the divergence of the vector-field with the basis function
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
1495  };
1496  double dot = fData.vvDotTable[symIndex[0]] * fData.vvDotTable[symIndex[1]] * fData.vvDotTable[symIndex[2]];
1497  return Real( dot *
1498  (
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] )
1502  #else // !GRADIENT_DOMAIN_SOLUTION
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] )
1505  #endif // GRADIENT_DOMAIN_SOLUTION
1506  )
1507  );
1508 }
1509 template< int Degree >
1510 void Octree< Degree >::SetMatrixRowBounds( const TreeOctNode* node , int rDepth , const int rOff[3] , int& xStart , int& xEnd , int& yStart , int& yEnd , int& zStart , int& zEnd ) const
1511 {
1512  xStart = 0 , yStart = 0 , zStart = 0 , xEnd = 5 , yEnd = 5 , zEnd = 5;
1513  int depth , off[3];
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 );
1523 }
1524 template< int Degree >
1525 int Octree< Degree >::GetMatrixRowSize( const OctNode< TreeNodeData , Real >::Neighbors5& neighbors5 ) const { return GetMatrixRowSize( neighbors5 , 0 , 5 , 0 , 5 , 0 , 5 ); }
1526 template< int Degree >
1527 int Octree< Degree >::GetMatrixRowSize( const OctNode< TreeNodeData , Real >::Neighbors5& neighbors5 , int xStart , int xEnd , int yStart , int yEnd , int zStart , int zEnd ) const
1528 {
1529  int count = 0;
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 )
1536  count++;
1537  return count;
1538 }
1539 template< int Degree >
1540 int Octree< Degree >::SetMatrixRow( const OctNode< TreeNodeData , Real >::Neighbors5& neighbors5 , Pointer( MatrixEntry< MatrixReal > ) row , int offset , const double stencil[5][5][5] ) const
1541 {
1542  return SetMatrixRow( neighbors5 , row , offset , stencil , 0 , 5 , 0 , 5 , 0 , 5 );
1543 }
1544 
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
1547 {
1548  bool hasYZPoints[3] , hasZPoints[3][3];
1549  Real diagonal = 0;
1550  Real splineValues[3*3*3*3*3];
1551  memset( splineValues , 0 , sizeof( Real ) * 3 * 3 * 3 * 3 * 3 );
1552 
1553  int count = 0;
1554  const TreeOctNode* node = neighbors5.neighbors[2][2][2];
1555  //int index[] = { int( node->off[0] ) , int( node->off[1] ), int( node->off[2] ) };
1556 
1557  bool isInterior;
1558  int d , off[3];
1559  neighbors5.neighbors[2][2][2]->depthAndOffset( d , off );
1560 
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 );
1564 
1565  if( _constrainValues )
1566  {
1567  int d , idx[3];
1568  node->depthAndOffset( d , idx );
1569  idx[0] = BinaryNode< double >::CenterIndex( d , idx[0] );
1570  idx[1] = BinaryNode< double >::CenterIndex( d , idx[1] );
1571  idx[2] = BinaryNode< double >::CenterIndex( d , idx[2] );
1572  for( int j=0 ; j<3 ; j++ )
1573  {
1574  hasYZPoints[j] = false;
1575  for( int k=0 ; k<3 ; k++ )
1576  {
1577  hasZPoints[j][k] = false;
1578  for( int l=0 ; l<3 ; l++ )
1579  {
1580  const TreeOctNode* _node = neighbors5.neighbors[j+1][k+1][l+1];
1581  if( _node && _node->nodeData.pointIndex!=-1 )
1582  {
1583  const PointData& pData = _points[ _node->nodeData.pointIndex ];
1584  Real* _splineValues = splineValues + 3*3*(3*(3*j+k)+l);
1585  Real weight = pData.weight;
1586  Point3D< Real > p = pData.position;
1587  for( int s=0 ; s<3 ; s++ )
1588  {
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
1598  }
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;
1604  }
1605  }
1606  }
1607  }
1608  }
1609 
1610  Real pointValues[5][5][5];
1611  if( _constrainValues )
1612  {
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++ )
1617  {
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++ )
1624  {
1625  Real splineValue = _splineValuesX[-ii];
1626  for( int jj=0 ; jj<=2 ; jj++ )
1627  {
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];
1631  }
1632  }
1633  }
1634  }
1635  for( int x=xStart ; x<=2 ; x++ )
1636  {
1637  //int minX , maxX ;
1638  //minX = std::max< int >( 0 , -2+x ) , maxX = std::min< int >( 2 , -2+x+2 );
1639  //int dX = 2-x+3*0;
1640  for( int y=yStart ; y<yEnd ; y++ )
1641  {
1642  //int minY;
1643  if( x==2 && y>2 ) continue;
1644  //minY = std::max< int >( 0 , -2+y );// , maxY = std::min< int >( 2 , -2+y+2 );
1645  //int dY = 2-y+3*1;
1646  for( int z=zStart ; z<zEnd ; z++ )
1647  {
1648  if( x==2 && y==2 && z>2 ) continue;
1649  //int dZ = 2-z+3*2;
1650  if( neighbors5.neighbors[x][y][z] && neighbors5.neighbors[x][y][z]->nodeData.nodeIndex>=0 )
1651  {
1652  const TreeOctNode* _node = neighbors5.neighbors[x][y][z];
1653  Real temp;
1654  if( isInterior ) temp = Real( stencil[x][y][z] );
1655  else temp = GetLaplacian( node , _node );
1656  if( _constrainValues )
1657  {
1658  if( x==2 && y==2 && z==2 ) temp += diagonal;
1659  else
1660  {
1661  temp += pointValues[x][y][z];
1662  }
1663  }
1664  if( x==2 && y==2 && z==2 ) temp /= 2;
1665  if( fabs(temp)>MATRIX_ENTRY_EPSILON )
1666  {
1667  row[count].N = _node->nodeData.nodeIndex-offset;
1668  row[count].Value = temp;
1669  count++;
1670  }
1671  }
1672  }
1673  }
1674  }
1675  return count;
1676 }
1677 template< int Degree >
1678 void Octree< Degree >::SetDivergenceStencil( int depth , Point3D< double > stencil[5][5][5] , bool scatter ) const
1679 {
1680  if( depth<2 ) return;
1681  int center = 1<<(depth-1);
1682  int offset[] = { center , center , center };
1683  short d , off[3];
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++ )
1689  {
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] );
1694  int symIndex[] =
1695  {
1696  BSplineData< Degree , Real >::SymmetricIndex( index1[0] , index2[0] ) ,
1697  BSplineData< Degree , Real >::SymmetricIndex( index1[1] , index2[1] ) ,
1698  BSplineData< Degree , Real >::SymmetricIndex( index1[2] , index2[2] ) ,
1699  };
1700  int aSymIndex[] =
1701  {
1702  #if GRADIENT_DOMAIN_SOLUTION
1703  // Take the dot-product of the vector-field with the gradient of the basis function
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
1708  // Take the dot-product of the divergence of the vector-field with the basis function
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
1713  };
1714 
1715  double dot = fData.vvDotTable[symIndex[0]] * fData.vvDotTable[symIndex[1]] * fData.vvDotTable[symIndex[2]];
1716  Point3D<double> forClangSymbolFinder; //clang needs this, otherwise he will fail at the next lines with error message "error: subscript of pointer to incomplete type 'Point3D<double> [5][5]"
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
1726  }
1727 }
1728 template< int Degree >
1729 void Octree< Degree >::SetDivergenceStencils( int depth , Stencil< Point3D< double > , 5 > stencils[2][2][2] , bool scatter ) const
1730 {
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++ )
1735  {
1736  short d , off[3];
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++ )
1742  {
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] );
1747 
1748  int symIndex[] =
1749  {
1750  BSplineData< Degree , Real >::SymmetricIndex( index1[0] , index2[0] ) ,
1751  BSplineData< Degree , Real >::SymmetricIndex( index1[1] , index2[1] ) ,
1752  BSplineData< Degree , Real >::SymmetricIndex( index1[2] , index2[2] ) ,
1753  };
1754  int aSymIndex[] =
1755  {
1756  #if GRADIENT_DOMAIN_SOLUTION
1757  // Take the dot-product of the vector-field with the gradient of the basis function
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
1762  // Take the dot-product of the divergence of the vector-field with the basis function
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
1767  };
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
1778  }
1779  }
1780 }
1781 template< int Degree >
1782 void Octree< Degree >::SetLaplacianStencil( int depth , double stencil[5][5][5] ) const
1783 {
1784  if( depth<2 ) return;
1785  int center = 1<<(depth-1);
1786  int offset[] = { center , center , center };
1787  short d , off[3];
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++ )
1791  {
1792  int _offset[] = { x+center , y+center , z+center };
1793  short _d , _off[3];
1794  TreeOctNode::Index( depth , _offset , _d , _off );
1795  int _index[] = { int( _off[0] ) , int( _off[1] ) , int( _off[2] ) };
1796  int symIndex[3];
1797  symIndex[0] = BSplineData< Degree , Real >::SymmetricIndex( index[0] , _index[0] );
1798  symIndex[1] = BSplineData< Degree , Real >::SymmetricIndex( index[1] , _index[1] );
1799  symIndex[2] = BSplineData< Degree , Real >::SymmetricIndex( index[2] , _index[2] );
1800  stencil[x+2][y+2][z+2] = GetLaplacian( symIndex );
1801  }
1802 }
1803 template< int Degree >
1804 void Octree< Degree >::SetLaplacianStencils( int depth , Stencil< double , 5 > stencils[2][2][2] ) const
1805 {
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++ )
1809  {
1810  short d , off[3];
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++ )
1815  {
1816  int _offset[] = { x+center/2 , y+center/2 , z+center/2 };
1817  short _d , _off[3];
1818  TreeOctNode::Index( depth-1 , _offset , _d , _off );
1819  int _index[] = { int( _off[0] ) , int( _off[1] ) , int( _off[2] ) };
1820  int symIndex[3];
1821  symIndex[0] = BSplineData< Degree , Real >::SymmetricIndex( index[0] , _index[0] );
1822  symIndex[1] = BSplineData< Degree , Real >::SymmetricIndex( index[1] , _index[1] );
1823  symIndex[2] = BSplineData< Degree , Real >::SymmetricIndex( index[2] , _index[2] );
1824  stencils[i][j][k].values[x+2][y+2][z+2] = GetLaplacian( symIndex );
1825  }
1826  }
1827 }
1828 template< int Degree >
1829 void Octree< Degree >::SetEvaluationStencils( int depth , Stencil< Real , 3 > stencil1[8] , Stencil< Real , 3 > stencil2[8][8] ) const
1830 {
1831  if( depth>2 )
1832  {
1833  int idx[3];
1834  int off[] = { 2 , 2 , 2 };
1835  for( int c=0 ; c<8 ; c++ )
1836  {
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++ )
1840  {
1841  short _d , _off[3];
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]) ] );
1845  }
1846  }
1847  }
1848  if( depth>3 )
1849  for( int _c=0 ; _c<8 ; _c++ )
1850  {
1851  int idx[3];
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++ )
1856  {
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++ )
1860  {
1861  short _d , _off[3];
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]) ] );
1865  }
1866  }
1867  }
1868 }
1869 template< int Degree >
1870 void Octree< Degree >::UpdateCoarserSupportBounds( const TreeOctNode* node , int& startX , int& endX , int& startY , int& endY , int& startZ , int& endZ )
1871 {
1872  if( node->parent )
1873  {
1874  int x , y , z , c = int( node - node->parent->children );
1875  Cube::FactorCornerIndex( c , x , y , z );
1876  if( x==0 ) endX = 4;
1877  else startX = 1;
1878  if( y==0 ) endY = 4;
1879  else startY = 1;
1880  if( z==0 ) endZ = 4;
1881  else startZ = 1;
1882  }
1883 }
1884 
1885 template< int Degree >
1886 void Octree< Degree >::UpdateConstraintsFromCoarser( const OctNode< TreeNodeData , Real >::NeighborKey5& neighborKey5 , TreeOctNode* node , Real* metSolution , const Stencil< double , 5 >& lapStencil ) const
1887 {
1888  bool isInterior;
1889  {
1890  int d , off[3];
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 );
1895  }
1896  //Real constraint = Real( 0 );
1897  int depth = node->depth();
1898  if( depth<=_minDepth ) return;
1899  // Offset the constraints using the solution from lower resolutions.
1900  int startX = 0 , endX = 5 , startY = 0 , endY = 5 , startZ = 0 , endZ = 5;
1901  UpdateCoarserSupportBounds( node , startX , endX , startY , endY , startZ , endZ );
1902 
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 )
1906  {
1907  const TreeOctNode* _node = neighbors5.neighbors[x][y][z];
1908  Real _solution = metSolution[ _node->nodeData.nodeIndex ];
1909  {
1910  if( isInterior ) node->nodeData.constraint -= Real( lapStencil.values[x][y][z] * _solution );
1911  else node->nodeData.constraint -= GetLaplacian( _node , node ) * _solution;
1912  }
1913  }
1914  if( _constrainValues )
1915  {
1916  double constraint = 0;
1917  int d , idx[3];
1918  node->depthAndOffset( d, idx );
1919  idx[0] = BinaryNode< double >::CenterIndex( d , idx[0] );
1920  idx[1] = BinaryNode< double >::CenterIndex( d , idx[1] );
1921  idx[2] = BinaryNode< double >::CenterIndex( d , idx[2] );
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 )
1925  {
1926  const PointData& pData = _points[ neighbors5.neighbors[x][y][z]->nodeData.pointIndex ];
1927  Real pointValue = pData.coarserValue;
1928  Point3D< Real > p = pData.position;
1929  constraint +=
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] ) *
1933  pointValue;
1934  }
1935  node->nodeData.constraint -= Real( constraint );
1936  }
1937 }
1938 struct UpSampleData
1939 {
1940  int start;
1941  double v[2];
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; }
1944 };
1945 template< int Degree >
1946 void Octree< Degree >::UpSampleCoarserSolution( int depth , const SortedTreeNodes& sNodes , PoissonVector< Real >& Solution ) const
1947 {
1948  int start = sNodes.nodeCount[depth] , end = sNodes.nodeCount[depth+1] , range = end-start;
1949  Solution.Resize( range );
1950  double cornerValue;
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;
1955  else
1956  {
1957  // For every node at the current depth
1958 #ifdef USE_OPENMP
1959 #pragma omp parallel for num_threads( threads )
1960 #endif
1961  for( int t=0 ; t<threads ; t++ )
1962  {
1963  TreeOctNode::NeighborKey3 neighborKey;
1964  neighborKey.set( depth );
1965  for( int i=start+(range*t)/threads ; i<start+(range*(t+1))/threads ; i++ )
1966  {
1967  int d , off[3];
1968  UpSampleData usData[3];
1969  sNodes.treeNodes[i]->depthAndOffset( d , off );
1970  for( int dd=0 ; dd<3 ; dd++ )
1971  {
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 );
1976  }
1977  neighborKey.getNeighbors( sNodes.treeNodes[i]->parent );
1978  for( int ii=0 ; ii<2 ; ii++ )
1979  {
1980  int _ii = ii + usData[0].start;
1981  double dx = usData[0].v[ii];
1982  for( int jj=0 ; jj<2 ; jj++ )
1983  {
1984  int _jj = jj + usData[1].start;
1985  double dxy = dx * usData[1].v[jj];
1986  for( int kk=0 ; kk<2 ; kk++ )
1987  {
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 );
1992  }
1993  }
1994  }
1995  }
1996  }
1997  }
1998  // Clear the coarser solution
1999  start = sNodes.nodeCount[depth-1] , end = sNodes.nodeCount[depth] , range = end-start;
2000 #ifdef USE_OPENMP
2001 #pragma omp parallel for num_threads( threads )
2002 #endif
2003  for( int i=start ; i<end ; i++ ) sNodes.treeNodes[i]->nodeData.solution = Real( 0. );
2004 }
2005 template< int Degree >
2006 void Octree< Degree >::DownSampleFinerConstraints( int depth , SortedTreeNodes& sNodes ) const
2007 {
2008  double cornerValue;
2009  if ( _boundaryType==-1 ) cornerValue = 0.50;
2010  else if( _boundaryType== 1 ) cornerValue = 1.00;
2011  else cornerValue = 0.75;
2012  if( !depth ) return;
2013 #ifdef USE_OPENMP
2014 #pragma omp parallel for num_threads( threads )
2015 #endif
2016  for( int i=sNodes.nodeCount[depth-1] ; i<sNodes.nodeCount[depth] ; i++ )
2017  sNodes.treeNodes[i]->nodeData.constraint = Real( 0 );
2018 
2019  if( depth==1 )
2020  {
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;
2023  return;
2024  }
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];
2029  // For every node at the current depth
2030 #ifdef USE_OPENMP
2031 #pragma omp parallel for num_threads( threads )
2032 #endif
2033  for( int t=0 ; t<threads ; t++ )
2034  {
2035  TreeOctNode::NeighborKey3 neighborKey;
2036  neighborKey.set( depth );
2037  for( int i=start+(range*t)/threads ; i<start+(range*(t+1))/threads ; i++ )
2038  {
2039  int d , off[3];
2040  UpSampleData usData[3];
2041  sNodes.treeNodes[i]->depthAndOffset( d , off );
2042  for( int d=0 ; d<3 ; d++ )
2043  {
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 );
2048  }
2049  neighborKey.getNeighbors( sNodes.treeNodes[i]->parent );
2050  TreeOctNode::Neighbors3& neighbors = neighborKey.neighbors[depth-1];
2051  for( int ii=0 ; ii<2 ; ii++ )
2052  {
2053  int _ii = ii + usData[0].start;
2054  double dx = usData[0].v[ii];
2055  for( int jj=0 ; jj<2 ; jj++ )
2056  {
2057  int _jj = jj + usData[1].start;
2058  double dxy = dx * usData[1].v[jj];
2059  for( int kk=0 ; kk<2 ; kk++ )
2060  {
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;
2065  }
2066  }
2067  }
2068  }
2069  }
2070 #ifdef USE_OPENMP
2071 #pragma omp parallel for num_threads( threads )
2072 #endif
2073  for( int i=lStart ; i<lEnd ; i++ )
2074  {
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;
2078  }
2079 }
2080 template< int Degree >
2081 template< class C >
2082 void Octree< Degree >::DownSample( int depth , const SortedTreeNodes& sNodes , C* constraints ) const
2083 {
2084  double cornerValue;
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];
2092  // For every node at the current depth
2093 #ifdef USE_OPENMP
2094 #pragma omp parallel for num_threads( threads )
2095 #endif
2096  for( int t=0 ; t<threads ; t++ )
2097  {
2098  TreeOctNode::NeighborKey3 neighborKey;
2099  neighborKey.set( depth );
2100  for( int i=start+(range*t)/threads ; i<start+(range*(t+1))/threads ; i++ )
2101  {
2102  int d , off[3];
2103  UpSampleData usData[3];
2104  sNodes.treeNodes[i]->depthAndOffset( d , off );
2105  for( int d=0 ; d<3 ; d++ )
2106  {
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 );
2111  }
2112  TreeOctNode::Neighbors3& neighbors = neighborKey.getNeighbors( sNodes.treeNodes[i]->parent );
2113  C c = constraints[i];
2114  for( int ii=0 ; ii<2 ; ii++ )
2115  {
2116  int _ii = ii + usData[0].start;
2117  C cx = C( c*usData[0].v[ii] );
2118  for( int jj=0 ; jj<2 ; jj++ )
2119  {
2120  int _jj = jj + usData[1].start;
2121  C cxy = C( cx*usData[1].v[jj] );
2122  for( int kk=0 ; kk<2 ; kk++ )
2123  {
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] );
2128  }
2129  }
2130  }
2131  }
2132  }
2133 #ifdef USE_OPENMP
2134 #pragma omp parallel for num_threads( threads )
2135 #endif
2136  for( int i=lStart ; i<lEnd ; i++ )
2137  {
2138  C cSum = C(0);
2139  for( int t=0 ; t<threads ; t++ ) cSum += _constraints[t][i-lStart];
2140  constraints[i] += cSum;
2141  }
2142 }
2143 template< int Degree >
2144 template< class C >
2145 void Octree< Degree >::UpSample( int depth , const SortedTreeNodes& sNodes , C* coefficients ) const
2146 {
2147  double cornerValue;
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;
2152 
2153  int start = sNodes.nodeCount[depth] , end = sNodes.nodeCount[depth+1] , range = end-start;
2154  // For every node at the current depth
2155 #ifdef USE_OPENMP
2156 #pragma omp parallel for num_threads( threads )
2157 #endif
2158  for( int t=0 ; t<threads ; t++ )
2159  {
2160  TreeOctNode::NeighborKey3 neighborKey;
2161  neighborKey.set( depth-1 );
2162  for( int i=start+(range*t)/threads ; i<start+(range*(t+1))/threads ; i++ )
2163  {
2164  bool isInterior = true;
2165  TreeOctNode* node = sNodes.treeNodes[i];
2166  int d , off[3];
2167  UpSampleData usData[3];
2168  node->depthAndOffset( d , off );
2169  for( int d=0 ; d<3 ; d++ )
2170  {
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 );
2175  }
2176  TreeOctNode::Neighbors3& neighbors = neighborKey.getNeighbors( node->parent );
2177  for( int ii=0 ; ii<2 ; ii++ )
2178  {
2179  int _ii = ii + usData[0].start;
2180  double dx = usData[0].v[ii];
2181  for( int jj=0 ; jj<2 ; jj++ )
2182  {
2183  int _jj = jj + usData[1].start;
2184  double dxy = dx * usData[1].v[jj];
2185  for( int kk=0 ; kk<2 ; kk++ )
2186  {
2187  int _kk = kk + usData[2].start;
2188  TreeOctNode* node = neighbors.neighbors[_ii][_jj][_kk];
2189  if( node && node->nodeData.nodeIndex!=-1 )
2190  {
2191  double dxyz = dxy * usData[2].v[kk];
2192  int _i = node->nodeData.nodeIndex;
2193  coefficients[i] += coefficients[_i] * Real( dxyz );
2194  }
2195  }
2196  }
2197  }
2198  }
2199  }
2200 }
2201 template< int Degree >
2202 void Octree< Degree >::SetCoarserPointValues( int depth , const SortedTreeNodes& sNodes , Real* metSolution )
2203 {
2204  int start = sNodes.nodeCount[depth] , end = sNodes.nodeCount[depth+1] , range = end-start;
2205  // For every node at the current depth
2206 #ifdef USE_OPENMP
2207 #pragma omp parallel for num_threads( threads )
2208 #endif
2209  for( int t=0 ; t<threads ; t++ )
2210  {
2211  TreeOctNode::NeighborKey3 neighborKey;
2212  neighborKey.set( depth );
2213  for( int i=start+(range*t)/threads ; i<start+(range*(t+1))/threads ; i++ )
2214  {
2215  int pIdx = sNodes.treeNodes[i]->nodeData.pointIndex;
2216  if( pIdx!=-1 )
2217  {
2218  neighborKey.getNeighbors( sNodes.treeNodes[i] );
2219  _points[ pIdx ].coarserValue = WeightedCoarserFunctionValue( neighborKey , sNodes.treeNodes[i] , metSolution );
2220  }
2221  }
2222  }
2223 }
2224 template< int Degree >
2225 Real Octree< Degree >::WeightedCoarserFunctionValue( const OctNode< TreeNodeData , Real >::NeighborKey3& neighborKey , const TreeOctNode* pointNode , Real* metSolution ) const
2226 {
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;
2230 
2231  if( (_boundaryType!=0 && depth==0) || (_boundaryType==0 && depth<=2) || pointNode->nodeData.pointIndex==-1 ) return Real(0.);
2232 
2233  Real weight = _points[ pointNode->nodeData.pointIndex ].weight;
2234  Point3D< Real > p = _points[ pointNode->nodeData.pointIndex ].position;
2235 
2236  // Iterate over all basis functions that overlap the point at the coarser resolutions
2237  {
2238  int d , _idx[3];
2239  const TreeOctNode::Neighbors3& neighbors = neighborKey.neighbors[depth-1];
2240  neighbors.neighbors[1][1][1]->depthAndOffset( d , _idx );
2241  _idx[0] = BinaryNode< double >::CenterIndex( d , _idx[0]-1 );
2242  _idx[1] = BinaryNode< double >::CenterIndex( d , _idx[1]-1 );
2243  _idx[2] = BinaryNode< double >::CenterIndex( d , _idx[2]-1 );
2244 
2245  for( int j=0 ; j<3 ; j++ )
2246  {
2247 #if ROBERTO_TOLDO_FIX
2248  double xValue = 0;
2249  if( _idx[0]+j>=0 && _idx[0]+j<((1<<depth)-1) ) xValue = fData.baseBSplines[ _idx[0]+j ][2-j]( p[0] );
2250  else continue;
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++ )
2255  {
2256 #if ROBERTO_TOLDO_FIX
2257  double xyValue = 0;
2258  if( _idx[1]+k>=0 && _idx[1]+k<((1<<depth)-1) ) xyValue = xValue * fData.baseBSplines[ _idx[1]+k ][2-k]( p[1] );
2259  else continue;
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++ )
2265  {
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
2274  }
2275  pointValue += _pointValue * xyValue;
2276  }
2277  }
2278  }
2279  if( _boundaryType==-1 ) pointValue -= Real(0.5);
2280  return Real( pointValue * weight );
2281 }
2282 template< int Degree >
2283 int Octree< Degree >::GetFixedDepthLaplacian( SparseSymmetricMatrix< Real >& matrix , int depth , const SortedTreeNodes& sNodes , Real* metSolution )
2284 {
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 );
2291 #ifdef USE_OPENMP
2292 #pragma omp parallel for num_threads( threads )
2293 #endif
2294  for( int t=0 ; t<threads ; t++ )
2295  {
2296  TreeOctNode::NeighborKey5 neighborKey5;
2297  neighborKey5.set( depth );
2298  for( int i=(range*t)/threads ; i<(range*(t+1))/threads ; i++ )
2299  {
2300  TreeOctNode* node = sNodes.treeNodes[i+start];
2301  neighborKey5.getNeighbors( node );
2302  // Get the matrix row size
2303  bool insetSupported = _boundaryType!=0 || _IsInsetSupported( node );
2304  int count = insetSupported ? GetMatrixRowSize( neighborKey5.neighbors[depth] ) : 1;
2305 
2306  // Allocate memory for the row
2307 #ifdef USE_OPENMP
2308 #pragma omp critical (matrix_set_row_size)
2309 #endif
2310  {
2311  matrix.SetRowSize( i , count );
2312  }
2313 
2314  // Set the row entries
2315  if( insetSupported ) matrix.rowSizes[i] = SetMatrixRow( neighborKey5.neighbors[depth] , matrix[i] , start , stencil );
2316  else
2317  {
2318  matrix[i][0] = MatrixEntry< Real >( i , Real(1) );
2319  matrix.rowSizes[i] = 1;
2320  }
2321 
2322  // Offset the constraints using the solution from lower resolutions.
2323  int x , y , z;
2324  if( node->parent )
2325  {
2326  int c = int( node - node->parent->children );
2327  Cube::FactorCornerIndex( c , x , y , z );
2328  }
2329  else x = y = z = 0;
2330  if( insetSupported ) UpdateConstraintsFromCoarser( neighborKey5 , node , metSolution , stencils[x][y][z] );
2331  }
2332  }
2333  return 1;
2334 }
2335 template<int Degree>
2336 int Octree<Degree>::GetRestrictedFixedDepthLaplacian( SparseSymmetricMatrix< Real >& matrix , int depth , const int* entries , int entryCount ,
2337  const TreeOctNode* rNode , Real radius ,
2338  const SortedTreeNodes& sNodes , Real* metSolution )
2339 {
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 );
2348 #ifdef USE_OPENMP
2349 #pragma omp parallel for num_threads( threads )
2350 #endif
2351  for( int t=0 ; t<threads ; t++ )
2352  {
2353  TreeOctNode::NeighborKey5 neighborKey5;
2354  neighborKey5.set( depth );
2355  for( int i=(entryCount*t)/threads ; i<(entryCount*(t+1))/threads ; i++ )
2356  {
2357  TreeOctNode* node = sNodes.treeNodes[ entries[i] ];
2358  int d , off[3];
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] );
2362 
2363  neighborKey5.getNeighbors( node );
2364 
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 );
2367 
2368  // Get the matrix row size
2369  bool insetSupported = _boundaryType!=0 || _IsInsetSupported( node );
2370  int count = insetSupported ? GetMatrixRowSize( neighborKey5.neighbors[depth] , xStart , xEnd , yStart , yEnd , zStart , zEnd ) : 1;
2371 
2372  // Allocate memory for the row
2373 #ifdef USE_OPENMP
2374 #pragma omp critical (matrix_set_row_size)
2375 #endif
2376  {
2377  matrix.SetRowSize( i , count );
2378  }
2379 
2380  // Set the matrix row entries
2381  if( insetSupported ) matrix.rowSizes[i] = SetMatrixRow( neighborKey5.neighbors[depth] , matrix[i] , 0 , stencil , xStart , xEnd , yStart , yEnd , zStart , zEnd );
2382  else
2383  {
2384  matrix[i][0] = MatrixEntry< Real >( i , Real(1) );
2385  matrix.rowSizes[i] = 1;
2386  }
2387 
2388  // Adjust the system constraints
2389  int x , y , z ;
2390  if( node->parent )
2391  {
2392  int c = int( node - node->parent->children );
2393  Cube::FactorCornerIndex( c , x , y , z );
2394  }
2395  else x = y = z = 0;
2396  if( insetSupported ) UpdateConstraintsFromCoarser( neighborKey5 , node , metSolution , stencils[x][y][z] );
2397  }
2398  }
2399  for( int i=0 ; i<entryCount ; i++ ) sNodes.treeNodes[entries[i]]->nodeData.nodeIndex = entries[i];
2400  return 1;
2401 }
2402 
2403 template<int Degree>
2404 int Octree<Degree>::LaplacianMatrixIteration( int subdivideDepth , bool showResidual , int minIters , double accuracy , int maxSolveDepth , int fixedIters )
2405 {
2406  int iter=0;
2407  fData.setDotTables( fData.DD_DOT_FLAG | fData.DV_DOT_FLAG , _boundaryType==0 );
2408  if( _boundaryType==0 ) subdivideDepth++ , maxSolveDepth++;
2409 
2410  _sNodes.treeNodes[0]->nodeData.solution = 0;
2411 
2412  std::vector< Real > metSolution( _sNodes.nodeCount[ _sNodes.maxDepth ] , 0 );
2413  for( int d=(_boundaryType==0?2:0) ; d<_sNodes.maxDepth ; d++ )
2414  {
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 );
2418  }
2419  fData.clearDotTables( fData.VV_DOT_FLAG | fData.DV_DOT_FLAG | fData.DD_DOT_FLAG );
2420 
2421  return iter;
2422 }
2423 
2424 template<int Degree>
2425 int Octree< Degree >::_SolveFixedDepthMatrix( int depth , const SortedTreeNodes& sNodes , Real* metSolution , bool showResidual , int minIters , double accuracy , bool noSolve , int fixedIters )
2426 {
2427  double _maxMemoryUsage = maxMemoryUsage;
2428  maxMemoryUsage = 0;
2429  int iter = 0;
2430  PoissonVector< Real > X , B;
2432  double systemTime=0. , solveTime=0. , evaluateTime = 0.; //, updateTime=0.
2433  X.Resize( sNodes.nodeCount[depth+1]-sNodes.nodeCount[depth] );
2434  if( depth<=_minDepth ) UpSampleCoarserSolution( depth , sNodes , X );
2435  else
2436  {
2437  // Up-sample the cumulative solution into the previous depth
2438  UpSample( depth-1 , sNodes , metSolution );
2439  // Add in the solution from that depth
2440  if( depth )
2441 #ifdef USE_OPENMP
2442 #pragma omp parallel for num_threads( threads )
2443 #endif
2444  for( int i=_sNodes.nodeCount[depth-1] ; i<_sNodes.nodeCount[depth] ; i++ ) metSolution[i] += _sNodes.treeNodes[i]->nodeData.solution;
2445  }
2446  if( _constrainValues )
2447  {
2448  evaluateTime = Time();
2449  SetCoarserPointValues( depth , sNodes , metSolution );
2450  evaluateTime = Time() - evaluateTime;
2451  }
2452 
2453  systemTime = Time();
2454  {
2455  // Get the system matrix
2456  GetFixedDepthLaplacian( M , depth , sNodes , metSolution );
2457  // Set the constraint vector
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);
2462  }
2463  systemTime = Time()-systemTime;
2464 
2465 
2466  solveTime = Time();
2467  // Solve the linear system
2468  Real _accuracy = Real( accuracy / 100000 ) * M.rows;
2469  int res = 1<<depth;
2470 
2471  MapReduceVector< Real > mrVector;
2472  mrVector.resize( threads , M.rows );
2473 
2474  if( _boundaryType==0 && depth>3 ) res -= 1<<(depth-2);
2475  if( !noSolve )
2476  {
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 );
2479  }
2480  solveTime = Time()-solveTime;
2481  if( showResidual )
2482  {
2483  double mNorm = 0;
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 );
2487  }
2488 
2489  // Copy the solution back into the tree (over-writing the constraints)
2490  for( int i=sNodes.nodeCount[depth] ; i<sNodes.nodeCount[depth+1] ; i++ ) sNodes.treeNodes[i]->nodeData.solution = Real( X[i-sNodes.nodeCount[depth]] );
2491 
2492  MemoryUsage();
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 );
2495  return iter;
2496 }
2497 template<int Degree>
2498 int Octree<Degree>::_SolveFixedDepthMatrix( int depth , const SortedTreeNodes& sNodes , Real* metSolution , int startingDepth , bool showResidual , int minIters , double accuracy , bool noSolve , int fixedIters )
2499 {
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;
2504  PoissonVector< Real > B , _B , _X;
2505  AdjacencySetFunction asf;
2506  AdjacencyCountFunction acf;
2507  double systemTime = 0 , solveTime = 0 , memUsage = 0 , evaluateTime = 0 , gTime , sTime;
2508  Real myRadius;
2509 
2510  if( depth>_minDepth )
2511  {
2512  // Up-sample the cumulative solution into the previous depth
2513  UpSample( depth-1 , sNodes , metSolution );
2514  // Add in the solution from that depth
2515  if( depth )
2516 #ifdef USE_OPENMP
2517 #pragma omp parallel for num_threads( threads )
2518 #endif
2519  for( int i=_sNodes.nodeCount[depth-1] ; i<_sNodes.nodeCount[depth] ; i++ ) metSolution[i] += _sNodes.treeNodes[i]->nodeData.solution;
2520  }
2521 
2522  if( _constrainValues )
2523  {
2524  evaluateTime = Time();
2525  SetCoarserPointValues( depth , sNodes , metSolution );
2526  evaluateTime = Time() - evaluateTime;
2527  }
2528  B.Resize( sNodes.nodeCount[depth+1] - sNodes.nodeCount[depth] );
2529 
2530  // Back-up the constraints
2531  for( i=sNodes.nodeCount[depth] ; i<sNodes.nodeCount[depth+1] ; i++ )
2532  {
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;
2536  }
2537 
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++ )
2545  {
2546  // Count the number of nodes at depth "depth" that lie under sNodes.treeNodes[i]
2547  acf.adjacencyCount = 0;
2548  for( TreeOctNode* temp=sNodes.treeNodes[i]->nextNode() ; temp ; )
2549  {
2550  if( temp->depth()==depth ) acf.adjacencyCount++ , temp = sNodes.treeNodes[i]->nextBranch( temp );
2551  else temp = sNodes.treeNodes[i]->nextNode ( temp );
2552  }
2553  for( j=sNodes.nodeCount[d] ; j<sNodes.nodeCount[d+1] ; j++ )
2554  {
2555  if( i==j ) continue;
2556  TreeOctNode::ProcessFixedDepthNodeAdjacentNodes( fData.depth , sNodes.treeNodes[i] , 1 , sNodes.treeNodes[j] , 2*width-1 , depth , &acf );
2557  }
2558  subDimension[i-sNodes.nodeCount[d]] = acf.adjacencyCount;
2559  maxDimension = std::max< int >( maxDimension , subDimension[i-sNodes.nodeCount[d]] );
2560  }
2561  asf.adjacencies = new int[maxDimension];
2562  MapReduceVector< Real > mrVector;
2563  mrVector.resize( threads , maxDimension );
2564  // Iterate through the coarse-level nodes
2565  for( i=sNodes.nodeCount[d] ; i<sNodes.nodeCount[d+1] ; i++ )
2566  {
2567  int iter = 0;
2568  gTime = Time();
2569  // Count the number of nodes at depth "depth" that lie under sNodes.treeNodes[i]
2570  acf.adjacencyCount = subDimension[i-sNodes.nodeCount[d]];
2571  if( !acf.adjacencyCount ) continue;
2572 
2573  // Set the indices for the nodes under, or near, sNodes.treeNodes[i].
2574  asf.adjacencyCount = 0;
2575  for( TreeOctNode* temp=sNodes.treeNodes[i]->nextNode() ; temp ; )
2576  {
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 );
2579  }
2580  for( j=sNodes.nodeCount[d] ; j<sNodes.nodeCount[d+1] ; j++ )
2581  {
2582  if( i==j ) continue;
2583  TreeOctNode::ProcessFixedDepthNodeAdjacentNodes( fData.depth , sNodes.treeNodes[i] , 1 , sNodes.treeNodes[j] , 2*width-1 , depth , &asf );
2584  }
2585 
2586  // Get the associated constraint vector
2587  _B.Resize( asf.adjacencyCount );
2588  for( j=0 ; j<asf.adjacencyCount ; j++ ) _B[j] = B[ asf.adjacencies[j]-sNodes.nodeCount[depth] ];
2589 
2590  _X.Resize( asf.adjacencyCount );
2591 #ifdef USE_OPENMP
2592 #pragma omp parallel for num_threads( threads ) schedule( static )
2593 #endif
2594  for( j=0 ; j<asf.adjacencyCount ; j++ ) _X[j] = sNodes.treeNodes[ asf.adjacencies[j] ]->nodeData.solution;
2595  // Get the associated matrix
2596  GetRestrictedFixedDepthLaplacian( _M , depth , asf.adjacencies , asf.adjacencyCount , sNodes.treeNodes[i] , myRadius , sNodes , metSolution );
2597 #ifdef USE_OPENMP
2598 #pragma omp parallel for num_threads( threads ) schedule( static )
2599 #endif
2600  for( j=0 ; j<asf.adjacencyCount ; j++ )
2601  {
2602  _B[j] += sNodes.treeNodes[asf.adjacencies[j]]->nodeData.constraint;
2603  sNodes.treeNodes[ asf.adjacencies[j] ]->nodeData.constraint = 0;
2604  }
2605  gTime = Time()-gTime;
2606 
2607  // Solve the matrix
2608  // Since we don't have the full matrix, the system shouldn't be singular, so we shouldn't have to correct it
2609  sTime=Time();
2610  Real _accuracy = Real( accuracy / 100000 ) * _M.rows;
2611  if( !noSolve )
2612  {
2613  if( fixedIters>=0 ) iter += SparseSymmetricMatrix< Real >::Solve( _M , _B , fixedIters , _X , mrVector , Real(1e-10) , 0 );
2614  else iter += SparseSymmetricMatrix< Real >::Solve( _M , _B , std::max< int >( int( pow( _M.rows , ITERATION_POWER ) ) , minIters ) , _X , mrVector , _accuracy , 0 );
2615  }
2616  sTime=Time()-sTime;
2617 
2618  if( showResidual )
2619  {
2620  double mNorm = 0;
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 );
2624  }
2625 
2626  // Update the solution for all nodes in the sub-tree
2627 #ifdef USE_OPENMP
2628 #pragma omp parallel for num_threads( threads )
2629 #endif
2630  for( j=0 ; j<asf.adjacencyCount ; j++ )
2631  {
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] );
2635  }
2636  systemTime += gTime;
2637  solveTime += sTime;
2638  memUsage = std::max< double >( MemoryUsage() , memUsage );
2639  tIter += iter;
2640  }
2641  delete[] asf.adjacencies;
2642  MemoryUsage();
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 );
2645  return tIter;
2646 }
2647 template<int Degree>
2648 int Octree<Degree>::HasNormals(TreeOctNode* node,Real epsilon)
2649 {
2650  int hasNormals=0;
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);
2653 
2654  return hasNormals;
2655 }
2656 template<int Degree>
2657 void Octree<Degree>::ClipTree( void )
2658 {
2659  int maxDepth = tree.maxDepth();
2660  for( TreeOctNode* temp=tree.nextNode() ; temp ; temp=tree.nextNode(temp) )
2661  if( temp->children && temp->d>=_minDepth )
2662  {
2663  int hasNormals=0;
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;
2666  }
2667  MemoryUsage();
2668 }
2669 template<int Degree>
2671 {
2672  // To set the Laplacian constraints, we iterate over the
2673  // splatted normals and compute the dot-product of the
2674  // divergence of the normal field with all the basis functions.
2675  // Within the same depth: set directly as a gather
2676  // Coarser depths
2677  fData.setDotTables( fData.VV_DOT_FLAG | fData.DV_DOT_FLAG , _boundaryType==0 );
2678  int maxDepth = _sNodes.maxDepth-1;
2679  Point3D< Real > zeroPoint;
2680  zeroPoint[0] = zeroPoint[1] = zeroPoint[2] = 0;
2681  std::vector< Real > constraints( _sNodes.nodeCount[maxDepth] , Real(0) );
2682 
2683  // Clear the constraints
2684 #ifdef USE_OPENMP
2685 #pragma omp parallel for num_threads( threads )
2686 #endif
2687  for( int i=0 ; i<_sNodes.nodeCount[maxDepth+1] ; i++ ) _sNodes.treeNodes[i]->nodeData.constraint = Real( 0. );
2688 
2689  for( int d=maxDepth ; d>=(_boundaryType==0?2:0) ; d-- )
2690  {
2691  // For the scattering part of the operation, we parallelize by duplicating the constraints and then summing at the end.
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 );
2696  Point3D< double > stencil[5][5][5];
2697  SetDivergenceStencil( d , stencil , false );
2698  Stencil< Point3D< double > , 5 > stencils[2][2][2];
2699  SetDivergenceStencils( d , stencils , true );
2700 #ifdef USE_OPENMP
2701 #pragma omp parallel for num_threads( threads )
2702 #endif
2703  for( int t=0 ; t<threads ; t++ )
2704  {
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++ )
2709  {
2710  TreeOctNode* node = _sNodes.treeNodes[i];
2711  int startX=0 , endX=5 , startY=0 , endY=5 , startZ=0 , endZ=5;
2712  int depth = node->depth();
2713  neighborKey5.getNeighbors( node );
2714 
2715  bool isInterior , isInterior2;
2716  {
2717  int d , off[3];
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 );
2722  mn += 2 , mx -= 2;
2723  isInterior2 = ( off[0]>=mn && off[0]<mx && off[1]>=mn && off[1]<mx && off[2]>=mn && off[2]<mx );
2724  }
2725  int cx , cy , cz;
2726  if( d )
2727  {
2728  int c = int( node - node->parent->children );
2729  Cube::FactorCornerIndex( c , cx , cy , cz );
2730  }
2731  else cx = cy = cz = 0;
2732  Stencil< Point3D< double > , 5 >& _stencil = stencils[cx][cy][cz];
2733 
2734  // Set constraints from current depth
2735  {
2736  const TreeOctNode::Neighbors5& neighbors5 = neighborKey5.neighbors[depth];
2737 
2738  if( isInterior )
2739  for( int x=startX ; x<endX ; x++ ) for( int y=startY ; y<endY ; y++ ) for( int z=startZ ; z<endZ ; z++ )
2740  {
2741  const TreeOctNode* _node = neighbors5.neighbors[x][y][z];
2742  if( _node && _node->nodeData.normalIndex>=0 )
2743  {
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] );
2746  }
2747  }
2748  else
2749  for( int x=startX ; x<endX ; x++ ) for( int y=startY ; y<endY ; y++ ) for( int z=startZ ; z<endZ ; z++ )
2750  {
2751  const TreeOctNode* _node = neighbors5.neighbors[x][y][z];
2752  if( _node && _node->nodeData.normalIndex>=0 )
2753  {
2754  const Point3D< Real >& _normal = (*normals)[_node->nodeData.normalIndex];
2755  node->nodeData.constraint += GetDivergence( _node , node , _normal );
2756  }
2757  }
2758  UpdateCoarserSupportBounds( neighbors5.neighbors[2][2][2] , startX , endX , startY , endY , startZ , endZ );
2759  }
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;
2763 
2764  if( depth )
2765  {
2766  const TreeOctNode::Neighbors5& neighbors5 = neighborKey5.neighbors[depth-1];
2767 
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 )
2770  {
2771  TreeOctNode* _node = neighbors5.neighbors[x][y][z];
2772  if( isInterior2 )
2773  {
2774  Point3D< double >& div = _stencil.values[x][y][z];
2775  _constraints[t][ _node->nodeData.nodeIndex-offset ] += Real( div[0] * normal[0] + div[1] * normal[1] + div[2] * normal[2] );
2776  }
2777  else _constraints[t][ _node->nodeData.nodeIndex-offset ] += GetDivergence( node , _node , normal );
2778  }
2779  }
2780  }
2781  }
2782 #ifdef USE_OPENMP
2783 #pragma omp parallel for num_threads( threads ) schedule( static )
2784 #endif
2785  for( int i=0 ; i<sz ; i++ )
2786  {
2787  Real cSum = Real(0.);
2788  for( int t=0 ; t<threads ; t++ ) cSum += _constraints[t][i];
2789  constraints[i+offset] = cSum;
2790  }
2791  MemoryUsage();
2792  }
2793  std::vector< Point3D< Real > > coefficients( _sNodes.nodeCount[maxDepth] , zeroPoint );
2794  for( int d=maxDepth-1 ; d>=0 ; d-- )
2795  {
2796 #ifdef USE_OPENMP
2797 #pragma omp parallel for num_threads( threads )
2798 #endif
2799  for( int t=0 ; t<threads ; t++ )
2800  {
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++ )
2803  {
2804  TreeOctNode* node = _sNodes.treeNodes[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;
2809  }
2810  }
2811  }
2812 
2813  // Fine-to-coarse down-sampling of constraints
2814  for( int d=maxDepth-1 ; d>=(_boundaryType==0?2:0) ; d-- ) DownSample( d , _sNodes , &constraints[0] );
2815 
2816  // Coarse-to-fine up-sampling of coefficients
2817  for( int d=(_boundaryType==0?2:0) ; d<maxDepth ; d++ ) UpSample( d , _sNodes , &coefficients[0] );
2818 
2819  // Add the accumulated constraints from all finer depths
2820 #ifdef USE_OPENMP
2821 #pragma omp parallel for num_threads( threads )
2822 #endif
2823  for( int i=0 ; i<_sNodes.nodeCount[maxDepth] ; i++ ) _sNodes.treeNodes[i]->nodeData.constraint += constraints[i];
2824 
2825  // Compute the contribution from all coarser depths
2826  for( int d=0 ; d<=maxDepth ; d++ )
2827  {
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 );
2831 #ifdef USE_OPENMP
2832 #pragma omp parallel for num_threads( threads )
2833 #endif
2834  for( int t=0 ; t<threads ; t++ )
2835  {
2836  TreeOctNode::NeighborKey5 neighborKey5;
2837  neighborKey5.set( maxDepth );
2838  for( int i=start+(range*t)/threads ; i<start+(range*(t+1))/threads ; i++ )
2839  {
2840  TreeOctNode* node = _sNodes.treeNodes[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 );
2846 
2847  bool isInterior;
2848  {
2849  int d , off[3];
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 );
2854  }
2855  int cx , cy , cz;
2856  if( d )
2857  {
2858  int c = int( node - node->parent->children );
2859  Cube::FactorCornerIndex( c , cx , cy , cz );
2860  }
2861  else cx = cy = cz = 0;
2862  Stencil< Point3D< double > , 5 >& _stencil = stencils[cx][cy][cz];
2863 
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 )
2867  {
2868  TreeOctNode* _node = neighbors5.neighbors[x][y][z];
2869  int _i = _node->nodeData.nodeIndex;
2870  if( isInterior )
2871  {
2872  Point3D< double >& div = _stencil.values[x][y][z];
2873  Point3D< Real >& normal = coefficients[_i];
2874  constraint += Real( div[0] * normal[0] + div[1] * normal[1] + div[2] * normal[2] );
2875  }
2876  else constraint += GetDivergence( _node , node , coefficients[_i] );
2877  }
2878  node->nodeData.constraint += constraint;
2879  }
2880  }
2881  }
2882 
2883  fData.clearDotTables( fData.DV_DOT_FLAG );
2884 
2885  // Set the point weights for evaluating the iso-value
2886 #ifdef USE_OPENMP
2887 #pragma omp parallel for num_threads( threads )
2888 #endif
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++ )
2891  {
2892  TreeOctNode* temp = _sNodes.treeNodes[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]) );
2895  }
2896  MemoryUsage();
2897  delete normals;
2898  normals = NULL;
2899 }
2900 template<int Degree>
2901 void Octree<Degree>::AdjacencyCountFunction::Function(const TreeOctNode* node1,const TreeOctNode* node2){adjacencyCount++;}
2902 template<int Degree>
2903 void Octree<Degree>::AdjacencySetFunction::Function(const TreeOctNode* node1,const TreeOctNode* node2){adjacencies[adjacencyCount++]=node1->nodeData.nodeIndex;}
2904 template<int Degree>
2906 {
2907  if( !node1->children && node1->depth()<depth ) node1->initChildren();
2908 }
2909 template< int Degree >
2910 void Octree< Degree >::FaceEdgesFunction::Function( const TreeOctNode* node1 , const TreeOctNode* node2 )
2911 {
2912  if( !node1->children && MarchingCubes::HasRoots( node1->nodeData.mcIndex ) )
2913  {
2914  RootInfo ri1 , ri2;
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 );
2918 
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)] ) )
2922  {
2923  if( GetRootIndex( node1 , isoTri[j*3+k] , maxDepth , ri1 ) && GetRootIndex( node1 , isoTri[j*3+((k+1)%3)] , maxDepth , ri2 ) )
2924  {
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() )
2929  {
2930  (*vertexCount)[key1].first = ri1;
2931  (*vertexCount)[key1].second=0;
2932  }
2933  iter=vertexCount->find(key2);
2934  if( iter==vertexCount->end() )
2935  {
2936  (*vertexCount)[key2].first = ri2;
2937  (*vertexCount)[key2].second=0;
2938  }
2939  (*vertexCount)[key1].second--;
2940  (*vertexCount)[key2].second++;
2941  }
2942  else
2943  std::cerr << "Bad Edge 1:" << ri1.key << " " << ri2.key << std::endl;
2944  }
2945  }
2946 }
2947 
2948 template< int Degree >
2949 int Octree< Degree >::refineBoundary( int subdivideDepth )
2950 {
2951  // This implementation is somewhat tricky.
2952  // We would like to ensure that leaf-nodes across a subdivision boundary have the same depth.
2953  // We do this by calling the setNeighbors function.
2954  // The key is to implement this in a single pass through the leaves, ensuring that refinements don't propogate.
2955  // To this end, we do the minimal refinement that ensures that a cross boundary neighbor, and any of its cross-boundary
2956  // neighbors are all refined simultaneously.
2957  // For this reason, the implementation can only support nodes deeper than sDepth.
2958  bool flags[3][3][3];
2959  int maxDepth = tree.maxDepth();
2960 
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 );
2966  if( sDepth==0 )
2967  {
2968  _sNodes.set( tree );
2969  return sDepth;
2970  }
2971 
2972  // Ensure that face adjacent neighbors across the subdivision boundary exist to allow for
2973  // a consistent definition of the iso-surface
2974  TreeOctNode::NeighborKey3 nKey;
2975  nKey.set( maxDepth );
2976  for( TreeOctNode* leaf=tree.nextLeaf() ; leaf ; leaf=tree.nextLeaf( leaf ) )
2977  if( leaf->depth()>sDepth )
2978  {
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] =
2984  {
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) }
2988  };
2989 
2990  if( boundary[0][0] || boundary[0][1] || boundary[1][0] || boundary[1][1] || boundary[2][0] || boundary[2][1] )
2991  {
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;
3001 
3002  if( x || y || z )
3003  {
3004  // Corner case
3005  if( x && y && z ) flags[1+x][1+y][1+z] = true;
3006  // Edge cases
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;
3010  // Face cases
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 );
3015  }
3016  }
3017  }
3018  _sNodes.set( tree );
3019  MemoryUsage();
3020  return sDepth;
3021 }
3022 template<int Degree>
3023 void Octree<Degree>::GetMCIsoTriangles( Real isoValue , int subdivideDepth , CoredMeshData* mesh , int fullDepthIso , int nonLinearFit , bool addBarycenter , bool polygonMesh )
3024 {
3025  fData.setValueTables( fData.VALUE_FLAG | fData.D_VALUE_FLAG , 0 , postDerivativeSmooth );
3026  // Ensure that the subtrees are self-contained
3027  int sDepth = refineBoundary( subdivideDepth );
3028 
3029  RootData rootData , coarseRootData;
3030  std::vector< Point3D< Real > >* interiorPoints;
3031  int maxDepth = tree.maxDepth();
3032 
3033  std::vector< Real > metSolution( _sNodes.nodeCount[maxDepth] , 0 );
3034 #ifdef USE_OPENMP
3035 #pragma omp parallel for num_threads( threads )
3036 #endif
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] );
3039 
3040  // Clear the marching cube indices
3041 #ifdef USE_OPENMP
3042 #pragma omp parallel for num_threads( threads )
3043 #endif
3044  for( int i=0 ; i<_sNodes.nodeCount[maxDepth+1] ; i++ ) _sNodes.treeNodes[i]->nodeData.mcIndex = 0;
3045 
3046  rootData.boundaryValues = new hash_map< long long , std::pair< Real , Point3D< Real > > >();
3047  int offSet = 0;
3048 
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 );
3064  MemoryUsage();
3065 
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 );
3073  // First process all leaf nodes at depths strictly finer than sDepth, one subtree at a time.
3074  for( int i=_sNodes.nodeCount[sDepth] ; i<_sNodes.nodeCount[sDepth+1] ; i++ )
3075  {
3076  if( !_sNodes.treeNodes[i]->children ) continue;
3077 
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-- )
3085  {
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 );
3093 
3094  // First set the corner values and associated marching-cube indices
3095 #ifdef USE_OPENMP
3096 #pragma omp parallel for num_threads( threads )
3097 #endif
3098  for( int t=0 ; t<threads ; t++ ) for( int i=(leafNodeCount*t)/threads ; i<(leafNodeCount*(t+1))/threads ; i++ )
3099  {
3100  TreeOctNode* leaf = leafNodes[i];
3101  SetIsoCorners( isoValue , leaf , rootData , rootData.cornerValuesSet , rootData.cornerValues , nKeys[t] , &metSolution[0] , stencil1 , stencil2 );
3102 
3103  // If this node shares a vertex with a coarser node, set the vertex value
3104  int d , off[3];
3105  leaf->depthAndOffset( d , off );
3106  int res = 1<<(d-sDepth);
3107  off[0] %= res , off[1] %=res , off[2] %= res;
3108  res--;
3109  if( !(off[0]%res) && !(off[1]%res) && !(off[2]%res) )
3110  {
3111  const TreeOctNode* temp = leaf;
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;
3118  }
3119 
3120  // Compute the iso-vertices
3121  //
3122  if( _boundaryType!=0 || _IsInset( leaf ) ) SetMCRootPositions( leaf , sDepth , isoValue , nKeys5[t] , rootData , interiorPoints , mesh , &metSolution[0] , nonLinearFit );
3123  }
3124  // Note that this should be broken off for multi-threading as
3125  // the SetMCRootPositions writes to interiorPoints (with lockupdateing)
3126  // while GetMCIsoTriangles reads from interiorPoints (without locking)
3127  std::vector< Point3D< Real > > barycenters;
3128  std::vector< Point3D< Real > >* barycenterPtr = addBarycenter ? & barycenters : NULL;
3129 #ifdef USE_OPENMP
3130 #pragma omp parallel for num_threads( threads )
3131 #endif
3132  for( int t=0 ; t<threads ; t++ ) for( int i=(leafNodeCount*t)/threads ; i<(leafNodeCount*(t+1))/threads ; ++i )
3133  {
3134  TreeOctNode* leaf = leafNodes[i];
3135  if( _boundaryType!=0 || _IsInset( leaf ) ) GetMCIsoTriangles( leaf , mesh , rootData , interiorPoints , offSet , sDepth , polygonMesh , barycenterPtr );
3136  }
3137  for( size_t i=0 ; i<barycenters.size() ; i++ ) interiorPoints->push_back( barycenters[i] );
3138  }
3139  offSet = mesh->outOfCorePointCount();
3140  delete interiorPoints;
3141  }
3142 
3143  MemoryUsage();
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;
3152 
3153  for( int d=sDepth ; d>=0 ; d-- )
3154  {
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++ )
3160  {
3161  TreeOctNode* leaf = _sNodes.treeNodes[i];
3162  if( leaf->children ) continue;
3163 
3164  // First set the corner values and associated marching-cube indices
3165  SetIsoCorners( isoValue , leaf , coarseRootData , coarseRootData.cornerValuesSet , coarseRootData.cornerValues , nKey , &metSolution[0] , stencil1 , stencil2 );
3166 
3167  // Now compute the iso-vertices
3168  {
3169  if( _boundaryType!=0 || _IsInset( leaf ) )
3170  {
3171  SetMCRootPositions( leaf , 0 , isoValue , nKey5 , coarseRootData , NULL , mesh , &metSolution[0] , nonLinearFit );
3172  GetMCIsoTriangles( leaf , mesh , coarseRootData , NULL , 0 , 0 , polygonMesh , barycenterPtr );
3173  }
3174  }
3175  }
3176  }
3177  MemoryUsage();
3178 
3179  DeletePointer( coarseRootData.cornerValues ) ; DeletePointer( coarseRootData.cornerNormals );
3180  DeletePointer( coarseRootData.cornerValuesSet ) ; DeletePointer( coarseRootData.cornerNormalsSet );
3181  delete rootData.boundaryValues;
3182 }
3183 template<int Degree>
3185 {
3186  int idx[3];
3187  Real value=0;
3188 
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++ )
3196  {
3197  const TreeOctNode* n=neighborKey.neighbors[i].neighbors[j][k][l];
3198  if( n )
3199  value +=
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])]);
3204  }
3205  if( node->children )
3206  {
3207  for(unsigned int i=0;i<Cube::CORNERS;i++){
3208  int ii=Cube::AntipodalCornerIndex(i);
3209  const TreeOctNode* n=&node->children[i];
3210  while(1)
3211  {
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];
3217  else break;
3218  }
3219  }
3220  }
3221  return value;
3222 }
3223 template< int Degree >
3224 Real Octree< Degree >::getCornerValue( const OctNode< TreeNodeData , Real >::ConstNeighborKey3& neighborKey3 , const TreeOctNode* node , int corner , const Real* metSolution )
3225 {
3226  int idx[3];
3227  Real value = 0;
3228  if( _boundaryType==-1 ) value = -0.5;
3229 
3230  VertexData::CornerIndex( node , corner , fData.depth , idx );
3231  idx[0] *= fData.functionCount;
3232  idx[1] *= fData.functionCount;
3233  idx[2] *= fData.functionCount;
3234 
3235  int d = node->depth();
3236  int cx , cy , cz;
3237  int startX = 0 , endX = 3 , startY = 0 , endY = 3 , startZ = 0 , endZ = 3;
3238  Cube::FactorCornerIndex( corner , cx , cy , cz );
3239  {
3240  TreeOctNode::ConstNeighbors3& neighbors = neighborKey3.neighbors[d];
3241  if( cx==0 ) endX = 2;
3242  else startX = 1;
3243  if( cy==0 ) endY = 2;
3244  else startY = 1;
3245  if( cz==0 ) endZ = 2;
3246  else startZ = 1;
3247  for( int x=startX ; x<endX ; x++ ) for( int y=startY ; y<endY ; y++ ) for( int z=startZ ; z<endZ ; z++ )
3248  {
3249  const TreeOctNode* n=neighbors.neighbors[x][y][z];
3250  if( n )
3251  value +=
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;
3256  }
3257  }
3258  if( d>0 && d>_minDepth )
3259  {
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++ )
3268  {
3269  const TreeOctNode* n=neighbors.neighbors[x][y][z];
3270  if( n )
3271  value +=
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 ];
3276  }
3277  }
3278  return Real( value );
3279 }
3280 template< int Degree >
3281 Real Octree< Degree >::getCornerValue( const OctNode< TreeNodeData , Real >::ConstNeighborKey3& neighborKey3 , const TreeOctNode* node , int corner , const Real* metSolution , const Real stencil1[3][3][3] , const Real stencil2[3][3][3] )
3282 {
3283  Real value = 0;
3284  if( _boundaryType==-1 ) value = -0.5;
3285  int d = node->depth();
3286  int cx , cy , cz;
3287  int startX = 0 , endX = 3 , startY = 0 , endY = 3 , startZ = 0 , endZ = 3;
3288  Cube::FactorCornerIndex( corner , cx , cy , cz );
3289  {
3290  TreeOctNode::ConstNeighbors3& neighbors = neighborKey3.neighbors[d];
3291  if( cx==0 ) endX = 2;
3292  else startX = 1;
3293  if( cy==0 ) endY = 2;
3294  else startY = 1;
3295  if( cz==0 ) endZ = 2;
3296  else startZ = 1;
3297  for( int x=startX ; x<endX ; x++ ) for( int y=startY ; y<endY ; y++ ) for( int z=startZ ; z<endZ ; z++ )
3298  {
3299  const TreeOctNode* n=neighbors.neighbors[x][y][z];
3300  if( n ) value += n->nodeData.solution * stencil1[x][y][z];
3301  }
3302  }
3303  if( d>0 && d>_minDepth )
3304  {
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++ )
3313  {
3314  const TreeOctNode* n=neighbors.neighbors[x][y][z];
3315  if( n ) value += metSolution[ n->nodeData.nodeIndex ] * stencil2[x][y][z];
3316  }
3317  }
3318  return Real( value );
3319 }
3320 template< int Degree >
3321 Point3D< Real > Octree< Degree >::getCornerNormal( const OctNode< TreeNodeData , Real >::ConstNeighborKey5& neighborKey5 , const TreeOctNode* node , int corner , const Real* metSolution )
3322 {
3323  int idx[3];
3324  Point3D< Real > normal;
3325  normal[0] = normal[1] = normal[2] = 0.;
3326 
3327  VertexData::CornerIndex( node , corner , fData.depth , idx );
3328  idx[0] *= fData.functionCount;
3329  idx[1] *= fData.functionCount;
3330  idx[2] *= fData.functionCount;
3331 
3332  int d = node->depth();
3333  // Iterate over all ancestors that can overlap the corner
3334  {
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++ )
3337  {
3338  const TreeOctNode* n=neighbors.neighbors[j][k][l];
3339  if( n )
3340  {
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 );
3348  }
3349  }
3350  }
3351  if( d>0 && d>_minDepth )
3352  {
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++ )
3355  {
3356  const TreeOctNode* n=neighbors.neighbors[j][k][l];
3357  if( n )
3358  {
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 );
3366  }
3367  }
3368  }
3369  return normal;
3370 }
3371 template< int Degree >
3372 Real Octree<Degree>::GetIsoValue( void )
3373 {
3374  Real isoValue , weightSum;
3375 
3376  fData.setValueTables( fData.VALUE_FLAG , 0 );
3377 
3378  isoValue = weightSum = 0;
3379 #ifdef USE_OPENMP
3380 #pragma omp parallel for num_threads( threads ) reduction( + : isoValue , weightSum )
3381 #endif
3382  for( int t=0 ; t<threads ; t++)
3383  {
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++ )
3388  {
3389  TreeOctNode* temp = _sNodes.treeNodes[i];
3390  nKey.getNeighbors( temp );
3391  Real w = temp->nodeData.centerWeightContribution;
3392  if( w!=0 )
3393  {
3394  isoValue += getCenterValue( nKey , temp ) * w;
3395  weightSum += w;
3396  }
3397  }
3398  }
3399  if( _boundaryType==-1 ) return isoValue/weightSum - Real(0.5);
3400  else return isoValue/weightSum;
3401 }
3402 
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] )
3405 {
3406  Real cornerValues[ Cube::CORNERS ];
3407  const SortedTreeNodes::CornerIndices& cIndices = cData[ leaf ];
3408 
3409  bool isInterior;
3410  int d , off[3];
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++ )
3417  {
3418  int vIndex = cIndices[c];
3419  if( valuesSet[vIndex] ) cornerValues[c] = values[vIndex];
3420  else
3421  {
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;
3426  }
3427  }
3428  leaf->nodeData.mcIndex = MarchingCubes::GetIndex( cornerValues , isoValue );
3429 
3430  // Set the marching cube indices for all interior nodes.
3431  if( leaf->parent )
3432  {
3433  TreeOctNode* parent = leaf->parent;
3434  int c = int( leaf - leaf->parent->children );
3435  int mcid = leaf->nodeData.mcIndex & (1<<MarchingCubes::cornerMap[c]);
3436 
3437  if( mcid )
3438  {
3439 #ifdef WIN32
3440  InterlockedOr( (volatile unsigned long long*)&(parent->nodeData.mcIndex) , mcid );
3441 #else // !WIN32
3442 
3443 #ifdef USE_OPENMP
3444 #pragma omp atomic
3445 #endif
3446 
3447  parent->nodeData.mcIndex |= mcid;
3448 #endif // WIN32
3449  while( 1 )
3450  {
3451  if( parent->parent && parent->parent->d>=_minDepth && (parent-parent->parent->children)==c )
3452  {
3453 #ifdef WIN32
3454  InterlockedOr( (volatile unsigned long long*)&(parent->parent->nodeData.mcIndex) , mcid );
3455 #else // !WIN32
3456 
3457 #ifdef USE_OPENMP
3458 #pragma omp atomic
3459 #endif
3460  parent->parent->nodeData.mcIndex |= mcid;
3461 #endif // WIN32
3462  parent = parent->parent;
3463  }
3464  else break;
3465  }
3466  }
3467  }
3468 }
3469 
3470 
3471 template<int Degree>
3472 int Octree<Degree>::InteriorFaceRootCount(const TreeOctNode* node,const int &faceIndex,int maxDepth){
3473 
3474  int cnt = 0;
3475  int corners[Cube::CORNERS/2];
3476  if(node->children){
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);
3480  c1=corners[0];
3481  c2=corners[3];
3482  switch(dir){
3483  case 0:
3484  e1=Cube::EdgeIndex(1,off,1);
3485  e2=Cube::EdgeIndex(2,off,1);
3486  break;
3487  case 1:
3488  e1=Cube::EdgeIndex(0,off,1);
3489  e2=Cube::EdgeIndex(2,1,off);
3490  break;
3491  case 2:
3492  e1=Cube::EdgeIndex(0,1,off);
3493  e2=Cube::EdgeIndex(1,1,off);
3494  break;
3495  };
3496  cnt+=EdgeRootCount(&node->children[c1],e1,maxDepth)+EdgeRootCount(&node->children[c1],e2,maxDepth);
3497  switch(dir){
3498  case 0:
3499  e1=Cube::EdgeIndex(1,off,0);
3500  e2=Cube::EdgeIndex(2,off,0);
3501  break;
3502  case 1:
3503  e1=Cube::EdgeIndex(0,off,0);
3504  e2=Cube::EdgeIndex(2,0,off);
3505  break;
3506  case 2:
3507  e1=Cube::EdgeIndex(0,0,off);
3508  e2=Cube::EdgeIndex(1,0,off);
3509  break;
3510  };
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);}}
3513  }
3514  return cnt;
3515 }
3516 
3517 template<int Degree>
3518 int Octree<Degree>::EdgeRootCount(const TreeOctNode* node,int edgeIndex,int maxDepth){
3519  int f1,f2,c1,c2;
3520  const TreeOctNode* temp;
3521  Cube::FacesAdjacentToEdge(edgeIndex,f1,f2);
3522 
3523  int eIndex;
3524  const TreeOctNode* finest=node;
3525  eIndex=edgeIndex;
3526  if(node->depth()<maxDepth){
3527  temp=node->faceNeighbor(f1);
3528  if(temp && temp->children){
3529  finest=temp;
3530  eIndex=Cube::FaceReflectEdgeIndex(edgeIndex,f1);
3531  }
3532  else{
3533  temp=node->faceNeighbor(f2);
3534  if(temp && temp->children){
3535  finest=temp;
3536  eIndex=Cube::FaceReflectEdgeIndex(edgeIndex,f2);
3537  }
3538  else{
3539  temp=node->edgeNeighbor(edgeIndex);
3540  if(temp && temp->children){
3541  finest=temp;
3542  eIndex=Cube::EdgeReflectEdgeIndex(edgeIndex);
3543  }
3544  }
3545  }
3546  }
3547 
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);
3551 }
3552 template<int Degree>
3553 int Octree<Degree>::IsBoundaryFace(const TreeOctNode* node,int faceIndex,int subdivideDepth){
3554  int dir,offset,d,o[3],idx;
3555 
3556  if(subdivideDepth<0){return 0;}
3557  if(node->d<=subdivideDepth){return 1;}
3558  Cube::FactorFaceIndex(faceIndex,dir,offset);
3559  node->depthAndOffset(d,o);
3560 
3561  idx=(int(o[dir])<<1) + (offset<<1);
3562  return !(idx%(2<<(int(node->d)-subdivideDepth)));
3563 }
3564 template<int Degree>
3565 int Octree<Degree>::IsBoundaryEdge(const TreeOctNode* node,int edgeIndex,int subdivideDepth){
3566  int dir,x,y;
3567  Cube::FactorEdgeIndex(edgeIndex,dir,x,y);
3568  return IsBoundaryEdge(node,dir,x,y,subdivideDepth);
3569 }
3570 template<int Degree>
3571 int Octree<Degree>::IsBoundaryEdge( const TreeOctNode* node , int dir , int x , int y , int subdivideDepth )
3572 {
3573  int d , o[3];
3574  int idx1 = 0;
3575  int idx2 = 0;
3576 
3577  if( subdivideDepth<0 ) return 0;
3578  if( node->d<=subdivideDepth ) return 1;
3579  node->depthAndOffset( d , o );
3580 
3581  switch( dir )
3582  {
3583  case 0:
3584  idx1 = o[1] + x;
3585  idx2 = o[2] + y;
3586  break;
3587  case 1:
3588  idx1 = o[0] + x;
3589  idx2 = o[2] + y;
3590  break;
3591  case 2:
3592  idx1 = o[0] + x;
3593  idx2 = o[1] + y;
3594  break;
3595  }
3596  int mask = 1<<( int(node->d) - subdivideDepth );
3597  return !(idx1%(mask)) || !(idx2%(mask));
3598 }
3599 template< int Degree >
3601 {
3602  int o , i1 , i2;
3603  Real width;
3604  Point3D< Real > c;
3605 
3606  Cube::FactorEdgeIndex( ri.edgeIndex , o , i1 , i2 );
3607  ri.node->centerAndWidth( c , width );
3608  switch(o)
3609  {
3610  case 0:
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;
3615  break;
3616  case 1:
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;
3621  break;
3622  case 2:
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;
3627  break;
3628  }
3629 }
3631 // The assumption made when calling this code is that the edge has at most one root //
3633 template< int Degree >
3634 int Octree< Degree >::GetRoot( const RootInfo& ri , Real isoValue , TreeOctNode::ConstNeighborKey5& neighborKey5 , Point3D< Real > & position , RootData& rootData , int sDepth , const Real* metSolution , int nonLinearFit )
3635 {
3636  if( !MarchingCubes::HasRoots( ri.node->nodeData.mcIndex ) ) return 0;
3637  int c1 , c2;
3638  Cube::EdgeCorners( ri.edgeIndex , c1 , c2 );
3639  if( !MarchingCubes::HasEdgeRoots( ri.node->nodeData.mcIndex , ri.edgeIndex ) ) return 0;
3640 
3641  long long key1 , key2;
3642  Point3D< Real > n[2];
3643 
3644  int i , o , i1 , i2 , rCount=0;
3645  Polynomial<2> P;
3646  std::vector< double > roots;
3647  double x0 , x1;
3648  Real center , width;
3649  Real averageRoot=0;
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 );
3654 
3655  bool isBoundary = ( IsBoundaryEdge( ri.node , ri.edgeIndex , sDepth )!=0 );
3656  bool haveKey1 , haveKey2;
3657  std::pair< Real , Point3D< Real > > keyValue1 , keyValue2;
3658  int iter1 , iter2;
3659  {
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];
3664  if( isBoundary )
3665  {
3666 #ifdef USE_OPENMP
3667 #pragma omp critical (normal_hash_access)
3668 #endif
3669  {
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];
3674  }
3675  }
3676  else
3677  {
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];
3684  }
3685  }
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;
3690 
3691  if( !haveKey2 ) keyValue2.second = getCornerNormal( neighborKey5 , ri.node , c2 , metSolution );
3692  x1 = keyValue2.first;
3693  n[1] = keyValue2.second;
3694 
3695  if( !haveKey1 || !haveKey2 )
3696  {
3697  if( isBoundary )
3698  {
3699 #ifdef USE_OPENMP
3700 #pragma omp critical (normal_hash_access)
3701 #endif
3702  {
3703  if( !haveKey1 ) (*rootData.boundaryValues)[key1] = keyValue1;
3704  if( !haveKey2 ) (*rootData.boundaryValues)[key2] = keyValue2;
3705  }
3706  }
3707  else
3708  {
3709  if( !haveKey1 ) rootData.cornerNormals[iter1] = keyValue1.second , rootData.cornerNormalsSet[ iter1 ] = 1;
3710  if( !haveKey2 ) rootData.cornerNormals[iter2] = keyValue2.second , rootData.cornerNormalsSet[ iter2 ] = 1;
3711  }
3712  }
3713 
3714  Point3D< Real > c;
3715  ri.node->centerAndWidth(c,width);
3716  center=c[o];
3717  for( i=0 ; i<DIMENSION ; i++ ) n[0][i] *= width , n[1][i] *= width;
3718 
3719  switch(o)
3720  {
3721  case 0:
3722  position[1] = c[1]-width/2+width*i1;
3723  position[2] = c[2]-width/2+width*i2;
3724  break;
3725  case 1:
3726  position[0] = c[0]-width/2+width*i1;
3727  position[2] = c[2]-width/2+width*i2;
3728  break;
3729  case 2:
3730  position[0] = c[0]-width/2+width*i1;
3731  position[1] = c[1]-width/2+width*i2;
3732  break;
3733  }
3734  double dx0,dx1;
3735  dx0 = n[0][o];
3736  dx1 = n[1][o];
3737 
3738  // The scaling will turn the Hermite Spline into a quadratic
3739  double scl=(x1-x0)/((dx1+dx0)/2);
3740  dx0 *= scl;
3741  dx1 *= scl;
3742 
3743  // Hermite Spline
3744  P.coefficients[0] = x0;
3745  P.coefficients[1] = dx0;
3746  P.coefficients[2] = 3*(x1-x0)-dx1-2*dx0;
3747 
3748  P.getSolutions( isoValue , roots , EPSILON );
3749  for( i=0 ; i<int(roots.size()) ; i++ )
3750  if( roots[i]>=0 && roots[i]<=1 )
3751  {
3752  averageRoot += Real( roots[i] );
3753  rCount++;
3754  }
3755  if( rCount && nonLinearFit ) averageRoot /= rCount;
3756  else averageRoot = Real((x0-isoValue)/(x0-x1));
3757  if( averageRoot<0 || averageRoot>1 )
3758  {
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;
3763  }
3764  position[o] = Real(center-width/2+width*averageRoot);
3765  return 1;
3766 }
3767 template< int Degree >
3768 int Octree< Degree >::GetRootIndex( const TreeOctNode* node , int edgeIndex , int maxDepth , int sDepth , RootInfo& ri )
3769 {
3770  int c1,c2,f1,f2;
3771  const TreeOctNode *temp,*finest;
3772  int finestIndex;
3773 
3774  Cube::FacesAdjacentToEdge(edgeIndex,f1,f2);
3775 
3776  finest=node;
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 );
3783  else
3784  {
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 );
3789  else
3790  {
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 );
3795  }
3796  }
3797  }
3798 
3799  Cube::EdgeCorners( finestIndex , c1 , c2 );
3800  if( finest->children )
3801  {
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;
3804  else
3805  {
3806  fprintf( stderr , "[WARNING] Couldn't find root index with either child\n" );
3807  return 0;
3808  }
3809  }
3810  else
3811  {
3812  if( !(MarchingCubes::edgeMask[finest->nodeData.mcIndex] & (1<<finestIndex)) )
3813  {
3814  fprintf( stderr , "[WARNING] Finest node does not have iso-edge\n" );
3815  return 0;
3816  }
3817 
3818  int o,i1,i2;
3819  Cube::FactorEdgeIndex(finestIndex,o,i1,i2);
3820  int d,off[3];
3821  finest->depthAndOffset(d,off);
3822  ri.node=finest;
3823  ri.edgeIndex=finestIndex;
3824  int eIndex[2],offset;
3825  offset=BinaryNode<Real>::CenterIndex( d , off[o] );
3826  switch(o)
3827  {
3828  case 0:
3829  eIndex[0]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[1],i1);
3830  eIndex[1]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[2],i2);
3831  break;
3832  case 1:
3833  eIndex[0]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[0],i1);
3834  eIndex[1]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[2],i2);
3835  break;
3836  case 2:
3837  eIndex[0]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[0],i1);
3838  eIndex[1]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[1],i2);
3839  break;
3840  }
3841  ri.key = (long long)(o) | (long long)(eIndex[0])<<5 | (long long)(eIndex[1])<<25 | (long long)(offset)<<45;
3842  return 1;
3843  }
3844 }
3845 template<int Degree>
3846 int Octree<Degree>::GetRootIndex( const TreeOctNode* node , int edgeIndex , int maxDepth , RootInfo& ri )
3847 {
3848  int c1 , c2 , f1 , f2;
3849  const TreeOctNode *temp,*finest;
3850  int finestIndex;
3851 
3852  if( node->nodeData.nodeIndex==-1 ) fprintf( stderr , "[WARNING] Called GetRootIndex with bad node\n" );
3853  // The assumption is that the super-edge has a root along it.
3854  if( !(MarchingCubes::edgeMask[node->nodeData.mcIndex] & (1<<edgeIndex) ) ) return 0;
3855 
3856  Cube::FacesAdjacentToEdge( edgeIndex , f1 , f2 );
3857 
3858  finest = node;
3859  finestIndex = edgeIndex;
3860  if( node->depth()<maxDepth && !node->children )
3861  {
3862  temp=node->faceNeighbor( f1 );
3863  if( temp && temp->nodeData.nodeIndex!=-1 && temp->children ) finest = temp , finestIndex = Cube::FaceReflectEdgeIndex( edgeIndex , f1 );
3864  else
3865  {
3866  temp = node->faceNeighbor( f2 );
3867  if( temp && temp->nodeData.nodeIndex!=-1 && temp->children ) finest = temp , finestIndex = Cube::FaceReflectEdgeIndex( edgeIndex , f2 );
3868  else
3869  {
3870  temp = node->edgeNeighbor( edgeIndex );
3871  if( temp && temp->nodeData.nodeIndex!=-1 && temp->children ) finest = temp , finestIndex = Cube::EdgeReflectEdgeIndex( edgeIndex );
3872  }
3873  }
3874  }
3875 
3876  Cube::EdgeCorners( finestIndex , c1 , c2 );
3877  if( finest->children )
3878  {
3879  if ( GetRootIndex( finest->children + c1 , finestIndex , maxDepth , ri ) ) return 1;
3880  else if( GetRootIndex( finest->children + c2 , finestIndex , maxDepth , ri ) ) return 1;
3881  else
3882  {
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 );
3887  printf( "\t" );
3888  for( int i=0 ; i<8 ; i++ ) if( node->nodeData.mcIndex & (1<<i) ) printf( "1" ); else printf( "0" );
3889  printf( "\t" );
3890  for( int i=0 ; i<8 ; i++ ) if( finest->nodeData.mcIndex & (1<<i) ) printf( "1" ); else printf( "0" );
3891  printf( "\n" );
3892  return 0;
3893  }
3894  }
3895  else
3896  {
3897  int o,i1,i2;
3898  Cube::FactorEdgeIndex(finestIndex,o,i1,i2);
3899  int d,off[3];
3900  finest->depthAndOffset(d,off);
3901  ri.node = finest;
3902  ri.edgeIndex = finestIndex;
3903  int offset = 0;
3904  int eIndex[2] = {0,0};
3905  offset = BinaryNode< Real >::CenterIndex( d , off[o] );
3906  switch(o)
3907  {
3908  case 0:
3909  eIndex[0]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[1],i1);
3910  eIndex[1]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[2],i2);
3911  break;
3912  case 1:
3913  eIndex[0]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[0],i1);
3914  eIndex[1]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[2],i2);
3915  break;
3916  case 2:
3917  eIndex[0]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[0],i1);
3918  eIndex[1]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[1],i2);
3919  break;
3920  }
3921  ri.key= (long long)(o) | (long long)(eIndex[0])<<5 | (long long)(eIndex[1])<<25 | (long long)(offset)<<45;
3922  return 1;
3923  }
3924 }
3925 template<int Degree>
3926 int Octree<Degree>::GetRootPair(const RootInfo& ri,int maxDepth,RootInfo& pair)
3927 {
3928  const TreeOctNode* node = ri.node;
3929  int c1 , c2 , c;
3930  Cube::EdgeCorners( ri.edgeIndex , c1 , c2 );
3931  while( node->parent )
3932  {
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 ) )
3936  {
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 );
3939  }
3940  node = node->parent;
3941  }
3942  return 0;
3943 
3944 }
3945 template<int Degree>
3946 int Octree< Degree >::GetRootIndex( const RootInfo& ri , RootData& rootData , CoredPointIndex& index )
3947 {
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() )
3952  {
3953  index.inCore = 1;
3954  index.index = rootIter->second;
3955  return 1;
3956  }
3957  else if( rootData.interiorRoots )
3958  {
3959  int eIndex = rootData.edgeIndices( ri.node )[ ri.edgeIndex ];
3960  if( rootData.edgesSet[ eIndex ] )
3961  {
3962  index.inCore = 0;
3963  index.index = rootData.interiorRoots[ eIndex ];
3964  return 1;
3965  }
3966  }
3967  return 0;
3968 }
3969 template< int Degree >
3970 int Octree< Degree >::SetMCRootPositions( TreeOctNode* node , int sDepth , Real isoValue , TreeOctNode::ConstNeighborKey5& neighborKey5 , RootData& rootData ,
3971  std::vector< Point3D< Real > >* interiorPositions , CoredMeshData* mesh , const Real* metSolution , int nonLinearFit )
3972 {
3973  Point3D< Real > position;
3974  int eIndex;
3975  RootInfo ri;
3976  int count=0;
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++ )
3979  {
3980 
3981  eIndex = Cube::EdgeIndex( i , j , k );
3982  if( GetRootIndex( node , eIndex , fData.depth , ri ) )
3983  {
3984  long long key = ri.key;
3985  if( !rootData.interiorRoots || IsBoundaryEdge( node , i , j , k , sDepth ) )
3986  {
3987  hash_map< long long , int >::iterator iter , end;
3988  // Check if the root has already been set
3989 #ifdef USE_OPENMP
3990 #pragma omp critical (boundary_roots_hash_access)
3991 #endif
3992  {
3993  iter = rootData.boundaryRoots.find( key );
3994  end = rootData.boundaryRoots.end();
3995  }
3996  if( iter==end )
3997  {
3998  // Get the root information
3999  GetRoot( ri , isoValue , neighborKey5 , position , rootData , sDepth , metSolution , nonLinearFit );
4000  position = position * _scale + _center;
4001  // Add the root if it hasn't been added already
4002 #ifdef USE_OPENMP
4003 #pragma omp critical (boundary_roots_hash_access)
4004 #endif
4005  {
4006  iter = rootData.boundaryRoots.find( key );
4007  end = rootData.boundaryRoots.end();
4008  if( iter==end )
4009  {
4010  mesh->inCorePoints.push_back( position );
4011  rootData.boundaryRoots[key] = int( mesh->inCorePoints.size() ) - 1;
4012  }
4013  }
4014  if( iter==end ) count++;
4015  }
4016  }
4017  else
4018  {
4019  int nodeEdgeIndex = rootData.edgeIndices( ri.node )[ ri.edgeIndex ];
4020  if( !rootData.edgesSet[ nodeEdgeIndex ] )
4021  {
4022  // Get the root information
4023  GetRoot( ri , isoValue , neighborKey5 , position , rootData , sDepth , metSolution , nonLinearFit );
4024  position = position * _scale + _center;
4025  // Add the root if it hasn't been added already
4026 #ifdef USE_OPENMP
4027 #pragma omp critical (add_point_access)
4028 #endif
4029  {
4030  if( !rootData.edgesSet[ nodeEdgeIndex ] )
4031  {
4032  rootData.interiorRoots[ nodeEdgeIndex ] = mesh->addOutOfCorePoint( position );
4033  interiorPositions->push_back( position );
4034  rootData.edgesSet[ nodeEdgeIndex ] = 1;
4035  count++;
4036  }
4037  }
4038  }
4039  }
4040  }
4041  }
4042  return count;
4043 }
4044 template<int Degree>
4045 int Octree< Degree >::SetBoundaryMCRootPositions( int sDepth , Real isoValue , RootData& rootData , CoredMeshData* mesh , int nonLinearFit )
4046 {
4047  Point3D< Real > position;
4048  int i,j,k,eIndex,hits=0;
4049  RootInfo ri;
4050  int count=0;
4051  TreeOctNode* node;
4052 
4053  node = tree.nextLeaf();
4054  while( node )
4055  {
4056  if( MarchingCubes::HasRoots( node->nodeData.mcIndex ) )
4057  {
4058  hits=0;
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 ) )
4063  {
4064  hits++;
4065  eIndex = Cube::EdgeIndex( i , j , k );
4066  if( GetRootIndex( node , eIndex , fData.depth , ri ) )
4067  {
4068  long long key = ri.key;
4069  if( rootData.boundaryRoots.find(key)==rootData.boundaryRoots.end() )
4070  {
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;
4075  count++;
4076  }
4077  }
4078  }
4079  }
4080  if( hits ) node=tree.nextLeaf(node);
4081  else node=tree.nextBranch(node);
4082  }
4083  return count;
4084 }
4085 template<int Degree>
4086 void Octree< Degree >::GetMCIsoEdges( TreeOctNode* node , int sDepth , std::vector< std::pair< RootInfo , RootInfo > >& edges )
4087 {
4088  TreeOctNode* temp;
4089  int count=0;// , tris=0;
4090  int isoTri[ DIMENSION * MarchingCubes::MAX_TRIANGLES ];
4091  FaceEdgesFunction fef;
4092  int ref , fIndex;
4093  hash_map< long long , std::pair< RootInfo , int > >::iterator iter;
4094  hash_map< long long , std::pair< RootInfo , int > > vertexCount;
4095 
4096  fef.edges = &edges;
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++ )
4101  {
4102  ref = Cube::FaceReflectFaceIndex( fIndex , fIndex );
4103  fef.fIndex = ref;
4104  temp = node->faceNeighbor( fIndex );
4105  // If the face neighbor exists and has higher resolution than the current node,
4106  // get the iso-curve from the neighbor
4107  if( temp && temp->nodeData.nodeIndex!=-1 && temp->children && !IsBoundaryFace( node , fIndex , sDepth ) ) temp->processNodeFaces( temp , &fef , ref );
4108  // Otherwise, get it from the node
4109  else
4110  {
4111  RootInfo ri1 , ri2;
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)] ) )
4115  {
4116  if( GetRootIndex( node , isoTri[j*3+k] , fData.depth , ri1 ) && GetRootIndex( node , isoTri[j*3+((k+1)%3)] , fData.depth , ri2 ) )
4117  {
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() )
4122  {
4123  vertexCount[key1].first = ri1;
4124  vertexCount[key1].second = 0;
4125  }
4126  iter=vertexCount.find( key2 );
4127  if( iter==vertexCount.end() )
4128  {
4129  vertexCount[key2].first = ri2;
4130  vertexCount[key2].second = 0;
4131  }
4132  vertexCount[key1].second++;
4133  vertexCount[key2].second--;
4134  }
4135  else
4136  {
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;
4140  }
4141  }
4142  }
4143  }
4144  for( int i=0 ; i<int(edges.size()) ; i++ )
4145  {
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;
4149 
4150  else if( vertexCount[ edges[i].first.key ].second )
4151  {
4152  RootInfo ri;
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() )
4157  {
4158  int d , off[3];
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] );
4161  }
4162  else
4163  {
4164  edges.push_back( std::pair< RootInfo , RootInfo >( ri , edges[i].first ) );
4165  vertexCount[ key ].second++;
4166  vertexCount[ edges[i].first.key ].second--;
4167  }
4168  }
4169 
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;
4173 
4174  else if( vertexCount[edges[i].second.key].second )
4175  {
4176  RootInfo ri;
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() )
4181  {
4182  int d , off[3];
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] );
4185  }
4186  else
4187  {
4188  edges.push_back( std::pair< RootInfo , RootInfo >( edges[i].second , ri ) );
4189  vertexCount[key].second--;
4190  vertexCount[ edges[i].second.key ].second++;
4191  }
4192  }
4193  }
4194 }
4195 template<int Degree>
4196 int Octree< Degree >::GetMCIsoTriangles( TreeOctNode* node , CoredMeshData* mesh , RootData& rootData , std::vector< Point3D< Real > >* interiorPositions , int offSet , int sDepth , bool polygonMesh , std::vector< Point3D< Real > >* barycenters )
4197 {
4198  int tris=0;
4199  std::vector< std::pair< RootInfo , RootInfo > > edges;
4200  std::vector< std::vector< std::pair< RootInfo , RootInfo > > > edgeLoops;
4201  GetMCIsoEdges( node , sDepth , edges );
4202 
4203  GetEdgeLoops( edges , edgeLoops );
4204  for( int i=0 ; i<int(edgeLoops.size()) ; i++ )
4205  {
4206  CoredPointIndex p;
4207  std::vector<CoredPointIndex> edgeIndices;
4208  for( int j=int(edgeLoops[i].size())-1 ; j>=0 ; j-- )
4209  {
4210  if( !GetRootIndex( edgeLoops[i][j].first , rootData , p ) ) printf( "Bad Point Index\n" );
4211  else edgeIndices.push_back( p );
4212  }
4213  tris += AddTriangles( mesh , edgeIndices , interiorPositions , offSet , polygonMesh , barycenters );
4214  }
4215  return tris;
4216 }
4217 
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 )
4220 {
4221  int loopSize=0;
4222  long long frontIdx , backIdx;
4223  std::pair< RootInfo , RootInfo > e , temp;
4224  loops.clear();
4225 
4226  while( !edges.empty() )
4227  {
4228  std::vector< std::pair< RootInfo , RootInfo > > front , back;
4229  e = edges[0];
4230  loops.resize( loopSize+1 );
4231  edges[0] = edges.back();
4232  edges.pop_back();
4233  frontIdx = e.second.key;
4234  backIdx = e.first.key;
4235  for( int j=int(edges.size())-1 ; j>=0 ; j-- )
4236  {
4237  if( edges[j].first.key==frontIdx || edges[j].second.key==frontIdx )
4238  {
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();
4244  edges.pop_back();
4245  j = int(edges.size());
4246  }
4247  else if( edges[j].first.key==backIdx || edges[j].second.key==backIdx )
4248  {
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();
4254  edges.pop_back();
4255  j = int(edges.size());
4256  }
4257  }
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] );
4261  loopSize++;
4262  }
4263  return int(loops.size());
4264 }
4265 template<int Degree>
4266 int Octree<Degree>::AddTriangles( CoredMeshData* mesh , std::vector<CoredPointIndex>& edges , std::vector< Point3D< Real > >* interiorPositions , int offSet , bool polygonMesh , std::vector< Point3D< Real > >* barycenters )
4267 {
4269  std::vector< Point3D< Real > > vertices;
4270  std::vector< TriangleIndex > triangles;
4271  if( polygonMesh )
4272  {
4273  std::vector< CoredVertexIndex > vertices( edges.size() );
4274  for( int i=0 ; i<int(edges.size()) ; i++ )
4275  {
4276  vertices[i].idx = edges[i].index;
4277  vertices[i].inCore = (edges[i].inCore!=0);
4278  }
4279 #ifdef USE_OPENMP
4280 #pragma omp critical (add_polygon_access)
4281 #endif
4282  {
4283  mesh->addPolygon( vertices );
4284  }
4285  return 1;
4286  }
4287  if( edges.size()>3 )
4288  {
4289  bool isCoplanar = false;
4290 
4291  if( barycenters )
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 )
4295  {
4296  Point3D< Real > v1 , v2;
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;
4302  }
4303  if( isCoplanar )
4304  {
4305  Point3D< Real > c;
4306  c[0] = c[1] = c[2] = 0;
4307  for( int i=0 ; i<int(edges.size()) ; i++ )
4308  {
4309  Point3D<Real> p;
4310  if(edges[i].inCore) p = mesh->inCorePoints[edges[i].index ];
4311  else p = (*interiorPositions)[edges[i].index-offSet];
4312  c += p;
4313  }
4314  c /= Real( edges.size() );
4315  int cIdx;
4316 #ifdef USE_OPENMP
4317 #pragma omp critical (add_point_access)
4318 #endif
4319  {
4320  cIdx = mesh->addOutOfCorePoint( c );
4321  barycenters->push_back( c );
4322  }
4323  for( int i=0 ; i<int(edges.size()) ; i++ )
4324  {
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;
4332 #ifdef USE_OPENMP
4333 #pragma omp critical (add_polygon_access)
4334 #endif
4335  {
4336  mesh->addPolygon( vertices );
4337  }
4338  }
4339  return int( edges.size() );
4340  }
4341  else
4342  {
4343  vertices.resize( edges.size() );
4344  // Add the points
4345  for( int i=0 ; i<int(edges.size()) ; i++ )
4346  {
4347  Point3D< Real > p;
4348  if( edges[i].inCore ) p = mesh->inCorePoints[edges[i].index ];
4349  else p = (*interiorPositions)[edges[i].index-offSet];
4350  vertices[i] = p;
4351  }
4352  MAT.GetTriangulation( vertices , triangles );
4353  for( int i=0 ; i<int(triangles.size()) ; i++ )
4354  {
4355  std::vector< CoredVertexIndex > _vertices( 3 );
4356  for( int j=0 ; j<3 ; j++ )
4357  {
4358  _vertices[j].idx = edges[ triangles[i].idx[j] ].index;
4359  _vertices[j].inCore = (edges[ triangles[i].idx[j] ].inCore!=0);
4360  }
4361 #ifdef USE_OPENMP
4362 #pragma omp critical (add_polygon_access)
4363 #endif
4364  {
4365  mesh->addPolygon( _vertices );
4366  }
4367  }
4368  }
4369  }
4370  else if( edges.size()==3 )
4371  {
4372  std::vector< CoredVertexIndex > vertices( 3 );
4373  for( int i=0 ; i<3 ; i++ )
4374  {
4375  vertices[i].idx = edges[i].index;
4376  vertices[i].inCore = (edges[i].inCore!=0);
4377  }
4378 #ifdef USE_OPENMP
4379 #pragma omp critical (add_polygon_access)
4380 #endif
4381  mesh->addPolygon( vertices );
4382  }
4383  return int(edges.size())-2;
4384 }
4385 template< int Degree >
4386 Pointer( Real ) Octree< Degree >::GetSolutionGrid( int& res , Real isoValue , int depth )
4387 {
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 );
4392  res = 1<<depth;
4393  fData.setValueTables( fData.VALUE_FLAG );
4394  Pointer( Real ) values = NewPointer< Real >( res * res * res );
4395  memset( values , 0 , sizeof( Real ) * res * res * res );
4396 
4397  for( TreeOctNode* n=tree.nextNode() ; n ; n=tree.nextNode( n ) )
4398  {
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 );
4403  bool skip=false;
4404  for( int i=0 ; i<3 ; i++ )
4405  {
4406  // Get the index of the functions
4407  idx[i] = BinaryNode< double >::CenterIndex( d , idx[i] );
4408  // Figure out which samples fall into the range
4409  fData.setSampleSpan( idx[i] , start[i] , end[i] );
4410  // We only care about the odd indices
4411  if( !(start[i]&1) ) start[i]++;
4412  if( !( end[i]&1) ) end[i]--;
4413  if( _boundaryType==0 )
4414  {
4415  // (start[i]-1)>>1 >= res/2
4416  // ( end[i]-1)<<1 < 3*res/2
4417  start[i] = std::max< int >( start[i] , res+1 );
4418  end [i] = std::min< int >( end [i] , 3*res-1 );
4419  }
4420  }
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 )
4426  {
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 ] +=
4430  coefficient *
4431  fData.valueTables[ idx[0]+x*fData.functionCount ] *
4432  fData.valueTables[ idx[1]+y*fData.functionCount ] *
4433  fData.valueTables[ idx[2]+z*fData.functionCount ];
4434  }
4435  }
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;
4438 
4439  return values;
4440 }
4441 
4443 // VertexData //
4445 long long VertexData::CenterIndex(const TreeOctNode* node,int maxDepth){
4446  int idx[DIMENSION];
4447  return CenterIndex(node,maxDepth,idx);
4448 }
4449 long long VertexData::CenterIndex(const TreeOctNode* node,int maxDepth,int idx[DIMENSION]){
4450  int d,o[3];
4451  node->depthAndOffset(d,o);
4452  for(int i=0;i<DIMENSION;i++){idx[i]=BinaryNode<Real>::CornerIndex(maxDepth+1,d+1,o[i]<<1,1);}
4453  return (long long)(idx[0]) | (long long)(idx[1])<<15 | (long long)(idx[2])<<30;
4454 }
4455 long long VertexData::CenterIndex(int depth,const int offSet[DIMENSION],int maxDepth,int idx[DIMENSION]){
4456  for(int i=0;i<DIMENSION;i++){idx[i]=BinaryNode<Real>::CornerIndex(maxDepth+1,depth+1,offSet[i]<<1,1);}
4457  return (long long)(idx[0]) | (long long)(idx[1])<<15 | (long long)(idx[2])<<30;
4458 }
4459 long long VertexData::CornerIndex(const TreeOctNode* node,int cIndex,int maxDepth){
4460  int idx[DIMENSION];
4461  return CornerIndex(node,cIndex,maxDepth,idx);
4462 }
4463 long long VertexData::CornerIndex( const TreeOctNode* node , int cIndex , int maxDepth , int idx[DIMENSION] )
4464 {
4465  int x[DIMENSION];
4466  Cube::FactorCornerIndex( cIndex , x[0] , x[1] , x[2] );
4467  int d , o[3];
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 );
4471 }
4472 long long VertexData::CornerIndex( int depth , const int offSet[DIMENSION] , int cIndex , int maxDepth , int idx[DIMENSION] )
4473 {
4474  int x[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 );
4478 }
4479 long long VertexData::CornerIndexKey( const int idx[DIMENSION] )
4480 {
4481  return (long long)(idx[0]) | (long long)(idx[1])<<15 | (long long)(idx[2])<<30;
4482 }
4483 long long VertexData::FaceIndex(const TreeOctNode* node,int fIndex,int maxDepth){
4484  int idx[DIMENSION];
4485  return FaceIndex(node,fIndex,maxDepth,idx);
4486 }
4487 long long VertexData::FaceIndex(const TreeOctNode* node,int fIndex,int maxDepth,int idx[DIMENSION]){
4488  int dir,offset;
4489  Cube::FactorFaceIndex(fIndex,dir,offset);
4490  int d,o[3];
4491  node->depthAndOffset(d,o);
4492  for(int i=0;i<DIMENSION;i++){idx[i]=BinaryNode<Real>::CornerIndex(maxDepth+1,d+1,o[i]<<1,1);}
4493  idx[dir]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,o[dir],offset);
4494  return (long long)(idx[0]) | (long long)(idx[1])<<15 | (long long)(idx[2])<<30;
4495 }
4496 long long VertexData::EdgeIndex(const TreeOctNode* node,int eIndex,int maxDepth){
4497  int idx[DIMENSION];
4498  return EdgeIndex(node,eIndex,maxDepth,idx);
4499 }
4500 long long VertexData::EdgeIndex(const TreeOctNode* node,int eIndex,int maxDepth,int idx[DIMENSION]){
4501  int o,i1,i2;
4502  int d,off[3];
4503  node->depthAndOffset(d,off);
4504  for(int i=0;i<DIMENSION;i++){idx[i]=BinaryNode<Real>::CornerIndex(maxDepth+1,d+1,off[i]<<1,1);}
4505  Cube::FactorEdgeIndex(eIndex,o,i1,i2);
4506  switch(o){
4507  case 0:
4508  idx[1]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[1],i1);
4509  idx[2]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[2],i2);
4510  break;
4511  case 1:
4512  idx[0]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[0],i1);
4513  idx[2]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[2],i2);
4514  break;
4515  case 2:
4516  idx[0]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[0],i1);
4517  idx[1]=BinaryNode<Real>::CornerIndex(maxDepth+1,d,off[1],i2);
4518  break;
4519  };
4520  return (long long)(idx[0]) | (long long)(idx[1])<<15 | (long long)(idx[2])<<30;
4521 }
4522 
4523 #endif
osg::Vec3f::ValueType dot(const osg::Vec3f &_v1, const osg::Vec3f &_v2)
Adapter for osg vector member computing a scalar product.