/*
* 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 2014, by Airbus Group SAS
*/
package org.jcae.mesh.amibe.projection;
import gnu.trove.map.hash.TCustomHashMap;
import gnu.trove.strategy.HashingStrategy;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
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;
/**
* Rebuild a triangulation in closed set of AbstractHalfEdge.
* This class only provide the glue to convert a set of AbstractHalfEdge to a
* polyline, and update the adjacency using the new triangulation.
* @author Jerome Robert
*/
public abstract class AbstractLocaleRemesher {
private static class OrientedEdge
{
public Vertex origin;
public Vertex destination;
public OrientedEdge() {
}
public final void set(AbstractHalfEdge edge)
{
this.origin = edge.origin();
this.destination = edge.destination();
}
public final void setSym(AbstractHalfEdge edge)
{
this.destination = edge.origin();
this.origin = edge.destination();
}
}
private final Map<Vertex, Vertex> vertexMap = HashFactory.createMap();
private final OrientedEdge searchKey = new OrientedEdge();
private final TCustomHashMap<AbstractHalfEdge, AbstractHalfEdge> edgeMap =
new TCustomHashMap(new HashingStrategy<Object>() {
public int computeHashCode(Object object) {
Vertex v1, v2;
if(object instanceof AbstractHalfEdge)
{
AbstractHalfEdge edge = (AbstractHalfEdge) object;
v1 = edge.origin();
v2 = edge.destination();
}
else
{
OrientedEdge edge = (OrientedEdge) object;
v1 = edge.origin;
v2 = edge.destination;
}
return v1.hashCode()+v2.hashCode();
}
public boolean equals(Object o1, Object o2) {
Vertex origin1, origin2, destination1, destination2;
if(o1 instanceof AbstractHalfEdge)
{
AbstractHalfEdge edge = (AbstractHalfEdge) o1;
origin1 = edge.origin();
destination1 = edge.destination();
}
else
{
OrientedEdge edge = (OrientedEdge) o1;
origin1 = edge.origin;
destination1 = edge.destination;
}
if(o2 instanceof AbstractHalfEdge)
{
AbstractHalfEdge edge = (AbstractHalfEdge) o2;
origin2 = edge.origin();
destination2 = edge.destination();
}
else
{
OrientedEdge edge = (OrientedEdge) o2;
origin2 = edge.origin;
destination2 = edge.destination;
}
return origin1 == origin2 && destination1 == destination2;
}
});
private Collection<List<Vertex>> createPolylines(Collection<AbstractHalfEdge> edges)
{
assert !edges.isEmpty();
for(AbstractHalfEdge e: edges)
vertexMap.put(e.origin(), e.destination());
Collection<List<Vertex>> polylines = new ArrayList<List<Vertex>>();
while(!vertexMap.isEmpty())
{
Vertex start = vertexMap.keySet().iterator().next();
ArrayList<Vertex> polyline = new ArrayList<Vertex>();
polylines.add(polyline);
Vertex current = vertexMap.get(start);
vertexMap.remove(start);
polyline.add(start);
while(current != start)
{
Vertex next = vertexMap.get(current);
assert next != null : "Cannot find next point after " + current
+ " in\n" + edges + "\n. Map is\n" + vertexMap +
"\n polylines is " + polylines;
vertexMap.remove(current);
polyline.add(current);
current = next;
}
assert !polyline.isEmpty();
}
assert !polylines.isEmpty();
return polylines;
}
private void updateLink(Vertex v, Triangle oldTri, Triangle newTri)
{
if(v.isManifold())
{
if(v.getLink() == oldTri)
v.setLink(newTri);
}
else
{
Triangle[] link = (Triangle[])v.getLink();
for(int i = 0; i < link.length; i++)
{
if(link[i] == oldTri)
{
link[i] = newTri;
break;
}
}
}
}
private void updateAdjacency(Mesh mesh, Collection<AbstractHalfEdge> edges,
Collection<Triangle> newTriangles)
{
Collection<Triangle> newTrianglesCopy = HashFactory.createSet(newTriangles);
edgeMap.clear();
for(Triangle t: newTriangles)
{
AbstractHalfEdge e = t.getAbstractHalfEdge();
for(int i = 0; i < 3; i++)
{
edgeMap.put(e, e);
e = e.next();
}
}
for(AbstractHalfEdge e: edges)
edgeMap.put(e.sym(), e.sym());
for(Triangle t: newTriangles)
{
AbstractHalfEdge e = t.getAbstractHalfEdge();
for(int i = 0; i < 3; i++)
{
searchKey.setSym(e);
AbstractHalfEdge other = edgeMap.get(searchKey);
other.glue(e);
if(other.hasAttributes(AbstractHalfEdge.BOUNDARY))
e.setAttributes(AbstractHalfEdge.BOUNDARY);
if(other.hasAttributes(AbstractHalfEdge.NONMANIFOLD))
e.setAttributes(AbstractHalfEdge.NONMANIFOLD);
e = e.next();
}
}
int group = -1;
for(AbstractHalfEdge e: edges)
{
assert e.sym().sym() != e : e + "\n**\n" + e.sym() + "\n**\n" + e.sym().sym();
group = e.getTri().getGroupId();
assert edgeMap.contains(e) : e + "\n:sym" + edgeMap.get(e.sym());
Triangle newTri = edgeMap.remove(e).getTri();
newTrianglesCopy.remove(newTri);
//assert newTri.getGroupId() == -1: newTri;
newTri.setGroupId(group);
assert newTriangles.contains(newTri);
updateLink(e.origin(), e.getTri(), newTri);
updateLink(e.destination(), e.getTri(), newTri);
}
// only triangles created from inside vertices remain in newTriangleCopy.
// We set their group to the group of an input edge
for(Triangle t:newTrianglesCopy) {
t.setGroupId(group);
for(int i = 0; i < 3; i++) {
Vertex v = t.getV(i);
if(v.getLink() == null)
v.setLink(t);
}
}
}
protected Collection<Triangle> newTriangles = new ArrayList<Triangle>();
protected List<Vertex> vertIndex = new ArrayList<Vertex>();
public void triangulate(Mesh mesh,
Collection<AbstractHalfEdge> edges, Collection<List<Vertex>> vertices)
throws IOException
{
Collection<List<Vertex>> polylines = createPolylines(edges);
polylines.addAll(vertices);
vertIndex.clear();
for(List<Vertex> vs: polylines)
vertIndex.addAll(vs);
newTriangles.clear();
triangulate(mesh, polylines);
assert !newTriangles.isEmpty();
updateAdjacency(mesh, edges, newTriangles);
}
public Collection<Triangle> getNewTriangles()
{
return newTriangles;
}
/**
* return and edge create in triangulate(Mesh, Collection, Collection) using
* the vertices parameter
*/
public AbstractHalfEdge getEdge(Vertex origin, Vertex destination)
{
searchKey.origin = origin;
searchKey.destination = destination;
return edgeMap.get(searchKey);
}
protected void addTriangle(Mesh m, int i1, int i2, int i3)
{
Vertex v1 = vertIndex.get(i1);
Vertex v2 = vertIndex.get(i2);
Vertex v3 = vertIndex.get(i3);
newTriangles.add(m.createTriangle(v1, v2, v3));
}
/** Actually triangulate and call addTriangle for each triangle */
protected abstract void triangulate(Mesh mesh, Collection<List<Vertex>> vertices) throws IOException;
}