GW_I32 GW_ASELoader::Load(GW_Mesh& Mesh, const char *name, GW_I32 bits) { FILE *strm = fopen(name, "r"); if (!strm) return GW_Error_Opening_File; Release(); want = bits; GetInfo(strm); Allocate(); GetData(strm); fclose(strm); if (want & kNormals) MakeNormals(); if (want & kTexCoord && numTexVerts) Align(); else if (want & kTexCoord && !numTexVerts) return 0; numIndex = numFaces * 3; /* retrieve information */ Mesh.SetNbrVertex( this->GetNumVerts() ); Mesh.SetNbrFace( this->GetNumFaces() ); GW_U32* pFace = this->GetFaces(); GW_Real32* pVert = this->GetVerts(); GW_Real32* pNormal = this->GetVertNormals(); GW_Real32* pTexture = this->GetTexture(); GW_Vertex* pCurVert = NULL; GW_Vector3D Pos, Normal; std::map<int, int> VertCorrespondance; /* load vertex */ for( GW_I32 i=0; i<this->GetNumVerts(); ++i ) { Pos = GW_Vector3D( pVert[3*i], pVert[3*i+1], pVert[3*i+2] ); /* this is to avoid an annoying problem of vertex duplication */ for( GW_I32 j=0; j<i; ++j ) { if( GW_ABS(pVert[3*i+0] - pVert[3*j+0])<GW_EPSILON && GW_ABS(pVert[3*i+1] - pVert[3*j+1])<GW_EPSILON && GW_ABS(pVert[3*i+2] - pVert[3*j+2])<GW_EPSILON ) VertCorrespondance[j] = i; } if( pNormal!=NULL ) Normal = GW_Vector3D( pNormal[3*i], pNormal[3*i+1], pNormal[3*i+2] ); pCurVert = &Mesh.CreateNewVertex(); pCurVert->SetPosition( Pos ); pCurVert->SetNormal( Normal ); if( want & kTexCoord ) { for( GW_U32 s=0; s<1; ++s ) { if( pTexture[2*i+s]<0 ) pTexture[2*i+s] += 1; if( pTexture[2*i+s]>1 ) pTexture[2*i+s] -= 1; } pCurVert->SetTexCoords( pTexture[2*i+0], pTexture[2*i+1] ); } Mesh.SetVertex( i, pCurVert ); } /* load faces */ GW_Face* pCurFace = NULL; for( GW_I32 i=0; i<this->GetNumFaces(); ++i ) { pCurFace = &Mesh.CreateNewFace(); GW_U32 FaceNumber[3]; for( GW_U32 s=0; s<3; ++s ) { FaceNumber[s] = pFace[3*i+s]; if( VertCorrespondance.find(FaceNumber[s])!=VertCorrespondance.end() ) FaceNumber[s] = VertCorrespondance[FaceNumber[s]]; } pCurFace->SetVertex( *Mesh.GetVertex(FaceNumber[0]), *Mesh.GetVertex(FaceNumber[1]), *Mesh.GetVertex(FaceNumber[2]) ); Mesh.SetFace( i, pCurFace ); } return GW_OK; }
/*------------------------------------------------------------------------------*/ 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(); }
/* 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); } }
/*------------------------------------------------------------------------------*/ GW_Vertex* GW_Mesh::InsertVertexInEdge( GW_Vertex& Vert1, GW_Vertex& Vert2, GW_Float x, GW_Bool& bIsNewVertCreated ) { if( x<GW_EPSILON ) { bIsNewVertCreated = GW_False; return &Vert2; } if( x>1-GW_EPSILON ) { bIsNewVertCreated = GW_False; return &Vert1; } bIsNewVertCreated = GW_True; /* create the new vertex */ GW_Vertex* pNewVert = &this->CreateNewVertex(); this->SetNbrVertex( this->GetNbrVertex()+1 ); this->SetVertex( this->GetNbrVertex()-1, pNewVert ); /* set position */ pNewVert->SetPosition( Vert1.GetPosition()*x + Vert2.GetPosition()*(1-x) ); /* retrieve the neigbor faces face */ GW_Face* pFace1 = NULL; GW_Face* pFace2 = NULL; Vert1.GetFaces( Vert2, pFace1, pFace2 ); GW_ASSERT( pFace1!=NULL || pFace2!=NULL ); /* assign the face of new vertex */ if( pFace1!=NULL ) pNewVert->SetFace( *pFace1 ); else if( pFace2!=NULL ) pNewVert->SetFace( *pFace2 ); GW_I32 nVert1Num1, nVert1Num2, nVert1Num3, nVert2Num1, nVert2Num2, nVert2Num3; GW_Face* pNewFace1 = NULL; GW_Face* pNewFace2 = NULL; if( pFace1!=NULL ) { nVert1Num1 = pFace1->GetEdgeNumber( Vert1 ); GW_ASSERT( nVert1Num1>=0 ); nVert1Num2 = pFace1->GetEdgeNumber( Vert2 ); GW_ASSERT( nVert1Num2>=0 ); nVert1Num3 = 3-nVert1Num2-nVert1Num1; pNewFace1 = &this->CreateNewFace(); this->SetNbrFace( this->GetNbrFace()+1 ); this->SetFace( this->GetNbrFace()-1, pNewFace1 ); pNewFace1->SetVertex( *pFace1->GetVertex(nVert1Num3), nVert1Num3 ); pNewFace1->SetVertex( Vert2, nVert1Num2 ); pNewFace1->SetVertex( *pNewVert, nVert1Num1 ); /* connectivity between Face1 and new face */ GW_Face* pFaceNeighbor = pFace1->GetFaceNeighbor(nVert1Num1); pNewFace1->SetFaceNeighbor( pFaceNeighbor, nVert1Num1 ); pNewFace1->SetFaceNeighbor( pFace1, nVert1Num2 ); if( pFaceNeighbor!=NULL ) { GW_I32 nNum = pFaceNeighbor->GetEdgeNumber( Vert2, *pFace1->GetVertex(nVert1Num3) ); GW_ASSERT( nNum>=0 ); pFaceNeighbor->SetFaceNeighbor( pNewFace1, nNum ); } /* connectivity for face 1 */ pFace1->SetFaceNeighbor( pNewFace1, nVert1Num1 ); pFace1->SetVertex( *pNewVert, nVert1Num2 ); /* reassign vertex 2 */ Vert2.SetFace( *pNewFace1 ); } if( pFace2!=NULL ) { nVert2Num1 = pFace2->GetEdgeNumber( Vert1 ); GW_ASSERT( nVert2Num1>=0 ); nVert2Num2 = pFace2->GetEdgeNumber( Vert2 ); GW_ASSERT( nVert2Num2>=0 ); nVert2Num3 = 3-nVert2Num2-nVert2Num1; pNewFace2 = &this->CreateNewFace(); this->SetNbrFace( this->GetNbrFace()+1 ); this->SetFace( this->GetNbrFace()-1, pNewFace2 ); pNewFace2->SetVertex( *pFace2->GetVertex(nVert2Num3), nVert2Num3 ); pNewFace2->SetVertex( Vert2, nVert2Num2 ); pNewFace2->SetVertex( *pNewVert, nVert2Num1 ); /* connectivity between Face2 and new face */ GW_Face* pFaceNeighbor = pFace2->GetFaceNeighbor(nVert2Num1); pNewFace2->SetFaceNeighbor( pFaceNeighbor, nVert2Num1 ); pNewFace2->SetFaceNeighbor( pFace2, nVert2Num2 ); if( pFaceNeighbor!=NULL ) { GW_I32 nNum = pFaceNeighbor->GetEdgeNumber( Vert2, *pFace2->GetVertex(nVert2Num3) ); GW_ASSERT( nNum>=0 ); pFaceNeighbor->SetFaceNeighbor( pNewFace2, nNum ); } /* connectivity for face 1 */ pFace2->SetFaceNeighbor( pNewFace2, nVert2Num1 ); pFace2->SetVertex( *pNewVert, nVert2Num2 ); /* reassign vertex 2 */ Vert2.SetFace( *pNewFace2 ); } /* set inter connectivity */ if( pNewFace1!=NULL ) pNewFace1->SetFaceNeighbor( pNewFace2, nVert1Num3 ); if( pNewFace2!=NULL ) pNewFace2->SetFaceNeighbor( pNewFace1, nVert2Num3 ); /* last thing : compute normal */ pNewVert->BuildRawNormal(); return pNewVert; }
/*------------------------------------------------------------------------------*/ 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 ); }
/*------------------------------------------------------------------------------*/ 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; } } } }
/*------------------------------------------------------------------------------*/ void GW_VoronoiMesh::BuildMesh( GW_GeodesicMesh& Mesh, GW_Bool bFixHole ) { /* Create Vornoi vertex and make the inverse map GeodesicVertex->VoronoiVertex */ this->CreateVoronoiVertex(); #if 1 // simple method GW_OutputComment("Recomputing the whole Voronoi diagram."); GW_VoronoiMesh::PerformFastMarching( Mesh, BaseVertexList_ ); /* find the faces */ GW_OutputComment("Building the faces."); T_FaceMap FaceMap; // to store the faces already built. for( GW_U32 i=0; i<Mesh.GetNbrFace(); ++i ) { GW_Face* pFace = Mesh.GetFace(i); GW_ASSERT( pFace!=NULL ); GW_GeodesicVertex* pGeo[3]; GW_GeodesicVertex* pFront[3]; for( GW_U32 j=0; j<3; ++j ) { pGeo[j] = (GW_GeodesicVertex*) pFace->GetVertex(j); GW_ASSERT( pGeo[j]!=NULL ); pFront[j] = pGeo[j]->GetFront(); } if( pFront[0]!=pFront[1] && pFront[1]!=pFront[2] && pFront[2]!=pFront[0] ) { GW_U32 nID = GW_Vertex::ComputeUniqueId( *pFront[0], *pFront[1], *pFront[2] ); if( FaceMap.find(nID)==FaceMap.end() ) { /* create the face */ GW_Face& Face = this->CreateNewFace(); FaceMap[nID] = &Face; for( GW_U32 j=0; j<3; ++j ) // assign the vertices { GW_U32 nID = pFront[j]->GetID(); GW_ASSERT( VoronoiVertexMap_.find(nID)!=VoronoiVertexMap_.end() ); GW_VoronoiVertex* pVorVert = VoronoiVertexMap_[nID]; GW_ASSERT( pVorVert!=NULL ); Face.SetVertex( *pVorVert, j ); } } } } #else GW_OutputComment("Computing voronoi diagrams."); /* perform once more a firestart to set up connectivity */ Mesh.RegisterNewDeadVertexCallbackFunction( GW_VoronoiMesh::FastMarchingCallbackFunction_MeshBuilding ); Mesh.ResetGeodesicMesh(); GW_VoronoiMesh::PerformFastMarching( Mesh, BaseVertexList_ ); Mesh.RegisterNewDeadVertexCallbackFunction( NULL ); /* build the faces */ T_FaceMap FaceMap; // to store the faces already built. GW_OutputComment("Building voronoi mesh faces."); for( IT_GeodesicVertexList it = BaseVertexList_.begin(); it!=BaseVertexList_.end(); ++it ) { GW_GeodesicVertex* pVert0 = *it; GW_ASSERT( pVert0!=NULL ); /* retrive the corresponding voronoi vertex */ GW_VoronoiVertex* pVoronoiVert0 = GW_VoronoiMesh::GetVoronoiFromGeodesic( *pVert0 ); GW_ASSERT( pVoronoiVert0!=NULL ); for( IT_VoronoiVertexList itVoronoi1=pVoronoiVert0->BeginNeighborIterator(); itVoronoi1!=pVoronoiVert0->EndNeighborIterator(); ++itVoronoi1 ) { GW_VoronoiVertex* pVoronoiVert1 = *itVoronoi1; GW_ASSERT( pVoronoiVert1!=NULL ); GW_U32 nNumTriangle = 0; for( IT_VoronoiVertexList itVoronoi2=pVoronoiVert1->BeginNeighborIterator(); itVoronoi2!=pVoronoiVert1->EndNeighborIterator(); ++itVoronoi2 ) { GW_VoronoiVertex* pVoronoiVert2 = *itVoronoi2; GW_ASSERT( pVoronoiVert2!=NULL ); if( pVoronoiVert2!=pVoronoiVert0 && pVoronoiVert0->IsNeighbor(*pVoronoiVert2) ) { /* yes, we find a triangle ! Test if it wasn't already constructed */ GW_U32 nUniqueId = GW_Vertex::ComputeUniqueId( *pVoronoiVert0, *pVoronoiVert1, *pVoronoiVert2 ); if( FaceMap.find(nUniqueId)==FaceMap.end() ) { nNumTriangle++; GW_ASSERT( nNumTriangle<=2 ); // assert manifold structure /* this is the 1st time we encounter this face. */ GW_Face* pFace = &Mesh.CreateNewFace(); /* set up the face */ pFace->SetVertex( *pVoronoiVert0, *pVoronoiVert1, *pVoronoiVert2 ); FaceMap[nUniqueId] = pFace; } } } } } #endif /* assign the faces */ this->SetNbrFace( (GW_U32) FaceMap.size() ); GW_U32 nNum = 0; for( IT_FaceMap it = FaceMap.begin(); it!=FaceMap.end(); ++it ) { this->SetFace( nNum, it->second ); nNum++; } /* rebuild connectivity */ GW_OutputComment("Building connectivity."); this->BuildConnectivity(); /* try to fill the holes */ if( bFixHole ) { GW_OutputComment("Fixing holes."); this->FixHole(); /* re-rebuild connectivity */ this->BuildConnectivity(); } }
/*------------------------------------------------------------------------------*/ void GW_VoronoiMesh::ComputeVertexParameters( GW_GeodesicMesh& Mesh ) { for( GW_U32 i=0; i<Mesh.GetNbrVertex(); ++i ) { GW_GeodesicVertex* pVert = (GW_GeodesicVertex*) Mesh.GetVertex( i ); GW_ASSERT( pVert!=NULL ); GW_Float d0, d1, d2; GW_VoronoiVertex* pVornoiVert0 = pVert->GetParameterVertex( 0, d0 ); GW_VoronoiVertex* pVornoiVert1 = pVert->GetParameterVertex( 1, d1 ); GW_VoronoiVertex* pVornoiVert2 = pVert->GetParameterVertex( 2, d2 ); if( pVornoiVert0!=NULL && pVornoiVert1!=NULL && pVornoiVert2!=NULL ) { GW_ASSERT( pVornoiVert0!=NULL ); GW_ASSERT( pVornoiVert1!=NULL ); GW_ASSERT( pVornoiVert2!=NULL ); GW_GeodesicVertex* pVert0 = pVornoiVert0->GetBaseVertex(); GW_GeodesicVertex* pVert1 = pVornoiVert1->GetBaseVertex(); GW_GeodesicVertex* pVert2 = pVornoiVert2->GetBaseVertex(); GW_ASSERT( pVert0!=NULL ); GW_ASSERT( pVert1!=NULL ); GW_ASSERT( pVert2!=NULL ); GW_U32 nID0 = GW_Vertex::ComputeUniqueId( *pVornoiVert1, *pVornoiVert2 ); GW_U32 nID1 = GW_Vertex::ComputeUniqueId( *pVornoiVert0, *pVornoiVert2 ); GW_U32 nID2 = GW_Vertex::ComputeUniqueId( *pVornoiVert0, *pVornoiVert1 ); if( GeodesicDistanceMap_.find(nID0)!=GeodesicDistanceMap_.end() && GeodesicDistanceMap_.find(nID1)!=GeodesicDistanceMap_.end() && GeodesicDistanceMap_.find(nID2)!=GeodesicDistanceMap_.end() ) { /* length of each triangle segment. */ GW_Float l0 = GeodesicDistanceMap_[nID0]; GW_Float l1 = GeodesicDistanceMap_[nID1]; GW_Float l2 = GeodesicDistanceMap_[nID2]; /* now use Heron rule to compute parameter */ GW_Float a0 = GW_Maths::ComputeTriangleArea( l0, d1, d2 ); GW_Float a1 = GW_Maths::ComputeTriangleArea( d0, l1, d2 ); GW_Float a2 = GW_Maths::ComputeTriangleArea( d0, d1, l2 ); GW_Float t = GW_Maths::ComputeTriangleArea( l0, l1, l2 ); // area of the big triangle GW_Float a = a0 + a1 + a2; GW_ASSERT( a>GW_EPSILON ); /* test if the point is outside */ if( a1+a2>t ) pVert->SetParameterVertex( 0, a1/(a1+a2), a2/(a1+a2) ); else if( a0+a2>t ) pVert->SetParameterVertex( a0/(a0+a2), 0, a2/(a0+a2) ); else if( a0+a1>t ) pVert->SetParameterVertex( a0/(a0+a1), a1/(a0+a1), 0 ); else { /* the point is inside the triangle */ pVert->SetParameterVertex( a0/a, a1/a, a2/a ); } pVert->SetParameterVertex( a0/a, a1/a, a2/a ); } else { pVert->SetParameterVertex( 0, 0, 0 ); } } } /* fix parameter for voronoi vertex */ for( GW_U32 i=0; i<this->GetNbrVertex(); ++i ) { GW_VoronoiVertex* pVoronoiVert0 = (GW_VoronoiVertex*) this->GetVertex( i ); GW_ASSERT( pVoronoiVert0!=NULL ); GW_GeodesicVertex* pVert = pVoronoiVert0->GetBaseVertex(); GW_ASSERT( pVert!=NULL ); GW_Face* pFace = pVoronoiVert0->GetFace(); GW_ASSERT( pFace!=NULL ); GW_VoronoiVertex* pVoronoiVert1 = (GW_VoronoiVertex*) pFace->GetNextVertex( *pVoronoiVert0 ); GW_ASSERT( pVoronoiVert1!=NULL ); GW_VoronoiVertex* pVoronoiVert2 = (GW_VoronoiVertex*) pFace->GetNextVertex( *pVoronoiVert1 ); GW_ASSERT( pVoronoiVert2!=NULL ); pVert->ResetParametrizationData(); pVert->AddParameterVertex( *pVoronoiVert0, 1 ); pVert->AddParameterVertex( *pVoronoiVert1, 0 ); pVert->AddParameterVertex( *pVoronoiVert2, 0 ); } /* find the center of each voronoi face */ CentralParameterMap_.clear(); T_FloatMap BestVertexValue; for( GW_U32 i=0; i<Mesh.GetNbrVertex(); ++i ) { GW_GeodesicVertex* pVert = (GW_GeodesicVertex*) Mesh.GetVertex( i ); GW_ASSERT( pVert!=NULL ); GW_Float a,b,c; GW_VoronoiVertex* pVert0 = pVert->GetParameterVertex( 0, a ); GW_ASSERT( pVert0!=NULL ); GW_VoronoiVertex* pVert1 = pVert->GetParameterVertex( 1, b ); GW_ASSERT( pVert1!=NULL ); GW_VoronoiVertex* pVert2 = pVert->GetParameterVertex( 2, c ); if( pVert2!=NULL ) { GW_Float rBestDist = GW_INFINITE; GW_U32 nID = GW_Vertex::ComputeUniqueId( *pVert0, *pVert1, *pVert2 ); if( BestVertexValue.find(nID)!=BestVertexValue.end() ) rBestDist = BestVertexValue[nID]; GW_Float rDist = GW_ABS(a - 1.0/3.0) + GW_ABS(b - 1.0/3.0) + GW_ABS(c - 1.0/3.0); if( rDist<rBestDist ) { BestVertexValue[nID] = rDist; CentralParameterMap_[nID] = pVert; } } } }