/* * Project Info: http://jcae.sourceforge.net * * This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * (C) Copyright 2007-2010, by EADS France */ package org.jcae.mesh.xmldata; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintStream; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.Iterator; import java.util.StringTokenizer; import java.util.TreeSet; import java.util.logging.Level; import java.util.logging.Logger; /** * Convert a UNV mesh to an Amibe mesh. * <ul> * <li>The convertion is out-of-core and can handle large mesh.</li> * <li>The nodes and triangles of the input file must have contiguous ids.</li> * <li>Only triangles, nodes, and groups are imported.</li> * <li>2412-21 (linear beams) and 2412-92 (parabolic trias) are exported as a minimal unv * if setStripedUnv as been called.</li> * <li>If the input file do not contains any groups, a group with all triangles is * created.</li> * </ul> * @author Jerome Robert */ public class UNV2Amibe { /** A 2412 element which won't be stored into the amibe file */ private abstract class Element { String buffer; int[] nodes; protected abstract String parse(BufferedReader in) throws IOException; public Element(String line, BufferedReader in) throws IOException { buffer=line+'\n'+parse(in); } public void write(PrintStream out) { out.println(buffer); } public final int getNode(int id) { return nodes[id]; } public final int getNbNodes() { return nodes.length; } } private class Element21 extends Element { public Element21(String line, BufferedReader in) throws IOException { super(line, in); } @Override protected String parse(BufferedReader in) throws IOException { nodes=new int[2]; String l1=in.readLine(); String l2=in.readLine(); StringTokenizer st=new StringTokenizer(l2); nodes[0]=Integer.parseInt(st.nextToken()); nodes[1]=Integer.parseInt(st.nextToken()); return l1+'\n'+l2; } } private class Element24 extends Element { public Element24(String line, BufferedReader in) throws IOException { super(line, in); } @Override protected String parse(BufferedReader in) throws IOException { nodes = new int[3]; String l1 = in.readLine(); String l2 = in.readLine(); StringTokenizer st = new StringTokenizer(l2); nodes[0] = Integer.parseInt(st.nextToken()); nodes[1] = Integer.parseInt(st.nextToken()); nodes[2] = Integer.parseInt(st.nextToken()); return l1 + '\n' + l2; } } private class Element92 extends Element { public Element92(String line, BufferedReader in) throws IOException { super(line, in); } @Override protected String parse(BufferedReader in) throws IOException { nodes=new int[6]; String l1=in.readLine(); StringTokenizer st=new StringTokenizer(l1); for(int i=0; i<6; i++) nodes[i]=Integer.parseInt(st.nextToken()); return l1; } } /** * Map an UNV element ID with Amibe element ID. * This is required because UNV file mix beams and trias while amibe * separate them * This is done in a temporary file to save memory */ private static class IDMapping { /** * Element type in the temporary file used to separate beams from trias * in groups. */ public static int TRIAS = 0, BEAMS = 1; private FileChannel channel; private File file; private ByteBuffer buffer = ByteBuffer.allocate(8); public IDMapping() throws IOException { file = File.createTempFile("amibe", ".bin"); file.deleteOnExit(); channel = new RandomAccessFile(file, "rw").getChannel(); } public void close() throws IOException { channel.close(); file.delete(); } public void add(int amibeID, int type) throws IOException { buffer.rewind(); buffer.putInt(amibeID); buffer.putInt(type); buffer.rewind(); channel.write(buffer); } public void seek(int id) throws IOException { buffer.rewind(); channel.read(buffer, 8*id); } public int getID() { return buffer.getInt(0); } public int getType() { return buffer.getInt(4); } } private static final Logger LOGGER=Logger.getLogger(UNV2Amibe.class.getName()); private String unitBlock; private String stripedUnvFile; private IDMapping idMapping; private double scale = 1.0; /** a list of 2412 elements which won't be store in the amibe file */ private final ArrayList<Element> elements=new ArrayList<Element>(); public final void importMesh(String input, String output) throws IOException { importMesh(new File(input), output); } public final void importMesh(File input, String output) throws IOException { BufferedReader br=new BufferedReader(new FileReader(input)); importMesh(br, output); br.close(); } public final void importMesh(BufferedReader in, String outputDir) throws IOException { AmibeWriter.Dim3 out = new AmibeWriter.Dim3(outputDir); out.setFixNoGroup(true); importMesh(in, out); out.finish(); if(stripedUnvFile!=null) writeStripedUnv(out); } private void importMesh(BufferedReader in, AmibeWriter.Dim3 out) throws IOException { idMapping = new IDMapping(); double unit = 1.0; String line; while ((line=in.readLine())!=null) { if (line.trim().equals("-1")) { line = in.readLine().trim(); if (line.equals("2411") || line.equals("781")) { // read nodes convertNodes(in, unit / scale, out); } else if (line.equals("2412")) { // read faces convertFaces(in, out); } else if (line.equals("164")) { // read unit unit = readUnit(in); } else if ( "2430".equals(line) || "2435".equals(line) || "2477".equals(line) || "2467".equals(line)) { // read groups convertGroups(in, line, out); } /*else if (line.trim().equals("2414")) { // read colors }*/ else { // default group // read end of group while (!(line=in.readLine().trim()).equals("-1")); } } } idMapping.close(); } /** List of nodes used in elements which are not written in the amibe file */ private int[] computeListOfNodes() { TreeSet<Integer> hs=new TreeSet<Integer>(); for(int i=0; i<elements.size(); i++) { Element e=elements.get(i); for(int j=0; j<e.getNbNodes(); j++) hs.add(Integer.valueOf(e.getNode(j))); } int[] toReturn=new int[hs.size()]; Iterator<Integer> it=hs.iterator(); int k=0; while(it.hasNext()) toReturn[k++]=it.next().intValue(); return toReturn; } private void writeStripedUnv(AmibeWriter out) throws IOException { if(elements.isEmpty()) return; PrintStream stripedUnv=new PrintStream(new FileOutputStream(stripedUnvFile)); stripedUnv.println(" -1"); stripedUnv.println(" 164"); stripedUnv.println(unitBlock); stripedUnv.println(" -1"); stripedUnv.println(" -1"); stripedUnv.println(" 2411"); //write nodes int[] nodes=computeListOfNodes(); double[] nc = new double[3]; for(int i=0; i<nodes.length; i++) { out.getNode(nodes[i]-1, nc); MeshExporter.UNV.writeSingleNode(stripedUnv, nodes[i], nc[0], nc[1], nc[2]); } stripedUnv.println(" -1"); stripedUnv.println(" -1"); stripedUnv.println(" 2412"); for(int i=0; i<elements.size(); i++) { Element e=elements.get(i); stripedUnv.println(e.buffer); } //write elements stripedUnv.println(" -1"); //don't write groups for now :-( stripedUnv.close(); } protected boolean skipGroup(String name) { return false; } /** * * @param in * @return ArrayList of Group * @throws IOException */ private void convertGroups(BufferedReader in, String type, AmibeWriter out) throws IOException { String line = in.readLine(); while(!line.trim().equals("-1")) { // read the number of elements to read in the last number of the line StringTokenizer st = new StringTokenizer(line); String snb = ""; // Block number st.nextToken(); while(st.hasMoreTokens()) { snb = st.nextToken(); } // Number of elements int nbelem = Integer.valueOf(snb).intValue(); // Read group name String groupName = in.readLine().trim(); boolean skipGroup = skipGroup(groupName); boolean groupCreated = false; line = in.readLine().trim(); while (line.charAt(0) == '8' || line.charAt(0) == '7') { st = new StringTokenizer(line); // read one element over two, the first one doesnt matter while(st.hasMoreTokens()) { st.nextToken(); int ind = Integer.parseInt(st.nextToken()); if (ind != 0 && !skipGroup) { ind --; if(line.charAt(0) == '8') { if(!groupCreated) { out.nextGroup(groupName); groupCreated = true; } idMapping.seek(ind); if(idMapping.getType() == IDMapping.BEAMS) out.addBeamToGroup(idMapping.getID()); else out.addTriaToGroup(idMapping.getID()); } else //line.charAt(0) == '7' { if(!groupCreated) { out.nextNodeGroup(groupName); groupCreated = true; } out.addNodeToGroup(ind); } } nbelem--; if ("2435".equals(type) || "2477".equals(type) || "2467".equals(type)) { st.nextToken(); st.nextToken(); } } if (nbelem <= 0) { line = in.readLine(); break; } line = in.readLine().trim(); } } } private double readUnit(BufferedReader rd) throws IOException { double unit = 1.0; String line = ""; //retrieve the second line unitBlock = rd.readLine()+'\n'; line = rd.readLine(); unitBlock += line +'\n'; // fisrt number : the unit StringTokenizer st = new StringTokenizer(line); String unite = st.nextToken(); unite = unite.replace('D','E'); unit = Double.parseDouble(unite); while(!(line=rd.readLine().trim()).equals("-1")) unitBlock += line; return unit; } private void convertNodes(BufferedReader rd, double unit, AmibeWriter.Dim3 out) throws IOException { double x,y,z; String line = ""; while(!(line=rd.readLine().trim()).equals("-1")) { StringTokenizer st = new StringTokenizer(line); st.nextToken(); //node id line = rd.readLine(); //line contains coord x,y,z st = new StringTokenizer(line); String x1 = st.nextToken(); String y1 = st.nextToken(); String z1; try { z1 = st.nextToken(); } catch (java.util.NoSuchElementException ex) { z1="0.0"; } x1 = x1.replace('D','E'); y1 = y1.replace('D','E'); z1 = z1.replace('D','E'); x = Double.parseDouble(x1)/unit; y = Double.parseDouble(y1)/unit; z = Double.parseDouble(z1)/unit; out.addNode(x, y, z); } } private void convertFaces(BufferedReader rd, AmibeWriter.Dim3 out) throws IOException { LOGGER.fine("Reading triangles"); String line = ""; int nbTrias = 0; int nbBeams = 0; while (!(line=rd.readLine()).trim().equals("-1")) { // first line: type of object StringTokenizer st = new StringTokenizer(line); st.nextToken(); // face index int type=Integer.parseInt(st.nextToken()); switch(type) { case 41: case 51: case 61: case 74: case 91: line=rd.readLine(); // triangle st = new StringTokenizer(line); int p1, p2, p3; p1 = Integer.parseInt(st.nextToken()); p2 = Integer.parseInt(st.nextToken()); p3 = Integer.parseInt(st.nextToken()); out.addTriangle(p1-1, p2-1, p3-1); idMapping.add(nbTrias, IDMapping.TRIAS); nbTrias ++; break; case 94: break; //ignored case 11: //rod case 21: //linear beam Element21 beam = new Element21(line, rd); out.addBeam(beam.getNode(0)-1, beam.getNode(1)-1); idMapping.add(nbBeams, IDMapping.BEAMS); nbBeams ++; break; case 22: case 24: // parabolic beam Element24 b = new Element24(line, rd); out.addBeam(b.getNode(0) - 1, b.getNode(2) - 1); idMapping.add(nbBeams, IDMapping.BEAMS); nbBeams++; break; case 42: case 92: //parabolic triangles Element92 e=new Element92(line, rd); out.addTriangle(e.getNode(0)-1, e.getNode(2)-1, e.getNode(4)-1); idMapping.add(nbTrias, IDMapping.TRIAS); nbTrias ++; break; case 118: //tetra //skip it rd.readLine(); rd.readLine(); case 111: //tetra //skip it rd.readLine(); break; default: LOGGER.log(Level.WARNING, "Warning: Section 2412, type {0} unknown", type); } } } public final void setStripedUnv(String file) { stripedUnvFile=file; } public void setScale(double scale) { this.scale = scale; } public static void main(String[] args) { try { UNV2Amibe u=new UNV2Amibe(); String unvFile = "/home/jerome/Models/unv/FlightSMALL.unv"; String stripedFile = "/tmp/FlightSMALL1-strp.unv"; String amibeDir = "/tmp/pouet"; if (args.length > 0) unvFile = args[0]; if (args.length > 1) amibeDir = args[1]; if (args.length > 2) stripedFile = args[2]; u.setStripedUnv(stripedFile); u.importMesh(unvFile, amibeDir); } catch (Exception ex) { LOGGER.log(Level.SEVERE, null, ex); } } }