/* jCAE stand for Java Computer Aided Engineering. Features are : Small CAD
modeler, Finite element mesher, Plugin architecture.
Copyright (C) 2010, by EADS France
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.jcae.mesh.xmldata;
import gnu.trove.set.hash.TIntHashSet;
import gnu.trove.map.hash.TIntObjectHashMap;
import java.util.logging.Level;
import org.jcae.mesh.amibe.ds.Mesh;
import org.jcae.mesh.amibe.ds.Triangle;
import org.jcae.mesh.amibe.ds.Vertex;
import org.jcae.mesh.amibe.traits.MeshTraitsBuilder;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
public class SubMeshWorker
{
private static final Logger logger=Logger.getLogger(SubMeshWorker.class.getName());
private static final String submeshDirExt = "ext";
private static final String submeshDirInt = "int";
private final String amibeDir;
private int[] groupIdsIntToGlobal;
private int[] groupIdsExtToGlobal;
public SubMeshWorker(String dir)
{
amibeDir = dir;
}
/**
* Extract groups from a mesh. Two meshes are created on disk,
* one with the selected groups, and one with the complement.
*
* @param groupNames array of selected groups
* @return the directory containing the extracted mesh
* @throws IOException
*/
public String extractGroups(String[] groupNames) throws IOException
{
logger.config("Extracting specified groups from directory: "+amibeDir);
MeshTraitsBuilder mtbInt = new MeshTraitsBuilder().addTriangleSet();
Mesh meshInt = new Mesh(mtbInt);
MeshReader.readObject3D(meshInt, amibeDir);
HashSet<String> setGroupNames = new HashSet<String>(groupNames.length);
for (String name : groupNames)
setGroupNames.add(name);
// By convention, group Ids start from 1. First value will be unused.
groupIdsExtToGlobal = new int[1+groupNames.length];
groupIdsIntToGlobal = new int[1+meshInt.getNumberOfGroups() - groupNames.length];
int indInt = 1;
int indExt = 1;
for (int i = 1; i <= meshInt.getNumberOfGroups(); i++)
{
if (setGroupNames.contains(meshInt.getGroupName(i)))
groupIdsExtToGlobal[indExt++] = i;
else
groupIdsIntToGlobal[indInt++] = i;
}
Mesh meshExt = splitSelectedGroups(meshInt,
meshInt.getGroupIDs(groupNames));
meshInt.setPersistentReferences(true);
MeshWriter.writeObject3D(meshInt, amibeDir+File.separator+submeshDirInt, null);
meshExt.setPersistentReferences(true);
MeshWriter.writeObject3D(meshExt, amibeDir+File.separator+submeshDirExt, null);
return amibeDir+File.separator+submeshDirExt;
}
private Mesh splitSelectedGroups(Mesh meshInt, int[] groupIds)
{
TIntHashSet groups = new TIntHashSet(groupIds);
Mesh meshExt = new Mesh();
int approxNrNodes = meshInt.getTriangles().size() / 2;
HashMap<Vertex, Vertex> mapVertexIntToExt = new HashMap<Vertex, Vertex>(approxNrNodes);
Vertex[] vExt = new Vertex[3];
List<Triangle> removedTriangles = new ArrayList<Triangle>();
int maxRef = 0;
for (Triangle t : meshInt.getTriangles())
{
for (int i = 0; i < 3; i++)
maxRef = Math.max(maxRef, Math.abs(t.getV(i).getRef()));
if (!groups.contains(t.getGroupId()))
continue;
removedTriangles.add(t);
for (int i = 0; i < 3; i++)
{
Vertex vn = mapVertexIntToExt.get(t.getV(i));
if (null == vn)
{
Vertex v = t.getV(i);
vn = meshExt.createVertex(v);
vn.copy(v);
mapVertexIntToExt.put(v, vn);
}
vExt[i] = vn;
}
Triangle newT = meshExt.createTriangle(vExt[0], vExt[1], vExt[2]);
newT.setGroupId(t.getGroupId());
meshExt.add(newT);
}
for (Triangle t : removedTriangles)
meshInt.remove(t);
for (int id : groupIds)
meshExt.setGroupName(id, meshInt.getGroupName(id));
logger.config("Extracted "+meshExt.getTriangles().size()+" triangles");
// Ensure that boundary nodes of the selected groups have
// a reference set.
meshExt.buildAdjacency(maxRef);
// Adjust references on interface
for (Map.Entry<Vertex, Vertex> entry : mapVertexIntToExt.entrySet())
entry.getKey().setRef(entry.getValue().getRef());
return meshExt;
}
public void mergeMeshes(String newDir) throws IOException
{
MeshTraitsBuilder mtbInt = new MeshTraitsBuilder();
mtbInt.addTriangleSet();
mtbInt.addNodeSet();
Mesh meshInt = new Mesh(mtbInt);
MeshReader.readObject3D(meshInt, amibeDir+File.separator+submeshDirInt);
TIntObjectHashMap<Vertex> ref2Vertex = new TIntObjectHashMap<Vertex>();
for (Vertex v : meshInt.getNodes())
{
if (v.getRef() != 0)
ref2Vertex.put(v.getRef(), v);
}
Mesh meshExt = new Mesh(mtbInt);
MeshReader.readObject3D(meshExt, amibeDir+File.separator+submeshDirExt);
// Rebuild original group names
String[] mergedNames = new String[1 + meshExt.getNumberOfGroups() + meshInt.getNumberOfGroups()];
for (int i = 1; i <= meshInt.getNumberOfGroups(); i++)
mergedNames[groupIdsIntToGlobal[i]] = meshInt.getGroupName(i);
for (int i = 1; i <= meshExt.getNumberOfGroups(); i++)
mergedNames[groupIdsExtToGlobal[i]] = meshExt.getGroupName(i);
// Reset original groupId and groupName
for (Triangle t : meshInt.getTriangles())
t.setGroupId(groupIdsIntToGlobal[t.getGroupId()]);
for (int i = 1; i < mergedNames.length; i++)
meshInt.setGroupName(i, mergedNames[i]);
Vertex[] vInt = new Vertex[3];
for (Triangle t : meshExt.getTriangles())
{
for (int i = 0; i < 3; i++)
{
int ref1d = t.getV(i).getRef();
if (0 == ref1d)
{
// Inner vertex
vInt[i] = t.getV(i);
}
else if (ref2Vertex.contains(ref1d))
{
// Already processed boundary point
vInt[i] = ref2Vertex.get(ref1d);
}
else
{
// New boundary point
vInt[i] = meshInt.createVertex(t.getV(i));
vInt[i].copy(t.getV(i));
ref2Vertex.put(ref1d, vInt[i]);
}
meshInt.add(vInt[i]);
}
Triangle newT = meshInt.createTriangle(vInt[0], vInt[1], vInt[2]);
newT.setGroupId(groupIdsExtToGlobal[t.getGroupId()]);
meshInt.add(newT);
}
meshInt.setPersistentReferences(true);
MeshWriter.writeObject3D(meshInt, newDir, null);
}
/*
* Usage: dirIn dirOut groupNumber targetSize
*/
public static void main(String [] args)
{
SubMeshWorker smw = new SubMeshWorker(args[0]);
String[] groups = new String[]{args[2]};
try {
String extractedDir = smw.extractGroups(groups);
Mesh workMesh = new Mesh();
MeshReader.readObject3D(workMesh, extractedDir);
org.jcae.mesh.amibe.projection.MeshLiaison liaison = new org.jcae.mesh.amibe.projection.MapMeshLiaison(workMesh);
liaison.getMesh().tagFreeEdges(org.jcae.mesh.amibe.ds.AbstractHalfEdge.IMMUTABLE);
liaison.getMesh().buildRidges(0.9);
HashMap<String, String> opts = new HashMap<String, String>();
opts.put("size", args[3]);
org.jcae.mesh.amibe.algos3d.Remesh algo = new org.jcae.mesh.amibe.algos3d.Remesh(liaison, opts);
algo.compute();
HashMap<String, String> swapOpts = new HashMap<String, String>();
org.jcae.mesh.amibe.algos3d.SwapEdge swap = new org.jcae.mesh.amibe.algos3d.SwapEdge(liaison, swapOpts);
swap.compute();
MeshWriter.writeObject3D(liaison.getMesh(), extractedDir, null);
smw.mergeMeshes(args[1]);
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
}