/*
* 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 java.util.Iterator;
import org.jcae.mesh.amibe.ds.AbstractHalfEdge;
import org.jcae.mesh.amibe.ds.AbstractHalfEdge.Quality;
import org.jcae.mesh.amibe.ds.HalfEdge;
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.projection.MeshLiaison;
import org.jcae.mesh.amibe.projection.TriangleKdTree;
/**
* Swap edges around a give vertex to improve triangles quality
* @author Jerome Robert
*/
public class VertexSwapper {
private final Mesh mesh;
private final Quality quality = new Quality();
private TriangleKdTree kdTree;
private int group = -1;
public VertexSwapper(MeshLiaison liaison) {
this(liaison, null);
}
public VertexSwapper(Mesh mesh) {
this(null, mesh);
}
private VertexSwapper(MeshLiaison liaison, Mesh mesh) {
quality.setLiaison(liaison);
if(liaison == null)
this.mesh = mesh;
else
this.mesh = liaison.getMesh();
assert this.mesh != null;
}
public void setKdTree(TriangleKdTree kdTree) {
this.kdTree = kdTree;
}
public void setGroup(int group) {
this.group = group;
}
/**
* Swap the edges whose v is the origin
* This method is much slower than swap and should be avoided when possible
*/
public void swapOrigin(Vertex v)
{
loop: while(true)
{
Iterator<AbstractHalfEdge> it = v.getNeighbourIteratorAbstractHalfEdge();
while(it.hasNext())
{
HalfEdge he = (HalfEdge) it.next();
if(swapImpl(he) != he)
continue loop;
}
break loop;
}
}
/** Swap the edges whose v is the apex */
public void swap(Vertex v)
{
if(v.isManifold())
{
swapManifold(v, (Triangle)v.getLink());
}
else
{
for(Triangle t:(Triangle[])v.getLink())
swapManifold(v, t);
}
}
/** Return true if the edge should be swapped */
protected boolean isQualityImproved(Quality quality)
{
return quality.getSwappedAngle() > 0 &&
quality.getSwappedQuality() > quality.getQuality();
}
/**
* Allow subclasser to customize when an half edge can be swapped.
* By default this call HalfEdge.canSwapTopology
*/
protected boolean canSwap(HalfEdge e)
{
return e.canSwapTopology();
}
private void swapManifold(Vertex v, Triangle triangle)
{
HalfEdge current = (HalfEdge) v.getIncidentAbstractHalfEdge(triangle, null);
current = current.next();
Vertex o = current.origin();
assert current.apex() == v;
boolean redo = true;
while(redo)
{
redo = false;
while(true)
{
HalfEdge next = swapImpl(current);
boolean swapped = next != current;
current = next;
if(swapped)
redo = true;
else
{
current = current.nextApexLoop();
if (current.origin() == o)
break;
}
}
}
}
private HalfEdge swapImpl(HalfEdge current)
{
if (!current.hasAttributes(AbstractHalfEdge.NONMANIFOLD |
AbstractHalfEdge.BOUNDARY | AbstractHalfEdge.OUTER | AbstractHalfEdge.IMMUTABLE)
&& canSwap(current))
{
quality.setEdge(current);
if(isQualityImproved(quality))
{
if(kdTree != null)
{
kdTree.remove(current.getTri());
kdTree.remove(current.sym().getTri());
}
current = (HalfEdge) mesh.edgeSwap(current);
HalfEdge swapped = current.next();
if(kdTree != null)
{
kdTree.addTriangle(swapped.getTri());
kdTree.addTriangle(swapped.sym().getTri());
}
}
}
return current;
}
}