From d83cdb913332b02fd310f5cdf3df045162c4cc54 Mon Sep 17 00:00:00 2001
From: Luc Maisonobe
Date: Wed, 1 Jan 2014 17:30:06 +0000
Subject: [PATCH] Simplified 1-sphere case.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1554654 13f79535-47bb-0310-9956-ffa450edef68
---
.../math3/geometry/spherical/oned/Arc.java | 59 +++-
.../geometry/spherical/oned/ArcsSet.java | 286 +++++++++++++--
.../oned/{Chord.java => LimitAngle.java} | 84 ++---
.../geometry/spherical/oned/S1Point.java | 3 +-
.../geometry/spherical/oned/SubChord.java | 332 ------------------
.../spherical/oned/SubLimitAngle.java | 74 ++++
.../math3/geometry/spherical/twod/Circle.java | 10 +-
.../geometry/spherical/twod/SubCircle.java | 24 +-
.../geometry/spherical/oned/ArcTest.java | 47 +--
.../geometry/spherical/oned/ArcsSetTest.java | 103 +++++-
.../geometry/spherical/oned/ChordTest.java | 92 -----
.../geometry/spherical/oned/SubChordTest.java | 279 ---------------
12 files changed, 535 insertions(+), 858 deletions(-)
rename src/main/java/org/apache/commons/math3/geometry/spherical/oned/{Chord.java => LimitAngle.java} (58%)
delete mode 100644 src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubChord.java
create mode 100644 src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubLimitAngle.java
delete mode 100644 src/test/java/org/apache/commons/math3/geometry/spherical/oned/ChordTest.java
delete mode 100644 src/test/java/org/apache/commons/math3/geometry/spherical/oned/SubChordTest.java
diff --git a/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Arc.java b/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Arc.java
index 24ec0c341..026e0128c 100644
--- a/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Arc.java
+++ b/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Arc.java
@@ -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.
*
- * 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.
*
* @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;
+ 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 {
- this.upper = MathUtils.normalizeAngle(upper, lower + FastMath.PI);
+ throw new NumberIsTooLargeException(LocalizedFormats.ENDPOINTS_NOT_AN_INTERVAL,
+ lower, upper, true);
}
- this.middle = 0.5 * (this.lower + this.upper);
}
/** 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;
diff --git a/src/main/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSet.java b/src/main/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSet.java
index 5678dda89..ae8eaa6e0 100644
--- a/src/main/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSet.java
+++ b/src/main/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSet.java
@@ -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.
+ *
+ * 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.
+ *
* @version $Id$
* @since 3.3
*/
@@ -47,19 +56,19 @@ public class ArcsSet extends AbstractRegion {
/** Build an arcs set corresponding to a single arc.
*
- * 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).
*
* @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 {
}
/** Build an inside/outside tree representing a single arc.
- *
- * 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.
- *
* @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 buildTree(final double lower, final double upper, final double tolerance) {
+ private static BSPTree 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(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(new Chord(lower, normalizedUpper, tolerance).wholeHyperplane(),
- new BSPTree(Boolean.FALSE),
- new BSPTree(Boolean.TRUE),
- null);
+ // 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 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 upperCut =
+ new LimitAngle(new S1Point(normalizedUpper), true, tolerance).wholeHyperplane();
+ return new BSPTree(lowerCut,
+ new BSPTree(Boolean.FALSE),
+ new BSPTree(upperCut,
+ new BSPTree(Boolean.FALSE),
+ new BSPTree(Boolean.TRUE),
+ null),
+ null);
+ } else {
+ // arc wrapping around 2 \pi
+ final SubHyperplane upperCut =
+ new LimitAngle(new S1Point(normalizedUpper - MathUtils.TWO_PI), true, tolerance).wholeHyperplane();
+ return new BSPTree(lowerCut,
+ new BSPTree(upperCut,
+ new BSPTree(Boolean.FALSE),
+ new BSPTree(Boolean.TRUE),
+ null),
+ new BSPTree(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 node = getTree(false);
+ if (node.getCut() == null) {
+ return null;
+ }
+
+ BSPTree 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 node = getTree(false);
+ if (node.getCut() == null) {
+ return null;
+ }
+
+ BSPTree 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 nextNode(BSPTree node) {
+
+ final BSPTree 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 previousNode(BSPTree node) {
+
+ final BSPTree 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 node) {
+ final BSPTree 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 node) {
+ final BSPTree 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 findSmallest(BSPTree node) {
+
+ BSPTree 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 findLargest(BSPTree node) {
+
+ BSPTree 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 {
} 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 {
// 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 {
final LimitsCollector finder = new LimitsCollector();
root.visit(finder);
final List 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 {
// 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 {
/** {@inheritDoc} */
public void visitInternalNode(final BSPTree 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());
}
}
diff --git a/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Chord.java b/src/main/java/org/apache/commons/math3/geometry/spherical/oned/LimitAngle.java
similarity index 58%
rename from src/main/java/org/apache/commons/math3/geometry/spherical/oned/Chord.java
rename to src/main/java/org/apache/commons/math3/geometry/spherical/oned/LimitAngle.java
index dd92ab14a..6c0e7a138 100644
--- a/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Chord.java
+++ b/src/main/java/org/apache/commons/math3/geometry/spherical/oned/LimitAngle.java
@@ -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.
- * An hyperplane on the 1-sphere is a chord that splits
- * the circle in two parts.
+ * An hyperplane on the 1-sphere is an angle with an orientation.
* Instances of this class are guaranteed to be immutable.
* @version $Id$
* @since 3.3
*/
-public class Chord implements Hyperplane {
+public class LimitAngle implements Hyperplane {
- /** 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 {
* the instance.
* @return the instance itself
*/
- public Chord copySelf() {
+ public LimitAngle copySelf() {
return this;
}
/** {@inheritDoc} */
public double getOffset(final Point 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.
- * Get a chord with reversed orientation with respect to the
+ *
Get a limit angle with reversed orientation with respect to the
* instance. A new object is built, the instance is untouched.
- * @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 {
* not be used otherwise.
* @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 {
/** {@inheritDoc} */
public boolean sameOrientationAs(final Hyperplane 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;
diff --git a/src/main/java/org/apache/commons/math3/geometry/spherical/oned/S1Point.java b/src/main/java/org/apache/commons/math3/geometry/spherical/oned/S1Point.java
index e7184d93d..72e612c69 100644
--- a/src/main/java/org/apache/commons/math3/geometry/spherical/oned/S1Point.java
+++ b/src/main/java/org/apache/commons/math3/geometry/spherical/oned/S1Point.java
@@ -49,7 +49,8 @@ public class S1Point implements Point {
* @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.
diff --git a/src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubChord.java b/src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubChord.java
deleted file mode 100644
index 9bede9d48..000000000
--- a/src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubChord.java
+++ /dev/null
@@ -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}.
- * Instances of this class are guaranteed to be immutable.
- * @version $Id$
- * @since 3.3
- */
-public class SubChord implements SubHyperplane {
-
- /** Underlying hyperplane. */
- private final Chord chord;
-
- /** Boundary angles. */
- private final List limits;
-
- /** Simple constructor.
- * @param chord underlying hyperplane
- */
- public SubChord(final Chord chord) {
- this.chord = chord;
- this.limits = new ArrayList();
- 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 limits) {
- this.chord = chord;
- this.limits = new ArrayList(limits);
- }
-
- /** Get the sub-arcs.
- * @return a newly created list with sub-arcs
- */
- public List getSubArcs() {
- final List subArcs = new ArrayList(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 ith sub-arc.
- * @param i index of the desired arc (counting from 0)
- * @return start of the ith sub-arc
- */
- public double getStart(final int i) {
- return limits.get(2 * i);
- }
-
- /** Get the end of the ith sub-arc.
- * @param i index of the desired arc (counting from 0)
- * @return end of the ith 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 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 split(final Hyperplane hyperplane) {
-
- final List minus = new ArrayList(limits.size());
- final List plus = new ArrayList(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(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 other) {
-
- final List otherLimits = ((SubChord) other).limits;
-
- final List merged;
- if (other.isEmpty()) {
- merged = limits;
- } else if (isEmpty()) {
- merged = otherLimits;
- } else {
-
- merged = new ArrayList(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);
-
- }
-
-}
diff --git a/src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubLimitAngle.java b/src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubLimitAngle.java
new file mode 100644
index 000000000..bf3cd43ad
--- /dev/null
+++ b/src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubLimitAngle.java
@@ -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}.
+ * Instances of this class are guaranteed to be immutable.
+ * @version $Id$
+ * @since 3.3
+ */
+public class SubLimitAngle extends AbstractSubHyperplane {
+
+ /** Simple constructor.
+ * @param hyperplane underlying hyperplane
+ * @param remainingRegion remaining region of the hyperplane
+ */
+ public SubLimitAngle(final Hyperplane hyperplane,
+ final Region remainingRegion) {
+ super(hyperplane, remainingRegion);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public double getSize() {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isEmpty() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected AbstractSubHyperplane buildNew(final Hyperplane hyperplane,
+ final Region remainingRegion) {
+ return new SubLimitAngle(hyperplane, remainingRegion);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Side side(final Hyperplane 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 split(final Hyperplane hyperplane) {
+ final double global = hyperplane.getOffset(((LimitAngle) getHyperplane()).getLocation());
+ return (global < -1.0e-10) ?
+ new SplitSubHyperplane(null, this) :
+ new SplitSubHyperplane(this, null);
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/math3/geometry/spherical/twod/Circle.java b/src/main/java/org/apache/commons/math3/geometry/spherical/twod/Circle.java
index 184479aea..5d2355d7a 100644
--- a/src/main/java/org/apache/commons/math3/geometry/spherical/twod/Circle.java
+++ b/src/main/java/org/apache/commons/math3/geometry/spherical/twod/Circle.java
@@ -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, Embedding {
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 {
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(null, this) :
- new SplitSubHyperplane(this, null);
- }
-
- // the circles do intersect
final SubHyperplane subMinus = chord.wholeHyperplane();
final SubHyperplane subPlus = chord.getReverse().wholeHyperplane();
final BSPTree splitTree = getRemainingRegion().getTree(false).split(subMinus);
diff --git a/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcTest.java b/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcTest.java
index 76f7d1ded..b835ea8ad 100644
--- a/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcTest.java
+++ b/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcTest.java
@@ -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);
}
diff --git a/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSetTest.java b/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSetTest.java
index f729853b1..415505819 100644
--- a/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSetTest.java
+++ b/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSetTest.java
@@ -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().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> boundary = new ArrayList>();
+ 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 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);
}
}
diff --git a/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ChordTest.java b/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ChordTest.java
deleted file mode 100644
index 828172424..000000000
--- a/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ChordTest.java
+++ /dev/null
@@ -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());
- }
- }
-
-}
diff --git a/src/test/java/org/apache/commons/math3/geometry/spherical/oned/SubChordTest.java b/src/test/java/org/apache/commons/math3/geometry/spherical/oned/SubChordTest.java
deleted file mode 100644
index e92bcc8cf..000000000
--- a/src/test/java/org/apache/commons/math3/geometry/spherical/oned/SubChordTest.java
+++ /dev/null
@@ -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 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 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 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 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 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 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 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 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 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 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 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 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 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 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);
- }
-
-}