/* * 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 2012, by EADS France */ package org.jcae.mesh.amibe.algos3d; import gnu.trove.list.array.TIntArrayList; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.Collection; import java.util.List; import java.util.Random; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.xpath.XPathExpressionException; import org.jcae.mesh.amibe.ds.AbstractHalfEdge; 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.util.HashFactory; import org.jcae.mesh.xmldata.AmibeReader; import org.jcae.mesh.xmldata.JCAEXMLData; import org.jcae.mesh.xmldata.XMLReader; import org.jcae.mesh.xmldata.XMLWriter; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; /** * Set a given group on random triangles * @author Jerome Robert */ public class RandomizeGroups { private final String amibeDir; private final double ratio; private final String newGroupName; public RandomizeGroups(double ratio, String newGroupName) { this(null, ratio, newGroupName); } public RandomizeGroups(String amibeDir, double ratio, String newGroupName) { this.amibeDir = amibeDir; this.ratio = ratio; this.newGroupName = newGroupName; } /** * same as compute but do not change group of non-manifold elements and * work in-core. */ public void compute(Mesh mesh) throws IOException, SAXException { compute(mesh, false); } private boolean canRandomize(Vertex v, Collection<Vertex> forbidden) { return v.isManifold() && !forbidden.contains(v); } public void compute(Mesh mesh, boolean neighbors) throws IOException, SAXException { Random random = new Random(0); Set<Vertex> vertices = HashFactory.createSet(); for(Collection<Vertex> l:mesh.getVertexGroup().values()) vertices.addAll(l); vertices.addAll(mesh.getBeams()); int newGroupId = mesh.getNumberOfGroups(); mesh.setGroupName(newGroupId, newGroupName); triangles: for(Triangle t:mesh.getTriangles()) { String groupName = mesh.getGroupName(t.getGroupId()); if(groupName != null && canRandomize(groupName)) { if(!canRandomize(t.getV0(), vertices) || !canRandomize(t.getV1(), vertices) || !canRandomize(t.getV2(), vertices)) continue; AbstractHalfEdge e = t.getAbstractHalfEdge(); if(neighbors) { if(!canRandomize(e.sym().apex(), vertices) || !canRandomize(e.next().sym().apex(), vertices) || !canRandomize(e.prev().sym().apex(), vertices)) continue; } if(random.nextDouble() < ratio) { t.setGroupId(newGroupId); if(neighbors) { e.sym().getTri().setGroupId(newGroupId); e.next().sym().getTri().setGroupId(newGroupId); e.prev().sym().getTri().setGroupId(newGroupId); } } } } } public void compute() throws IOException, SAXException { AmibeReader.Dim3 ar = new AmibeReader.Dim3(amibeDir); AmibeReader.SubMesh sm = ar.getSubmeshes().get(0); List<AmibeReader.Group> groups = sm.getGroups(); File groupsFile = new File(new File(amibeDir, "jcae3d.files"), JCAEXMLData.groupsFilename); String tmpFile = groupsFile.getPath()+".tmp"; FileChannel fc = new FileOutputStream(tmpFile).getChannel(); TIntArrayList newGroup = new TIntArrayList( 100 + (int) (ratio * sm.getNumberOfTrias())); ByteBuffer bb = ByteBuffer.allocate(4096); TIntArrayList groupSize = new TIntArrayList(groups.size()+1); Random random = new Random(0); for(AmibeReader.Group g: sm.getGroups()) { if(g.getNumberOfBeams() == 0 && g.getNumberOfTrias() == 0) continue; boolean canRandom = canRandomize(g.getName()); int currentSize = 0; for(int triID:g.readTria3Ids()) { if(canRandom && random.nextDouble() < ratio) { newGroup.add(triID); } else { currentSize++; bb.putInt(triID); flushChannel(fc, bb, false); } } groupSize.add(currentSize); } for(int i = 0; i < newGroup.size(); i++) { bb.putInt(newGroup.get(i)); flushChannel(fc, bb, false); } groupSize.add(newGroup.size()); newGroup = null; flushChannel(fc, bb, true); updateXML(new File(amibeDir, JCAEXMLData.xml3dFilename), groupSize); groupsFile.delete(); new File(tmpFile).renameTo(groupsFile); } private void updateXML(final File file, final TIntArrayList groupSize) throws SAXException, IOException { new XMLReader() { @Override protected void read(Document dom) throws SAXException, XPathExpressionException, IOException { Element groupsE = getElement( dom.getDocumentElement(), "mesh", "submesh", "groups"); int gid = 0; long offset = 0; Element last = null; for(Element e:getElements(groupsE, "group")) { int size = groupSize.get(gid++); Element numberElement = getElement(e, "number"); //check that this is not a beam only group if(numberElement != null) { numberElement.setTextContent(Integer.toString(size)); Element fileE = getElement(e, "file"); if(offset == 0) fileE.removeAttribute("offset"); else fileE.setAttribute("offset", Long.toString(offset)); offset += size; last = e; } } int size = groupSize.get(gid); Element e = (Element) last.cloneNode(true); //the id attribut is now ignored but we remove it instead of //having a wrong one. e.removeAttribute("id"); getElement(e, "name").setTextContent(newGroupName); getElement(e, "number").setTextContent(Integer.toString(size)); getElement(e, "file").setAttribute("offset", Long.toString(offset)); groupsE.appendChild(e); XMLWriter.writeDocument(dom, file.getPath()); } @Override protected String getXSD() { return null; } }.read(file); } private static void flushChannel(FileChannel fc, ByteBuffer bb, boolean force) throws IOException { if(force || bb.position() == bb.limit()) { bb.limit(bb.position()); bb.rewind(); fc.write(bb); bb.clear(); } } /** * Override to specify which groups can be changed. * Default allow to change any groups */ protected boolean canRandomize(String groupName) { return true; } public static void main(final String[] args) { try { new RandomizeGroups("/home/robert/ast-a319-neo/demo-anabelle/demo/AST_mesh.amibe", 0.01, "CR_EXT_random").compute(); } catch (IOException ex) { Logger.getLogger(RandomizeGroups.class.getName()).log(Level.SEVERE, null, ex); } catch (SAXException ex) { Logger.getLogger(RandomizeGroups.class.getName()).log(Level.SEVERE, null, ex); } } }