| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| SortedTreeNodes::SortedTreeNodes( void ) |
| { |
| _sliceStart = NullPointer( Pointer( int ) ); |
| treeNodes = NullPointer( TreeOctNode* ); |
| _levels = 0; |
| } |
| SortedTreeNodes::~SortedTreeNodes( void ) |
| { |
| if( _sliceStart ) for( int d=0 ; d<_levels ; d++ ) FreePointer( _sliceStart[d] ); |
| FreePointer( _sliceStart ); |
| DeletePointer( treeNodes ); |
| } |
| void SortedTreeNodes::set( TreeOctNode& root , std::vector< int >* map ) |
| { |
| set( root ); |
|
|
| if( map ) |
| { |
| map->resize( _sliceStart[_levels-1][(size_t)1<<(_levels-1)] ); |
| for( int i=0 ; i<_sliceStart[_levels-1][(size_t)1<<(_levels-1)] ; i++ ) (*map)[i] = treeNodes[i]->nodeData.nodeIndex; |
| } |
| for( int i=0 ; i<_sliceStart[_levels-1][(size_t)1<<(_levels-1)] ; i++ ) treeNodes[i]->nodeData.nodeIndex = i; |
| } |
| void SortedTreeNodes::set( TreeOctNode& root ) |
| { |
| _levels = root.maxDepth()+1; |
|
|
| if( _sliceStart ) for( int d=0 ; d<_levels ; d++ ) FreePointer( _sliceStart[d] ); |
| FreePointer( _sliceStart ); |
| DeletePointer( treeNodes ); |
|
|
| _sliceStart = AllocPointer< Pointer( int ) >( _levels ); |
| for( int l=0 ; l<_levels ; l++ ) |
| { |
| _sliceStart[l] = AllocPointer< int >( ((size_t)1<<l)+1 ); |
| memset( _sliceStart[l] , 0 , sizeof(int)*( ((size_t)1<<l)+1 ) ); |
| } |
|
|
| |
| for( TreeOctNode* node = root.nextNode() ; node ; node = root.nextNode( node ) ) |
| { |
| int d , off[3]; |
| node->depthAndOffset( d , off ); |
| _sliceStart[d][ off[2]+1 ]++; |
| } |
|
|
| |
| { |
| int levelOffset = 0; |
| for( int l=0 ; l<_levels ; l++ ) |
| { |
| _sliceStart[l][0] = levelOffset; |
| for( int s=0 ; s<((size_t)1<<l); s++ ) _sliceStart[l][s+1] += _sliceStart[l][s]; |
| levelOffset = _sliceStart[l][(size_t)1<<l]; |
| } |
| } |
| |
| treeNodes = NewPointer< TreeOctNode* >( _sliceStart[_levels-1][(size_t)1<<(_levels-1)] ); |
|
|
| |
| for( TreeOctNode* node=root.nextNode() ; node ; node=root.nextNode( node ) ) |
| { |
| int d , off[3]; |
| node->depthAndOffset( d , off ); |
| treeNodes[ _sliceStart[d][ off[2] ]++ ] = node; |
| } |
|
|
| |
| for( int l=0 ; l<_levels ; l++ ) |
| { |
| for( int s=(1<<l) ; s>0 ; s-- ) _sliceStart[l][s] = _sliceStart[l][s-1]; |
| _sliceStart[l][0] = l>0 ? _sliceStart[l-1][(size_t)1<<(l-1)] : 0; |
| } |
| } |
| SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( const TreeOctNode* node ) { return cTable[ node->nodeData.nodeIndex - nodeOffset ]; } |
| SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( int idx ) { return cTable[ idx - nodeOffset ]; } |
| const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( const TreeOctNode* node ) const { return cTable[ node->nodeData.nodeIndex - nodeOffset ]; } |
| const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( int idx ) const { return cTable[ idx - nodeOffset ]; } |
| SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( const TreeOctNode* node ) { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } |
| SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( int idx ) { return eTable[ idx - nodeOffset ]; } |
| const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( const TreeOctNode* node ) const { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } |
| const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( int idx ) const { return eTable[ idx - nodeOffset ]; } |
| SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( const TreeOctNode* node ) { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } |
| SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( int idx ) { return fTable[ idx - nodeOffset ]; } |
| const SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( const TreeOctNode* node ) const { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } |
| const SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( int idx ) const { return fTable[ idx - nodeOffset ]; } |
| SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( const TreeOctNode* node ) { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } |
| SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( int idx ) { return eTable[ idx - nodeOffset ]; } |
| const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( const TreeOctNode* node ) const { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } |
| const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( int idx ) const { return eTable[ idx - nodeOffset ]; } |
| SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( const TreeOctNode* node ) { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } |
| SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( int idx ) { return fTable[ idx - nodeOffset ]; } |
| const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( const TreeOctNode* node ) const { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } |
| const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( int idx ) const { return fTable[ idx - nodeOffset ]; } |
|
|
| void SortedTreeNodes::setSliceTableData( SliceTableData& sData , int depth , int offset , int threads ) const |
| { |
| |
| typedef OctNode< TreeNodeData >::template ConstNeighborKey< 1 , 1 > ConstAdjacenctNodeKey; |
| if( offset<0 || offset>((size_t)1<<depth) ) return; |
| if( threads<=0 ) threads = 1; |
| |
| std::pair< int , int > span( _sliceStart[depth][ std::max< int >( 0 , offset-1 ) ] , _sliceStart[depth][ std::min< int >( (size_t)1<<depth , offset+1 ) ] ); |
| sData.nodeOffset = span.first; |
| sData.nodeCount = span.second - span.first; |
|
|
| DeletePointer( sData._cMap ) ; DeletePointer( sData._eMap ) ; DeletePointer( sData._fMap ); |
| DeletePointer( sData.cTable ) ; DeletePointer( sData.eTable ) ; DeletePointer( sData.fTable ); |
| if( sData.nodeCount ) |
| { |
| sData._cMap = NewPointer< int >( sData.nodeCount * Square::CORNERS ); |
| sData._eMap = NewPointer< int >( sData.nodeCount * Square::EDGES ); |
| sData._fMap = NewPointer< int >( sData.nodeCount * Square::FACES ); |
| sData.cTable = NewPointer< typename SortedTreeNodes::SquareCornerIndices >( sData.nodeCount ); |
| sData.eTable = NewPointer< typename SortedTreeNodes::SquareCornerIndices >( sData.nodeCount ); |
| sData.fTable = NewPointer< typename SortedTreeNodes::SquareFaceIndices >( sData.nodeCount ); |
| memset( sData._cMap , 0 , sizeof(int) * sData.nodeCount * Square::CORNERS ); |
| memset( sData._eMap , 0 , sizeof(int) * sData.nodeCount * Square::EDGES ); |
| memset( sData._fMap , 0 , sizeof(int) * sData.nodeCount * Square::FACES ); |
| } |
| std::vector< ConstAdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); |
| for( size_t i=0 ; i<neighborKeys.size() ; i++ ) neighborKeys[i].set( depth ); |
| #pragma omp parallel for num_threads( threads ) |
| for( int i=span.first ; i<span.second ; i++ ) |
| { |
| ConstAdjacenctNodeKey& neighborKey = neighborKeys[ omp_get_thread_num() ]; |
| TreeOctNode* node = treeNodes[i]; |
| const TreeOctNode::ConstNeighbors< 3 >& neighbors = neighborKey.getNeighbors( node ); |
| int d , off[3]; |
| node->depthAndOffset( d , off ); |
| int z; |
| if ( off[2]==offset-1 ) z = 1; |
| else if( off[2]==offset ) z = 0; |
| else fprintf( stderr , "[ERROR] Node out of bounds: %d %d\n" , offset , off[2] ) , exit( 0 ); |
| |
| for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) |
| { |
| int c = Cube::CornerIndex( x , y , z ); |
| int fc = Square::CornerIndex( x , y ); |
| bool cornerOwner = true; |
| int ac = Cube::AntipodalCornerIndex(c); |
| for( int cc=0 ; cc<Cube::CORNERS ; cc++ ) |
| { |
| int xx , yy , zz; |
| Cube::FactorCornerIndex( cc , xx , yy , zz ); |
| xx += x , yy += y , zz += z; |
| if( neighbors.neighbors[xx][yy][zz] && cc<ac ){ cornerOwner = false ; break; } |
| } |
| if( cornerOwner ) |
| { |
| int myCount = (i - sData.nodeOffset) * Square::CORNERS + fc; |
| sData._cMap[ myCount ] = 1; |
| for( int cc=0 ; cc<Cube::CORNERS ; cc++ ) |
| { |
| int xx , yy , zz; |
| Cube::FactorCornerIndex( cc , xx , yy , zz ); |
| int ac = Square::CornerIndex( 1-xx , 1-yy ); |
| xx += x , yy += y , zz += z; |
| if( neighbors.neighbors[xx][yy][zz] ) sData.cornerIndices( neighbors.neighbors[xx][yy][zz] )[ac] = myCount; |
| } |
| } |
| } |
| |
| for( int o=0 ; o<2 ; o++ ) for( int y=0 ; y<2 ; y++ ) |
| { |
| int fe = Square::EdgeIndex( o , y ); |
| bool edgeOwner = true; |
|
|
| int ac = Square::AntipodalCornerIndex( Square::CornerIndex( y , z ) ); |
| for( int cc=0 ; cc<Square::CORNERS ; cc++ ) |
| { |
| int ii , jj , xx , yy , zz; |
| Square::FactorCornerIndex( cc , ii , jj ); |
| ii += y , jj += z; |
| switch( o ) |
| { |
| case 0: yy = ii , zz = jj , xx = 1 ; break; |
| case 1: xx = ii , zz = jj , yy = 1 ; break; |
| } |
| if( neighbors.neighbors[xx][yy][zz] && cc<ac ){ edgeOwner = false ; break; } |
| } |
| if( edgeOwner ) |
| { |
| int myCount = ( i - sData.nodeOffset ) * Square::EDGES + fe; |
| sData._eMap[ myCount ] = 1; |
| |
| for( int cc=0 ; cc<Square::CORNERS ; cc++ ) |
| { |
| int ii , jj , aii , ajj , xx , yy , zz; |
| Square::FactorCornerIndex( cc , ii , jj ); |
| Square::FactorCornerIndex( Square::AntipodalCornerIndex( cc ) , aii , ajj ); |
| ii += y , jj += z; |
| switch( o ) |
| { |
| case 0: yy = ii , zz = jj , xx = 1 ; break; |
| case 1: xx = ii , zz = jj , yy = 1 ; break; |
| } |
| if( neighbors.neighbors[xx][yy][zz] ) sData.edgeIndices( neighbors.neighbors[xx][yy][zz] )[ Square::EdgeIndex( o , aii ) ] = myCount; |
| } |
| } |
| } |
| |
| { |
| bool faceOwner = !( neighbors.neighbors[1][1][2*z] && !z ); |
| if( faceOwner ) |
| { |
| int myCount = ( i - sData.nodeOffset ) * Square::FACES; |
| sData._fMap[ myCount ] = 1; |
| |
| sData.faceIndices( node )[0] = myCount; |
| if( neighbors.neighbors[1][1][2*z] ) sData.faceIndices( neighbors.neighbors[1][1][2*z] )[0] = myCount; |
| } |
| } |
| } |
| int cCount = 0 , eCount = 0 , fCount = 0; |
|
|
| for( size_t i=0 ; i<sData.nodeCount * Square::CORNERS ; i++ ) if( sData._cMap[i] ) sData._cMap[i] = cCount++; |
| for( size_t i=0 ; i<sData.nodeCount * Square::EDGES ; i++ ) if( sData._eMap[i] ) sData._eMap[i] = eCount++; |
| for( size_t i=0 ; i<sData.nodeCount * Square::FACES ; i++ ) if( sData._fMap[i] ) sData._fMap[i] = fCount++; |
| #pragma omp parallel for num_threads( threads ) |
| for( int i=0 ; i<sData.nodeCount ; i++ ) |
| { |
| for( int j=0 ; j<Square::CORNERS ; j++ ) sData.cTable[i][j] = sData._cMap[ sData.cTable[i][j] ]; |
| for( int j=0 ; j<Square::EDGES ; j++ ) sData.eTable[i][j] = sData._eMap[ sData.eTable[i][j] ]; |
| for( int j=0 ; j<Square::FACES ; j++ ) sData.fTable[i][j] = sData._fMap[ sData.fTable[i][j] ]; |
| } |
|
|
| sData.cCount = cCount , sData.eCount = eCount , sData.fCount = fCount; |
| } |
| void SortedTreeNodes::setXSliceTableData( XSliceTableData& sData , int depth , int offset , int threads ) const |
| { |
| typedef OctNode< TreeNodeData >::template ConstNeighborKey< 1 , 1 > ConstAdjacenctNodeKey; |
| if( offset<0 || offset>=((size_t)1<<depth) ) return; |
| if( threads<=0 ) threads = 1; |
| |
| std::pair< int , int > span( _sliceStart[depth][offset] , _sliceStart[depth][offset+1] ); |
| sData.nodeOffset = span.first; |
| sData.nodeCount = span.second - span.first; |
|
|
| DeletePointer( sData._eMap ) ; DeletePointer( sData._fMap ); |
| DeletePointer( sData.eTable ) ; DeletePointer( sData.fTable ); |
| if( sData.nodeCount ) |
| { |
| sData._eMap = NewPointer< int >( sData.nodeCount * Square::CORNERS ); |
| sData._fMap = NewPointer< int >( sData.nodeCount * Square::EDGES ); |
| sData.eTable = NewPointer< typename SortedTreeNodes::SquareCornerIndices >( sData.nodeCount ); |
| sData.fTable = NewPointer< typename SortedTreeNodes::SquareEdgeIndices >( sData.nodeCount ); |
| memset( sData._eMap , 0 , sizeof(int) * sData.nodeCount * Square::CORNERS ); |
| memset( sData._fMap , 0 , sizeof(int) * sData.nodeCount * Square::EDGES ); |
| } |
|
|
| std::vector< ConstAdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); |
| for( size_t i=0 ; i<neighborKeys.size() ; i++ ) neighborKeys[i].set( depth ); |
| #pragma omp parallel for num_threads( threads ) |
| for( int i=span.first ; i<span.second ; i++ ) |
| { |
| ConstAdjacenctNodeKey& neighborKey = neighborKeys[ omp_get_thread_num() ]; |
| TreeOctNode* node = treeNodes[i]; |
| const TreeOctNode::ConstNeighbors<3>& neighbors = neighborKey.getNeighbors( node ); |
| int d , off[3]; |
| node->depthAndOffset( d , off ); |
| |
| int o=2; |
| for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) |
| { |
| int fc = Square::CornerIndex( x , y ); |
| bool edgeOwner = true; |
|
|
| int ac = Square::AntipodalCornerIndex( Square::CornerIndex( x , y ) ); |
| for( int cc=0 ; cc<Square::CORNERS ; cc++ ) |
| { |
| int ii , jj , xx , yy , zz; |
| Square::FactorCornerIndex( cc , ii , jj ); |
| ii += x , jj += y; |
| xx = ii , yy = jj , zz = 1; |
| if( neighbors.neighbors[xx][yy][zz] && cc<ac ){ edgeOwner = false ; break; } |
| } |
| if( edgeOwner ) |
| { |
| int myCount = ( i - sData.nodeOffset ) * Square::CORNERS + fc; |
| sData._eMap[ myCount ] = 1; |
|
|
| |
| for( int cc=0 ; cc<Square::CORNERS ; cc++ ) |
| { |
| int ii , jj , aii , ajj , xx , yy , zz; |
| Square::FactorCornerIndex( cc , ii , jj ); |
| Square::FactorCornerIndex( Square::AntipodalCornerIndex( cc ) , aii , ajj ); |
| ii += x , jj += y; |
| xx = ii , yy = jj , zz = 1; |
| if( neighbors.neighbors[xx][yy][zz] ) sData.edgeIndices( neighbors.neighbors[xx][yy][zz] )[ Square::CornerIndex( aii , ajj ) ] = myCount; |
| } |
| } |
| } |
| |
| for( int o=0 ; o<2 ; o++ ) for( int y=0 ; y<2 ; y++ ) |
| { |
| bool faceOwner; |
| if( o==0 ) faceOwner = !( neighbors.neighbors[1][2*y][1] && !y ); |
| else faceOwner = !( neighbors.neighbors[2*y][1][1] && !y ); |
| if( faceOwner ) |
| { |
| int fe = Square::EdgeIndex( o , y ); |
| int ae = Square::EdgeIndex( o , 1-y ); |
| int myCount = ( i - sData.nodeOffset ) * Square::EDGES + fe; |
| sData._fMap[ myCount ] = 1; |
| |
| sData.faceIndices( node )[fe] = myCount; |
| if( o==0 && neighbors.neighbors[1][2*y][1] ) sData.faceIndices( neighbors.neighbors[1][2*y][1] )[ae] = myCount; |
| if( o==1 && neighbors.neighbors[2*y][1][1] ) sData.faceIndices( neighbors.neighbors[2*y][1][1] )[ae] = myCount; |
| } |
| } |
| } |
| int eCount = 0 , fCount = 0; |
|
|
| for( size_t i=0 ; i<sData.nodeCount * Square::CORNERS ; i++ ) if( sData._eMap[i] ) sData._eMap[i] = eCount++; |
| for( size_t i=0 ; i<sData.nodeCount * Square::EDGES ; i++ ) if( sData._fMap[i] ) sData._fMap[i] = fCount++; |
| #pragma omp parallel for num_threads( threads ) |
| for( int i=0 ; i<sData.nodeCount ; i++ ) |
| { |
| for( int j=0 ; j<Square::CORNERS ; j++ ) sData.eTable[i][j] = sData._eMap[ sData.eTable[i][j] ]; |
| for( int j=0 ; j<Square::EDGES ; j++ ) sData.fTable[i][j] = sData._fMap[ sData.fTable[i][j] ]; |
| } |
|
|
| sData.eCount = eCount , sData.fCount = fCount; |
| } |
|
|