[MATH-749] Use new method Vector2D.crossProduct, fix typos, return Segment instead of Line in ConvexHull2D.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1563687 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Thomas Neidhart 2014-02-02 17:56:13 +00:00
parent 0fa8bcc008
commit 7897aa6a83
4 changed files with 28 additions and 56 deletions

View File

@ -130,7 +130,7 @@ public final class AklToussaintHeuristic {
} }
// get the location of the point relative to the first two vertices // get the location of the point relative to the first two vertices
final double last = getLocation(point, p1, p2); final double last = point.crossProduct(p1, p2);
final int size = quadrilateralPoints.size(); final int size = quadrilateralPoints.size();
// loop through the rest of the vertices // loop through the rest of the vertices
for (int i = 1; i < size; i++) { for (int i = 1; i < size; i++) {
@ -141,33 +141,14 @@ public final class AklToussaintHeuristic {
return true; return true;
} }
// do side of line test // do side of line test: multiply the last location with this location
// multiply the last location with this location
// if they are the same sign then the operation will yield a positive result // if they are the same sign then the operation will yield a positive result
// -x * -y = +xy, x * y = +xy, -x * y = -xy, x * -y = -xy // -x * -y = +xy, x * y = +xy, -x * y = -xy, x * -y = -xy
if (last * getLocation(point, p1, p2) < 0) { if (last * point.crossProduct(p1, p2) < 0) {
return false; return false;
} }
} }
return true; return true;
} }
/**
* Get the location of a point with regard to the given line.
* <p>
* Note: this method does the same as {@link Line#getOffset(Vector)} but is
* faster, thus preferred for this heuristic.
*
* @param point the point to check
* @param linePoint1 the first point of the line
* @param linePoint2 the second point of the line
* @return the location of the point with regard to the line
*/
private static double getLocation(final Vector2D point,
final Vector2D linePoint1,
final Vector2D linePoint2) {
return (linePoint2.getX() - linePoint1.getX()) * (point.getY() - linePoint1.getY()) -
(point.getX() - linePoint1.getX()) * (linePoint2.getY() - linePoint1.getY());
}
} }

View File

@ -23,6 +23,7 @@ import java.util.Iterator;
import org.apache.commons.math3.exception.InsufficientDataException; import org.apache.commons.math3.exception.InsufficientDataException;
import org.apache.commons.math3.geometry.euclidean.twod.Euclidean2D; import org.apache.commons.math3.geometry.euclidean.twod.Euclidean2D;
import org.apache.commons.math3.geometry.euclidean.twod.Line; import org.apache.commons.math3.geometry.euclidean.twod.Line;
import org.apache.commons.math3.geometry.euclidean.twod.Segment;
import org.apache.commons.math3.geometry.euclidean.twod.Vector2D; import org.apache.commons.math3.geometry.euclidean.twod.Vector2D;
import org.apache.commons.math3.geometry.hull.ConvexHull; import org.apache.commons.math3.geometry.hull.ConvexHull;
import org.apache.commons.math3.geometry.partitioning.Region; import org.apache.commons.math3.geometry.partitioning.Region;
@ -43,11 +44,11 @@ public class ConvexHull2D implements ConvexHull<Euclidean2D, Vector2D>, Serializ
private final Vector2D[] vertices; private final Vector2D[] vertices;
/** Line segments of the hull. */ /** Line segments of the hull. */
private final Line[] lineSegments; private final Segment[] lineSegments;
/** /**
* Simple constructor. * Simple constructor.
* @param vertices the vertices of the convex hull * @param vertices the vertices of the convex hull, must be ordered in CCW winding
* @param tolerance tolerance below which points are considered identical * @param tolerance tolerance below which points are considered identical
*/ */
ConvexHull2D(final Collection<Vector2D> vertices, final double tolerance) { ConvexHull2D(final Collection<Vector2D> vertices, final double tolerance) {
@ -56,13 +57,15 @@ public class ConvexHull2D implements ConvexHull<Euclidean2D, Vector2D>, Serializ
// construct the line segments - handle special cases of 1 or 2 points // construct the line segments - handle special cases of 1 or 2 points
final int size = vertices.size(); final int size = vertices.size();
if (size <= 1) { if (size <= 1) {
this.lineSegments = new Line[0]; this.lineSegments = new Segment[0];
} else if (size == 2) { } else if (size == 2) {
this.lineSegments = new Line[1]; this.lineSegments = new Segment[1];
final Iterator<Vector2D> it = vertices.iterator(); final Iterator<Vector2D> it = vertices.iterator();
this.lineSegments[0] = new Line(it.next(), it.next(), tolerance); final Vector2D p1 = it.next();
final Vector2D p2 = it.next();
this.lineSegments[0] = new Segment(p1, p2, new Line(p1, p2, tolerance));
} else { } else {
this.lineSegments = new Line[size]; this.lineSegments = new Segment[size];
Vector2D firstPoint = null; Vector2D firstPoint = null;
Vector2D lastPoint = null; Vector2D lastPoint = null;
int index = 0; int index = 0;
@ -71,11 +74,13 @@ public class ConvexHull2D implements ConvexHull<Euclidean2D, Vector2D>, Serializ
firstPoint = point; firstPoint = point;
lastPoint = point; lastPoint = point;
} else { } else {
this.lineSegments[index++] = new Line(lastPoint, point, tolerance); this.lineSegments[index++] =
new Segment(lastPoint, point, new Line(lastPoint, point, tolerance));
lastPoint = point; lastPoint = point;
} }
} }
this.lineSegments[index] = new Line(lastPoint, firstPoint, tolerance); this.lineSegments[index] =
new Segment(lastPoint, firstPoint, new Line(lastPoint, firstPoint, tolerance));
} }
} }
@ -85,10 +90,10 @@ public class ConvexHull2D implements ConvexHull<Euclidean2D, Vector2D>, Serializ
} }
/** /**
* Get the line segments of the convex hull, ordered in CCW direction. * Get the line segments of the convex hull, ordered in CCW winding.
* @return the line segments of the convex hull * @return the line segments of the convex hull
*/ */
public Line[] getLineSegments() { public Segment[] getLineSegments() {
return lineSegments.clone(); return lineSegments.clone();
} }
@ -98,6 +103,10 @@ public class ConvexHull2D implements ConvexHull<Euclidean2D, Vector2D>, Serializ
throw new InsufficientDataException(); throw new InsufficientDataException();
} }
final RegionFactory<Euclidean2D> factory = new RegionFactory<Euclidean2D>(); final RegionFactory<Euclidean2D> factory = new RegionFactory<Euclidean2D>();
return factory.buildConvex(lineSegments); final Line[] lineArray = new Line[lineSegments.length];
for (int i = 0; i < lineSegments.length; i++) {
lineArray[i] = lineSegments[i].getLine();
}
return factory.buildConvex(lineArray);
} }
} }

