/* jCAE stand for Java Computer Aided Engineering. Features are : Small CAD
modeler, Finite element mesher, Plugin architecture.
Copyright (C) 2006, by EADS CRC
Copyright (C) 2007,2008,2009,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.bora.xmldata;
import org.jcae.mesh.amibe.ds.MEdge1D;
import org.jcae.mesh.amibe.ds.MNode1D;
import org.jcae.mesh.amibe.ds.Mesh;
import org.jcae.mesh.amibe.ds.SubMesh1D;
import org.jcae.mesh.amibe.ds.Triangle;
import org.jcae.mesh.amibe.ds.AbstractHalfEdge;
import org.jcae.mesh.amibe.ds.Vertex;
import org.jcae.mesh.amibe.patch.Mesh2D;
import org.jcae.mesh.bora.ds.BModel;
import org.jcae.mesh.bora.ds.BSubMesh;
import org.jcae.mesh.bora.ds.BCADGraphCell;
import org.jcae.mesh.bora.ds.BDiscretization;
import org.jcae.mesh.bora.ds.Constraint;
import org.jcae.mesh.cad.CADVertex;
import org.jcae.mesh.cad.CADEdge;
import org.jcae.mesh.cad.CADFace;
import org.jcae.mesh.cad.CADSolid;
import org.jcae.mesh.cad.CADGeomCurve3D;
import org.jcae.mesh.cad.CADGeomSurface;
import org.jcae.mesh.cad.CADShapeFactory;
import org.jcae.mesh.cad.CADShapeEnum;
import org.jcae.mesh.xmldata.DoubleFileReader;
import org.jcae.mesh.xmldata.IntFileReader;
import org.jcae.mesh.xmldata.PrimitiveFileReaderFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.PrintStream;
import java.io.IOException;
import gnu.trove.map.hash.TObjectIntHashMap;
import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.list.array.TIntArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Storage
{
private static final Logger LOGGER = Logger.getLogger(Storage.class.getName());
private static void writeId(File dir, int id)
{
// Create the output directory if it does not exist
if(!dir.exists())
dir.mkdirs();
File idFile = new File(dir, "id");
if(idFile.exists())
idFile.delete();
try
{
PrintStream out=new PrintStream(new FileOutputStream(idFile, true));
out.println(""+id);
out.close();
}
catch(java.io.FileNotFoundException ex)
{
}
}
public static void writeEdge(BDiscretization d)
{
BCADGraphCell edge = d.getGraphCell();
CADEdge E = (CADEdge) edge.getShape();
if (E.isDegenerated())
return;
SubMesh1D submesh = (SubMesh1D) d.getMesh();
if (null == submesh)
return;
try
{
File dir = new File(edge.getGraph().getModel().getOutputDir(d));
writeId(dir, edge.getId());
Collection<MNode1D> nodelist = submesh.getNodes();
// Write node references and compute local indices
TObjectIntHashMap<MNode1D> localIdx = write1dNodeReferences(dir, nodelist, edge);
// Write node coordinates
write1dCoordinates(dir, nodelist, CADShapeFactory.getFactory().newCurve3D(E));
// Write edge connectivity
write1dEdges(dir, submesh.getEdges(), localIdx);
}
catch(Exception ex)
{
ex.printStackTrace();
throw new RuntimeException();
}
}
public static void writeFace(BDiscretization d)
{
BCADGraphCell face = d.getGraphCell();
Mesh2D submesh = (Mesh2D) d.getMesh();
if (null == submesh)
return;
try
{
File dir = new File(face.getGraph().getModel().getOutputDir(d));
writeId(dir, face.getId());
CADFace F = (CADFace) face.getShape();
Collection<Triangle> trianglelist = submesh.getTriangles();
Collection<Vertex> nodelist = submesh.getNodes();
TObjectIntHashMap<Vertex> localIdx = write2dNodeReferences(dir, face.getId(), nodelist, submesh.outerVertex);
write2dCoordinates(dir, nodelist, submesh.outerVertex, F.getGeomSurface());
write2dTriangles(dir, trianglelist, localIdx);
}
catch(Exception ex)
{
ex.printStackTrace();
throw new RuntimeException();
}
}
public static void writeSolid(BDiscretization d)
{
BCADGraphCell solid = d.getGraphCell();
Mesh submesh = (Mesh) d.getMesh();
if (null == submesh)
return;
try
{
File dir = new File(solid.getGraph().getModel().getOutputDir(d));
writeId(dir, solid.getId());
Collection<Vertex> nodelist = submesh.getNodes();
TObjectIntHashMap<Vertex> localIdx = write2dNodeReferences(dir, solid.getId(), nodelist, submesh.outerVertex);
write2dCoordinates(dir, nodelist, submesh.outerVertex, null);
write2dTriangles(dir, submesh.getTriangles(), localIdx);
}
catch(Exception ex)
{
ex.printStackTrace();
throw new RuntimeException();
}
}
/**
* Populates a Mesh instance by reading all faces and edges which have
* constraints.
* @param m <code>Mesh</code> instance
* @param root root shape
* @throws RuntimeException if an error occurred
*/
public static void readAll(Mesh m, BCADGraphCell root) throws IOException
{
TIntObjectHashMap<Vertex> vertMap = new TIntObjectHashMap<Vertex>();
for (BSubMesh s : root.getGraph().getModel().getSubMeshes())
{
int cid = 1;
Map<String, Integer> groups = new HashMap<String, Integer>();
for (Constraint c : s.getConstraints()) {
Integer id = groups.get(c.getGroup());
if(id == null)
{
groups.put(c.getGroup(), cid);
m.setGroupName(cid++, c.getGroup());
}
}
for (Constraint c : s.getConstraints()) {
BCADGraphCell cell = c.getGraphCell();
if(CADShapeEnum.EDGE.equals(cell.getType()))
readEdge(m, cell, s, vertMap, c.getGroup(), groups.get(c.getGroup()));
else if(CADShapeEnum.FACE.equals(cell.getType()))
readFace(m, cell, s, vertMap);
}
}
}
/**
* Populates a Mesh instance by reading all faces.
* @param m <code>Mesh</code> instance
* @param root root shape
* @param s consider discretizations only if they appear in this BSubMesh instance
* @throws RuntimeException if an error occurred
*/
public static void readAllFaces(Mesh m, BCADGraphCell root, BSubMesh s)
{
TIntObjectHashMap<Vertex> vertMap = new TIntObjectHashMap<Vertex>();
for (Iterator<BCADGraphCell> it = root.uniqueShapesExplorer(CADShapeEnum.FACE); it.hasNext(); )
readFace(m, it.next(), s, vertMap);
}
public static void readEdge(Mesh mesh, BCADGraphCell edge, BSubMesh s,
TIntObjectHashMap<Vertex> mapRefVertex, String groupName, int groupId)
throws IOException
{
assert edge.getShape() instanceof CADEdge;
BModel model = edge.getGraph().getModel();
boolean reversed = false;
if (edge.getOrientation() != 0)
{
reversed = true;
if (edge.getReversed() != null)
edge = edge.getReversed();
}
BDiscretization d = edge.getDiscretizationSubMesh(s);
if (null == d)
return;
int id = edge.getId();
File dir = new File(model.getOutputDir(d));
// Read vertex references
int [] refs = readNodeReferences(d);
// Create a Vertex array, and insert new references
// into mapRefVertex.
Vertex [] nodelist = read2dCoordinates(dir, mesh, refs, mapRefVertex);
int[] indices = readConnectivity(d);
for(int i = 0; i<indices.length; i+=2)
mesh.addBeam(nodelist[indices[i] - 1], nodelist[indices[i+1] - 1], groupId);
}
/**
* Append a discretized face into a Mesh instance.
* @param mesh original mesh
* @param face cell graph containing a CAD face
* @param s consider discretizations only if they appear in this BSubMesh instance
* @param mapRefVertex map between references and Vertex instances
* @throws RuntimeException if an error occurred
*/
public static void readFace(Mesh mesh, BCADGraphCell face, BSubMesh s, TIntObjectHashMap<Vertex> mapRefVertex)
{
assert face.getShape() instanceof CADFace;
BModel model = face.getGraph().getModel();
boolean reversed = false;
if (face.getOrientation() != 0)
{
reversed = true;
if (face.getReversed() != null)
face = face.getReversed();
}
BDiscretization d = face.getDiscretizationSubMesh(s);
if (null == d)
return;
int id = face.getId();
try
{
File dir = new File(model.getOutputDir(d));
// Read vertex references
int [] refs = readNodeReferences(d);
// Create a Vertex array, and insert new references
// into mapRefVertex.
Vertex [] nodelist = read2dCoordinates(dir, mesh, refs, mapRefVertex);
// Read triangles and appends them to the mesh.
read2dTriangles(dir, id, 3, mesh, reversed, nodelist);
}
catch(java.io.FileNotFoundException ex)
{
ex.printStackTrace();
throw new RuntimeException(ex);
}
catch(Exception ex)
{
ex.printStackTrace();
throw new RuntimeException(ex);
}
if (LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "end reading cell "+id);
}
/**
* Populates a Mesh instance by reading all volumes.
* @param m <code>Mesh</code> instance
* @param root root shape
* @throws RuntimeException if an error occurred
*/
@SuppressWarnings("unused")
private static void readAllVolumes(Mesh m, BCADGraphCell root, BSubMesh s)
{
TIntObjectHashMap<Vertex> vertMap = new TIntObjectHashMap<Vertex>();
for (Iterator<BCADGraphCell> it = root.uniqueShapesExplorer(CADShapeEnum.SOLID); it.hasNext(); )
readVolume(m, it.next(), s, vertMap);
}
/**
* Append a discretized solid into a Mesh instance.
* @param mesh original mesh
* @param volume cell graph containing a CAD solid
* @param mapRefVertex map between references and Vertex instances
* @throws RuntimeException if an error occurred
*/
private static void readVolume(Mesh mesh, BCADGraphCell volume, BSubMesh s, TIntObjectHashMap<Vertex> mapRefVertex)
{
assert volume.getShape() instanceof CADSolid;
BModel model = volume.getGraph().getModel();
boolean reversed = false;
if (volume.getOrientation() != 0)
{
reversed = true;
if (volume.getReversed() != null)
volume = volume.getReversed();
}
BDiscretization d = volume.getDiscretizationSubMesh(s);
if (null == d)
return;
int id = volume.getId();
try
{
File dir = new File(model.getOutputDir(d));
// Read vertex references
int [] refs = readNodeReferences(d);
// Create a Vertex array, and insert new references
// into mapRefVertex.
Vertex [] nodelist = read2dCoordinates(dir, mesh, refs, mapRefVertex);
if (mesh.hasNodes())
{
for (int i = 0, n = nodelist.length; i < n; i++)
mesh.add(nodelist[i]);
}
// Read triangles and appends them to the mesh.
read2dTriangles(dir, id, 4, mesh, reversed, nodelist);
}
catch(Exception ex)
{
ex.printStackTrace();
throw new RuntimeException(ex);
}
if (LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "end reading cell "+id);
}
private static TObjectIntHashMap<MNode1D> write1dNodeReferences(File dir, Collection<MNode1D> nodelist, BCADGraphCell edge)
throws IOException
{
File refFile = new File(dir, "r");
if(refFile.exists())
refFile.delete();
// Save references
if (LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "begin writing "+refFile);
DataOutputStream refsout = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(refFile, true)));
TObjectIntHashMap<MNode1D> localIdx = new TObjectIntHashMap<MNode1D>(nodelist.size());
int i = 0;
for (Iterator<MNode1D> itn = nodelist.iterator(); itn.hasNext(); )
{
MNode1D n = itn.next();
// Set first index to 1; a null index in
// localIdx is thus an error
localIdx.put(n, i+1);
CADVertex v = n.getCADVertex();
if (null != v)
{
// TODO: replace this id by Vertex.getRef()
BCADGraphCell vv = edge.getGraph().getByShape(v);
refsout.writeInt(i);
refsout.writeInt(vv.getId());
}
i++;
}
refsout.close();
return localIdx;
}
private static TObjectIntHashMap<Vertex> write2dNodeReferences(File dir, int id, Collection<Vertex> nodelist, Vertex outer)
throws IOException
{
File refFile = new File(dir, "r");
if(refFile.exists())
refFile.delete();
// Save references
if (LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "begin writing "+refFile+" face "+id);
DataOutputStream refsout = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(refFile, true)));
TObjectIntHashMap<Vertex> localIdx = new TObjectIntHashMap<Vertex>(nodelist.size());
int i = 0;
for (Iterator<Vertex> itn = nodelist.iterator(); itn.hasNext(); )
{
Vertex n = itn.next();
if (n == outer)
continue;
// Set first index to 1; a null index in
// localIdx is thus an error
localIdx.put(n, i+1);
int ref1d = n.getRef();
if (ref1d != 0)
{
refsout.writeInt(i);
refsout.writeInt(Math.abs(ref1d));
}
i++;
}
refsout.close();
return localIdx;
}
private static void write1dCoordinates(File dir, Collection<MNode1D> nodelist, CADGeomCurve3D curve)
throws IOException
{
File nodesFile = new File(dir, "n");
if(nodesFile.exists())
nodesFile.delete();
File parasFile = new File(dir, "p");
if(parasFile.exists())
parasFile.delete();
if (LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "begin writing "+nodesFile+" and "+parasFile);
DataOutputStream nodesout = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(nodesFile, true)));
DataOutputStream parasout = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(parasFile, true)));
for (Iterator<MNode1D> itn = nodelist.iterator(); itn.hasNext(); )
{
MNode1D n = itn.next();
double p = n.getParameter();
parasout.writeDouble(p);
double [] xyz = curve.value(p);
for (int k = 0; k < 3; k++)
nodesout.writeDouble(xyz[k]);
}
nodesout.close();
parasout.close();
}
private static void write2dCoordinates(File dir, Collection<Vertex> nodelist, Vertex outer, CADGeomSurface surface)
throws IOException
{
File nodesFile = new File(dir, "n");
if(nodesFile.exists())
nodesFile.delete();
File parasFile = new File(dir, "p");
if(parasFile.exists())
parasFile.delete();
// Save nodes
if (LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "begin writing "+nodesFile+" and "+parasFile);
DataOutputStream nodesout = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(nodesFile, true)));
DataOutputStream parasout = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(parasFile, true)));
double [] xyz;
double[] tmpXYZ = new double[3];
for (Iterator<Vertex> itn = nodelist.iterator(); itn.hasNext(); )
{
Vertex n = itn.next();
if (n == outer)
continue;
if (surface == null)
{
n.get(tmpXYZ);
xyz = tmpXYZ;
}
else
{
for (int d = 0; d < n.dim(); d++)
parasout.writeDouble(n.get(d));
xyz = surface.value(n.getX(), n.getY());
}
for (int k = 0; k < 3; k++)
nodesout.writeDouble(xyz[k]);
}
nodesout.close();
parasout.close();
}
private static void write1dEdges(File dir, Collection<MEdge1D> edgelist, TObjectIntHashMap<MNode1D> localIdx)
throws IOException
{
File beamsFile=new File(dir, "b");
if(beamsFile.exists())
beamsFile.delete();
if (LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "begin writing "+beamsFile);
DataOutputStream beamsout = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(beamsFile, true)));
for (Iterator<MEdge1D> ite = edgelist.iterator(); ite.hasNext(); )
{
MEdge1D e = ite.next();
MNode1D pt1 = e.getNodes1();
MNode1D pt2 = e.getNodes2();
beamsout.writeInt(localIdx.get(pt1));
beamsout.writeInt(localIdx.get(pt2));
}
beamsout.close();
}
private static void write2dTriangles(File dir, Collection<Triangle> trianglelist, TObjectIntHashMap<Vertex> localIdx)
throws IOException
{
File facesFile=new File(dir, "f");
if(facesFile.exists())
facesFile.delete();
// Save faces
if (LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "begin writing "+facesFile);
DataOutputStream facesout = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(facesFile, true)));
for (Triangle f: trianglelist)
{
if (f.hasAttributes(AbstractHalfEdge.OUTER))
continue;
for (int j = 0, n = f.vertexNumber(); j < n; j++)
facesout.writeInt(localIdx.get(f.getV(j)));
}
facesout.close();
}
public static int [] readNodeReferences(BDiscretization d)
throws IOException
{
File refFile = new File(d.getGraphCell().getGraph().getModel().getOutputDir(d), "r");
IntFileReader ifrR = new PrimitiveFileReaderFactory().getIntReader(refFile);
int numberOfReferences = (int) refFile.length() / 4;
int [] refs = new int[numberOfReferences];
ifrR.get(refs);
ifrR.close();
return refs;
}
public static int getNumberOfNodes(BDiscretization d)
{
File nodesFile = new File(d.getGraphCell().getGraph().getModel().getOutputDir(d), "n");
return (int) nodesFile.length() / 24;
}
public static double[] readNodeCoordinates(BDiscretization d)
throws IOException
{
File nodesFile = new File(d.getGraphCell().getGraph().getModel().getOutputDir(d), "n");
DoubleFileReader dfrN = new PrimitiveFileReaderFactory().getDoubleReader(nodesFile);
int numberOfNodes = (int) nodesFile.length() / 24;
double [] coord = new double[3*numberOfNodes];
dfrN.get(coord);
dfrN.close();
return coord;
}
private static Vertex [] read2dCoordinates(File dir, Mesh mesh, int [] refs, TIntObjectHashMap<Vertex> mapRefVertex)
throws IOException
{
File nodesFile = new File(dir, "n");
DoubleFileReader dfrN = new PrimitiveFileReaderFactory().getDoubleReader(nodesFile);
int numberOfNodes = (int) nodesFile.length() / 24;
int numberOfReferences = refs.length / 2;
Vertex [] nodelist = new Vertex[numberOfNodes];
double [] coord = new double[3];
if (LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "Reading "+numberOfNodes+" nodes");
mesh.ensureCapacity(2*numberOfNodes);
for (int i = 0; i < numberOfNodes; i++)
{
dfrN.get(coord);
nodelist[i] = mesh.createVertex(coord[0], coord[1], coord[2]);
}
if (mesh.hasNodes())
{
for (int i=0; i < numberOfNodes; i++)
mesh.add(nodelist[i]);
}
for (int i = 0; i < numberOfReferences; i++)
{
int ind = refs[2*i];
int label = refs[2*i+1];
Vertex v = mapRefVertex.get(label);
if (v == null)
mapRefVertex.put(label, nodelist[ind]);
else
nodelist[ind] = v;
nodelist[ind].setRef(label);
}
dfrN.close();
if (LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "end reading "+dir+File.separator+"n");
return nodelist;
}
public static int[] readConnectivity(BDiscretization d)
throws IOException
{
File trianglesFile = null;
int nodesByElement;
if (d.getGraphCell().getType().equals(CADShapeEnum.EDGE))
{
trianglesFile = new File(d.getGraphCell().getGraph().getModel().getOutputDir(d), "b");
nodesByElement = 2;
}
else if (d.getGraphCell().getType().equals(CADShapeEnum.FACE))
{
trianglesFile = new File(d.getGraphCell().getGraph().getModel().getOutputDir(d), "f");
nodesByElement = 3;
}
else if (d.getGraphCell().getType().equals(CADShapeEnum.SOLID))
{
trianglesFile = new File(d.getGraphCell().getGraph().getModel().getOutputDir(d), "f");
nodesByElement = 4;
}
else
{
throw new IllegalArgumentException();
}
IntFileReader ifr = new PrimitiveFileReaderFactory().getIntReader(trianglesFile);
int[] connectivity = new int[(int) trianglesFile.length() / 4];
ifr.get(connectivity);
ifr.close();
return connectivity;
}
private static void read2dTriangles(File dir, int id, int nr, Mesh mesh, boolean reversed, Vertex [] nodelist)
throws IOException
{
File trianglesFile = new File(dir, "f");
IntFileReader ifr = new PrimitiveFileReaderFactory().getIntReader(trianglesFile);
int numberOfTriangles = (int) trianglesFile.length() / (4*nr);
if (LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "Reading "+numberOfTriangles+" elements");
mesh.ensureCapacity(numberOfTriangles);
Triangle face;
Vertex [] pts = new Vertex[nr];
for (int i = 0; i < numberOfTriangles; i++)
{
for (int j = 0; j < nr; j++)
pts[j] = nodelist[ifr.get()-1];
// Remove triangles incident to degenerated edges.
// These triangles are only useful in parameter space.
boolean degenerated = false;
for (int j = 0; j < nr; j++)
{
if (pts[j].getRef() == 0)
continue;
for (int k = j + 1; k < nr; k++)
{
if (pts[j] == pts[k])
{
j = nr;
k = nr;
degenerated = true;
}
}
}
if (degenerated)
continue;
if (reversed)
{
Vertex temp = pts[1];
pts[1] = pts[2];
pts[2] = temp;
}
face = mesh.createTriangle(pts);
mesh.add(face);
face.setGroupId(id);
}
ifr.close();
}
private static void read2dEdges(File dir, int id, int nr, Mesh mesh, boolean reversed, Vertex [] nodelist)
throws IOException
{
File edgesFile = new File(dir, "f");
IntFileReader ifr = new PrimitiveFileReaderFactory().getIntReader(edgesFile);
int numberOfBeams = (int) edgesFile.length() / (4*2);
if (LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "Reading "+numberOfBeams+" elements");
Triangle face;
Vertex [] pts = new Vertex[nr];
for (int i = 0; i < numberOfBeams; i++)
{
for (int j = 0; j < 2; j++)
pts[j] = nodelist[ifr.get()-1];
// Remove triangles incident to degenerated edges.
// These triangles are only useful in parameter space.
boolean degenerated = false;
for (int j = 0; j < nr; j++)
{
if (pts[j].getRef() == 0)
continue;
for (int k = j + 1; k < nr; k++)
{
if (pts[j] == pts[k])
{
j = nr;
k = nr;
degenerated = true;
}
}
}
if (degenerated)
continue;
if (reversed)
{
Vertex temp = pts[1];
pts[1] = pts[2];
pts[2] = temp;
}
face = mesh.createTriangle(pts);
mesh.add(face);
face.setGroupId(id);
}
ifr.close();
}
}