/*
* __ .__ .__ ._____.
* _/ |_ _______ __|__| ____ | | |__\_ |__ ______
* \ __\/ _ \ \/ / |/ ___\| | | || __ \ / ___/
* | | ( <_> > <| \ \___| |_| || \_\ \\___ \
* |__| \____/__/\_ \__|\___ >____/__||___ /____ >
* \/ \/ \/ \/
*
* Copyright (c) 2006-2011 Karsten Schmidt
*
* 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.
*
* http://creativecommons.org/licenses/LGPL/2.1/
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
package spimedb.util.geom;
import java.util.ArrayList;
import java.util.List;
/**
* A more generic version of the Sutherland-Hodgeman algorithm to limit 2D
* polygons to convex clipping regions. Uses the clipping region's centroid and
* {@link Line2D#classifyPoint(ReadonlyVec2D)} to identify if an edge needs to
* be clipped or not.
*
* More information: http://en.wikipedia.org/wiki/Sutherland-Hodgman_algorithm
*
* @see SutherlandHodgemanClipper
* @since 0021
*/
public class ConvexPolygonClipper implements PolygonClipper2D {
protected Polygon2D bounds;
protected Vec2D boundsCentroid;
public ConvexPolygonClipper(Polygon2D bounds) {
setBounds(bounds);
}
public Polygon2D clipPolygon(Polygon2D poly) {
List<Vec2D> points = new ArrayList<>(poly.vertices);
List<Vec2D> clipped = new ArrayList<>();
points.add(points.get(0));
for (Line2D clipEdge : bounds.getEdges()) {
clipped.clear();
float sign = clipEdge.classifyPoint(boundsCentroid);
for (int i = 0, num = points.size() - 1; i < num; i++) {
Vec2D p = points.get(i);
Vec2D q = points.get(i + 1);
if (clipEdge.classifyPoint(p) == sign) {
if (clipEdge.classifyPoint(q) == sign) {
clipped.add(q.copy());
} else {
clipped.add(getClippedPosOnEdge(clipEdge, p, q));
}
continue;
}
if (clipEdge.classifyPoint(q) == sign) {
clipped.add(getClippedPosOnEdge(clipEdge, p, q));
clipped.add(q.copy());
}
}
if (clipped.size() > 0
&& clipped.get(0) != clipped.get(clipped.size() - 1)) {
clipped.add(clipped.get(0));
}
List<Vec2D> t = points;
points = clipped;
clipped = t;
}
return new Polygon2D(points).removeDuplicates(0.001f);
}
public Polygon2D getBounds() {
return bounds;
}
protected static Vec2D getClippedPosOnEdge(Line2D clipEdge, Vec2D p, Vec2D q) {
return clipEdge.intersectLine(new Line2D(p, q)).getPos();
}
protected static boolean isKnownVertex(List<Vec2D> list, Vec2D q) {
for (Vec2D p : list) {
if (p.equalsWithTolerance(q, 0.001f)) {
return true;
}
}
return false;
}
public void setBounds(Polygon2D bounds) {
this.bounds = bounds;
this.boundsCentroid = bounds.getCentroid();
}
}