View File

@ -33,7 +33,7 @@ import org.apache.commons.math3.util.MathUtils;
* Implements Graham's scan method to generate the convex hull of a finite set of * Implements Graham's scan method to generate the convex hull of a finite set of
* points in the two-dimensional euclidean space. * points in the two-dimensional euclidean space.
* <p> * <p>
* The implementation is not sensitive to colinear points. The runtime complexity * The implementation is not sensitive to collinear points. The runtime complexity
* is O(n log n), with n being the number of input points. * is O(n log n), with n being the number of input points.
* *
* @see <a href="http://en.wikipedia.org/wiki/Graham_scan">Graham's scan algorithm (Wikipedia)</a> * @see <a href="http://en.wikipedia.org/wiki/Graham_scan">Graham's scan algorithm (Wikipedia)</a>
@ -127,7 +127,7 @@ public class GrahamScan implements ConvexHullGenerator2D {
hullVertices.add(currentPoint); hullVertices.add(currentPoint);
currentPoint = null; currentPoint = null;
} else { } else {
// otherwise, the point is either colinear or will create // otherwise, the point is either collinear or will create
// a concave section, thus we need to remove the last point. // a concave section, thus we need to remove the last point.
hullVertices.remove(size - 1); hullVertices.remove(size - 1);
} }

View File

@ -31,7 +31,7 @@ import org.apache.commons.math3.util.MathUtils;
* Implements Andrew's monotone chain method to generate the convex hull of a finite set of * Implements Andrew's monotone chain method to generate the convex hull of a finite set of
* points in the two-dimensional euclidean space. * points in the two-dimensional euclidean space.
* <p> * <p>
* The implementation is not sensitive to colinear points. The runtime complexity * The implementation is not sensitive to collinear points. The runtime complexity
* is O(n log n), with n being the number of input points. If the point set is already * is O(n log n), with n being the number of input points. If the point set is already
* sorted (by x-coordinate), the runtime complexity is O(n). * sorted (by x-coordinate), the runtime complexity is O(n).
* *
@ -97,7 +97,7 @@ public class MonotoneChain implements ConvexHullGenerator2D {
final Vector2D p1 = lowerHull.get(size - 2); final Vector2D p1 = lowerHull.get(size - 2);
final Vector2D p2 = lowerHull.get(size - 1); final Vector2D p2 = lowerHull.get(size - 1);
if (getLocation(p, p1, p2) <= 0) { if (p.crossProduct(p1, p2) <= 0) {
lowerHull.remove(size - 1); lowerHull.remove(size - 1);
} else { } else {
break; break;
@ -115,7 +115,7 @@ public class MonotoneChain implements ConvexHullGenerator2D {
final Vector2D p1 = upperHull.get(size - 2); final Vector2D p1 = upperHull.get(size - 2);
final Vector2D p2 = upperHull.get(size - 1); final Vector2D p2 = upperHull.get(size - 1);
if (getLocation(p, p1, p2) <= 0) { if (p.crossProduct(p1, p2) <= 0) {
upperHull.remove(size - 1); upperHull.remove(size - 1);
} else { } else {
break; break;
@ -137,22 +137,4 @@ public class MonotoneChain implements ConvexHullGenerator2D {
return new ConvexHull2D(hullVertices, tolerance); return new ConvexHull2D(hullVertices, tolerance);
} }
/**
* Get the location of a point with regard to the given line.
* <p>
* Note: this method does the same as {@link Line#getOffset(Vector)} but is
* faster, thus preferred for this heuristic.
*
* @param point the point to check
* @param linePoint1 the first point of the line
* @param linePoint2 the second point of the line
* @return the location of the point with regard to the line
*/
private double getLocation(final Vector2D point,
final Vector2D linePoint1,
final Vector2D linePoint2) {
return (linePoint2.getX() - linePoint1.getX()) * (point.getY() - linePoint1.getY()) -
(point.getX() - linePoint1.getX()) * (linePoint2.getY() - linePoint1.getY());
}
} }