/* jCAE stand for Java Computer Aided Engineering. Features are : Small CAD modeler, Finite element mesher, Plugin architecture. Copyright (C) 2003,2004,2005,2006, 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.bora.algo; import org.jcae.mesh.bora.ds.BCADGraphCell; import org.jcae.mesh.bora.ds.BDiscretization; import org.jcae.mesh.amibe.patch.Mesh2D; import org.jcae.mesh.amibe.patch.Vertex2D; import org.jcae.mesh.amibe.traits.TriangleTraitsBuilder; import org.jcae.mesh.amibe.traits.MeshTraitsBuilder; import org.jcae.mesh.cad.CADShape; import org.jcae.mesh.cad.CADVertex; import org.jcae.mesh.cad.CADEdge; import org.jcae.mesh.cad.CADWire; import org.jcae.mesh.cad.CADFace; import org.jcae.mesh.cad.CADShapeEnum; import org.jcae.mesh.cad.CADShapeFactory; import org.jcae.mesh.cad.CADWireExplorer; import org.jcae.mesh.cad.CADGeomCurve2D; import org.jcae.mesh.cad.CADGeomCurve3D; import org.jcae.mesh.amibe.algos2d.CheckDelaunay; import org.jcae.mesh.amibe.algos2d.ConstraintNormal3D; import org.jcae.mesh.amibe.algos2d.EnforceAbsDeflection; import org.jcae.mesh.amibe.algos2d.Initial; import org.jcae.mesh.amibe.algos2d.Insertion; import org.jcae.mesh.amibe.ds.MNode1D; import org.jcae.mesh.amibe.ds.SubMesh1D; import org.jcae.mesh.amibe.ds.MeshParameters; import java.util.ArrayList; import java.util.Iterator; import java.util.HashMap; import java.util.logging.Level; import java.util.logging.Logger; /** * @see org.jcae.mesh.amibe.algos2d.BasicMesh */ public class Basic2d implements AlgoInterface { private static final Logger LOGGER = Logger.getLogger(Basic2d.class.getName()); private final double maxlen; private final double deflection; private final boolean relDefl; private final boolean isotropic; public Basic2d(double len, double defl, boolean rel, boolean iso) { maxlen = len; deflection = defl; relDefl = rel; isotropic = iso; } public boolean isAvailable() { return true; } public int getOrientation(int o) { return o; } public boolean compute(BDiscretization d) { BCADGraphCell cell = d.getGraphCell(); CADFace F = (CADFace) cell.getShape(); if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, ""+this+" shape: "+F); TriangleTraitsBuilder ttb = new TriangleTraitsBuilder(); ttb.addVirtualHalfEdge(); MeshTraitsBuilder mtb = new MeshTraitsBuilder(); mtb.addTriangleList(); mtb.addKdTree(2); mtb.add(ttb); HashMap<String, String> options = new HashMap<String, String>(); options.put("size", Double.toString(maxlen)); options.put("deflection", Double.toString(deflection)); options.put("relativeDeflection", Boolean.toString(relDefl)); options.put("isotropic", Boolean.toString(isotropic)); MeshParameters mp = new MeshParameters(options); Mesh2D m = new Mesh2D(mtb, mp, F); d.setMesh(m); boolean accumulateEpsilon = mp.hasCumulativeEpsilon(); double epsilon = mp.getEpsilon(); // Insert interior vertices, if any ArrayList<MNode1D> innerV = new ArrayList<MNode1D>(); for (Iterator<BCADGraphCell> it = cell.shapesIterator(); it.hasNext(); ) { BCADGraphCell sub = it.next(); CADShape subV = sub.getShape(); if (subV instanceof CADVertex) { MNode1D n = new MNode1D(0.0, (CADVertex) subV); innerV.add(n); } } // Boundary nodes. See org.jcae.mesh.mesher.ds.MMesh1D.boundaryNodes() ArrayList<Vertex2D> bndV = new ArrayList<Vertex2D>(); CADWireExplorer wexp = CADShapeFactory.getFactory().newWireExplorer(); for (Iterator<BCADGraphCell> it = cell.shapesExplorer(CADShapeEnum.WIRE); it.hasNext(); ) { BCADGraphCell wire = it.next(); MNode1D p1 = null; Vertex2D p20 = null, p2 = null, lastPoint = null; double accumulatedLength = 0.0; ArrayList<Vertex2D> nodesWire = new ArrayList<Vertex2D>(); for (wexp.init((CADWire) wire.getShape(), F); wexp.more(); wexp.next()) { CADEdge te = wexp.current(); CADGeomCurve2D c2d = CADShapeFactory.getFactory().newCurve2D(te, F); CADGeomCurve3D c3d = CADShapeFactory.getFactory().newCurve3D(te); BDiscretization dc = cell.getGraph().getByShape(te).getDiscretizationSubMesh(d.getFirstSubMesh()); SubMesh1D submesh1d = (SubMesh1D) dc.getMesh(); ArrayList<MNode1D> nodelist = submesh1d.getNodes(); ArrayList<MNode1D> saveList = new ArrayList<MNode1D>(nodelist); if (!te.isOrientationForward()) { // Sort in reverse order int size = saveList.size(); for (int i = 0; i < size/2; i++) { MNode1D o = saveList.get(i); saveList.set(i, saveList.get(size - i - 1)); saveList.set(size - i - 1, o); } } Iterator<MNode1D> itn = saveList.iterator(); // Except for the very first edge, the first // vertex is constrained to be the last one // of the previous edge. p1 = itn.next(); if (null == p2) { p2 = Vertex2D.valueOf(p1, c2d, F); nodesWire.add(p2); p20 = p2; lastPoint = p2; } ArrayList<Vertex2D> newNodes = new ArrayList<Vertex2D>(saveList.size()); while (itn.hasNext()) { p1 = itn.next(); p2 = Vertex2D.valueOf(p1, c2d, F); newNodes.add(p2); } // An edge is skipped if all the following conditions // are met: // 1. It is not degenerated // 2. It has not been discretized in 1D // 3. Edge length is smaller than epsilon // 4. Accumulated points form a curve with a deflection // which meets its criterion boolean canSkip = false; if (nodelist.size() == 2 && !te.isDegenerated()) { // 3. Edge length is smaller than epsilon double edgelen = c3d.length(); if (accumulateEpsilon) canSkip = edgelen + accumulatedLength < epsilon; else canSkip = edgelen < epsilon; if (canSkip) accumulatedLength += edgelen; // 4. Check whether deflection is valid. if (canSkip && mp.hasDeflection()) { double[] start = m.getGeomSurface().value( lastPoint.getX(), lastPoint.getY()); double [] end = m.getGeomSurface().value(p2.getX(), p2.getY()); double dist = Math.sqrt( (start[0] - end[0]) * (start[0] - end[0]) + (start[1] - end[1]) * (start[1] - end[1]) + (start[2] - end[2]) * (start[2] - end[2])); double dmax = m.getMeshParameters().getDeflection(); if (m.getMeshParameters().hasRelativeDeflection()) dmax *= accumulatedLength; if (accumulatedLength - dist > dmax) canSkip = false; } } if (!canSkip) { nodesWire.addAll(newNodes); accumulatedLength = 0.0; lastPoint = p2; } } // If a wire has less than 3 points, it is discarded if (nodesWire.size() > 3) { // Overwrite the last value to close the wire nodesWire.set(nodesWire.size()-1, p20); bndV.addAll(nodesWire); } } new Initial(m, mtb, bndV.toArray(new Vertex2D[bndV.size()]), innerV).compute(); m.pushCompGeom(3); new Insertion(m, 16.0 / Math.sqrt(2.0), 16.0 * Math.sqrt(2.0)).compute(); new ConstraintNormal3D(m).compute(); new Insertion(m, 4.0 / Math.sqrt(2.0), 4.0 * Math.sqrt(2.0)).compute(); new ConstraintNormal3D(m).compute(); new Insertion(m, 1.0 / Math.sqrt(2.0), Math.sqrt(2.0)).compute(); m.popCompGeom(3); new ConstraintNormal3D(m).compute(); new CheckDelaunay(m).compute(); if (deflection > 0.0 && !relDefl) new EnforceAbsDeflection(m).compute(); return true; } @Override public final String toString() { StringBuilder ret = new StringBuilder("Algo: "+getClass().getName()); ret.append("\nTarget size: ").append(maxlen); ret.append("\nDeflection: ").append(deflection); if (relDefl) ret.append(" (relative)"); else ret.append(" (absolute)"); return ret.toString(); } }