/*------------------------------------------------------------------------------*/ void GW_GeodesicPath::AddVertexToPath( GW_GeodesicVertex& Vert ) { pPrevFace_ = pCurFace_; GW_Float rBestDistance = GW_INFINITE; pCurFace_ = NULL; GW_GeodesicVertex* pSelectedVert = NULL; for( GW_VertexIterator it = Vert.BeginVertexIterator(); it!=Vert.EndVertexIterator(); ++it ) { GW_GeodesicVertex* pVert = (GW_GeodesicVertex*) *it; if( pVert->GetDistance()<rBestDistance ) { rBestDistance = pVert->GetDistance(); pSelectedVert = pVert; GW_GeodesicVertex* pVert1 = (GW_GeodesicVertex*) it.GetLeftVertex(); GW_GeodesicVertex* pVert2 = (GW_GeodesicVertex*) it.GetRightVertex(); if( pVert1!=NULL && pVert2!=NULL ) { if( pVert1->GetDistance()<pVert2->GetDistance() ) pCurFace_ = (GW_GeodesicFace*) it.GetLeftFace(); else pCurFace_ = (GW_GeodesicFace*) it.GetRightFace(); } else if( pVert1!=NULL ) { pCurFace_ = (GW_GeodesicFace*) it.GetLeftFace(); } else { GW_ASSERT( pVert2!=NULL ); pCurFace_ = (GW_GeodesicFace*) it.GetRightFace(); } } } GW_ASSERT( pCurFace_!=NULL ); GW_ASSERT( pSelectedVert!=NULL ); GW_GeodesicPoint* pPoint = new GW_GeodesicPoint; Path_.push_back( pPoint ); pPoint->SetVertex1( Vert ); pPoint->SetVertex2( *pSelectedVert ); pPoint->SetCoord(1); pPoint->SetCurFace( *pCurFace_ ); }
/*------------------------------------------------------------------------------*/ void GW_TriangularInterpolation_Cubic::ComputeLocalGradient( GW_GeodesicVertex& Vert ) { /* compute the total angle */ GW_Vector3D PrevEdge; GW_Float rTotalAngle = 0; for( GW_VertexIterator it=Vert.BeginVertexIterator(); it!=Vert.EndVertexIterator(); ++it ) { GW_Vertex* pVert = *it; GW_ASSERT( pVert!=NULL ); if( it==Vert.BeginVertexIterator() ) { PrevEdge = pVert->GetPosition() - Vert.GetPosition(); PrevEdge.Normalize(); } else { GW_Vector3D NextEdge = pVert->GetPosition() - Vert.GetPosition(); NextEdge.Normalize(); rTotalAngle += acos( NextEdge*PrevEdge ); PrevEdge = NextEdge; } } /* matrix and RHS for least square minimusation */ GW_Float M[2][2] = {{0,0},{0,0}}; GW_Float b[2] = {0,0}; GW_Float rCurAngle = 0; PrevEdge.SetZero(); for( GW_VertexIterator it=Vert.BeginVertexIterator(); it!=Vert.EndVertexIterator(); ++it ) { GW_GeodesicVertex* pVert = (GW_GeodesicVertex*) *it; GW_ASSERT( pVert!=NULL ); GW_Vector3D Edge = pVert->GetPosition() - Vert.GetPosition(); GW_Float a = Edge.Norm(); Edge /= a; if( it!=Vert.BeginVertexIterator() ) { /* update the angle */ rCurAngle += acos( Edge*PrevEdge ); } /* directional gradient estimation */ GW_Float delta = (pVert->GetDistance() - Vert.GetDistance())/a; /* coordonate of the edge on (u,v) [flatened coords] */ GW_Float eu = a*cos( rCurAngle/rTotalAngle ); GW_Float ev = a*sin( rCurAngle/rTotalAngle ); /* update the matrix */ M[0][0] += eu*eu; M[0][1] += eu*ev; M[1][0] += eu*ev; M[1][1] += ev*ev; b[0] += delta*eu; b[1] += delta*ev; PrevEdge = Edge; } /* invert the system */ GW_Float det = M[0][0]*M[1][1] - M[0][1]*M[1][0]; GW_ASSERT( det!=0 ); GW_Float gu = 1/det * ( M[1][1]*b[0] - M[0][1]*b[1] ); GW_Float gv = 1/det * (-M[1][0]*b[0] + M[0][0]*b[1] ); /* set the gradient in local coords for each surrounding face */ rCurAngle = 0; for( GW_FaceIterator it = Vert.BeginFaceIterator(); it!=Vert.EndFaceIterator(); ++it ) { GW_GeodesicFace* pFace = (GW_GeodesicFace*) *it; GW_ASSERT( pFace!=NULL ); GW_Vertex* pVert1 = it.GetLeftVertex(); GW_ASSERT( pVert1!=NULL ); GW_Vertex* pVert2 = it.GetRightVertex(); GW_ASSERT( pVert1!=NULL ); GW_Vector3D e1 = pVert1->GetPosition() - Vert.GetPosition(); GW_Vector3D e2 = pVert2->GetPosition() - Vert.GetPosition(); GW_Float a1 = e1.Norm(); GW_Float a2 = e2.Norm(); e1 /= a1; e2 /= a2; GW_Float rInnerAngle = acos( e1*e2 ); /* flattened position of the two vertex */ GW_Float p1[2], p2[2]; p1[0] = cos( rCurAngle ); p1[1] = sin( rCurAngle ); p2[0] = cos( rCurAngle+rInnerAngle ); p2[1] = sin( rCurAngle+rInnerAngle ); /* we have grad = gu*u + gv*v we are searching for grad = g1*p1 + g2*p2, so: gu = g1*<p1,u> + g2*<p2,u> gv = g1*<p1,v> + g2*<p2,v> i.e. |p1[0] p2[0]| |g1| |gu| |p1[1] p2[1]|*|g2| = |gv| */ det = p1[0]*p2[1]-p1[1]*p2[0]; GW_ASSERT( det!=0 ); GW_Float g1 = 1/det * ( p2[1]*gu - p2[0]*gv ); GW_Float g2 = 1/det * (-p1[1]*gu + p1[0]*gv ); /* now compute the gradient in world coords */ GW_Vector3D LocGrad = e1*g1 + e2*g2; GW_TriangularInterpolation_ABC* pInterp = pFace->GetTriangularInterpolation(); if( pInterp==NULL ) { pInterp = new GW_TriangularInterpolation_Cubic; pFace->SetTriangularInterpolation( *pInterp ); } GW_ASSERT( pInterp->GetType()==kCubicTriangulationInterpolation ); ((GW_TriangularInterpolation_Cubic*) pInterp)->SetLocalGradient( LocGrad, *pFace, Vert ); rCurAngle += rInnerAngle; } }
/*------------------------------------------------------------------------------*/ void GW_VoronoiMesh::FastMarchingCallbackFunction_MeshBuilding( GW_GeodesicVertex& CurVert ) { GW_GeodesicVertex* pFront = CurVert.GetFront(); GW_ASSERT( pFront!=NULL ); /* retrieve the voronoi vertex corresponding to the front */ GW_VoronoiVertex* pVoronoiVert0 = GW_VoronoiMesh::GetVoronoiFromGeodesic( *pFront ); GW_ASSERT( pVoronoiVert0!=NULL ); /* test if this point is a saddle point */ for( GW_VertexIterator it=CurVert.BeginVertexIterator(); it!=CurVert.EndVertexIterator(); ++it ) { GW_GeodesicVertex* pNeighborVert = (GW_GeodesicVertex*) *it; GW_GeodesicVertex* pNeighborFront = pNeighborVert->GetFront(); if( pNeighborFront!=NULL && pNeighborFront!=pFront ) { /* that's it ! */ GW_VoronoiVertex* pVoronoiVert1 = GW_VoronoiMesh::GetVoronoiFromGeodesic( *pNeighborFront ); GW_ASSERT( pVoronoiVert1!=NULL ); if( !pVoronoiVert0->IsNeighbor(*pVoronoiVert1) ) { GW_ASSERT( ! pVoronoiVert1->IsNeighbor(*pVoronoiVert0) ); /* test for manifold structure for the future edge */ GW_U32 nNumTriangle = 0; for( IT_VoronoiVertexList itVoronoi=pVoronoiVert1->BeginNeighborIterator(); itVoronoi!=pVoronoiVert1->EndNeighborIterator(); ++itVoronoi ) { GW_VoronoiVertex* pVoronoiVert2 = *itVoronoi; GW_ASSERT( pVoronoiVert2!=NULL ); if( pVoronoiVert2!=pVoronoiVert0 && pVoronoiVert0->IsNeighbor(*pVoronoiVert2) ) nNumTriangle++; } if( nNumTriangle<=2 ) { pVoronoiVert0->AddNeighbor( *pVoronoiVert1 ); pVoronoiVert1->AddNeighbor( *pVoronoiVert0 ); } /* test for manifold structure on the newly created edges */ for( IT_VoronoiVertexList itVoronoi=pVoronoiVert1->BeginNeighborIterator(); itVoronoi!=pVoronoiVert1->EndNeighborIterator(); ++itVoronoi ) { GW_VoronoiVertex* pVoronoiVert2 = *itVoronoi; GW_ASSERT( pVoronoiVert2!=NULL ); if( pVoronoiVert2!=pVoronoiVert0 && pVoronoiVert0->IsNeighbor(*pVoronoiVert2) ) { /* we are on a newly created face : test for structure integrity */ if( !GW_VoronoiMesh::TestManifoldStructure(*pVoronoiVert0, *pVoronoiVert2) ) { pVoronoiVert0->RemoveNeighbor( *pVoronoiVert1 ); pVoronoiVert1->RemoveNeighbor( *pVoronoiVert0 ); break; } if( !GW_VoronoiMesh::TestManifoldStructure(*pVoronoiVert1, *pVoronoiVert2) ) { pVoronoiVert0->RemoveNeighbor( *pVoronoiVert1 ); pVoronoiVert1->RemoveNeighbor( *pVoronoiVert0 ); break; } } } } else { /* the graph must be undirected */ GW_ASSERT( pVoronoiVert1->IsNeighbor(*pVoronoiVert0) ); } } } }