Simplified 1-sphere case.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1554654 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
57eff0d0c3
commit
d83cdb9133
|
@ -16,6 +16,8 @@
|
|||
*/
|
||||
package org.apache.commons.math3.geometry.spherical.oned;
|
||||
|
||||
import org.apache.commons.math3.exception.NumberIsTooLargeException;
|
||||
import org.apache.commons.math3.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math3.geometry.partitioning.Region.Location;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
import org.apache.commons.math3.util.MathUtils;
|
||||
|
@ -38,38 +40,54 @@ public class Arc {
|
|||
/** Middle point of the arc. */
|
||||
private final double middle;
|
||||
|
||||
/** Tolerance below which angles are considered identical. */
|
||||
private final double tolerance;
|
||||
|
||||
/** Simple constructor.
|
||||
* <p>
|
||||
* As the circle is a closed curve, {@code lower} is
|
||||
* allowed to be greater than {@code upper}, and will
|
||||
* be automatically canonicalized so the arc wraps
|
||||
* around \( 2\pi \), but without exceeding a total
|
||||
* length of \( 2\pi \). If {@code lower} is equals
|
||||
* to {@code upper}, the arc is considered to be the full
|
||||
* circle.
|
||||
* If either {@code lower} is equals to {@code upper} or
|
||||
* the interval exceeds \( 2 \pi \), the arc is considered
|
||||
* to be the full circle and its initial defining boundaries
|
||||
* will be forgotten. {@code lower} is not allowed to be
|
||||
* greater than {@code upper} (an exception is thrown in this case).
|
||||
* {@code lower} will be canonicalized between 0 and \( 2 \pi \), and
|
||||
* upper shifted accordingly, so the {@link #getInf()} and {@link #getSup()}
|
||||
* may not return the value used at instance construction.
|
||||
* </p>
|
||||
* @param lower lower angular bound of the arc
|
||||
* @param upper upper angular bound of the arc
|
||||
* @param tolerance tolerance below which angles are considered identical
|
||||
* @exception NumberIsTooLargeException if lower is greater than upper
|
||||
*/
|
||||
public Arc(final double lower, final double upper) {
|
||||
this.lower = lower;
|
||||
if (Precision.equals(lower, upper, 0)) {
|
||||
this.upper = MathUtils.TWO_PI + lower;
|
||||
} else {
|
||||
this.upper = MathUtils.normalizeAngle(upper, lower + FastMath.PI);
|
||||
}
|
||||
public Arc(final double lower, final double upper, final double tolerance)
|
||||
throws NumberIsTooLargeException {
|
||||
this.tolerance = tolerance;
|
||||
if (Precision.equals(lower, upper, 0) || (upper - lower) >= MathUtils.TWO_PI) {
|
||||
// the arc must cover the whole circle
|
||||
this.lower = 0;
|
||||
this.upper = MathUtils.TWO_PI;
|
||||
this.middle = FastMath.PI;
|
||||
} else if (lower <= upper) {
|
||||
this.lower = MathUtils.normalizeAngle(lower, FastMath.PI);
|
||||
this.upper = this.lower + (upper - lower);
|
||||
this.middle = 0.5 * (this.lower + this.upper);
|
||||
} else {
|
||||
throw new NumberIsTooLargeException(LocalizedFormats.ENDPOINTS_NOT_AN_INTERVAL,
|
||||
lower, upper, true);
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the lower angular bound of the arc.
|
||||
* @return lower angular bound of the arc
|
||||
* @return lower angular bound of the arc,
|
||||
* always between 0 and \( 2 \pi \)
|
||||
*/
|
||||
public double getInf() {
|
||||
return lower;
|
||||
}
|
||||
|
||||
/** Get the upper angular bound of the arc.
|
||||
* @return upper angular bound of the arc
|
||||
* @return upper angular bound of the arc,
|
||||
* always between {@link #getInf()} and {@link #getInf()} \( + 2 \pi \)
|
||||
*/
|
||||
public double getSup() {
|
||||
return upper;
|
||||
|
@ -89,14 +107,19 @@ public class Arc {
|
|||
return middle;
|
||||
}
|
||||
|
||||
/** Get the tolerance below which angles are considered identical.
|
||||
* @return tolerance below which angles are considered identical
|
||||
*/
|
||||
public double getTolerance() {
|
||||
return tolerance;
|
||||
}
|
||||
|
||||
/** Check a point with respect to the arc.
|
||||
* @param point point to check
|
||||
* @param tolerance tolerance below which points are considered to
|
||||
* belong to the boundary
|
||||
* @return a code representing the point status: either {@link
|
||||
* Location#INSIDE}, {@link Location#OUTSIDE} or {@link Location#BOUNDARY}
|
||||
*/
|
||||
public Location checkPoint(final double point, final double tolerance) {
|
||||
public Location checkPoint(final double point) {
|
||||
final double normalizedPoint = MathUtils.normalizeAngle(point, middle);
|
||||
if (normalizedPoint < lower - tolerance || normalizedPoint > upper + tolerance) {
|
||||
return Location.OUTSIDE;
|
||||
|
|
|
@ -21,6 +21,8 @@ import java.util.Collection;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.math3.exception.NumberIsTooLargeException;
|
||||
import org.apache.commons.math3.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math3.geometry.partitioning.AbstractRegion;
|
||||
import org.apache.commons.math3.geometry.partitioning.BSPTree;
|
||||
import org.apache.commons.math3.geometry.partitioning.BSPTreeVisitor;
|
||||
|
@ -30,6 +32,13 @@ import org.apache.commons.math3.util.MathUtils;
|
|||
import org.apache.commons.math3.util.Precision;
|
||||
|
||||
/** This class represents a region of a circle: a set of arcs.
|
||||
* <p>
|
||||
* Note that due to the wrapping around \(2 \pi\), barycenter is
|
||||
* ill-defined here. It was defined only in order to fulfill
|
||||
* the requirements of the {@link
|
||||
* org.apache.commons.math3.geometry.partitioning.Region Region}
|
||||
* interface, but its use is discouraged.
|
||||
* </p>
|
||||
* @version $Id$
|
||||
* @since 3.3
|
||||
*/
|
||||
|
@ -47,19 +56,19 @@ public class ArcsSet extends AbstractRegion<Sphere1D, Sphere1D> {
|
|||
|
||||
/** Build an arcs set corresponding to a single arc.
|
||||
* <p>
|
||||
* As the circle is a closed curve, {@code lower} is
|
||||
* allowed to be greater than {@code upper}, and will
|
||||
* be automatically canonicalized so the arc wraps
|
||||
* around \( 2\pi \), but without exceeding a total
|
||||
* length of \( 2\pi \). If {@code lower} is equals
|
||||
* to {@code upper}, the arc is considered to be the full
|
||||
* circle.
|
||||
* If either {@code lower} is equals to {@code upper} or
|
||||
* the interval exceeds \( 2 \pi \), the arc is considered
|
||||
* to be the full circle and its initial defining boundaries
|
||||
* will be forgotten. {@code lower} is not allowed to be greater
|
||||
* than {@code upper} (an exception is thrown in this case).
|
||||
* </p>
|
||||
* @param lower lower bound of the arc
|
||||
* @param upper upper bound of the arc
|
||||
* @param tolerance tolerance below which close sub-arcs are merged together
|
||||
* @exception NumberIsTooLargeException if lower is greater than upper
|
||||
*/
|
||||
public ArcsSet(final double lower, final double upper, final double tolerance) {
|
||||
public ArcsSet(final double lower, final double upper, final double tolerance)
|
||||
throws NumberIsTooLargeException {
|
||||
super(buildTree(lower, upper, tolerance));
|
||||
this.tolerance = tolerance;
|
||||
}
|
||||
|
@ -105,33 +114,236 @@ public class ArcsSet extends AbstractRegion<Sphere1D, Sphere1D> {
|
|||
}
|
||||
|
||||
/** Build an inside/outside tree representing a single arc.
|
||||
* <p>
|
||||
* As the circle is a closed curve, {@code lower} is
|
||||
* allowed to be greater than {@code upper}, and will
|
||||
* be automatically canonicalized so the arc wraps
|
||||
* around \( 2\pi \), but without exceeding a total
|
||||
* length of \( 2\pi \). If {@code lower} is equals
|
||||
* to {@code upper}, the arc is considered to be the full
|
||||
* circle.
|
||||
* </p>
|
||||
* @param lower lower angular bound of the arc
|
||||
* @param upper upper angular bound of the arc
|
||||
* @param tolerance tolerance below which close sub-arcs are merged together
|
||||
* @return the built tree
|
||||
* @exception NumberIsTooLargeException if lower is greater than upper
|
||||
*/
|
||||
private static BSPTree<Sphere1D> buildTree(final double lower, final double upper, final double tolerance) {
|
||||
private static BSPTree<Sphere1D> buildTree(final double lower, final double upper,
|
||||
final double tolerance)
|
||||
throws NumberIsTooLargeException {
|
||||
|
||||
if (Precision.equals(lower, upper, 0)) {
|
||||
// the tree must cover the whole real line
|
||||
if (Precision.equals(lower, upper, 0) || (upper - lower) >= MathUtils.TWO_PI) {
|
||||
// the tree must cover the whole circle
|
||||
return new BSPTree<Sphere1D>(Boolean.TRUE);
|
||||
} else if (lower > upper) {
|
||||
throw new NumberIsTooLargeException(LocalizedFormats.ENDPOINTS_NOT_AN_INTERVAL,
|
||||
lower, upper, true);
|
||||
}
|
||||
|
||||
// the two boundary angles define only one cutting chord
|
||||
final double normalizedUpper = MathUtils.normalizeAngle(upper, lower + FastMath.PI);
|
||||
return new BSPTree<Sphere1D>(new Chord(lower, normalizedUpper, tolerance).wholeHyperplane(),
|
||||
// this is a regular arc, covering only part of the circle
|
||||
final double normalizedLower = MathUtils.normalizeAngle(lower, FastMath.PI);
|
||||
final double normalizedUpper = normalizedLower + (upper - lower);
|
||||
final SubHyperplane<Sphere1D> lowerCut =
|
||||
new LimitAngle(new S1Point(normalizedLower), false, tolerance).wholeHyperplane();
|
||||
|
||||
if (normalizedUpper <= MathUtils.TWO_PI) {
|
||||
// simple arc starting after 0 and ending before 2 \pi
|
||||
final SubHyperplane<Sphere1D> upperCut =
|
||||
new LimitAngle(new S1Point(normalizedUpper), true, tolerance).wholeHyperplane();
|
||||
return new BSPTree<Sphere1D>(lowerCut,
|
||||
new BSPTree<Sphere1D>(Boolean.FALSE),
|
||||
new BSPTree<Sphere1D>(upperCut,
|
||||
new BSPTree<Sphere1D>(Boolean.FALSE),
|
||||
new BSPTree<Sphere1D>(Boolean.TRUE),
|
||||
null),
|
||||
null);
|
||||
} else {
|
||||
// arc wrapping around 2 \pi
|
||||
final SubHyperplane<Sphere1D> upperCut =
|
||||
new LimitAngle(new S1Point(normalizedUpper - MathUtils.TWO_PI), true, tolerance).wholeHyperplane();
|
||||
return new BSPTree<Sphere1D>(lowerCut,
|
||||
new BSPTree<Sphere1D>(upperCut,
|
||||
new BSPTree<Sphere1D>(Boolean.FALSE),
|
||||
new BSPTree<Sphere1D>(Boolean.TRUE),
|
||||
null),
|
||||
new BSPTree<Sphere1D>(Boolean.TRUE),
|
||||
null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Get the tolerance below which angles are considered identical.
|
||||
* @return tolerance below which angles are considered identical
|
||||
*/
|
||||
public double getTolerance() {
|
||||
return tolerance;
|
||||
}
|
||||
|
||||
/** Get the smallest internal node.
|
||||
* @return smallest internal node (i.e. first after 0.0 radians, in trigonometric direction),
|
||||
* or null if there are no internal nodes (i.e. the set is either empty or covers the full circle)
|
||||
*/
|
||||
public LimitAngle getSmallestLimit() {
|
||||
|
||||
// start search at the tree root
|
||||
BSPTree<Sphere1D> node = getTree(false);
|
||||
if (node.getCut() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BSPTree<Sphere1D> previous = previousNode(node);
|
||||
while (previous != null) {
|
||||
node = previous;
|
||||
previous = previousNode(node);
|
||||
}
|
||||
|
||||
return (LimitAngle) node.getCut().getHyperplane();
|
||||
|
||||
}
|
||||
|
||||
/** Get the largest limit angle in the set.
|
||||
* @return largest limit angle (i.e. last before or at \(2 \pi) radians, in trigonometric direction),
|
||||
* or null if there are no limits (i.e. the set is either empty or covers the full circle)
|
||||
*/
|
||||
public LimitAngle getLargestLimit() {
|
||||
|
||||
// start search at the tree root
|
||||
BSPTree<Sphere1D> node = getTree(false);
|
||||
if (node.getCut() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BSPTree<Sphere1D> next = nextNode(node);
|
||||
while (next != null) {
|
||||
node = next;
|
||||
next = nextNode(node);
|
||||
}
|
||||
|
||||
return (LimitAngle) node.getCut().getHyperplane();
|
||||
|
||||
}
|
||||
|
||||
/** Get the next internal node.
|
||||
* @param node current node
|
||||
* @return next internal node in trigonometric order, or null
|
||||
* if this is the last internal node
|
||||
*/
|
||||
private BSPTree<Sphere1D> nextNode(BSPTree<Sphere1D> node) {
|
||||
|
||||
final BSPTree<Sphere1D> nextDeeper =
|
||||
((LimitAngle) node.getCut().getHyperplane()).isDirect() ?
|
||||
node.getPlus() : node.getMinus();
|
||||
|
||||
if (nextDeeper.getCut() != null) {
|
||||
// the next node is in the sub-tree
|
||||
return findSmallest(nextDeeper);
|
||||
}
|
||||
|
||||
// there is nothing left deeper in the tree, we backtrack
|
||||
while (isAfterParent(node)) {
|
||||
node = node.getParent();
|
||||
}
|
||||
return node.getParent();
|
||||
|
||||
}
|
||||
|
||||
/** Get the previous internal node.
|
||||
* @param node current node
|
||||
* @return previous internal node in trigonometric order, or null
|
||||
* if this is the first internal node
|
||||
*/
|
||||
private BSPTree<Sphere1D> previousNode(BSPTree<Sphere1D> node) {
|
||||
|
||||
final BSPTree<Sphere1D> nextDeeper =
|
||||
((LimitAngle) node.getCut().getHyperplane()).isDirect() ?
|
||||
node.getMinus() : node.getPlus();
|
||||
|
||||
if (nextDeeper.getCut() != null) {
|
||||
// the next node is in the sub-tree
|
||||
return findLargest(nextDeeper);
|
||||
}
|
||||
|
||||
// there is nothing left deeper in the tree, we backtrack
|
||||
while (isBeforeParent(node)) {
|
||||
node = node.getParent();
|
||||
}
|
||||
return node.getParent();
|
||||
|
||||
}
|
||||
|
||||
/** Check if a node is the child before its parent in trigonometric order.
|
||||
* @param node child node considered
|
||||
* @return true is the node has a parent end is before it in trigonometric order
|
||||
*/
|
||||
private boolean isBeforeParent(final BSPTree<Sphere1D> node) {
|
||||
final BSPTree<Sphere1D> parent = node.getParent();
|
||||
if (parent == null) {
|
||||
return false;
|
||||
}
|
||||
if (((LimitAngle) parent.getCut().getHyperplane()).isDirect()) {
|
||||
// smaller angles are on minus side, larger angles are on plus side
|
||||
return node == parent.getMinus();
|
||||
} else {
|
||||
// smaller angles are on plus side, larger angles are on minus side
|
||||
return node == parent.getPlus();
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if a node is the child after its parent in trigonometric order.
|
||||
* @param node child node considered
|
||||
* @return true is the node has a parent end is after it in trigonometric order
|
||||
*/
|
||||
private boolean isAfterParent(final BSPTree<Sphere1D> node) {
|
||||
final BSPTree<Sphere1D> parent = node.getParent();
|
||||
if (parent == null) {
|
||||
return false;
|
||||
}
|
||||
if (((LimitAngle) parent.getCut().getHyperplane()).isDirect()) {
|
||||
// smaller angles are on minus side, larger angles are on plus side
|
||||
return node == parent.getPlus();
|
||||
} else {
|
||||
// smaller angles are on plus side, larger angles are on minus side
|
||||
return node == parent.getMinus();
|
||||
}
|
||||
}
|
||||
|
||||
/** Find the smallest internal node in a sub-tree.
|
||||
* @param node node at which the sub-tree starts
|
||||
* @return smallest internal node (in trigonometric order), may be the
|
||||
* provided node if no smaller internal node exist
|
||||
*/
|
||||
private BSPTree<Sphere1D> findSmallest(BSPTree<Sphere1D> node) {
|
||||
|
||||
BSPTree<Sphere1D> internal = null;
|
||||
|
||||
while (node.getCut() != null) {
|
||||
internal = node;
|
||||
if (((LimitAngle) node.getCut().getHyperplane()).isDirect()) {
|
||||
// smaller angles are on minus side, larger angles are on plus side
|
||||
node = node.getMinus();
|
||||
} else {
|
||||
// smaller angles are on plus side, larger angles are on minus side
|
||||
node = node.getPlus();
|
||||
}
|
||||
}
|
||||
|
||||
return internal;
|
||||
|
||||
}
|
||||
|
||||
/** Find the largest internal node in a sub-tree.
|
||||
* @param node node at which the sub-tree starts
|
||||
* @return largest internal node (in trigonometric order), may be the
|
||||
* provided node if no larger internal node exist
|
||||
*/
|
||||
private BSPTree<Sphere1D> findLargest(BSPTree<Sphere1D> node) {
|
||||
|
||||
BSPTree<Sphere1D> internal = null;
|
||||
|
||||
while (node.getCut() != null) {
|
||||
internal = node;
|
||||
if (((LimitAngle) node.getCut().getHyperplane()).isDirect()) {
|
||||
// smaller angles are on minus side, larger angles are on plus side
|
||||
node = node.getPlus();
|
||||
} else {
|
||||
// smaller angles are on plus side, larger angles are on minus side
|
||||
node = node.getMinus();
|
||||
}
|
||||
}
|
||||
|
||||
return internal;
|
||||
|
||||
}
|
||||
|
||||
|
@ -160,8 +372,8 @@ public class ArcsSet extends AbstractRegion<Sphere1D, Sphere1D> {
|
|||
} else if (size >= Precision.SAFE_MIN) {
|
||||
setBarycenter(new S1Point(sum / size));
|
||||
} else {
|
||||
final Chord chord = (Chord) getTree(false).getCut().getHyperplane();
|
||||
setBarycenter(new S1Point(0.5 * (chord.getStart() + chord.getEnd())));
|
||||
final LimitAngle limit = (LimitAngle) getTree(false).getCut().getHyperplane();
|
||||
setBarycenter(limit.getLocation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -182,7 +394,7 @@ public class ArcsSet extends AbstractRegion<Sphere1D, Sphere1D> {
|
|||
// the tree has a single node
|
||||
if ((Boolean) root.getAttribute()) {
|
||||
// it is an inside node, it represents the full circle
|
||||
list.add(new Arc(0.0, 0.0)); // since lower == upper, the arc covers the full circle
|
||||
list.add(new Arc(0.0, 0.0, tolerance)); // since lower == upper, the arc covers the full circle
|
||||
}
|
||||
} else {
|
||||
|
||||
|
@ -190,6 +402,11 @@ public class ArcsSet extends AbstractRegion<Sphere1D, Sphere1D> {
|
|||
final LimitsCollector finder = new LimitsCollector();
|
||||
root.visit(finder);
|
||||
final List<Double> limits = finder.getLimits();
|
||||
if (limits.size() < 2) {
|
||||
// the start and end angle collapsed to the same value, its the full circle again
|
||||
list.add(new Arc(0.0, 0.0, tolerance)); // since lower == upper, the arc covers the full circle
|
||||
return list;
|
||||
}
|
||||
|
||||
// sort them so the first angle is an arc start
|
||||
Collections.sort(limits);
|
||||
|
@ -201,7 +418,7 @@ public class ArcsSet extends AbstractRegion<Sphere1D, Sphere1D> {
|
|||
|
||||
// we can now build the list
|
||||
for (int i = 0; i < limits.size(); i += 2) {
|
||||
list.add(new Arc(limits.get(i), limits.get(i + 1)));
|
||||
list.add(new Arc(limits.get(i), limits.get(i + 1), tolerance));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -229,12 +446,9 @@ public class ArcsSet extends AbstractRegion<Sphere1D, Sphere1D> {
|
|||
/** {@inheritDoc} */
|
||||
public void visitInternalNode(final BSPTree<Sphere1D> node) {
|
||||
// check if the chord end points are arc limits
|
||||
final Chord chord = (Chord) node.getCut().getHyperplane();
|
||||
if (checkPoint(new S1Point(chord.getStart())) == Location.BOUNDARY) {
|
||||
limits.add(MathUtils.normalizeAngle(chord.getStart(), FastMath.PI));
|
||||
}
|
||||
if (checkPoint(new S1Point(chord.getEnd())) == Location.BOUNDARY) {
|
||||
limits.add(MathUtils.normalizeAngle(chord.getEnd(), FastMath.PI));
|
||||
final LimitAngle limit = (LimitAngle) node.getCut().getHyperplane();
|
||||
if (checkPoint(limit.getLocation()) == Location.BOUNDARY) {
|
||||
limits.add(limit.getLocation().getAlpha());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,43 +18,33 @@ package org.apache.commons.math3.geometry.spherical.oned;
|
|||
|
||||
import org.apache.commons.math3.geometry.Point;
|
||||
import org.apache.commons.math3.geometry.partitioning.Hyperplane;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
import org.apache.commons.math3.util.MathUtils;
|
||||
|
||||
/** This class represents a 1D oriented hyperplane on the circle.
|
||||
* <p>An hyperplane on the 1-sphere is a chord that splits
|
||||
* the circle in two parts.</p>
|
||||
* <p>An hyperplane on the 1-sphere is an angle with an orientation.</p>
|
||||
* <p>Instances of this class are guaranteed to be immutable.</p>
|
||||
* @version $Id$
|
||||
* @since 3.3
|
||||
*/
|
||||
public class Chord implements Hyperplane<Sphere1D> {
|
||||
public class LimitAngle implements Hyperplane<Sphere1D> {
|
||||
|
||||
/** Start angle of the chord. */
|
||||
private final double start;
|
||||
/** Angle location. */
|
||||
private S1Point location;
|
||||
|
||||
/** End angle of the chord. */
|
||||
private final double end;
|
||||
/** Orientation. */
|
||||
private boolean direct;
|
||||
|
||||
/** Cosine of the half aperture. */
|
||||
private final double cos;
|
||||
|
||||
/** Middle point of the chord. */
|
||||
private final S1Point middle;
|
||||
|
||||
/** Tolerance below which close sub-arcs are merged together. */
|
||||
/** Tolerance below which angles are considered identical. */
|
||||
private final double tolerance;
|
||||
|
||||
/** Simple constructor.
|
||||
* @param start start angle of the chord
|
||||
* @param end end angle of the chord
|
||||
* @param tolerance tolerance below which close sub-arcs are merged together
|
||||
* @param location location of the hyperplane
|
||||
* @param direct if true, the plus side of the hyperplane is towards
|
||||
* angles greater than {@code location}
|
||||
* @param tolerance tolerance below which angles are considered identical
|
||||
*/
|
||||
public Chord(final double start, final double end, final double tolerance) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.middle = new S1Point(0.5 * (start + end));
|
||||
this.cos = FastMath.cos(0.5 * (end - start));
|
||||
public LimitAngle(final S1Point location, final boolean direct, final double tolerance) {
|
||||
this.location = location;
|
||||
this.direct = direct;
|
||||
this.tolerance = tolerance;
|
||||
}
|
||||
|
||||
|
@ -63,22 +53,31 @@ public class Chord implements Hyperplane<Sphere1D> {
|
|||
* the instance.</p>
|
||||
* @return the instance itself
|
||||
*/
|
||||
public Chord copySelf() {
|
||||
public LimitAngle copySelf() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public double getOffset(final Point<Sphere1D> point) {
|
||||
return cos - middle.getVector().dotProduct(((S1Point) point).getVector());
|
||||
final double delta = ((S1Point) point).getAlpha()- location.getAlpha();
|
||||
return direct ? delta : -delta;
|
||||
}
|
||||
|
||||
/** Check if the hyperplane orientation is direct.
|
||||
* @return true if the plus side of the hyperplane is towards
|
||||
* angles greater than hyperplane location
|
||||
*/
|
||||
public boolean isDirect() {
|
||||
return direct;
|
||||
}
|
||||
|
||||
/** Get the reverse of the instance.
|
||||
* <p>Get a chord with reversed orientation with respect to the
|
||||
* <p>Get a limit angle with reversed orientation with respect to the
|
||||
* instance. A new object is built, the instance is untouched.</p>
|
||||
* @return a new chord, with orientation opposite to the instance orientation
|
||||
* @return a new limit angle, with orientation opposite to the instance orientation
|
||||
*/
|
||||
public Chord getReverse() {
|
||||
return new Chord(end, MathUtils.normalizeAngle(start, end + FastMath.PI), tolerance);
|
||||
public LimitAngle getReverse() {
|
||||
return new LimitAngle(location, !direct, tolerance);
|
||||
}
|
||||
|
||||
/** Build a region covering the whole hyperplane.
|
||||
|
@ -92,8 +91,8 @@ public class Chord implements Hyperplane<Sphere1D> {
|
|||
* <em>not</em> be used otherwise.</p>
|
||||
* @return a dummy sub hyperplane
|
||||
*/
|
||||
public SubChord wholeHyperplane() {
|
||||
return new SubChord(this);
|
||||
public SubLimitAngle wholeHyperplane() {
|
||||
return new SubLimitAngle(this, null);
|
||||
}
|
||||
|
||||
/** Build a region covering the whole space.
|
||||
|
@ -106,25 +105,18 @@ public class Chord implements Hyperplane<Sphere1D> {
|
|||
|
||||
/** {@inheritDoc} */
|
||||
public boolean sameOrientationAs(final Hyperplane<Sphere1D> other) {
|
||||
return middle.getVector().dotProduct(((Chord) other).middle.getVector()) >= 0.0;
|
||||
return !(direct ^ ((LimitAngle) other).direct);
|
||||
}
|
||||
|
||||
/** Get the start angle of the chord.
|
||||
* @return start angle of the chord.
|
||||
/** Get the hyperplane location on the circle.
|
||||
* @return the hyperplane location
|
||||
*/
|
||||
public double getStart() {
|
||||
return start;
|
||||
public S1Point getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/** Get the end angle of the chord.
|
||||
* @return end angle of the chord.
|
||||
*/
|
||||
public double getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
/** Get the tolerance below which close sub-arcs are merged together.
|
||||
* @return tolerance below which close sub-arcs are merged together
|
||||
/** Get the tolerance below which angles are considered identical.
|
||||
* @return tolerance below which angles are considered identical
|
||||
*/
|
||||
public double getTolerance() {
|
||||
return tolerance;
|
|
@ -49,7 +49,8 @@ public class S1Point implements Point<Sphere1D> {
|
|||
* @see #getAlpha()
|
||||
*/
|
||||
public S1Point(final double alpha) {
|
||||
this(alpha, new Vector2D(FastMath.cos(alpha), FastMath.sin(alpha)));
|
||||
this(MathUtils.normalizeAngle(alpha, FastMath.PI),
|
||||
new Vector2D(FastMath.cos(alpha), FastMath.sin(alpha)));
|
||||
}
|
||||
|
||||
/** Build a point from its internal components.
|
||||
|
|
|
@ -1,332 +0,0 @@
|
|||
/*
|
||||
* 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.math3.geometry.spherical.oned;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.math3.geometry.partitioning.Hyperplane;
|
||||
import org.apache.commons.math3.geometry.partitioning.Side;
|
||||
import org.apache.commons.math3.geometry.partitioning.SubHyperplane;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
import org.apache.commons.math3.util.MathUtils;
|
||||
import org.apache.commons.math3.util.Precision;
|
||||
|
||||
/** This class represents sub-hyperplane for {@link Chord}.
|
||||
* <p>Instances of this class are guaranteed to be immutable.</p>
|
||||
* @version $Id$
|
||||
* @since 3.3
|
||||
*/
|
||||
public class SubChord implements SubHyperplane<Sphere1D> {
|
||||
|
||||
/** Underlying hyperplane. */
|
||||
private final Chord chord;
|
||||
|
||||
/** Boundary angles. */
|
||||
private final List<Double> limits;
|
||||
|
||||
/** Simple constructor.
|
||||
* @param chord underlying hyperplane
|
||||
*/
|
||||
public SubChord(final Chord chord) {
|
||||
this.chord = chord;
|
||||
this.limits = new ArrayList<Double>();
|
||||
limits.add(chord.getStart());
|
||||
limits.add(chord.getEnd());
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* @param chord underlying hyperplane
|
||||
* @param limits limit angles (the list will be copied into a new independent list)
|
||||
*/
|
||||
private SubChord(final Chord chord, final List<Double> limits) {
|
||||
this.chord = chord;
|
||||
this.limits = new ArrayList<Double>(limits);
|
||||
}
|
||||
|
||||
/** Get the sub-arcs.
|
||||
* @return a newly created list with sub-arcs
|
||||
*/
|
||||
public List<Arc> getSubArcs() {
|
||||
final List<Arc> subArcs = new ArrayList<Arc>(limits.size() / 2);
|
||||
for (int i = 0; i < limits.size(); i += 2) {
|
||||
subArcs.add(new Arc(limits.get(i), limits.get(i + 1)));
|
||||
}
|
||||
return subArcs;
|
||||
}
|
||||
|
||||
/** Get the number of sub-arcs.
|
||||
* @return number of sub-arcs
|
||||
*/
|
||||
public int getNbSubArcs() {
|
||||
return limits.size() / 2;
|
||||
}
|
||||
|
||||
/** Get the start of the i<sup>th</sup> sub-arc.
|
||||
* @param i index of the desired arc (counting from 0)
|
||||
* @return start of the i<sup>th</sup> sub-arc
|
||||
*/
|
||||
public double getStart(final int i) {
|
||||
return limits.get(2 * i);
|
||||
}
|
||||
|
||||
/** Get the end of the i<sup>th</sup> sub-arc.
|
||||
* @param i index of the desired arc (counting from 0)
|
||||
* @return end of the i<sup>th</sup> sub-arc
|
||||
*/
|
||||
public double getEnd(final int i) {
|
||||
return limits.get(2 * i + 1);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public double getSize() {
|
||||
double sum = 0;
|
||||
for (int i = 0; i < limits.size(); i += 2) {
|
||||
sum += limits.get(i + 1) - limits.get(i);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public Side side(final Hyperplane<Sphere1D> hyperplane) {
|
||||
|
||||
final Chord testChord = (Chord) hyperplane;
|
||||
final double reference = FastMath.PI + testChord.getStart();
|
||||
final double chordLength = testChord.getEnd() - testChord.getStart();
|
||||
|
||||
boolean inMinus = false;
|
||||
boolean inPlus = false;
|
||||
for (int i = 0; i < limits.size(); i += 2) {
|
||||
final double syncedStart = MathUtils.normalizeAngle(limits.get(i), reference) - testChord.getStart();
|
||||
final double chordOffset = limits.get(i) - syncedStart;
|
||||
final double syncedEnd = limits.get(i + 1) - chordOffset;
|
||||
if (syncedStart < chordLength || syncedEnd > MathUtils.TWO_PI) {
|
||||
inMinus = true;
|
||||
}
|
||||
if (syncedEnd > chordLength) {
|
||||
inPlus = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (inMinus) {
|
||||
if (inPlus) {
|
||||
return Side.BOTH;
|
||||
} else {
|
||||
return Side.MINUS;
|
||||
}
|
||||
} else {
|
||||
if (inPlus) {
|
||||
return Side.PLUS;
|
||||
} else {
|
||||
return Side.HYPER;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public SplitSubHyperplane<Sphere1D> split(final Hyperplane<Sphere1D> hyperplane) {
|
||||
|
||||
final List<Double> minus = new ArrayList<Double>(limits.size());
|
||||
final List<Double> plus = new ArrayList<Double>(limits.size());
|
||||
|
||||
final Chord testChord = (Chord) hyperplane;
|
||||
final double reference = FastMath.PI + testChord.getStart();
|
||||
final double chordLength = testChord.getEnd() - testChord.getStart();
|
||||
|
||||
for (int i = 0; i < limits.size(); i += 2) {
|
||||
final double syncedStart = MathUtils.normalizeAngle(limits.get(i), reference) - testChord.getStart();
|
||||
final double chordOffset = limits.get(i) - syncedStart;
|
||||
final double syncedEnd = limits.get(i + 1) - chordOffset;
|
||||
if (syncedStart < chordLength) {
|
||||
// the start point limits.get(i) is in the minus part of the chord
|
||||
minus.add(limits.get(i));
|
||||
if (syncedEnd > chordLength) {
|
||||
// the end point limits.get(i + 1) is past the end of the chord
|
||||
// so we leave the minus part and enter the plus part
|
||||
final double minusToPlus = chordLength + chordOffset;
|
||||
minus.add(minusToPlus);
|
||||
plus.add(minusToPlus);
|
||||
if (syncedEnd > MathUtils.TWO_PI) {
|
||||
// in fact the end point limits.get(i + 1) goes far enough that we
|
||||
// leave the plus part of the chord and enter the minus part again
|
||||
final double plusToMinus = MathUtils.TWO_PI + chordOffset;
|
||||
plus.add(plusToMinus);
|
||||
minus.add(plusToMinus);
|
||||
minus.add(limits.get(i + 1));
|
||||
} else {
|
||||
// the end point limits.get(i + 1) is in the plus part of the chord
|
||||
plus.add(limits.get(i + 1));
|
||||
}
|
||||
} else {
|
||||
// the end point limits.get(i + 1) is in the minus part of the chord
|
||||
minus.add(limits.get(i + 1));
|
||||
}
|
||||
} else {
|
||||
// the start point limits.get(i) is in the plus part of the chord
|
||||
plus.add(limits.get(i));
|
||||
if (syncedEnd > MathUtils.TWO_PI) {
|
||||
// the end point limits.get(i + 1) wraps around to the start of the chord
|
||||
// so we leave the plus part and enter the minus part
|
||||
final double plusToMinus = MathUtils.TWO_PI + chordOffset;
|
||||
plus.add(plusToMinus);
|
||||
minus.add(plusToMinus);
|
||||
if (syncedEnd > MathUtils.TWO_PI + chordLength) {
|
||||
// in fact the end point limits.get(i + 1) goes far enough that we
|
||||
// leave the minus part of the chord and enter the plus part again
|
||||
final double minusToPlus = MathUtils.TWO_PI + chordLength + chordOffset;
|
||||
minus.add(minusToPlus);
|
||||
plus.add(minusToPlus);
|
||||
plus.add(limits.get(i + 1));
|
||||
} else {
|
||||
// the end point limits.get(i + 1) is in the minus part of the chord
|
||||
minus.add(limits.get(i + 1));
|
||||
}
|
||||
} else {
|
||||
// the end point limits.get(i + 1) is in the plus part of the chord
|
||||
plus.add(limits.get(i + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new SplitSubHyperplane<Sphere1D>(plus.isEmpty() ? null : new SubChord(chord, plus),
|
||||
minus.isEmpty() ? null : new SubChord(chord, minus));
|
||||
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public SubChord copySelf() {
|
||||
return new SubChord(chord.copySelf(), limits);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public Chord getHyperplane() {
|
||||
return chord;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public boolean isEmpty() {
|
||||
return getSize() <= Precision.SAFE_MIN;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public SubChord reunite(SubHyperplane<Sphere1D> other) {
|
||||
|
||||
final List<Double> otherLimits = ((SubChord) other).limits;
|
||||
|
||||
final List<Double> merged;
|
||||
if (other.isEmpty()) {
|
||||
merged = limits;
|
||||
} else if (isEmpty()) {
|
||||
merged = otherLimits;
|
||||
} else {
|
||||
|
||||
merged = new ArrayList<Double>(limits.size() + otherLimits.size());
|
||||
final double reference = limits.get(0) + FastMath.PI;
|
||||
|
||||
// initialize loop on first limits list
|
||||
int i = 0;
|
||||
int iEnd = limits.size() - 1;
|
||||
boolean enteringI = true;
|
||||
|
||||
// initialize loop on second limits list
|
||||
int j = otherLimits.size() - 1;
|
||||
double angleAfter = Double.POSITIVE_INFINITY;
|
||||
for (int jSearch = 0; jSearch < otherLimits.size(); ++jSearch) {
|
||||
// look for the first angle in the second list that lies just after first limits start
|
||||
final double angleJ = MathUtils.normalizeAngle(otherLimits.get(jSearch), reference);
|
||||
if (angleJ < angleAfter) {
|
||||
j = jSearch;
|
||||
angleAfter = angleJ;
|
||||
}
|
||||
}
|
||||
int jEnd = (j + otherLimits.size() - 1) % otherLimits.size();
|
||||
boolean enteringJ = j % 2 == 0;
|
||||
|
||||
// perform merging loop
|
||||
boolean inMerged = !enteringJ;
|
||||
double angleI = MathUtils.normalizeAngle(limits.get(i), reference);
|
||||
double angleJ = MathUtils.normalizeAngle(otherLimits.get(j), reference);
|
||||
while (i >= 0 || j >= 0) {
|
||||
|
||||
if (i >= 0 && (j < 0 || angleI <= angleJ)) {
|
||||
if (inMerged && (!enteringI) && enteringJ) {
|
||||
// we were in a merged arc and exit from it
|
||||
merged.add(angleI);
|
||||
inMerged = false;
|
||||
} else if (!inMerged && enteringI) {
|
||||
// we were outside and enter into a merged arc
|
||||
merged.add(angleI);
|
||||
inMerged = true;
|
||||
}
|
||||
if (i == iEnd) {
|
||||
i = -1;
|
||||
} else {
|
||||
++i;
|
||||
angleI = MathUtils.normalizeAngle(limits.get(i), reference);
|
||||
}
|
||||
enteringI = !enteringI;
|
||||
} else {
|
||||
if (inMerged) {
|
||||
if (enteringI && !enteringJ) {
|
||||
// we were in a merged arc and exit from it
|
||||
merged.add(angleJ);
|
||||
inMerged = false;
|
||||
}
|
||||
} else {
|
||||
if (enteringJ) {
|
||||
// we were outside and enter into a merged arc
|
||||
merged.add(angleJ);
|
||||
inMerged = true;
|
||||
}
|
||||
}
|
||||
if (j == jEnd) {
|
||||
j = -1;
|
||||
} else {
|
||||
j = (j + 1) % otherLimits.size();
|
||||
angleJ = MathUtils.normalizeAngle(otherLimits.get(j), reference);
|
||||
}
|
||||
enteringJ = !enteringJ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (inMerged) {
|
||||
// we end the merging loop inside a merged arc,
|
||||
// we have to put its start at the front of the limits list
|
||||
if (merged.isEmpty()) {
|
||||
// the merged arc covers all the circle
|
||||
merged.add(0.0);
|
||||
merged.add(MathUtils.TWO_PI);
|
||||
} else {
|
||||
double previousAngle = merged.get(merged.size() - 1) - MathUtils.TWO_PI;
|
||||
for (int k = 0; k < merged.size() - 1; ++k) {
|
||||
final double tmp = merged.get(k);
|
||||
merged.set(k, previousAngle);
|
||||
previousAngle = tmp;
|
||||
}
|
||||
merged.set(merged.size() - 1, previousAngle);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return new SubChord(chord, merged);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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.math3.geometry.spherical.oned;
|
||||
|
||||
import org.apache.commons.math3.geometry.partitioning.AbstractSubHyperplane;
|
||||
import org.apache.commons.math3.geometry.partitioning.Hyperplane;
|
||||
import org.apache.commons.math3.geometry.partitioning.Region;
|
||||
import org.apache.commons.math3.geometry.partitioning.Side;
|
||||
|
||||
/** This class represents sub-hyperplane for {@link LimitAngle}.
|
||||
* <p>Instances of this class are guaranteed to be immutable.</p>
|
||||
* @version $Id$
|
||||
* @since 3.3
|
||||
*/
|
||||
public class SubLimitAngle extends AbstractSubHyperplane<Sphere1D, Sphere1D> {
|
||||
|
||||
/** Simple constructor.
|
||||
* @param hyperplane underlying hyperplane
|
||||
* @param remainingRegion remaining region of the hyperplane
|
||||
*/
|
||||
public SubLimitAngle(final Hyperplane<Sphere1D> hyperplane,
|
||||
final Region<Sphere1D> remainingRegion) {
|
||||
super(hyperplane, remainingRegion);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public double getSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected AbstractSubHyperplane<Sphere1D, Sphere1D> buildNew(final Hyperplane<Sphere1D> hyperplane,
|
||||
final Region<Sphere1D> remainingRegion) {
|
||||
return new SubLimitAngle(hyperplane, remainingRegion);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public Side side(final Hyperplane<Sphere1D> hyperplane) {
|
||||
final double global = hyperplane.getOffset(((LimitAngle) getHyperplane()).getLocation());
|
||||
return (global < -1.0e-10) ? Side.MINUS : ((global > 1.0e-10) ? Side.PLUS : Side.HYPER);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public SplitSubHyperplane<Sphere1D> split(final Hyperplane<Sphere1D> hyperplane) {
|
||||
final double global = hyperplane.getOffset(((LimitAngle) getHyperplane()).getLocation());
|
||||
return (global < -1.0e-10) ?
|
||||
new SplitSubHyperplane<Sphere1D>(null, this) :
|
||||
new SplitSubHyperplane<Sphere1D>(this, null);
|
||||
}
|
||||
|
||||
}
|
|
@ -23,8 +23,8 @@ import org.apache.commons.math3.geometry.partitioning.Embedding;
|
|||
import org.apache.commons.math3.geometry.partitioning.Hyperplane;
|
||||
import org.apache.commons.math3.geometry.partitioning.SubHyperplane;
|
||||
import org.apache.commons.math3.geometry.partitioning.Transform;
|
||||
import org.apache.commons.math3.geometry.spherical.oned.Arc;
|
||||
import org.apache.commons.math3.geometry.spherical.oned.ArcsSet;
|
||||
import org.apache.commons.math3.geometry.spherical.oned.Chord;
|
||||
import org.apache.commons.math3.geometry.spherical.oned.S1Point;
|
||||
import org.apache.commons.math3.geometry.spherical.oned.Sphere1D;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
|
@ -223,15 +223,15 @@ public class Circle implements Hyperplane<Sphere2D>, Embedding<Sphere2D, Sphere1
|
|||
return pole;
|
||||
}
|
||||
|
||||
/** Get the chord of the instance that lies inside the other circle.
|
||||
/** Get the arc of the instance that lies inside the other circle.
|
||||
* @param other other circle
|
||||
* @return chord of the instance that lies inside the other circle
|
||||
* @return arc of the instance that lies inside the other circle
|
||||
* (guaranteed to always have a length of \( \pi \))
|
||||
*/
|
||||
public Chord getChord(final Circle other) {
|
||||
public Arc getInsideArc(final Circle other) {
|
||||
final double alpha = getPhase(other.pole);
|
||||
final double halfPi = 0.5 * FastMath.PI;
|
||||
return new Chord(alpha - halfPi, alpha + halfPi, tolerance);
|
||||
return new Arc(alpha - halfPi, alpha + halfPi, tolerance);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.apache.commons.math3.geometry.partitioning.Hyperplane;
|
|||
import org.apache.commons.math3.geometry.partitioning.Region;
|
||||
import org.apache.commons.math3.geometry.partitioning.Side;
|
||||
import org.apache.commons.math3.geometry.partitioning.SubHyperplane;
|
||||
import org.apache.commons.math3.geometry.spherical.oned.Arc;
|
||||
import org.apache.commons.math3.geometry.spherical.oned.ArcsSet;
|
||||
import org.apache.commons.math3.geometry.spherical.oned.Chord;
|
||||
import org.apache.commons.math3.geometry.spherical.oned.Sphere1D;
|
||||
|
@ -54,16 +55,8 @@ public class SubCircle extends AbstractSubHyperplane<Sphere2D, Sphere1D> {
|
|||
|
||||
final Circle thisCircle = (Circle) getHyperplane();
|
||||
final Circle otherCircle = (Circle) hyperplane;
|
||||
final Chord chord = thisCircle.getChord(otherCircle);
|
||||
|
||||
if (chord == null) {
|
||||
// the circles are disjoint
|
||||
final double global = otherCircle.getOffset(thisCircle.getXAxis());
|
||||
return (global < -1.0e-10) ? Side.MINUS : ((global > 1.0e-10) ? Side.PLUS : Side.HYPER);
|
||||
}
|
||||
|
||||
// the circles do intersect each other
|
||||
return getRemainingRegion().side(chord);
|
||||
final Arc arc = thisCircle.getInsideArc(otherCircle);
|
||||
return ((ArcsSet) getRemainingRegion()).side(arc);
|
||||
|
||||
}
|
||||
|
||||
|
@ -73,17 +66,8 @@ public class SubCircle extends AbstractSubHyperplane<Sphere2D, Sphere1D> {
|
|||
|
||||
final Circle thisCircle = (Circle) getHyperplane();
|
||||
final Circle otherCircle = (Circle) hyperplane;
|
||||
final Chord chord = thisCircle.getChord(otherCircle);
|
||||
final Arc arc = thisCircle.getInsideArc(otherCircle);
|
||||
|
||||
if (chord == null) {
|
||||
// the circles are disjoint
|
||||
final double global = otherCircle.getOffset(thisCircle.getXAxis());
|
||||
return (global < -1.0e-10) ?
|
||||
new SplitSubHyperplane<Sphere2D>(null, this) :
|
||||
new SplitSubHyperplane<Sphere2D>(this, null);
|
||||
}
|
||||
|
||||
// the circles do intersect
|
||||
final SubHyperplane<Sphere1D> subMinus = chord.wholeHyperplane();
|
||||
final SubHyperplane<Sphere1D> subPlus = chord.getReverse().wholeHyperplane();
|
||||
final BSPTree<Sphere1D> splitTree = getRemainingRegion().getTree(false).split(subMinus);
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
*/
|
||||
package org.apache.commons.math3.geometry.spherical.oned;
|
||||
|
||||
import org.apache.commons.math3.exception.NumberIsTooLargeException;
|
||||
import org.apache.commons.math3.geometry.partitioning.Region;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
import org.apache.commons.math3.util.MathUtils;
|
||||
import org.apache.commons.math3.util.Precision;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
@ -26,49 +28,52 @@ public class ArcTest {
|
|||
|
||||
@Test
|
||||
public void testArc() {
|
||||
Arc arc = new Arc(2.3, 5.7);
|
||||
Arc arc = new Arc(2.3, 5.7, 1.0e-10);
|
||||
Assert.assertEquals(3.4, arc.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(4.0, arc.getBarycenter(), 1.0e-10);
|
||||
Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(2.3, 1.0e-10));
|
||||
Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(5.7, 1.0e-10));
|
||||
Assert.assertEquals(Region.Location.OUTSIDE, arc.checkPoint(1.2, 1.0e-10));
|
||||
Assert.assertEquals(Region.Location.OUTSIDE, arc.checkPoint(8.5, 1.0e-10));
|
||||
Assert.assertEquals(Region.Location.INSIDE, arc.checkPoint(8.7, 1.0e-10));
|
||||
Assert.assertEquals(Region.Location.INSIDE, arc.checkPoint(3.0, 1.0e-10));
|
||||
Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(2.3));
|
||||
Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(5.7));
|
||||
Assert.assertEquals(Region.Location.OUTSIDE, arc.checkPoint(1.2));
|
||||
Assert.assertEquals(Region.Location.OUTSIDE, arc.checkPoint(8.5));
|
||||
Assert.assertEquals(Region.Location.INSIDE, arc.checkPoint(8.7));
|
||||
Assert.assertEquals(Region.Location.INSIDE, arc.checkPoint(3.0));
|
||||
Assert.assertEquals(2.3, arc.getInf(), 1.0e-10);
|
||||
Assert.assertEquals(5.7, arc.getSup(), 1.0e-10);
|
||||
Assert.assertEquals(4.0, arc.getBarycenter(), 1.0e-10);
|
||||
Assert.assertEquals(3.4, arc.getSize(), 1.0e-10);
|
||||
}
|
||||
|
||||
@Test(expected=NumberIsTooLargeException.class)
|
||||
public void testWrongInterval() {
|
||||
new Arc(1.2, 0.0, 1.0e-10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTolerance() {
|
||||
Arc arc = new Arc(2.3, 5.7);
|
||||
Assert.assertEquals(Region.Location.OUTSIDE, arc.checkPoint(1.2, 1.0));
|
||||
Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(1.2, 1.2));
|
||||
Assert.assertEquals(Region.Location.OUTSIDE, arc.checkPoint(6.5, 0.7));
|
||||
Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(6.5, 0.9));
|
||||
Assert.assertEquals(Region.Location.INSIDE, arc.checkPoint(3.0, 0.6));
|
||||
Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(3.0, 0.8));
|
||||
Assert.assertEquals(Region.Location.OUTSIDE, new Arc(2.3, 5.7, 1.0).checkPoint(1.2));
|
||||
Assert.assertEquals(Region.Location.BOUNDARY, new Arc(2.3, 5.7, 1.2).checkPoint(1.2));
|
||||
Assert.assertEquals(Region.Location.OUTSIDE, new Arc(2.3, 5.7, 0.7).checkPoint(6.5));
|
||||
Assert.assertEquals(Region.Location.BOUNDARY, new Arc(2.3, 5.7, 0.9).checkPoint(6.5));
|
||||
Assert.assertEquals(Region.Location.INSIDE, new Arc(2.3, 5.7, 0.6).checkPoint(3.0));
|
||||
Assert.assertEquals(Region.Location.BOUNDARY, new Arc(2.3, 5.7, 0.8).checkPoint(3.0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFullCircle() {
|
||||
Arc arc = new Arc(9.0, 9.0);
|
||||
Arc arc = new Arc(9.0, 9.0, 1.0e-10);
|
||||
// no boundaries on a full circle
|
||||
Assert.assertEquals(Region.Location.INSIDE, arc.checkPoint(9.0, 1.0e-10));
|
||||
Assert.assertEquals(9.0, arc.getInf(), 1.0e-10);
|
||||
Assert.assertEquals(9.0 + 2.0 * FastMath.PI, arc.getSup(), 1.0e-10);
|
||||
Assert.assertEquals(Region.Location.INSIDE, arc.checkPoint(9.0));
|
||||
Assert.assertEquals(.0, arc.getInf(), 1.0e-10);
|
||||
Assert.assertEquals(MathUtils.TWO_PI, arc.getSup(), 1.0e-10);
|
||||
Assert.assertEquals(2.0 * FastMath.PI, arc.getSize(), 1.0e-10);
|
||||
for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) {
|
||||
Assert.assertEquals(Region.Location.INSIDE,
|
||||
arc.checkPoint(alpha, 1.0e-10));
|
||||
Assert.assertEquals(Region.Location.INSIDE, arc.checkPoint(alpha));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSmall() {
|
||||
Arc arc = new Arc(1.0, FastMath.nextAfter(1.0, Double.POSITIVE_INFINITY));
|
||||
Arc arc = new Arc(1.0, FastMath.nextAfter(1.0, Double.POSITIVE_INFINITY), Precision.EPSILON);
|
||||
Assert.assertEquals(2 * Precision.EPSILON, arc.getSize(), Precision.SAFE_MIN);
|
||||
Assert.assertEquals(1.0, arc.getBarycenter(), Precision.EPSILON);
|
||||
}
|
||||
|
|
|
@ -16,11 +16,14 @@
|
|||
*/
|
||||
package org.apache.commons.math3.geometry.spherical.oned;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.math3.exception.NumberIsTooLargeException;
|
||||
import org.apache.commons.math3.geometry.partitioning.Region;
|
||||
import org.apache.commons.math3.geometry.partitioning.Region.Location;
|
||||
import org.apache.commons.math3.geometry.partitioning.RegionFactory;
|
||||
import org.apache.commons.math3.geometry.partitioning.SubHyperplane;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
import org.apache.commons.math3.util.MathUtils;
|
||||
import org.apache.commons.math3.util.Precision;
|
||||
|
@ -33,7 +36,7 @@ public class ArcsSetTest {
|
|||
public void testArc() {
|
||||
ArcsSet set = new ArcsSet(2.3, 5.7, 1.0e-10);
|
||||
Assert.assertEquals(3.4, set.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(4.0, ((S1Point) set.getBarycenter()).getAlpha(), 1.0e-10);
|
||||
Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
|
||||
Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(2.3)));
|
||||
Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(5.7)));
|
||||
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new S1Point(1.2)));
|
||||
|
@ -43,13 +46,43 @@ public class ArcsSetTest {
|
|||
Assert.assertEquals(1, set.asList().size());
|
||||
Assert.assertEquals(2.3, set.asList().get(0).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(5.7, set.asList().get(0).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(4.0, ((S1Point) set.getBarycenter()).getAlpha(), 1.0e-10);
|
||||
Assert.assertEquals(3.4, set.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(2.3, set.getSmallestLimit().getLocation().getAlpha(), 1.0e-10);
|
||||
Assert.assertFalse(set.getSmallestLimit().isDirect());
|
||||
Assert.assertEquals(5.7, set.getLargestLimit().getLocation().getAlpha(), 1.0e-10);
|
||||
Assert.assertTrue(set.getLargestLimit().isDirect());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFullCircle() {
|
||||
ArcsSet set = new ArcsSet(9.0, 9.0, 1.0e-10);
|
||||
public void testWrapAround2PiArc() {
|
||||
ArcsSet set = new ArcsSet(5.7 - MathUtils.TWO_PI, 2.3, 1.0e-10);
|
||||
Assert.assertEquals(MathUtils.TWO_PI - 3.4, set.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
|
||||
Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(2.3)));
|
||||
Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(5.7)));
|
||||
Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(1.2)));
|
||||
Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(8.5)));
|
||||
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new S1Point(8.7)));
|
||||
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new S1Point(3.0)));
|
||||
Assert.assertEquals(1, set.asList().size());
|
||||
Assert.assertEquals(5.7, set.asList().get(0).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(2.3 + MathUtils.TWO_PI, set.asList().get(0).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(2.3, set.getSmallestLimit().getLocation().getAlpha(), 1.0e-10);
|
||||
Assert.assertTrue(set.getSmallestLimit().isDirect());
|
||||
Assert.assertEquals(5.7, set.getLargestLimit().getLocation().getAlpha(), 1.0e-10);
|
||||
Assert.assertFalse(set.getLargestLimit().isDirect());
|
||||
}
|
||||
|
||||
@Test(expected=NumberIsTooLargeException.class)
|
||||
public void testWrongInterval() {
|
||||
new ArcsSet(1.2, 0.0, 1.0e-10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFullEqualEndPoints() {
|
||||
ArcsSet set = new ArcsSet(1.0, 1.0, 1.0e-10);
|
||||
Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
|
||||
Assert.assertNull(set.getSmallestLimit());
|
||||
Assert.assertNull(set.getLargestLimit());
|
||||
Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(9.0)));
|
||||
for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) {
|
||||
Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(alpha)));
|
||||
|
@ -60,6 +93,60 @@ public class ArcsSetTest {
|
|||
Assert.assertEquals(2 * FastMath.PI, set.getSize(), 1.0e-10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFullCircle() {
|
||||
ArcsSet set = new ArcsSet(1.0e-10);
|
||||
Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
|
||||
Assert.assertNull(set.getSmallestLimit());
|
||||
Assert.assertNull(set.getLargestLimit());
|
||||
Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(9.0)));
|
||||
for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) {
|
||||
Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(alpha)));
|
||||
}
|
||||
Assert.assertEquals(1, set.asList().size());
|
||||
Assert.assertEquals(0.0, set.asList().get(0).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(2 * FastMath.PI, set.asList().get(0).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(2 * FastMath.PI, set.getSize(), 1.0e-10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
ArcsSet empty = (ArcsSet) new RegionFactory<Sphere1D>().getComplement(new ArcsSet(1.0e-10));
|
||||
Assert.assertEquals(1.0e-10, empty.getTolerance(), 1.0e-20);
|
||||
Assert.assertEquals(0.0, empty.getSize(), 1.0e-10);
|
||||
Assert.assertTrue(empty.asList().isEmpty());
|
||||
Assert.assertNull(empty.getSmallestLimit());
|
||||
Assert.assertNull(empty.getLargestLimit());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTiny() {
|
||||
ArcsSet tiny = new ArcsSet(0.0, Precision.SAFE_MIN / 2, 1.0e-10);
|
||||
Assert.assertEquals(1.0e-10, tiny.getTolerance(), 1.0e-20);
|
||||
Assert.assertEquals(Precision.SAFE_MIN / 2, tiny.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(1, tiny.asList().size());
|
||||
Assert.assertEquals(0.0, tiny.asList().get(0).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(Precision.SAFE_MIN / 2, tiny.asList().get(0).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(0.0, tiny.getSmallestLimit().getLocation().getAlpha(), 1.0e-10);
|
||||
Assert.assertEquals(Precision.SAFE_MIN / 2, tiny.getLargestLimit().getLocation().getAlpha(), 1.0e-10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpecialConstruction() {
|
||||
List<SubHyperplane<Sphere1D>> boundary = new ArrayList<SubHyperplane<Sphere1D>>();
|
||||
boundary.add(new LimitAngle(new S1Point(0.0), false, 1.0e-10).wholeHyperplane());
|
||||
boundary.add(new LimitAngle(new S1Point(MathUtils.TWO_PI), true, 1.0e-10).wholeHyperplane());
|
||||
ArcsSet set = new ArcsSet(boundary, 1.0e-10);
|
||||
Assert.assertEquals(MathUtils.TWO_PI, set.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
|
||||
Assert.assertEquals(1, set.asList().size());
|
||||
Assert.assertEquals(0.0, set.asList().get(0).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(MathUtils.TWO_PI, set.asList().get(0).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(0.0, set.getSmallestLimit().getLocation().getAlpha(), 1.0e-10);
|
||||
Assert.assertFalse(set.getSmallestLimit().isDirect());
|
||||
Assert.assertEquals(0.0, set.getLargestLimit().getLocation().getAlpha(), 1.0e-10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifference() {
|
||||
|
||||
|
@ -139,9 +226,11 @@ public class ArcsSetTest {
|
|||
}
|
||||
|
||||
List<Arc> aMbList = aMb.asList();
|
||||
Assert.assertEquals(1, aMbList.size());
|
||||
Assert.assertEquals(2, aMbList.size());
|
||||
Assert.assertEquals(1.0, aMbList.get(0).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(3.0, aMbList.get(0).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(5.0, aMbList.get(1).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(5.5, aMbList.get(1).getSup(), 1.0e-10);
|
||||
|
||||
|
||||
}
|
||||
|
@ -155,7 +244,6 @@ public class ArcsSetTest {
|
|||
new ArcsSet(0.5, 2.0, 1.0e-10)),
|
||||
new ArcsSet(0.0, 5.5, 1.0e-10));
|
||||
Assert.assertEquals(3.0, set.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(7.0 / 3.0, ((S1Point) set.getBarycenter()).getAlpha(), 1.0e-10);
|
||||
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new S1Point(0.0)));
|
||||
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new S1Point(4.0)));
|
||||
Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new S1Point(6.0)));
|
||||
|
@ -179,7 +267,6 @@ public class ArcsSetTest {
|
|||
public void testSinglePoint() {
|
||||
ArcsSet set = new ArcsSet(1.0, FastMath.nextAfter(1.0, Double.POSITIVE_INFINITY), 1.0e-10);
|
||||
Assert.assertEquals(2 * Precision.EPSILON, set.getSize(), Precision.SAFE_MIN);
|
||||
Assert.assertEquals(1.0, ((S1Point) set.getBarycenter()).getAlpha(), Precision.EPSILON);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* 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.math3.geometry.spherical.oned;
|
||||
|
||||
import org.apache.commons.math3.util.MathUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ChordTest {
|
||||
|
||||
@Test
|
||||
public void testChord() {
|
||||
Chord chord = new Chord(2.3, 5.7, 1.0e-10);
|
||||
Assert.assertEquals(2.3, chord.copySelf().getStart(), 1.0e-10);
|
||||
Assert.assertEquals(5.7, chord.copySelf().getEnd(), 1.0e-10);
|
||||
Assert.assertEquals(1.0e-10, chord.copySelf().getTolerance(), 1.0e-20);
|
||||
Assert.assertEquals(3.4, chord.wholeHyperplane().getSize(), 1.0e-10);
|
||||
checkOutside(chord, 2.25);
|
||||
checkBoundary(chord, 2.3);
|
||||
checkInside(chord, 2.35);
|
||||
checkInside(chord, 5.65);
|
||||
checkBoundary(chord, 5.7);
|
||||
checkOutside(chord, 5.75);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReverse() {
|
||||
Chord chord = new Chord(2.3, 5.7, 1.0e-10);
|
||||
Chord reversed = chord.getReverse();
|
||||
Assert.assertEquals(chord.getEnd(), reversed.getStart(), 1.0e-10);
|
||||
Assert.assertEquals(chord.getStart() + MathUtils.TWO_PI, reversed.getEnd(), 1.0e-10);
|
||||
Assert.assertEquals(1.0e-10, reversed.getTolerance(), 1.0e-20);
|
||||
Assert.assertEquals(MathUtils.TWO_PI - 3.4, reversed.wholeHyperplane().getSize(), 1.0e-10);
|
||||
Assert.assertFalse(chord.sameOrientationAs(reversed));
|
||||
checkInside(reversed, 2.25);
|
||||
checkBoundary(reversed, 2.3);
|
||||
checkOutside(reversed, 2.35);
|
||||
checkOutside(reversed, 5.65);
|
||||
checkBoundary(reversed, 5.7);
|
||||
checkInside(reversed, 5.75);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWholeHyperplane() {
|
||||
Chord chord = new Chord(2.3, 5.7, 1.0e-10);
|
||||
SubChord subChord = chord.wholeHyperplane();
|
||||
Assert.assertTrue(chord == subChord.getHyperplane());
|
||||
Assert.assertEquals(chord.getEnd() - chord.getStart(), subChord.getSize(), 1.0e-10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWholeSpace() {
|
||||
Chord chord = new Chord(2.3, 5.7, 1.0e-10);
|
||||
ArcsSet set = chord.wholeSpace();
|
||||
Assert.assertEquals(1, set.asList().size());
|
||||
Assert.assertEquals(0.0, set.asList().get(0).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(MathUtils.TWO_PI, set.asList().get(0).getSup(), 1.0e-10);
|
||||
}
|
||||
|
||||
private void checkInside(Chord chord, double alpha) {
|
||||
for (int i = -2; i < 3; ++i) {
|
||||
Assert.assertTrue(chord.getOffset(new S1Point(alpha + i * MathUtils.TWO_PI)) < 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkOutside(Chord chord, double alpha) {
|
||||
for (int i = -2; i < 3; ++i) {
|
||||
Assert.assertTrue(chord.getOffset(new S1Point(alpha + i * MathUtils.TWO_PI)) > 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkBoundary(Chord chord, double alpha) {
|
||||
for (int i = -2; i < 3; ++i) {
|
||||
Assert.assertEquals(0.0, chord.getOffset(new S1Point(alpha + i * MathUtils.TWO_PI)), chord.getTolerance());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,279 +0,0 @@
|
|||
/*
|
||||
* 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.math3.geometry.spherical.oned;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.math3.geometry.partitioning.Side;
|
||||
import org.apache.commons.math3.geometry.partitioning.SubHyperplane.SplitSubHyperplane;
|
||||
import org.apache.commons.math3.util.MathUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SubChordTest {
|
||||
|
||||
@Test
|
||||
public void testSubChord() {
|
||||
|
||||
SubChord subChord = new SubChord(new Chord(2.3, 5.7, 1.0e-10));
|
||||
Assert.assertEquals(3.4, subChord.getSize(), 1.0e-10);
|
||||
Assert.assertFalse(subChord.isEmpty());
|
||||
|
||||
Assert.assertEquals(1, subChord.getNbSubArcs());
|
||||
Assert.assertEquals(2.3, subChord.getStart(0), 1.0e-10);
|
||||
Assert.assertEquals(5.7, subChord.getEnd(0), 1.0e-10);
|
||||
Assert.assertEquals(1, subChord.getSubArcs().size());
|
||||
Assert.assertEquals(2.3, subChord.getSubArcs().get(0).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(5.7, subChord.getSubArcs().get(0).getSup(), 1.0e-10);
|
||||
|
||||
// despite a deep copy is used, chord being immutable its copy returns the same instance
|
||||
Assert.assertTrue(subChord.getHyperplane() == subChord.copySelf().getHyperplane());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSideEmbedded() {
|
||||
|
||||
SubChord s35 = new SubChord(new Chord(3.0, 5.0, 1.0e-10));
|
||||
SubChord s16 = new SubChord(new Chord(1.0, 6.0, 1.0e-10));
|
||||
|
||||
Assert.assertEquals(Side.BOTH, s16.side(s35.getHyperplane()));
|
||||
Assert.assertEquals(Side.BOTH, s16.side(s35.getHyperplane().getReverse()));
|
||||
Assert.assertEquals(Side.MINUS, s35.side(s16.getHyperplane()));
|
||||
Assert.assertEquals(Side.PLUS, s35.side(s16.getHyperplane().getReverse()));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSideOverlapping() {
|
||||
SubChord s35 = new SubChord(new Chord(3.0, 5.0, 1.0e-10));
|
||||
SubChord s46 = new SubChord(new Chord(4.0, 6.0, 1.0e-10));
|
||||
|
||||
Assert.assertEquals(Side.BOTH, s46.side(s35.getHyperplane()));
|
||||
Assert.assertEquals(Side.BOTH, s46.side(s35.getHyperplane().getReverse()));
|
||||
Assert.assertEquals(Side.BOTH, s35.side(s46.getHyperplane()));
|
||||
Assert.assertEquals(Side.BOTH, s35.side(s46.getHyperplane().getReverse()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSideHyper() {
|
||||
Chord zeroLength = new Chord(2.0, 2.0, 1.0e-10);
|
||||
SubChord sub = new SubChord(zeroLength);
|
||||
Assert.assertTrue(sub.isEmpty());
|
||||
Assert.assertEquals(Side.HYPER, sub.side(zeroLength));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitEmbedded() {
|
||||
|
||||
SubChord s35 = new SubChord(new Chord(3.0, 5.0, 1.0e-10));
|
||||
SubChord s16 = new SubChord(new Chord(1.0, 6.0, 1.0e-10));
|
||||
|
||||
SplitSubHyperplane<Sphere1D> split1 = s16.split(s35.getHyperplane());
|
||||
SubChord split1Plus = (SubChord) split1.getPlus();
|
||||
SubChord split1Minus = (SubChord) split1.getMinus();
|
||||
Assert.assertEquals(3.0, split1Plus.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(2, split1Plus.getNbSubArcs());
|
||||
Assert.assertEquals(1.0, split1Plus.getStart(0), 1.0e-10);
|
||||
Assert.assertEquals(3.0, split1Plus.getEnd(0), 1.0e-10);
|
||||
Assert.assertEquals(5.0, split1Plus.getStart(1), 1.0e-10);
|
||||
Assert.assertEquals(6.0, split1Plus.getEnd(1), 1.0e-10);
|
||||
Assert.assertEquals(2.0, split1Minus.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(1, split1Minus.getNbSubArcs());
|
||||
Assert.assertEquals(3.0, split1Minus.getStart(0), 1.0e-10);
|
||||
Assert.assertEquals(5.0, split1Minus.getEnd(0), 1.0e-10);
|
||||
|
||||
SplitSubHyperplane<Sphere1D> split2 = s16.split(s35.getHyperplane().getReverse());
|
||||
SubChord split2Plus = (SubChord) split2.getPlus();
|
||||
SubChord split2Minus = (SubChord) split2.getMinus();
|
||||
Assert.assertEquals(2.0, split2Plus.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(1, split2Plus.getNbSubArcs());
|
||||
Assert.assertEquals(3.0, split2Plus.getStart(0), 1.0e-10);
|
||||
Assert.assertEquals(5.0, split2Plus.getEnd(0), 1.0e-10);
|
||||
Assert.assertEquals(3.0, split2Minus.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(2, split2Minus.getNbSubArcs());
|
||||
Assert.assertEquals(1.0, split2Minus.getStart(0), 1.0e-10);
|
||||
Assert.assertEquals(3.0, split2Minus.getEnd(0), 1.0e-10);
|
||||
Assert.assertEquals(5.0, split2Minus.getStart(1), 1.0e-10);
|
||||
Assert.assertEquals(6.0, split2Minus.getEnd(1), 1.0e-10);
|
||||
|
||||
SplitSubHyperplane<Sphere1D> split3 = s35.split(s16.getHyperplane());
|
||||
SubChord split3Plus = (SubChord) split3.getPlus();
|
||||
SubChord split3Minus = (SubChord) split3.getMinus();
|
||||
Assert.assertNull(split3Plus);
|
||||
Assert.assertEquals(2.0, split3Minus.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(1, split3Minus.getNbSubArcs());
|
||||
Assert.assertEquals(3.0, split3Minus.getStart(0), 1.0e-10);
|
||||
Assert.assertEquals(5.0, split3Minus.getEnd(0), 1.0e-10);
|
||||
|
||||
SplitSubHyperplane<Sphere1D> split4 = s35.split(s16.getHyperplane().getReverse());
|
||||
SubChord split4Plus = (SubChord) split4.getPlus();
|
||||
SubChord split4Minus = (SubChord) split4.getMinus();
|
||||
Assert.assertEquals(2.0, split4Plus.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(1, split4Plus.getNbSubArcs());
|
||||
Assert.assertEquals(3.0, split4Plus.getStart(0), 1.0e-10);
|
||||
Assert.assertEquals(5.0, split4Plus.getEnd(0), 1.0e-10);
|
||||
Assert.assertNull(split4Minus);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitOverlapping() {
|
||||
|
||||
SubChord s35 = new SubChord(new Chord(3.0, 5.0, 1.0e-10));
|
||||
SubChord s46 = new SubChord(new Chord(4.0, 6.0, 1.0e-10));
|
||||
|
||||
SplitSubHyperplane<Sphere1D> split1 = s46.split(s35.getHyperplane());
|
||||
SubChord split1Plus = (SubChord) split1.getPlus();
|
||||
SubChord split1Minus = (SubChord) split1.getMinus();
|
||||
Assert.assertEquals(1.0, split1Plus.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(1, split1Plus.getNbSubArcs());
|
||||
Assert.assertEquals(5.0, split1Plus.getStart(0), 1.0e-10);
|
||||
Assert.assertEquals(6.0, split1Plus.getEnd(0), 1.0e-10);
|
||||
Assert.assertEquals(1.0, split1Minus.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(1, split1Minus.getNbSubArcs());
|
||||
Assert.assertEquals(4.0, split1Minus.getStart(0), 1.0e-10);
|
||||
Assert.assertEquals(5.0, split1Minus.getEnd(0), 1.0e-10);
|
||||
|
||||
SplitSubHyperplane<Sphere1D> split2 = s46.split(s35.getHyperplane().getReverse());
|
||||
SubChord split2Plus = (SubChord) split2.getPlus();
|
||||
SubChord split2Minus = (SubChord) split2.getMinus();
|
||||
Assert.assertEquals(1.0, split2Plus.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(1, split2Plus.getNbSubArcs());
|
||||
Assert.assertEquals(4.0, split2Plus.getStart(0), 1.0e-10);
|
||||
Assert.assertEquals(5.0, split2Plus.getEnd(0), 1.0e-10);
|
||||
Assert.assertEquals(1.0, split2Minus.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(1, split2Minus.getNbSubArcs());
|
||||
Assert.assertEquals(5.0, split2Minus.getStart(0), 1.0e-10);
|
||||
Assert.assertEquals(6.0, split2Minus.getEnd(0), 1.0e-10);
|
||||
|
||||
SplitSubHyperplane<Sphere1D> split3 = s35.split(s46.getHyperplane());
|
||||
SubChord split3Plus = (SubChord) split3.getPlus();
|
||||
SubChord split3Minus = (SubChord) split3.getMinus();
|
||||
Assert.assertEquals(1.0, split3Plus.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(1, split3Plus.getNbSubArcs());
|
||||
Assert.assertEquals(3.0, split3Plus.getStart(0), 1.0e-10);
|
||||
Assert.assertEquals(4.0, split3Plus.getEnd(0), 1.0e-10);
|
||||
Assert.assertEquals(1.0, split3Minus.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(1, split3Minus.getNbSubArcs());
|
||||
Assert.assertEquals(4.0, split3Minus.getStart(0), 1.0e-10);
|
||||
Assert.assertEquals(5.0, split3Minus.getEnd(0), 1.0e-10);
|
||||
|
||||
SplitSubHyperplane<Sphere1D> split4 = s35.split(s46.getHyperplane().getReverse());
|
||||
SubChord split4Plus = (SubChord) split4.getPlus();
|
||||
SubChord split4Minus = (SubChord) split4.getMinus();
|
||||
Assert.assertEquals(1.0, split4Plus.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(1, split4Plus.getNbSubArcs());
|
||||
Assert.assertEquals(4.0, split4Plus.getStart(0), 1.0e-10);
|
||||
Assert.assertEquals(5.0, split4Plus.getEnd(0), 1.0e-10);
|
||||
Assert.assertEquals(1.0, split4Minus.getSize(), 1.0e-10);
|
||||
Assert.assertEquals(1, split4Minus.getNbSubArcs());
|
||||
Assert.assertEquals(3.0, split4Minus.getStart(0), 1.0e-10);
|
||||
Assert.assertEquals(4.0, split4Minus.getEnd(0), 1.0e-10);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReunite() {
|
||||
|
||||
// build sub-chord with arcs: [0.5, 1.375], [1.5, 1.75], [2.25, 4.5]
|
||||
SubChord sA1 = new SubChord(new Chord(0.5, 4.5, 1.0e-10));
|
||||
SubChord sA2 = (SubChord) sA1.split(new Chord(1.375, 1.5, 1.0e-10)).getPlus();
|
||||
SubChord sA = (SubChord) sA2.split(new Chord(1.75, 2.25, 1.0e-10)).getPlus();
|
||||
List<Arc> listSa = sA.getSubArcs();
|
||||
Assert.assertEquals(3, listSa.size());
|
||||
Assert.assertEquals(0.5, listSa.get(0).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(1.375, listSa.get(0).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(1.5, listSa.get(1).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(1.75, listSa.get(1).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(2.25, listSa.get(2).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(4.5, listSa.get(2).getSup(), 1.0e-10);
|
||||
|
||||
// sub-chord with arcs: [5.0, 5.5], [5.75, 1.0+2pi], [ 1.625+2pi, 1.875+2pi], [2.0+2pi, 2.125+2pi], [2.5+2pi, 3.5+2pi]
|
||||
SubChord sB1 = new SubChord(new Chord(5.0, 3.5 + MathUtils.TWO_PI, 1.0e-10));
|
||||
SubChord sB2 = (SubChord) sB1.split(new Chord(5.5, 5.75, 1.0e-10)).getPlus();
|
||||
SubChord sB3 = (SubChord) sB2.split(new Chord(1.0 + MathUtils.TWO_PI, 1.625 + MathUtils.TWO_PI, 1.0e-10)).getPlus();
|
||||
SubChord sB4 = (SubChord) sB3.split(new Chord(1.875 + MathUtils.TWO_PI, 2.0 + MathUtils.TWO_PI, 1.0e-10)).getPlus();
|
||||
SubChord sB = (SubChord) sB4.split(new Chord(2.125 + MathUtils.TWO_PI, 2.5 + MathUtils.TWO_PI, 1.0e-10)).getPlus();
|
||||
List<Arc> listSb = sB.getSubArcs();
|
||||
Assert.assertEquals(5, listSb.size());
|
||||
Assert.assertEquals(5.0, listSb.get(0).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(5.5, listSb.get(0).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(5.75, listSb.get(1).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(1.0 + MathUtils.TWO_PI, listSb.get(1).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(1.625 + MathUtils.TWO_PI, listSb.get(2).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(1.875 + MathUtils.TWO_PI, listSb.get(2).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(2.0 + MathUtils.TWO_PI, listSb.get(3).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(2.125 + MathUtils.TWO_PI, listSb.get(3).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(2.5 + MathUtils.TWO_PI, listSb.get(4).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(3.5 + MathUtils.TWO_PI, listSb.get(4).getSup(), 1.0e-10);
|
||||
|
||||
List<Arc> listAB = sA.reunite(sB).getSubArcs();
|
||||
Assert.assertEquals(5, listAB.size());
|
||||
Assert.assertEquals(5.75 - MathUtils.TWO_PI, listAB.get(0).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(1.375, listAB.get(0).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(1.5, listAB.get(1).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(1.875, listAB.get(1).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(2.0, listAB.get(2).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(2.125, listAB.get(2).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(2.25, listAB.get(3).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(4.5, listAB.get(3).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(5.0, listAB.get(4).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(5.5, listAB.get(4).getSup(), 1.0e-10);
|
||||
|
||||
List<Arc> listBA = sB.reunite(sA).getSubArcs();
|
||||
Assert.assertEquals(5, listBA.size());
|
||||
Assert.assertEquals(5.0, listBA.get(0).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(5.5, listBA.get(0).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(5.75, listBA.get(1).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(1.375 + MathUtils.TWO_PI, listBA.get(1).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(1.5 + MathUtils.TWO_PI, listBA.get(2).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(1.875 + MathUtils.TWO_PI, listBA.get(2).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(2.0 + MathUtils.TWO_PI, listBA.get(3).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(2.125 + MathUtils.TWO_PI, listBA.get(3).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(2.25 + MathUtils.TWO_PI, listBA.get(4).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(4.5 + MathUtils.TWO_PI, listBA.get(4).getSup(), 1.0e-10);
|
||||
|
||||
// special cases
|
||||
List<Arc> listAEmpty = sA.reunite(new SubChord(new Chord(0, 0, 1.0e-10))).getSubArcs();
|
||||
Assert.assertEquals(3, listAEmpty.size());
|
||||
Assert.assertEquals(0.5, listAEmpty.get(0).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(1.375, listAEmpty.get(0).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(1.5, listAEmpty.get(1).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(1.75, listAEmpty.get(1).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(2.25, listAEmpty.get(2).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(4.5, listAEmpty.get(2).getSup(), 1.0e-10);
|
||||
|
||||
List<Arc> listEmptyA = new SubChord(new Chord(0, 0, 1.0e-10)).reunite(sA).getSubArcs();
|
||||
Assert.assertEquals(3, listAEmpty.size());
|
||||
Assert.assertEquals(0.5, listEmptyA.get(0).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(1.375, listEmptyA.get(0).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(1.5, listEmptyA.get(1).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(1.75, listEmptyA.get(1).getSup(), 1.0e-10);
|
||||
Assert.assertEquals(2.25, listEmptyA.get(2).getInf(), 1.0e-10);
|
||||
Assert.assertEquals(4.5, listEmptyA.get(2).getSup(), 1.0e-10);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReuniteFullCircle() {
|
||||
SubChord s1 = new SubChord(new Chord(0, 4, 1.0e-10));
|
||||
SubChord s2 = new SubChord(new Chord(3, 7, 1.0e-10));
|
||||
Assert.assertEquals(MathUtils.TWO_PI, s1.reunite(s2).getSize(), 1.0e-10);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue