void GW_Mesh::CheckIntegrity() { for( GW_U32 i=0; i<this->GetNbrVertex(); ++i ) { GW_Vertex* pVert = this->GetVertex(i); GW_ASSERT( pVert!=NULL ); GW_Face* pFace = pVert->GetFace(); GW_ASSERT( pFace!=NULL ); if( pFace!=NULL && pFace->GetVertex(0)!=pVert && pFace->GetVertex(1)!=pVert && pFace->GetVertex(2)!=pVert ) GW_ASSERT( GW_False ); } for( GW_U32 i=0; i<this->GetNbrFace(); ++i ) { GW_Face* pFace = this->GetFace(i); GW_ASSERT( pFace!=NULL ); for( GW_U32 k=0; k<3; ++k ) { GW_U32 k1 = (k+1)%3; GW_U32 k2 = (k+2)%3; GW_Face* pNeighFace = pFace->GetFaceNeighbor(k); GW_Vertex* pV1 = pFace->GetVertex(k1); GW_ASSERT( pV1!=NULL ); GW_Vertex* pV2 = pFace->GetVertex(k2); GW_ASSERT( pV2!=NULL ); if( pNeighFace!=NULL ) { GW_ASSERT( pNeighFace->GetFaceNeighbor(*pV1, *pV2)==pFace ); GW_ASSERT( pFace->GetFaceNeighbor(*pV1, *pV2)==pNeighFace); } } } }
/*------------------------------------------------------------------------------*/ void GW_Mesh::FlipOrientation() { for( GW_U32 i=0; i<this->GetNbrFace(); ++i ) { GW_Face* pFace = this->GetFace(i); GW_ASSERT( pFace!=NULL ); pFace->SetVertex( *pFace->GetVertex(1), *pFace->GetVertex(0), *pFace->GetVertex(2) ); pFace->SetFaceNeighbor( pFace->GetFaceNeighbor(1), pFace->GetFaceNeighbor(0), pFace->GetFaceNeighbor(2) ); } }
/*------------------------------------------------------------------------------*/ void GW_Mesh::ReOrientMesh( GW_Face& start_face ) { /* march on the voronoi diagram */ T_FaceList FaceToProceed; FaceToProceed.push_back( &start_face ); T_FaceMap FaceDone; FaceDone[ start_face.GetID() ] = &start_face; while( !FaceToProceed.empty() ) { GW_Face* pFace = FaceToProceed.front(); GW_ASSERT( pFace!=NULL ); FaceToProceed.pop_front(); /* add neighbors */ for( GW_U32 i=0; i<3; ++i ) { GW_Vertex* pVertDir = pFace->GetVertex(i); GW_ASSERT( pVertDir!=NULL ); GW_Face* pNewFace = pFace->GetFaceNeighbor(*pVertDir); if( pNewFace!=NULL && FaceDone.find(pNewFace->GetID())==FaceDone.end() ) { /* find the two other vertices */ GW_U32 i1 = (i+1)%3; GW_U32 i2 = (i+2)%3; GW_Vertex* pNewVert[3]; pNewVert[0] = pFace->GetVertex(i2); GW_ASSERT( pNewVert[0]!=NULL ); pNewVert[1] = pFace->GetVertex(i1); GW_ASSERT( pNewVert[1]!=NULL ); pNewVert[2] = pNewFace->GetVertex(*pNewVert[0], *pNewVert[1]); GW_ASSERT( pNewVert[2]!=NULL ); GW_Face* pNeigh[3]; pNeigh[0] = pNewFace->GetFaceNeighbor( *pNewVert[0] ); pNeigh[1] = pNewFace->GetFaceNeighbor( *pNewVert[1] ); pNeigh[2] = pNewFace->GetFaceNeighbor( *pNewVert[2] ); /* reorient the face */ pNewFace->SetVertex( *pNewVert[0], *pNewVert[1], *pNewVert[2] ); pNewFace->SetFaceNeighbor( pNeigh[0], pNeigh[1], pNeigh[2] ); FaceToProceed.push_back( pNewFace ); FaceDone[ pNewFace->GetID() ] = pNewFace; // so that it won't be added anymore } } } /* check for global orientation (just an heuristic) */ GW_Face* pFace = this->GetFace(0); GW_ASSERT( pFace!=NULL ); GW_Vector3D v = pFace->GetVertex(0)->GetPosition() + pFace->GetVertex(1)->GetPosition() + pFace->GetVertex(2)->GetPosition(); GW_Vector3D n = pFace->ComputeNormal(); if( n*v<0 ) this->FlipOrientation(); }
/*------------------------------------------------------------------------------*/ void GW_Mesh::IterateConnectedComponent_Face( GW_Face& start_face, FaceIterate_Callback pCallback ) { /* march on the voronoi diagram */ T_FaceList FaceToProceed; FaceToProceed.push_back( &start_face ); T_FaceMap FaceDone; FaceDone[ start_face.GetID() ] = &start_face; while( !FaceToProceed.empty() ) { GW_Face* pFace = FaceToProceed.front(); GW_ASSERT( pFace!=NULL ); FaceToProceed.pop_front(); /* cut the face */ pCallback( *pFace ); /* add neighbors */ for( GW_U32 i=0; i<3; ++i ) { GW_Face* pNewFace = pFace->GetFaceNeighbor(i); if( pNewFace!=NULL && FaceDone.find(pNewFace->GetID())==FaceDone.end() ) { FaceToProceed.push_back( pNewFace ); FaceDone[ pNewFace->GetID() ] = pNewFace; // so that it won't be added anymore } } } }
/*------------------------------------------------------------------------------*/ void GW_Mesh::BuildConnectivity() { T_FaceList* VertexToFaceMap = new T_FaceList[this->GetNbrVertex()]; /* build the inverse map vertex->face */ for( IT_FaceVector it = FaceVector_.begin(); it!=FaceVector_.end(); ++it ) { GW_Face* pFace = *it; GW_ASSERT( pFace!=NULL ); for( GW_U32 i=0; i<3; ++i ) { GW_Vertex* pVert = pFace->GetVertex(i); GW_ASSERT(pVert!=NULL); GW_ASSERT( pVert->GetID() <= this->GetNbrVertex() ); VertexToFaceMap[pVert->GetID()].push_back( pFace ); } } /* now we can set up connectivity */ for( IT_FaceVector it=FaceVector_.begin(); it!=FaceVector_.end(); ++it ) { GW_Face* pFace = *it; GW_ASSERT( pFace!=NULL ); /* set up the neigbooring faces of the 3 vertices */ T_FaceList* pFaceLists[3]; for( GW_U32 i=0; i<3; ++i ) { GW_Vertex* pVert = pFace->GetVertex(i); pFaceLists[i] = &VertexToFaceMap[pVert->GetID()]; } /* compute neighbor in the 3 directions */ for( GW_U32 i=0; i<3; ++i ) { GW_Face* pNeighbor = NULL; GW_U32 i1 = (i+1)%3; GW_U32 i2 = (i+2)%3; /* we must find the intersection of the surrounding faces of these 2 vertex */ GW_Bool bFind = GW_False; for( IT_FaceList it1 = pFaceLists[i1]->begin(); it1!=pFaceLists[i1]->end() && bFind!=GW_True; ++it1 ) { GW_Face* pFace1 = *it1; for( IT_FaceList it2 = pFaceLists[i2]->begin(); it2!=pFaceLists[i2]->end() && bFind!=GW_True; ++it2 ) { GW_Face* pFace2 = *it2; if( pFace1==pFace2 && pFace1!=pFace ) { pNeighbor = pFace1; bFind=GW_True; } } } // GW_ASSERT( pNeighbor!=NULL ); /* assign the face */ /* if( pFace->GetFaceNeighbor(i)!=NULL ) GW_ASSERT( pFace->GetFaceNeighbor(i)==pNeighbor ); */ pFace->SetFaceNeighbor( pNeighbor, i ); /* make some test on the neighbor to assure symetry in the connectivity relationship */ if( pNeighbor!=NULL ) { GW_I32 nEdgeNumber = pNeighbor->GetEdgeNumber( *pFace->GetVertex(i1),*pFace->GetVertex(i2) ); GW_ASSERT( nEdgeNumber>=0 ); #if 0 if( pNeighbor->GetFaceNeighbor( nEdgeNumber )!=NULL ) GW_ASSERT(pNeighbor->GetFaceNeighbor(nEdgeNumber)==pFace); #endif pNeighbor->SetFaceNeighbor( pFace, nEdgeNumber ); } } } GW_DELETEARRAY( VertexToFaceMap ); }
/* progression : \todo take in acount NULL pointer */ void GW_FaceIterator::operator++() { /*!! if( nNbrIncrement_>100 ) { GW_ASSERT( GW_False ); (*this) = GW_FaceIterator(NULL,NULL,NULL); return; }*/ if( pFace_!=NULL && pDirection_!=NULL && pOrigin_!=NULL ) { GW_Face* pNextFace = pFace_->GetFaceNeighbor( *pDirection_ ); /* check for end() */ if( pNextFace==pOrigin_->GetFace() ) { (*this) = GW_FaceIterator(NULL,NULL,NULL); } else { if( pNextFace==NULL ) { /* we are on a border face : Rewind on the first face */ GW_Face* pPrevFace = pFace_; pDirection_ = pFace_->GetVertex( *pDirection_, *pOrigin_ ); // get rewind direction GW_ASSERT( pDirection_!=NULL ); GW_U32 nIter = 0; do { pFace_ = pPrevFace; pPrevFace = pPrevFace->GetFaceNeighbor( *pDirection_ ); pDirection_ = pFace_->GetVertex( *pOrigin_, *pDirection_ ); // next direction nIter++; GW_ASSERT( nIter<20 ); if( nIter>=20 ) { // this is on non-manifold ... (*this) = GW_FaceIterator(NULL,NULL,NULL); return; } } while( pPrevFace!=NULL ); if( pFace_==pOrigin_->GetFace() ) { // we are on End. (*this) = GW_FaceIterator(NULL,NULL,NULL); } else { GW_ASSERT( pDirection_!=NULL ); (*this) = GW_FaceIterator( pFace_, pOrigin_, pDirection_, nNbrIncrement_+1 ); } return; } GW_Vertex* pNextDirection = pFace_->GetVertex( *pOrigin_, *pDirection_ ); GW_ASSERT( pNextDirection!=NULL ); (*this) = GW_FaceIterator( pNextFace, pOrigin_, pNextDirection, nNbrIncrement_+1 ); } } else { (*this) = GW_FaceIterator(NULL,NULL,NULL); } }
/*------------------------------------------------------------------------------*/ void GW_VoronoiMesh::FixHole() { typedef std::pair<GW_VoronoiVertex*, GW_VoronoiVertex*> T_VertexPair; typedef std::list<T_VertexPair> T_VertexPairList; typedef T_VertexPairList::iterator IT_VertexPairList; T_VertexPairList VertexPairList; for( GW_U32 i=0; i<this->GetNbrFace(); ++i ) { GW_Face* pFace = this->GetFace(i); GW_ASSERT( pFace!=NULL ); for( GW_U32 nV = 0; nV<3; ++nV ) { if( pFace->GetFaceNeighbor(nV)==NULL ) { GW_VoronoiVertex* pVert1 = (GW_VoronoiVertex*) pFace->GetVertex( (nV+1)%3 ); GW_VoronoiVertex* pVert2 = (GW_VoronoiVertex*) pFace->GetVertex( (nV+2)%3 ); VertexPairList.push_back( T_VertexPair(pVert1,pVert2) ); } } } char str[50]; sprintf( str, "%d boundary edges detected.", VertexPairList.size() ); GW_OutputComment( str ); while( !VertexPairList.empty() ) { T_VertexPairList HoleBorder; T_VertexPair StartEdge = VertexPairList.front(); T_VertexPair CurEdge = StartEdge; VertexPairList.pop_front(); HoleBorder.push_back( CurEdge ); /* try to find the hole border */ GW_Bool bNextEdgeFound = GW_False; while( true ) { bNextEdgeFound = GW_False; for( IT_VertexPairList it = VertexPairList.begin(); it!=VertexPairList.end(); ++it ) { T_VertexPair NewEdge = *it; if( (NewEdge.first==CurEdge.second) && (NewEdge.second!=CurEdge.first) ) { CurEdge = NewEdge; HoleBorder.push_back( CurEdge ); bNextEdgeFound = GW_True; VertexPairList.erase( it ); break; } if( (NewEdge.second==CurEdge.second) && (NewEdge.first!=CurEdge.first) ) { CurEdge = T_VertexPair( NewEdge.second, NewEdge.first); HoleBorder.push_back( CurEdge ); bNextEdgeFound = GW_True; VertexPairList.erase( it ); break; } } if( !bNextEdgeFound ) break; // the hole cannot be completed if( StartEdge.first == CurEdge.second ) break; // the hole is completed } if( bNextEdgeFound && HoleBorder.size()>2 ) // that means we have a full hole { char str[50]; sprintf( str, "Filing a hole of %d vertex.", HoleBorder.size() ); GW_OutputComment( str ); IT_VertexPairList it = HoleBorder.begin(); GW_VoronoiVertex* pVert0 = it->first; GW_ASSERT( pVert0!=NULL ); it++; GW_VoronoiVertex* pVert1 = it->first; GW_ASSERT( pVert1!=NULL ); it++; for( ; it!=HoleBorder.end(); ++it ) { GW_VoronoiVertex* pVert2 = it->first; GW_ASSERT( pVert2!=NULL ); /* test for manifold structure before creating a new edge [v0,v2] */ GW_Bool bManifold = GW_True; GW_Face* pFace1, *pFace2; pVert0->GetFaces( *pVert1, pFace1, pFace2 ); if( pFace1!=NULL && pFace2!=NULL ) bManifold = GW_False; pVert1->GetFaces( *pVert2, pFace1, pFace2 ); if( pFace1!=NULL && pFace2!=NULL ) bManifold = GW_False; pVert0->GetFaces( *pVert2, pFace1, pFace2 ); if( pFace1!=NULL && pFace2!=NULL ) bManifold = GW_False; if( bManifold ) { GW_Face& Face = this->CreateNewFace(); Face.SetVertex( *pVert0, *pVert1, *pVert2 ); this->AddFace( Face ); } pVert1 = pVert2; } } } }