use the reorganized Binary Space Partitioning framework for Euclidean spaces 1D, 2D and 3D.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1131127 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
6a14866cfc
commit
540bf1525f
|
@ -19,7 +19,8 @@ package org.apache.commons.math.geometry.euclidean.oned;
|
||||||
|
|
||||||
/** This class represents a 1D interval.
|
/** This class represents a 1D interval.
|
||||||
* @see IntervalsSet
|
* @see IntervalsSet
|
||||||
* @version $Revision$ $Date$
|
* @version $Id:$
|
||||||
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class Interval {
|
public class Interval {
|
||||||
|
|
||||||
|
|
|
@ -20,14 +20,16 @@ import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
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.BSPTree;
|
||||||
import org.apache.commons.math.geometry.partitioning.Region;
|
import org.apache.commons.math.geometry.partitioning.Region;
|
||||||
import org.apache.commons.math.geometry.partitioning.SubHyperplane;
|
import org.apache.commons.math.geometry.partitioning.SubHyperplane;
|
||||||
|
|
||||||
/** This class represents a 1D region: a set of intervals.
|
/** 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<Euclidean1D, Euclidean1D> {
|
||||||
|
|
||||||
/** Build an intervals set representing the whole real line.
|
/** 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}</p>
|
* {@code Boolean.TRUE} and {@code Boolean.FALSE}</p>
|
||||||
* @param tree inside/outside BSP tree representing the intervals set
|
* @param tree inside/outside BSP tree representing the intervals set
|
||||||
*/
|
*/
|
||||||
public IntervalsSet(final BSPTree tree) {
|
public IntervalsSet(final BSPTree<Euclidean1D> tree) {
|
||||||
super(tree);
|
super(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +79,7 @@ public class IntervalsSet extends Region {
|
||||||
* space.</p>
|
* space.</p>
|
||||||
* @param boundary collection of boundary elements
|
* @param boundary collection of boundary elements
|
||||||
*/
|
*/
|
||||||
public IntervalsSet(final Collection<SubHyperplane> boundary) {
|
public IntervalsSet(final Collection<SubHyperplane<Euclidean1D>> boundary) {
|
||||||
super(boundary);
|
super(boundary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,52 +90,52 @@ public class IntervalsSet extends Region {
|
||||||
* to {@code lower} (may be {@code Double.POSITIVE_INFINITY})
|
* to {@code lower} (may be {@code Double.POSITIVE_INFINITY})
|
||||||
* @return the built tree
|
* @return the built tree
|
||||||
*/
|
*/
|
||||||
private static BSPTree buildTree(final double lower, final double upper) {
|
private static BSPTree<Euclidean1D> buildTree(final double lower, final double upper) {
|
||||||
if (Double.isInfinite(lower) && (lower < 0)) {
|
if (Double.isInfinite(lower) && (lower < 0)) {
|
||||||
if (Double.isInfinite(upper) && (upper > 0)) {
|
if (Double.isInfinite(upper) && (upper > 0)) {
|
||||||
// the tree must cover the whole real line
|
// the tree must cover the whole real line
|
||||||
return new BSPTree(Boolean.TRUE);
|
return new BSPTree<Euclidean1D>(Boolean.TRUE);
|
||||||
}
|
}
|
||||||
// the tree must be open on the negative infinity side
|
// the tree must be open on the negative infinity side
|
||||||
final SubHyperplane upperCut =
|
final SubHyperplane<Euclidean1D> upperCut =
|
||||||
new SubHyperplane(new OrientedPoint(new Point1D(upper), true));
|
new OrientedPoint(new Vector1D(upper), true).wholeHyperplane();
|
||||||
return new BSPTree(upperCut,
|
return new BSPTree<Euclidean1D>(upperCut,
|
||||||
new BSPTree(Boolean.FALSE),
|
new BSPTree<Euclidean1D>(Boolean.FALSE),
|
||||||
new BSPTree(Boolean.TRUE),
|
new BSPTree<Euclidean1D>(Boolean.TRUE),
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
final SubHyperplane lowerCut =
|
final SubHyperplane<Euclidean1D> lowerCut =
|
||||||
new SubHyperplane(new OrientedPoint(new Point1D(lower), false));
|
new OrientedPoint(new Vector1D(lower), false).wholeHyperplane();
|
||||||
if (Double.isInfinite(upper) && (upper > 0)) {
|
if (Double.isInfinite(upper) && (upper > 0)) {
|
||||||
// the tree must be open on the positive infinity side
|
// the tree must be open on the positive infinity side
|
||||||
return new BSPTree(lowerCut,
|
return new BSPTree<Euclidean1D>(lowerCut,
|
||||||
new BSPTree(Boolean.FALSE),
|
new BSPTree<Euclidean1D>(Boolean.FALSE),
|
||||||
new BSPTree(Boolean.TRUE),
|
new BSPTree<Euclidean1D>(Boolean.TRUE),
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the tree must be bounded on the two sides
|
// the tree must be bounded on the two sides
|
||||||
final SubHyperplane upperCut =
|
final SubHyperplane<Euclidean1D> upperCut =
|
||||||
new SubHyperplane(new OrientedPoint(new Point1D(upper), true));
|
new OrientedPoint(new Vector1D(upper), true).wholeHyperplane();
|
||||||
return new BSPTree(lowerCut,
|
return new BSPTree<Euclidean1D>(lowerCut,
|
||||||
new BSPTree(Boolean.FALSE),
|
new BSPTree<Euclidean1D>(Boolean.FALSE),
|
||||||
new BSPTree(upperCut,
|
new BSPTree<Euclidean1D>(upperCut,
|
||||||
new BSPTree(Boolean.FALSE),
|
new BSPTree<Euclidean1D>(Boolean.FALSE),
|
||||||
new BSPTree(Boolean.TRUE),
|
new BSPTree<Euclidean1D>(Boolean.TRUE),
|
||||||
null),
|
null),
|
||||||
null);
|
null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public Region buildNew(final BSPTree tree) {
|
public IntervalsSet buildNew(final BSPTree<Euclidean1D> tree) {
|
||||||
return new IntervalsSet(tree);
|
return new IntervalsSet(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
protected void computeGeometricalProperties() {
|
protected void computeGeometricalProperties() {
|
||||||
if (getTree(false).getCut() == null) {
|
if (getTree(false).getCut() == null) {
|
||||||
setBarycenter(Point1D.UNDEFINED);
|
setBarycenter(Vector1D.NaN);
|
||||||
setSize(((Boolean) getTree(false).getAttribute()) ? Double.POSITIVE_INFINITY : 0);
|
setSize(((Boolean) getTree(false).getAttribute()) ? Double.POSITIVE_INFINITY : 0);
|
||||||
} else {
|
} else {
|
||||||
double size = 0.0;
|
double size = 0.0;
|
||||||
|
@ -143,7 +145,7 @@ public class IntervalsSet extends Region {
|
||||||
sum += interval.getLength() * interval.getMidPoint();
|
sum += interval.getLength() * interval.getMidPoint();
|
||||||
}
|
}
|
||||||
setSize(size);
|
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)
|
* instance is empty)
|
||||||
*/
|
*/
|
||||||
public double getInf() {
|
public double getInf() {
|
||||||
BSPTree node = getTree(false);
|
BSPTree<Euclidean1D> node = getTree(false);
|
||||||
double inf = Double.POSITIVE_INFINITY;
|
double inf = Double.POSITIVE_INFINITY;
|
||||||
while (node.getCut() != null) {
|
while (node.getCut() != null) {
|
||||||
final OrientedPoint op = (OrientedPoint) node.getCut().getHyperplane();
|
final OrientedPoint op = (OrientedPoint) node.getCut().getHyperplane();
|
||||||
inf = op.getLocation().getAbscissa();
|
inf = op.getLocation().getX();
|
||||||
node = op.isDirect() ? node.getMinus() : node.getPlus();
|
node = op.isDirect() ? node.getMinus() : node.getPlus();
|
||||||
}
|
}
|
||||||
return ((Boolean) node.getAttribute()) ? Double.NEGATIVE_INFINITY : inf;
|
return ((Boolean) node.getAttribute()) ? Double.NEGATIVE_INFINITY : inf;
|
||||||
|
@ -171,11 +173,11 @@ public class IntervalsSet extends Region {
|
||||||
* instance is empty)
|
* instance is empty)
|
||||||
*/
|
*/
|
||||||
public double getSup() {
|
public double getSup() {
|
||||||
BSPTree node = getTree(false);
|
BSPTree<Euclidean1D> node = getTree(false);
|
||||||
double sup = Double.NEGATIVE_INFINITY;
|
double sup = Double.NEGATIVE_INFINITY;
|
||||||
while (node.getCut() != null) {
|
while (node.getCut() != null) {
|
||||||
final OrientedPoint op = (OrientedPoint) node.getCut().getHyperplane();
|
final OrientedPoint op = (OrientedPoint) node.getCut().getHyperplane();
|
||||||
sup = op.getLocation().getAbscissa();
|
sup = op.getLocation().getX();
|
||||||
node = op.isDirect() ? node.getPlus() : node.getMinus();
|
node = op.isDirect() ? node.getPlus() : node.getMinus();
|
||||||
}
|
}
|
||||||
return ((Boolean) node.getAttribute()) ? Double.POSITIVE_INFINITY : sup;
|
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 lower lower bound of the current convex cell
|
||||||
* @param upper upper bound of the current convex cell
|
* @param upper upper bound of the current convex cell
|
||||||
*/
|
*/
|
||||||
private void recurseList(final BSPTree node, final List<Interval> list,
|
private void recurseList(final BSPTree<Euclidean1D> node,
|
||||||
|
final List<Interval> list,
|
||||||
final double lower, final double upper) {
|
final double lower, final double upper) {
|
||||||
|
|
||||||
if (node.getCut() == null) {
|
if (node.getCut() == null) {
|
||||||
|
@ -217,12 +220,14 @@ public class IntervalsSet extends Region {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final OrientedPoint op = (OrientedPoint) node.getCut().getHyperplane();
|
final OrientedPoint op = (OrientedPoint) node.getCut().getHyperplane();
|
||||||
final Point1D loc = op.getLocation();
|
final Vector1D loc = op.getLocation();
|
||||||
double x = loc.getAbscissa();
|
double x = loc.getX();
|
||||||
|
|
||||||
// make sure we explore the tree in increasing order
|
// make sure we explore the tree in increasing order
|
||||||
final BSPTree low = op.isDirect() ? node.getMinus() : node.getPlus();
|
final BSPTree<Euclidean1D> low =
|
||||||
final BSPTree high = op.isDirect() ? node.getPlus() : node.getMinus();
|
op.isDirect() ? node.getMinus() : node.getPlus();
|
||||||
|
final BSPTree<Euclidean1D> high =
|
||||||
|
op.isDirect() ? node.getPlus() : node.getMinus();
|
||||||
|
|
||||||
recurseList(low, list, lower, x);
|
recurseList(low, list, lower, x);
|
||||||
if ((checkPoint(low, loc) == Location.INSIDE) &&
|
if ((checkPoint(low, loc) == Location.INSIDE) &&
|
||||||
|
|
|
@ -16,28 +16,22 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.commons.math.geometry.euclidean.oned;
|
package org.apache.commons.math.geometry.euclidean.oned;
|
||||||
|
|
||||||
import org.apache.commons.math.exception.MathUnsupportedOperationException;
|
import org.apache.commons.math.geometry.Vector;
|
||||||
import org.apache.commons.math.exception.util.LocalizedFormats;
|
|
||||||
import org.apache.commons.math.geometry.partitioning.BSPTree;
|
|
||||||
import org.apache.commons.math.geometry.partitioning.Hyperplane;
|
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.Region;
|
||||||
import org.apache.commons.math.geometry.partitioning.SubHyperplane;
|
import org.apache.commons.math.geometry.partitioning.SubHyperplane;
|
||||||
import org.apache.commons.math.geometry.partitioning.SubSpace;
|
|
||||||
|
|
||||||
/** This class represents a 1D oriented hyperplane.
|
/** This class represents a 1D oriented hyperplane.
|
||||||
* <p>An hyperplane in 1D is a simple point, its orientation being a
|
* <p>An hyperplane in 1D is a simple point, its orientation being a
|
||||||
* boolean.</p>
|
* boolean.</p>
|
||||||
* <p>Instances of this class are guaranteed to be immutable.</p>
|
* <p>Instances of this class are guaranteed to be immutable.</p>
|
||||||
* @version $Revision$ $Date$
|
* @version $Id:$
|
||||||
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class OrientedPoint implements Hyperplane {
|
public class OrientedPoint implements Hyperplane<Euclidean1D> {
|
||||||
|
|
||||||
/** Dummy region returned by the {@link #wholeHyperplane} method. */
|
/** Vector location. */
|
||||||
private static final Region DUMMY_REGION = new DummyRegion();
|
private Vector1D location;
|
||||||
|
|
||||||
/** Point location. */
|
|
||||||
private Point1D location;
|
|
||||||
|
|
||||||
/** Orientation. */
|
/** Orientation. */
|
||||||
private boolean direct;
|
private boolean direct;
|
||||||
|
@ -45,9 +39,9 @@ public class OrientedPoint implements Hyperplane {
|
||||||
/** Simple constructor.
|
/** Simple constructor.
|
||||||
* @param location location of the hyperplane
|
* @param location location of the hyperplane
|
||||||
* @param direct if true, the plus side of the hyperplane is towards
|
* @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.location = location;
|
||||||
this.direct = direct;
|
this.direct = direct;
|
||||||
}
|
}
|
||||||
|
@ -57,62 +51,16 @@ public class OrientedPoint implements Hyperplane {
|
||||||
* the instance.</p>
|
* the instance.</p>
|
||||||
* @return the instance itself
|
* @return the instance itself
|
||||||
*/
|
*/
|
||||||
public Hyperplane copySelf() {
|
public OrientedPoint copySelf() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the offset (oriented distance) of a point to the hyperplane.
|
/** {@inheritDoc} */
|
||||||
* @param point point to check
|
public double getOffset(final Vector<Euclidean1D> point) {
|
||||||
* @return offset of the point
|
final double delta = ((Vector1D) point).getX() - location.getX();
|
||||||
*/
|
|
||||||
public double getOffset(final Point point) {
|
|
||||||
final double delta = ((Point1D) point).getAbscissa() - location.getAbscissa();
|
|
||||||
return direct ? delta : -delta;
|
return direct ? delta : -delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Transform a space point into a sub-space point.
|
|
||||||
* <p>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.</p>
|
|
||||||
* @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.
|
|
||||||
* <p>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.</p>
|
|
||||||
* @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.
|
|
||||||
* <p>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.</p>
|
|
||||||
* @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.
|
/** Build a region covering the whole hyperplane.
|
||||||
* <p>Since this class represent zero dimension spaces which does
|
* <p>Since this class represent zero dimension spaces which does
|
||||||
* not have lower dimension sub-spaces, this method returns a dummy
|
* not have lower dimension sub-spaces, this method returns a dummy
|
||||||
|
@ -122,15 +70,15 @@ public class OrientedPoint implements Hyperplane {
|
||||||
* properly, it should <em>not</em> be used otherwise.</p>
|
* properly, it should <em>not</em> be used otherwise.</p>
|
||||||
* @return a dummy region
|
* @return a dummy region
|
||||||
*/
|
*/
|
||||||
public Region wholeHyperplane() {
|
public SubOrientedPoint wholeHyperplane() {
|
||||||
return DUMMY_REGION;
|
return new SubOrientedPoint(this, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Build a region covering the whole space.
|
/** Build a region covering the whole space.
|
||||||
* @return a region containing the instance (really an {@link
|
* @return a region containing the instance (really an {@link
|
||||||
* IntervalsSet IntervalsSet} instance)
|
* IntervalsSet IntervalsSet} instance)
|
||||||
*/
|
*/
|
||||||
public Region wholeSpace() {
|
public IntervalsSet wholeSpace() {
|
||||||
return new IntervalsSet();
|
return new IntervalsSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,40 +95,14 @@ public class OrientedPoint implements Hyperplane {
|
||||||
* @return true if the instance and the other hyperplane have
|
* @return true if the instance and the other hyperplane have
|
||||||
* the same orientation
|
* the same orientation
|
||||||
*/
|
*/
|
||||||
public boolean sameOrientationAs(final Hyperplane other) {
|
public boolean sameOrientationAs(final Hyperplane<Euclidean1D> other) {
|
||||||
return !(direct ^ ((OrientedPoint) other).direct);
|
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 <em>never</em> 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.
|
/** Get the hyperplane location on the real line.
|
||||||
* @return the hyperplane location
|
* @return the hyperplane location
|
||||||
*/
|
*/
|
||||||
public Point1D getLocation() {
|
public Vector1D getLocation() {
|
||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,25 +120,4 @@ public class OrientedPoint implements Hyperplane {
|
||||||
direct = !direct;
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}.
|
||||||
|
* <p>An hyperplane in 1D is a simple point, its orientation being a
|
||||||
|
* boolean.</p>
|
||||||
|
* <p>Instances of this class are guaranteed to be immutable.</p>
|
||||||
|
* @version $Id:$
|
||||||
|
* @since 3.0
|
||||||
|
*/
|
||||||
|
public class SubOrientedPoint extends AbstractSubHyperplane<Euclidean1D, Euclidean1D> {
|
||||||
|
|
||||||
|
/** Simple constructor.
|
||||||
|
* @param hyperplane underlying hyperplane
|
||||||
|
* @param remainingRegion remaining region of the hyperplane
|
||||||
|
*/
|
||||||
|
public SubOrientedPoint(final Hyperplane<Euclidean1D> hyperplane,
|
||||||
|
final Region<Euclidean1D> remainingRegion) {
|
||||||
|
super(hyperplane, remainingRegion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public double getSize() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
protected AbstractSubHyperplane<Euclidean1D, Euclidean1D> buildNew(final Hyperplane<Euclidean1D> hyperplane,
|
||||||
|
final Region<Euclidean1D> remainingRegion) {
|
||||||
|
return new SubOrientedPoint(hyperplane, remainingRegion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public Side side(final Hyperplane<Euclidean1D> 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<Euclidean1D> split(final Hyperplane<Euclidean1D> hyperplane) {
|
||||||
|
final double global = hyperplane.getOffset(((OrientedPoint) getHyperplane()).getLocation());
|
||||||
|
return (global < -1.0e-10) ?
|
||||||
|
new SplitSubHyperplane<Euclidean1D>(null, this) :
|
||||||
|
new SplitSubHyperplane<Euclidean1D>(this, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,9 +16,10 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.commons.math.geometry.euclidean.threed;
|
package org.apache.commons.math.geometry.euclidean.threed;
|
||||||
|
|
||||||
import org.apache.commons.math.geometry.euclidean.oned.Point1D;
|
import org.apache.commons.math.geometry.Vector;
|
||||||
import org.apache.commons.math.geometry.partitioning.Point;
|
import org.apache.commons.math.geometry.euclidean.oned.Euclidean1D;
|
||||||
import org.apache.commons.math.geometry.partitioning.SubSpace;
|
import org.apache.commons.math.geometry.euclidean.oned.Vector1D;
|
||||||
|
import org.apache.commons.math.geometry.partitioning.Embedding;
|
||||||
import org.apache.commons.math.util.FastMath;
|
import org.apache.commons.math.util.FastMath;
|
||||||
|
|
||||||
/** The class represent lines in a three dimensional space.
|
/** 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
|
* which is closest to the origin. Abscissa increases in the line
|
||||||
* direction.</p>
|
* direction.</p>
|
||||||
|
|
||||||
* @version $Revision$ $Date$
|
* @version $Id:$
|
||||||
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class Line implements SubSpace {
|
public class Line implements Embedding<Euclidean3D, Euclidean1D> {
|
||||||
|
|
||||||
/** Line direction. */
|
/** Line direction. */
|
||||||
private Vector3D direction;
|
private Vector3D direction;
|
||||||
|
|
||||||
/** Line point closest to the origin. */
|
/** Line point closest to the origin. */
|
||||||
private Point3D zero;
|
private Vector3D zero;
|
||||||
|
|
||||||
/** Build a line from a point and a direction.
|
/** Build a line from a point and a direction.
|
||||||
* @param p point belonging to the line (this can be any point)
|
* @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");
|
throw new IllegalArgumentException("null norm");
|
||||||
}
|
}
|
||||||
this.direction = new Vector3D(1.0 / norm, dir);
|
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() {
|
public Line revert() {
|
||||||
direction = direction.negate();
|
return new Line(zero, direction.negate());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the normalized direction vector.
|
/** 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}
|
* @param point point to check (must be a {@link Vector3D Vector3D}
|
||||||
* instance)
|
* instance)
|
||||||
* @return abscissa of the point (really a
|
* @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) {
|
public Vector1D toSubSpace(final Vector<Euclidean3D> point) {
|
||||||
final double x = Vector3D.dotProduct(((Vector3D) point).subtract(zero), direction);
|
Vector3D p3 = (Vector3D) point;
|
||||||
return new Point1D(x);
|
return new Vector1D(Vector3D.dotProduct(p3.subtract(zero), direction));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get one point from the line.
|
/** Get one point from the line.
|
||||||
* @param point desired abscissa for the point (must be a
|
* @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
|
* @return one point belonging to the line, at specified abscissa
|
||||||
* (really a {@link Vector3D Vector3D} instance)
|
* (really a {@link Vector3D Vector3D} instance)
|
||||||
*/
|
*/
|
||||||
public Point toSpace(final Point point) {
|
public Vector3D toSpace(final Vector<Euclidean1D> point) {
|
||||||
return new Point3D(1.0, zero, ((Point1D) point).getAbscissa(), direction);
|
Vector1D p1 = (Vector1D) point;
|
||||||
|
return new Vector3D(1.0, zero, p1.getX(), direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check if the instance is similar to another line.
|
/** Check if the instance is similar to another line.
|
||||||
|
|
|
@ -16,20 +16,24 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.commons.math.geometry.euclidean.threed;
|
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.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.BSPTree;
|
||||||
import org.apache.commons.math.geometry.partitioning.BSPTreeVisitor;
|
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.geometry.partitioning.SubHyperplane;
|
||||||
import org.apache.commons.math.util.FastMath;
|
import org.apache.commons.math.util.FastMath;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/** Extractor for {@link PolygonsSet polyhedrons sets} outlines.
|
/** Extractor for {@link PolygonsSet polyhedrons sets} outlines.
|
||||||
* <p>This class extracts the 2D outlines from {{@link PolygonsSet
|
* <p>This class extracts the 2D outlines from {{@link PolygonsSet
|
||||||
* polyhedrons sets} in a specified projection plane.</p>
|
* polyhedrons sets} in a specified projection plane.</p>
|
||||||
* @version $Revision$ $Date$
|
* @version $Id:$
|
||||||
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class OutlineExtractor {
|
public class OutlineExtractor {
|
||||||
|
|
||||||
|
@ -56,7 +60,7 @@ public class OutlineExtractor {
|
||||||
* @param polyhedronsSet polyhedrons set whose outline must be extracted
|
* @param polyhedronsSet polyhedrons set whose outline must be extracted
|
||||||
* @return an outline, as an array of loops.
|
* @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
|
// project all boundary facets into one polygons set
|
||||||
final BoundaryProjector projector = new BoundaryProjector();
|
final BoundaryProjector projector = new BoundaryProjector();
|
||||||
|
@ -64,9 +68,9 @@ public class OutlineExtractor {
|
||||||
final PolygonsSet projected = projector.getProjected();
|
final PolygonsSet projected = projector.getProjected();
|
||||||
|
|
||||||
// Remove the spurious intermediate vertices from the outline
|
// 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) {
|
for (int i = 0; i < outline.length; ++i) {
|
||||||
final Point2D[] rawLoop = outline[i];
|
final Vector2D[] rawLoop = outline[i];
|
||||||
int end = rawLoop.length;
|
int end = rawLoop.length;
|
||||||
int j = 0;
|
int j = 0;
|
||||||
while (j < end) {
|
while (j < end) {
|
||||||
|
@ -83,7 +87,7 @@ public class OutlineExtractor {
|
||||||
}
|
}
|
||||||
if (end != rawLoop.length) {
|
if (end != rawLoop.length) {
|
||||||
// resize the array
|
// resize the array
|
||||||
outline[i] = new Point2D[end];
|
outline[i] = new Vector2D[end];
|
||||||
System.arraycopy(rawLoop, 0, outline[i], 0, 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)
|
* @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
|
* @return true if the point is exactly between its neighbours
|
||||||
*/
|
*/
|
||||||
private boolean pointIsBetween(final Point2D[] loop, final int n, final int i) {
|
private boolean pointIsBetween(final Vector2D[] loop, final int n, final int i) {
|
||||||
final Point2D previous = loop[(i + n - 1) % n];
|
final Vector2D previous = loop[(i + n - 1) % n];
|
||||||
final Point2D current = loop[i];
|
final Vector2D current = loop[i];
|
||||||
final Point2D next = loop[(i + 1) % n];
|
final Vector2D next = loop[(i + 1) % n];
|
||||||
final double dx1 = current.x - previous.x;
|
final double dx1 = current.getX() - previous.getX();
|
||||||
final double dy1 = current.y - previous.y;
|
final double dy1 = current.getY() - previous.getY();
|
||||||
final double dx2 = next.x - current.x;
|
final double dx2 = next.getX() - current.getX();
|
||||||
final double dy2 = next.y - current.y;
|
final double dy2 = next.getY() - current.getY();
|
||||||
final double cross = dx1 * dy2 - dx2 * dy1;
|
final double cross = dx1 * dy2 - dx2 * dy1;
|
||||||
final double dot = dx1 * dx2 + dy1 * dy2;
|
final double dot = dx1 * dx2 + dy1 * dy2;
|
||||||
final double d1d2 = FastMath.sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * 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. */
|
/** Visitor projecting the boundary facets on a plane. */
|
||||||
private class BoundaryProjector implements BSPTreeVisitor {
|
private class BoundaryProjector implements BSPTreeVisitor<Euclidean3D> {
|
||||||
|
|
||||||
/** Projection of the polyhedrons set on the plane. */
|
/** Projection of the polyhedrons set on the plane. */
|
||||||
private PolygonsSet projected;
|
private PolygonsSet projected;
|
||||||
|
@ -123,18 +127,19 @@ public class OutlineExtractor {
|
||||||
/** Simple constructor.
|
/** Simple constructor.
|
||||||
*/
|
*/
|
||||||
public BoundaryProjector() {
|
public BoundaryProjector() {
|
||||||
projected = new PolygonsSet(new BSPTree(Boolean.FALSE));
|
projected = new PolygonsSet(new BSPTree<Euclidean2D>(Boolean.FALSE));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public Order visitOrder(final BSPTree node) {
|
public Order visitOrder(final BSPTree<Euclidean3D> node) {
|
||||||
return Order.MINUS_SUB_PLUS;
|
return Order.MINUS_SUB_PLUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public void visitInternalNode(final BSPTree node) {
|
public void visitInternalNode(final BSPTree<Euclidean3D> node) {
|
||||||
final Region.BoundaryAttribute attribute =
|
@SuppressWarnings("unchecked")
|
||||||
(Region.BoundaryAttribute) node.getAttribute();
|
final BoundaryAttribute<Euclidean3D> attribute =
|
||||||
|
(BoundaryAttribute<Euclidean3D>) node.getAttribute();
|
||||||
if (attribute.getPlusOutside() != null) {
|
if (attribute.getPlusOutside() != null) {
|
||||||
addContribution(attribute.getPlusOutside(), false);
|
addContribution(attribute.getPlusOutside(), false);
|
||||||
}
|
}
|
||||||
|
@ -144,19 +149,22 @@ public class OutlineExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public void visitLeafNode(final BSPTree node) {
|
public void visitLeafNode(final BSPTree<Euclidean3D> node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add he contribution of a boundary facet.
|
/** Add he contribution of a boundary facet.
|
||||||
* @param facet boundary facet
|
* @param facet boundary facet
|
||||||
* @param reversed if true, the facet has the inside on its plus side
|
* @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<Euclidean3D> facet, final boolean reversed) {
|
||||||
|
|
||||||
// extract the vertices of the facet
|
// extract the vertices of the facet
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final AbstractSubHyperplane<Euclidean3D, Euclidean2D> absFacet =
|
||||||
|
(AbstractSubHyperplane<Euclidean3D, Euclidean2D>) facet;
|
||||||
final Plane plane = (Plane) facet.getHyperplane();
|
final Plane plane = (Plane) facet.getHyperplane();
|
||||||
Point2D[][] vertices =
|
Vector2D[][] vertices =
|
||||||
((PolygonsSet) facet.getRemainingRegion()).getVertices();
|
((PolygonsSet) absFacet.getRemainingRegion()).getVertices();
|
||||||
|
|
||||||
final double scal = Vector3D.dotProduct(plane.getNormal(), w);
|
final double scal = Vector3D.dotProduct(plane.getNormal(), w);
|
||||||
if (FastMath.abs(scal) > 1.0e-3) {
|
if (FastMath.abs(scal) > 1.0e-3) {
|
||||||
|
@ -164,10 +172,10 @@ public class OutlineExtractor {
|
||||||
if ((scal < 0) ^ reversed) {
|
if ((scal < 0) ^ reversed) {
|
||||||
// the facet is seen from the inside,
|
// the facet is seen from the inside,
|
||||||
// we need to invert its boundary orientation
|
// 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) {
|
for (int i = 0; i < vertices.length; ++i) {
|
||||||
final Point2D[] loop = vertices[i];
|
final Vector2D[] loop = vertices[i];
|
||||||
final Point2D[] newLoop = new Point2D[loop.length];
|
final Vector2D[] newLoop = new Vector2D[loop.length];
|
||||||
if (loop[0] == null) {
|
if (loop[0] == null) {
|
||||||
newLoop[0] = null;
|
newLoop[0] = null;
|
||||||
for (int j = 1; j < loop.length; ++j) {
|
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
|
// compute the projection of the facet in the outline plane
|
||||||
final ArrayList<SubHyperplane> edges = new ArrayList<SubHyperplane>();
|
final ArrayList<SubHyperplane<Euclidean2D>> edges = new ArrayList<SubHyperplane<Euclidean2D>>();
|
||||||
for (Point2D[] loop : vertices) {
|
for (Vector2D[] loop : vertices) {
|
||||||
final boolean closed = loop[0] != null;
|
final boolean closed = loop[0] != null;
|
||||||
int previous = closed ? (loop.length - 1) : 1;
|
int previous = closed ? (loop.length - 1) : 1;
|
||||||
Vector3D previous3D = (Vector3D) plane.toSpace(loop[previous]);
|
Vector3D previous3D = (Vector3D) plane.toSpace(loop[previous]);
|
||||||
int current = (previous + 1) % loop.length;
|
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));
|
Vector3D.dotProduct(previous3D, v));
|
||||||
while (current < loop.length) {
|
while (current < loop.length) {
|
||||||
|
|
||||||
final Vector3D current3D = (Vector3D) plane.toSpace(loop[current]);
|
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));
|
Vector3D.dotProduct(current3D, v));
|
||||||
final org.apache.commons.math.geometry.euclidean.twod.Line line =
|
final org.apache.commons.math.geometry.euclidean.twod.Line line =
|
||||||
new org.apache.commons.math.geometry.euclidean.twod.Line(pPoint, cPoint);
|
new org.apache.commons.math.geometry.euclidean.twod.Line(pPoint, cPoint);
|
||||||
SubHyperplane edge = new SubHyperplane(line);
|
SubHyperplane<Euclidean2D> edge = line.wholeHyperplane();
|
||||||
|
|
||||||
if (closed || (previous != 1)) {
|
if (closed || (previous != 1)) {
|
||||||
// the previous point is a real vertex
|
// the previous point is a real vertex
|
||||||
|
@ -210,7 +218,7 @@ public class OutlineExtractor {
|
||||||
final double angle = line.getAngle() + 0.5 * FastMath.PI;
|
final double angle = line.getAngle() + 0.5 * FastMath.PI;
|
||||||
final org.apache.commons.math.geometry.euclidean.twod.Line l =
|
final org.apache.commons.math.geometry.euclidean.twod.Line l =
|
||||||
new org.apache.commons.math.geometry.euclidean.twod.Line(pPoint, angle);
|
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))) {
|
if (closed || (current != (loop.length - 1))) {
|
||||||
|
@ -219,7 +227,7 @@ public class OutlineExtractor {
|
||||||
final double angle = line.getAngle() + 0.5 * FastMath.PI;
|
final double angle = line.getAngle() + 0.5 * FastMath.PI;
|
||||||
final org.apache.commons.math.geometry.euclidean.twod.Line l =
|
final org.apache.commons.math.geometry.euclidean.twod.Line l =
|
||||||
new org.apache.commons.math.geometry.euclidean.twod.Line(cPoint, angle);
|
new org.apache.commons.math.geometry.euclidean.twod.Line(cPoint, angle);
|
||||||
edge = l.split(edge).getMinus();
|
edge = edge.split(l).getMinus();
|
||||||
}
|
}
|
||||||
|
|
||||||
edges.add(edge);
|
edges.add(edge);
|
||||||
|
@ -233,7 +241,7 @@ public class OutlineExtractor {
|
||||||
final PolygonsSet projectedFacet = new PolygonsSet(edges);
|
final PolygonsSet projectedFacet = new PolygonsSet(edges);
|
||||||
|
|
||||||
// add the contribution of the facet to the global outline
|
// add the contribution of the facet to the global outline
|
||||||
projected = (PolygonsSet) Region.union(projected, projectedFacet);
|
projected = (PolygonsSet) new RegionFactory<Euclidean2D>().union(projected, projectedFacet);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,27 +16,26 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.commons.math.geometry.euclidean.threed;
|
package org.apache.commons.math.geometry.euclidean.threed;
|
||||||
|
|
||||||
import org.apache.commons.math.geometry.euclidean.oned.Point1D;
|
import org.apache.commons.math.geometry.Vector;
|
||||||
import org.apache.commons.math.geometry.euclidean.twod.Point2D;
|
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.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.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;
|
import org.apache.commons.math.util.FastMath;
|
||||||
|
|
||||||
/** The class represent planes in a three dimensional space.
|
/** 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<Euclidean3D>, Embedding<Euclidean3D, Euclidean2D> {
|
||||||
|
|
||||||
/** Offset of the origin with respect to the plane. */
|
/** Offset of the origin with respect to the plane. */
|
||||||
private double originOffset;
|
private double originOffset;
|
||||||
|
|
||||||
/** Origin of the plane frame. */
|
/** Origin of the plane frame. */
|
||||||
private Point3D origin;
|
private Vector3D origin;
|
||||||
|
|
||||||
/** First vector of the plane frame (in plane). */
|
/** First vector of the plane frame (in plane). */
|
||||||
private Vector3D u;
|
private Vector3D u;
|
||||||
|
@ -100,7 +99,7 @@ public class Plane implements Hyperplane {
|
||||||
* shared (except for immutable objects).</p>
|
* shared (except for immutable objects).</p>
|
||||||
* @return a new hyperplane, copy of the instance
|
* @return a new hyperplane, copy of the instance
|
||||||
*/
|
*/
|
||||||
public Hyperplane copySelf() {
|
public Plane copySelf() {
|
||||||
return new Plane(this);
|
return new Plane(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +142,7 @@ public class Plane implements Hyperplane {
|
||||||
/** Reset the plane frame.
|
/** Reset the plane frame.
|
||||||
*/
|
*/
|
||||||
private void setFrame() {
|
private void setFrame() {
|
||||||
origin = new Point3D(-originOffset, w);
|
origin = new Vector3D(-originOffset, w);
|
||||||
u = w.orthogonal();
|
u = w.orthogonal();
|
||||||
v = Vector3D.crossProduct(w, u);
|
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
|
* @return the origin point of the plane frame (point closest to the
|
||||||
* 3D-space origin)
|
* 3D-space origin)
|
||||||
*/
|
*/
|
||||||
public Point3D getOrigin() {
|
public Vector3D getOrigin() {
|
||||||
return origin;
|
return origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,24 +216,24 @@ public class Plane implements Hyperplane {
|
||||||
* @param point point of the space (must be a {@link Vector3D
|
* @param point point of the space (must be a {@link Vector3D
|
||||||
* Vector3D} instance)
|
* Vector3D} instance)
|
||||||
* @return in-plane point (really a {@link
|
* @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
|
* @see #toSpace
|
||||||
*/
|
*/
|
||||||
public Point toSubSpace(final Point point) {
|
public Vector2D toSubSpace(final Vector<Euclidean3D> point) {
|
||||||
final Vector3D p3D = (Vector3D) point;
|
final Vector3D p3D = (Vector3D) point;
|
||||||
return new Point2D(Vector3D.dotProduct(p3D, u),
|
return new Vector2D(Vector3D.dotProduct(p3D, u),
|
||||||
Vector3D.dotProduct(p3D, v));
|
Vector3D.dotProduct(p3D, v));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Transform an in-plane point into a 3D space point.
|
/** Transform an in-plane point into a 3D space point.
|
||||||
* @param point in-plane point (must be a {@link
|
* @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)
|
* @return 3D space point (really a {@link Vector3D Vector3D} instance)
|
||||||
* @see #toSubSpace
|
* @see #toSubSpace
|
||||||
*/
|
*/
|
||||||
public Point toSpace(final Point point) {
|
public Vector3D toSpace(final Vector<Euclidean2D> point) {
|
||||||
final Point2D p2D = (Point2D) point;
|
final Vector2D p2D = (Vector2D) point;
|
||||||
return new Point3D(p2D.x, u, p2D.y, v, -originOffset, w);
|
return new Vector3D(p2D.getX(), u, p2D.getY(), v, -originOffset, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get one point from the 3D-space.
|
/** 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
|
* @return one point in the 3D-space, with given coordinates and offset
|
||||||
* relative to the plane
|
* relative to the plane
|
||||||
*/
|
*/
|
||||||
public Vector3D getPointAt(final Point2D inPlane, final double offset) {
|
public Vector3D getPointAt(final Vector2D inPlane, final double offset) {
|
||||||
return new Vector3D(inPlane.x, u, inPlane.y, v, offset - originOffset, w);
|
return new Vector3D(inPlane.getX(), u, inPlane.getY(), v, offset - originOffset, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check if the instance is similar to another plane.
|
/** 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
|
* @return intersection point between between the line and the
|
||||||
* instance (null if the line is parallel to the instance)
|
* 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 Vector3D direction = line.getDirection();
|
||||||
final double dot = Vector3D.dotProduct(w, direction);
|
final double dot = Vector3D.dotProduct(w, direction);
|
||||||
if (FastMath.abs(dot) < 1.0e-10) {
|
if (FastMath.abs(dot) < 1.0e-10) {
|
||||||
return null;
|
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;
|
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.
|
/** 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
|
* @return line at the intersection of the instance and the
|
||||||
* other plane (really a {@link Line Line} instance)
|
* other plane (really a {@link Line Line} instance)
|
||||||
*/
|
*/
|
||||||
public SubSpace intersection(final Hyperplane other) {
|
public Line intersection(final Plane other) {
|
||||||
final Plane otherP = (Plane) other;
|
final Vector3D direction = Vector3D.crossProduct(w, other.w);
|
||||||
final Vector3D direction = Vector3D.crossProduct(w, otherP.w);
|
|
||||||
if (direction.getNorm() < 1.0e-10) {
|
if (direction.getNorm() < 1.0e-10) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new Line(intersection(this, otherP, new Plane(direction)),
|
return new Line(intersection(this, other, new Plane(direction)),
|
||||||
direction);
|
direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,15 +372,15 @@ public class Plane implements Hyperplane {
|
||||||
/** Build a region covering the whole hyperplane.
|
/** Build a region covering the whole hyperplane.
|
||||||
* @return a region covering the whole hyperplane
|
* @return a region covering the whole hyperplane
|
||||||
*/
|
*/
|
||||||
public Region wholeHyperplane() {
|
public SubPlane wholeHyperplane() {
|
||||||
return new PolygonsSet();
|
return new SubPlane(this, new PolygonsSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Build a region covering the whole space.
|
/** Build a region covering the whole space.
|
||||||
* @return a region containing the instance (really a {@link
|
* @return a region containing the instance (really a {@link
|
||||||
* PolyhedronsSet PolyhedronsSet} instance)
|
* PolyhedronsSet PolyhedronsSet} instance)
|
||||||
*/
|
*/
|
||||||
public Region wholeSpace() {
|
public PolyhedronsSet wholeSpace() {
|
||||||
return new PolyhedronsSet();
|
return new PolyhedronsSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,7 +388,7 @@ public class Plane implements Hyperplane {
|
||||||
* @param p point to check
|
* @param p point to check
|
||||||
* @return true if p belongs to the plane
|
* @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;
|
return FastMath.abs(getOffset(p)) < 1.0e-10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,7 +414,7 @@ public class Plane implements Hyperplane {
|
||||||
* @param point point to check
|
* @param point point to check
|
||||||
* @return offset of the point
|
* @return offset of the point
|
||||||
*/
|
*/
|
||||||
public double getOffset(final Point point) {
|
public double getOffset(final Vector<Euclidean3D> point) {
|
||||||
return Vector3D.dotProduct((Vector3D) point, w) + originOffset;
|
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
|
* @return true if the instance and the other hyperplane have
|
||||||
* the same orientation
|
* the same orientation
|
||||||
*/
|
*/
|
||||||
public boolean sameOrientationAs(final Hyperplane other) {
|
public boolean sameOrientationAs(final Hyperplane<Euclidean3D> other) {
|
||||||
return Vector3D.dotProduct(((Plane) other).w, w) > 0.0;
|
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)));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,23 +17,29 @@
|
||||||
package org.apache.commons.math.geometry.euclidean.threed;
|
package org.apache.commons.math.geometry.euclidean.threed;
|
||||||
|
|
||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
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.BSPTree;
|
||||||
import org.apache.commons.math.geometry.partitioning.BSPTreeVisitor;
|
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.Hyperplane;
|
||||||
import org.apache.commons.math.geometry.partitioning.Point;
|
|
||||||
import org.apache.commons.math.geometry.partitioning.Region;
|
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.SubHyperplane;
|
||||||
import org.apache.commons.math.geometry.partitioning.Transform;
|
import org.apache.commons.math.geometry.partitioning.Transform;
|
||||||
|
import org.apache.commons.math.geometry.partitioning.AbstractRegion;
|
||||||
import org.apache.commons.math.util.FastMath;
|
import org.apache.commons.math.util.FastMath;
|
||||||
|
|
||||||
/** This class represents a 3D region: a set of polyhedrons.
|
/** 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<Euclidean3D, Euclidean2D> {
|
||||||
|
|
||||||
/** Build a polyhedrons set representing the whole real line.
|
/** 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}</p>
|
* {@code Boolean.TRUE} and {@code Boolean.FALSE}</p>
|
||||||
* @param tree inside/outside BSP tree representing the region
|
* @param tree inside/outside BSP tree representing the region
|
||||||
*/
|
*/
|
||||||
public PolyhedronsSet(final BSPTree tree) {
|
public PolyhedronsSet(final BSPTree<Euclidean3D> tree) {
|
||||||
super(tree);
|
super(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,19 +67,19 @@ public class PolyhedronsSet extends Region {
|
||||||
* its plus side.</p>
|
* its plus side.</p>
|
||||||
* <p>The boundary elements can be in any order, and can form
|
* <p>The boundary elements can be in any order, and can form
|
||||||
* several non-connected sets (like for example polyhedrons with holes
|
* 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
|
* fact, the elements do not even need to be connected together
|
||||||
* (their topological connections are not used here). However, if the
|
* (their topological connections are not used here). However, if the
|
||||||
* boundary does not really separate an inside open from an outside
|
* boundary does not really separate an inside open from an outside
|
||||||
* open (open having here its topological meaning), then subsequent
|
* 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.</p>
|
* not be meaningful anymore.</p>
|
||||||
* <p>If the boundary is empty, the region will represent the whole
|
* <p>If the boundary is empty, the region will represent the whole
|
||||||
* space.</p>
|
* space.</p>
|
||||||
* @param boundary collection of boundary elements, as a
|
* @param boundary collection of boundary elements, as a
|
||||||
* collection of {@link SubHyperplane SubHyperplane} objects
|
* collection of {@link SubHyperplane SubHyperplane} objects
|
||||||
*/
|
*/
|
||||||
public PolyhedronsSet(final Collection<SubHyperplane> boundary) {
|
public PolyhedronsSet(final Collection<SubHyperplane<Euclidean3D>> boundary) {
|
||||||
super(boundary);
|
super(boundary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,21 +91,21 @@ public class PolyhedronsSet extends Region {
|
||||||
* @param zMin low bound along the z direction
|
* @param zMin low bound along the z direction
|
||||||
* @param zMax high bound along the z direction
|
* @param zMax high bound along the z direction
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public PolyhedronsSet(final double xMin, final double xMax,
|
public PolyhedronsSet(final double xMin, final double xMax,
|
||||||
final double yMin, final double yMax,
|
final double yMin, final double yMax,
|
||||||
final double zMin, final double zMax) {
|
final double zMin, final double zMax) {
|
||||||
this(buildConvex(Arrays.asList(new Hyperplane[] {
|
this(new RegionFactory<Euclidean3D>().buildConvex(
|
||||||
new Plane(new Vector3D(xMin, 0, 0), Vector3D.MINUS_I),
|
new Plane(new Vector3D(xMin, 0, 0), Vector3D.MINUS_I),
|
||||||
new Plane(new Vector3D(xMax, 0, 0), Vector3D.PLUS_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, yMin, 0), Vector3D.MINUS_J),
|
||||||
new Plane(new Vector3D(0, yMax, 0), Vector3D.PLUS_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, zMin), Vector3D.MINUS_K),
|
||||||
new Plane(new Vector3D(0, 0, zMax), Vector3D.PLUS_K)
|
new Plane(new Vector3D(0, 0, zMax), Vector3D.PLUS_K)).getTree(false));
|
||||||
})).getTree(false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public Region buildNew(final BSPTree tree) {
|
public PolyhedronsSet buildNew(final BSPTree<Euclidean3D> tree) {
|
||||||
return new PolyhedronsSet(tree);
|
return new PolyhedronsSet(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,32 +119,34 @@ public class PolyhedronsSet extends Region {
|
||||||
// the polyhedrons set as a finite outside
|
// the polyhedrons set as a finite outside
|
||||||
// surrounded by an infinite inside
|
// surrounded by an infinite inside
|
||||||
setSize(Double.POSITIVE_INFINITY);
|
setSize(Double.POSITIVE_INFINITY);
|
||||||
setBarycenter(Point3D.UNDEFINED);
|
setBarycenter(Vector3D.NaN);
|
||||||
} else {
|
} else {
|
||||||
// the polyhedrons set is finite, apply the remaining scaling factors
|
// the polyhedrons set is finite, apply the remaining scaling factors
|
||||||
setSize(getSize() / 3.0);
|
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. */
|
/** Visitor computing geometrical properties. */
|
||||||
private class FacetsContributionVisitor implements BSPTreeVisitor {
|
private class FacetsContributionVisitor implements BSPTreeVisitor<Euclidean3D> {
|
||||||
|
|
||||||
/** Simple constructor. */
|
/** Simple constructor. */
|
||||||
public FacetsContributionVisitor() {
|
public FacetsContributionVisitor() {
|
||||||
setSize(0);
|
setSize(0);
|
||||||
setBarycenter(new Point3D(0, 0, 0));
|
setBarycenter(new Vector3D(0, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public Order visitOrder(final BSPTree node) {
|
public Order visitOrder(final BSPTree<Euclidean3D> node) {
|
||||||
return Order.MINUS_SUB_PLUS;
|
return Order.MINUS_SUB_PLUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public void visitInternalNode(final BSPTree node) {
|
public void visitInternalNode(final BSPTree<Euclidean3D> node) {
|
||||||
final BoundaryAttribute attribute = (BoundaryAttribute) node.getAttribute();
|
@SuppressWarnings("unchecked")
|
||||||
|
final BoundaryAttribute<Euclidean3D> attribute =
|
||||||
|
(BoundaryAttribute<Euclidean3D>) node.getAttribute();
|
||||||
if (attribute.getPlusOutside() != null) {
|
if (attribute.getPlusOutside() != null) {
|
||||||
addContribution(attribute.getPlusOutside(), false);
|
addContribution(attribute.getPlusOutside(), false);
|
||||||
}
|
}
|
||||||
|
@ -148,32 +156,32 @@ public class PolyhedronsSet extends Region {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public void visitLeafNode(final BSPTree node) {
|
public void visitLeafNode(final BSPTree<Euclidean3D> node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add he contribution of a boundary facet.
|
/** Add he contribution of a boundary facet.
|
||||||
* @param facet boundary facet
|
* @param facet boundary facet
|
||||||
* @param reversed if true, the facet has the inside on its plus side
|
* @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<Euclidean3D> facet, final boolean reversed) {
|
||||||
|
|
||||||
final Region polygon = facet.getRemainingRegion();
|
final Region<Euclidean2D> polygon = ((SubPlane) facet).getRemainingRegion();
|
||||||
final double area = polygon.getSize();
|
final double area = polygon.getSize();
|
||||||
|
|
||||||
if (Double.isInfinite(area)) {
|
if (Double.isInfinite(area)) {
|
||||||
setSize(Double.POSITIVE_INFINITY);
|
setSize(Double.POSITIVE_INFINITY);
|
||||||
setBarycenter(Point3D.UNDEFINED);
|
setBarycenter(Vector3D.NaN);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
final Plane plane = (Plane) facet.getHyperplane();
|
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());
|
double scaled = area * Vector3D.dotProduct(facetB, plane.getNormal());
|
||||||
if (reversed) {
|
if (reversed) {
|
||||||
scaled = -scaled;
|
scaled = -scaled;
|
||||||
}
|
}
|
||||||
|
|
||||||
setSize(getSize() + 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
|
* given point, or null if the line does not intersect any
|
||||||
* sub-hyperplaned
|
* sub-hyperplaned
|
||||||
*/
|
*/
|
||||||
public SubHyperplane firstIntersection(final Vector3D point, final Line line) {
|
public SubHyperplane<Euclidean3D> firstIntersection(final Vector3D point, final Line line) {
|
||||||
return recurseFirstIntersection(getTree(true), point, 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
|
* given point, or null if the line does not intersect any
|
||||||
* sub-hyperplaned
|
* sub-hyperplaned
|
||||||
*/
|
*/
|
||||||
private SubHyperplane recurseFirstIntersection(final BSPTree node,
|
private SubHyperplane<Euclidean3D> recurseFirstIntersection(final BSPTree<Euclidean3D> node,
|
||||||
final Vector3D point,
|
final Vector3D point,
|
||||||
final Line line) {
|
final Line line) {
|
||||||
|
|
||||||
final SubHyperplane cut = node.getCut();
|
final SubHyperplane<Euclidean3D> cut = node.getCut();
|
||||||
if (cut == null) {
|
if (cut == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final BSPTree minus = node.getMinus();
|
final BSPTree<Euclidean3D> minus = node.getMinus();
|
||||||
final BSPTree plus = node.getPlus();
|
final BSPTree<Euclidean3D> plus = node.getPlus();
|
||||||
final Plane plane = (Plane) cut.getHyperplane();
|
final Plane plane = (Plane) cut.getHyperplane();
|
||||||
|
|
||||||
// establish search order
|
// 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 boolean in = FastMath.abs(offset) < 1.0e-10;
|
||||||
final BSPTree near;
|
final BSPTree<Euclidean3D> near;
|
||||||
final BSPTree far;
|
final BSPTree<Euclidean3D> far;
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
near = minus;
|
near = minus;
|
||||||
far = plus;
|
far = plus;
|
||||||
|
@ -227,14 +235,14 @@ public class PolyhedronsSet extends Region {
|
||||||
|
|
||||||
if (in) {
|
if (in) {
|
||||||
// search in the cut hyperplane
|
// search in the cut hyperplane
|
||||||
final SubHyperplane facet = boundaryFacet(point, node);
|
final SubHyperplane<Euclidean3D> facet = boundaryFacet(point, node);
|
||||||
if (facet != null) {
|
if (facet != null) {
|
||||||
return facet;
|
return facet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// search in the near branch
|
// search in the near branch
|
||||||
final SubHyperplane crossed = recurseFirstIntersection(near, point, line);
|
final SubHyperplane<Euclidean3D> crossed = recurseFirstIntersection(near, point, line);
|
||||||
if (crossed != null) {
|
if (crossed != null) {
|
||||||
return crossed;
|
return crossed;
|
||||||
}
|
}
|
||||||
|
@ -243,7 +251,7 @@ public class PolyhedronsSet extends Region {
|
||||||
// search in the cut hyperplane
|
// search in the cut hyperplane
|
||||||
final Vector3D hit3D = plane.intersection(line);
|
final Vector3D hit3D = plane.intersection(line);
|
||||||
if (hit3D != null) {
|
if (hit3D != null) {
|
||||||
final SubHyperplane facet = boundaryFacet(hit3D, node);
|
final SubHyperplane<Euclidean3D> facet = boundaryFacet(hit3D, node);
|
||||||
if (facet != null) {
|
if (facet != null) {
|
||||||
return facet;
|
return facet;
|
||||||
}
|
}
|
||||||
|
@ -261,15 +269,18 @@ public class PolyhedronsSet extends Region {
|
||||||
* @return the boundary facet this points belongs to (or null if it
|
* @return the boundary facet this points belongs to (or null if it
|
||||||
* does not belong to any boundary facet)
|
* does not belong to any boundary facet)
|
||||||
*/
|
*/
|
||||||
private SubHyperplane boundaryFacet(final Vector3D point, final BSPTree node) {
|
private SubHyperplane<Euclidean3D> boundaryFacet(final Vector3D point,
|
||||||
final Point point2D = node.getCut().getHyperplane().toSubSpace((Point) point);
|
final BSPTree<Euclidean3D> node) {
|
||||||
final BoundaryAttribute attribute = (BoundaryAttribute) node.getAttribute();
|
final Vector2D point2D = ((Plane) node.getCut().getHyperplane()).toSubSpace(point);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final BoundaryAttribute<Euclidean3D> attribute =
|
||||||
|
(BoundaryAttribute<Euclidean3D>) node.getAttribute();
|
||||||
if ((attribute.getPlusOutside() != null) &&
|
if ((attribute.getPlusOutside() != null) &&
|
||||||
(attribute.getPlusOutside().getRemainingRegion().checkPoint(point2D) == Location.INSIDE)) {
|
(((SubPlane) attribute.getPlusOutside()).getRemainingRegion().checkPoint(point2D) == Location.INSIDE)) {
|
||||||
return attribute.getPlusOutside();
|
return attribute.getPlusOutside();
|
||||||
}
|
}
|
||||||
if ((attribute.getPlusInside() != null) &&
|
if ((attribute.getPlusInside() != null) &&
|
||||||
(attribute.getPlusInside().getRemainingRegion().checkPoint(point2D) == Location.INSIDE)) {
|
(((SubPlane) attribute.getPlusInside()).getRemainingRegion().checkPoint(point2D) == Location.INSIDE)) {
|
||||||
return attribute.getPlusInside();
|
return attribute.getPlusInside();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -286,7 +297,7 @@ public class PolyhedronsSet extends Region {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 3D rotation as a Transform. */
|
/** 3D rotation as a Transform. */
|
||||||
private static class RotationTransform implements Transform {
|
private static class RotationTransform implements Transform<Euclidean3D, Euclidean2D> {
|
||||||
|
|
||||||
/** Center point of the rotation. */
|
/** Center point of the rotation. */
|
||||||
private Vector3D center;
|
private Vector3D center;
|
||||||
|
@ -295,10 +306,10 @@ public class PolyhedronsSet extends Region {
|
||||||
private Rotation rotation;
|
private Rotation rotation;
|
||||||
|
|
||||||
/** Cached original hyperplane. */
|
/** Cached original hyperplane. */
|
||||||
private Hyperplane cachedOriginal;
|
private Plane cachedOriginal;
|
||||||
|
|
||||||
/** Cached 2D transform valid inside the cached original hyperplane. */
|
/** Cached 2D transform valid inside the cached original hyperplane. */
|
||||||
private Transform cachedTransform;
|
private Transform<Euclidean2D, Euclidean1D> cachedTransform;
|
||||||
|
|
||||||
/** Build a rotation transform.
|
/** Build a rotation transform.
|
||||||
* @param center center point of the rotation
|
* @param center center point of the rotation
|
||||||
|
@ -310,40 +321,41 @@ public class PolyhedronsSet extends Region {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public Point apply(final Point point) {
|
public Vector3D apply(final Vector<Euclidean3D> point) {
|
||||||
final Vector3D delta = ((Vector3D) point).subtract(center);
|
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} */
|
/** {@inheritDoc} */
|
||||||
public Hyperplane apply(final Hyperplane hyperplane) {
|
public Plane apply(final Hyperplane<Euclidean3D> hyperplane) {
|
||||||
return ((Plane) hyperplane).rotate(center, rotation);
|
return ((Plane) hyperplane).rotate(center, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public SubHyperplane apply(final SubHyperplane sub,
|
public SubHyperplane<Euclidean2D> apply(final SubHyperplane<Euclidean2D> sub,
|
||||||
final Hyperplane original, final Hyperplane transformed) {
|
final Hyperplane<Euclidean3D> original,
|
||||||
|
final Hyperplane<Euclidean3D> transformed) {
|
||||||
if (original != cachedOriginal) {
|
if (original != cachedOriginal) {
|
||||||
// we have changed hyperplane, reset the in-hyperplane transform
|
// we have changed hyperplane, reset the in-hyperplane transform
|
||||||
|
|
||||||
final Plane oPlane = (Plane) original;
|
final Plane oPlane = (Plane) original;
|
||||||
final Plane tPlane = (Plane) transformed;
|
final Plane tPlane = (Plane) transformed;
|
||||||
final Vector3D p00 = oPlane.getOrigin();
|
final Vector3D p00 = oPlane.getOrigin();
|
||||||
final Vector3D p10 = (Vector3D) oPlane.toSpace(new Point2D(1.0, 0.0));
|
final Vector3D p10 = (Vector3D) oPlane.toSpace(new Vector2D(1.0, 0.0));
|
||||||
final Vector3D p01 = (Vector3D) oPlane.toSpace(new Point2D(0.0, 1.0));
|
final Vector3D p01 = (Vector3D) oPlane.toSpace(new Vector2D(0.0, 1.0));
|
||||||
final Point2D tP00 = (Point2D) tPlane.toSubSpace(apply((Point) p00));
|
final Vector2D tP00 = (Vector2D) tPlane.toSubSpace(apply(p00));
|
||||||
final Point2D tP10 = (Point2D) tPlane.toSubSpace(apply((Point) p10));
|
final Vector2D tP10 = (Vector2D) tPlane.toSubSpace(apply(p10));
|
||||||
final Point2D tP01 = (Point2D) tPlane.toSubSpace(apply((Point) p01));
|
final Vector2D tP01 = (Vector2D) tPlane.toSubSpace(apply(p01));
|
||||||
final AffineTransform at =
|
final AffineTransform at =
|
||||||
new AffineTransform(tP10.getX() - tP00.getX(), tP10.getY() - tP00.getY(),
|
new AffineTransform(tP10.getX() - tP00.getX(), tP10.getY() - tP00.getY(),
|
||||||
tP01.getX() - tP00.getX(), tP01.getY() - tP00.getY(),
|
tP01.getX() - tP00.getX(), tP01.getY() - tP00.getY(),
|
||||||
tP00.getX(), tP00.getY());
|
tP00.getX(), tP00.getY());
|
||||||
|
|
||||||
cachedOriginal = original;
|
cachedOriginal = (Plane) original;
|
||||||
cachedTransform = org.apache.commons.math.geometry.euclidean.twod.Line.getTransform(at);
|
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. */
|
/** 3D translation as a transform. */
|
||||||
private static class TranslationTransform implements Transform {
|
private static class TranslationTransform implements Transform<Euclidean3D, Euclidean2D> {
|
||||||
|
|
||||||
/** Translation vector. */
|
/** Translation vector. */
|
||||||
private Vector3D translation;
|
private Vector3D translation;
|
||||||
|
|
||||||
/** Cached original hyperplane. */
|
/** Cached original hyperplane. */
|
||||||
private Hyperplane cachedOriginal;
|
private Plane cachedOriginal;
|
||||||
|
|
||||||
/** Cached 2D transform valid inside the cached original hyperplane. */
|
/** Cached 2D transform valid inside the cached original hyperplane. */
|
||||||
private Transform cachedTransform;
|
private Transform<Euclidean2D, Euclidean1D> cachedTransform;
|
||||||
|
|
||||||
/** Build a translation transform.
|
/** Build a translation transform.
|
||||||
* @param translation translation vector
|
* @param translation translation vector
|
||||||
|
@ -377,34 +389,35 @@ public class PolyhedronsSet extends Region {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public Point apply(final Point point) {
|
public Vector3D apply(final Vector<Euclidean3D> point) {
|
||||||
return new Point3D(1.0, (Vector3D) point, 1.0, translation);
|
return new Vector3D(1.0, (Vector3D) point, 1.0, translation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public Hyperplane apply(final Hyperplane hyperplane) {
|
public Plane apply(final Hyperplane<Euclidean3D> hyperplane) {
|
||||||
return ((Plane) hyperplane).translate(translation);
|
return ((Plane) hyperplane).translate(translation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public SubHyperplane apply(final SubHyperplane sub,
|
public SubHyperplane<Euclidean2D> apply(final SubHyperplane<Euclidean2D> sub,
|
||||||
final Hyperplane original, final Hyperplane transformed) {
|
final Hyperplane<Euclidean3D> original,
|
||||||
|
final Hyperplane<Euclidean3D> transformed) {
|
||||||
if (original != cachedOriginal) {
|
if (original != cachedOriginal) {
|
||||||
// we have changed hyperplane, reset the in-hyperplane transform
|
// we have changed hyperplane, reset the in-hyperplane transform
|
||||||
|
|
||||||
final Plane oPlane = (Plane) original;
|
final Plane oPlane = (Plane) original;
|
||||||
final Plane tPlane = (Plane) transformed;
|
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 =
|
final AffineTransform at =
|
||||||
AffineTransform.getTranslateInstance(shift.getX(), shift.getY());
|
AffineTransform.getTranslateInstance(shift.getX(), shift.getY());
|
||||||
|
|
||||||
cachedOriginal = original;
|
cachedOriginal = (Plane) original;
|
||||||
cachedTransform =
|
cachedTransform =
|
||||||
org.apache.commons.math.geometry.euclidean.twod.Line.getTransform(at);
|
org.apache.commons.math.geometry.euclidean.twod.Line.getTransform(at);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sub.applyTransform(cachedTransform);
|
return ((SubLine) sub).applyTransform(cachedTransform);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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<Euclidean3D, Euclidean2D> {
|
||||||
|
|
||||||
|
/** Simple constructor.
|
||||||
|
* @param hyperplane underlying hyperplane
|
||||||
|
* @param remainingRegion remaining region of the hyperplane
|
||||||
|
*/
|
||||||
|
public SubPlane(final Hyperplane<Euclidean3D> hyperplane,
|
||||||
|
final Region<Euclidean2D> remainingRegion) {
|
||||||
|
super(hyperplane, remainingRegion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
protected AbstractSubHyperplane<Euclidean3D, Euclidean2D> buildNew(final Hyperplane<Euclidean3D> hyperplane,
|
||||||
|
final Region<Euclidean2D> remainingRegion) {
|
||||||
|
return new SubPlane(hyperplane, remainingRegion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public Side side(Hyperplane<Euclidean3D> 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<Euclidean3D> split(Hyperplane<Euclidean3D> 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<Euclidean3D>(null, this) :
|
||||||
|
new SplitSubHyperplane<Euclidean3D>(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<Euclidean2D> l2DMinus =
|
||||||
|
new org.apache.commons.math.geometry.euclidean.twod.Line(p, q).wholeHyperplane();
|
||||||
|
final SubHyperplane<Euclidean2D> l2DPlus =
|
||||||
|
new org.apache.commons.math.geometry.euclidean.twod.Line(q, p).wholeHyperplane();
|
||||||
|
|
||||||
|
final BSPTree<Euclidean2D> splitTree = getRemainingRegion().getTree(false).split(l2DMinus);
|
||||||
|
final BSPTree<Euclidean2D> plusTree = getRemainingRegion().isEmpty(splitTree.getPlus()) ?
|
||||||
|
new BSPTree<Euclidean2D>(Boolean.FALSE) :
|
||||||
|
new BSPTree<Euclidean2D>(l2DPlus, new BSPTree<Euclidean2D>(Boolean.FALSE),
|
||||||
|
splitTree.getPlus(), null);
|
||||||
|
|
||||||
|
final BSPTree<Euclidean2D> minusTree = getRemainingRegion().isEmpty(splitTree.getMinus()) ?
|
||||||
|
new BSPTree<Euclidean2D>(Boolean.FALSE) :
|
||||||
|
new BSPTree<Euclidean2D>(l2DMinus, new BSPTree<Euclidean2D>(Boolean.FALSE),
|
||||||
|
splitTree.getMinus(), null);
|
||||||
|
|
||||||
|
return new SplitSubHyperplane<Euclidean3D>(new SubPlane(thisPlane.copySelf(), new PolygonsSet(plusTree)),
|
||||||
|
new SubPlane(thisPlane.copySelf(), new PolygonsSet(minusTree)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -20,15 +20,14 @@ import java.awt.geom.AffineTransform;
|
||||||
|
|
||||||
import org.apache.commons.math.exception.MathIllegalArgumentException;
|
import org.apache.commons.math.exception.MathIllegalArgumentException;
|
||||||
import org.apache.commons.math.exception.util.LocalizedFormats;
|
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.IntervalsSet;
|
||||||
import org.apache.commons.math.geometry.euclidean.oned.OrientedPoint;
|
import org.apache.commons.math.geometry.euclidean.oned.OrientedPoint;
|
||||||
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.BSPTree;
|
import org.apache.commons.math.geometry.partitioning.Embedding;
|
||||||
import org.apache.commons.math.geometry.partitioning.Hyperplane;
|
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.SubHyperplane;
|
||||||
import org.apache.commons.math.geometry.partitioning.SubSpace;
|
|
||||||
import org.apache.commons.math.geometry.partitioning.Transform;
|
import org.apache.commons.math.geometry.partitioning.Transform;
|
||||||
import org.apache.commons.math.util.FastMath;
|
import org.apache.commons.math.util.FastMath;
|
||||||
import org.apache.commons.math.util.MathUtils;
|
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
|
* left half plane is the set of points with negative offsets and the
|
||||||
* right half plane is the set of points with positive offsets.</p>
|
* right half plane is the set of points with positive offsets.</p>
|
||||||
|
|
||||||
* @version $Revision$ $Date$
|
* @version $Id:$
|
||||||
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class Line implements Hyperplane {
|
public class Line implements Hyperplane<Euclidean2D>, Embedding<Euclidean2D, Euclidean1D> {
|
||||||
|
|
||||||
/** Angle with respect to the abscissa axis. */
|
/** Angle with respect to the abscissa axis. */
|
||||||
private double angle;
|
private double angle;
|
||||||
|
@ -78,7 +78,7 @@ public class Line implements Hyperplane {
|
||||||
* @param p1 first point
|
* @param p1 first point
|
||||||
* @param p2 second point
|
* @param p2 second point
|
||||||
*/
|
*/
|
||||||
public Line(final Point2D p1, final Point2D p2) {
|
public Line(final Vector2D p1, final Vector2D p2) {
|
||||||
reset(p1, p2);
|
reset(p1, p2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ public class Line implements Hyperplane {
|
||||||
* @param p point belonging to the line
|
* @param p point belonging to the line
|
||||||
* @param angle angle of the line with respect to abscissa axis
|
* @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);
|
reset(p, angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ public class Line implements Hyperplane {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public Hyperplane copySelf() {
|
public Line copySelf() {
|
||||||
return new Line(this);
|
return new Line(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,20 +125,20 @@ public class Line implements Hyperplane {
|
||||||
* @param p1 first point
|
* @param p1 first point
|
||||||
* @param p2 second point
|
* @param p2 second point
|
||||||
*/
|
*/
|
||||||
public void reset(final Point2D p1, final Point2D p2) {
|
public void reset(final Vector2D p1, final Vector2D p2) {
|
||||||
final double dx = p2.x - p1.x;
|
final double dx = p2.getX() - p1.getX();
|
||||||
final double dy = p2.y - p1.y;
|
final double dy = p2.getY() - p1.getY();
|
||||||
final double d = FastMath.hypot(dx, dy);
|
final double d = FastMath.hypot(dx, dy);
|
||||||
if (d == 0.0) {
|
if (d == 0.0) {
|
||||||
angle = 0.0;
|
angle = 0.0;
|
||||||
cos = 1.0;
|
cos = 1.0;
|
||||||
sin = 0.0;
|
sin = 0.0;
|
||||||
originOffset = p1.y;
|
originOffset = p1.getY();
|
||||||
} else {
|
} else {
|
||||||
angle = FastMath.PI + FastMath.atan2(-dy, -dx);
|
angle = FastMath.PI + FastMath.atan2(-dy, -dx);
|
||||||
cos = FastMath.cos(angle);
|
cos = FastMath.cos(angle);
|
||||||
sin = FastMath.sin(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 p point belonging to the line
|
||||||
* @param alpha angle of the line with respect to abscissa axis
|
* @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);
|
this.angle = MathUtils.normalizeAngle(alpha, FastMath.PI);
|
||||||
cos = FastMath.cos(this.angle);
|
cos = FastMath.cos(this.angle);
|
||||||
sin = FastMath.sin(this.angle);
|
sin = FastMath.sin(this.angle);
|
||||||
originOffset = cos * p.y - sin * p.x;
|
originOffset = cos * p.getY() - sin * p.getX();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Revert the instance.
|
/** Revert the instance.
|
||||||
|
@ -176,57 +176,44 @@ public class Line implements Hyperplane {
|
||||||
-cos, -sin, -originOffset);
|
-cos, -sin, -originOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Transform a 2D space point into a line point.
|
/** {@inheritDoc} */
|
||||||
* @param point 2D point (must be a {@link Point2D Point2D}
|
public Vector1D toSubSpace(final Vector<Euclidean2D> point) {
|
||||||
* instance)
|
Vector2D p2 = (Vector2D) point;
|
||||||
* @return line point corresponding to the 2D point (really a {@link
|
return new Vector1D(cos * p2.getX() + sin * p2.getY());
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get one point from the line.
|
/** {@inheritDoc} */
|
||||||
* @param point desired abscissa for the point (must be a {@link
|
public Vector2D toSpace(final Vector<Euclidean1D> point) {
|
||||||
* org.apache.commons.math.geometry.euclidean.oned.Point1D Point1D} instance)
|
final double abscissa = ((Vector1D) point).getX();
|
||||||
* @return line point at specified abscissa (really a {@link Point2D
|
return new Vector2D(abscissa * cos - originOffset * sin,
|
||||||
* Point2D} instance)
|
|
||||||
*/
|
|
||||||
public Point toSpace(final Point point) {
|
|
||||||
final double abscissa = ((Point1D) point).getAbscissa();
|
|
||||||
return new Point2D(abscissa * cos - originOffset * sin,
|
|
||||||
abscissa * sin + originOffset * cos);
|
abscissa * sin + originOffset * cos);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the intersection point of the instance and another line.
|
/** Get the intersection point of the instance and another line.
|
||||||
* @param other other line
|
* @param other other line
|
||||||
* @return intersection point of the instance and the 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<Euclidean2D> other) {
|
||||||
final Line otherL = (Line) other;
|
final Line otherL = (Line) other;
|
||||||
final double d = sin * otherL.cos - otherL.sin * cos;
|
final double d = sin * otherL.cos - otherL.sin * cos;
|
||||||
if (FastMath.abs(d) < 1.0e-10) {
|
if (FastMath.abs(d) < 1.0e-10) {
|
||||||
return null;
|
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);
|
(sin * otherL.originOffset - otherL.sin * originOffset) / d);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Build a region covering the whole hyperplane.
|
/** {@inheritDoc} */
|
||||||
* @return a region covering the whole hyperplane
|
public SubLine wholeHyperplane() {
|
||||||
*/
|
return new SubLine(this, new IntervalsSet());
|
||||||
public Region wholeHyperplane() {
|
|
||||||
return new IntervalsSet();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Build a region covering the whole space.
|
/** Build a region covering the whole space.
|
||||||
* @return a region containing the instance (really a {@link
|
* @return a region containing the instance (really a {@link
|
||||||
* PolygonsSet PolygonsSet} instance)
|
* PolygonsSet PolygonsSet} instance)
|
||||||
*/
|
*/
|
||||||
public Region wholeSpace() {
|
public PolygonsSet wholeSpace() {
|
||||||
return new PolygonsSet();
|
return new PolygonsSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +227,8 @@ public class Line implements Hyperplane {
|
||||||
* @param line line to check
|
* @param line line to check
|
||||||
* @return offset of the line
|
* @return offset of the line
|
||||||
*/
|
*/
|
||||||
public double getOffset(final Line line) {
|
public double getOffset(final Hyperplane<Euclidean2D> hyperplane) {
|
||||||
|
Line line = (Line) hyperplane;
|
||||||
return originOffset +
|
return originOffset +
|
||||||
((cos * line.cos + sin * line.sin > 0) ? -line.originOffset : line.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
|
* 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
|
* negative if it is on the left side, according to its natural
|
||||||
* orientation.</p>
|
* orientation.</p>
|
||||||
* @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
|
* @return offset of the point
|
||||||
*/
|
*/
|
||||||
public double getOffset(final Point point) {
|
public double getOffset(final Vector<Euclidean2D> point) {
|
||||||
final Point2D p2D = (Point2D) point;
|
Vector2D p2 = (Vector2D) point;
|
||||||
return sin * p2D.x - cos * p2D.y + originOffset;
|
return sin * p2.getX() - cos * p2.getY() + originOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check if the instance has the same orientation as another hyperplane.
|
/** 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
|
* @return true if the instance and the other hyperplane have
|
||||||
* the same orientation
|
* the same orientation
|
||||||
*/
|
*/
|
||||||
public boolean sameOrientationAs(final Hyperplane other) {
|
public boolean sameOrientationAs(final Hyperplane<Euclidean2D> other) {
|
||||||
final Line otherL = (Line) other;
|
final Line otherL = (Line) other;
|
||||||
return (sin * otherL.sin + cos * otherL.cos) >= 0.0;
|
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
|
* @return one point in the plane, with given abscissa and offset
|
||||||
* relative to the line
|
* relative to the line
|
||||||
*/
|
*/
|
||||||
public Point2D getPointAt(final Point1D abscissa, final double offset) {
|
public Vector2D getPointAt(final Vector1D abscissa, final double offset) {
|
||||||
final double x = abscissa.getAbscissa();
|
final double x = abscissa.getX();
|
||||||
final double dOffset = offset - originOffset;
|
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.
|
/** Check if the line contains a point.
|
||||||
* @param p point to check
|
* @param p point to check
|
||||||
* @return true if p belongs to the line
|
* @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;
|
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.
|
/** Translate the line to force it passing by a point.
|
||||||
* @param p point by which the line should pass
|
* @param p point by which the line should pass
|
||||||
*/
|
*/
|
||||||
public void translateToPoint(final Point2D p) {
|
public void translateToPoint(final Vector2D p) {
|
||||||
originOffset = cos * p.y - sin * p.x;
|
originOffset = cos * p.getY() - sin * p.getX();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the angle of the line.
|
/** Get the angle of the line.
|
||||||
|
@ -342,75 +330,6 @@ public class Line implements Hyperplane {
|
||||||
originOffset = offset;
|
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
|
/** Get a {@link org.apache.commons.math.geometry.partitioning.Transform
|
||||||
* Transform} embedding an affine transform.
|
* Transform} embedding an affine transform.
|
||||||
* @param transform affine transform to embed (must be inversible
|
* @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
|
* apply(Hyperplane)} method would work only for some lines, and
|
||||||
* fail for other ones)
|
* fail for other ones)
|
||||||
* @return a new transform that can be applied to either {@link
|
* @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
|
* org.apache.commons.math.geometry.partitioning.SubHyperplane
|
||||||
* SubHyperplane} instances
|
* SubHyperplane} instances
|
||||||
* @exception MathIllegalArgumentException if the transform is non invertible
|
* @exception MathIllegalArgumentException if the transform is non invertible
|
||||||
*/
|
*/
|
||||||
public static Transform getTransform(final AffineTransform transform) throws MathIllegalArgumentException {
|
public static Transform<Euclidean2D, Euclidean1D> getTransform(final AffineTransform transform)
|
||||||
|
throws MathIllegalArgumentException {
|
||||||
return new LineTransform(transform);
|
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
|
* applied to a large number of lines (for example to a large
|
||||||
* polygon)./<p>
|
* polygon)./<p>
|
||||||
*/
|
*/
|
||||||
private static class LineTransform implements Transform {
|
private static class LineTransform implements Transform<Euclidean2D, Euclidean1D> {
|
||||||
|
|
||||||
// CHECKSTYLE: stop JavadocVariable check
|
// CHECKSTYLE: stop JavadocVariable check
|
||||||
private double cXX;
|
private double cXX;
|
||||||
|
@ -478,16 +398,16 @@ public class Line implements Hyperplane {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public Point apply(final Point point) {
|
public Vector2D apply(final Vector<Euclidean2D> point) {
|
||||||
final Point2D p2D = (Point2D) point;
|
final Vector2D p2D = (Vector2D) point;
|
||||||
final double x = p2D.getX();
|
final double x = p2D.getX();
|
||||||
final double y = p2D.getY();
|
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);
|
cYX * x + cYY * y + cY1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public Hyperplane apply(final Hyperplane hyperplane) {
|
public Line apply(final Hyperplane<Euclidean2D> hyperplane) {
|
||||||
final Line line = (Line) hyperplane;
|
final Line line = (Line) hyperplane;
|
||||||
final double rOffset = c1X * line.cos + c1Y * line.sin + c11 * line.originOffset;
|
final double rOffset = c1X * line.cos + c1Y * line.sin + c11 * line.originOffset;
|
||||||
final double rCos = cXX * line.cos + cXY * line.sin;
|
final double rCos = cXX * line.cos + cXY * line.sin;
|
||||||
|
@ -499,12 +419,15 @@ public class Line implements Hyperplane {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public SubHyperplane apply(final SubHyperplane sub,
|
public SubHyperplane<Euclidean1D> apply(final SubHyperplane<Euclidean1D> sub,
|
||||||
final Hyperplane original, final Hyperplane transformed) {
|
final Hyperplane<Euclidean2D> original,
|
||||||
final OrientedPoint op = (OrientedPoint) sub.getHyperplane();
|
final Hyperplane<Euclidean2D> transformed) {
|
||||||
final Point1D newLoc =
|
final OrientedPoint op = (OrientedPoint) sub.getHyperplane();
|
||||||
(Point1D) transformed.toSubSpace(apply(original.toSpace(op.getLocation())));
|
final Line originalLine = (Line) original;
|
||||||
return new SubHyperplane(new OrientedPoint(newLoc, op.isDirect()));
|
final Line transformedLine = (Line) transformed;
|
||||||
|
final Vector1D newLoc =
|
||||||
|
transformedLine.toSubSpace(apply(originalLine.toSpace(op.getLocation())));
|
||||||
|
return new OrientedPoint(newLoc, op.isDirect()).wholeHyperplane();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,44 +17,43 @@
|
||||||
package org.apache.commons.math.geometry.euclidean.twod;
|
package org.apache.commons.math.geometry.euclidean.twod;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import org.apache.commons.math.exception.MathIllegalArgumentException;
|
import org.apache.commons.math.exception.MathIllegalArgumentException;
|
||||||
import org.apache.commons.math.exception.util.LocalizedFormats;
|
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.IntervalsSet;
|
||||||
import org.apache.commons.math.geometry.euclidean.oned.Point1D;
|
|
||||||
import org.apache.commons.math.geometry.partitioning.Hyperplane;
|
|
||||||
import org.apache.commons.math.geometry.partitioning.Region;
|
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.SubHyperplane;
|
||||||
|
|
||||||
/** This class represent a tree of nested 2D boundary loops.
|
/** This class represent a tree of nested 2D boundary loops.
|
||||||
|
|
||||||
* <p>This class is used during Piece instances construction.
|
* <p>This class is used for piecewise polygons construction.
|
||||||
* Beams are built using the outline edges as
|
* Polygons are built using the outline edges as
|
||||||
* representative of facets, the orientation of these facets are
|
* representative of boundaries, the orientation of these lines are
|
||||||
* meaningful. However, we want to allow the user to specify its
|
* meaningful. However, we want to allow the user to specify its
|
||||||
* outline loops without having to take care of this orientation. This
|
* outline loops without having to take care of this orientation. This
|
||||||
* class is devoted to correct mis-oriented loops.<p>
|
* class is devoted to correct mis-oriented loops.<p>
|
||||||
|
|
||||||
* <p>Orientation is computed assuming the piece is finite, i.e. the
|
* <p>Orientation is computed assuming the piecewise polygon is finite,
|
||||||
* outermost loops have their exterior side facing points at infinity,
|
* i.e. the outermost loops have their exterior side facing points at
|
||||||
* and hence are oriented counter-clockwise. The orientation of
|
* infinity, and hence are oriented counter-clockwise. The orientation of
|
||||||
* internal loops is computed as the reverse of the orientation of
|
* internal loops is computed as the reverse of the orientation of
|
||||||
* their immediate surrounding loop.</p>
|
* their immediate surrounding loop.</p>
|
||||||
|
|
||||||
* @version $Revision$ $Date$
|
* @version $Id:$
|
||||||
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
class NestedLoops {
|
class NestedLoops {
|
||||||
|
|
||||||
/** Boundary loop. */
|
/** Boundary loop. */
|
||||||
private Point2D[] loop;
|
private Vector2D[] loop;
|
||||||
|
|
||||||
/** Surrounded loops. */
|
/** Surrounded loops. */
|
||||||
private ArrayList<NestedLoops> surrounded;
|
private ArrayList<NestedLoops> surrounded;
|
||||||
|
|
||||||
/** Polygon enclosing a finite region. */
|
/** Polygon enclosing a finite region. */
|
||||||
private Region polygon;
|
private Region<Euclidean2D> polygon;
|
||||||
|
|
||||||
/** Indicator for original loop orientation. */
|
/** Indicator for original loop orientation. */
|
||||||
private boolean originalIsClockwise;
|
private boolean originalIsClockwise;
|
||||||
|
@ -74,7 +73,7 @@ class NestedLoops {
|
||||||
* @param loop boundary loop (will be reversed in place if needed)
|
* @param loop boundary loop (will be reversed in place if needed)
|
||||||
* @exception MathIllegalArgumentException if an outline has an open boundary loop
|
* @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) {
|
if (loop[0] == null) {
|
||||||
throw new MathIllegalArgumentException(LocalizedFormats.OUTLINE_BOUNDARY_LOOP_OPEN);
|
throw new MathIllegalArgumentException(LocalizedFormats.OUTLINE_BOUNDARY_LOOP_OPEN);
|
||||||
|
@ -84,23 +83,21 @@ class NestedLoops {
|
||||||
surrounded = new ArrayList<NestedLoops>();
|
surrounded = new ArrayList<NestedLoops>();
|
||||||
|
|
||||||
// build the polygon defined by the loop
|
// build the polygon defined by the loop
|
||||||
final ArrayList<SubHyperplane> edges = new ArrayList<SubHyperplane>();
|
final ArrayList<SubHyperplane<Euclidean2D>> edges = new ArrayList<SubHyperplane<Euclidean2D>>();
|
||||||
Point2D current = loop[loop.length - 1];
|
Vector2D current = loop[loop.length - 1];
|
||||||
for (int i = 0; i < loop.length; ++i) {
|
for (int i = 0; i < loop.length; ++i) {
|
||||||
final Point2D previous = current;
|
final Vector2D previous = current;
|
||||||
current = loop[i];
|
current = loop[i];
|
||||||
final Line line = new Line(previous, current);
|
final Line line = new Line(previous, current);
|
||||||
final Region region = Region.buildConvex(Arrays.asList(new Hyperplane[] {
|
final IntervalsSet region =
|
||||||
new OrientedPoint((Point1D) line.toSubSpace(previous), false),
|
new IntervalsSet(line.toSubSpace(previous).getX(), line.toSubSpace(current).getX());
|
||||||
new OrientedPoint((Point1D) line.toSubSpace(current), true)
|
edges.add(new SubLine(line, region));
|
||||||
}));
|
|
||||||
edges.add(new SubHyperplane(line, region));
|
|
||||||
}
|
}
|
||||||
polygon = new PolygonsSet(edges);
|
polygon = new PolygonsSet(edges);
|
||||||
|
|
||||||
// ensure the polygon encloses a finite region of the plane
|
// ensure the polygon encloses a finite region of the plane
|
||||||
if (Double.isInfinite(polygon.getSize())) {
|
if (Double.isInfinite(polygon.getSize())) {
|
||||||
polygon = polygon.getComplement();
|
polygon = new RegionFactory<Euclidean2D>().getComplement(polygon);
|
||||||
originalIsClockwise = false;
|
originalIsClockwise = false;
|
||||||
} else {
|
} else {
|
||||||
originalIsClockwise = true;
|
originalIsClockwise = true;
|
||||||
|
@ -113,7 +110,7 @@ class NestedLoops {
|
||||||
* @exception MathIllegalArgumentException if an outline has crossing
|
* @exception MathIllegalArgumentException if an outline has crossing
|
||||||
* boundary loops or open boundary loops
|
* 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));
|
add(new NestedLoops(bLoop));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,8 +139,9 @@ class NestedLoops {
|
||||||
}
|
}
|
||||||
|
|
||||||
// we should be separate from the remaining children
|
// we should be separate from the remaining children
|
||||||
|
RegionFactory<Euclidean2D> factory = new RegionFactory<Euclidean2D>();
|
||||||
for (final NestedLoops child : surrounded) {
|
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);
|
throw new MathIllegalArgumentException(LocalizedFormats.CROSSING_BOUNDARY_LOOPS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,7 +152,7 @@ class NestedLoops {
|
||||||
|
|
||||||
/** Correct the orientation of the loops contained in the tree.
|
/** Correct the orientation of the loops contained in the tree.
|
||||||
* <p>This is this method that really inverts the loops that where
|
* <p>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</p>
|
* they are mis-oriented</p>
|
||||||
*/
|
*/
|
||||||
public void correctOrientation() {
|
public void correctOrientation() {
|
||||||
|
@ -174,7 +172,7 @@ class NestedLoops {
|
||||||
int min = -1;
|
int min = -1;
|
||||||
int max = loop.length;
|
int max = loop.length;
|
||||||
while (++min < --max) {
|
while (++min < --max) {
|
||||||
final Point2D tmp = loop[min];
|
final Vector2D tmp = loop[min];
|
||||||
loop[min] = loop[max];
|
loop[min] = loop[max];
|
||||||
loop[max] = tmp;
|
loop[max] = tmp;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,25 +17,27 @@
|
||||||
package org.apache.commons.math.geometry.euclidean.twod;
|
package org.apache.commons.math.geometry.euclidean.twod;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
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.BSPTree;
|
||||||
import org.apache.commons.math.geometry.partitioning.Hyperplane;
|
|
||||||
import org.apache.commons.math.geometry.partitioning.Region;
|
import org.apache.commons.math.geometry.partitioning.Region;
|
||||||
import org.apache.commons.math.geometry.partitioning.SubHyperplane;
|
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.geometry.partitioning.utilities.AVLTree;
|
||||||
import org.apache.commons.math.util.FastMath;
|
import org.apache.commons.math.util.FastMath;
|
||||||
|
|
||||||
/** This class represents a 2D region: a set of polygons.
|
/** 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<Euclidean2D, Euclidean1D> {
|
||||||
|
|
||||||
/** Vertices organized as boundary loops. */
|
/** Vertices organized as boundary loops. */
|
||||||
private Point2D[][] vertices;
|
private Vector2D[][] vertices;
|
||||||
|
|
||||||
/** Build a polygons set representing the whole real line.
|
/** 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}</p>
|
* {@code Boolean.TRUE} and {@code Boolean.FALSE}</p>
|
||||||
* @param tree inside/outside BSP tree representing the region
|
* @param tree inside/outside BSP tree representing the region
|
||||||
*/
|
*/
|
||||||
public PolygonsSet(final BSPTree tree) {
|
public PolygonsSet(final BSPTree<Euclidean2D> tree) {
|
||||||
super(tree);
|
super(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +65,7 @@ public class PolygonsSet extends Region {
|
||||||
* its plus side.</p>
|
* its plus side.</p>
|
||||||
* <p>The boundary elements can be in any order, and can form
|
* <p>The boundary elements can be in any order, and can form
|
||||||
* several non-connected sets (like for example polygons with holes
|
* 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
|
* fact, the elements do not even need to be connected together
|
||||||
* (their topological connections are not used here). However, if the
|
* (their topological connections are not used here). However, if the
|
||||||
* boundary does not really separate an inside open from an outside
|
* 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
|
* @param boundary collection of boundary elements, as a
|
||||||
* collection of {@link SubHyperplane SubHyperplane} objects
|
* collection of {@link SubHyperplane SubHyperplane} objects
|
||||||
*/
|
*/
|
||||||
public PolygonsSet(final Collection<SubHyperplane> boundary) {
|
public PolygonsSet(final Collection<SubHyperplane<Euclidean2D>> boundary) {
|
||||||
super(boundary);
|
super(boundary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +90,7 @@ public class PolygonsSet extends Region {
|
||||||
*/
|
*/
|
||||||
public PolygonsSet(final double xMin, final double xMax,
|
public PolygonsSet(final double xMin, final double xMax,
|
||||||
final double yMin, final double yMax) {
|
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.
|
/** 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
|
* @param yMax high bound along the y direction
|
||||||
* @return boundary of the box
|
* @return boundary of the box
|
||||||
*/
|
*/
|
||||||
private static List<Hyperplane> boxBoundary(final double xMin, final double xMax,
|
private static Line[] boxBoundary(final double xMin, final double xMax,
|
||||||
final double yMin, final double yMax) {
|
final double yMin, final double yMax) {
|
||||||
final Point2D minMin = new Point2D(xMin, yMin);
|
final Vector2D minMin = new Vector2D(xMin, yMin);
|
||||||
final Point2D minMax = new Point2D(xMin, yMax);
|
final Vector2D minMax = new Vector2D(xMin, yMax);
|
||||||
final Point2D maxMin = new Point2D(xMax, yMin);
|
final Vector2D maxMin = new Vector2D(xMax, yMin);
|
||||||
final Point2D maxMax = new Point2D(xMax, yMax);
|
final Vector2D maxMax = new Vector2D(xMax, yMax);
|
||||||
return Arrays.asList(new Hyperplane[] {
|
return new Line[] {
|
||||||
new Line(minMin, maxMin),
|
new Line(minMin, maxMin),
|
||||||
new Line(maxMin, maxMax),
|
new Line(maxMin, maxMax),
|
||||||
new Line(maxMax, minMax),
|
new Line(maxMax, minMax),
|
||||||
new Line(minMax, minMin)
|
new Line(minMax, minMin)
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public Region buildNew(final BSPTree tree) {
|
public PolygonsSet buildNew(final BSPTree<Euclidean2D> tree) {
|
||||||
return new PolygonsSet(tree);
|
return new PolygonsSet(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
protected void computeGeometricalProperties() {
|
protected void computeGeometricalProperties() {
|
||||||
|
|
||||||
final Point2D[][] v = getVertices();
|
final Vector2D[][] v = getVertices();
|
||||||
|
|
||||||
if (v.length == 0) {
|
if (v.length == 0) {
|
||||||
if ((Boolean) getTree(false).getAttribute()) {
|
if ((Boolean) getTree(false).getAttribute()) {
|
||||||
setSize(Double.POSITIVE_INFINITY);
|
setSize(Double.POSITIVE_INFINITY);
|
||||||
setBarycenter(Point2D.UNDEFINED);
|
setBarycenter(Vector2D.NaN);
|
||||||
} else {
|
} else {
|
||||||
setSize(0);
|
setSize(0);
|
||||||
setBarycenter(new Point2D(0, 0));
|
setBarycenter(new Vector2D(0, 0));
|
||||||
}
|
}
|
||||||
} else if (v[0][0] == null) {
|
} else if (v[0][0] == null) {
|
||||||
// there is at least one open-loop: the polygon is infinite
|
// there is at least one open-loop: the polygon is infinite
|
||||||
setSize(Double.POSITIVE_INFINITY);
|
setSize(Double.POSITIVE_INFINITY);
|
||||||
setBarycenter(Point2D.UNDEFINED);
|
setBarycenter(Vector2D.NaN);
|
||||||
} else {
|
} else {
|
||||||
// all loops are closed, we compute some integrals around the shape
|
// all loops are closed, we compute some integrals around the shape
|
||||||
|
|
||||||
|
@ -141,14 +143,14 @@ public class PolygonsSet extends Region {
|
||||||
double sumX = 0;
|
double sumX = 0;
|
||||||
double sumY = 0;
|
double sumY = 0;
|
||||||
|
|
||||||
for (Point2D[] loop : v) {
|
for (Vector2D[] loop : v) {
|
||||||
double x1 = loop[loop.length - 1].x;
|
double x1 = loop[loop.length - 1].getX();
|
||||||
double y1 = loop[loop.length - 1].y;
|
double y1 = loop[loop.length - 1].getY();
|
||||||
for (final Point2D point : loop) {
|
for (final Vector2D point : loop) {
|
||||||
final double x0 = x1;
|
final double x0 = x1;
|
||||||
final double y0 = y1;
|
final double y0 = y1;
|
||||||
x1 = point.x;
|
x1 = point.getX();
|
||||||
y1 = point.y;
|
y1 = point.getY();
|
||||||
final double factor = x0 * y1 - y0 * x1;
|
final double factor = x0 * y1 - y0 * x1;
|
||||||
sum += factor;
|
sum += factor;
|
||||||
sumX += factor * (x0 + x1);
|
sumX += factor * (x0 + x1);
|
||||||
|
@ -159,10 +161,10 @@ public class PolygonsSet extends Region {
|
||||||
if (sum < 0) {
|
if (sum < 0) {
|
||||||
// the polygon as a finite outside surrounded by an infinite inside
|
// the polygon as a finite outside surrounded by an infinite inside
|
||||||
setSize(Double.POSITIVE_INFINITY);
|
setSize(Double.POSITIVE_INFINITY);
|
||||||
setBarycenter(Point2D.UNDEFINED);
|
setBarycenter(Vector2D.NaN);
|
||||||
} else {
|
} else {
|
||||||
setSize(sum / 2);
|
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
|
* loops with the open loops first (the returned value is guaranteed
|
||||||
* to be non-null)
|
* to be non-null)
|
||||||
*/
|
*/
|
||||||
public Point2D[][] getVertices() {
|
public Vector2D[][] getVertices() {
|
||||||
if (vertices == null) {
|
if (vertices == null) {
|
||||||
if (getTree(false).getCut() == null) {
|
if (getTree(false).getCut() == null) {
|
||||||
vertices = new Point2D[0][];
|
vertices = new Vector2D[0][];
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// sort the segmfinal ents according to their start point
|
// sort the segments according to their start point
|
||||||
final SegmentsBuilder visitor = new SegmentsBuilder();
|
final SegmentsBuilder visitor = new SegmentsBuilder();
|
||||||
getTree(true).visit(visitor);
|
getTree(true).visit(visitor);
|
||||||
final AVLTree<Segment> sorted = visitor.getSorted();
|
final AVLTree<Segment> sorted = visitor.getSorted();
|
||||||
|
|
||||||
// identify the loops, starting from the open ones
|
// 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<List<Segment>> loops = new ArrayList<List<Segment>>();
|
final ArrayList<List<Segment>> loops = new ArrayList<List<Segment>>();
|
||||||
while (!sorted.isEmpty()) {
|
while (!sorted.isEmpty()) {
|
||||||
final AVLTree<Segment>.Node node = sorted.getSmallest();
|
final AVLTree<Segment>.Node node = sorted.getSmallest();
|
||||||
|
@ -215,31 +217,30 @@ public class PolygonsSet extends Region {
|
||||||
}
|
}
|
||||||
|
|
||||||
// tranform the loops in an array of arrays of points
|
// tranform the loops in an array of arrays of points
|
||||||
vertices = new Point2D[loops.size()][];
|
vertices = new Vector2D[loops.size()][];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (final List<Segment> loop : loops) {
|
for (final List<Segment> loop : loops) {
|
||||||
if (loop.size() < 2) {
|
if (loop.size() < 2) {
|
||||||
// sifinal ngle infinite line
|
// single infinite line
|
||||||
final Line line = ((Segment) loop.get(0)).getLine();
|
final Line line = loop.get(0).getLine();
|
||||||
vertices[i++] = new Point2D[] {
|
vertices[i++] = new Vector2D[] {
|
||||||
null,
|
null,
|
||||||
(Point2D) line.toSpace(new Point1D(-Float.MAX_VALUE)),
|
line.toSpace(new Vector1D(-Float.MAX_VALUE)),
|
||||||
(Point2D) line.toSpace(new Point1D(+Float.MAX_VALUE))
|
line.toSpace(new Vector1D(+Float.MAX_VALUE))
|
||||||
};
|
};
|
||||||
} else if (((Segment) loop.get(0)).getStart() == null) {
|
} else if (loop.get(0).getStart() == null) {
|
||||||
// open lofinal op with at least one real point
|
// open loop with at least one real point
|
||||||
final Point2D[] array = new Point2D[loop.size() + 2];
|
final Vector2D[] array = new Vector2D[loop.size() + 2];
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (Segment segment : loop) {
|
for (Segment segment : loop) {
|
||||||
|
|
||||||
if (j == 0) {
|
if (j == 0) {
|
||||||
// null point and first dummy point
|
// null point and first dummy point
|
||||||
double x =
|
double x = segment.getLine().toSubSpace(segment.getEnd()).getX();
|
||||||
((Point1D) segment.getLine().toSubSpace(segment.getEnd())).getAbscissa();
|
|
||||||
x -= FastMath.max(1.0, FastMath.abs(x / 2));
|
x -= FastMath.max(1.0, FastMath.abs(x / 2));
|
||||||
array[j++] = null;
|
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)) {
|
if (j < (array.length - 1)) {
|
||||||
|
@ -249,16 +250,15 @@ public class PolygonsSet extends Region {
|
||||||
|
|
||||||
if (j == (array.length - 1)) {
|
if (j == (array.length - 1)) {
|
||||||
// last dummy point
|
// last dummy point
|
||||||
double x =
|
double x = segment.getLine().toSubSpace(segment.getStart()).getX();
|
||||||
((Point1D) segment.getLine().toSubSpace(segment.getStart())).getAbscissa();
|
|
||||||
x += FastMath.max(1.0, FastMath.abs(x / 2));
|
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;
|
vertices[i++] = array;
|
||||||
} else {
|
} else {
|
||||||
final Point2D[] array = new Point2D[loop.size()];
|
final Vector2D[] array = new Vector2D[loop.size()];
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (Segment segment : loop) {
|
for (Segment segment : loop) {
|
||||||
array[j++] = segment.getStart();
|
array[j++] = segment.getStart();
|
||||||
|
@ -285,10 +285,10 @@ public class PolygonsSet extends Region {
|
||||||
final AVLTree<Segment> sorted) {
|
final AVLTree<Segment> sorted) {
|
||||||
|
|
||||||
final ArrayList<Segment> loop = new ArrayList<Segment>();
|
final ArrayList<Segment> loop = new ArrayList<Segment>();
|
||||||
Segment segment = (Segment) node.getElement();
|
Segment segment = node.getElement();
|
||||||
loop.add(segment);
|
loop.add(segment);
|
||||||
final Point2D globalStart = segment.getStart();
|
final Vector2D globalStart = segment.getStart();
|
||||||
Point2D end = segment.getEnd();
|
Vector2D end = segment.getEnd();
|
||||||
node.delete();
|
node.delete();
|
||||||
|
|
||||||
// is this an open or a closed loop ?
|
// is this an open or a closed loop ?
|
||||||
|
@ -333,7 +333,7 @@ public class PolygonsSet extends Region {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((end == null) && !open) {
|
if ((end == null) && !open) {
|
||||||
throw new RuntimeException("internal error");
|
throw new MathInternalError();
|
||||||
}
|
}
|
||||||
|
|
||||||
return loop;
|
return loop;
|
||||||
|
|
|
@ -19,15 +19,16 @@ package org.apache.commons.math.geometry.euclidean.twod;
|
||||||
import org.apache.commons.math.geometry.partitioning.utilities.OrderedTuple;
|
import org.apache.commons.math.geometry.partitioning.utilities.OrderedTuple;
|
||||||
|
|
||||||
/** This class holds segments information before they are connected.
|
/** This class holds segments information before they are connected.
|
||||||
* @version $Revision$ $Date$
|
* @version $Id:$
|
||||||
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
class Segment implements Comparable<Segment> {
|
class Segment implements Comparable<Segment> {
|
||||||
|
|
||||||
/** Start point of the segment. */
|
/** Start point of the segment. */
|
||||||
private final Point2D start;
|
private final Vector2D start;
|
||||||
|
|
||||||
/** End point of the segments. */
|
/** End point of the segments. */
|
||||||
private final Point2D end;
|
private final Vector2D end;
|
||||||
|
|
||||||
/** Line containing the segment. */
|
/** Line containing the segment. */
|
||||||
private final Line line;
|
private final Line line;
|
||||||
|
@ -40,13 +41,13 @@ class Segment implements Comparable<Segment> {
|
||||||
* @param end end point of the segment
|
* @param end end point of the segment
|
||||||
* @param line line containing 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.start = start;
|
||||||
this.end = end;
|
this.end = end;
|
||||||
this.line = line;
|
this.line = line;
|
||||||
sortingKey = (start == null) ?
|
sortingKey = (start == null) ?
|
||||||
new OrderedTuple(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY) :
|
new OrderedTuple(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY) :
|
||||||
new OrderedTuple(start.x, start.y);
|
new OrderedTuple(start.getX(), start.getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Build a dummy segment.
|
/** Build a dummy segment.
|
||||||
|
@ -58,24 +59,24 @@ class Segment implements Comparable<Segment> {
|
||||||
* @param dx abscissa offset from the start point
|
* @param dx abscissa offset from the start point
|
||||||
* @param dy ordinate 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.start = null;
|
||||||
this.end = null;
|
this.end = null;
|
||||||
this.line = 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.
|
/** Get the start point of the segment.
|
||||||
* @return start point of the segment
|
* @return start point of the segment
|
||||||
*/
|
*/
|
||||||
public Point2D getStart() {
|
public Vector2D getStart() {
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the end point of the segment.
|
/** Get the end point of the segment.
|
||||||
* @return end point of the segment
|
* @return end point of the segment
|
||||||
*/
|
*/
|
||||||
public Point2D getEnd() {
|
public Vector2D getEnd() {
|
||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,19 +18,22 @@ package org.apache.commons.math.geometry.euclidean.twod;
|
||||||
|
|
||||||
import java.util.List;
|
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.Interval;
|
||||||
import org.apache.commons.math.geometry.euclidean.oned.IntervalsSet;
|
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.BSPTree;
|
||||||
import org.apache.commons.math.geometry.partitioning.BSPTreeVisitor;
|
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.SubHyperplane;
|
||||||
import org.apache.commons.math.geometry.partitioning.utilities.AVLTree;
|
import org.apache.commons.math.geometry.partitioning.utilities.AVLTree;
|
||||||
|
|
||||||
/** Visitor building segments.
|
/** Visitor building segments.
|
||||||
* @version $Revision$ $Date$
|
* @version $Id:$
|
||||||
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
class SegmentsBuilder implements BSPTreeVisitor {
|
class SegmentsBuilder implements BSPTreeVisitor<Euclidean2D> {
|
||||||
|
|
||||||
/** Sorted segments. */
|
/** Sorted segments. */
|
||||||
private AVLTree<Segment> sorted;
|
private AVLTree<Segment> sorted;
|
||||||
|
@ -41,13 +44,14 @@ class SegmentsBuilder implements BSPTreeVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public Order visitOrder(final BSPTree node) {
|
public Order visitOrder(final BSPTree<Euclidean2D> node) {
|
||||||
return Order.MINUS_SUB_PLUS;
|
return Order.MINUS_SUB_PLUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public void visitInternalNode(final BSPTree node) {
|
public void visitInternalNode(final BSPTree<Euclidean2D> node) {
|
||||||
final BoundaryAttribute attribute = (BoundaryAttribute) node.getAttribute();
|
@SuppressWarnings("unchecked")
|
||||||
|
final BoundaryAttribute<Euclidean2D> attribute = (BoundaryAttribute<Euclidean2D>) node.getAttribute();
|
||||||
if (attribute.getPlusOutside() != null) {
|
if (attribute.getPlusOutside() != null) {
|
||||||
addContribution(attribute.getPlusOutside(), false);
|
addContribution(attribute.getPlusOutside(), false);
|
||||||
}
|
}
|
||||||
|
@ -57,21 +61,24 @@ class SegmentsBuilder implements BSPTreeVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public void visitLeafNode(final BSPTree node) {
|
public void visitLeafNode(final BSPTree<Euclidean2D> node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add he contribution of a boundary facet.
|
/** Add he contribution of a boundary facet.
|
||||||
* @param sub boundary facet
|
* @param sub boundary facet
|
||||||
* @param reversed if true, the facet has the inside on its plus side
|
* @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<Euclidean2D> sub, final boolean reversed) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final AbstractSubHyperplane<Euclidean2D, Euclidean1D> absSub =
|
||||||
|
(AbstractSubHyperplane<Euclidean2D, Euclidean1D>) sub;
|
||||||
final Line line = (Line) sub.getHyperplane();
|
final Line line = (Line) sub.getHyperplane();
|
||||||
final List<Interval> intervals = ((IntervalsSet) sub.getRemainingRegion()).asList();
|
final List<Interval> intervals = ((IntervalsSet) absSub.getRemainingRegion()).asList();
|
||||||
for (final Interval i : intervals) {
|
for (final Interval i : intervals) {
|
||||||
final Point2D start = Double.isInfinite(i.getLower()) ?
|
final Vector2D start = Double.isInfinite(i.getLower()) ?
|
||||||
null : (Point2D) line.toSpace(new Point1D(i.getLower()));
|
null : (Vector2D) line.toSpace(new Vector1D(i.getLower()));
|
||||||
final Point2D end = Double.isInfinite(i.getUpper()) ?
|
final Vector2D end = Double.isInfinite(i.getUpper()) ?
|
||||||
null : (Point2D) line.toSpace(new Point1D(i.getUpper()));
|
null : (Vector2D) line.toSpace(new Vector1D(i.getUpper()));
|
||||||
if (reversed) {
|
if (reversed) {
|
||||||
sorted.insert(new Segment(end, start, line.getReverse()));
|
sorted.insert(new Segment(end, start, line.getReverse()));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -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<Euclidean2D, Euclidean1D> {
|
||||||
|
|
||||||
|
/** Simple constructor.
|
||||||
|
* @param hyperplane underlying hyperplane
|
||||||
|
* @param remainingRegion remaining region of the hyperplane
|
||||||
|
*/
|
||||||
|
public SubLine(final Hyperplane<Euclidean2D> hyperplane,
|
||||||
|
final Region<Euclidean1D> remainingRegion) {
|
||||||
|
super(hyperplane, remainingRegion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
protected AbstractSubHyperplane<Euclidean2D, Euclidean1D> buildNew(final Hyperplane<Euclidean2D> hyperplane,
|
||||||
|
final Region<Euclidean1D> remainingRegion) {
|
||||||
|
return new SubLine(hyperplane, remainingRegion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public Side side(final Hyperplane<Euclidean2D> 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<Euclidean2D> split(final Hyperplane<Euclidean2D> 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<Euclidean2D>(null, this) :
|
||||||
|
new SplitSubHyperplane<Euclidean2D>(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<Euclidean1D> subPlus = new OrientedPoint(x, !direct).wholeHyperplane();
|
||||||
|
final SubHyperplane<Euclidean1D> subMinus = new OrientedPoint(x, direct).wholeHyperplane();
|
||||||
|
|
||||||
|
final BSPTree<Euclidean1D> splitTree = getRemainingRegion().getTree(false).split(subMinus);
|
||||||
|
final BSPTree<Euclidean1D> plusTree = getRemainingRegion().isEmpty(splitTree.getPlus()) ?
|
||||||
|
new BSPTree<Euclidean1D>(Boolean.FALSE) :
|
||||||
|
new BSPTree<Euclidean1D>(subPlus, new BSPTree<Euclidean1D>(Boolean.FALSE),
|
||||||
|
splitTree.getPlus(), null);
|
||||||
|
final BSPTree<Euclidean1D> minusTree = getRemainingRegion().isEmpty(splitTree.getMinus()) ?
|
||||||
|
new BSPTree<Euclidean1D>(Boolean.FALSE) :
|
||||||
|
new BSPTree<Euclidean1D>(subMinus, new BSPTree<Euclidean1D>(Boolean.FALSE),
|
||||||
|
splitTree.getMinus(), null);
|
||||||
|
|
||||||
|
return new SplitSubHyperplane<Euclidean2D>(new SubLine(thisLine.copySelf(), new IntervalsSet(plusTree)),
|
||||||
|
new SubLine(thisLine.copySelf(), new IntervalsSet(minusTree)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.Interval;
|
||||||
import org.apache.commons.math.geometry.euclidean.oned.IntervalsSet;
|
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.Region;
|
||||||
|
import org.apache.commons.math.geometry.partitioning.RegionFactory;
|
||||||
import org.apache.commons.math.util.FastMath;
|
import org.apache.commons.math.util.FastMath;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -32,12 +33,12 @@ public class IntervalsSetTest {
|
||||||
public void testInterval() {
|
public void testInterval() {
|
||||||
IntervalsSet set = new IntervalsSet(2.3, 5.7);
|
IntervalsSet set = new IntervalsSet(2.3, 5.7);
|
||||||
Assert.assertEquals(3.4, set.getSize(), 1.0e-10);
|
Assert.assertEquals(3.4, set.getSize(), 1.0e-10);
|
||||||
Assert.assertEquals(4.0, ((Point1D) set.getBarycenter()).getAbscissa(), 1.0e-10);
|
Assert.assertEquals(4.0, ((Vector1D) set.getBarycenter()).getX(), 1.0e-10);
|
||||||
Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Point1D(2.3)));
|
Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Vector1D(2.3)));
|
||||||
Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Point1D(5.7)));
|
Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Vector1D(5.7)));
|
||||||
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Point1D(1.2)));
|
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Vector1D(1.2)));
|
||||||
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Point1D(8.7)));
|
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Vector1D(8.7)));
|
||||||
Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Point1D(3.0)));
|
Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Vector1D(3.0)));
|
||||||
Assert.assertEquals(2.3, set.getInf(), 1.0e-10);
|
Assert.assertEquals(2.3, set.getInf(), 1.0e-10);
|
||||||
Assert.assertEquals(5.7, set.getSup(), 1.0e-10);
|
Assert.assertEquals(5.7, set.getSup(), 1.0e-10);
|
||||||
}
|
}
|
||||||
|
@ -45,17 +46,17 @@ public class IntervalsSetTest {
|
||||||
@Test
|
@Test
|
||||||
public void testInfinite() {
|
public void testInfinite() {
|
||||||
IntervalsSet set = new IntervalsSet(9.0, Double.POSITIVE_INFINITY);
|
IntervalsSet set = new IntervalsSet(9.0, Double.POSITIVE_INFINITY);
|
||||||
Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Point1D(9.0)));
|
Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Vector1D(9.0)));
|
||||||
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Point1D(8.4)));
|
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Vector1D(8.4)));
|
||||||
for (double e = 1.0; e <= 6.0; e += 1.0) {
|
for (double e = 1.0; e <= 6.0; e += 1.0) {
|
||||||
Assert.assertEquals(Region.Location.INSIDE,
|
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.assertTrue(Double.isInfinite(set.getSize()));
|
||||||
Assert.assertEquals(9.0, set.getInf(), 1.0e-10);
|
Assert.assertEquals(9.0, set.getInf(), 1.0e-10);
|
||||||
Assert.assertTrue(Double.isInfinite(set.getSup()));
|
Assert.assertTrue(Double.isInfinite(set.getSup()));
|
||||||
|
|
||||||
set = (IntervalsSet) set.getComplement();
|
set = (IntervalsSet) new RegionFactory<Euclidean1D>().getComplement(set);
|
||||||
Assert.assertEquals(9.0, set.getSup(), 1.0e-10);
|
Assert.assertEquals(9.0, set.getSup(), 1.0e-10);
|
||||||
Assert.assertTrue(Double.isInfinite(set.getInf()));
|
Assert.assertTrue(Double.isInfinite(set.getInf()));
|
||||||
|
|
||||||
|
@ -63,22 +64,23 @@ public class IntervalsSetTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultiple() {
|
public void testMultiple() {
|
||||||
|
RegionFactory<Euclidean1D> factory = new RegionFactory<Euclidean1D>();
|
||||||
IntervalsSet set = (IntervalsSet)
|
IntervalsSet set = (IntervalsSet)
|
||||||
Region.intersection(Region.union(Region.difference(new IntervalsSet(1.0, 6.0),
|
factory.intersection(factory.union(factory.difference(new IntervalsSet(1.0, 6.0),
|
||||||
new IntervalsSet(3.0, 5.0)),
|
new IntervalsSet(3.0, 5.0)),
|
||||||
new IntervalsSet(9.0, Double.POSITIVE_INFINITY)),
|
new IntervalsSet(9.0, Double.POSITIVE_INFINITY)),
|
||||||
new IntervalsSet(Double.NEGATIVE_INFINITY, 11.0));
|
new IntervalsSet(Double.NEGATIVE_INFINITY, 11.0));
|
||||||
Assert.assertEquals(5.0, set.getSize(), 1.0e-10);
|
Assert.assertEquals(5.0, set.getSize(), 1.0e-10);
|
||||||
Assert.assertEquals(5.9, ((Point1D) set.getBarycenter()).getAbscissa(), 1.0e-10);
|
Assert.assertEquals(5.9, ((Vector1D) set.getBarycenter()).getX(), 1.0e-10);
|
||||||
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Point1D(0.0)));
|
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Vector1D(0.0)));
|
||||||
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Point1D(4.0)));
|
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Vector1D(4.0)));
|
||||||
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Point1D(8.0)));
|
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Vector1D(8.0)));
|
||||||
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Point1D(12.0)));
|
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new Vector1D(12.0)));
|
||||||
Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Point1D(1.2)));
|
Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Vector1D(1.2)));
|
||||||
Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Point1D(5.9)));
|
Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Vector1D(5.9)));
|
||||||
Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Point1D(9.01)));
|
Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new Vector1D(9.01)));
|
||||||
Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Point1D(5.0)));
|
Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Vector1D(5.0)));
|
||||||
Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Point1D(11.0)));
|
Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Vector1D(11.0)));
|
||||||
Assert.assertEquals( 1.0, set.getInf(), 1.0e-10);
|
Assert.assertEquals( 1.0, set.getInf(), 1.0e-10);
|
||||||
Assert.assertEquals(11.0, set.getSup(), 1.0e-10);
|
Assert.assertEquals(11.0, set.getSup(), 1.0e-10);
|
||||||
|
|
||||||
|
|
|
@ -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.Line;
|
||||||
import org.apache.commons.math.geometry.euclidean.threed.Plane;
|
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.Rotation;
|
||||||
import org.apache.commons.math.geometry.euclidean.threed.Vector3D;
|
import org.apache.commons.math.geometry.euclidean.threed.Vector3D;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
@ -29,22 +28,22 @@ public class PlaneTest {
|
||||||
@Test
|
@Test
|
||||||
public void testContains() {
|
public void testContains() {
|
||||||
Plane p = new Plane(new Vector3D(0, 0, 1), new Vector3D(0, 0, 1));
|
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 Vector3D(0, 0, 1)));
|
||||||
Assert.assertTrue(p.contains(new Point3D(17, -32, 1)));
|
Assert.assertTrue(p.contains(new Vector3D(17, -32, 1)));
|
||||||
Assert.assertTrue(! p.contains(new Point3D(17, -32, 1.001)));
|
Assert.assertTrue(! p.contains(new Vector3D(17, -32, 1.001)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOffset() {
|
public void testOffset() {
|
||||||
Vector3D p1 = new Vector3D(1, 1, 1);
|
Vector3D p1 = new Vector3D(1, 1, 1);
|
||||||
Plane p = new Plane(p1, new Vector3D(0.2, 0, 0));
|
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 Vector3D(-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(6, 10, -12)), 1.0e-10);
|
||||||
Assert.assertEquals(0.3,
|
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);
|
1.0e-10);
|
||||||
Assert.assertEquals(-0.3,
|
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);
|
1.0e-10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,9 +55,9 @@ public class PlaneTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testThreePoints() {
|
public void testThreePoints() {
|
||||||
Point3D p1 = new Point3D(1.2, 3.4, -5.8);
|
Vector3D p1 = new Vector3D(1.2, 3.4, -5.8);
|
||||||
Point3D p2 = new Point3D(3.4, -5.8, 1.2);
|
Vector3D p2 = new Vector3D(3.4, -5.8, 1.2);
|
||||||
Point3D p3 = new Point3D(-2.0, 4.3, 0.7);
|
Vector3D p3 = new Vector3D(-2.0, 4.3, 0.7);
|
||||||
Plane p = new Plane(p1, p2, p3);
|
Plane p = new Plane(p1, p2, p3);
|
||||||
Assert.assertTrue(p.contains(p1));
|
Assert.assertTrue(p.contains(p1));
|
||||||
Assert.assertTrue(p.contains(p2));
|
Assert.assertTrue(p.contains(p2));
|
||||||
|
@ -67,9 +66,9 @@ public class PlaneTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRotate() {
|
public void testRotate() {
|
||||||
Point3D p1 = new Point3D(1.2, 3.4, -5.8);
|
Vector3D p1 = new Vector3D(1.2, 3.4, -5.8);
|
||||||
Point3D p2 = new Point3D(3.4, -5.8, 1.2);
|
Vector3D p2 = new Vector3D(3.4, -5.8, 1.2);
|
||||||
Point3D p3 = new Point3D(-2.0, 4.3, 0.7);
|
Vector3D p3 = new Vector3D(-2.0, 4.3, 0.7);
|
||||||
Plane p = new Plane(p1, p2, p3);
|
Plane p = new Plane(p1, p2, p3);
|
||||||
Vector3D oldNormal = p.getNormal();
|
Vector3D oldNormal = p.getNormal();
|
||||||
|
|
||||||
|
@ -92,9 +91,9 @@ public class PlaneTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTranslate() {
|
public void testTranslate() {
|
||||||
Point3D p1 = new Point3D(1.2, 3.4, -5.8);
|
Vector3D p1 = new Vector3D(1.2, 3.4, -5.8);
|
||||||
Point3D p2 = new Point3D(3.4, -5.8, 1.2);
|
Vector3D p2 = new Vector3D(3.4, -5.8, 1.2);
|
||||||
Point3D p3 = new Point3D(-2.0, 4.3, 0.7);
|
Vector3D p3 = new Vector3D(-2.0, 4.3, 0.7);
|
||||||
Plane p = new Plane(p1, p2, p3);
|
Plane p = new Plane(p1, p2, p3);
|
||||||
|
|
||||||
p = p.translate(new Vector3D(2.0, p.getU(), -1.5, p.getV()));
|
p = p.translate(new Vector3D(2.0, p.getU(), -1.5, p.getV()));
|
||||||
|
@ -118,7 +117,7 @@ public class PlaneTest {
|
||||||
public void testIntersection() {
|
public void testIntersection() {
|
||||||
Plane p = new Plane(new Vector3D(1, 2, 3), new Vector3D(-4, 1, -5));
|
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));
|
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(p.contains(point));
|
||||||
Assert.assertTrue(l.contains(point));
|
Assert.assertTrue(l.contains(point));
|
||||||
Assert.assertNull(p.intersection(new Line(new Vector3D(10, 10, 10),
|
Assert.assertNull(p.intersection(new Line(new Vector3D(10, 10, 10),
|
||||||
|
|
|
@ -16,20 +16,13 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.commons.math.geometry.euclidean.threed;
|
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.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.BSPTree;
|
||||||
import org.apache.commons.math.geometry.partitioning.BSPTreeVisitor;
|
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.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.apache.commons.math.util.FastMath;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -53,41 +46,41 @@ public class PolyhedronsSetTest {
|
||||||
boolean zOK = (z >= 0.0) && (z <= 1.0);
|
boolean zOK = (z >= 0.0) && (z <= 1.0);
|
||||||
Region.Location expected =
|
Region.Location expected =
|
||||||
(xOK && yOK && zOK) ? Region.Location.INSIDE : Region.Location.OUTSIDE;
|
(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[] {
|
checkPoints(Region.Location.BOUNDARY, tree, new Vector3D[] {
|
||||||
new Point3D(0.0, 0.5, 0.5),
|
new Vector3D(0.0, 0.5, 0.5),
|
||||||
new Point3D(1.0, 0.5, 0.5),
|
new Vector3D(1.0, 0.5, 0.5),
|
||||||
new Point3D(0.5, 0.0, 0.5),
|
new Vector3D(0.5, 0.0, 0.5),
|
||||||
new Point3D(0.5, 1.0, 0.5),
|
new Vector3D(0.5, 1.0, 0.5),
|
||||||
new Point3D(0.5, 0.5, 0.0),
|
new Vector3D(0.5, 0.5, 0.0),
|
||||||
new Point3D(0.5, 0.5, 1.0)
|
new Vector3D(0.5, 0.5, 1.0)
|
||||||
});
|
});
|
||||||
checkPoints(Region.Location.OUTSIDE, tree, new Point3D[] {
|
checkPoints(Region.Location.OUTSIDE, tree, new Vector3D[] {
|
||||||
new Point3D(0.0, 1.2, 1.2),
|
new Vector3D(0.0, 1.2, 1.2),
|
||||||
new Point3D(1.0, 1.2, 1.2),
|
new Vector3D(1.0, 1.2, 1.2),
|
||||||
new Point3D(1.2, 0.0, 1.2),
|
new Vector3D(1.2, 0.0, 1.2),
|
||||||
new Point3D(1.2, 1.0, 1.2),
|
new Vector3D(1.2, 1.0, 1.2),
|
||||||
new Point3D(1.2, 1.2, 0.0),
|
new Vector3D(1.2, 1.2, 0.0),
|
||||||
new Point3D(1.2, 1.2, 1.0)
|
new Vector3D(1.2, 1.2, 1.0)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTetrahedron() {
|
public void testTetrahedron() {
|
||||||
Point3D vertex1 = new Point3D(1, 2, 3);
|
Vector3D vertex1 = new Vector3D(1, 2, 3);
|
||||||
Point3D vertex2 = new Point3D(2, 2, 4);
|
Vector3D vertex2 = new Vector3D(2, 2, 4);
|
||||||
Point3D vertex3 = new Point3D(2, 3, 3);
|
Vector3D vertex3 = new Vector3D(2, 3, 3);
|
||||||
Point3D vertex4 = new Point3D(1, 3, 4);
|
Vector3D vertex4 = new Vector3D(1, 3, 4);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
PolyhedronsSet tree =
|
PolyhedronsSet tree =
|
||||||
(PolyhedronsSet) Region.buildConvex(Arrays.asList(new Hyperplane[] {
|
(PolyhedronsSet) new RegionFactory<Euclidean3D>().buildConvex(
|
||||||
new Plane(vertex3, vertex2, vertex1),
|
new Plane(vertex3, vertex2, vertex1),
|
||||||
new Plane(vertex2, vertex3, vertex4),
|
new Plane(vertex2, vertex3, vertex4),
|
||||||
new Plane(vertex4, vertex3, vertex1),
|
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(1.0 / 3.0, tree.getSize(), 1.0e-10);
|
||||||
Assert.assertEquals(2.0 * FastMath.sqrt(3.0), tree.getBoundarySize(), 1.0e-10);
|
Assert.assertEquals(2.0 * FastMath.sqrt(3.0), tree.getBoundarySize(), 1.0e-10);
|
||||||
Vector3D barycenter = (Vector3D) tree.getBarycenter();
|
Vector3D barycenter = (Vector3D) tree.getBarycenter();
|
||||||
|
@ -95,18 +88,18 @@ public class PolyhedronsSetTest {
|
||||||
Assert.assertEquals(2.5, barycenter.getY(), 1.0e-10);
|
Assert.assertEquals(2.5, barycenter.getY(), 1.0e-10);
|
||||||
Assert.assertEquals(3.5, barycenter.getZ(), 1.0e-10);
|
Assert.assertEquals(3.5, barycenter.getZ(), 1.0e-10);
|
||||||
double third = 1.0 / 3.0;
|
double third = 1.0 / 3.0;
|
||||||
checkPoints(Region.Location.BOUNDARY, tree, new Point3D[] {
|
checkPoints(Region.Location.BOUNDARY, tree, new Vector3D[] {
|
||||||
vertex1, vertex2, vertex3, vertex4,
|
vertex1, vertex2, vertex3, vertex4,
|
||||||
new Point3D(third, vertex1, third, vertex2, third, vertex3),
|
new Vector3D(third, vertex1, third, vertex2, third, vertex3),
|
||||||
new Point3D(third, vertex2, third, vertex3, third, vertex4),
|
new Vector3D(third, vertex2, third, vertex3, third, vertex4),
|
||||||
new Point3D(third, vertex3, third, vertex4, third, vertex1),
|
new Vector3D(third, vertex3, third, vertex4, third, vertex1),
|
||||||
new Point3D(third, vertex4, third, vertex1, third, vertex2)
|
new Vector3D(third, vertex4, third, vertex1, third, vertex2)
|
||||||
});
|
});
|
||||||
checkPoints(Region.Location.OUTSIDE, tree, new Point3D[] {
|
checkPoints(Region.Location.OUTSIDE, tree, new Vector3D[] {
|
||||||
new Point3D(1, 2, 4),
|
new Vector3D(1, 2, 4),
|
||||||
new Point3D(2, 2, 3),
|
new Vector3D(2, 2, 3),
|
||||||
new Point3D(2, 3, 4),
|
new Vector3D(2, 3, 4),
|
||||||
new Point3D(1, 3, 3)
|
new Vector3D(1, 3, 3)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,13 +109,13 @@ public class PolyhedronsSetTest {
|
||||||
Vector3D vertex2 = new Vector3D(2.0, 2.4, 4.2);
|
Vector3D vertex2 = new Vector3D(2.0, 2.4, 4.2);
|
||||||
Vector3D vertex3 = new Vector3D(2.8, 3.3, 3.7);
|
Vector3D vertex3 = new Vector3D(2.8, 3.3, 3.7);
|
||||||
Vector3D vertex4 = new Vector3D(1.0, 3.6, 4.5);
|
Vector3D vertex4 = new Vector3D(1.0, 3.6, 4.5);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
PolyhedronsSet tree =
|
PolyhedronsSet tree =
|
||||||
(PolyhedronsSet) Region.buildConvex(Arrays.asList(new Hyperplane[] {
|
(PolyhedronsSet) new RegionFactory<Euclidean3D>().buildConvex(
|
||||||
new Plane(vertex3, vertex2, vertex1),
|
new Plane(vertex3, vertex2, vertex1),
|
||||||
new Plane(vertex2, vertex3, vertex4),
|
new Plane(vertex2, vertex3, vertex4),
|
||||||
new Plane(vertex4, vertex3, vertex1),
|
new Plane(vertex4, vertex3, vertex1),
|
||||||
new Plane(vertex1, vertex2, vertex4)
|
new Plane(vertex1, vertex2, vertex4));
|
||||||
}));
|
|
||||||
Vector3D barycenter = (Vector3D) tree.getBarycenter();
|
Vector3D barycenter = (Vector3D) tree.getBarycenter();
|
||||||
Vector3D s = new Vector3D(10.2, 4.3, -6.7);
|
Vector3D s = new Vector3D(10.2, 4.3, -6.7);
|
||||||
Vector3D c = new Vector3D(-0.2, 2.1, -3.2);
|
Vector3D c = new Vector3D(-0.2, 2.1, -3.2);
|
||||||
|
@ -152,29 +145,30 @@ public class PolyhedronsSetTest {
|
||||||
1.0, c,
|
1.0, c,
|
||||||
1.0, r.applyTo(vertex4.subtract(c)))
|
1.0, r.applyTo(vertex4.subtract(c)))
|
||||||
};
|
};
|
||||||
tree.getTree(true).visit(new BSPTreeVisitor() {
|
tree.getTree(true).visit(new BSPTreeVisitor<Euclidean3D>() {
|
||||||
|
|
||||||
public Order visitOrder(BSPTree node) {
|
public Order visitOrder(BSPTree<Euclidean3D> node) {
|
||||||
return Order.MINUS_SUB_PLUS;
|
return Order.MINUS_SUB_PLUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitInternalNode(BSPTree node) {
|
public void visitInternalNode(BSPTree<Euclidean3D> node) {
|
||||||
Region.BoundaryAttribute attribute =
|
@SuppressWarnings("unchecked")
|
||||||
(Region.BoundaryAttribute) node.getAttribute();
|
BoundaryAttribute<Euclidean3D> attribute =
|
||||||
|
(BoundaryAttribute<Euclidean3D>) node.getAttribute();
|
||||||
if (attribute.getPlusOutside() != null) {
|
if (attribute.getPlusOutside() != null) {
|
||||||
checkFacet(attribute.getPlusOutside());
|
checkFacet((SubPlane) attribute.getPlusOutside());
|
||||||
}
|
}
|
||||||
if (attribute.getPlusInside() != null) {
|
if (attribute.getPlusInside() != null) {
|
||||||
checkFacet(attribute.getPlusInside());
|
checkFacet((SubPlane) attribute.getPlusInside());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitLeafNode(BSPTree node) {
|
public void visitLeafNode(BSPTree<Euclidean3D> node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkFacet(SubHyperplane facet) {
|
private void checkFacet(SubPlane facet) {
|
||||||
Plane plane = (Plane) facet.getHyperplane();
|
Plane plane = (Plane) facet.getHyperplane();
|
||||||
Point2D[][] vertices =
|
Vector2D[][] vertices =
|
||||||
((PolygonsSet) facet.getRemainingRegion()).getVertices();
|
((PolygonsSet) facet.getRemainingRegion()).getVertices();
|
||||||
Assert.assertEquals(1, vertices.length);
|
Assert.assertEquals(1, vertices.length);
|
||||||
for (int i = 0; i < vertices[0].length; ++i) {
|
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);
|
new PolyhedronsSet(x - w, x + w, y - l, y + l, z - w, z + w);
|
||||||
PolyhedronsSet zBeam =
|
PolyhedronsSet zBeam =
|
||||||
new PolyhedronsSet(x - w, x + w, y - w, y + w, z - l, z + l);
|
new PolyhedronsSet(x - w, x + w, y - w, y + w, z - l, z + l);
|
||||||
PolyhedronsSet tree =
|
RegionFactory<Euclidean3D> factory = new RegionFactory<Euclidean3D>();
|
||||||
(PolyhedronsSet) Region.union(xBeam, Region.union(yBeam, zBeam));
|
PolyhedronsSet tree = (PolyhedronsSet) factory.union(xBeam, factory.union(yBeam, zBeam));
|
||||||
Vector3D barycenter = (Vector3D) tree.getBarycenter();
|
Vector3D barycenter = (Vector3D) tree.getBarycenter();
|
||||||
|
|
||||||
Assert.assertEquals(x, barycenter.getX(), 1.0e-10);
|
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) {
|
for (int i = 0; i < points.length; ++i) {
|
||||||
Assert.assertEquals(expected, tree.checkPoint(points[i]));
|
Assert.assertEquals(expected, tree.checkPoint(points[i]));
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,10 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.commons.math.geometry.euclidean.twod;
|
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.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.geometry.partitioning.Transform;
|
||||||
import org.apache.commons.math.util.FastMath;
|
import org.apache.commons.math.util.FastMath;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
@ -30,48 +31,48 @@ public class LineTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testContains() {
|
public void testContains() {
|
||||||
Line l = new Line(new Point2D(0, 1), new Point2D(1, 2));
|
Line l = new Line(new Vector2D(0, 1), new Vector2D(1, 2));
|
||||||
Assert.assertTrue(l.contains(new Point2D(0, 1)));
|
Assert.assertTrue(l.contains(new Vector2D(0, 1)));
|
||||||
Assert.assertTrue(l.contains(new Point2D(1, 2)));
|
Assert.assertTrue(l.contains(new Vector2D(1, 2)));
|
||||||
Assert.assertTrue(l.contains(new Point2D(7, 8)));
|
Assert.assertTrue(l.contains(new Vector2D(7, 8)));
|
||||||
Assert.assertTrue(! l.contains(new Point2D(8, 7)));
|
Assert.assertTrue(! l.contains(new Vector2D(8, 7)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAbscissa() {
|
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,
|
Assert.assertEquals(0.0,
|
||||||
((Point1D) l.toSubSpace(new Point2D(-3, 4))).getAbscissa(),
|
((Vector1D) l.toSubSpace(new Vector2D(-3, 4))).getX(),
|
||||||
1.0e-10);
|
1.0e-10);
|
||||||
Assert.assertEquals(0.0,
|
Assert.assertEquals(0.0,
|
||||||
((Point1D) l.toSubSpace(new Point2D( 3, -4))).getAbscissa(),
|
((Vector1D) l.toSubSpace(new Vector2D( 3, -4))).getX(),
|
||||||
1.0e-10);
|
1.0e-10);
|
||||||
Assert.assertEquals(-5.0,
|
Assert.assertEquals(-5.0,
|
||||||
((Point1D) l.toSubSpace(new Point2D( 7, -1))).getAbscissa(),
|
((Vector1D) l.toSubSpace(new Vector2D( 7, -1))).getX(),
|
||||||
1.0e-10);
|
1.0e-10);
|
||||||
Assert.assertEquals( 5.0,
|
Assert.assertEquals( 5.0,
|
||||||
((Point1D) l.toSubSpace(new Point2D(-1, -7))).getAbscissa(),
|
((Vector1D) l.toSubSpace(new Vector2D(-1, -7))).getX(),
|
||||||
1.0e-10);
|
1.0e-10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOffset() {
|
public void testOffset() {
|
||||||
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(-5.0, l.getOffset(new Point2D(5, -3)), 1.0e-10);
|
Assert.assertEquals(-5.0, l.getOffset(new Vector2D(5, -3)), 1.0e-10);
|
||||||
Assert.assertEquals(+5.0, l.getOffset(new Point2D(-5, 2)), 1.0e-10);
|
Assert.assertEquals(+5.0, l.getOffset(new Vector2D(-5, 2)), 1.0e-10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPointAt() {
|
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) {
|
for (double a = -2.0; a < 2.0; a += 0.2) {
|
||||||
Point1D pA = new Point1D(a);
|
Vector1D pA = new Vector1D(a);
|
||||||
Point2D point = (Point2D) l.toSpace(pA);
|
Vector2D point = (Vector2D) l.toSpace(pA);
|
||||||
Assert.assertEquals(a, ((Point1D) l.toSubSpace(point)).getAbscissa(), 1.0e-10);
|
Assert.assertEquals(a, ((Vector1D) l.toSubSpace(point)).getX(), 1.0e-10);
|
||||||
Assert.assertEquals(0.0, l.getOffset(point), 1.0e-10);
|
Assert.assertEquals(0.0, l.getOffset(point), 1.0e-10);
|
||||||
for (double o = -2.0; o < 2.0; o += 0.2) {
|
for (double o = -2.0; o < 2.0; o += 0.2) {
|
||||||
point = l.getPointAt(pA, o);
|
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);
|
Assert.assertEquals(o, l.getOffset(point), 1.0e-10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,38 +80,36 @@ public class LineTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOriginOffset() {
|
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);
|
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);
|
Assert.assertEquals(-FastMath.sqrt(0.5), l2.getOriginOffset(), 1.0e-10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParallel() {
|
public void testParallel() {
|
||||||
Line l1 = new Line(new Point2D(0, 1), new Point2D(1, 2));
|
Line l1 = new Line(new Vector2D(0, 1), new Vector2D(1, 2));
|
||||||
Line l2 = new Line(new Point2D(2, 2), new Point2D(3, 3));
|
Line l2 = new Line(new Vector2D(2, 2), new Vector2D(3, 3));
|
||||||
Assert.assertTrue(l1.isParallelTo(l2));
|
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));
|
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));
|
Assert.assertTrue(! l1.isParallelTo(l4));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransform() {
|
public void testTransform() {
|
||||||
|
|
||||||
Line l1 = new Line(new Point2D(1.0 ,1.0), new Point2D(4.0 ,1.0));
|
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,
|
Transform<Euclidean2D, Euclidean1D> t1 =
|
||||||
-1.0, 0.0,
|
Line.getTransform(new AffineTransform(0.0, 0.5, -1.0, 0.0, 1.0, 1.5));
|
||||||
1.0, 1.5));
|
|
||||||
Assert.assertEquals(0.5 * FastMath.PI,
|
Assert.assertEquals(0.5 * FastMath.PI,
|
||||||
((Line) t1.apply(l1)).getAngle(),
|
((Line) t1.apply(l1)).getAngle(),
|
||||||
1.0e-10);
|
1.0e-10);
|
||||||
|
|
||||||
Line l2 = new Line(new Point2D(0.0, 0.0), new Point2D(1.0, 1.0));
|
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,
|
Transform<Euclidean2D, Euclidean1D> t2 =
|
||||||
-1.0, 0.0,
|
Line.getTransform(new AffineTransform(0.0, 0.5, -1.0, 0.0, 1.0, 1.5));
|
||||||
1.0, 1.5));
|
|
||||||
Assert.assertEquals(FastMath.atan2(1.0, -2.0),
|
Assert.assertEquals(FastMath.atan2(1.0, -2.0),
|
||||||
((Line) t2.apply(l2)).getAngle(),
|
((Line) t2.apply(l2)).getAngle(),
|
||||||
1.0e-10);
|
1.0e-10);
|
||||||
|
@ -119,11 +118,11 @@ public class LineTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIntersection() {
|
public void testIntersection() {
|
||||||
Line l1 = new Line(new Point2D( 0, 1), new Point2D(1, 2));
|
Line l1 = new Line(new Vector2D( 0, 1), new Vector2D(1, 2));
|
||||||
Line l2 = new Line(new Point2D(-1, 2), new Point2D(2, 1));
|
Line l2 = new Line(new Vector2D(-1, 2), new Vector2D(2, 1));
|
||||||
Point2D p = (Point2D) l1.intersection(l2);
|
Vector2D p = (Vector2D) l1.intersection(l2);
|
||||||
Assert.assertEquals(0.5, p.x, 1.0e-10);
|
Assert.assertEquals(0.5, p.getX(), 1.0e-10);
|
||||||
Assert.assertEquals(1.5, p.y, 1.0e-10);
|
Assert.assertEquals(1.5, p.getY(), 1.0e-10);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue