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;
}
Ejemplo n.º 2
0
/*------------------------------------------------------------------------------*/
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();
}
Ejemplo n.º 3
0
/* 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);
    }
}
Ejemplo n.º 4
0
/*------------------------------------------------------------------------------*/
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;
}
Ejemplo n.º 5
0
/*------------------------------------------------------------------------------*/
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;
			}
		}
	}
}