#ifndef __CPM__DATASTRUCTURES__QUADEDGEMESH__HXX__ #define __CPM__DATASTRUCTURES__QUADEDGEMESH__HXX__ // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > typename cpm::DataStructures::QuadEdgeMesh< P, D, T >:: TPrimalEdge* cpm::DataStructures::QuadEdgeMesh< P, D, T >:: FindEdge( const PointIdentifier& a ) const { if( a < this->m_OnextRings.size( ) ) return( this->m_OnextRings[ a ] ); else return( NULL ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > typename cpm::DataStructures::QuadEdgeMesh< P, D, T >:: TPrimalEdge* cpm::DataStructures::QuadEdgeMesh< P, D, T >:: FindEdge( const PointIdentifier& a, const PointIdentifier& b ) const { TPrimalEdge* found = NULL; TPrimalEdge* e = this->FindEdge( a ); if( e != NULL ) { typename TPrimalEdge::Iterator eIt = e->BeginOnext( ); for( ; eIt != e->EndOnext( ) && found == NULL; eIt++ ) if( ( *eIt )->GetDestination( ) == b ) found = *eIt; } // fi return( found ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > typename cpm::DataStructures::QuadEdgeMesh< P, D, T >:: TPrimalEdge* cpm::DataStructures::QuadEdgeMesh< P, D, T >:: FindEntryEdge( const CellIdentifier& i ) const { if( i < this->GetNumberOfCells( ) ) { CellAutoPointer c; this->GetCell( i, c ); TQuadEdgeCell* ec = dynamic_cast< TQuadEdgeCell* >( c.GetPointer( ) ); if( ec != NULL ) return( ec->GetEntryPrimalEdge( ) ); else return( NULL ); } else return( NULL ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > const typename cpm::DataStructures::QuadEdgeMesh< P, D, T >:: CntNormals& cpm::DataStructures::QuadEdgeMesh< P, D, T >:: GetPointNormalsContainer( ) const { return( this->m_PointNormals ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > typename cpm::DataStructures::QuadEdgeMesh< P, D, T >:: NormalsIterator cpm::DataStructures::QuadEdgeMesh< P, D, T >:: BeginPointNormals( ) const { return( this->m_PointNormals.begin( ) ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > typename cpm::DataStructures::QuadEdgeMesh< P, D, T >:: NormalsIterator cpm::DataStructures::QuadEdgeMesh< P, D, T >:: EndPointNormals( ) const { return( this->m_PointNormals.end( ) ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > const typename cpm::DataStructures::QuadEdgeMesh< P, D, T >:: VectorType& cpm::DataStructures::QuadEdgeMesh< P, D, T >:: GetPointNormal( const PointIdentifier& id ) const { static const VectorType zero( TScalar( 0 ) ); if( id < this->m_PointNormals.size( ) ) return( this->m_PointNormals[ id ] ); else return( zero ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > bool cpm::DataStructures::QuadEdgeMesh< P, D, T >:: RequestedRegionIsOutsideOfTheBufferedRegion( ) { // Mesh regions don't have meaning with QuadEdges, this is important // in order to guarantee correct pipeline execution return( false ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > void cpm::DataStructures::QuadEdgeMesh< P, D, T >:: SetPoints( PointsContainer* points ) { this->_ReleaseQuadEdgeObjects( ); this->m_OnextRings.resize( points->Size( ), NULL ); this->m_PointNormals.resize( points->Size( ), VectorType( TScalar( 0 ) ) ); this->Superclass::SetPoints( points ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > void cpm::DataStructures::QuadEdgeMesh< P, D, T >:: SetPoint( PointIdentifier id , PointType point ) { // If the point is brand new, add some non-existent edges and normals unsigned long N = this->GetNumberOfPoints( ); N = ( N < id + 1 )? id + 1: N; if( this->m_OnextRings.size( ) < N ) { this->m_OnextRings.resize( N, NULL ); this->m_PointNormals.resize( N, VectorType( TScalar( 0 ) ) ); } // fi // Ok pass it to itk this->Superclass::SetPoint( id, point ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > void cpm::DataStructures::QuadEdgeMesh< P, D, T >:: Initialize( ) { this->Superclass::Initialize( ); this->_ReleaseQuadEdgeObjects( ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > void cpm::DataStructures::QuadEdgeMesh< P, D, T >:: Graft( const itk::DataObject* data ) { this->Superclass::Graft( data ); const Self* mesh = dynamic_cast< const Self* >( data ); if( mesh != NULL ) { this->_ReleaseQuadEdgeObjects( ); this->m_PrimalEdges = mesh->m_PrimalEdges; this->m_DualEdges = mesh->m_DualEdges; this->m_OnextRings = mesh->m_OnextRings; this->m_PointNormals = mesh->m_PointNormals; } // fi } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > void cpm::DataStructures::QuadEdgeMesh< P, D, T >:: SetCells( CellsContainer* cells ) { // Clear cells if( this->GetCells( ) != NULL ) this->SetCells( CellsContainer::New( ) ); this->_ReleaseQuadEdgeObjects( ); this->m_OnextRings.resize( this->GetNumberOfPoints( ), NULL ); // Copy cells if( cells != NULL ) { for( unsigned long cId = 0; cId < cells->Size( ); ++cId ) { CellAutoPointer cell( cells->GetElement( cId ), false ); this->SetCell( cId, cell ); } // rof } // fi } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > void cpm::DataStructures::QuadEdgeMesh< P, D, T >:: SetCellData( CellDataContainer* data ) { /* TODO No need for CellData in initial application: how should this be overridden? */ } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > void cpm::DataStructures::QuadEdgeMesh< P, D, T >:: SetCell( CellIdentifier id, CellAutoPointer& ptr ) { // Overwrite an existing cell? if( id < this->GetNumberOfCells( ) ) { itkExceptionMacro( << "TODO: What do I do here? Trying to overwrite a cell!" ); } // fi // Do not allow to add vertices or edges as cells for the sake of // correct mesh construction if( ptr->GetNumberOfPoints( ) < 3 ) { itkExceptionMacro( << "Face have less than 3 points (" << ptr->GetNumberOfPoints( ) << ")" ); } // fi // Fill up geometrical prerrequisites if( !( this->_CheckPoints( ptr ) ) ) { itkExceptionMacro( << "Points missing in the mesh" ); } // fi // Get (or create) individual edges _TEdges edges; this->_ConstructEdges( edges, ptr ); // Configure new face's geometry edges[ 0 ]->SetLnextRingGeometry( id ); // Update normals typename _TEdges::const_iterator eIt = edges.begin( ); for( ; eIt != edges.end( ); ++eIt ) this->m_PointNormals[ ( *eIt )->GetOrigin( ) ] = this->_ComputePointNormal( *eIt ); // Save cell TQuadEdgeCell* qcell = new TQuadEdgeCell( edges[ 0 ] ); CellAutoPointer cell; cell.TakeOwnership( qcell ); this->Superclass::SetCell( id, cell ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > void cpm::DataStructures::QuadEdgeMesh< P, D, T >:: SetCellData( CellIdentifier id, CellPixelType data ) { /* TODO No need for CellData in initial application: how should this be overridden? */ } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > void cpm::DataStructures::QuadEdgeMesh< P, D, T >:: BuildCellLinks( ) const { // This is no longer required when using QuadEdges } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > cpm::DataStructures::QuadEdgeMesh< P, D, T >:: QuadEdgeMesh( ) : Superclass( ) { this->_ReleaseQuadEdgeObjects( ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > cpm::DataStructures::QuadEdgeMesh< P, D, T >:: ~QuadEdgeMesh( ) { this->_ReleaseQuadEdgeObjects( ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > bool cpm::DataStructures::QuadEdgeMesh< P, D, T >:: _CheckPoints( const CellAutoPointer& ptr ) const { const typename Superclass::PointsContainer* pnts = this->GetPoints( ); bool all_exist = true; typename CellType::PointIdConstIterator pIt = ptr->PointIdsBegin( ); for( ; pIt != ptr->PointIdsEnd( ) && all_exist; ++pIt ) all_exist &= pnts->IndexExists( *pIt ); return( all_exist ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > void cpm::DataStructures::QuadEdgeMesh< P, D, T >:: _DeletePoint( const PointIdentifier& pId ) { PointIdentifier lastId = this->GetNumberOfPoints( ) - 1; if( lastId < pId ) return; // Modify point container PointType to_delete = this->GetPoint( pId ); PointType last = this->GetPoint( lastId ); this->Superclass::SetPoint( pId, last ); // Modify Onext ring and normals containers this->m_OnextRings[ pId ] = this->m_OnextRings[ lastId ]; this->m_PointNormals[ pId ] = this->m_PointNormals[ lastId ]; this->m_OnextRings.pop_back( ); this->m_PointNormals.pop_back( ); // Update origins typename TPrimalEdge::Iterator oIt = this->m_OnextRings[ pId ]->BeginOnext( ); for( ; oIt != this->m_OnextRings[ pId ]->EndOnext( ); ++oIt ) ( *oIt )->SetOrigin( pId ); // Erase the point this->GetPoints( )->CastToSTLContainer( ).pop_back( ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > typename cpm::DataStructures::QuadEdgeMesh< P, D, T >:: TPrimalEdge* cpm::DataStructures::QuadEdgeMesh< P, D, T >:: _CreateQuadEdge( const PointIdentifier& a, const PointIdentifier& b ) { // Create brand new object typename TPrimalEdge::Pointer edge = TPrimalEdge::New( ); edge->CreateRings( ); // Configure geometry edge->SetOrigin( a ); edge->SetDestination( b ); // Keep trace of all reserved memory this->m_PrimalEdges.insert( edge ); this->m_PrimalEdges.insert( edge->GetSym( ) ); this->m_DualEdges.insert( edge->GetRot( ) ); this->m_DualEdges.insert( edge->GetInvRot( ) ); return( edge ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > void cpm::DataStructures::QuadEdgeMesh< P, D, T >:: _DeleteEdge( TPrimalEdge* edge ) { this->m_DualEdges.erase( edge->GetInvRot( ) ); this->m_PrimalEdges.erase( edge->GetSym( ) ); this->m_DualEdges.erase( edge->GetRot( ) ); this->m_PrimalEdges.erase( edge ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > void cpm::DataStructures::QuadEdgeMesh< P, D, T >:: _DeleteFace( const CellIdentifier& f ) { unsigned long cellId = this->GetNumberOfCells( ) - 1; if( cellId < f ) return; // Exchange desired face with last one CellAutoPointer to_delete, last; this->GetCell( f, to_delete ); this->GetCell( cellId, last ); this->Superclass::SetCell( f, last ); this->Superclass::SetCell( cellId, to_delete ); // This will delete cell's memory when to_delete is no longer used to_delete.TakeOwnership( ); // Squeeze container this->GetCells( )->CastToSTLContainer( ).pop_back( ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > void cpm::DataStructures::QuadEdgeMesh< P, D, T >:: _ConstructEdges( _TEdges& edges, const CellAutoPointer& ptr ) { edges.clear( ); typename CellType::PointIdConstIterator pIt = ptr->PointIdsBegin( ); for( pIt = ptr->PointIdsBegin( ); pIt != ptr->PointIdsEnd( ); ++pIt ) { typename CellType::PointIdConstIterator nIt = pIt; ++nIt; if( nIt == ptr->PointIdsEnd( ) ) nIt = ptr->PointIdsBegin( ); TPrimalEdge* edge = this->FindEdge( *pIt, *nIt ); if( edge == NULL ) { edge = this->_CreateQuadEdge( *pIt, *nIt ); if( this->m_OnextRings[ *pIt ] != NULL ) { if( this->m_OnextRings[ *pIt ]->IsOriginInternal( ) ) { itkExceptionMacro( << "Edge [" << *pIt << ", " << *nIt << "] is already internal." ); } // fi // Put edge in Onext ring typename TPrimalEdge::Iterator eIt = this->m_OnextRings[ *pIt ]->BeginOnext( ); while( eIt != this->m_OnextRings[ *pIt ]->EndOnext( ) ) { if( !( ( *eIt )->IsLeftSet( ) ) ) { TPrimalEdge::Splice( *eIt, edge ); eIt = this->m_OnextRings[ *pIt ]->EndOnext( ); } else ++eIt; } // elihw } else this->m_OnextRings[ *pIt ] = edge; } else { if( edge->IsLeftSet( ) ) { itkExceptionMacro( << "Edge [" << edge->GetOrigin( ) << ", " << edge->GetDestination( ) << "] already have a left face (" << edge->GetLeft( ) << "). Face already exits (at least in part)." ); } // fi } // fi edges.push_back( edge ); } // rof // Reorder Onext rings typename _TEdges::iterator ecIt; for( ecIt = edges.begin( ); ecIt != edges.end( ); ++ecIt ) { TPrimalEdge* e = *ecIt; TPrimalEdge* eOprev; if( ecIt != edges.begin( ) ) { typename _TEdges::iterator eOprevIt = ecIt; --eOprevIt; eOprev = ( *eOprevIt )->GetSym( ); } else eOprev = edges.back( )->GetSym( ); TPrimalEdge::ReorderOnextRing( e, eOprev ); } // rof } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > typename cpm::DataStructures::QuadEdgeMesh< P, D, T >:: VectorType cpm::DataStructures::QuadEdgeMesh< P, D, T >:: _ComputePointNormal( const TPrimalEdge* e ) const { static const TScalar zero = TScalar( 0 ); VectorType n( zero ); if( Superclass::PointDimension == 3 ) { PointType p0 = this->GetPoint( e->GetOrigin( ) ); typename TPrimalEdge::ConstIterator eIt = e->BeginOnext( ); unsigned int count = 0; for( ; eIt != e->EndOnext( ); eIt++ ) { if( ( *eIt )->IsLeftSet( ) ) { typename TPrimalEdge::ConstIterator nIt = eIt; nIt++; if( nIt == e->EndOnext( ) ) nIt = e->BeginOnext( ); n += itk::CrossProduct( this->GetPoint( ( *eIt )->GetDestination( ) ) - p0, this->GetPoint( ( *nIt )->GetDestination( ) ) - p0 ); count++; } // fi } // rof TScalar nn = n.GetNorm( ); if( nn > zero && count > 0 ) n /= nn * TScalar( count ); } // fi return( n ); } // ------------------------------------------------------------------------- template< typename P, unsigned int D, typename T > void cpm::DataStructures::QuadEdgeMesh< P, D, T >:: _ReleaseQuadEdgeObjects( ) { this->m_PrimalEdges.clear( ); this->m_OnextRings.clear( ); this->m_DualEdges.clear( ); this->m_PointNormals.clear( ); } #endif // __CPM__DATASTRUCTURES__QUADEDGEMESH__HXX__ // eof - $RCSfile$