/* jCAE stand for Java Computer Aided Engineering. Features are : Small CAD modeler, Finite element mesher, Plugin architecture. Copyright (C) 2003,2004,2005, by EADS CRC Copyright (C) 2007,2008,2009, 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 java.io.IOException; import java.util.logging.Level; import org.jcae.mesh.cad.CADExplorer; import org.jcae.mesh.cad.CADFace; import org.jcae.mesh.cad.CADGeomSurface; import org.jcae.mesh.cad.CADShape; import org.jcae.mesh.cad.CADShapeEnum; import org.jcae.mesh.cad.CADShapeFactory; import java.io.File; import java.io.FileNotFoundException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; import gnu.trove.map.hash.TIntIntHashMap; import gnu.trove.map.hash.TIntObjectHashMap; import org.w3c.dom.Document; import org.w3c.dom.Node; import java.util.logging.Logger; public class MeshToMMesh3DConvert implements FilterInterface, JCAEXMLData { private static final Logger LOGGER=Logger.getLogger(MeshToMMesh3DConvert.class.getName()); private int nrRefs = 0; private int nrIntNodes = 0; private int nrTriangles = 0; private int offsetBnd = 0; private int nodeOffset = 0; private TIntIntHashMap xrefs; private final TIntObjectHashMap<CADFace> mapFaces = new TIntObjectHashMap<CADFace>(); private double [] coordRefs = null; private final String xmlDir; private final String brepFile; private UNVGenericWriter unvWriter; private AmibeWriter.Dim3 amibeWriter; private boolean writeNormal; public MeshToMMesh3DConvert(String dir, String bFile, CADShape shape) { xmlDir = dir; brepFile = bFile; int iFace = 0; CADExplorer expF = CADShapeFactory.getFactory().newExplorer(); for (expF.init(shape, CADShapeEnum.FACE); expF.more(); expF.next()) { iFace++; mapFaces.put(iFace, (CADFace) expF.current()); } } public final void exportUNV(boolean b, String unvName) { if (b) unvWriter = new UNVGenericWriter(unvName); } public final void collectBoundaryNodes(int[] faces) { for (int iFace : faces) { Document document; File xmlFile2d = null; try { xmlFile2d = new File(xmlDir, JCAEXMLData.xml2dFilename+iFace); document = XMLHelper.parseXML(xmlFile2d); } catch(FileNotFoundException ex) { continue; } catch(Exception ex) { ex.printStackTrace(); throw new RuntimeException(ex); } XPath xpath = XPathFactory.newInstance().newXPath(); try { String formatVersion = xpath.evaluate("/jcae/@version", document); if (formatVersion != null && formatVersion.length() > 0) throw new RuntimeException("File "+xmlFile2d+" has been written by a newer version of jCAE and cannot be re-read"); Node submeshElement = (Node) xpath.evaluate("/jcae/mesh/submesh", document, XPathConstants.NODE); Node submeshNodes = (Node) xpath.evaluate("nodes", submeshElement, XPathConstants.NODE); int numberOfReferences = Integer.parseInt( xpath.evaluate("references/number/text()", submeshNodes)); nrRefs += numberOfReferences; int numberOfNodes = Integer.parseInt( xpath.evaluate("number/text()", submeshNodes)); nrIntNodes += numberOfNodes - numberOfReferences; } catch(Exception ex) { ex.printStackTrace(); throw new RuntimeException(ex); } LOGGER.fine("Total: "+nrRefs+" references"); } } public final void beforeProcessingAllShapes(boolean writeNormal) { try { coordRefs = new double[3 * nrRefs]; xrefs = new TIntIntHashMap(nrRefs); amibeWriter = new AmibeWriter.Dim3(xmlDir, writeNormal); amibeWriter.setShape(brepFile); this.writeNormal = writeNormal; } catch (IOException ex) { LOGGER.log(Level.SEVERE, ex.getMessage(), ex); } } public final void afterProcessingAllShapes() { // Stores coordinates of boundary nodes // Set nrRefs to its final value after elimination // of duplicates nrRefs = offsetBnd; int nrNodes = nrIntNodes + nrRefs; LOGGER.fine("Append coordinates of "+nrRefs+" nodes"); try { for (int i = 0; i < 3*nrRefs; i+=3) amibeWriter.addNode(coordRefs[i], coordRefs[i+1], coordRefs[i+2]); if (unvWriter != null) unvWriter.finish(nrRefs, nrIntNodes, nrTriangles, coordRefs); amibeWriter.finish(); LOGGER.info("Total number of nodes: "+nrNodes); LOGGER.info("Total number of triangles: "+nrTriangles); } catch(Exception ex) { ex.printStackTrace(); throw new RuntimeException(ex); } } /** * Convert 2D files to 3D files. * @param groupId group number of this 2D mesh * @param groupName group name * @param iFace face number */ public final void processOneShape(int groupId, String groupName, int iFace) { Document documentIn; File xmlFile2d = null; try { xmlFile2d = new File(xmlDir, JCAEXMLData.xml2dFilename+groupId); documentIn = XMLHelper.parseXML(xmlFile2d); } catch(FileNotFoundException ex) { return; } catch(Exception ex) { ex.printStackTrace(); throw new RuntimeException(ex); } CADFace F = mapFaces.get(iFace); XPath xpath = XPathFactory.newInstance().newXPath(); CADGeomSurface surface = F.getGeomSurface(); surface.dinit(1); try { String formatVersion = xpath.evaluate("/jcae/@version", documentIn); if (formatVersion != null && formatVersion.length() > 0) throw new RuntimeException("File "+xmlFile2d+" has been written by a newer version of jCAE and cannot be re-read"); String nodesFileInput = xpath.evaluate( "/jcae/mesh/submesh/nodes/file/@location", documentIn); PrimitiveFileReaderFactory pfrf = new PrimitiveFileReaderFactory(); DoubleFileReader dfrN = pfrf.getDoubleReader(new File(xmlDir, nodesFileInput)); String refFileInput = xpath.evaluate( "/jcae/mesh/submesh/nodes/references/file/@location", documentIn); IntFileReader ifrR = pfrf.getIntReader(new File(xmlDir, refFileInput)); String trianglesFileInput = xpath.evaluate( "/jcae/mesh/submesh/triangles/file/@location", documentIn); IntFileReader ifrT = pfrf.getIntReader(new File(xmlDir, trianglesFileInput)); Node submeshElement = (Node) xpath.evaluate("/jcae/mesh/submesh", documentIn, XPathConstants.NODE); Node submeshNodes = (Node) xpath.evaluate("nodes", submeshElement, XPathConstants.NODE); int numberOfReferences = Integer.parseInt( xpath.evaluate("references/number/text()", submeshNodes)); int [] refs = new int[numberOfReferences]; LOGGER.fine("Reading "+numberOfReferences+" references"); int numberOfNodes = Integer.parseInt( xpath.evaluate("number/text()", submeshNodes)); LOGGER.fine("Reading "+numberOfNodes+" nodes"); double [] normals = new double[3*numberOfNodes]; // Interior nodes for (int i = 0; i < numberOfNodes - numberOfReferences; i++) { double u = dfrN.get(); double v = dfrN.get(); double [] p3 = surface.value(u, v); amibeWriter.addNode(p3); if (unvWriter != null) unvWriter.writeNode(i+nodeOffset+1, p3); surface.setParameter(u, v); p3 = surface.normal(); System.arraycopy(p3, 0, normals, 3 * i, 3); } // Boundary nodes ifrR.get(refs); for (int i = 0; i < numberOfReferences; i++) { double u = dfrN.get(); double v = dfrN.get(); surface.setParameter(u, v); double [] p3 = surface.normal(); System.arraycopy(p3, 0, normals, 3 * (i + numberOfNodes - numberOfReferences), 3); if (!xrefs.contains(refs[i])) { p3 = surface.value(u, v); xrefs.put(refs[i], offsetBnd); System.arraycopy(p3, 0, coordRefs, 3 * offsetBnd, 3); offsetBnd++; amibeWriter.addNodeRef(refs[i]); } } Node submeshFaces = (Node) xpath.evaluate("triangles", submeshElement, XPathConstants.NODE); int numberOfFaces = Integer.parseInt(xpath.evaluate( "number/text()", submeshFaces)); LOGGER.fine("Reading "+numberOfFaces+" faces"); int ind [] = new int[4]; int indLoc [] = new int[3]; int cntTriangles = 0; for (int i = 0; i < numberOfFaces; i++) { for (int j = 0; j < 3; j++) { // Local node number for this group indLoc[j] = ifrT.get(); } if (indLoc[0] < 0 || indLoc[1] < 0 || indLoc[2] < 0) { // Skip outer triangles continue; } for (int j = 0; j < 3; j++) { // Global node number if (indLoc[j] < numberOfNodes - numberOfReferences) ind[j+1] = indLoc[j] + nodeOffset; else ind[j+1] = xrefs.get(refs[indLoc[j] - numberOfNodes + numberOfReferences]) + nrIntNodes; } if (ind[1] == ind[2] || ind[2] == ind[3] || ind[3] == ind[1]) { LOGGER.fine("Triangle bound from a degenerated edge skipped"); continue; } if (writeNormal) { for (int j = 0; j < 3; j++) { int u = 3*indLoc[j]; // Write normals if (F.isOrientationForward()) amibeWriter.addNormal(normals[u], normals[u+1], normals[u+2]); else amibeWriter.addNormal(-normals[u], -normals[u+1], -normals[u+2]); } } if (F.isOrientationForward()) { int temp = ind[1]; ind[1] = ind[2]; ind[2] = temp; } amibeWriter.addTriangle(ind[1], ind[2], ind[3]); if (unvWriter != null) { ind[0] = 3; for (int j = 1; j < 4; j++) ind[j]++; unvWriter.writeElement(cntTriangles+nrTriangles+1, ind); } cntTriangles++; } LOGGER.fine("End reading"); amibeWriter.nextGroup(groupName); for (int i=0; i < cntTriangles; i++) amibeWriter.addTriaToGroup(i+nrTriangles); if (unvWriter != null) { int [] ids = new int[cntTriangles]; for (int i = 0; i < cntTriangles; i++) ids[i] = i + nrTriangles + 1; unvWriter.writeGroup(groupId, groupName, ids); } nodeOffset += numberOfNodes - numberOfReferences; nrTriangles += cntTriangles; ifrT.close(); dfrN.close(); ifrR.close(); } catch(Exception ex) { ex.printStackTrace(); throw new RuntimeException(ex); } } }