/* 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, 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 java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
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.metrics.KdTree;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jcae.mesh.amibe.traits.MeshTraitsBuilder;
import org.jcae.mesh.amibe.util.HashFactory;
import org.jcae.mesh.xmldata.MeshReader;
import org.jcae.mesh.xmldata.MeshWriter;
/**
* Fuse near nodes in a Mesh instance.
*/
public class Fuse
{
private static final Logger LOGGER=Logger.getLogger(Fuse.class.getName());
private final Mesh mesh;
private final double[] tolerances;
/**
* Creates a <code>Fuse</code> instance.
*
* @param m the <code>MMesh3D</code> instance to refine.
* @param eps tolerance.
*/
public Fuse(Mesh m, double ... eps)
{
mesh = m;
int k = 0;
tolerances = new double[eps.length];
for(double e: eps)
tolerances[k++] = e * e;
}
public void compute()
{
LOGGER.fine("Running Fuse");
double [] bmin = new double[3];
double [] bmax = new double[3];
for (int i = 0; i < 3; i++)
{
bmin[i] = Double.MAX_VALUE;
bmax[i] = Double.MIN_VALUE;
}
Collection<Vertex> nodes = mesh.getOrComputeNodes(-1, null);
for (Vertex n: nodes)
{
bmin[0] = Math.min(bmin[0], n.getX());
bmax[0] = Math.max(bmax[0], n.getX());
bmin[1] = Math.min(bmin[1], n.getY());
bmax[1] = Math.max(bmax[1], n.getY());
bmin[2] = Math.min(bmin[2], n.getZ());
bmax[2] = Math.max(bmax[2], n.getZ());
}
// Enlarge the bounding box
for (int i = 0; i < 3; i++)
{
if (bmin[i] > 0.0)
bmin[i] *= 0.99;
else
bmin[i] *= 1.01;
if (bmax[i] > 0.0)
bmax[i] *= 1.01;
else
bmax[i] *= 0.99;
}
double [] bbox = new double[6];
for (int i = 0; i < 3; i++)
{
bbox[i] = bmin[i];
bbox[i+3] = bmax[i];
}
Map<Vertex, Vertex> map = HashFactory.createMap();
for(double tolerance: tolerances)
{
KdTree<Vertex> octree = new KdTree<Vertex>(bbox);
map.clear();
for (Vertex n: nodes)
{
Vertex p = octree.getNearestVertex(mesh.getMetric(n), n);
if (p == null || n.sqrDistance3D(p) > tolerance)
octree.add(n);
else
{
LOGGER.log(Level.FINE,
"Node {0} is removed, it is too close from {1}",
new Object[]{n, p});
map.put(n, p);
n.setRef(0);
}
}
LOGGER.log(Level.INFO, "{0} node(s) are removed", map.size());
Iterator<Triangle> itt = mesh.getTriangles().iterator();
while(itt.hasNext())
{
Triangle t = itt.next();
for (int j = 0; j < 3; j++)
{
Vertex n = t.getV(j);
Vertex p = map.get(n);
if (p != null)
{
t.setV(j, p);
nodes.remove(n);
}
}
if(t.getV0() == t.getV1() || t.getV0() == t.getV2() || t.getV1() == t.getV2())
itt.remove();
}
}
}
}