diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/oned/Interval.java b/src/main/java/org/apache/commons/math/geometry/euclidean/oned/Interval.java index 609d195a3..37e0cc0fb 100644 --- a/src/main/java/org/apache/commons/math/geometry/euclidean/oned/Interval.java +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/oned/Interval.java @@ -19,7 +19,8 @@ package org.apache.commons.math.geometry.euclidean.oned; /** This class represents a 1D interval. * @see IntervalsSet - * @version $Revision$ $Date$ + * @version $Id:$ + * @since 3.0 */ public class Interval { diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/oned/IntervalsSet.java b/src/main/java/org/apache/commons/math/geometry/euclidean/oned/IntervalsSet.java index e76e9287c..1814d380f 100644 --- a/src/main/java/org/apache/commons/math/geometry/euclidean/oned/IntervalsSet.java +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/oned/IntervalsSet.java @@ -20,14 +20,16 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import org.apache.commons.math.geometry.partitioning.AbstractRegion; import org.apache.commons.math.geometry.partitioning.BSPTree; import org.apache.commons.math.geometry.partitioning.Region; import org.apache.commons.math.geometry.partitioning.SubHyperplane; /** This class represents a 1D region: a set of intervals. - * @version $Revision$ $Date$ + * @version $Id:$ + * @since 3.0 */ -public class IntervalsSet extends Region { +public class IntervalsSet extends AbstractRegion { /** Build an intervals set representing the whole real line. */ @@ -54,7 +56,7 @@ public class IntervalsSet extends Region { * {@code Boolean.TRUE} and {@code Boolean.FALSE}

* @param tree inside/outside BSP tree representing the intervals set */ - public IntervalsSet(final BSPTree tree) { + public IntervalsSet(final BSPTree tree) { super(tree); } @@ -77,7 +79,7 @@ public class IntervalsSet extends Region { * space.

* @param boundary collection of boundary elements */ - public IntervalsSet(final Collection boundary) { + public IntervalsSet(final Collection> boundary) { super(boundary); } @@ -88,52 +90,52 @@ public class IntervalsSet extends Region { * to {@code lower} (may be {@code Double.POSITIVE_INFINITY}) * @return the built tree */ - private static BSPTree buildTree(final double lower, final double upper) { + private static BSPTree buildTree(final double lower, final double upper) { if (Double.isInfinite(lower) && (lower < 0)) { if (Double.isInfinite(upper) && (upper > 0)) { // the tree must cover the whole real line - return new BSPTree(Boolean.TRUE); + return new BSPTree(Boolean.TRUE); } // the tree must be open on the negative infinity side - final SubHyperplane upperCut = - new SubHyperplane(new OrientedPoint(new Point1D(upper), true)); - return new BSPTree(upperCut, - new BSPTree(Boolean.FALSE), - new BSPTree(Boolean.TRUE), + final SubHyperplane upperCut = + new OrientedPoint(new Vector1D(upper), true).wholeHyperplane(); + return new BSPTree(upperCut, + new BSPTree(Boolean.FALSE), + new BSPTree(Boolean.TRUE), null); } - final SubHyperplane lowerCut = - new SubHyperplane(new OrientedPoint(new Point1D(lower), false)); + final SubHyperplane lowerCut = + new OrientedPoint(new Vector1D(lower), false).wholeHyperplane(); if (Double.isInfinite(upper) && (upper > 0)) { // the tree must be open on the positive infinity side - return new BSPTree(lowerCut, - new BSPTree(Boolean.FALSE), - new BSPTree(Boolean.TRUE), + return new BSPTree(lowerCut, + new BSPTree(Boolean.FALSE), + new BSPTree(Boolean.TRUE), null); } // the tree must be bounded on the two sides - final SubHyperplane upperCut = - new SubHyperplane(new OrientedPoint(new Point1D(upper), true)); - return new BSPTree(lowerCut, - new BSPTree(Boolean.FALSE), - new BSPTree(upperCut, - new BSPTree(Boolean.FALSE), - new BSPTree(Boolean.TRUE), + final SubHyperplane upperCut = + new OrientedPoint(new Vector1D(upper), true).wholeHyperplane(); + return new BSPTree(lowerCut, + new BSPTree(Boolean.FALSE), + new BSPTree(upperCut, + new BSPTree(Boolean.FALSE), + new BSPTree(Boolean.TRUE), null), null); } /** {@inheritDoc} */ - public Region buildNew(final BSPTree tree) { + public IntervalsSet buildNew(final BSPTree tree) { return new IntervalsSet(tree); } /** {@inheritDoc} */ protected void computeGeometricalProperties() { if (getTree(false).getCut() == null) { - setBarycenter(Point1D.UNDEFINED); + setBarycenter(Vector1D.NaN); setSize(((Boolean) getTree(false).getAttribute()) ? Double.POSITIVE_INFINITY : 0); } else { double size = 0.0; @@ -143,7 +145,7 @@ public class IntervalsSet extends Region { sum += interval.getLength() * interval.getMidPoint(); } setSize(size); - setBarycenter(Double.isInfinite(size) ? Point1D.UNDEFINED : new Point1D(sum / size)); + setBarycenter(Double.isInfinite(size) ? Vector1D.NaN : new Vector1D(sum / size)); } } @@ -154,11 +156,11 @@ public class IntervalsSet extends Region { * instance is empty) */ public double getInf() { - BSPTree node = getTree(false); + BSPTree node = getTree(false); double inf = Double.POSITIVE_INFINITY; while (node.getCut() != null) { final OrientedPoint op = (OrientedPoint) node.getCut().getHyperplane(); - inf = op.getLocation().getAbscissa(); + inf = op.getLocation().getX(); node = op.isDirect() ? node.getMinus() : node.getPlus(); } return ((Boolean) node.getAttribute()) ? Double.NEGATIVE_INFINITY : inf; @@ -171,11 +173,11 @@ public class IntervalsSet extends Region { * instance is empty) */ public double getSup() { - BSPTree node = getTree(false); + BSPTree node = getTree(false); double sup = Double.NEGATIVE_INFINITY; while (node.getCut() != null) { final OrientedPoint op = (OrientedPoint) node.getCut().getHyperplane(); - sup = op.getLocation().getAbscissa(); + sup = op.getLocation().getX(); node = op.isDirect() ? node.getPlus() : node.getMinus(); } return ((Boolean) node.getAttribute()) ? Double.POSITIVE_INFINITY : sup; @@ -207,7 +209,8 @@ public class IntervalsSet extends Region { * @param lower lower bound of the current convex cell * @param upper upper bound of the current convex cell */ - private void recurseList(final BSPTree node, final List list, + private void recurseList(final BSPTree node, + final List list, final double lower, final double upper) { if (node.getCut() == null) { @@ -217,12 +220,14 @@ public class IntervalsSet extends Region { } } else { final OrientedPoint op = (OrientedPoint) node.getCut().getHyperplane(); - final Point1D loc = op.getLocation(); - double x = loc.getAbscissa(); + final Vector1D loc = op.getLocation(); + double x = loc.getX(); // make sure we explore the tree in increasing order - final BSPTree low = op.isDirect() ? node.getMinus() : node.getPlus(); - final BSPTree high = op.isDirect() ? node.getPlus() : node.getMinus(); + final BSPTree low = + op.isDirect() ? node.getMinus() : node.getPlus(); + final BSPTree high = + op.isDirect() ? node.getPlus() : node.getMinus(); recurseList(low, list, lower, x); if ((checkPoint(low, loc) == Location.INSIDE) && diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/oned/OrientedPoint.java b/src/main/java/org/apache/commons/math/geometry/euclidean/oned/OrientedPoint.java index 5ffa056a4..e642dd5d2 100644 --- a/src/main/java/org/apache/commons/math/geometry/euclidean/oned/OrientedPoint.java +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/oned/OrientedPoint.java @@ -16,28 +16,22 @@ */ package org.apache.commons.math.geometry.euclidean.oned; -import org.apache.commons.math.exception.MathUnsupportedOperationException; -import org.apache.commons.math.exception.util.LocalizedFormats; -import org.apache.commons.math.geometry.partitioning.BSPTree; +import org.apache.commons.math.geometry.Vector; import org.apache.commons.math.geometry.partitioning.Hyperplane; -import org.apache.commons.math.geometry.partitioning.Point; import org.apache.commons.math.geometry.partitioning.Region; import org.apache.commons.math.geometry.partitioning.SubHyperplane; -import org.apache.commons.math.geometry.partitioning.SubSpace; /** This class represents a 1D oriented hyperplane. *

An hyperplane in 1D is a simple point, its orientation being a * boolean.

*

Instances of this class are guaranteed to be immutable.

- * @version $Revision$ $Date$ + * @version $Id:$ + * @since 3.0 */ -public class OrientedPoint implements Hyperplane { +public class OrientedPoint implements Hyperplane { - /** Dummy region returned by the {@link #wholeHyperplane} method. */ - private static final Region DUMMY_REGION = new DummyRegion(); - - /** Point location. */ - private Point1D location; + /** Vector location. */ + private Vector1D location; /** Orientation. */ private boolean direct; @@ -45,9 +39,9 @@ public class OrientedPoint implements Hyperplane { /** Simple constructor. * @param location location of the hyperplane * @param direct if true, the plus side of the hyperplane is towards - * abscissae greater than {@code location} + * abscissas greater than {@code location} */ - public OrientedPoint(final Point1D location, final boolean direct) { + public OrientedPoint(final Vector1D location, final boolean direct) { this.location = location; this.direct = direct; } @@ -57,62 +51,16 @@ public class OrientedPoint implements Hyperplane { * the instance.

* @return the instance itself */ - public Hyperplane copySelf() { + public OrientedPoint copySelf() { return this; } - /** Get the offset (oriented distance) of a point to the hyperplane. - * @param point point to check - * @return offset of the point - */ - public double getOffset(final Point point) { - final double delta = ((Point1D) point).getAbscissa() - location.getAbscissa(); + /** {@inheritDoc} */ + public double getOffset(final Vector point) { + final double delta = ((Vector1D) point).getX() - location.getX(); return direct ? delta : -delta; } - /** Transform a space point into a sub-space point. - *

Since this class represent zero dimension spaces which does - * not have lower dimension sub-spaces, this method cannot be - * supported here. It always throws a {@code RuntimeException} - * when called.

- * @param point n-dimension point of the space - * @return (n-1)-dimension point of the sub-space corresponding to - * the specified space point - * @see #toSpace - */ - public Point toSubSpace(final Point point) { - throw new MathUnsupportedOperationException(LocalizedFormats.NOT_SUPPORTED_IN_DIMENSION_N, 1); - } - - /** Transform a sub-space point into a space point. - *

Since this class represent zero dimension spaces which does - * not have lower dimension sub-spaces, this method cannot be - * supported here. It always throws a {@code RuntimeException} - * when called.

- * @param point (n-1)-dimension point of the sub-space - * @return n-dimension point of the space corresponding to the - * specified sub-space point - * @see #toSubSpace - */ - public Point toSpace(final Point point) { - throw new MathUnsupportedOperationException(LocalizedFormats.NOT_SUPPORTED_IN_DIMENSION_N, 1); - } - - /** Build the sub-space shared by the instance and another hyperplane. - *

Since this class represent zero dimension spaces which does - * not have lower dimension sub-spaces, this method cannot be - * supported here. It always throws a {@code RuntimeException} - * when called.

- * @param other other sub-space (must have the same dimension as the - * instance) - * @return a sub-space at the intersection of the instance and the - * other sub-space (it has a dimension one unit less than the - * instance) - */ - public SubSpace intersection(final Hyperplane other) { - throw new MathUnsupportedOperationException(LocalizedFormats.NOT_SUPPORTED_IN_DIMENSION_N, 1); - } - /** Build a region covering the whole hyperplane. *

Since this class represent zero dimension spaces which does * not have lower dimension sub-spaces, this method returns a dummy @@ -122,15 +70,15 @@ public class OrientedPoint implements Hyperplane { * properly, it should not be used otherwise.

* @return a dummy region */ - public Region wholeHyperplane() { - return DUMMY_REGION; + public SubOrientedPoint wholeHyperplane() { + return new SubOrientedPoint(this, null); } /** Build a region covering the whole space. * @return a region containing the instance (really an {@link * IntervalsSet IntervalsSet} instance) */ - public Region wholeSpace() { + public IntervalsSet wholeSpace() { return new IntervalsSet(); } @@ -147,40 +95,14 @@ public class OrientedPoint implements Hyperplane { * @return true if the instance and the other hyperplane have * the same orientation */ - public boolean sameOrientationAs(final Hyperplane other) { + public boolean sameOrientationAs(final Hyperplane other) { return !(direct ^ ((OrientedPoint) other).direct); } - /** Compute the relative position of a sub-hyperplane with respect - * to the instance. - * @param sub sub-hyperplane to check - * @return one of {@link org.apache.commons.math.geometry.partitioning.Hyperplane.Side#PLUS PLUS}, - * {@link org.apache.commons.math.geometry.partitioning.Hyperplane.Side#MINUS MINUS} - * or {@link org.apache.commons.math.geometry.partitioning.Hyperplane.Side#HYPER HYPER} - * (in dimension 1, this method never returns {@link - * org.apache.commons.math.geometry.partitioning.Hyperplane.Side#BOTH BOTH}) - * - */ - public Side side(final SubHyperplane sub) { - final double global = getOffset(((OrientedPoint) sub.getHyperplane()).location); - return (global < -1.0e-10) ? Side.MINUS : ((global > 1.0e-10) ? Side.PLUS : Side.HYPER); - } - - /** Split a sub-hyperplane in two parts by the instance. - * @param sub sub-hyperplane to split - * @return an object containing both the part of the sub-hyperplane - * on the plus side of the instance and the part of the - * sub-hyperplane on the minus side of the instance - */ - public SplitSubHyperplane split(final SubHyperplane sub) { - final double global = getOffset(((OrientedPoint) sub.getHyperplane()).location); - return (global < -1.0e-10) ? new SplitSubHyperplane(null, sub) : new SplitSubHyperplane(sub, null); - } - /** Get the hyperplane location on the real line. * @return the hyperplane location */ - public Point1D getLocation() { + public Vector1D getLocation() { return location; } @@ -198,25 +120,4 @@ public class OrientedPoint implements Hyperplane { direct = !direct; } - /** Dummy region representing the whole set of reals. */ - private static class DummyRegion extends Region { - - /** Simple constructor. - */ - public DummyRegion() { - super(); - } - - /** {@inheritDoc} */ - public Region buildNew(final BSPTree tree) { - return this; - } - - /** {@inheritDoc} */ - protected void computeGeometricalProperties() { - setSize(0); - setBarycenter(Point1D.ZERO); - } - } - } diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/oned/SubOrientedPoint.java b/src/main/java/org/apache/commons/math/geometry/euclidean/oned/SubOrientedPoint.java new file mode 100644 index 000000000..9432e3439 --- /dev/null +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/oned/SubOrientedPoint.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math.geometry.euclidean.oned; + +import org.apache.commons.math.geometry.partitioning.AbstractSubHyperplane; +import org.apache.commons.math.geometry.partitioning.Hyperplane; +import org.apache.commons.math.geometry.partitioning.Region; +import org.apache.commons.math.geometry.partitioning.Side; + +/** This class represents sub-hyperplane for {@link OrOrientedPoint}. + *

An hyperplane in 1D is a simple point, its orientation being a + * boolean.

+ *

Instances of this class are guaranteed to be immutable.

+ * @version $Id:$ + * @since 3.0 + */ +public class SubOrientedPoint extends AbstractSubHyperplane { + + /** Simple constructor. + * @param hyperplane underlying hyperplane + * @param remainingRegion remaining region of the hyperplane + */ + public SubOrientedPoint(final Hyperplane hyperplane, + final Region remainingRegion) { + super(hyperplane, remainingRegion); + } + + /** {@inheritDoc} */ + public double getSize() { + return 0; + } + + /** {@inheritDoc} */ + protected AbstractSubHyperplane buildNew(final Hyperplane hyperplane, + final Region remainingRegion) { + return new SubOrientedPoint(hyperplane, remainingRegion); + } + + /** {@inheritDoc} */ + public Side side(final Hyperplane hyperplane) { + final double global = hyperplane.getOffset(((OrientedPoint) getHyperplane()).getLocation()); + return (global < -1.0e-10) ? Side.MINUS : ((global > 1.0e-10) ? Side.PLUS : Side.HYPER); + } + + /** {@inheritDoc} */ + public SplitSubHyperplane split(final Hyperplane hyperplane) { + final double global = hyperplane.getOffset(((OrientedPoint) getHyperplane()).getLocation()); + return (global < -1.0e-10) ? + new SplitSubHyperplane(null, this) : + new SplitSubHyperplane(this, null); + } + +} diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/threed/Line.java b/src/main/java/org/apache/commons/math/geometry/euclidean/threed/Line.java index 9f554f484..84b725562 100644 --- a/src/main/java/org/apache/commons/math/geometry/euclidean/threed/Line.java +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/threed/Line.java @@ -16,9 +16,10 @@ */ package org.apache.commons.math.geometry.euclidean.threed; -import org.apache.commons.math.geometry.euclidean.oned.Point1D; -import org.apache.commons.math.geometry.partitioning.Point; -import org.apache.commons.math.geometry.partitioning.SubSpace; +import org.apache.commons.math.geometry.Vector; +import org.apache.commons.math.geometry.euclidean.oned.Euclidean1D; +import org.apache.commons.math.geometry.euclidean.oned.Vector1D; +import org.apache.commons.math.geometry.partitioning.Embedding; import org.apache.commons.math.util.FastMath; /** The class represent lines in a three dimensional space. @@ -30,15 +31,16 @@ import org.apache.commons.math.util.FastMath; * which is closest to the origin. Abscissa increases in the line * direction.

- * @version $Revision$ $Date$ + * @version $Id:$ + * @since 3.0 */ -public class Line implements SubSpace { +public class Line implements Embedding { /** Line direction. */ private Vector3D direction; /** Line point closest to the origin. */ - private Point3D zero; + private Vector3D zero; /** Build a line from a point and a direction. * @param p point belonging to the line (this can be any point) @@ -60,13 +62,14 @@ public class Line implements SubSpace { throw new IllegalArgumentException("null norm"); } this.direction = new Vector3D(1.0 / norm, dir); - zero = new Point3D(1.0, p, -Vector3D.dotProduct(p, this.direction), this.direction); + zero = new Vector3D(1.0, p, -Vector3D.dotProduct(p, this.direction), this.direction); } - /** Revert the line direction. + /** Get a line with reversed direction. + * @return a new instance, with reversed direction */ - public void revertSelf() { - direction = direction.negate(); + public Line revert() { + return new Line(zero, direction.negate()); } /** Get the normalized direction vector. @@ -90,21 +93,22 @@ public class Line implements SubSpace { * @param point point to check (must be a {@link Vector3D Vector3D} * instance) * @return abscissa of the point (really a - * {org.apache.commons.math.geometry.euclidean.oned.Point1D Point1D} instance) + * {org.apache.commons.math.geometry.euclidean.oned.Vector1D Vector1D} instance) */ - public Point toSubSpace(final Point point) { - final double x = Vector3D.dotProduct(((Vector3D) point).subtract(zero), direction); - return new Point1D(x); + public Vector1D toSubSpace(final Vector point) { + Vector3D p3 = (Vector3D) point; + return new Vector1D(Vector3D.dotProduct(p3.subtract(zero), direction)); } /** Get one point from the line. * @param point desired abscissa for the point (must be a - * {org.apache.commons.math.geometry.euclidean.oned.Point1D Point1D} instance) + * {org.apache.commons.math.geometry.euclidean.oned.Vector1D Vector1D} instance) * @return one point belonging to the line, at specified abscissa * (really a {@link Vector3D Vector3D} instance) */ - public Point toSpace(final Point point) { - return new Point3D(1.0, zero, ((Point1D) point).getAbscissa(), direction); + public Vector3D toSpace(final Vector point) { + Vector1D p1 = (Vector1D) point; + return new Vector3D(1.0, zero, p1.getX(), direction); } /** Check if the instance is similar to another line. diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/threed/OutlineExtractor.java b/src/main/java/org/apache/commons/math/geometry/euclidean/threed/OutlineExtractor.java index bb73e43d4..e945ab56a 100644 --- a/src/main/java/org/apache/commons/math/geometry/euclidean/threed/OutlineExtractor.java +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/threed/OutlineExtractor.java @@ -16,20 +16,24 @@ */ package org.apache.commons.math.geometry.euclidean.threed; -import org.apache.commons.math.geometry.euclidean.twod.Point2D; +import java.util.ArrayList; + +import org.apache.commons.math.geometry.euclidean.twod.Euclidean2D; import org.apache.commons.math.geometry.euclidean.twod.PolygonsSet; +import org.apache.commons.math.geometry.euclidean.twod.Vector2D; +import org.apache.commons.math.geometry.partitioning.AbstractSubHyperplane; import org.apache.commons.math.geometry.partitioning.BSPTree; import org.apache.commons.math.geometry.partitioning.BSPTreeVisitor; -import org.apache.commons.math.geometry.partitioning.Region; +import org.apache.commons.math.geometry.partitioning.BoundaryAttribute; +import org.apache.commons.math.geometry.partitioning.RegionFactory; import org.apache.commons.math.geometry.partitioning.SubHyperplane; import org.apache.commons.math.util.FastMath; -import java.util.ArrayList; - /** Extractor for {@link PolygonsSet polyhedrons sets} outlines. *

This class extracts the 2D outlines from {{@link PolygonsSet * polyhedrons sets} in a specified projection plane.

- * @version $Revision$ $Date$ + * @version $Id:$ + * @since 3.0 */ public class OutlineExtractor { @@ -56,7 +60,7 @@ public class OutlineExtractor { * @param polyhedronsSet polyhedrons set whose outline must be extracted * @return an outline, as an array of loops. */ - public Point2D[][] getOutline(final PolyhedronsSet polyhedronsSet) { + public Vector2D[][] getOutline(final PolyhedronsSet polyhedronsSet) { // project all boundary facets into one polygons set final BoundaryProjector projector = new BoundaryProjector(); @@ -64,9 +68,9 @@ public class OutlineExtractor { final PolygonsSet projected = projector.getProjected(); // Remove the spurious intermediate vertices from the outline - final Point2D[][] outline = projected.getVertices(); + final Vector2D[][] outline = projected.getVertices(); for (int i = 0; i < outline.length; ++i) { - final Point2D[] rawLoop = outline[i]; + final Vector2D[] rawLoop = outline[i]; int end = rawLoop.length; int j = 0; while (j < end) { @@ -83,7 +87,7 @@ public class OutlineExtractor { } if (end != rawLoop.length) { // resize the array - outline[i] = new Point2D[end]; + outline[i] = new Vector2D[end]; System.arraycopy(rawLoop, 0, outline[i], 0, end); } } @@ -100,14 +104,14 @@ public class OutlineExtractor { * @param i index of the point to check (must be between 0 and n-1) * @return true if the point is exactly between its neighbours */ - private boolean pointIsBetween(final Point2D[] loop, final int n, final int i) { - final Point2D previous = loop[(i + n - 1) % n]; - final Point2D current = loop[i]; - final Point2D next = loop[(i + 1) % n]; - final double dx1 = current.x - previous.x; - final double dy1 = current.y - previous.y; - final double dx2 = next.x - current.x; - final double dy2 = next.y - current.y; + private boolean pointIsBetween(final Vector2D[] loop, final int n, final int i) { + final Vector2D previous = loop[(i + n - 1) % n]; + final Vector2D current = loop[i]; + final Vector2D next = loop[(i + 1) % n]; + final double dx1 = current.getX() - previous.getX(); + final double dy1 = current.getY() - previous.getY(); + final double dx2 = next.getX() - current.getX(); + final double dy2 = next.getY() - current.getY(); final double cross = dx1 * dy2 - dx2 * dy1; final double dot = dx1 * dx2 + dy1 * dy2; final double d1d2 = FastMath.sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2)); @@ -115,7 +119,7 @@ public class OutlineExtractor { } /** Visitor projecting the boundary facets on a plane. */ - private class BoundaryProjector implements BSPTreeVisitor { + private class BoundaryProjector implements BSPTreeVisitor { /** Projection of the polyhedrons set on the plane. */ private PolygonsSet projected; @@ -123,18 +127,19 @@ public class OutlineExtractor { /** Simple constructor. */ public BoundaryProjector() { - projected = new PolygonsSet(new BSPTree(Boolean.FALSE)); + projected = new PolygonsSet(new BSPTree(Boolean.FALSE)); } /** {@inheritDoc} */ - public Order visitOrder(final BSPTree node) { + public Order visitOrder(final BSPTree node) { return Order.MINUS_SUB_PLUS; } /** {@inheritDoc} */ - public void visitInternalNode(final BSPTree node) { - final Region.BoundaryAttribute attribute = - (Region.BoundaryAttribute) node.getAttribute(); + public void visitInternalNode(final BSPTree node) { + @SuppressWarnings("unchecked") + final BoundaryAttribute attribute = + (BoundaryAttribute) node.getAttribute(); if (attribute.getPlusOutside() != null) { addContribution(attribute.getPlusOutside(), false); } @@ -144,19 +149,22 @@ public class OutlineExtractor { } /** {@inheritDoc} */ - public void visitLeafNode(final BSPTree node) { + public void visitLeafNode(final BSPTree node) { } /** Add he contribution of a boundary facet. * @param facet boundary facet * @param reversed if true, the facet has the inside on its plus side */ - private void addContribution(final SubHyperplane facet, final boolean reversed) { + private void addContribution(final SubHyperplane facet, final boolean reversed) { // extract the vertices of the facet + @SuppressWarnings("unchecked") + final AbstractSubHyperplane absFacet = + (AbstractSubHyperplane) facet; final Plane plane = (Plane) facet.getHyperplane(); - Point2D[][] vertices = - ((PolygonsSet) facet.getRemainingRegion()).getVertices(); + Vector2D[][] vertices = + ((PolygonsSet) absFacet.getRemainingRegion()).getVertices(); final double scal = Vector3D.dotProduct(plane.getNormal(), w); if (FastMath.abs(scal) > 1.0e-3) { @@ -164,10 +172,10 @@ public class OutlineExtractor { if ((scal < 0) ^ reversed) { // the facet is seen from the inside, // we need to invert its boundary orientation - final Point2D[][] newVertices = new Point2D[vertices.length][]; + final Vector2D[][] newVertices = new Vector2D[vertices.length][]; for (int i = 0; i < vertices.length; ++i) { - final Point2D[] loop = vertices[i]; - final Point2D[] newLoop = new Point2D[loop.length]; + final Vector2D[] loop = vertices[i]; + final Vector2D[] newLoop = new Vector2D[loop.length]; if (loop[0] == null) { newLoop[0] = null; for (int j = 1; j < loop.length; ++j) { @@ -187,22 +195,22 @@ public class OutlineExtractor { } // compute the projection of the facet in the outline plane - final ArrayList edges = new ArrayList(); - for (Point2D[] loop : vertices) { + final ArrayList> edges = new ArrayList>(); + for (Vector2D[] loop : vertices) { final boolean closed = loop[0] != null; int previous = closed ? (loop.length - 1) : 1; Vector3D previous3D = (Vector3D) plane.toSpace(loop[previous]); int current = (previous + 1) % loop.length; - Point2D pPoint = new Point2D(Vector3D.dotProduct(previous3D, u), + Vector2D pPoint = new Vector2D(Vector3D.dotProduct(previous3D, u), Vector3D.dotProduct(previous3D, v)); while (current < loop.length) { final Vector3D current3D = (Vector3D) plane.toSpace(loop[current]); - final Point2D cPoint = new Point2D(Vector3D.dotProduct(current3D, u), + final Vector2D cPoint = new Vector2D(Vector3D.dotProduct(current3D, u), Vector3D.dotProduct(current3D, v)); final org.apache.commons.math.geometry.euclidean.twod.Line line = new org.apache.commons.math.geometry.euclidean.twod.Line(pPoint, cPoint); - SubHyperplane edge = new SubHyperplane(line); + SubHyperplane edge = line.wholeHyperplane(); if (closed || (previous != 1)) { // the previous point is a real vertex @@ -210,7 +218,7 @@ public class OutlineExtractor { final double angle = line.getAngle() + 0.5 * FastMath.PI; final org.apache.commons.math.geometry.euclidean.twod.Line l = new org.apache.commons.math.geometry.euclidean.twod.Line(pPoint, angle); - edge = l.split(edge).getPlus(); + edge = edge.split(l).getPlus(); } if (closed || (current != (loop.length - 1))) { @@ -219,7 +227,7 @@ public class OutlineExtractor { final double angle = line.getAngle() + 0.5 * FastMath.PI; final org.apache.commons.math.geometry.euclidean.twod.Line l = new org.apache.commons.math.geometry.euclidean.twod.Line(cPoint, angle); - edge = l.split(edge).getMinus(); + edge = edge.split(l).getMinus(); } edges.add(edge); @@ -233,7 +241,7 @@ public class OutlineExtractor { final PolygonsSet projectedFacet = new PolygonsSet(edges); // add the contribution of the facet to the global outline - projected = (PolygonsSet) Region.union(projected, projectedFacet); + projected = (PolygonsSet) new RegionFactory().union(projected, projectedFacet); } } diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/threed/Plane.java b/src/main/java/org/apache/commons/math/geometry/euclidean/threed/Plane.java index 61bbe53de..79e3f23b5 100644 --- a/src/main/java/org/apache/commons/math/geometry/euclidean/threed/Plane.java +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/threed/Plane.java @@ -16,27 +16,26 @@ */ package org.apache.commons.math.geometry.euclidean.threed; -import org.apache.commons.math.geometry.euclidean.oned.Point1D; -import org.apache.commons.math.geometry.euclidean.twod.Point2D; +import org.apache.commons.math.geometry.Vector; +import org.apache.commons.math.geometry.euclidean.oned.Vector1D; +import org.apache.commons.math.geometry.euclidean.twod.Euclidean2D; +import org.apache.commons.math.geometry.euclidean.twod.Vector2D; import org.apache.commons.math.geometry.euclidean.twod.PolygonsSet; -import org.apache.commons.math.geometry.partitioning.BSPTree; +import org.apache.commons.math.geometry.partitioning.Embedding; import org.apache.commons.math.geometry.partitioning.Hyperplane; -import org.apache.commons.math.geometry.partitioning.Point; -import org.apache.commons.math.geometry.partitioning.Region; -import org.apache.commons.math.geometry.partitioning.SubHyperplane; -import org.apache.commons.math.geometry.partitioning.SubSpace; import org.apache.commons.math.util.FastMath; /** The class represent planes in a three dimensional space. - * @version $Revision$ $Date$ + * @version $Id:$ + * @since 3.0 */ -public class Plane implements Hyperplane { +public class Plane implements Hyperplane, Embedding { /** Offset of the origin with respect to the plane. */ private double originOffset; /** Origin of the plane frame. */ - private Point3D origin; + private Vector3D origin; /** First vector of the plane frame (in plane). */ private Vector3D u; @@ -100,7 +99,7 @@ public class Plane implements Hyperplane { * shared (except for immutable objects).

* @return a new hyperplane, copy of the instance */ - public Hyperplane copySelf() { + public Plane copySelf() { return new Plane(this); } @@ -143,7 +142,7 @@ public class Plane implements Hyperplane { /** Reset the plane frame. */ private void setFrame() { - origin = new Point3D(-originOffset, w); + origin = new Vector3D(-originOffset, w); u = w.orthogonal(); v = Vector3D.crossProduct(w, u); } @@ -154,7 +153,7 @@ public class Plane implements Hyperplane { * @return the origin point of the plane frame (point closest to the * 3D-space origin) */ - public Point3D getOrigin() { + public Vector3D getOrigin() { return origin; } @@ -217,24 +216,24 @@ public class Plane implements Hyperplane { * @param point point of the space (must be a {@link Vector3D * Vector3D} instance) * @return in-plane point (really a {@link - * org.apache.commons.math.geometry.euclidean.twod.Point2D Point2D} instance) + * org.apache.commons.math.geometry.euclidean.twod.Vector2D Vector2D} instance) * @see #toSpace */ - public Point toSubSpace(final Point point) { + public Vector2D toSubSpace(final Vector point) { final Vector3D p3D = (Vector3D) point; - return new Point2D(Vector3D.dotProduct(p3D, u), + return new Vector2D(Vector3D.dotProduct(p3D, u), Vector3D.dotProduct(p3D, v)); } /** Transform an in-plane point into a 3D space point. * @param point in-plane point (must be a {@link - * org.apache.commons.math.geometry.euclidean.twod.Point2D Point2D} instance) + * org.apache.commons.math.geometry.euclidean.twod.Vector2D Vector2D} instance) * @return 3D space point (really a {@link Vector3D Vector3D} instance) * @see #toSubSpace */ - public Point toSpace(final Point point) { - final Point2D p2D = (Point2D) point; - return new Point3D(p2D.x, u, p2D.y, v, -originOffset, w); + public Vector3D toSpace(final Vector point) { + final Vector2D p2D = (Vector2D) point; + return new Vector3D(p2D.getX(), u, p2D.getY(), v, -originOffset, w); } /** Get one point from the 3D-space. @@ -244,8 +243,8 @@ public class Plane implements Hyperplane { * @return one point in the 3D-space, with given coordinates and offset * relative to the plane */ - public Vector3D getPointAt(final Point2D inPlane, final double offset) { - return new Vector3D(inPlane.x, u, inPlane.y, v, offset - originOffset, w); + public Vector3D getPointAt(final Vector2D inPlane, final double offset) { + return new Vector3D(inPlane.getX(), u, inPlane.getY(), v, offset - originOffset, w); } /** Check if the instance is similar to another plane. @@ -303,15 +302,15 @@ public class Plane implements Hyperplane { * @return intersection point between between the line and the * instance (null if the line is parallel to the instance) */ - public Point3D intersection(final Line line) { + public Vector3D intersection(final Line line) { final Vector3D direction = line.getDirection(); final double dot = Vector3D.dotProduct(w, direction); if (FastMath.abs(dot) < 1.0e-10) { return null; } - final Vector3D point = (Vector3D) line.toSpace(Point1D.ZERO); + final Vector3D point = (Vector3D) line.toSpace(Vector1D.ZERO); final double k = -(originOffset + Vector3D.dotProduct(w, point)) / dot; - return new Point3D(1.0, point, k, direction); + return new Vector3D(1.0, point, k, direction); } /** Build the line shared by the instance and another plane. @@ -319,13 +318,12 @@ public class Plane implements Hyperplane { * @return line at the intersection of the instance and the * other plane (really a {@link Line Line} instance) */ - public SubSpace intersection(final Hyperplane other) { - final Plane otherP = (Plane) other; - final Vector3D direction = Vector3D.crossProduct(w, otherP.w); + public Line intersection(final Plane other) { + final Vector3D direction = Vector3D.crossProduct(w, other.w); if (direction.getNorm() < 1.0e-10) { return null; } - return new Line(intersection(this, otherP, new Plane(direction)), + return new Line(intersection(this, other, new Plane(direction)), direction); } @@ -374,15 +372,15 @@ public class Plane implements Hyperplane { /** Build a region covering the whole hyperplane. * @return a region covering the whole hyperplane */ - public Region wholeHyperplane() { - return new PolygonsSet(); + public SubPlane wholeHyperplane() { + return new SubPlane(this, new PolygonsSet()); } /** Build a region covering the whole space. * @return a region containing the instance (really a {@link * PolyhedronsSet PolyhedronsSet} instance) */ - public Region wholeSpace() { + public PolyhedronsSet wholeSpace() { return new PolyhedronsSet(); } @@ -390,7 +388,7 @@ public class Plane implements Hyperplane { * @param p point to check * @return true if p belongs to the plane */ - public boolean contains(final Point3D p) { + public boolean contains(final Vector3D p) { return FastMath.abs(getOffset(p)) < 1.0e-10; } @@ -416,7 +414,7 @@ public class Plane implements Hyperplane { * @param point point to check * @return offset of the point */ - public double getOffset(final Point point) { + public double getOffset(final Vector point) { return Vector3D.dotProduct((Vector3D) point, w) + originOffset; } @@ -425,102 +423,8 @@ public class Plane implements Hyperplane { * @return true if the instance and the other hyperplane have * the same orientation */ - public boolean sameOrientationAs(final Hyperplane other) { + public boolean sameOrientationAs(final Hyperplane other) { return Vector3D.dotProduct(((Plane) other).w, w) > 0.0; } - /** Compute the relative position of a sub-hyperplane with respect - * to the instance. - * @param sub sub-hyperplane to check - * @return one of {@link org.apache.commons.math.geometry.partitioning.Hyperplane.Side#PLUS PLUS}, - * {@link org.apache.commons.math.geometry.partitioning.Hyperplane.Side#MINUS MINUS}, - * {@link org.apache.commons.math.geometry.partitioning.Hyperplane.Side#BOTH BOTH}, - * {@link org.apache.commons.math.geometry.partitioning.Hyperplane.Side#HYPER HYPER} - */ - public Side side(final SubHyperplane sub) { - - final Plane otherPlane = (Plane) sub.getHyperplane(); - final Line inter = (Line) intersection(otherPlane); - - if (inter == null) { - // the hyperplanes are parallel, - // any point can be used to check their relative position - final double global = getOffset(otherPlane); - return (global < -1.0e-10) ? Side.MINUS : ((global > 1.0e-10) ? Side.PLUS : Side.HYPER); - } - - // create a 2D line in the otherPlane canonical 2D frame such that: - // - the line is the crossing line of the two planes in 3D - // - the line splits the otherPlane in two half planes with an - // orientation consistent with the orientation of the instance - // (i.e. the 3D half space on the plus side (resp. minus side) - // of the instance contains the 2D half plane on the plus side - // (resp. minus side) of the 2D line - Point2D p = (Point2D) otherPlane.toSubSpace(inter.toSpace(Point1D.ZERO)); - Point2D q = (Point2D) otherPlane.toSubSpace(inter.toSpace(Point1D.ONE)); - if (Vector3D.dotProduct(Vector3D.crossProduct(inter.getDirection(), - otherPlane.getNormal()), - w) < 0) { - final Point2D tmp = p; - p = q; - q = tmp; - } - final Hyperplane line2D = new org.apache.commons.math.geometry.euclidean.twod.Line(p, q); - - // check the side on the 2D plane - return sub.getRemainingRegion().side(line2D); - - } - - /** Split a sub-hyperplane in two parts by the instance. - * @param sub sub-hyperplane to split - * @return an object containing both the part of the sub-hyperplane - * on the plus side of the instance and the part of the - * sub-hyperplane on the minus side of the instance - */ - public SplitSubHyperplane split(final SubHyperplane sub) { - - final Plane otherPlane = (Plane) sub.getHyperplane(); - final Line inter = (Line) intersection(otherPlane); - - if (inter == null) { - // the hyperplanes are parallel - final double global = getOffset(otherPlane); - return (global < -1.0e-10) ? new SplitSubHyperplane(null, sub) : new SplitSubHyperplane(sub, null); - } - - // the hyperplanes do intersect - Point2D p = (Point2D) otherPlane.toSubSpace(inter.toSpace(Point1D.ZERO)); - Point2D q = (Point2D) otherPlane.toSubSpace(inter.toSpace(Point1D.ONE)); - if (Vector3D.dotProduct(Vector3D.crossProduct(inter.getDirection(), - otherPlane.getNormal()), - w) < 0) { - final Point2D tmp = p; - p = q; - q = tmp; - } - final SubHyperplane l2DMinus = - new SubHyperplane(new org.apache.commons.math.geometry.euclidean.twod.Line(p, q)); - final SubHyperplane l2DPlus = - new SubHyperplane(new org.apache.commons.math.geometry.euclidean.twod.Line(q, p)); - - final BSPTree splitTree = - sub.getRemainingRegion().getTree(false).split(l2DMinus); - final BSPTree plusTree = Region.isEmpty(splitTree.getPlus()) ? - new BSPTree(Boolean.FALSE) : - new BSPTree(l2DPlus, new BSPTree(Boolean.FALSE), - splitTree.getPlus(), null); - - final BSPTree minusTree = Region.isEmpty(splitTree.getMinus()) ? - new BSPTree(Boolean.FALSE) : - new BSPTree(l2DMinus, new BSPTree(Boolean.FALSE), - splitTree.getMinus(), null); - - return new SplitSubHyperplane(new SubHyperplane(otherPlane.copySelf(), - new PolygonsSet(plusTree)), - new SubHyperplane(otherPlane.copySelf(), - new PolygonsSet(minusTree))); - - } - } diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/threed/PolyhedronsSet.java b/src/main/java/org/apache/commons/math/geometry/euclidean/threed/PolyhedronsSet.java index 33664b655..e587d7949 100644 --- a/src/main/java/org/apache/commons/math/geometry/euclidean/threed/PolyhedronsSet.java +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/threed/PolyhedronsSet.java @@ -17,23 +17,29 @@ package org.apache.commons.math.geometry.euclidean.threed; import java.awt.geom.AffineTransform; -import java.util.Arrays; import java.util.Collection; -import org.apache.commons.math.geometry.euclidean.twod.Point2D; +import org.apache.commons.math.geometry.Vector; +import org.apache.commons.math.geometry.euclidean.oned.Euclidean1D; +import org.apache.commons.math.geometry.euclidean.twod.Euclidean2D; +import org.apache.commons.math.geometry.euclidean.twod.SubLine; +import org.apache.commons.math.geometry.euclidean.twod.Vector2D; import org.apache.commons.math.geometry.partitioning.BSPTree; import org.apache.commons.math.geometry.partitioning.BSPTreeVisitor; +import org.apache.commons.math.geometry.partitioning.BoundaryAttribute; import org.apache.commons.math.geometry.partitioning.Hyperplane; -import org.apache.commons.math.geometry.partitioning.Point; import org.apache.commons.math.geometry.partitioning.Region; +import org.apache.commons.math.geometry.partitioning.RegionFactory; import org.apache.commons.math.geometry.partitioning.SubHyperplane; import org.apache.commons.math.geometry.partitioning.Transform; +import org.apache.commons.math.geometry.partitioning.AbstractRegion; import org.apache.commons.math.util.FastMath; /** This class represents a 3D region: a set of polyhedrons. - * @version $Revision$ $Date$ + * @version $Id:$ + * @since 3.0 */ -public class PolyhedronsSet extends Region { +public class PolyhedronsSet extends AbstractRegion { /** Build a polyhedrons set representing the whole real line. */ @@ -50,7 +56,7 @@ public class PolyhedronsSet extends Region { * {@code Boolean.TRUE} and {@code Boolean.FALSE}

* @param tree inside/outside BSP tree representing the region */ - public PolyhedronsSet(final BSPTree tree) { + public PolyhedronsSet(final BSPTree tree) { super(tree); } @@ -61,19 +67,19 @@ public class PolyhedronsSet extends Region { * its plus side.

*

The boundary elements can be in any order, and can form * several non-connected sets (like for example polyhedrons with holes - * or a set of disjoints polyhedrons considered as a whole). In + * or a set of disjoint polyhedrons considered as a whole). In * fact, the elements do not even need to be connected together * (their topological connections are not used here). However, if the * boundary does not really separate an inside open from an outside * open (open having here its topological meaning), then subsequent - * calls to the {@link Region#checkPoint(Point) checkPoint} method will + * calls to the {@link Region#checkPoint(Vector) checkPoint} method will * not be meaningful anymore.

*

If the boundary is empty, the region will represent the whole * space.

* @param boundary collection of boundary elements, as a * collection of {@link SubHyperplane SubHyperplane} objects */ - public PolyhedronsSet(final Collection boundary) { + public PolyhedronsSet(final Collection> boundary) { super(boundary); } @@ -85,21 +91,21 @@ public class PolyhedronsSet extends Region { * @param zMin low bound along the z direction * @param zMax high bound along the z direction */ + @SuppressWarnings("unchecked") public PolyhedronsSet(final double xMin, final double xMax, final double yMin, final double yMax, final double zMin, final double zMax) { - this(buildConvex(Arrays.asList(new Hyperplane[] { + this(new RegionFactory().buildConvex( new Plane(new Vector3D(xMin, 0, 0), Vector3D.MINUS_I), new Plane(new Vector3D(xMax, 0, 0), Vector3D.PLUS_I), new Plane(new Vector3D(0, yMin, 0), Vector3D.MINUS_J), new Plane(new Vector3D(0, yMax, 0), Vector3D.PLUS_J), new Plane(new Vector3D(0, 0, zMin), Vector3D.MINUS_K), - new Plane(new Vector3D(0, 0, zMax), Vector3D.PLUS_K) - })).getTree(false)); + new Plane(new Vector3D(0, 0, zMax), Vector3D.PLUS_K)).getTree(false)); } /** {@inheritDoc} */ - public Region buildNew(final BSPTree tree) { + public PolyhedronsSet buildNew(final BSPTree tree) { return new PolyhedronsSet(tree); } @@ -113,32 +119,34 @@ public class PolyhedronsSet extends Region { // the polyhedrons set as a finite outside // surrounded by an infinite inside setSize(Double.POSITIVE_INFINITY); - setBarycenter(Point3D.UNDEFINED); + setBarycenter(Vector3D.NaN); } else { // the polyhedrons set is finite, apply the remaining scaling factors setSize(getSize() / 3.0); - setBarycenter(new Point3D(1.0 / (4 * getSize()), (Vector3D) getBarycenter())); + setBarycenter(new Vector3D(1.0 / (4 * getSize()), (Vector3D) getBarycenter())); } } /** Visitor computing geometrical properties. */ - private class FacetsContributionVisitor implements BSPTreeVisitor { + private class FacetsContributionVisitor implements BSPTreeVisitor { /** Simple constructor. */ public FacetsContributionVisitor() { setSize(0); - setBarycenter(new Point3D(0, 0, 0)); + setBarycenter(new Vector3D(0, 0, 0)); } /** {@inheritDoc} */ - public Order visitOrder(final BSPTree node) { + public Order visitOrder(final BSPTree node) { return Order.MINUS_SUB_PLUS; } /** {@inheritDoc} */ - public void visitInternalNode(final BSPTree node) { - final BoundaryAttribute attribute = (BoundaryAttribute) node.getAttribute(); + public void visitInternalNode(final BSPTree node) { + @SuppressWarnings("unchecked") + final BoundaryAttribute attribute = + (BoundaryAttribute) node.getAttribute(); if (attribute.getPlusOutside() != null) { addContribution(attribute.getPlusOutside(), false); } @@ -148,32 +156,32 @@ public class PolyhedronsSet extends Region { } /** {@inheritDoc} */ - public void visitLeafNode(final BSPTree node) { + public void visitLeafNode(final BSPTree node) { } /** Add he contribution of a boundary facet. * @param facet boundary facet * @param reversed if true, the facet has the inside on its plus side */ - private void addContribution(final SubHyperplane facet, final boolean reversed) { + private void addContribution(final SubHyperplane facet, final boolean reversed) { - final Region polygon = facet.getRemainingRegion(); + final Region polygon = ((SubPlane) facet).getRemainingRegion(); final double area = polygon.getSize(); if (Double.isInfinite(area)) { setSize(Double.POSITIVE_INFINITY); - setBarycenter(Point3D.UNDEFINED); + setBarycenter(Vector3D.NaN); } else { final Plane plane = (Plane) facet.getHyperplane(); - final Vector3D facetB = (Point3D) plane.toSpace(polygon.getBarycenter()); + final Vector3D facetB = plane.toSpace(polygon.getBarycenter()); double scaled = area * Vector3D.dotProduct(facetB, plane.getNormal()); if (reversed) { scaled = -scaled; } setSize(getSize() + scaled); - setBarycenter(new Point3D(1.0, (Point3D) getBarycenter(), scaled, facetB)); + setBarycenter(new Vector3D(1.0, (Vector3D) getBarycenter(), scaled, facetB)); } @@ -188,7 +196,7 @@ public class PolyhedronsSet extends Region { * given point, or null if the line does not intersect any * sub-hyperplaned */ - public SubHyperplane firstIntersection(final Vector3D point, final Line line) { + public SubHyperplane firstIntersection(final Vector3D point, final Line line) { return recurseFirstIntersection(getTree(true), point, line); } @@ -200,23 +208,23 @@ public class PolyhedronsSet extends Region { * given point, or null if the line does not intersect any * sub-hyperplaned */ - private SubHyperplane recurseFirstIntersection(final BSPTree node, - final Vector3D point, - final Line line) { + private SubHyperplane recurseFirstIntersection(final BSPTree node, + final Vector3D point, + final Line line) { - final SubHyperplane cut = node.getCut(); + final SubHyperplane cut = node.getCut(); if (cut == null) { return null; } - final BSPTree minus = node.getMinus(); - final BSPTree plus = node.getPlus(); - final Plane plane = (Plane) cut.getHyperplane(); + final BSPTree minus = node.getMinus(); + final BSPTree plus = node.getPlus(); + final Plane plane = (Plane) cut.getHyperplane(); // establish search order - final double offset = plane.getOffset((Point) point); + final double offset = plane.getOffset(point); final boolean in = FastMath.abs(offset) < 1.0e-10; - final BSPTree near; - final BSPTree far; + final BSPTree near; + final BSPTree far; if (offset < 0) { near = minus; far = plus; @@ -227,14 +235,14 @@ public class PolyhedronsSet extends Region { if (in) { // search in the cut hyperplane - final SubHyperplane facet = boundaryFacet(point, node); + final SubHyperplane facet = boundaryFacet(point, node); if (facet != null) { return facet; } } // search in the near branch - final SubHyperplane crossed = recurseFirstIntersection(near, point, line); + final SubHyperplane crossed = recurseFirstIntersection(near, point, line); if (crossed != null) { return crossed; } @@ -243,7 +251,7 @@ public class PolyhedronsSet extends Region { // search in the cut hyperplane final Vector3D hit3D = plane.intersection(line); if (hit3D != null) { - final SubHyperplane facet = boundaryFacet(hit3D, node); + final SubHyperplane facet = boundaryFacet(hit3D, node); if (facet != null) { return facet; } @@ -261,15 +269,18 @@ public class PolyhedronsSet extends Region { * @return the boundary facet this points belongs to (or null if it * does not belong to any boundary facet) */ - private SubHyperplane boundaryFacet(final Vector3D point, final BSPTree node) { - final Point point2D = node.getCut().getHyperplane().toSubSpace((Point) point); - final BoundaryAttribute attribute = (BoundaryAttribute) node.getAttribute(); + private SubHyperplane boundaryFacet(final Vector3D point, + final BSPTree node) { + final Vector2D point2D = ((Plane) node.getCut().getHyperplane()).toSubSpace(point); + @SuppressWarnings("unchecked") + final BoundaryAttribute attribute = + (BoundaryAttribute) node.getAttribute(); if ((attribute.getPlusOutside() != null) && - (attribute.getPlusOutside().getRemainingRegion().checkPoint(point2D) == Location.INSIDE)) { + (((SubPlane) attribute.getPlusOutside()).getRemainingRegion().checkPoint(point2D) == Location.INSIDE)) { return attribute.getPlusOutside(); } if ((attribute.getPlusInside() != null) && - (attribute.getPlusInside().getRemainingRegion().checkPoint(point2D) == Location.INSIDE)) { + (((SubPlane) attribute.getPlusInside()).getRemainingRegion().checkPoint(point2D) == Location.INSIDE)) { return attribute.getPlusInside(); } return null; @@ -286,7 +297,7 @@ public class PolyhedronsSet extends Region { } /** 3D rotation as a Transform. */ - private static class RotationTransform implements Transform { + private static class RotationTransform implements Transform { /** Center point of the rotation. */ private Vector3D center; @@ -295,10 +306,10 @@ public class PolyhedronsSet extends Region { private Rotation rotation; /** Cached original hyperplane. */ - private Hyperplane cachedOriginal; + private Plane cachedOriginal; /** Cached 2D transform valid inside the cached original hyperplane. */ - private Transform cachedTransform; + private Transform cachedTransform; /** Build a rotation transform. * @param center center point of the rotation @@ -310,40 +321,41 @@ public class PolyhedronsSet extends Region { } /** {@inheritDoc} */ - public Point apply(final Point point) { + public Vector3D apply(final Vector point) { final Vector3D delta = ((Vector3D) point).subtract(center); - return new Point3D(1.0, center, 1.0, rotation.applyTo(delta)); + return new Vector3D(1.0, center, 1.0, rotation.applyTo(delta)); } /** {@inheritDoc} */ - public Hyperplane apply(final Hyperplane hyperplane) { + public Plane apply(final Hyperplane hyperplane) { return ((Plane) hyperplane).rotate(center, rotation); } /** {@inheritDoc} */ - public SubHyperplane apply(final SubHyperplane sub, - final Hyperplane original, final Hyperplane transformed) { + public SubHyperplane apply(final SubHyperplane sub, + final Hyperplane original, + final Hyperplane transformed) { if (original != cachedOriginal) { // we have changed hyperplane, reset the in-hyperplane transform final Plane oPlane = (Plane) original; final Plane tPlane = (Plane) transformed; final Vector3D p00 = oPlane.getOrigin(); - final Vector3D p10 = (Vector3D) oPlane.toSpace(new Point2D(1.0, 0.0)); - final Vector3D p01 = (Vector3D) oPlane.toSpace(new Point2D(0.0, 1.0)); - final Point2D tP00 = (Point2D) tPlane.toSubSpace(apply((Point) p00)); - final Point2D tP10 = (Point2D) tPlane.toSubSpace(apply((Point) p10)); - final Point2D tP01 = (Point2D) tPlane.toSubSpace(apply((Point) p01)); + final Vector3D p10 = (Vector3D) oPlane.toSpace(new Vector2D(1.0, 0.0)); + final Vector3D p01 = (Vector3D) oPlane.toSpace(new Vector2D(0.0, 1.0)); + final Vector2D tP00 = (Vector2D) tPlane.toSubSpace(apply(p00)); + final Vector2D tP10 = (Vector2D) tPlane.toSubSpace(apply(p10)); + final Vector2D tP01 = (Vector2D) tPlane.toSubSpace(apply(p01)); final AffineTransform at = new AffineTransform(tP10.getX() - tP00.getX(), tP10.getY() - tP00.getY(), tP01.getX() - tP00.getX(), tP01.getY() - tP00.getY(), tP00.getX(), tP00.getY()); - cachedOriginal = original; + cachedOriginal = (Plane) original; cachedTransform = org.apache.commons.math.geometry.euclidean.twod.Line.getTransform(at); } - return sub.applyTransform(cachedTransform); + return ((SubLine) sub).applyTransform(cachedTransform); } } @@ -358,16 +370,16 @@ public class PolyhedronsSet extends Region { } /** 3D translation as a transform. */ - private static class TranslationTransform implements Transform { + private static class TranslationTransform implements Transform { /** Translation vector. */ private Vector3D translation; /** Cached original hyperplane. */ - private Hyperplane cachedOriginal; + private Plane cachedOriginal; /** Cached 2D transform valid inside the cached original hyperplane. */ - private Transform cachedTransform; + private Transform cachedTransform; /** Build a translation transform. * @param translation translation vector @@ -377,34 +389,35 @@ public class PolyhedronsSet extends Region { } /** {@inheritDoc} */ - public Point apply(final Point point) { - return new Point3D(1.0, (Vector3D) point, 1.0, translation); + public Vector3D apply(final Vector point) { + return new Vector3D(1.0, (Vector3D) point, 1.0, translation); } /** {@inheritDoc} */ - public Hyperplane apply(final Hyperplane hyperplane) { + public Plane apply(final Hyperplane hyperplane) { return ((Plane) hyperplane).translate(translation); } /** {@inheritDoc} */ - public SubHyperplane apply(final SubHyperplane sub, - final Hyperplane original, final Hyperplane transformed) { + public SubHyperplane apply(final SubHyperplane sub, + final Hyperplane original, + final Hyperplane transformed) { if (original != cachedOriginal) { // we have changed hyperplane, reset the in-hyperplane transform final Plane oPlane = (Plane) original; final Plane tPlane = (Plane) transformed; - final Point2D shift = (Point2D) tPlane.toSubSpace(apply((Point) oPlane.getOrigin())); + final Vector2D shift = (Vector2D) tPlane.toSubSpace(apply(oPlane.getOrigin())); final AffineTransform at = AffineTransform.getTranslateInstance(shift.getX(), shift.getY()); - cachedOriginal = original; + cachedOriginal = (Plane) original; cachedTransform = org.apache.commons.math.geometry.euclidean.twod.Line.getTransform(at); } - return sub.applyTransform(cachedTransform); + return ((SubLine) sub).applyTransform(cachedTransform); } diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/threed/SubPlane.java b/src/main/java/org/apache/commons/math/geometry/euclidean/threed/SubPlane.java new file mode 100644 index 000000000..0f045ff0b --- /dev/null +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/threed/SubPlane.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math.geometry.euclidean.threed; + +import org.apache.commons.math.geometry.euclidean.oned.Vector1D; +import org.apache.commons.math.geometry.euclidean.twod.Euclidean2D; +import org.apache.commons.math.geometry.euclidean.twod.Vector2D; +import org.apache.commons.math.geometry.euclidean.twod.PolygonsSet; +import org.apache.commons.math.geometry.partitioning.AbstractSubHyperplane; +import org.apache.commons.math.geometry.partitioning.BSPTree; +import org.apache.commons.math.geometry.partitioning.Hyperplane; +import org.apache.commons.math.geometry.partitioning.Region; +import org.apache.commons.math.geometry.partitioning.Side; +import org.apache.commons.math.geometry.partitioning.SubHyperplane; + +/** This class represents a sub-hyperplane for {@link Plane}. + * @version $Id:$ + * @since 3.0 + */ +public class SubPlane extends AbstractSubHyperplane { + + /** Simple constructor. + * @param hyperplane underlying hyperplane + * @param remainingRegion remaining region of the hyperplane + */ + public SubPlane(final Hyperplane hyperplane, + final Region remainingRegion) { + super(hyperplane, remainingRegion); + } + + /** {@inheritDoc} */ + protected AbstractSubHyperplane buildNew(final Hyperplane hyperplane, + final Region remainingRegion) { + return new SubPlane(hyperplane, remainingRegion); + } + + /** {@inheritDoc} */ + public Side side(Hyperplane hyperplane) { + + final Plane otherPlane = (Plane) hyperplane; + final Plane thisPlane = (Plane) getHyperplane(); + final Line inter = (Line) otherPlane.intersection(thisPlane); + + if (inter == null) { + // the hyperplanes are parallel, + // any point can be used to check their relative position + final double global = otherPlane.getOffset(thisPlane); + return (global < -1.0e-10) ? Side.MINUS : ((global > 1.0e-10) ? Side.PLUS : Side.HYPER); + } + + // create a 2D line in the otherPlane canonical 2D frame such that: + // - the line is the crossing line of the two planes in 3D + // - the line splits the otherPlane in two half planes with an + // orientation consistent with the orientation of the instance + // (i.e. the 3D half space on the plus side (resp. minus side) + // of the instance contains the 2D half plane on the plus side + // (resp. minus side) of the 2D line + Vector2D p = thisPlane.toSubSpace(inter.toSpace(Vector1D.ZERO)); + Vector2D q = thisPlane.toSubSpace(inter.toSpace(Vector1D.ONE)); + Vector3D crossP = Vector3D.crossProduct(inter.getDirection(), thisPlane.getNormal()); + if (Vector3D.dotProduct(crossP, otherPlane.getNormal()) < 0) { + final Vector2D tmp = p; + p = q; + q = tmp; + } + final org.apache.commons.math.geometry.euclidean.twod.Line line2D = + new org.apache.commons.math.geometry.euclidean.twod.Line(p, q); + + // check the side on the 2D plane + return getRemainingRegion().side(line2D); + + } + + /** Split the instance in two parts by an hyperplane. + * @param hyperplane splitting hyperplane + * @return an object containing both the part of the instance + * on the plus side of the instance and the part of the + * instance on the minus side of the instance + */ + public SplitSubHyperplane split(Hyperplane hyperplane) { + + final Plane otherPlane = (Plane) hyperplane; + final Plane thisPlane = (Plane) getHyperplane(); + final Line inter = (Line) otherPlane.intersection(thisPlane); + + if (inter == null) { + // the hyperplanes are parallel + final double global = otherPlane.getOffset(thisPlane); + return (global < -1.0e-10) ? + new SplitSubHyperplane(null, this) : + new SplitSubHyperplane(this, null); + } + + // the hyperplanes do intersect + Vector2D p = thisPlane.toSubSpace(inter.toSpace(Vector1D.ZERO)); + Vector2D q = thisPlane.toSubSpace(inter.toSpace(Vector1D.ONE)); + Vector3D crossP = Vector3D.crossProduct(inter.getDirection(), thisPlane.getNormal()); + if (Vector3D.dotProduct(crossP, otherPlane.getNormal()) < 0) { + final Vector2D tmp = p; + p = q; + q = tmp; + } + final SubHyperplane l2DMinus = + new org.apache.commons.math.geometry.euclidean.twod.Line(p, q).wholeHyperplane(); + final SubHyperplane l2DPlus = + new org.apache.commons.math.geometry.euclidean.twod.Line(q, p).wholeHyperplane(); + + final BSPTree splitTree = getRemainingRegion().getTree(false).split(l2DMinus); + final BSPTree plusTree = getRemainingRegion().isEmpty(splitTree.getPlus()) ? + new BSPTree(Boolean.FALSE) : + new BSPTree(l2DPlus, new BSPTree(Boolean.FALSE), + splitTree.getPlus(), null); + + final BSPTree minusTree = getRemainingRegion().isEmpty(splitTree.getMinus()) ? + new BSPTree(Boolean.FALSE) : + new BSPTree(l2DMinus, new BSPTree(Boolean.FALSE), + splitTree.getMinus(), null); + + return new SplitSubHyperplane(new SubPlane(thisPlane.copySelf(), new PolygonsSet(plusTree)), + new SubPlane(thisPlane.copySelf(), new PolygonsSet(minusTree))); + + } + +} diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/twod/Line.java b/src/main/java/org/apache/commons/math/geometry/euclidean/twod/Line.java index c2c500373..dd53deb43 100644 --- a/src/main/java/org/apache/commons/math/geometry/euclidean/twod/Line.java +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/twod/Line.java @@ -20,15 +20,14 @@ import java.awt.geom.AffineTransform; import org.apache.commons.math.exception.MathIllegalArgumentException; import org.apache.commons.math.exception.util.LocalizedFormats; +import org.apache.commons.math.geometry.Vector; +import org.apache.commons.math.geometry.euclidean.oned.Euclidean1D; import org.apache.commons.math.geometry.euclidean.oned.IntervalsSet; import org.apache.commons.math.geometry.euclidean.oned.OrientedPoint; -import org.apache.commons.math.geometry.euclidean.oned.Point1D; -import org.apache.commons.math.geometry.partitioning.BSPTree; +import org.apache.commons.math.geometry.euclidean.oned.Vector1D; +import org.apache.commons.math.geometry.partitioning.Embedding; import org.apache.commons.math.geometry.partitioning.Hyperplane; -import org.apache.commons.math.geometry.partitioning.Point; -import org.apache.commons.math.geometry.partitioning.Region; import org.apache.commons.math.geometry.partitioning.SubHyperplane; -import org.apache.commons.math.geometry.partitioning.SubSpace; import org.apache.commons.math.geometry.partitioning.Transform; import org.apache.commons.math.util.FastMath; import org.apache.commons.math.util.MathUtils; @@ -57,9 +56,10 @@ import org.apache.commons.math.util.MathUtils; * left half plane is the set of points with negative offsets and the * right half plane is the set of points with positive offsets.

- * @version $Revision$ $Date$ + * @version $Id:$ + * @since 3.0 */ -public class Line implements Hyperplane { +public class Line implements Hyperplane, Embedding { /** Angle with respect to the abscissa axis. */ private double angle; @@ -78,7 +78,7 @@ public class Line implements Hyperplane { * @param p1 first point * @param p2 second point */ - public Line(final Point2D p1, final Point2D p2) { + public Line(final Vector2D p1, final Vector2D p2) { reset(p1, p2); } @@ -86,7 +86,7 @@ public class Line implements Hyperplane { * @param p point belonging to the line * @param angle angle of the line with respect to abscissa axis */ - public Line(final Point2D p, final double angle) { + public Line(final Vector2D p, final double angle) { reset(p, angle); } @@ -116,7 +116,7 @@ public class Line implements Hyperplane { } /** {@inheritDoc} */ - public Hyperplane copySelf() { + public Line copySelf() { return new Line(this); } @@ -125,20 +125,20 @@ public class Line implements Hyperplane { * @param p1 first point * @param p2 second point */ - public void reset(final Point2D p1, final Point2D p2) { - final double dx = p2.x - p1.x; - final double dy = p2.y - p1.y; + public void reset(final Vector2D p1, final Vector2D p2) { + final double dx = p2.getX() - p1.getX(); + final double dy = p2.getY() - p1.getY(); final double d = FastMath.hypot(dx, dy); if (d == 0.0) { angle = 0.0; cos = 1.0; sin = 0.0; - originOffset = p1.y; + originOffset = p1.getY(); } else { angle = FastMath.PI + FastMath.atan2(-dy, -dx); cos = FastMath.cos(angle); sin = FastMath.sin(angle); - originOffset = (p2.x * p1.y - p1.x * p2.y) / d; + originOffset = (p2.getX() * p1.getY() - p1.getX() * p2.getY()) / d; } } @@ -146,11 +146,11 @@ public class Line implements Hyperplane { * @param p point belonging to the line * @param alpha angle of the line with respect to abscissa axis */ - public void reset(final Point2D p, final double alpha) { + public void reset(final Vector2D p, final double alpha) { this.angle = MathUtils.normalizeAngle(alpha, FastMath.PI); cos = FastMath.cos(this.angle); sin = FastMath.sin(this.angle); - originOffset = cos * p.y - sin * p.x; + originOffset = cos * p.getY() - sin * p.getX(); } /** Revert the instance. @@ -176,57 +176,44 @@ public class Line implements Hyperplane { -cos, -sin, -originOffset); } - /** Transform a 2D space point into a line point. - * @param point 2D point (must be a {@link Point2D Point2D} - * instance) - * @return line point corresponding to the 2D point (really a {@link - * org.apache.commons.math.geometry.euclidean.oned.Point1D Point1D} instance) - * @see #toSpace - */ - public Point toSubSpace(final Point point) { - final Point2D p2D = (Point2D) point; - return new Point1D(cos * p2D.x + sin * p2D.y); + /** {@inheritDoc} */ + public Vector1D toSubSpace(final Vector point) { + Vector2D p2 = (Vector2D) point; + return new Vector1D(cos * p2.getX() + sin * p2.getY()); } - /** Get one point from the line. - * @param point desired abscissa for the point (must be a {@link - * org.apache.commons.math.geometry.euclidean.oned.Point1D Point1D} instance) - * @return line point at specified abscissa (really a {@link Point2D - * Point2D} instance) - */ - public Point toSpace(final Point point) { - final double abscissa = ((Point1D) point).getAbscissa(); - return new Point2D(abscissa * cos - originOffset * sin, + /** {@inheritDoc} */ + public Vector2D toSpace(final Vector point) { + final double abscissa = ((Vector1D) point).getX(); + return new Vector2D(abscissa * cos - originOffset * sin, abscissa * sin + originOffset * cos); } /** Get the intersection point of the instance and another line. * @param other other line * @return intersection point of the instance and the other line - * (really a {@link Point2D Point2D} instance) + * (really a {@link Vector2D Vector2D} instance) */ - public SubSpace intersection(final Hyperplane other) { + public Vector2D intersection(final Hyperplane other) { final Line otherL = (Line) other; final double d = sin * otherL.cos - otherL.sin * cos; if (FastMath.abs(d) < 1.0e-10) { return null; } - return new Point2D((cos * otherL.originOffset - otherL.cos * originOffset) / d, + return new Vector2D((cos * otherL.originOffset - otherL.cos * originOffset) / d, (sin * otherL.originOffset - otherL.sin * originOffset) / d); } - /** Build a region covering the whole hyperplane. - * @return a region covering the whole hyperplane - */ - public Region wholeHyperplane() { - return new IntervalsSet(); + /** {@inheritDoc} */ + public SubLine wholeHyperplane() { + return new SubLine(this, new IntervalsSet()); } /** Build a region covering the whole space. * @return a region containing the instance (really a {@link * PolygonsSet PolygonsSet} instance) */ - public Region wholeSpace() { + public PolygonsSet wholeSpace() { return new PolygonsSet(); } @@ -240,7 +227,8 @@ public class Line implements Hyperplane { * @param line line to check * @return offset of the line */ - public double getOffset(final Line line) { + public double getOffset(final Hyperplane hyperplane) { + Line line = (Line) hyperplane; return originOffset + ((cos * line.cos + sin * line.sin > 0) ? -line.originOffset : line.originOffset); } @@ -250,12 +238,12 @@ public class Line implements Hyperplane { * positive if the point is on the right side of the line and * negative if it is on the left side, according to its natural * orientation.

- * @param point point to check (must be a {@link Point2D Point2D} instance) + * @param point point to check (must be a {@link Vector2D Vector2D} instance) * @return offset of the point */ - public double getOffset(final Point point) { - final Point2D p2D = (Point2D) point; - return sin * p2D.x - cos * p2D.y + originOffset; + public double getOffset(final Vector point) { + Vector2D p2 = (Vector2D) point; + return sin * p2.getX() - cos * p2.getY() + originOffset; } /** Check if the instance has the same orientation as another hyperplane. @@ -271,7 +259,7 @@ public class Line implements Hyperplane { * @return true if the instance and the other hyperplane have * the same orientation */ - public boolean sameOrientationAs(final Hyperplane other) { + public boolean sameOrientationAs(final Hyperplane other) { final Line otherL = (Line) other; return (sin * otherL.sin + cos * otherL.cos) >= 0.0; } @@ -282,17 +270,17 @@ public class Line implements Hyperplane { * @return one point in the plane, with given abscissa and offset * relative to the line */ - public Point2D getPointAt(final Point1D abscissa, final double offset) { - final double x = abscissa.getAbscissa(); + public Vector2D getPointAt(final Vector1D abscissa, final double offset) { + final double x = abscissa.getX(); final double dOffset = offset - originOffset; - return new Point2D(x * cos + dOffset * sin, x * sin - dOffset * cos); + return new Vector2D(x * cos + dOffset * sin, x * sin - dOffset * cos); } /** Check if the line contains a point. * @param p point to check * @return true if p belongs to the line */ - public boolean contains(final Point2D p) { + public boolean contains(final Vector2D p) { return FastMath.abs(getOffset(p)) < 1.0e-10; } @@ -308,8 +296,8 @@ public class Line implements Hyperplane { /** Translate the line to force it passing by a point. * @param p point by which the line should pass */ - public void translateToPoint(final Point2D p) { - originOffset = cos * p.y - sin * p.x; + public void translateToPoint(final Vector2D p) { + originOffset = cos * p.getY() - sin * p.getX(); } /** Get the angle of the line. @@ -342,75 +330,6 @@ public class Line implements Hyperplane { originOffset = offset; } - /** Compute the relative position of a sub-hyperplane with respect - * to the instance. - * @param sub sub-hyperplane to check - * @return one of {@link org.apache.commons.math.geometry.partitioning.Hyperplane.Side#PLUS PLUS}, - * {@link org.apache.commons.math.geometry.partitioning.Hyperplane.Side#MINUS MINUS}, - * {@link org.apache.commons.math.geometry.partitioning.Hyperplane.Side#BOTH BOTH}, - * {@link org.apache.commons.math.geometry.partitioning.Hyperplane.Side#HYPER HYPER} - */ - public Side side(final SubHyperplane sub) { - - final Hyperplane otherHyp = sub.getHyperplane(); - final Point2D crossing = (Point2D) intersection(otherHyp); - - if (crossing == null) { - // the lines are parallel, - final double global = getOffset((Line) otherHyp); - return (global < -1.0e-10) ? Side.MINUS : ((global > 1.0e-10) ? Side.PLUS : Side.HYPER); - } - - // the lines do intersect - final boolean direct = FastMath.sin(((Line) otherHyp).angle - angle) < 0; - final Point1D x = (Point1D) otherHyp.toSubSpace(crossing); - return sub.getRemainingRegion().side(new OrientedPoint(x, direct)); - - } - - /** Split a sub-hyperplane in two parts by the instance. - * @param sub sub-hyperplane to split - * @return an object containing both the part of the sub-hyperplane - * on the plus side of the instance and the part of the - * sub-hyperplane on the minus side of the instance - */ - public SplitSubHyperplane split(final SubHyperplane sub) { - - final Line otherLine = (Line) sub.getHyperplane(); - final Point2D crossing = (Point2D) intersection(otherLine); - - if (crossing == null) { - // the lines are parallel - final double global = getOffset(otherLine); - return (global < -1.0e-10) ? - new SplitSubHyperplane(null, sub) : - new SplitSubHyperplane(sub, null); - } - - // the lines do intersect - final boolean direct = FastMath.sin(otherLine.angle - angle) < 0; - final Point1D x = (Point1D) otherLine.toSubSpace(crossing); - final SubHyperplane subPlus = new SubHyperplane(new OrientedPoint(x, !direct)); - final SubHyperplane subMinus = new SubHyperplane(new OrientedPoint(x, direct)); - - final BSPTree splitTree = - sub.getRemainingRegion().getTree(false).split(subMinus); - final BSPTree plusTree = Region.isEmpty(splitTree.getPlus()) ? - new BSPTree(Boolean.FALSE) : - new BSPTree(subPlus, new BSPTree(Boolean.FALSE), - splitTree.getPlus(), null); - final BSPTree minusTree = Region.isEmpty(splitTree.getMinus()) ? - new BSPTree(Boolean.FALSE) : - new BSPTree(subMinus, new BSPTree(Boolean.FALSE), - splitTree.getMinus(), null); - - return new SplitSubHyperplane(new SubHyperplane(otherLine.copySelf(), - new IntervalsSet(plusTree)), - new SubHyperplane(otherLine.copySelf(), - new IntervalsSet(minusTree))); - - } - /** Get a {@link org.apache.commons.math.geometry.partitioning.Transform * Transform} embedding an affine transform. * @param transform affine transform to embed (must be inversible @@ -419,12 +338,13 @@ public class Line implements Hyperplane { * apply(Hyperplane)} method would work only for some lines, and * fail for other ones) * @return a new transform that can be applied to either {@link - * Point2D Point2D}, {@link Line Line} or {@link + * Vector2D Vector2D}, {@link Line Line} or {@link * org.apache.commons.math.geometry.partitioning.SubHyperplane * SubHyperplane} instances * @exception MathIllegalArgumentException if the transform is non invertible */ - public static Transform getTransform(final AffineTransform transform) throws MathIllegalArgumentException { + public static Transform getTransform(final AffineTransform transform) + throws MathIllegalArgumentException { return new LineTransform(transform); } @@ -435,7 +355,7 @@ public class Line implements Hyperplane { * applied to a large number of lines (for example to a large * polygon)./

*/ - private static class LineTransform implements Transform { + private static class LineTransform implements Transform { // CHECKSTYLE: stop JavadocVariable check private double cXX; @@ -478,16 +398,16 @@ public class Line implements Hyperplane { } /** {@inheritDoc} */ - public Point apply(final Point point) { - final Point2D p2D = (Point2D) point; + public Vector2D apply(final Vector point) { + final Vector2D p2D = (Vector2D) point; final double x = p2D.getX(); final double y = p2D.getY(); - return new Point2D(cXX * x + cXY * y + cX1, + return new Vector2D(cXX * x + cXY * y + cX1, cYX * x + cYY * y + cY1); } /** {@inheritDoc} */ - public Hyperplane apply(final Hyperplane hyperplane) { + public Line apply(final Hyperplane hyperplane) { final Line line = (Line) hyperplane; final double rOffset = c1X * line.cos + c1Y * line.sin + c11 * line.originOffset; final double rCos = cXX * line.cos + cXY * line.sin; @@ -499,12 +419,15 @@ public class Line implements Hyperplane { } /** {@inheritDoc} */ - public SubHyperplane apply(final SubHyperplane sub, - final Hyperplane original, final Hyperplane transformed) { - final OrientedPoint op = (OrientedPoint) sub.getHyperplane(); - final Point1D newLoc = - (Point1D) transformed.toSubSpace(apply(original.toSpace(op.getLocation()))); - return new SubHyperplane(new OrientedPoint(newLoc, op.isDirect())); + public SubHyperplane apply(final SubHyperplane sub, + final Hyperplane original, + final Hyperplane transformed) { + final OrientedPoint op = (OrientedPoint) sub.getHyperplane(); + final Line originalLine = (Line) original; + final Line transformedLine = (Line) transformed; + final Vector1D newLoc = + transformedLine.toSubSpace(apply(originalLine.toSpace(op.getLocation()))); + return new OrientedPoint(newLoc, op.isDirect()).wholeHyperplane(); } } diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/twod/NestedLoops.java b/src/main/java/org/apache/commons/math/geometry/euclidean/twod/NestedLoops.java index 687a7da96..3c4169d33 100644 --- a/src/main/java/org/apache/commons/math/geometry/euclidean/twod/NestedLoops.java +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/twod/NestedLoops.java @@ -17,44 +17,43 @@ package org.apache.commons.math.geometry.euclidean.twod; import java.util.ArrayList; -import java.util.Arrays; import java.util.Iterator; import org.apache.commons.math.exception.MathIllegalArgumentException; import org.apache.commons.math.exception.util.LocalizedFormats; -import org.apache.commons.math.geometry.euclidean.oned.OrientedPoint; -import org.apache.commons.math.geometry.euclidean.oned.Point1D; -import org.apache.commons.math.geometry.partitioning.Hyperplane; +import org.apache.commons.math.geometry.euclidean.oned.IntervalsSet; import org.apache.commons.math.geometry.partitioning.Region; +import org.apache.commons.math.geometry.partitioning.RegionFactory; import org.apache.commons.math.geometry.partitioning.SubHyperplane; /** This class represent a tree of nested 2D boundary loops. - *

This class is used during Piece instances construction. - * Beams are built using the outline edges as - * representative of facets, the orientation of these facets are + *

This class is used for piecewise polygons construction. + * Polygons are built using the outline edges as + * representative of boundaries, the orientation of these lines are * meaningful. However, we want to allow the user to specify its * outline loops without having to take care of this orientation. This * class is devoted to correct mis-oriented loops.

- *

Orientation is computed assuming the piece is finite, i.e. the - * outermost loops have their exterior side facing points at infinity, - * and hence are oriented counter-clockwise. The orientation of + *

Orientation is computed assuming the piecewise polygon is finite, + * i.e. the outermost loops have their exterior side facing points at + * infinity, and hence are oriented counter-clockwise. The orientation of * internal loops is computed as the reverse of the orientation of * their immediate surrounding loop.

- * @version $Revision$ $Date$ + * @version $Id:$ + * @since 3.0 */ class NestedLoops { /** Boundary loop. */ - private Point2D[] loop; + private Vector2D[] loop; /** Surrounded loops. */ private ArrayList surrounded; /** Polygon enclosing a finite region. */ - private Region polygon; + private Region polygon; /** Indicator for original loop orientation. */ private boolean originalIsClockwise; @@ -74,7 +73,7 @@ class NestedLoops { * @param loop boundary loop (will be reversed in place if needed) * @exception MathIllegalArgumentException if an outline has an open boundary loop */ - private NestedLoops(final Point2D[] loop) throws MathIllegalArgumentException { + private NestedLoops(final Vector2D[] loop) throws MathIllegalArgumentException { if (loop[0] == null) { throw new MathIllegalArgumentException(LocalizedFormats.OUTLINE_BOUNDARY_LOOP_OPEN); @@ -84,23 +83,21 @@ class NestedLoops { surrounded = new ArrayList(); // build the polygon defined by the loop - final ArrayList edges = new ArrayList(); - Point2D current = loop[loop.length - 1]; + final ArrayList> edges = new ArrayList>(); + Vector2D current = loop[loop.length - 1]; for (int i = 0; i < loop.length; ++i) { - final Point2D previous = current; + final Vector2D previous = current; current = loop[i]; final Line line = new Line(previous, current); - final Region region = Region.buildConvex(Arrays.asList(new Hyperplane[] { - new OrientedPoint((Point1D) line.toSubSpace(previous), false), - new OrientedPoint((Point1D) line.toSubSpace(current), true) - })); - edges.add(new SubHyperplane(line, region)); + final IntervalsSet region = + new IntervalsSet(line.toSubSpace(previous).getX(), line.toSubSpace(current).getX()); + edges.add(new SubLine(line, region)); } polygon = new PolygonsSet(edges); // ensure the polygon encloses a finite region of the plane if (Double.isInfinite(polygon.getSize())) { - polygon = polygon.getComplement(); + polygon = new RegionFactory().getComplement(polygon); originalIsClockwise = false; } else { originalIsClockwise = true; @@ -113,7 +110,7 @@ class NestedLoops { * @exception MathIllegalArgumentException if an outline has crossing * boundary loops or open boundary loops */ - public void add(final Point2D[] bLoop) throws MathIllegalArgumentException { + public void add(final Vector2D[] bLoop) throws MathIllegalArgumentException { add(new NestedLoops(bLoop)); } @@ -142,8 +139,9 @@ class NestedLoops { } // we should be separate from the remaining children + RegionFactory factory = new RegionFactory(); for (final NestedLoops child : surrounded) { - if (!Region.intersection(node.polygon, child.polygon).isEmpty()) { + if (!factory.intersection(node.polygon, child.polygon).isEmpty()) { throw new MathIllegalArgumentException(LocalizedFormats.CROSSING_BOUNDARY_LOOPS); } } @@ -154,7 +152,7 @@ class NestedLoops { /** Correct the orientation of the loops contained in the tree. *

This is this method that really inverts the loops that where - * provided through the {@link #add(Point2D[]) add} method if + * provided through the {@link #add(Vector2D[]) add} method if * they are mis-oriented

*/ public void correctOrientation() { @@ -174,7 +172,7 @@ class NestedLoops { int min = -1; int max = loop.length; while (++min < --max) { - final Point2D tmp = loop[min]; + final Vector2D tmp = loop[min]; loop[min] = loop[max]; loop[max] = tmp; } diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/twod/PolygonsSet.java b/src/main/java/org/apache/commons/math/geometry/euclidean/twod/PolygonsSet.java index c8fdee73c..a84c5b068 100644 --- a/src/main/java/org/apache/commons/math/geometry/euclidean/twod/PolygonsSet.java +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/twod/PolygonsSet.java @@ -17,25 +17,27 @@ package org.apache.commons.math.geometry.euclidean.twod; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.List; -import org.apache.commons.math.geometry.euclidean.oned.Point1D; +import org.apache.commons.math.exception.MathInternalError; +import org.apache.commons.math.geometry.euclidean.oned.Euclidean1D; +import org.apache.commons.math.geometry.euclidean.oned.Vector1D; import org.apache.commons.math.geometry.partitioning.BSPTree; -import org.apache.commons.math.geometry.partitioning.Hyperplane; import org.apache.commons.math.geometry.partitioning.Region; import org.apache.commons.math.geometry.partitioning.SubHyperplane; +import org.apache.commons.math.geometry.partitioning.AbstractRegion; import org.apache.commons.math.geometry.partitioning.utilities.AVLTree; import org.apache.commons.math.util.FastMath; /** This class represents a 2D region: a set of polygons. - * @version $Revision$ $Date$ + * @version $Id:$ + * @since 3.0 */ -public class PolygonsSet extends Region { +public class PolygonsSet extends AbstractRegion { /** Vertices organized as boundary loops. */ - private Point2D[][] vertices; + private Vector2D[][] vertices; /** Build a polygons set representing the whole real line. */ @@ -52,7 +54,7 @@ public class PolygonsSet extends Region { * {@code Boolean.TRUE} and {@code Boolean.FALSE}

* @param tree inside/outside BSP tree representing the region */ - public PolygonsSet(final BSPTree tree) { + public PolygonsSet(final BSPTree tree) { super(tree); } @@ -63,7 +65,7 @@ public class PolygonsSet extends Region { * its plus side.

*

The boundary elements can be in any order, and can form * several non-connected sets (like for example polygons with holes - * or a set of disjoints polyhedrons considered as a whole). In + * or a set of disjoint polyhedrons considered as a whole). In * fact, the elements do not even need to be connected together * (their topological connections are not used here). However, if the * boundary does not really separate an inside open from an outside @@ -76,7 +78,7 @@ public class PolygonsSet extends Region { * @param boundary collection of boundary elements, as a * collection of {@link SubHyperplane SubHyperplane} objects */ - public PolygonsSet(final Collection boundary) { + public PolygonsSet(final Collection> boundary) { super(boundary); } @@ -88,7 +90,7 @@ public class PolygonsSet extends Region { */ public PolygonsSet(final double xMin, final double xMax, final double yMin, final double yMax) { - this(buildConvex(boxBoundary(xMin, xMax, yMin, yMax)).getTree(false)); + super(boxBoundary(xMin, xMax, yMin, yMax)); } /** Create a list of hyperplanes representing the boundary of a box. @@ -98,42 +100,42 @@ public class PolygonsSet extends Region { * @param yMax high bound along the y direction * @return boundary of the box */ - private static List boxBoundary(final double xMin, final double xMax, - final double yMin, final double yMax) { - final Point2D minMin = new Point2D(xMin, yMin); - final Point2D minMax = new Point2D(xMin, yMax); - final Point2D maxMin = new Point2D(xMax, yMin); - final Point2D maxMax = new Point2D(xMax, yMax); - return Arrays.asList(new Hyperplane[] { + private static Line[] boxBoundary(final double xMin, final double xMax, + final double yMin, final double yMax) { + final Vector2D minMin = new Vector2D(xMin, yMin); + final Vector2D minMax = new Vector2D(xMin, yMax); + final Vector2D maxMin = new Vector2D(xMax, yMin); + final Vector2D maxMax = new Vector2D(xMax, yMax); + return new Line[] { new Line(minMin, maxMin), new Line(maxMin, maxMax), new Line(maxMax, minMax), new Line(minMax, minMin) - }); + }; } /** {@inheritDoc} */ - public Region buildNew(final BSPTree tree) { + public PolygonsSet buildNew(final BSPTree tree) { return new PolygonsSet(tree); } /** {@inheritDoc} */ protected void computeGeometricalProperties() { - final Point2D[][] v = getVertices(); + final Vector2D[][] v = getVertices(); if (v.length == 0) { if ((Boolean) getTree(false).getAttribute()) { setSize(Double.POSITIVE_INFINITY); - setBarycenter(Point2D.UNDEFINED); + setBarycenter(Vector2D.NaN); } else { setSize(0); - setBarycenter(new Point2D(0, 0)); + setBarycenter(new Vector2D(0, 0)); } } else if (v[0][0] == null) { // there is at least one open-loop: the polygon is infinite setSize(Double.POSITIVE_INFINITY); - setBarycenter(Point2D.UNDEFINED); + setBarycenter(Vector2D.NaN); } else { // all loops are closed, we compute some integrals around the shape @@ -141,14 +143,14 @@ public class PolygonsSet extends Region { double sumX = 0; double sumY = 0; - for (Point2D[] loop : v) { - double x1 = loop[loop.length - 1].x; - double y1 = loop[loop.length - 1].y; - for (final Point2D point : loop) { + for (Vector2D[] loop : v) { + double x1 = loop[loop.length - 1].getX(); + double y1 = loop[loop.length - 1].getY(); + for (final Vector2D point : loop) { final double x0 = x1; final double y0 = y1; - x1 = point.x; - y1 = point.y; + x1 = point.getX(); + y1 = point.getY(); final double factor = x0 * y1 - y0 * x1; sum += factor; sumX += factor * (x0 + x1); @@ -159,10 +161,10 @@ public class PolygonsSet extends Region { if (sum < 0) { // the polygon as a finite outside surrounded by an infinite inside setSize(Double.POSITIVE_INFINITY); - setBarycenter(Point2D.UNDEFINED); + setBarycenter(Vector2D.NaN); } else { setSize(sum / 2); - setBarycenter(new Point2D(sumX / (3 * sum), sumY / (3 * sum))); + setBarycenter(new Vector2D(sumX / (3 * sum), sumY / (3 * sum))); } } @@ -192,19 +194,19 @@ public class PolygonsSet extends Region { * loops with the open loops first (the returned value is guaranteed * to be non-null) */ - public Point2D[][] getVertices() { + public Vector2D[][] getVertices() { if (vertices == null) { if (getTree(false).getCut() == null) { - vertices = new Point2D[0][]; + vertices = new Vector2D[0][]; } else { - // sort the segmfinal ents according to their start point + // sort the segments according to their start point final SegmentsBuilder visitor = new SegmentsBuilder(); getTree(true).visit(visitor); final AVLTree sorted = visitor.getSorted(); // identify the loops, starting from the open ones - // (their start segments final are naturally at the sorted set beginning) + // (their start segments are naturally at the sorted set beginning) final ArrayList> loops = new ArrayList>(); while (!sorted.isEmpty()) { final AVLTree.Node node = sorted.getSmallest(); @@ -215,31 +217,30 @@ public class PolygonsSet extends Region { } // tranform the loops in an array of arrays of points - vertices = new Point2D[loops.size()][]; + vertices = new Vector2D[loops.size()][]; int i = 0; for (final List loop : loops) { if (loop.size() < 2) { - // sifinal ngle infinite line - final Line line = ((Segment) loop.get(0)).getLine(); - vertices[i++] = new Point2D[] { + // single infinite line + final Line line = loop.get(0).getLine(); + vertices[i++] = new Vector2D[] { null, - (Point2D) line.toSpace(new Point1D(-Float.MAX_VALUE)), - (Point2D) line.toSpace(new Point1D(+Float.MAX_VALUE)) + line.toSpace(new Vector1D(-Float.MAX_VALUE)), + line.toSpace(new Vector1D(+Float.MAX_VALUE)) }; - } else if (((Segment) loop.get(0)).getStart() == null) { - // open lofinal op with at least one real point - final Point2D[] array = new Point2D[loop.size() + 2]; + } else if (loop.get(0).getStart() == null) { + // open loop with at least one real point + final Vector2D[] array = new Vector2D[loop.size() + 2]; int j = 0; for (Segment segment : loop) { if (j == 0) { // null point and first dummy point - double x = - ((Point1D) segment.getLine().toSubSpace(segment.getEnd())).getAbscissa(); + double x = segment.getLine().toSubSpace(segment.getEnd()).getX(); x -= FastMath.max(1.0, FastMath.abs(x / 2)); array[j++] = null; - array[j++] = (Point2D) segment.getLine().toSpace(new Point1D(x)); + array[j++] = segment.getLine().toSpace(new Vector1D(x)); } if (j < (array.length - 1)) { @@ -249,16 +250,15 @@ public class PolygonsSet extends Region { if (j == (array.length - 1)) { // last dummy point - double x = - ((Point1D) segment.getLine().toSubSpace(segment.getStart())).getAbscissa(); + double x = segment.getLine().toSubSpace(segment.getStart()).getX(); x += FastMath.max(1.0, FastMath.abs(x / 2)); - array[j++] = (Point2D) segment.getLine().toSpace(new Point1D(x)); + array[j++] = segment.getLine().toSpace(new Vector1D(x)); } } vertices[i++] = array; } else { - final Point2D[] array = new Point2D[loop.size()]; + final Vector2D[] array = new Vector2D[loop.size()]; int j = 0; for (Segment segment : loop) { array[j++] = segment.getStart(); @@ -285,10 +285,10 @@ public class PolygonsSet extends Region { final AVLTree sorted) { final ArrayList loop = new ArrayList(); - Segment segment = (Segment) node.getElement(); + Segment segment = node.getElement(); loop.add(segment); - final Point2D globalStart = segment.getStart(); - Point2D end = segment.getEnd(); + final Vector2D globalStart = segment.getStart(); + Vector2D end = segment.getEnd(); node.delete(); // is this an open or a closed loop ? @@ -333,7 +333,7 @@ public class PolygonsSet extends Region { } if ((end == null) && !open) { - throw new RuntimeException("internal error"); + throw new MathInternalError(); } return loop; diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/twod/Segment.java b/src/main/java/org/apache/commons/math/geometry/euclidean/twod/Segment.java index a631a2be2..eceb980cd 100644 --- a/src/main/java/org/apache/commons/math/geometry/euclidean/twod/Segment.java +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/twod/Segment.java @@ -19,15 +19,16 @@ package org.apache.commons.math.geometry.euclidean.twod; import org.apache.commons.math.geometry.partitioning.utilities.OrderedTuple; /** This class holds segments information before they are connected. - * @version $Revision$ $Date$ + * @version $Id:$ + * @since 3.0 */ class Segment implements Comparable { /** Start point of the segment. */ - private final Point2D start; + private final Vector2D start; /** End point of the segments. */ - private final Point2D end; + private final Vector2D end; /** Line containing the segment. */ private final Line line; @@ -40,13 +41,13 @@ class Segment implements Comparable { * @param end end point of the segment * @param line line containing the segment */ - public Segment(final Point2D start, final Point2D end, final Line line) { + public Segment(final Vector2D start, final Vector2D end, final Line line) { this.start = start; this.end = end; this.line = line; sortingKey = (start == null) ? new OrderedTuple(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY) : - new OrderedTuple(start.x, start.y); + new OrderedTuple(start.getX(), start.getY()); } /** Build a dummy segment. @@ -58,24 +59,24 @@ class Segment implements Comparable { * @param dx abscissa offset from the start point * @param dy ordinate offset from the start point */ - public Segment(final Point2D start, final double dx, final double dy) { + public Segment(final Vector2D start, final double dx, final double dy) { this.start = null; this.end = null; this.line = null; - sortingKey = new OrderedTuple(start.x + dx, start.y + dy); + sortingKey = new OrderedTuple(start.getX() + dx, start.getY() + dy); } /** Get the start point of the segment. * @return start point of the segment */ - public Point2D getStart() { + public Vector2D getStart() { return start; } /** Get the end point of the segment. * @return end point of the segment */ - public Point2D getEnd() { + public Vector2D getEnd() { return end; } diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/twod/SegmentBuilder.java b/src/main/java/org/apache/commons/math/geometry/euclidean/twod/SegmentBuilder.java index 622b3f881..6f68f4478 100644 --- a/src/main/java/org/apache/commons/math/geometry/euclidean/twod/SegmentBuilder.java +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/twod/SegmentBuilder.java @@ -18,19 +18,22 @@ package org.apache.commons.math.geometry.euclidean.twod; import java.util.List; +import org.apache.commons.math.geometry.euclidean.oned.Euclidean1D; import org.apache.commons.math.geometry.euclidean.oned.Interval; import org.apache.commons.math.geometry.euclidean.oned.IntervalsSet; -import org.apache.commons.math.geometry.euclidean.oned.Point1D; +import org.apache.commons.math.geometry.euclidean.oned.Vector1D; +import org.apache.commons.math.geometry.partitioning.AbstractSubHyperplane; import org.apache.commons.math.geometry.partitioning.BSPTree; import org.apache.commons.math.geometry.partitioning.BSPTreeVisitor; -import org.apache.commons.math.geometry.partitioning.Region.BoundaryAttribute; +import org.apache.commons.math.geometry.partitioning.BoundaryAttribute; import org.apache.commons.math.geometry.partitioning.SubHyperplane; import org.apache.commons.math.geometry.partitioning.utilities.AVLTree; /** Visitor building segments. - * @version $Revision$ $Date$ + * @version $Id:$ + * @since 3.0 */ -class SegmentsBuilder implements BSPTreeVisitor { +class SegmentsBuilder implements BSPTreeVisitor { /** Sorted segments. */ private AVLTree sorted; @@ -41,13 +44,14 @@ class SegmentsBuilder implements BSPTreeVisitor { } /** {@inheritDoc} */ - public Order visitOrder(final BSPTree node) { + public Order visitOrder(final BSPTree node) { return Order.MINUS_SUB_PLUS; } /** {@inheritDoc} */ - public void visitInternalNode(final BSPTree node) { - final BoundaryAttribute attribute = (BoundaryAttribute) node.getAttribute(); + public void visitInternalNode(final BSPTree node) { + @SuppressWarnings("unchecked") + final BoundaryAttribute attribute = (BoundaryAttribute) node.getAttribute(); if (attribute.getPlusOutside() != null) { addContribution(attribute.getPlusOutside(), false); } @@ -57,21 +61,24 @@ class SegmentsBuilder implements BSPTreeVisitor { } /** {@inheritDoc} */ - public void visitLeafNode(final BSPTree node) { + public void visitLeafNode(final BSPTree node) { } /** Add he contribution of a boundary facet. * @param sub boundary facet * @param reversed if true, the facet has the inside on its plus side */ - private void addContribution(final SubHyperplane sub, final boolean reversed) { + private void addContribution(final SubHyperplane sub, final boolean reversed) { + @SuppressWarnings("unchecked") + final AbstractSubHyperplane absSub = + (AbstractSubHyperplane) sub; final Line line = (Line) sub.getHyperplane(); - final List intervals = ((IntervalsSet) sub.getRemainingRegion()).asList(); + final List intervals = ((IntervalsSet) absSub.getRemainingRegion()).asList(); for (final Interval i : intervals) { - final Point2D start = Double.isInfinite(i.getLower()) ? - null : (Point2D) line.toSpace(new Point1D(i.getLower())); - final Point2D end = Double.isInfinite(i.getUpper()) ? - null : (Point2D) line.toSpace(new Point1D(i.getUpper())); + final Vector2D start = Double.isInfinite(i.getLower()) ? + null : (Vector2D) line.toSpace(new Vector1D(i.getLower())); + final Vector2D end = Double.isInfinite(i.getUpper()) ? + null : (Vector2D) line.toSpace(new Vector1D(i.getUpper())); if (reversed) { sorted.insert(new Segment(end, start, line.getReverse())); } else { diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/twod/SubLine.java b/src/main/java/org/apache/commons/math/geometry/euclidean/twod/SubLine.java new file mode 100644 index 000000000..c0965aac9 --- /dev/null +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/twod/SubLine.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math.geometry.euclidean.twod; + +import org.apache.commons.math.geometry.euclidean.oned.Euclidean1D; +import org.apache.commons.math.geometry.euclidean.oned.IntervalsSet; +import org.apache.commons.math.geometry.euclidean.oned.OrientedPoint; +import org.apache.commons.math.geometry.euclidean.oned.Vector1D; +import org.apache.commons.math.geometry.partitioning.AbstractSubHyperplane; +import org.apache.commons.math.geometry.partitioning.BSPTree; +import org.apache.commons.math.geometry.partitioning.Hyperplane; +import org.apache.commons.math.geometry.partitioning.Region; +import org.apache.commons.math.geometry.partitioning.Side; +import org.apache.commons.math.geometry.partitioning.SubHyperplane; +import org.apache.commons.math.util.FastMath; + +/** This class represents a sub-hyperplane for {@link Line}. + * @version $Id:$ + * @since 3.0 + */ +public class SubLine extends AbstractSubHyperplane { + + /** Simple constructor. + * @param hyperplane underlying hyperplane + * @param remainingRegion remaining region of the hyperplane + */ + public SubLine(final Hyperplane hyperplane, + final Region remainingRegion) { + super(hyperplane, remainingRegion); + } + + /** {@inheritDoc} */ + protected AbstractSubHyperplane buildNew(final Hyperplane hyperplane, + final Region remainingRegion) { + return new SubLine(hyperplane, remainingRegion); + } + + /** {@inheritDoc} */ + public Side side(final Hyperplane hyperplane) { + + final Line thisLine = (Line) getHyperplane(); + final Line otherLine = (Line) hyperplane; + final Vector2D crossing = thisLine.intersection(otherLine); + + if (crossing == null) { + // the lines are parallel, + final double global = otherLine.getOffset(thisLine); + return (global < -1.0e-10) ? Side.MINUS : ((global > 1.0e-10) ? Side.PLUS : Side.HYPER); + } + + // the lines do intersect + final boolean direct = FastMath.sin(thisLine.getAngle() - otherLine.getAngle()) < 0; + final Vector1D x = (Vector1D) thisLine.toSubSpace(crossing); + return getRemainingRegion().side(new OrientedPoint(x, direct)); + + } + + /** {@inheritDoc} */ + public SplitSubHyperplane split(final Hyperplane hyperplane) { + + final Line thisLine = (Line) getHyperplane(); + final Line otherLine = (Line) hyperplane; + final Vector2D crossing = thisLine.intersection(otherLine); + + if (crossing == null) { + // the lines are parallel + final double global = otherLine.getOffset(thisLine); + return (global < -1.0e-10) ? + new SplitSubHyperplane(null, this) : + new SplitSubHyperplane(this, null); + } + + // the lines do intersect + final boolean direct = FastMath.sin(thisLine.getAngle() - otherLine.getAngle()) < 0; + final Vector1D x = (Vector1D) thisLine.toSubSpace(crossing); + final SubHyperplane subPlus = new OrientedPoint(x, !direct).wholeHyperplane(); + final SubHyperplane subMinus = new OrientedPoint(x, direct).wholeHyperplane(); + + final BSPTree splitTree = getRemainingRegion().getTree(false).split(subMinus); + final BSPTree plusTree = getRemainingRegion().isEmpty(splitTree.getPlus()) ? + new BSPTree(Boolean.FALSE) : + new BSPTree(subPlus, new BSPTree(Boolean.FALSE), + splitTree.getPlus(), null); + final BSPTree minusTree = getRemainingRegion().isEmpty(splitTree.getMinus()) ? + new BSPTree(Boolean.FALSE) : + new BSPTree(subMinus, new BSPTree(Boolean.FALSE), + splitTree.getMinus(), null); + + return new SplitSubHyperplane(new SubLine(thisLine.copySelf(), new IntervalsSet(plusTree)), + new SubLine(thisLine.copySelf(), new IntervalsSet(minusTree))); + + } + +} diff --git a/src/test/java/org/apache/commons/math/geometry/euclidean/oned/IntervalsSetTest.java b/src/test/java/org/apache/commons/math/geometry/euclidean/oned/IntervalsSetTest.java index 1d8c63032..b7c4640a4 100644 --- a/src/test/java/org/apache/commons/math/geometry/euclidean/oned/IntervalsSetTest.java +++ b/src/test/java/org/apache/commons/math/geometry/euclidean/oned/IntervalsSetTest.java @@ -20,8 +20,9 @@ import java.util.List; import org.apache.commons.math.geometry.euclidean.oned.Interval; import org.apache.commons.math.geometry.euclidean.oned.IntervalsSet; -import org.apache.commons.math.geometry.euclidean.oned.Point1D; +import org.apache.commons.math.geometry.euclidean.oned.Vector1D; import org.apache.commons.math.geometry.partitioning.Region; +import org.apache.commons.math.geometry.partitioning.RegionFactory; import org.apache.commons.math.util.FastMath; import org.junit.Assert; import org.junit.Test; @@ -32,12 +33,12 @@ public class IntervalsSetTest { public void testInterval() { IntervalsSet set = new IntervalsSet(2.3, 5.7); Assert.assertEquals(3.4, set.getSize(), 1.0e-10); - Assert.assertEquals(4.0, ((Point1D) set.getBarycenter()).getAbscissa(), 1.0e-10); - Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Point1D(2.3))); - Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Point1D(5.7))); - Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Point1D(1.2))); - Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Point1D(8.7))); - Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Point1D(3.0))); + Assert.assertEquals(4.0, ((Vector1D) set.getBarycenter()).getX(), 1.0e-10); + Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Vector1D(2.3))); + Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Vector1D(5.7))); + Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Vector1D(1.2))); + Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Vector1D(8.7))); + Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Vector1D(3.0))); Assert.assertEquals(2.3, set.getInf(), 1.0e-10); Assert.assertEquals(5.7, set.getSup(), 1.0e-10); } @@ -45,17 +46,17 @@ public class IntervalsSetTest { @Test public void testInfinite() { IntervalsSet set = new IntervalsSet(9.0, Double.POSITIVE_INFINITY); - Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Point1D(9.0))); - Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Point1D(8.4))); + Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Vector1D(9.0))); + Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Vector1D(8.4))); for (double e = 1.0; e <= 6.0; e += 1.0) { Assert.assertEquals(Region.Location.INSIDE, - set.checkPoint(new Point1D(FastMath.pow(10.0, e)))); + set.checkPoint(new Vector1D(FastMath.pow(10.0, e)))); } Assert.assertTrue(Double.isInfinite(set.getSize())); Assert.assertEquals(9.0, set.getInf(), 1.0e-10); Assert.assertTrue(Double.isInfinite(set.getSup())); - set = (IntervalsSet) set.getComplement(); + set = (IntervalsSet) new RegionFactory().getComplement(set); Assert.assertEquals(9.0, set.getSup(), 1.0e-10); Assert.assertTrue(Double.isInfinite(set.getInf())); @@ -63,22 +64,23 @@ public class IntervalsSetTest { @Test public void testMultiple() { + RegionFactory factory = new RegionFactory(); IntervalsSet set = (IntervalsSet) - Region.intersection(Region.union(Region.difference(new IntervalsSet(1.0, 6.0), - new IntervalsSet(3.0, 5.0)), - new IntervalsSet(9.0, Double.POSITIVE_INFINITY)), - new IntervalsSet(Double.NEGATIVE_INFINITY, 11.0)); + factory.intersection(factory.union(factory.difference(new IntervalsSet(1.0, 6.0), + new IntervalsSet(3.0, 5.0)), + new IntervalsSet(9.0, Double.POSITIVE_INFINITY)), + new IntervalsSet(Double.NEGATIVE_INFINITY, 11.0)); Assert.assertEquals(5.0, set.getSize(), 1.0e-10); - Assert.assertEquals(5.9, ((Point1D) set.getBarycenter()).getAbscissa(), 1.0e-10); - Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Point1D(0.0))); - Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Point1D(4.0))); - Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Point1D(8.0))); - Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Point1D(12.0))); - Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Point1D(1.2))); - Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Point1D(5.9))); - Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Point1D(9.01))); - Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Point1D(5.0))); - Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Point1D(11.0))); + Assert.assertEquals(5.9, ((Vector1D) set.getBarycenter()).getX(), 1.0e-10); + Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Vector1D(0.0))); + Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Vector1D(4.0))); + Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Vector1D(8.0))); + Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Vector1D(12.0))); + Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Vector1D(1.2))); + Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Vector1D(5.9))); + Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Vector1D(9.01))); + Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Vector1D(5.0))); + Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Vector1D(11.0))); Assert.assertEquals( 1.0, set.getInf(), 1.0e-10); Assert.assertEquals(11.0, set.getSup(), 1.0e-10); diff --git a/src/test/java/org/apache/commons/math/geometry/euclidean/threed/PlaneTest.java b/src/test/java/org/apache/commons/math/geometry/euclidean/threed/PlaneTest.java index 3b4d35d06..e1ff38710 100644 --- a/src/test/java/org/apache/commons/math/geometry/euclidean/threed/PlaneTest.java +++ b/src/test/java/org/apache/commons/math/geometry/euclidean/threed/PlaneTest.java @@ -18,7 +18,6 @@ package org.apache.commons.math.geometry.euclidean.threed; import org.apache.commons.math.geometry.euclidean.threed.Line; import org.apache.commons.math.geometry.euclidean.threed.Plane; -import org.apache.commons.math.geometry.euclidean.threed.Point3D; import org.apache.commons.math.geometry.euclidean.threed.Rotation; import org.apache.commons.math.geometry.euclidean.threed.Vector3D; import org.junit.Assert; @@ -29,22 +28,22 @@ public class PlaneTest { @Test public void testContains() { Plane p = new Plane(new Vector3D(0, 0, 1), new Vector3D(0, 0, 1)); - Assert.assertTrue(p.contains(new Point3D(0, 0, 1))); - Assert.assertTrue(p.contains(new Point3D(17, -32, 1))); - Assert.assertTrue(! p.contains(new Point3D(17, -32, 1.001))); + Assert.assertTrue(p.contains(new Vector3D(0, 0, 1))); + Assert.assertTrue(p.contains(new Vector3D(17, -32, 1))); + Assert.assertTrue(! p.contains(new Vector3D(17, -32, 1.001))); } @Test public void testOffset() { Vector3D p1 = new Vector3D(1, 1, 1); Plane p = new Plane(p1, new Vector3D(0.2, 0, 0)); - Assert.assertEquals(-5.0, p.getOffset(new Point3D(-4, 0, 0)), 1.0e-10); - Assert.assertEquals(+5.0, p.getOffset(new Point3D(6, 10, -12)), 1.0e-10); + Assert.assertEquals(-5.0, p.getOffset(new Vector3D(-4, 0, 0)), 1.0e-10); + Assert.assertEquals(+5.0, p.getOffset(new Vector3D(6, 10, -12)), 1.0e-10); Assert.assertEquals(0.3, - p.getOffset(new Point3D(1.0, p1, 0.3, p.getNormal())), + p.getOffset(new Vector3D(1.0, p1, 0.3, p.getNormal())), 1.0e-10); Assert.assertEquals(-0.3, - p.getOffset(new Point3D(1.0, p1, -0.3, p.getNormal())), + p.getOffset(new Vector3D(1.0, p1, -0.3, p.getNormal())), 1.0e-10); } @@ -56,9 +55,9 @@ public class PlaneTest { @Test public void testThreePoints() { - Point3D p1 = new Point3D(1.2, 3.4, -5.8); - Point3D p2 = new Point3D(3.4, -5.8, 1.2); - Point3D p3 = new Point3D(-2.0, 4.3, 0.7); + Vector3D p1 = new Vector3D(1.2, 3.4, -5.8); + Vector3D p2 = new Vector3D(3.4, -5.8, 1.2); + Vector3D p3 = new Vector3D(-2.0, 4.3, 0.7); Plane p = new Plane(p1, p2, p3); Assert.assertTrue(p.contains(p1)); Assert.assertTrue(p.contains(p2)); @@ -67,9 +66,9 @@ public class PlaneTest { @Test public void testRotate() { - Point3D p1 = new Point3D(1.2, 3.4, -5.8); - Point3D p2 = new Point3D(3.4, -5.8, 1.2); - Point3D p3 = new Point3D(-2.0, 4.3, 0.7); + Vector3D p1 = new Vector3D(1.2, 3.4, -5.8); + Vector3D p2 = new Vector3D(3.4, -5.8, 1.2); + Vector3D p3 = new Vector3D(-2.0, 4.3, 0.7); Plane p = new Plane(p1, p2, p3); Vector3D oldNormal = p.getNormal(); @@ -92,9 +91,9 @@ public class PlaneTest { @Test public void testTranslate() { - Point3D p1 = new Point3D(1.2, 3.4, -5.8); - Point3D p2 = new Point3D(3.4, -5.8, 1.2); - Point3D p3 = new Point3D(-2.0, 4.3, 0.7); + Vector3D p1 = new Vector3D(1.2, 3.4, -5.8); + Vector3D p2 = new Vector3D(3.4, -5.8, 1.2); + Vector3D p3 = new Vector3D(-2.0, 4.3, 0.7); Plane p = new Plane(p1, p2, p3); p = p.translate(new Vector3D(2.0, p.getU(), -1.5, p.getV())); @@ -118,7 +117,7 @@ public class PlaneTest { public void testIntersection() { Plane p = new Plane(new Vector3D(1, 2, 3), new Vector3D(-4, 1, -5)); Line l = new Line(new Vector3D(0.2, -3.5, 0.7), new Vector3D(1, 1, -1)); - Point3D point = p.intersection(l); + Vector3D point = p.intersection(l); Assert.assertTrue(p.contains(point)); Assert.assertTrue(l.contains(point)); Assert.assertNull(p.intersection(new Line(new Vector3D(10, 10, 10), diff --git a/src/test/java/org/apache/commons/math/geometry/euclidean/threed/PolyhedronsSetTest.java b/src/test/java/org/apache/commons/math/geometry/euclidean/threed/PolyhedronsSetTest.java index 1197b7d90..fec1b602b 100644 --- a/src/test/java/org/apache/commons/math/geometry/euclidean/threed/PolyhedronsSetTest.java +++ b/src/test/java/org/apache/commons/math/geometry/euclidean/threed/PolyhedronsSetTest.java @@ -16,20 +16,13 @@ */ package org.apache.commons.math.geometry.euclidean.threed; -import java.util.Arrays; - -import org.apache.commons.math.geometry.euclidean.threed.Plane; -import org.apache.commons.math.geometry.euclidean.threed.Point3D; -import org.apache.commons.math.geometry.euclidean.threed.PolyhedronsSet; -import org.apache.commons.math.geometry.euclidean.threed.Rotation; -import org.apache.commons.math.geometry.euclidean.threed.Vector3D; -import org.apache.commons.math.geometry.euclidean.twod.Point2D; import org.apache.commons.math.geometry.euclidean.twod.PolygonsSet; +import org.apache.commons.math.geometry.euclidean.twod.Vector2D; import org.apache.commons.math.geometry.partitioning.BSPTree; import org.apache.commons.math.geometry.partitioning.BSPTreeVisitor; -import org.apache.commons.math.geometry.partitioning.Hyperplane; +import org.apache.commons.math.geometry.partitioning.BoundaryAttribute; import org.apache.commons.math.geometry.partitioning.Region; -import org.apache.commons.math.geometry.partitioning.SubHyperplane; +import org.apache.commons.math.geometry.partitioning.RegionFactory; import org.apache.commons.math.util.FastMath; import org.junit.Assert; import org.junit.Test; @@ -53,41 +46,41 @@ public class PolyhedronsSetTest { boolean zOK = (z >= 0.0) && (z <= 1.0); Region.Location expected = (xOK && yOK && zOK) ? Region.Location.INSIDE : Region.Location.OUTSIDE; - Assert.assertEquals(expected, tree.checkPoint(new Point3D(x, y, z))); + Assert.assertEquals(expected, tree.checkPoint(new Vector3D(x, y, z))); } } } - checkPoints(Region.Location.BOUNDARY, tree, new Point3D[] { - new Point3D(0.0, 0.5, 0.5), - new Point3D(1.0, 0.5, 0.5), - new Point3D(0.5, 0.0, 0.5), - new Point3D(0.5, 1.0, 0.5), - new Point3D(0.5, 0.5, 0.0), - new Point3D(0.5, 0.5, 1.0) + checkPoints(Region.Location.BOUNDARY, tree, new Vector3D[] { + new Vector3D(0.0, 0.5, 0.5), + new Vector3D(1.0, 0.5, 0.5), + new Vector3D(0.5, 0.0, 0.5), + new Vector3D(0.5, 1.0, 0.5), + new Vector3D(0.5, 0.5, 0.0), + new Vector3D(0.5, 0.5, 1.0) }); - checkPoints(Region.Location.OUTSIDE, tree, new Point3D[] { - new Point3D(0.0, 1.2, 1.2), - new Point3D(1.0, 1.2, 1.2), - new Point3D(1.2, 0.0, 1.2), - new Point3D(1.2, 1.0, 1.2), - new Point3D(1.2, 1.2, 0.0), - new Point3D(1.2, 1.2, 1.0) + checkPoints(Region.Location.OUTSIDE, tree, new Vector3D[] { + new Vector3D(0.0, 1.2, 1.2), + new Vector3D(1.0, 1.2, 1.2), + new Vector3D(1.2, 0.0, 1.2), + new Vector3D(1.2, 1.0, 1.2), + new Vector3D(1.2, 1.2, 0.0), + new Vector3D(1.2, 1.2, 1.0) }); } @Test public void testTetrahedron() { - Point3D vertex1 = new Point3D(1, 2, 3); - Point3D vertex2 = new Point3D(2, 2, 4); - Point3D vertex3 = new Point3D(2, 3, 3); - Point3D vertex4 = new Point3D(1, 3, 4); + Vector3D vertex1 = new Vector3D(1, 2, 3); + Vector3D vertex2 = new Vector3D(2, 2, 4); + Vector3D vertex3 = new Vector3D(2, 3, 3); + Vector3D vertex4 = new Vector3D(1, 3, 4); + @SuppressWarnings("unchecked") PolyhedronsSet tree = - (PolyhedronsSet) Region.buildConvex(Arrays.asList(new Hyperplane[] { + (PolyhedronsSet) new RegionFactory().buildConvex( new Plane(vertex3, vertex2, vertex1), new Plane(vertex2, vertex3, vertex4), new Plane(vertex4, vertex3, vertex1), - new Plane(vertex1, vertex2, vertex4) - })); + new Plane(vertex1, vertex2, vertex4)); Assert.assertEquals(1.0 / 3.0, tree.getSize(), 1.0e-10); Assert.assertEquals(2.0 * FastMath.sqrt(3.0), tree.getBoundarySize(), 1.0e-10); Vector3D barycenter = (Vector3D) tree.getBarycenter(); @@ -95,18 +88,18 @@ public class PolyhedronsSetTest { Assert.assertEquals(2.5, barycenter.getY(), 1.0e-10); Assert.assertEquals(3.5, barycenter.getZ(), 1.0e-10); double third = 1.0 / 3.0; - checkPoints(Region.Location.BOUNDARY, tree, new Point3D[] { + checkPoints(Region.Location.BOUNDARY, tree, new Vector3D[] { vertex1, vertex2, vertex3, vertex4, - new Point3D(third, vertex1, third, vertex2, third, vertex3), - new Point3D(third, vertex2, third, vertex3, third, vertex4), - new Point3D(third, vertex3, third, vertex4, third, vertex1), - new Point3D(third, vertex4, third, vertex1, third, vertex2) + new Vector3D(third, vertex1, third, vertex2, third, vertex3), + new Vector3D(third, vertex2, third, vertex3, third, vertex4), + new Vector3D(third, vertex3, third, vertex4, third, vertex1), + new Vector3D(third, vertex4, third, vertex1, third, vertex2) }); - checkPoints(Region.Location.OUTSIDE, tree, new Point3D[] { - new Point3D(1, 2, 4), - new Point3D(2, 2, 3), - new Point3D(2, 3, 4), - new Point3D(1, 3, 3) + checkPoints(Region.Location.OUTSIDE, tree, new Vector3D[] { + new Vector3D(1, 2, 4), + new Vector3D(2, 2, 3), + new Vector3D(2, 3, 4), + new Vector3D(1, 3, 3) }); } @@ -116,13 +109,13 @@ public class PolyhedronsSetTest { Vector3D vertex2 = new Vector3D(2.0, 2.4, 4.2); Vector3D vertex3 = new Vector3D(2.8, 3.3, 3.7); Vector3D vertex4 = new Vector3D(1.0, 3.6, 4.5); + @SuppressWarnings("unchecked") PolyhedronsSet tree = - (PolyhedronsSet) Region.buildConvex(Arrays.asList(new Hyperplane[] { + (PolyhedronsSet) new RegionFactory().buildConvex( new Plane(vertex3, vertex2, vertex1), new Plane(vertex2, vertex3, vertex4), new Plane(vertex4, vertex3, vertex1), - new Plane(vertex1, vertex2, vertex4) - })); + new Plane(vertex1, vertex2, vertex4)); Vector3D barycenter = (Vector3D) tree.getBarycenter(); Vector3D s = new Vector3D(10.2, 4.3, -6.7); Vector3D c = new Vector3D(-0.2, 2.1, -3.2); @@ -152,29 +145,30 @@ public class PolyhedronsSetTest { 1.0, c, 1.0, r.applyTo(vertex4.subtract(c))) }; - tree.getTree(true).visit(new BSPTreeVisitor() { + tree.getTree(true).visit(new BSPTreeVisitor() { - public Order visitOrder(BSPTree node) { + public Order visitOrder(BSPTree node) { return Order.MINUS_SUB_PLUS; } - public void visitInternalNode(BSPTree node) { - Region.BoundaryAttribute attribute = - (Region.BoundaryAttribute) node.getAttribute(); + public void visitInternalNode(BSPTree node) { + @SuppressWarnings("unchecked") + BoundaryAttribute attribute = + (BoundaryAttribute) node.getAttribute(); if (attribute.getPlusOutside() != null) { - checkFacet(attribute.getPlusOutside()); + checkFacet((SubPlane) attribute.getPlusOutside()); } if (attribute.getPlusInside() != null) { - checkFacet(attribute.getPlusInside()); + checkFacet((SubPlane) attribute.getPlusInside()); } } - public void visitLeafNode(BSPTree node) { + public void visitLeafNode(BSPTree node) { } - private void checkFacet(SubHyperplane facet) { + private void checkFacet(SubPlane facet) { Plane plane = (Plane) facet.getHyperplane(); - Point2D[][] vertices = + Vector2D[][] vertices = ((PolygonsSet) facet.getRemainingRegion()).getVertices(); Assert.assertEquals(1, vertices.length); for (int i = 0; i < vertices[0].length; ++i) { @@ -222,8 +216,8 @@ public class PolyhedronsSetTest { new PolyhedronsSet(x - w, x + w, y - l, y + l, z - w, z + w); PolyhedronsSet zBeam = new PolyhedronsSet(x - w, x + w, y - w, y + w, z - l, z + l); - PolyhedronsSet tree = - (PolyhedronsSet) Region.union(xBeam, Region.union(yBeam, zBeam)); + RegionFactory factory = new RegionFactory(); + PolyhedronsSet tree = (PolyhedronsSet) factory.union(xBeam, factory.union(yBeam, zBeam)); Vector3D barycenter = (Vector3D) tree.getBarycenter(); Assert.assertEquals(x, barycenter.getX(), 1.0e-10); @@ -234,7 +228,7 @@ public class PolyhedronsSetTest { } - private void checkPoints(Region.Location expected, PolyhedronsSet tree, Point3D[] points) { + private void checkPoints(Region.Location expected, PolyhedronsSet tree, Vector3D[] points) { for (int i = 0; i < points.length; ++i) { Assert.assertEquals(expected, tree.checkPoint(points[i])); } diff --git a/src/test/java/org/apache/commons/math/geometry/euclidean/twod/LineTest.java b/src/test/java/org/apache/commons/math/geometry/euclidean/twod/LineTest.java index 62cfe97b9..894a2ac4b 100644 --- a/src/test/java/org/apache/commons/math/geometry/euclidean/twod/LineTest.java +++ b/src/test/java/org/apache/commons/math/geometry/euclidean/twod/LineTest.java @@ -16,9 +16,10 @@ */ package org.apache.commons.math.geometry.euclidean.twod; -import org.apache.commons.math.geometry.euclidean.oned.Point1D; +import org.apache.commons.math.geometry.euclidean.oned.Euclidean1D; +import org.apache.commons.math.geometry.euclidean.oned.Vector1D; import org.apache.commons.math.geometry.euclidean.twod.Line; -import org.apache.commons.math.geometry.euclidean.twod.Point2D; +import org.apache.commons.math.geometry.euclidean.twod.Vector2D; import org.apache.commons.math.geometry.partitioning.Transform; import org.apache.commons.math.util.FastMath; import org.junit.Assert; @@ -30,48 +31,48 @@ public class LineTest { @Test public void testContains() { - Line l = new Line(new Point2D(0, 1), new Point2D(1, 2)); - Assert.assertTrue(l.contains(new Point2D(0, 1))); - Assert.assertTrue(l.contains(new Point2D(1, 2))); - Assert.assertTrue(l.contains(new Point2D(7, 8))); - Assert.assertTrue(! l.contains(new Point2D(8, 7))); + Line l = new Line(new Vector2D(0, 1), new Vector2D(1, 2)); + Assert.assertTrue(l.contains(new Vector2D(0, 1))); + Assert.assertTrue(l.contains(new Vector2D(1, 2))); + Assert.assertTrue(l.contains(new Vector2D(7, 8))); + Assert.assertTrue(! l.contains(new Vector2D(8, 7))); } @Test public void testAbscissa() { - Line l = new Line(new Point2D(2, 1), new Point2D(-2, -2)); + Line l = new Line(new Vector2D(2, 1), new Vector2D(-2, -2)); Assert.assertEquals(0.0, - ((Point1D) l.toSubSpace(new Point2D(-3, 4))).getAbscissa(), + ((Vector1D) l.toSubSpace(new Vector2D(-3, 4))).getX(), 1.0e-10); Assert.assertEquals(0.0, - ((Point1D) l.toSubSpace(new Point2D( 3, -4))).getAbscissa(), + ((Vector1D) l.toSubSpace(new Vector2D( 3, -4))).getX(), 1.0e-10); Assert.assertEquals(-5.0, - ((Point1D) l.toSubSpace(new Point2D( 7, -1))).getAbscissa(), + ((Vector1D) l.toSubSpace(new Vector2D( 7, -1))).getX(), 1.0e-10); Assert.assertEquals( 5.0, - ((Point1D) l.toSubSpace(new Point2D(-1, -7))).getAbscissa(), + ((Vector1D) l.toSubSpace(new Vector2D(-1, -7))).getX(), 1.0e-10); } @Test public void testOffset() { - Line l = new Line(new Point2D(2, 1), new Point2D(-2, -2)); - Assert.assertEquals(-5.0, l.getOffset(new Point2D(5, -3)), 1.0e-10); - Assert.assertEquals(+5.0, l.getOffset(new Point2D(-5, 2)), 1.0e-10); + Line l = new Line(new Vector2D(2, 1), new Vector2D(-2, -2)); + Assert.assertEquals(-5.0, l.getOffset(new Vector2D(5, -3)), 1.0e-10); + Assert.assertEquals(+5.0, l.getOffset(new Vector2D(-5, 2)), 1.0e-10); } @Test public void testPointAt() { - Line l = new Line(new Point2D(2, 1), new Point2D(-2, -2)); + Line l = new Line(new Vector2D(2, 1), new Vector2D(-2, -2)); for (double a = -2.0; a < 2.0; a += 0.2) { - Point1D pA = new Point1D(a); - Point2D point = (Point2D) l.toSpace(pA); - Assert.assertEquals(a, ((Point1D) l.toSubSpace(point)).getAbscissa(), 1.0e-10); + Vector1D pA = new Vector1D(a); + Vector2D point = (Vector2D) l.toSpace(pA); + Assert.assertEquals(a, ((Vector1D) l.toSubSpace(point)).getX(), 1.0e-10); Assert.assertEquals(0.0, l.getOffset(point), 1.0e-10); for (double o = -2.0; o < 2.0; o += 0.2) { point = l.getPointAt(pA, o); - Assert.assertEquals(a, ((Point1D) l.toSubSpace(point)).getAbscissa(), 1.0e-10); + Assert.assertEquals(a, ((Vector1D) l.toSubSpace(point)).getX(), 1.0e-10); Assert.assertEquals(o, l.getOffset(point), 1.0e-10); } } @@ -79,38 +80,36 @@ public class LineTest { @Test public void testOriginOffset() { - Line l1 = new Line(new Point2D(0, 1), new Point2D(1, 2)); + Line l1 = new Line(new Vector2D(0, 1), new Vector2D(1, 2)); Assert.assertEquals(FastMath.sqrt(0.5), l1.getOriginOffset(), 1.0e-10); - Line l2 = new Line(new Point2D(1, 2), new Point2D(0, 1)); + Line l2 = new Line(new Vector2D(1, 2), new Vector2D(0, 1)); Assert.assertEquals(-FastMath.sqrt(0.5), l2.getOriginOffset(), 1.0e-10); } @Test public void testParallel() { - Line l1 = new Line(new Point2D(0, 1), new Point2D(1, 2)); - Line l2 = new Line(new Point2D(2, 2), new Point2D(3, 3)); + Line l1 = new Line(new Vector2D(0, 1), new Vector2D(1, 2)); + Line l2 = new Line(new Vector2D(2, 2), new Vector2D(3, 3)); Assert.assertTrue(l1.isParallelTo(l2)); - Line l3 = new Line(new Point2D(1, 0), new Point2D(0.5, -0.5)); + Line l3 = new Line(new Vector2D(1, 0), new Vector2D(0.5, -0.5)); Assert.assertTrue(l1.isParallelTo(l3)); - Line l4 = new Line(new Point2D(1, 0), new Point2D(0.5, -0.51)); + Line l4 = new Line(new Vector2D(1, 0), new Vector2D(0.5, -0.51)); Assert.assertTrue(! l1.isParallelTo(l4)); } @Test public void testTransform() { - Line l1 = new Line(new Point2D(1.0 ,1.0), new Point2D(4.0 ,1.0)); - Transform t1 = Line.getTransform(new AffineTransform(0.0, 0.5, - -1.0, 0.0, - 1.0, 1.5)); + Line l1 = new Line(new Vector2D(1.0 ,1.0), new Vector2D(4.0 ,1.0)); + Transform t1 = + Line.getTransform(new AffineTransform(0.0, 0.5, -1.0, 0.0, 1.0, 1.5)); Assert.assertEquals(0.5 * FastMath.PI, ((Line) t1.apply(l1)).getAngle(), 1.0e-10); - Line l2 = new Line(new Point2D(0.0, 0.0), new Point2D(1.0, 1.0)); - Transform t2 = Line.getTransform(new AffineTransform(0.0, 0.5, - -1.0, 0.0, - 1.0, 1.5)); + Line l2 = new Line(new Vector2D(0.0, 0.0), new Vector2D(1.0, 1.0)); + Transform t2 = + Line.getTransform(new AffineTransform(0.0, 0.5, -1.0, 0.0, 1.0, 1.5)); Assert.assertEquals(FastMath.atan2(1.0, -2.0), ((Line) t2.apply(l2)).getAngle(), 1.0e-10); @@ -119,11 +118,11 @@ public class LineTest { @Test public void testIntersection() { - Line l1 = new Line(new Point2D( 0, 1), new Point2D(1, 2)); - Line l2 = new Line(new Point2D(-1, 2), new Point2D(2, 1)); - Point2D p = (Point2D) l1.intersection(l2); - Assert.assertEquals(0.5, p.x, 1.0e-10); - Assert.assertEquals(1.5, p.y, 1.0e-10); + Line l1 = new Line(new Vector2D( 0, 1), new Vector2D(1, 2)); + Line l2 = new Line(new Vector2D(-1, 2), new Vector2D(2, 1)); + Vector2D p = (Vector2D) l1.intersection(l2); + Assert.assertEquals(0.5, p.getX(), 1.0e-10); + Assert.assertEquals(1.5, p.getY(), 1.0e-10); } } diff --git a/src/test/java/org/apache/commons/math/geometry/euclidean/twod/PolygonsSetTest.java b/src/test/java/org/apache/commons/math/geometry/euclidean/twod/PolygonsSetTest.java index df2c704da..8bae8944d 100644 --- a/src/test/java/org/apache/commons/math/geometry/euclidean/twod/PolygonsSetTest.java +++ b/src/test/java/org/apache/commons/math/geometry/euclidean/twod/PolygonsSetTest.java @@ -21,12 +21,13 @@ import java.util.List; import org.apache.commons.math.geometry.euclidean.oned.Interval; import org.apache.commons.math.geometry.euclidean.oned.IntervalsSet; -import org.apache.commons.math.geometry.euclidean.oned.Point1D; +import org.apache.commons.math.geometry.euclidean.oned.Vector1D; import org.apache.commons.math.geometry.euclidean.twod.Line; -import org.apache.commons.math.geometry.euclidean.twod.Point2D; +import org.apache.commons.math.geometry.euclidean.twod.Vector2D; import org.apache.commons.math.geometry.euclidean.twod.PolygonsSet; import org.apache.commons.math.geometry.partitioning.BSPTree; import org.apache.commons.math.geometry.partitioning.Region; +import org.apache.commons.math.geometry.partitioning.RegionFactory; import org.apache.commons.math.geometry.partitioning.SubHyperplane; import org.apache.commons.math.util.FastMath; import org.junit.Assert; @@ -36,59 +37,59 @@ public class PolygonsSetTest { @Test public void testSimplyConnected() { - Point2D[][] vertices = new Point2D[][] { - new Point2D[] { - new Point2D(36.0, 22.0), - new Point2D(39.0, 32.0), - new Point2D(19.0, 32.0), - new Point2D( 6.0, 16.0), - new Point2D(31.0, 10.0), - new Point2D(42.0, 16.0), - new Point2D(34.0, 20.0), - new Point2D(29.0, 19.0), - new Point2D(23.0, 22.0), - new Point2D(33.0, 25.0) + Vector2D[][] vertices = new Vector2D[][] { + new Vector2D[] { + new Vector2D(36.0, 22.0), + new Vector2D(39.0, 32.0), + new Vector2D(19.0, 32.0), + new Vector2D( 6.0, 16.0), + new Vector2D(31.0, 10.0), + new Vector2D(42.0, 16.0), + new Vector2D(34.0, 20.0), + new Vector2D(29.0, 19.0), + new Vector2D(23.0, 22.0), + new Vector2D(33.0, 25.0) } }; PolygonsSet set = buildSet(vertices); - Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Point2D(50.0, 30.0))); - checkPoints(Region.Location.INSIDE, set, new Point2D[] { - new Point2D(30.0, 15.0), - new Point2D(15.0, 20.0), - new Point2D(24.0, 25.0), - new Point2D(35.0, 30.0), - new Point2D(19.0, 17.0) + Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Vector2D(50.0, 30.0))); + checkPoints(Region.Location.INSIDE, set, new Vector2D[] { + new Vector2D(30.0, 15.0), + new Vector2D(15.0, 20.0), + new Vector2D(24.0, 25.0), + new Vector2D(35.0, 30.0), + new Vector2D(19.0, 17.0) }); - checkPoints(Region.Location.OUTSIDE, set, new Point2D[] { - new Point2D(50.0, 30.0), - new Point2D(30.0, 35.0), - new Point2D(10.0, 25.0), - new Point2D(10.0, 10.0), - new Point2D(40.0, 10.0), - new Point2D(50.0, 15.0), - new Point2D(30.0, 22.0) + checkPoints(Region.Location.OUTSIDE, set, new Vector2D[] { + new Vector2D(50.0, 30.0), + new Vector2D(30.0, 35.0), + new Vector2D(10.0, 25.0), + new Vector2D(10.0, 10.0), + new Vector2D(40.0, 10.0), + new Vector2D(50.0, 15.0), + new Vector2D(30.0, 22.0) }); - checkPoints(Region.Location.BOUNDARY, set, new Point2D[] { - new Point2D(30.0, 32.0), - new Point2D(34.0, 20.0) + checkPoints(Region.Location.BOUNDARY, set, new Vector2D[] { + new Vector2D(30.0, 32.0), + new Vector2D(34.0, 20.0) }); checkVertices(set.getVertices(), vertices); } @Test public void testStair() { - Point2D[][] vertices = new Point2D[][] { - new Point2D[] { - new Point2D( 0.0, 0.0), - new Point2D( 0.0, 2.0), - new Point2D(-0.1, 2.0), - new Point2D(-0.1, 1.0), - new Point2D(-0.3, 1.0), - new Point2D(-0.3, 1.5), - new Point2D(-1.3, 1.5), - new Point2D(-1.3, 2.0), - new Point2D(-1.8, 2.0), - new Point2D(-1.8 - 1.0 / FastMath.sqrt(2.0), + Vector2D[][] vertices = new Vector2D[][] { + new Vector2D[] { + new Vector2D( 0.0, 0.0), + new Vector2D( 0.0, 2.0), + new Vector2D(-0.1, 2.0), + new Vector2D(-0.1, 1.0), + new Vector2D(-0.3, 1.0), + new Vector2D(-0.3, 1.5), + new Vector2D(-1.3, 1.5), + new Vector2D(-1.3, 2.0), + new Vector2D(-1.8, 2.0), + new Vector2D(-1.8 - 1.0 / FastMath.sqrt(2.0), 2.0 - 1.0 / FastMath.sqrt(2.0)) } }; @@ -102,91 +103,91 @@ public class PolygonsSetTest { @Test public void testHole() { - Point2D[][] vertices = new Point2D[][] { - new Point2D[] { - new Point2D(0.0, 0.0), - new Point2D(3.0, 0.0), - new Point2D(3.0, 3.0), - new Point2D(0.0, 3.0) - }, new Point2D[] { - new Point2D(1.0, 2.0), - new Point2D(2.0, 2.0), - new Point2D(2.0, 1.0), - new Point2D(1.0, 1.0) + Vector2D[][] vertices = new Vector2D[][] { + new Vector2D[] { + new Vector2D(0.0, 0.0), + new Vector2D(3.0, 0.0), + new Vector2D(3.0, 3.0), + new Vector2D(0.0, 3.0) + }, new Vector2D[] { + new Vector2D(1.0, 2.0), + new Vector2D(2.0, 2.0), + new Vector2D(2.0, 1.0), + new Vector2D(1.0, 1.0) } }; PolygonsSet set = buildSet(vertices); - checkPoints(Region.Location.INSIDE, set, new Point2D[] { - new Point2D(0.5, 0.5), - new Point2D(1.5, 0.5), - new Point2D(2.5, 0.5), - new Point2D(0.5, 1.5), - new Point2D(2.5, 1.5), - new Point2D(0.5, 2.5), - new Point2D(1.5, 2.5), - new Point2D(2.5, 2.5), - new Point2D(0.5, 1.0) + checkPoints(Region.Location.INSIDE, set, new Vector2D[] { + new Vector2D(0.5, 0.5), + new Vector2D(1.5, 0.5), + new Vector2D(2.5, 0.5), + new Vector2D(0.5, 1.5), + new Vector2D(2.5, 1.5), + new Vector2D(0.5, 2.5), + new Vector2D(1.5, 2.5), + new Vector2D(2.5, 2.5), + new Vector2D(0.5, 1.0) }); - checkPoints(Region.Location.OUTSIDE, set, new Point2D[] { - new Point2D(1.5, 1.5), - new Point2D(3.5, 1.0), - new Point2D(4.0, 1.5), - new Point2D(6.0, 6.0) + checkPoints(Region.Location.OUTSIDE, set, new Vector2D[] { + new Vector2D(1.5, 1.5), + new Vector2D(3.5, 1.0), + new Vector2D(4.0, 1.5), + new Vector2D(6.0, 6.0) }); - checkPoints(Region.Location.BOUNDARY, set, new Point2D[] { - new Point2D(1.0, 1.0), - new Point2D(1.5, 0.0), - new Point2D(1.5, 1.0), - new Point2D(1.5, 2.0), - new Point2D(1.5, 3.0), - new Point2D(3.0, 3.0) + checkPoints(Region.Location.BOUNDARY, set, new Vector2D[] { + new Vector2D(1.0, 1.0), + new Vector2D(1.5, 0.0), + new Vector2D(1.5, 1.0), + new Vector2D(1.5, 2.0), + new Vector2D(1.5, 3.0), + new Vector2D(3.0, 3.0) }); checkVertices(set.getVertices(), vertices); } @Test public void testDisjointPolygons() { - Point2D[][] vertices = new Point2D[][] { - new Point2D[] { - new Point2D(0.0, 1.0), - new Point2D(2.0, 1.0), - new Point2D(1.0, 2.0) - }, new Point2D[] { - new Point2D(4.0, 0.0), - new Point2D(5.0, 1.0), - new Point2D(3.0, 1.0) + Vector2D[][] vertices = new Vector2D[][] { + new Vector2D[] { + new Vector2D(0.0, 1.0), + new Vector2D(2.0, 1.0), + new Vector2D(1.0, 2.0) + }, new Vector2D[] { + new Vector2D(4.0, 0.0), + new Vector2D(5.0, 1.0), + new Vector2D(3.0, 1.0) } }; PolygonsSet set = buildSet(vertices); - Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Point2D(1.0, 1.5))); - checkPoints(Region.Location.INSIDE, set, new Point2D[] { - new Point2D(1.0, 1.5), - new Point2D(4.5, 0.8) + Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Vector2D(1.0, 1.5))); + checkPoints(Region.Location.INSIDE, set, new Vector2D[] { + new Vector2D(1.0, 1.5), + new Vector2D(4.5, 0.8) }); - checkPoints(Region.Location.OUTSIDE, set, new Point2D[] { - new Point2D(1.0, 0.0), - new Point2D(3.5, 1.2), - new Point2D(2.5, 1.0), - new Point2D(3.0, 4.0) + checkPoints(Region.Location.OUTSIDE, set, new Vector2D[] { + new Vector2D(1.0, 0.0), + new Vector2D(3.5, 1.2), + new Vector2D(2.5, 1.0), + new Vector2D(3.0, 4.0) }); - checkPoints(Region.Location.BOUNDARY, set, new Point2D[] { - new Point2D(1.0, 1.0), - new Point2D(3.5, 0.5), - new Point2D(0.0, 1.0) + checkPoints(Region.Location.BOUNDARY, set, new Vector2D[] { + new Vector2D(1.0, 1.0), + new Vector2D(3.5, 0.5), + new Vector2D(0.0, 1.0) }); checkVertices(set.getVertices(), vertices); } @Test public void testOppositeHyperplanes() { - Point2D[][] vertices = new Point2D[][] { - new Point2D[] { - new Point2D(1.0, 0.0), - new Point2D(2.0, 1.0), - new Point2D(3.0, 1.0), - new Point2D(2.0, 2.0), - new Point2D(1.0, 1.0), - new Point2D(0.0, 1.0) + Vector2D[][] vertices = new Vector2D[][] { + new Vector2D[] { + new Vector2D(1.0, 0.0), + new Vector2D(2.0, 1.0), + new Vector2D(3.0, 1.0), + new Vector2D(2.0, 2.0), + new Vector2D(1.0, 1.0), + new Vector2D(0.0, 1.0) } }; PolygonsSet set = buildSet(vertices); @@ -195,16 +196,16 @@ public class PolygonsSetTest { @Test public void testSingularPoint() { - Point2D[][] vertices = new Point2D[][] { - new Point2D[] { - new Point2D( 0.0, 0.0), - new Point2D( 1.0, 0.0), - new Point2D( 1.0, 1.0), - new Point2D( 0.0, 1.0), - new Point2D( 0.0, 0.0), - new Point2D(-1.0, 0.0), - new Point2D(-1.0, -1.0), - new Point2D( 0.0, -1.0) + Vector2D[][] vertices = new Vector2D[][] { + new Vector2D[] { + new Vector2D( 0.0, 0.0), + new Vector2D( 1.0, 0.0), + new Vector2D( 1.0, 1.0), + new Vector2D( 0.0, 1.0), + new Vector2D( 0.0, 0.0), + new Vector2D(-1.0, 0.0), + new Vector2D(-1.0, -1.0), + new Vector2D( 0.0, -1.0) } }; PolygonsSet set = buildSet(vertices); @@ -213,48 +214,48 @@ public class PolygonsSetTest { @Test public void testLineIntersection() { - Point2D[][] vertices = new Point2D[][] { - new Point2D[] { - new Point2D( 0.0, 0.0), - new Point2D( 2.0, 0.0), - new Point2D( 2.0, 1.0), - new Point2D( 3.0, 1.0), - new Point2D( 3.0, 3.0), - new Point2D( 1.0, 3.0), - new Point2D( 1.0, 2.0), - new Point2D( 0.0, 2.0) + Vector2D[][] vertices = new Vector2D[][] { + new Vector2D[] { + new Vector2D( 0.0, 0.0), + new Vector2D( 2.0, 0.0), + new Vector2D( 2.0, 1.0), + new Vector2D( 3.0, 1.0), + new Vector2D( 3.0, 3.0), + new Vector2D( 1.0, 3.0), + new Vector2D( 1.0, 2.0), + new Vector2D( 0.0, 2.0) } }; PolygonsSet set = buildSet(vertices); - Line l1 = new Line(new Point2D(-1.5, 0.0), FastMath.PI / 4); - SubHyperplane s1 = set.intersection(new SubHyperplane(l1)); + Line l1 = new Line(new Vector2D(-1.5, 0.0), FastMath.PI / 4); + SubLine s1 = (SubLine) set.intersection(l1.wholeHyperplane()); List i1 = ((IntervalsSet) s1.getRemainingRegion()).asList(); Assert.assertEquals(2, i1.size()); Interval v10 = (Interval) i1.get(0); - Point2D p10Lower = (Point2D) l1.toSpace(new Point1D(v10.getLower())); + Vector2D p10Lower = (Vector2D) l1.toSpace(new Vector1D(v10.getLower())); Assert.assertEquals(0.0, p10Lower.getX(), 1.0e-10); Assert.assertEquals(1.5, p10Lower.getY(), 1.0e-10); - Point2D p10Upper = (Point2D) l1.toSpace(new Point1D(v10.getUpper())); + Vector2D p10Upper = (Vector2D) l1.toSpace(new Vector1D(v10.getUpper())); Assert.assertEquals(0.5, p10Upper.getX(), 1.0e-10); Assert.assertEquals(2.0, p10Upper.getY(), 1.0e-10); Interval v11 = (Interval) i1.get(1); - Point2D p11Lower = (Point2D) l1.toSpace(new Point1D(v11.getLower())); + Vector2D p11Lower = (Vector2D) l1.toSpace(new Vector1D(v11.getLower())); Assert.assertEquals(1.0, p11Lower.getX(), 1.0e-10); Assert.assertEquals(2.5, p11Lower.getY(), 1.0e-10); - Point2D p11Upper = (Point2D) l1.toSpace(new Point1D(v11.getUpper())); + Vector2D p11Upper = (Vector2D) l1.toSpace(new Vector1D(v11.getUpper())); Assert.assertEquals(1.5, p11Upper.getX(), 1.0e-10); Assert.assertEquals(3.0, p11Upper.getY(), 1.0e-10); - Line l2 = new Line(new Point2D(-1.0, 2.0), 0); - SubHyperplane s2 = set.intersection(new SubHyperplane(l2)); + Line l2 = new Line(new Vector2D(-1.0, 2.0), 0); + SubLine s2 = (SubLine) set.intersection(l2.wholeHyperplane()); List i2 = ((IntervalsSet) s2.getRemainingRegion()).asList(); Assert.assertEquals(1, i2.size()); Interval v20 = (Interval) i2.get(0); - Point2D p20Lower = (Point2D) l2.toSpace(new Point1D(v20.getLower())); + Vector2D p20Lower = (Vector2D) l2.toSpace(new Vector1D(v20.getLower())); Assert.assertEquals(1.0, p20Lower.getX(), 1.0e-10); Assert.assertEquals(2.0, p20Lower.getY(), 1.0e-10); - Point2D p20Upper = (Point2D) l2.toSpace(new Point1D(v20.getUpper())); + Vector2D p20Upper = (Vector2D) l2.toSpace(new Vector1D(v20.getUpper())); Assert.assertEquals(3.0, p20Upper.getX(), 1.0e-10); Assert.assertEquals(2.0, p20Upper.getY(), 1.0e-10); @@ -262,37 +263,38 @@ public class PolygonsSetTest { @Test public void testUnlimitedSubHyperplane() { - Point2D[][] vertices1 = new Point2D[][] { - new Point2D[] { - new Point2D(0.0, 0.0), - new Point2D(4.0, 0.0), - new Point2D(1.4, 1.5), - new Point2D(0.0, 3.5) + Vector2D[][] vertices1 = new Vector2D[][] { + new Vector2D[] { + new Vector2D(0.0, 0.0), + new Vector2D(4.0, 0.0), + new Vector2D(1.4, 1.5), + new Vector2D(0.0, 3.5) } }; PolygonsSet set1 = buildSet(vertices1); - Point2D[][] vertices2 = new Point2D[][] { - new Point2D[] { - new Point2D(1.4, 0.2), - new Point2D(2.8, -1.2), - new Point2D(2.5, 0.6) + Vector2D[][] vertices2 = new Vector2D[][] { + new Vector2D[] { + new Vector2D(1.4, 0.2), + new Vector2D(2.8, -1.2), + new Vector2D(2.5, 0.6) } }; PolygonsSet set2 = buildSet(vertices2); - PolygonsSet set = (PolygonsSet) Region.union(set1.copySelf(), - set2.copySelf()); + PolygonsSet set = + (PolygonsSet) new RegionFactory().union(set1.copySelf(), + set2.copySelf()); checkVertices(set1.getVertices(), vertices1); checkVertices(set2.getVertices(), vertices2); - checkVertices(set.getVertices(), new Point2D[][] { - new Point2D[] { - new Point2D(0.0, 0.0), - new Point2D(1.6, 0.0), - new Point2D(2.8, -1.2), - new Point2D(2.6, 0.0), - new Point2D(4.0, 0.0), - new Point2D(1.4, 1.5), - new Point2D(0.0, 3.5) + checkVertices(set.getVertices(), new Vector2D[][] { + new Vector2D[] { + new Vector2D(0.0, 0.0), + new Vector2D(1.6, 0.0), + new Vector2D(2.8, -1.2), + new Vector2D(2.6, 0.0), + new Vector2D(4.0, 0.0), + new Vector2D(1.4, 1.5), + new Vector2D(0.0, 3.5) } }); @@ -300,306 +302,306 @@ public class PolygonsSetTest { @Test public void testUnion() { - Point2D[][] vertices1 = new Point2D[][] { - new Point2D[] { - new Point2D( 0.0, 0.0), - new Point2D( 2.0, 0.0), - new Point2D( 2.0, 2.0), - new Point2D( 0.0, 2.0) + Vector2D[][] vertices1 = new Vector2D[][] { + new Vector2D[] { + new Vector2D( 0.0, 0.0), + new Vector2D( 2.0, 0.0), + new Vector2D( 2.0, 2.0), + new Vector2D( 0.0, 2.0) } }; PolygonsSet set1 = buildSet(vertices1); - Point2D[][] vertices2 = new Point2D[][] { - new Point2D[] { - new Point2D( 1.0, 1.0), - new Point2D( 3.0, 1.0), - new Point2D( 3.0, 3.0), - new Point2D( 1.0, 3.0) + Vector2D[][] vertices2 = new Vector2D[][] { + new Vector2D[] { + new Vector2D( 1.0, 1.0), + new Vector2D( 3.0, 1.0), + new Vector2D( 3.0, 3.0), + new Vector2D( 1.0, 3.0) } }; PolygonsSet set2 = buildSet(vertices2); - PolygonsSet set = (PolygonsSet) Region.union(set1.copySelf(), - set2.copySelf()); + PolygonsSet set = (PolygonsSet) new RegionFactory().union(set1.copySelf(), + set2.copySelf()); checkVertices(set1.getVertices(), vertices1); checkVertices(set2.getVertices(), vertices2); - checkVertices(set.getVertices(), new Point2D[][] { - new Point2D[] { - new Point2D( 0.0, 0.0), - new Point2D( 2.0, 0.0), - new Point2D( 2.0, 1.0), - new Point2D( 3.0, 1.0), - new Point2D( 3.0, 3.0), - new Point2D( 1.0, 3.0), - new Point2D( 1.0, 2.0), - new Point2D( 0.0, 2.0) + checkVertices(set.getVertices(), new Vector2D[][] { + new Vector2D[] { + new Vector2D( 0.0, 0.0), + new Vector2D( 2.0, 0.0), + new Vector2D( 2.0, 1.0), + new Vector2D( 3.0, 1.0), + new Vector2D( 3.0, 3.0), + new Vector2D( 1.0, 3.0), + new Vector2D( 1.0, 2.0), + new Vector2D( 0.0, 2.0) } }); - checkPoints(Region.Location.INSIDE, set, new Point2D[] { - new Point2D(1.0, 1.0), - new Point2D(0.5, 0.5), - new Point2D(2.0, 2.0), - new Point2D(2.5, 2.5), - new Point2D(0.5, 1.5), - new Point2D(1.5, 1.5), - new Point2D(1.5, 0.5), - new Point2D(1.5, 2.5), - new Point2D(2.5, 1.5), - new Point2D(2.5, 2.5) + checkPoints(Region.Location.INSIDE, set, new Vector2D[] { + new Vector2D(1.0, 1.0), + new Vector2D(0.5, 0.5), + new Vector2D(2.0, 2.0), + new Vector2D(2.5, 2.5), + new Vector2D(0.5, 1.5), + new Vector2D(1.5, 1.5), + new Vector2D(1.5, 0.5), + new Vector2D(1.5, 2.5), + new Vector2D(2.5, 1.5), + new Vector2D(2.5, 2.5) }); - checkPoints(Region.Location.OUTSIDE, set, new Point2D[] { - new Point2D(-0.5, 0.5), - new Point2D( 0.5, 2.5), - new Point2D( 2.5, 0.5), - new Point2D( 3.5, 2.5) + checkPoints(Region.Location.OUTSIDE, set, new Vector2D[] { + new Vector2D(-0.5, 0.5), + new Vector2D( 0.5, 2.5), + new Vector2D( 2.5, 0.5), + new Vector2D( 3.5, 2.5) }); - checkPoints(Region.Location.BOUNDARY, set, new Point2D[] { - new Point2D(0.0, 0.0), - new Point2D(0.5, 2.0), - new Point2D(2.0, 0.5), - new Point2D(2.5, 1.0), - new Point2D(3.0, 2.5) + checkPoints(Region.Location.BOUNDARY, set, new Vector2D[] { + new Vector2D(0.0, 0.0), + new Vector2D(0.5, 2.0), + new Vector2D(2.0, 0.5), + new Vector2D(2.5, 1.0), + new Vector2D(3.0, 2.5) }); } @Test public void testIntersection() { - Point2D[][] vertices1 = new Point2D[][] { - new Point2D[] { - new Point2D( 0.0, 0.0), - new Point2D( 2.0, 0.0), - new Point2D( 2.0, 2.0), - new Point2D( 0.0, 2.0) + Vector2D[][] vertices1 = new Vector2D[][] { + new Vector2D[] { + new Vector2D( 0.0, 0.0), + new Vector2D( 2.0, 0.0), + new Vector2D( 2.0, 2.0), + new Vector2D( 0.0, 2.0) } }; PolygonsSet set1 = buildSet(vertices1); - Point2D[][] vertices2 = new Point2D[][] { - new Point2D[] { - new Point2D( 1.0, 1.0), - new Point2D( 3.0, 1.0), - new Point2D( 3.0, 3.0), - new Point2D( 1.0, 3.0) + Vector2D[][] vertices2 = new Vector2D[][] { + new Vector2D[] { + new Vector2D( 1.0, 1.0), + new Vector2D( 3.0, 1.0), + new Vector2D( 3.0, 3.0), + new Vector2D( 1.0, 3.0) } }; PolygonsSet set2 = buildSet(vertices2); - PolygonsSet set = (PolygonsSet) Region.intersection(set1.copySelf(), - set2.copySelf()); + PolygonsSet set = (PolygonsSet) new RegionFactory().intersection(set1.copySelf(), + set2.copySelf()); checkVertices(set1.getVertices(), vertices1); checkVertices(set2.getVertices(), vertices2); - checkVertices(set.getVertices(), new Point2D[][] { - new Point2D[] { - new Point2D( 1.0, 1.0), - new Point2D( 2.0, 1.0), - new Point2D( 2.0, 2.0), - new Point2D( 1.0, 2.0) + checkVertices(set.getVertices(), new Vector2D[][] { + new Vector2D[] { + new Vector2D( 1.0, 1.0), + new Vector2D( 2.0, 1.0), + new Vector2D( 2.0, 2.0), + new Vector2D( 1.0, 2.0) } }); - checkPoints(Region.Location.INSIDE, set, new Point2D[] { - new Point2D(1.5, 1.5) + checkPoints(Region.Location.INSIDE, set, new Vector2D[] { + new Vector2D(1.5, 1.5) }); - checkPoints(Region.Location.OUTSIDE, set, new Point2D[] { - new Point2D(0.5, 1.5), - new Point2D(2.5, 1.5), - new Point2D(1.5, 0.5), - new Point2D(0.5, 0.5) + checkPoints(Region.Location.OUTSIDE, set, new Vector2D[] { + new Vector2D(0.5, 1.5), + new Vector2D(2.5, 1.5), + new Vector2D(1.5, 0.5), + new Vector2D(0.5, 0.5) }); - checkPoints(Region.Location.BOUNDARY, set, new Point2D[] { - new Point2D(1.0, 1.0), - new Point2D(2.0, 2.0), - new Point2D(1.0, 1.5), - new Point2D(1.5, 2.0) + checkPoints(Region.Location.BOUNDARY, set, new Vector2D[] { + new Vector2D(1.0, 1.0), + new Vector2D(2.0, 2.0), + new Vector2D(1.0, 1.5), + new Vector2D(1.5, 2.0) }); } @Test public void testXor() { - Point2D[][] vertices1 = new Point2D[][] { - new Point2D[] { - new Point2D( 0.0, 0.0), - new Point2D( 2.0, 0.0), - new Point2D( 2.0, 2.0), - new Point2D( 0.0, 2.0) + Vector2D[][] vertices1 = new Vector2D[][] { + new Vector2D[] { + new Vector2D( 0.0, 0.0), + new Vector2D( 2.0, 0.0), + new Vector2D( 2.0, 2.0), + new Vector2D( 0.0, 2.0) } }; PolygonsSet set1 = buildSet(vertices1); - Point2D[][] vertices2 = new Point2D[][] { - new Point2D[] { - new Point2D( 1.0, 1.0), - new Point2D( 3.0, 1.0), - new Point2D( 3.0, 3.0), - new Point2D( 1.0, 3.0) + Vector2D[][] vertices2 = new Vector2D[][] { + new Vector2D[] { + new Vector2D( 1.0, 1.0), + new Vector2D( 3.0, 1.0), + new Vector2D( 3.0, 3.0), + new Vector2D( 1.0, 3.0) } }; PolygonsSet set2 = buildSet(vertices2); - PolygonsSet set = (PolygonsSet) Region.xor(set1.copySelf(), - set2.copySelf()); + PolygonsSet set = (PolygonsSet) new RegionFactory().xor(set1.copySelf(), + set2.copySelf()); checkVertices(set1.getVertices(), vertices1); checkVertices(set2.getVertices(), vertices2); - checkVertices(set.getVertices(), new Point2D[][] { - new Point2D[] { - new Point2D( 0.0, 0.0), - new Point2D( 2.0, 0.0), - new Point2D( 2.0, 1.0), - new Point2D( 3.0, 1.0), - new Point2D( 3.0, 3.0), - new Point2D( 1.0, 3.0), - new Point2D( 1.0, 2.0), - new Point2D( 0.0, 2.0) + checkVertices(set.getVertices(), new Vector2D[][] { + new Vector2D[] { + new Vector2D( 0.0, 0.0), + new Vector2D( 2.0, 0.0), + new Vector2D( 2.0, 1.0), + new Vector2D( 3.0, 1.0), + new Vector2D( 3.0, 3.0), + new Vector2D( 1.0, 3.0), + new Vector2D( 1.0, 2.0), + new Vector2D( 0.0, 2.0) }, - new Point2D[] { - new Point2D( 1.0, 1.0), - new Point2D( 1.0, 2.0), - new Point2D( 2.0, 2.0), - new Point2D( 2.0, 1.0) + new Vector2D[] { + new Vector2D( 1.0, 1.0), + new Vector2D( 1.0, 2.0), + new Vector2D( 2.0, 2.0), + new Vector2D( 2.0, 1.0) } }); - checkPoints(Region.Location.INSIDE, set, new Point2D[] { - new Point2D(0.5, 0.5), - new Point2D(2.5, 2.5), - new Point2D(0.5, 1.5), - new Point2D(1.5, 0.5), - new Point2D(1.5, 2.5), - new Point2D(2.5, 1.5), - new Point2D(2.5, 2.5) + checkPoints(Region.Location.INSIDE, set, new Vector2D[] { + new Vector2D(0.5, 0.5), + new Vector2D(2.5, 2.5), + new Vector2D(0.5, 1.5), + new Vector2D(1.5, 0.5), + new Vector2D(1.5, 2.5), + new Vector2D(2.5, 1.5), + new Vector2D(2.5, 2.5) }); - checkPoints(Region.Location.OUTSIDE, set, new Point2D[] { - new Point2D(-0.5, 0.5), - new Point2D( 0.5, 2.5), - new Point2D( 2.5, 0.5), - new Point2D( 1.5, 1.5), - new Point2D( 3.5, 2.5) + checkPoints(Region.Location.OUTSIDE, set, new Vector2D[] { + new Vector2D(-0.5, 0.5), + new Vector2D( 0.5, 2.5), + new Vector2D( 2.5, 0.5), + new Vector2D( 1.5, 1.5), + new Vector2D( 3.5, 2.5) }); - checkPoints(Region.Location.BOUNDARY, set, new Point2D[] { - new Point2D(1.0, 1.0), - new Point2D(2.0, 2.0), - new Point2D(1.5, 1.0), - new Point2D(2.0, 1.5), - new Point2D(0.0, 0.0), - new Point2D(0.5, 2.0), - new Point2D(2.0, 0.5), - new Point2D(2.5, 1.0), - new Point2D(3.0, 2.5) + checkPoints(Region.Location.BOUNDARY, set, new Vector2D[] { + new Vector2D(1.0, 1.0), + new Vector2D(2.0, 2.0), + new Vector2D(1.5, 1.0), + new Vector2D(2.0, 1.5), + new Vector2D(0.0, 0.0), + new Vector2D(0.5, 2.0), + new Vector2D(2.0, 0.5), + new Vector2D(2.5, 1.0), + new Vector2D(3.0, 2.5) }); } @Test public void testDifference() { - Point2D[][] vertices1 = new Point2D[][] { - new Point2D[] { - new Point2D( 0.0, 0.0), - new Point2D( 2.0, 0.0), - new Point2D( 2.0, 2.0), - new Point2D( 0.0, 2.0) + Vector2D[][] vertices1 = new Vector2D[][] { + new Vector2D[] { + new Vector2D( 0.0, 0.0), + new Vector2D( 2.0, 0.0), + new Vector2D( 2.0, 2.0), + new Vector2D( 0.0, 2.0) } }; PolygonsSet set1 = buildSet(vertices1); - Point2D[][] vertices2 = new Point2D[][] { - new Point2D[] { - new Point2D( 1.0, 1.0), - new Point2D( 3.0, 1.0), - new Point2D( 3.0, 3.0), - new Point2D( 1.0, 3.0) + Vector2D[][] vertices2 = new Vector2D[][] { + new Vector2D[] { + new Vector2D( 1.0, 1.0), + new Vector2D( 3.0, 1.0), + new Vector2D( 3.0, 3.0), + new Vector2D( 1.0, 3.0) } }; PolygonsSet set2 = buildSet(vertices2); - PolygonsSet set = (PolygonsSet) Region.difference(set1.copySelf(), - set2.copySelf()); + PolygonsSet set = (PolygonsSet) new RegionFactory().difference(set1.copySelf(), + set2.copySelf()); checkVertices(set1.getVertices(), vertices1); checkVertices(set2.getVertices(), vertices2); - checkVertices(set.getVertices(), new Point2D[][] { - new Point2D[] { - new Point2D( 0.0, 0.0), - new Point2D( 2.0, 0.0), - new Point2D( 2.0, 1.0), - new Point2D( 1.0, 1.0), - new Point2D( 1.0, 2.0), - new Point2D( 0.0, 2.0) + checkVertices(set.getVertices(), new Vector2D[][] { + new Vector2D[] { + new Vector2D( 0.0, 0.0), + new Vector2D( 2.0, 0.0), + new Vector2D( 2.0, 1.0), + new Vector2D( 1.0, 1.0), + new Vector2D( 1.0, 2.0), + new Vector2D( 0.0, 2.0) } }); - checkPoints(Region.Location.INSIDE, set, new Point2D[] { - new Point2D(0.5, 0.5), - new Point2D(0.5, 1.5), - new Point2D(1.5, 0.5) + checkPoints(Region.Location.INSIDE, set, new Vector2D[] { + new Vector2D(0.5, 0.5), + new Vector2D(0.5, 1.5), + new Vector2D(1.5, 0.5) }); - checkPoints(Region.Location.OUTSIDE, set, new Point2D[] { - new Point2D( 2.5, 2.5), - new Point2D(-0.5, 0.5), - new Point2D( 0.5, 2.5), - new Point2D( 2.5, 0.5), - new Point2D( 1.5, 1.5), - new Point2D( 3.5, 2.5), - new Point2D( 1.5, 2.5), - new Point2D( 2.5, 1.5), - new Point2D( 2.0, 1.5), - new Point2D( 2.0, 2.0), - new Point2D( 2.5, 1.0), - new Point2D( 2.5, 2.5), - new Point2D( 3.0, 2.5) + checkPoints(Region.Location.OUTSIDE, set, new Vector2D[] { + new Vector2D( 2.5, 2.5), + new Vector2D(-0.5, 0.5), + new Vector2D( 0.5, 2.5), + new Vector2D( 2.5, 0.5), + new Vector2D( 1.5, 1.5), + new Vector2D( 3.5, 2.5), + new Vector2D( 1.5, 2.5), + new Vector2D( 2.5, 1.5), + new Vector2D( 2.0, 1.5), + new Vector2D( 2.0, 2.0), + new Vector2D( 2.5, 1.0), + new Vector2D( 2.5, 2.5), + new Vector2D( 3.0, 2.5) }); - checkPoints(Region.Location.BOUNDARY, set, new Point2D[] { - new Point2D(1.0, 1.0), - new Point2D(1.5, 1.0), - new Point2D(0.0, 0.0), - new Point2D(0.5, 2.0), - new Point2D(2.0, 0.5) + checkPoints(Region.Location.BOUNDARY, set, new Vector2D[] { + new Vector2D(1.0, 1.0), + new Vector2D(1.5, 1.0), + new Vector2D(0.0, 0.0), + new Vector2D(0.5, 2.0), + new Vector2D(2.0, 0.5) }); } @Test public void testEmptyDifference() { - Point2D[][] vertices1 = new Point2D[][] { - new Point2D[] { - new Point2D( 0.5, 3.5), - new Point2D( 0.5, 4.5), - new Point2D(-0.5, 4.5), - new Point2D(-0.5, 3.5) + Vector2D[][] vertices1 = new Vector2D[][] { + new Vector2D[] { + new Vector2D( 0.5, 3.5), + new Vector2D( 0.5, 4.5), + new Vector2D(-0.5, 4.5), + new Vector2D(-0.5, 3.5) } }; PolygonsSet set1 = buildSet(vertices1); - Point2D[][] vertices2 = new Point2D[][] { - new Point2D[] { - new Point2D( 1.0, 2.0), - new Point2D( 1.0, 8.0), - new Point2D(-1.0, 8.0), - new Point2D(-1.0, 2.0) + Vector2D[][] vertices2 = new Vector2D[][] { + new Vector2D[] { + new Vector2D( 1.0, 2.0), + new Vector2D( 1.0, 8.0), + new Vector2D(-1.0, 8.0), + new Vector2D(-1.0, 2.0) } }; PolygonsSet set2 = buildSet(vertices2); - Assert.assertTrue(Region.difference(set1.copySelf(), set2.copySelf()).isEmpty()); + Assert.assertTrue(new RegionFactory().difference(set1.copySelf(), set2.copySelf()).isEmpty()); } @Test public void testChoppedHexagon() { double pi6 = FastMath.PI / 6.0; double sqrt3 = FastMath.sqrt(3.0); - SubHyperplane[] hyp = { - new SubHyperplane(new Line(new Point2D( 0.0, 1.0), 5 * pi6)), - new SubHyperplane(new Line(new Point2D(-sqrt3, 1.0), 7 * pi6)), - new SubHyperplane(new Line(new Point2D(-sqrt3, 1.0), 9 * pi6)), - new SubHyperplane(new Line(new Point2D(-sqrt3, 0.0), 11 * pi6)), - new SubHyperplane(new Line(new Point2D( 0.0, 0.0), 13 * pi6)), - new SubHyperplane(new Line(new Point2D( 0.0, 1.0), 3 * pi6)), - new SubHyperplane(new Line(new Point2D(-5.0 * sqrt3 / 6.0, 0.0), 9 * pi6)) + SubLine[] hyp = { + new Line(new Vector2D( 0.0, 1.0), 5 * pi6).wholeHyperplane(), + new Line(new Vector2D(-sqrt3, 1.0), 7 * pi6).wholeHyperplane(), + new Line(new Vector2D(-sqrt3, 1.0), 9 * pi6).wholeHyperplane(), + new Line(new Vector2D(-sqrt3, 0.0), 11 * pi6).wholeHyperplane(), + new Line(new Vector2D( 0.0, 0.0), 13 * pi6).wholeHyperplane(), + new Line(new Vector2D( 0.0, 1.0), 3 * pi6).wholeHyperplane(), + new Line(new Vector2D(-5.0 * sqrt3 / 6.0, 0.0), 9 * pi6).wholeHyperplane() }; - hyp[1] = hyp[0].getHyperplane().split(hyp[1]).getMinus(); - hyp[2] = hyp[1].getHyperplane().split(hyp[2]).getMinus(); - hyp[3] = hyp[2].getHyperplane().split(hyp[3]).getMinus(); - hyp[4] = hyp[0].getHyperplane().split(hyp[3].getHyperplane().split(hyp[4]).getMinus()).getMinus(); - hyp[5] = hyp[0].getHyperplane().split(hyp[4].getHyperplane().split(hyp[5]).getMinus()).getMinus(); - hyp[6] = hyp[1].getHyperplane().split(hyp[3].getHyperplane().split(hyp[6]).getMinus()).getMinus(); - BSPTree tree = new BSPTree(Boolean.TRUE); + hyp[1] = (SubLine) hyp[1].split(hyp[0].getHyperplane()).getMinus(); + hyp[2] = (SubLine) hyp[2].split(hyp[1].getHyperplane()).getMinus(); + hyp[3] = (SubLine) hyp[3].split(hyp[2].getHyperplane()).getMinus(); + hyp[4] = (SubLine) hyp[4].split(hyp[3].getHyperplane()).getMinus().split(hyp[0].getHyperplane()).getMinus(); + hyp[5] = (SubLine) hyp[5].split(hyp[4].getHyperplane()).getMinus().split(hyp[0].getHyperplane()).getMinus(); + hyp[6] = (SubLine) hyp[6].split(hyp[3].getHyperplane()).getMinus().split(hyp[1].getHyperplane()).getMinus(); + BSPTree tree = new BSPTree(Boolean.TRUE); for (int i = hyp.length - 1; i >= 0; --i) { - tree = new BSPTree(hyp[i], new BSPTree(Boolean.FALSE), tree, null); + tree = new BSPTree(hyp[i], new BSPTree(Boolean.FALSE), tree, null); } PolygonsSet set = new PolygonsSet(tree); - SubHyperplane splitter = - new SubHyperplane(new Line(new Point2D(-2.0 * sqrt3 / 3.0, 0.0), 9 * pi6)); + SubLine splitter = + new Line(new Vector2D(-2.0 * sqrt3 / 3.0, 0.0), 9 * pi6).wholeHyperplane(); PolygonsSet slice = - new PolygonsSet(new BSPTree(splitter, - set.getTree(false).split(splitter).getPlus(), - new BSPTree(Boolean.FALSE), null)); + new PolygonsSet(new BSPTree(splitter, + set.getTree(false).split(splitter).getPlus(), + new BSPTree(Boolean.FALSE), null)); Assert.assertEquals(Region.Location.OUTSIDE, - slice.checkPoint(new Point2D(0.1, 0.5))); + slice.checkPoint(new Vector2D(0.1, 0.5))); Assert.assertEquals(11.0 / 3.0, slice.getBoundarySize(), 1.0e-10); } @@ -607,27 +609,27 @@ public class PolygonsSetTest { @Test public void testConcentric() { double h = FastMath.sqrt(3.0) / 2.0; - Point2D[][] vertices1 = new Point2D[][] { - new Point2D[] { - new Point2D( 0.00, 0.1 * h), - new Point2D( 0.05, 0.1 * h), - new Point2D( 0.10, 0.2 * h), - new Point2D( 0.05, 0.3 * h), - new Point2D(-0.05, 0.3 * h), - new Point2D(-0.10, 0.2 * h), - new Point2D(-0.05, 0.1 * h) + Vector2D[][] vertices1 = new Vector2D[][] { + new Vector2D[] { + new Vector2D( 0.00, 0.1 * h), + new Vector2D( 0.05, 0.1 * h), + new Vector2D( 0.10, 0.2 * h), + new Vector2D( 0.05, 0.3 * h), + new Vector2D(-0.05, 0.3 * h), + new Vector2D(-0.10, 0.2 * h), + new Vector2D(-0.05, 0.1 * h) } }; PolygonsSet set1 = buildSet(vertices1); - Point2D[][] vertices2 = new Point2D[][] { - new Point2D[] { - new Point2D( 0.00, 0.0 * h), - new Point2D( 0.10, 0.0 * h), - new Point2D( 0.20, 0.2 * h), - new Point2D( 0.10, 0.4 * h), - new Point2D(-0.10, 0.4 * h), - new Point2D(-0.20, 0.2 * h), - new Point2D(-0.10, 0.0 * h) + Vector2D[][] vertices2 = new Vector2D[][] { + new Vector2D[] { + new Vector2D( 0.00, 0.0 * h), + new Vector2D( 0.10, 0.0 * h), + new Vector2D( 0.20, 0.2 * h), + new Vector2D( 0.10, 0.4 * h), + new Vector2D(-0.10, 0.4 * h), + new Vector2D(-0.20, 0.2 * h), + new Vector2D(-0.10, 0.0 * h) } }; PolygonsSet set2 = buildSet(vertices2); @@ -636,109 +638,127 @@ public class PolygonsSetTest { @Test public void testBug20040520() { - BSPTree a0 = new BSPTree(buildSegment(new Point2D(0.85, -0.05), - new Point2D(0.90, -0.10)), - new BSPTree(Boolean.FALSE), - new BSPTree(Boolean.TRUE), - null); - BSPTree a1 = new BSPTree(buildSegment(new Point2D(0.85, -0.10), - new Point2D(0.90, -0.10)), - new BSPTree(Boolean.FALSE), a0, null); - BSPTree a2 = new BSPTree(buildSegment(new Point2D(0.90, -0.05), - new Point2D(0.85, -0.05)), - new BSPTree(Boolean.FALSE), a1, null); - BSPTree a3 = new BSPTree(buildSegment(new Point2D(0.82, -0.05), - new Point2D(0.82, -0.08)), - new BSPTree(Boolean.FALSE), - new BSPTree(Boolean.TRUE), - null); - BSPTree a4 = new BSPTree(buildHalfLine(new Point2D(0.85, -0.05), - new Point2D(0.80, -0.05), - false), - new BSPTree(Boolean.FALSE), a3, null); - BSPTree a5 = new BSPTree(buildSegment(new Point2D(0.82, -0.08), - new Point2D(0.82, -0.18)), - new BSPTree(Boolean.FALSE), - new BSPTree(Boolean.TRUE), - null); - BSPTree a6 = new BSPTree(buildHalfLine(new Point2D(0.82, -0.18), - new Point2D(0.85, -0.15), - true), - new BSPTree(Boolean.FALSE), a5, null); - BSPTree a7 = new BSPTree(buildHalfLine(new Point2D(0.85, -0.05), - new Point2D(0.82, -0.08), - false), - a4, a6, null); - BSPTree a8 = new BSPTree(buildLine(new Point2D(0.85, -0.25), - new Point2D(0.85, 0.05)), - a2, a7, null); - BSPTree a9 = new BSPTree(buildLine(new Point2D(0.90, 0.05), - new Point2D(0.90, -0.50)), - a8, new BSPTree(Boolean.FALSE), null); + BSPTree a0 = + new BSPTree(buildSegment(new Vector2D(0.85, -0.05), + new Vector2D(0.90, -0.10)), + new BSPTree(Boolean.FALSE), + new BSPTree(Boolean.TRUE), + null); + BSPTree a1 = + new BSPTree(buildSegment(new Vector2D(0.85, -0.10), + new Vector2D(0.90, -0.10)), + new BSPTree(Boolean.FALSE), a0, null); + BSPTree a2 = + new BSPTree(buildSegment(new Vector2D(0.90, -0.05), + new Vector2D(0.85, -0.05)), + new BSPTree(Boolean.FALSE), a1, null); + BSPTree a3 = + new BSPTree(buildSegment(new Vector2D(0.82, -0.05), + new Vector2D(0.82, -0.08)), + new BSPTree(Boolean.FALSE), + new BSPTree(Boolean.TRUE), + null); + BSPTree a4 = + new BSPTree(buildHalfLine(new Vector2D(0.85, -0.05), + new Vector2D(0.80, -0.05), + false), + new BSPTree(Boolean.FALSE), a3, null); + BSPTree a5 = + new BSPTree(buildSegment(new Vector2D(0.82, -0.08), + new Vector2D(0.82, -0.18)), + new BSPTree(Boolean.FALSE), + new BSPTree(Boolean.TRUE), + null); + BSPTree a6 = + new BSPTree(buildHalfLine(new Vector2D(0.82, -0.18), + new Vector2D(0.85, -0.15), + true), + new BSPTree(Boolean.FALSE), a5, null); + BSPTree a7 = + new BSPTree(buildHalfLine(new Vector2D(0.85, -0.05), + new Vector2D(0.82, -0.08), + false), + a4, a6, null); + BSPTree a8 = + new BSPTree(buildLine(new Vector2D(0.85, -0.25), + new Vector2D(0.85, 0.05)), + a2, a7, null); + BSPTree a9 = + new BSPTree(buildLine(new Vector2D(0.90, 0.05), + new Vector2D(0.90, -0.50)), + a8, new BSPTree(Boolean.FALSE), null); - BSPTree b0 = new BSPTree(buildSegment(new Point2D(0.92, -0.12), - new Point2D(0.92, -0.08)), - new BSPTree(Boolean.FALSE), new BSPTree(Boolean.TRUE), - null); - BSPTree b1 = new BSPTree(buildHalfLine(new Point2D(0.92, -0.08), - new Point2D(0.90, -0.10), - true), - new BSPTree(Boolean.FALSE), b0, null); - BSPTree b2 = new BSPTree(buildSegment(new Point2D(0.92, -0.18), - new Point2D(0.92, -0.12)), - new BSPTree(Boolean.FALSE), new BSPTree(Boolean.TRUE), - null); - BSPTree b3 = new BSPTree(buildSegment(new Point2D(0.85, -0.15), - new Point2D(0.90, -0.20)), - new BSPTree(Boolean.FALSE), b2, null); - BSPTree b4 = new BSPTree(buildSegment(new Point2D(0.95, -0.15), - new Point2D(0.85, -0.05)), - b1, b3, null); - BSPTree b5 = new BSPTree(buildHalfLine(new Point2D(0.85, -0.05), - new Point2D(0.85, -0.25), - true), - new BSPTree(Boolean.FALSE), b4, null); - BSPTree b6 = new BSPTree(buildLine(new Point2D(0.0, -1.10), - new Point2D(1.0, -0.10)), - new BSPTree(Boolean.FALSE), b5, null); + BSPTree b0 = + new BSPTree(buildSegment(new Vector2D(0.92, -0.12), + new Vector2D(0.92, -0.08)), + new BSPTree(Boolean.FALSE), new BSPTree(Boolean.TRUE), + null); + BSPTree b1 = + new BSPTree(buildHalfLine(new Vector2D(0.92, -0.08), + new Vector2D(0.90, -0.10), + true), + new BSPTree(Boolean.FALSE), b0, null); + BSPTree b2 = + new BSPTree(buildSegment(new Vector2D(0.92, -0.18), + new Vector2D(0.92, -0.12)), + new BSPTree(Boolean.FALSE), new BSPTree(Boolean.TRUE), + null); + BSPTree b3 = + new BSPTree(buildSegment(new Vector2D(0.85, -0.15), + new Vector2D(0.90, -0.20)), + new BSPTree(Boolean.FALSE), b2, null); + BSPTree b4 = + new BSPTree(buildSegment(new Vector2D(0.95, -0.15), + new Vector2D(0.85, -0.05)), + b1, b3, null); + BSPTree b5 = + new BSPTree(buildHalfLine(new Vector2D(0.85, -0.05), + new Vector2D(0.85, -0.25), + true), + new BSPTree(Boolean.FALSE), b4, null); + BSPTree b6 = + new BSPTree(buildLine(new Vector2D(0.0, -1.10), + new Vector2D(1.0, -0.10)), + new BSPTree(Boolean.FALSE), b5, null); - PolygonsSet c = (PolygonsSet) Region.union(new PolygonsSet(a9), - new PolygonsSet(b6)); + PolygonsSet c = + (PolygonsSet) new RegionFactory().union(new PolygonsSet(a9), + new PolygonsSet(b6)); - checkPoints(Region.Location.INSIDE, c, new Point2D[] { - new Point2D(0.83, -0.06), - new Point2D(0.83, -0.15), - new Point2D(0.88, -0.15), - new Point2D(0.88, -0.09), - new Point2D(0.88, -0.07), - new Point2D(0.91, -0.18), - new Point2D(0.91, -0.10) + checkPoints(Region.Location.INSIDE, c, new Vector2D[] { + new Vector2D(0.83, -0.06), + new Vector2D(0.83, -0.15), + new Vector2D(0.88, -0.15), + new Vector2D(0.88, -0.09), + new Vector2D(0.88, -0.07), + new Vector2D(0.91, -0.18), + new Vector2D(0.91, -0.10) }); - checkPoints(Region.Location.OUTSIDE, c, new Point2D[] { - new Point2D(0.80, -0.10), - new Point2D(0.83, -0.50), - new Point2D(0.83, -0.20), - new Point2D(0.83, -0.02), - new Point2D(0.87, -0.50), - new Point2D(0.87, -0.20), - new Point2D(0.87, -0.02), - new Point2D(0.91, -0.20), - new Point2D(0.91, -0.08), - new Point2D(0.93, -0.15) + checkPoints(Region.Location.OUTSIDE, c, new Vector2D[] { + new Vector2D(0.80, -0.10), + new Vector2D(0.83, -0.50), + new Vector2D(0.83, -0.20), + new Vector2D(0.83, -0.02), + new Vector2D(0.87, -0.50), + new Vector2D(0.87, -0.20), + new Vector2D(0.87, -0.02), + new Vector2D(0.91, -0.20), + new Vector2D(0.91, -0.08), + new Vector2D(0.93, -0.15) }); checkVertices(c.getVertices(), - new Point2D[][] { - new Point2D[] { - new Point2D(0.85, -0.15), - new Point2D(0.90, -0.20), - new Point2D(0.92, -0.18), - new Point2D(0.92, -0.08), - new Point2D(0.90, -0.10), - new Point2D(0.90, -0.05), - new Point2D(0.82, -0.05), - new Point2D(0.82, -0.18), + new Vector2D[][] { + new Vector2D[] { + new Vector2D(0.85, -0.15), + new Vector2D(0.90, -0.20), + new Vector2D(0.92, -0.18), + new Vector2D(0.92, -0.08), + new Vector2D(0.90, -0.10), + new Vector2D(0.90, -0.05), + new Vector2D(0.82, -0.05), + new Vector2D(0.82, -0.18), } }); @@ -748,43 +768,42 @@ public class PolygonsSetTest { public void testBug20041003() { Line[] l = { - new Line(new Point2D(0.0, 0.625000007541172), - new Point2D(1.0, 0.625000007541172)), - new Line(new Point2D(-0.19204433621902645, 0.0), - new Point2D(-0.19204433621902645, 1.0)), - new Line(new Point2D(-0.40303524786887, 0.4248364535319128), - new Point2D(-1.12851149797877, -0.2634107480798909)), - new Line(new Point2D(0.0, 2.0), - new Point2D(1.0, 2.0)) + new Line(new Vector2D(0.0, 0.625000007541172), + new Vector2D(1.0, 0.625000007541172)), + new Line(new Vector2D(-0.19204433621902645, 0.0), + new Vector2D(-0.19204433621902645, 1.0)), + new Line(new Vector2D(-0.40303524786887, 0.4248364535319128), + new Vector2D(-1.12851149797877, -0.2634107480798909)), + new Line(new Vector2D(0.0, 2.0), + new Vector2D(1.0, 2.0)) }; - BSPTree node1 = - new BSPTree(new SubHyperplane(l[0], + BSPTree node1 = + new BSPTree(new SubLine(l[0], new IntervalsSet(intersectionAbscissa(l[0], l[1]), intersectionAbscissa(l[0], l[2]))), - new BSPTree(Boolean.TRUE), new BSPTree(Boolean.FALSE), + new BSPTree(Boolean.TRUE), new BSPTree(Boolean.FALSE), null); - BSPTree node2 = - new BSPTree(new SubHyperplane(l[1], + BSPTree node2 = + new BSPTree(new SubLine(l[1], new IntervalsSet(intersectionAbscissa(l[1], l[2]), intersectionAbscissa(l[1], l[3]))), - node1, new BSPTree(Boolean.FALSE), null); - BSPTree node3 = - new BSPTree(new SubHyperplane(l[2], + node1, new BSPTree(Boolean.FALSE), null); + BSPTree node3 = + new BSPTree(new SubLine(l[2], new IntervalsSet(intersectionAbscissa(l[2], l[3]), Double.POSITIVE_INFINITY)), - node2, new BSPTree(Boolean.FALSE), null); - BSPTree node4 = - new BSPTree(new SubHyperplane(l[3]), - node3, new BSPTree(Boolean.FALSE), null); + node2, new BSPTree(Boolean.FALSE), null); + BSPTree node4 = + new BSPTree(l[3].wholeHyperplane(), node3, new BSPTree(Boolean.FALSE), null); PolygonsSet set = new PolygonsSet(node4); Assert.assertEquals(0, set.getVertices().length); } - private PolygonsSet buildSet(Point2D[][] vertices) { - ArrayList edges = new ArrayList(); + private PolygonsSet buildSet(Vector2D[][] vertices) { + ArrayList> edges = new ArrayList>(); for (int i = 0; i < vertices.length; ++i) { int l = vertices[i].length; for (int j = 0; j < l; ++j) { @@ -794,49 +813,49 @@ public class PolygonsSetTest { return new PolygonsSet(edges); } - private SubHyperplane buildLine(Point2D start, Point2D end) { - return new SubHyperplane(new Line(start, end)); + private SubHyperplane buildLine(Vector2D start, Vector2D end) { + return new Line(start, end).wholeHyperplane(); } private double intersectionAbscissa(Line l0, Line l1) { - Point2D p = (Point2D) l0.intersection(l1); - return ((Point1D) l0.toSubSpace(p)).getAbscissa(); + Vector2D p = (Vector2D) l0.intersection(l1); + return ((Vector1D) l0.toSubSpace(p)).getX(); } - private SubHyperplane buildHalfLine(Point2D start, Point2D end, - boolean startIsVirtual) { + private SubHyperplane buildHalfLine(Vector2D start, Vector2D end, + boolean startIsVirtual) { Line line = new Line(start, end); double lower = startIsVirtual ? Double.NEGATIVE_INFINITY - : ((Point1D) line.toSubSpace(start)).getAbscissa(); + : ((Vector1D) line.toSubSpace(start)).getX(); double upper = startIsVirtual - ? ((Point1D) line.toSubSpace(end)).getAbscissa() + ? ((Vector1D) line.toSubSpace(end)).getX() : Double.POSITIVE_INFINITY; - return new SubHyperplane(line, new IntervalsSet(lower, upper)); + return new SubLine(line, new IntervalsSet(lower, upper)); } - private SubHyperplane buildSegment(Point2D start, Point2D end) { + private SubHyperplane buildSegment(Vector2D start, Vector2D end) { Line line = new Line(start, end); - double lower = ((Point1D) line.toSubSpace(start)).getAbscissa(); - double upper = ((Point1D) line.toSubSpace(end)).getAbscissa(); - return new SubHyperplane(line, new IntervalsSet(lower, upper)); + double lower = ((Vector1D) line.toSubSpace(start)).getX(); + double upper = ((Vector1D) line.toSubSpace(end)).getX(); + return new SubLine(line, new IntervalsSet(lower, upper)); } private void checkPoints(Region.Location expected, PolygonsSet set, - Point2D[] points) { + Vector2D[] points) { for (int i = 0; i < points.length; ++i) { Assert.assertEquals(expected, set.checkPoint(points[i])); } } - private boolean checkInSegment(Point2D p, - Point2D p1, Point2D p2, + private boolean checkInSegment(Vector2D p, + Vector2D p1, Vector2D p2, double tolerance) { Line line = new Line(p1, p2); if (line.getOffset(p) < tolerance) { - double x = ((Point1D) line.toSubSpace(p)).getAbscissa(); - double x1 = ((Point1D) line.toSubSpace(p1)).getAbscissa(); - double x2 = ((Point1D) line.toSubSpace(p2)).getAbscissa(); + double x = ((Vector1D) line.toSubSpace(p)).getX(); + double x1 = ((Vector1D) line.toSubSpace(p1)).getX(); + double x2 = ((Vector1D) line.toSubSpace(p2)).getX(); return (((x - x1) * (x - x2) <= 0.0) || (p1.distance(p) < tolerance) || (p2.distance(p) < tolerance)); @@ -845,16 +864,16 @@ public class PolygonsSetTest { } } - private void checkVertices(Point2D[][] rebuiltVertices, - Point2D[][] vertices) { + private void checkVertices(Vector2D[][] rebuiltVertices, + Vector2D[][] vertices) { // each rebuilt vertex should be in a segment joining two original vertices for (int i = 0; i < rebuiltVertices.length; ++i) { for (int j = 0; j < rebuiltVertices[i].length; ++j) { boolean inSegment = false; - Point2D p = rebuiltVertices[i][j]; + Vector2D p = rebuiltVertices[i][j]; for (int k = 0; k < vertices.length; ++k) { - Point2D[] loop = vertices[k]; + Vector2D[] loop = vertices[k]; int length = loop.length; for (int l = 0; (! inSegment) && (l < length); ++l) { inSegment = checkInSegment(p, loop[l], loop[(l + 1) % length], 1.0e-10);