TriangleMesh * CorrespondTemplates::computeSurface(char * exportFilename, bool useMapping)
{
	int i, j, counter, numTetNodes;
	TriangleMesh * resultMesh = new TriangleMesh();
	vector<int> surfaceIds;

	//Find the surface:
	findSurfaceNodes();

	numTetNodes = volumetricMeshNodes.numberOfItems();
	surfaceIds.resize(numTetNodes);

	g_NodeContainer nodesSurf;
	if ( useMapping ) 
	   nodesSurf = rigidlyAlignedSurfaceTemplate->nodes();

	//Add the nodes:
	counter = 0;
	for(i = 0; i < numTetNodes; i++)
	{
		if(surfaceNodes[i] == -1) 
			surfaceIds[i] = -1;
		else 
		{
			surfaceIds[i] = counter;
			counter++;

			g_Vector coord;
			if ( useMapping ) {
			  coord =  mappingWeightsTet[3*i] * nodesSurf[mappingIndicesTet[3*i]]->coordinate(); 
			  coord += mappingWeightsTet[3*i+1] * nodesSurf[mappingIndicesTet[3*i+1]]->coordinate(); 
			  coord += mappingWeightsTet[3*i+2] * nodesSurf[mappingIndicesTet[3*i+2]]->coordinate();
			} else {
			  coord = volumetricMeshNodes[i]->coordinate();
			}
			g_Node * newNode = new g_Node(coord); 
			resultMesh->node(newNode);
		}
	}

	//Add the triangles (find the correct orientation):
	for(i = 0; i < trianglesOnSurface.size(); i++)
	{
		g_Element * elem = new g_Element();
	
		for(j = 0; j < allTetrahedra.size(); j++)
		{
			set<int> triangle; triangle.insert(allTetrahedra[j][0]); triangle.insert(allTetrahedra[j][1]); triangle.insert(allTetrahedra[j][2]);
			if(trianglesOnSurface[i] == triangle)
			{
				elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][0]]]);
				elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][2]]]);
				elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][1]]]);
				break;
			}
			triangle.clear(); triangle.insert(allTetrahedra[j][0]); triangle.insert(allTetrahedra[j][1]); triangle.insert(allTetrahedra[j][3]);
			if(trianglesOnSurface[i] == triangle)
			{
				elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][0]]]);
				elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][1]]]);
				elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][3]]]);
				break;
			}
			triangle.clear(); triangle.insert(allTetrahedra[j][0]); triangle.insert(allTetrahedra[j][2]); triangle.insert(allTetrahedra[j][3]);
			if(trianglesOnSurface[i] == triangle)
			{
				elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][0]]]);
				elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][3]]]);
				elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][2]]]);
				break;
			}
			triangle.clear(); triangle.insert(allTetrahedra[j][1]); triangle.insert(allTetrahedra[j][2]); triangle.insert(allTetrahedra[j][3]);
			if(trianglesOnSurface[i] == triangle)
			{
				elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][1]]]);
				elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][2]]]);
				elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][3]]]);
				break;
			}
		}

		resultMesh->element(elem);
	}

	//Export:
	if(exportFilename != NULL)
	{
		exportMeshWrapper(exportFilename, resultMesh);
	}

	return resultMesh;
}
void CorrespondTemplates::computeMappings(char * outfileMappingTet, char * outfileMappingSurf, g_Node * contactPoint)
{
	//Compute the mappings using barycentric coordinates
	findSurfaceNodes();
	maptet2surfID = surfaceNodes;
	// output tetmesh surface
	computeSurface( "tet_mesh_surf.wrl" );
	deformVolumetricMeshRigidly();

	int i, j, k, numNodesTet, numElemsTet, numNodesSurf, numElemsSurf;
	double dist, minDist, d, mind, distContactPoint, minDistContactPoint;
	numNodesTet = volumetricMeshNodes.numberOfItems();
	numElemsTet = trianglesOnSurface.size();
	numNodesSurf = rigidlyAlignedSurfaceTemplate->getNumberOfNodes();
	numElemsSurf = rigidlyAlignedSurfaceTemplate->getNumberOfTriangles();

	//First compute the mapping from the tetrahedral mesh to the surface mesh
	mappingIndicesTet.resize(3*numNodesTet);
	mappingWeightsTet.resize(3*numNodesTet);
	offsetsTet.resize(numNodesTet);

	for(i = 0; i < numNodesTet; i++)
	{
		if(surfaceNodes[i] == -1)
		{
			mappingIndicesTet[3*i] = mappingIndicesTet[3*i+1] = mappingIndicesTet[3*i+2] = -1;
			mappingWeightsTet[3*i] = mappingWeightsTet[3*i+1] = mappingWeightsTet[3*i+2] = -1;
		}
		else
		{
			for(j = 0; j < numElemsSurf; j++)
			{
			  // g_Vector closestPoint = computeClosestPoint(volumetricMeshNodes[i], rigidlyAlignedSurfaceTemplate->elements()[j]);
			  // dist = closestPoint.DistanceTo(volumetricMeshNodes[i]->coordinate());
		          g_Vector closestPoint;
			  dist = computeClosestPoint(*volumetricMeshNodes[i], *rigidlyAlignedSurfaceTemplate->elements()[j], closestPoint );
			  dist = sqrt(dist);

				if((j == 0) || (dist < minDist))
				{
					minDist = dist;
					
					mappingIndicesTet[3*i] = rigidlyAlignedSurfaceTemplate->elements()[j]->nodes()[0]->id()-1;
					mappingIndicesTet[3*i+1] = rigidlyAlignedSurfaceTemplate->elements()[j]->nodes()[1]->id()-1;
					mappingIndicesTet[3*i+2] = rigidlyAlignedSurfaceTemplate->elements()[j]->nodes()[2]->id()-1;

					//----------------------
					for(int n = 0; n < 3; n++){
						d = volumetricMeshNodes[i]->coordinate().DistanceTo(rigidlyAlignedSurfaceTemplate->elements()[j]->nodes()[n]->coordinate());
						if((n == 0) || (d < mind)){
							mind = d;
							maptet2surfID[i] = rigidlyAlignedSurfaceTemplate->elements()[j]->nodes()[n]->id()-1;
						}
					}
					//------------------------

					vector<double> barycentrics = computeBarycentrics(volumetricMeshNodes[i]->coordinate(), closestPoint, rigidlyAlignedSurfaceTemplate->elements()[j]);
					mappingWeightsTet[3*i] = barycentrics[0];
					mappingWeightsTet[3*i+1] = barycentrics[1];
					mappingWeightsTet[3*i+2] = barycentrics[2];
					offsetsTet[i] = barycentrics[3];
				}
			}
		}
	}

	//Export
	if(outfileMappingTet != NULL)
	{
#if 0
		FILE * fp = fopen(outfileMappingTet, "w");
		if(fp == NULL)
		{
			cout<<"Problem writing "<<outfileMappingTet<<endl;
			return;
		}
		for(i = 0; i < numNodesTet; i++)
			fprintf(fp, "%d %d %d %f %f %f %f\n", mappingIndicesTet[3*i], mappingIndicesTet[3*i+1], mappingIndicesTet[3*i+2], 
				mappingWeightsTet[3*i], mappingWeightsTet[3*i+1], mappingWeightsTet[3*i+2], offsetsTet[i]);
		fclose(fp);
#else
		// Make a surface mesh using the tetmesh surface plus the coordinates from the surface mesh
		computeSurface( outfileMappingTet, true );
#endif
	}

	//Second compute the mapping from the surface mesh to the tetrahedral mesh
	mappingIndicesSurf.resize(3*numNodesSurf);
	mappingWeightsSurf.resize(3*numNodesSurf);
	offsetsSurf.resize(numNodesSurf);
	contactTriangleId.resize(3);
	contactWeights.resize(3);
	contactoffset.resize(1);

	for(i = 0; i < numNodesSurf; i++)
	{
		for(j = 0; j < numElemsTet; j++)
		{
			g_Element elem;
			set<int>::iterator triangleIt;
			for(triangleIt = trianglesOnSurface[j].begin(); triangleIt != trianglesOnSurface[j].end(); triangleIt++)
				elem.node(volumetricMeshNodes[*triangleIt]);

			// g_Vector closestPoint = computeClosestPoint(rigidlyAlignedSurfaceTemplate->nodes()[i], &elem);
			// dist = closestPoint.DistanceTo(rigidlyAlignedSurfaceTemplate->nodes()[i]->coordinate());
		        g_Vector closestPoint;
		        dist = computeClosestPoint(*rigidlyAlignedSurfaceTemplate->nodes()[i], elem, closestPoint );
			dist = sqrt(dist);

			if((j == 0) || (dist < minDist))
			{
				minDist = dist;

				k = 0;
				for(triangleIt = trianglesOnSurface[j].begin(); triangleIt != trianglesOnSurface[j].end(); triangleIt++, k++)
					mappingIndicesSurf[3*i+k] = *triangleIt;

				vector<double> barycentrics = computeBarycentrics(rigidlyAlignedSurfaceTemplate->nodes()[i]->coordinate(), closestPoint, &elem);
				mappingWeightsSurf[3*i] = barycentrics[0];
				mappingWeightsSurf[3*i+1] = barycentrics[1];
				mappingWeightsSurf[3*i+2] = barycentrics[2];
				offsetsSurf[i] = barycentrics[3];
			}


			//---------------------------
			if(i == 0 && contactPoint != NULL){
			        g_Vector closestContactPoint;
				distContactPoint = computeClosestPoint(*contactPoint, elem, closestContactPoint );
				distContactPoint = sqrt(distContactPoint);
				// g_Vector closestContactPoint = computeClosestPoint(contactPoint, &elem);
				// distContactPoint = closestContactPoint.DistanceTo(contactPoint->coordinate());
				if((j == 0) || (distContactPoint < minDistContactPoint))
				{
					minDistContactPoint = distContactPoint;

					k = 0;
					for(triangleIt = trianglesOnSurface[j].begin(); triangleIt != trianglesOnSurface[j].end(); triangleIt++, k++)
						contactTriangleId[3*i+k] = *triangleIt;

					vector<double> barycentricsContactPoint = computeBarycentrics(contactPoint->coordinate(), closestContactPoint, &elem);
					contactWeights[3*i] = barycentricsContactPoint[0];
					contactWeights[3*i+1] = barycentricsContactPoint[1];
					contactWeights[3*i+2] = barycentricsContactPoint[2];
					contactoffset[i] = barycentricsContactPoint[3];
				}
			}
			//----------------------------
		}
	}

	//Export
	if(outfileMappingSurf != NULL)
	{
#if 0 
		FILE * fp = fopen(outfileMappingSurf, "w");
		if(fp == NULL)
		{
			cout<<"Problem writing "<<outfileMappingSurf<<endl;
			return;
		}
		for(i = 0; i < numNodesSurf; i++)
			fprintf(fp, "%d %d %d %f %f %f %f\n", mappingIndicesSurf[3*i], mappingIndicesSurf[3*i+1], mappingIndicesSurf[3*i+2], 
				mappingWeightsSurf[3*i], mappingWeightsSurf[3*i+1], mappingWeightsSurf[3*i+2], offsetsSurf[i]);
		fclose(fp);
#else
		// Make a surface mesh using the tetmesh surface plus the coordinates from the surface mesh
		TriangleMesh surfTet;
		for (int i=0; i<numNodesSurf; ++i ) {
		  // std::cerr << i << " " << std::endl;
		  g_Vector coord =  mappingWeightsSurf[3*i] * volumetricMeshNodes[mappingIndicesSurf[3*i]]->coordinate();
		  coord += mappingWeightsSurf[3*i+1] * volumetricMeshNodes[mappingIndicesSurf[3*i+1]]->coordinate(); 
		  coord += mappingWeightsSurf[3*i+2] * volumetricMeshNodes[mappingIndicesSurf[3*i+2]]->coordinate();
		  surfTet.node(new g_Node( coord ));
		}
		// std::cerr << std::endl;
		g_ElementContainer eleSurf = rigidlyAlignedSurfaceTemplate->elements();
		g_NodeContainer newNodes = surfTet.nodes();
		for ( g_ElementContainer::const_iterator fIt=eleSurf.begin(); fIt != eleSurf.end(); ++fIt ) {
		  g_Element *ele = new g_Element(); 
		  g_NodeContainer faceNodes = (*fIt)->nodes(); 
		  for ( g_NodeContainer::const_iterator nIt = faceNodes.begin(); 
			nIt != faceNodes.end(); ++nIt ) {
		    ele->node(newNodes[(*nIt)->id()-1]);
		  }
		  surfTet.element(ele);
		}
		exportMeshWrapper( outfileMappingSurf, &surfTet ); 
#endif


	}
}