/* jCAE stand for Java Computer Aided Engineering. Features are : Small CAD modeler, Finite element mesher, Plugin architecture. Copyright (C) 2011, 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.amibe.algos3d; import org.jcae.mesh.amibe.ds.Mesh; import org.jcae.mesh.amibe.ds.Vertex; import org.jcae.mesh.amibe.ds.AbstractHalfEdge; import org.jcae.mesh.amibe.ds.Triangle; import org.jcae.mesh.amibe.projection.MeshLiaison; import org.jcae.mesh.amibe.util.QSortedTree; import org.jcae.mesh.amibe.util.PAVLSortedTree; import java.util.Stack; import java.util.Iterator; import java.util.Collection; import java.io.ObjectOutputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import org.jcae.mesh.amibe.util.HashFactory; public abstract class AbstractAlgoVertex { Mesh mesh; MeshLiaison liaison; double tolerance = 0.0; double maxEdgeLength = -1.0; int processed = 0; int notProcessed = 0; int notInTree = 0; private int progressBarStatus = 10000; double minCos = 0.95; QSortedTree<Vertex> tree = new PAVLSortedTree<Vertex>(); private Collection<Vertex> nodeset; protected abstract void preProcessAllVertices(); protected abstract void postProcessAllVertices(); protected abstract boolean canProcessVertex(Vertex v); protected abstract boolean processVertex(Vertex v, double cost); protected abstract double cost(Vertex v); protected abstract Logger thisLogger(); private static final String dumpFile = "/tmp/jcae.dump"; AbstractAlgoVertex(final Mesh m) { this(m, null); } AbstractAlgoVertex(final Mesh m, final MeshLiaison meshLiaison) { mesh = m; liaison = meshLiaison; } public final void compute() { long startTime = System.nanoTime(); thisLogger().info("Run "+getClass().getName()); mesh.getTrace().println("# Begin "+getClass().getName()); processed = 0; notProcessed = 0; notInTree = 0; preProcessAllVertices(); thisLogger().info("Compute initial tree"); computeTree(); postComputeTree(); processAllVertices(); thisLogger().info("Number of processed points: "+processed); thisLogger().info("Total number of points which could not be processed: "+notProcessed); mesh.getTrace().println("# End "+getClass().getName()); assert mesh.checkNoDegeneratedTriangles(); assert mesh.checkNoInvertedTriangles(); long endTime = System.nanoTime(); thisLogger().log(Level.INFO, "Computation time: {0}ms", Double.toString((endTime - startTime)/1E6)); } public void setProgressBarStatus(int n) { progressBarStatus = n; } private void computeTree() { if (nodeset == null) nodeset = mesh.getNodes(); if (nodeset == null) { nodeset = HashFactory.<Vertex>createSet(mesh.getTriangles().size() / 2); for (Triangle f: mesh.getTriangles()) { if (f.hasAttributes(AbstractHalfEdge.OUTER)) continue; f.addVertexTo(nodeset); } } // Compute vertex cost for (Vertex v: nodeset) { if (!canProcessVertex(v)) continue; if (!tree.contains(v)) { double val = cost(v); if (val <= tolerance) tree.insert(v, val); } } } void postComputeTree() { } // This routine is needed by DecimateHalfedge. void preProcessVertex() { } private boolean processAllVertices() { Stack<Vertex> stackNotProcessedObject = new Stack<Vertex>(); Stack<Double> stackNotProcessedValue = new Stack<Double>(); double cost = -1.0; while (!tree.isEmpty()) { preProcessVertex(); Vertex current = null; Iterator<QSortedTree.Node<Vertex>> itt = tree.iterator(); if (processed > 0 && (processed % progressBarStatus) == 0) thisLogger().info("Vertices processed: "+processed); while (itt.hasNext()) { QSortedTree.Node<Vertex> q = itt.next(); current = q.getData(); cost = q.getValue(); if (cost > tolerance) break; if (canProcessVertex(current)) break; if (thisLogger().isLoggable(Level.FINE)) thisLogger().fine("Vertex not processed: "+current); notProcessed++; // Add a penalty to vertices which could not have been // processed. This has to be done outside this loop, // because PAVLSortedTree instances must not be modified // when walked through. stackNotProcessedObject.push(current); if (tolerance != 0.0) stackNotProcessedValue.push(Double.valueOf(cost+0.7*(tolerance - cost))); else // tolerance = cost = 0 stackNotProcessedValue.push(Double.valueOf(1.0)); current = null; } if (cost > tolerance || current == null) break; // Update costs for edges which were not contracted while (stackNotProcessedObject.size() > 0) { double newCost = stackNotProcessedValue.pop().doubleValue(); Vertex f = stackNotProcessedObject.pop(); tree.update(f, newCost); } tree.remove(current); processVertex(current, cost); afterProcessHook(); processed++; } postProcessAllVertices(); return processed > 0; } final void dumpState() { ObjectOutputStream out = null; try { out = new ObjectOutputStream(new FileOutputStream(dumpFile)); out.writeObject(mesh); out.writeObject(tree); appendDumpState(out); out.close(); } catch (Exception ex) { ex.printStackTrace(); System.exit(-1); } } void appendDumpState(ObjectOutputStream out) throws IOException { } @SuppressWarnings("unchecked") final boolean restoreState() { try { FileInputStream istream = new FileInputStream(dumpFile); ObjectInputStream q = new ObjectInputStream(istream); System.out.println("Loading restored state"); mesh = (Mesh) q.readObject(); tree = (QSortedTree<Vertex>) q.readObject(); appendRestoreState(q); System.out.println("... Done."); q.close(); assert mesh.isValid(); } catch (FileNotFoundException ex) { return false; } catch (Exception ex) { ex.printStackTrace(); System.exit(-1); } return true; } void appendRestoreState(ObjectInputStream q) throws IOException { } protected void afterProcessHook() { } protected void afterSwapHook() { } }