diff --git a/src/main/java/org/apache/commons/math3/geometry/partitioning/AbstractRegion.java b/src/main/java/org/apache/commons/math3/geometry/partitioning/AbstractRegion.java index 4454c3005..ed02f6b65 100644 --- a/src/main/java/org/apache/commons/math3/geometry/partitioning/AbstractRegion.java +++ b/src/main/java/org/apache/commons/math3/geometry/partitioning/AbstractRegion.java @@ -394,7 +394,7 @@ public abstract class AbstractRegion implement *

The filtering consist in splitting the specified * sub-hyperplane into several parts lying in inside and outside * cells of the tree. The principle is to call this method twice for - * each cut sub-hyperplane in the tree, once one the plus node and + * each cut sub-hyperplane in the tree, once on the plus node and * once on the minus node. The parts that have the same flag * (inside/inside or outside/outside) do not belong to the boundary * while parts that have different flags (inside/outside or 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 b36048d93..923d5a786 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 @@ -667,10 +667,8 @@ public class ArcsSet extends AbstractRegion implements Itera final BSPTree minus = new BSPTree(); minus.setAttribute(Boolean.FALSE); - boolean minusIgnored = false; final BSPTree plus = new BSPTree(); plus.setAttribute(Boolean.FALSE); - boolean plusIgnored = false; final double reference = FastMath.PI + arc.getInf(); final double arcLength = arc.getSup() - arc.getInf(); @@ -681,146 +679,90 @@ public class ArcsSet extends AbstractRegion implements Itera final double syncedEnd = a[1] - arcOffset; if (syncedStart < arcLength) { // the start point a[0] is in the minus part of the arc - minusIgnored = addArcStart(minus, a[0], minusIgnored); + addArcLimit(minus, a[0], true); if (syncedEnd > arcLength) { // the end point a[1] is past the end of the arc // so we leave the minus part and enter the plus part final double minusToPlus = arcLength + arcOffset; - minusIgnored = addArcEnd(minus, minusToPlus, minusIgnored); - plusIgnored = addArcStart(plus, minusToPlus, plusIgnored); + addArcLimit(minus, minusToPlus, false); + addArcLimit(plus, minusToPlus, true); if (syncedEnd > MathUtils.TWO_PI) { // in fact the end point a[1] goes far enough that we // leave the plus part of the arc and enter the minus part again final double plusToMinus = MathUtils.TWO_PI + arcOffset; - plusIgnored = addArcEnd(plus, plusToMinus, plusIgnored); - minusIgnored = addArcStart(minus, plusToMinus, minusIgnored); - minusIgnored = addArcEnd(minus, a[1], minusIgnored); + addArcLimit(plus, plusToMinus, false); + addArcLimit(minus, plusToMinus, true); + addArcLimit(minus, a[1], false); } else { // the end point a[1] is in the plus part of the arc - plusIgnored = addArcEnd(plus, a[1], plusIgnored); + addArcLimit(plus, a[1], false); } } else { // the end point a[1] is in the minus part of the arc - minusIgnored = addArcEnd(minus, a[1], minusIgnored); + addArcLimit(minus, a[1], false); } } else { // the start point a[0] is in the plus part of the arc - plusIgnored = addArcStart(plus, a[0], plusIgnored); + addArcLimit(plus, a[0], true); if (syncedEnd > MathUtils.TWO_PI) { // the end point a[1] wraps around to the start of the arc // so we leave the plus part and enter the minus part final double plusToMinus = MathUtils.TWO_PI + arcOffset; - plusIgnored = addArcEnd(plus, plusToMinus, plusIgnored); - minusIgnored = addArcStart(minus, plusToMinus, minusIgnored); + addArcLimit(plus, plusToMinus, false); + addArcLimit(minus, plusToMinus, true); if (syncedEnd > MathUtils.TWO_PI + arcLength) { // in fact the end point a[1] goes far enough that we // leave the minus part of the arc and enter the plus part again final double minusToPlus = MathUtils.TWO_PI + arcLength + arcOffset; - minusIgnored = addArcEnd(minus, minusToPlus, minusIgnored); - plusIgnored = addArcStart(plus, minusToPlus, plusIgnored); - plusIgnored = addArcEnd(plus, a[1], plusIgnored); + addArcLimit(minus, minusToPlus, false); + addArcLimit(plus, minusToPlus, true); + addArcLimit(plus, a[1], false); } else { // the end point a[1] is in the minus part of the arc - minusIgnored = addArcEnd(minus, a[1], minusIgnored); + addArcLimit(minus, a[1], false); } } else { // the end point a[1] is in the plus part of the arc - plusIgnored = addArcEnd(plus, a[1], plusIgnored); + addArcLimit(plus, a[1], false); } } } - return new Split(createSplitPart(plus, plusIgnored), createSplitPart(minus, minusIgnored)); + return new Split(createSplitPart(plus), createSplitPart(minus)); } - /** Add an arc start to a BSP tree under construction. - *

- * Note that this method MUST be called in increasing angle order. - *

+ /** Add an arc limit to a BSP tree under construction. * @param tree BSP tree under construction - * @param alpha arc start - * @param ignored if true, some end points have been ignored previously - * @return true if some points have been ignored, taking this arc end into account + * @param alpha arc limit + * @param isStart if true, the limit is the start of an arc */ - private boolean addArcStart(final BSPTree tree, final double alpha, final boolean ignored) { - - final BSPTree last = getLastLeaf(tree); - - if (alpha <= getTolerance()) { - // don't add a spurious cut hyperplane at the start of the circle, - last.setAttribute(Boolean.TRUE); - return true; + private void addArcLimit(final BSPTree tree, final double alpha, final boolean isStart) { + final LimitAngle limit = new LimitAngle(new S1Point(alpha), !isStart, getTolerance()); + final BSPTree node = tree.getCell(limit.getLocation(), getTolerance()); + if (node.getCut() != null) { + // we find again an already added limit, + // this means we have done a full turn around the circle + leafBefore(node).setAttribute(Boolean.valueOf(!isStart)); } else { - last.insertCut(new LimitAngle(new S1Point(alpha), false, getTolerance())); - last.setAttribute(null); - last.getPlus().setAttribute(Boolean.FALSE); - last.getMinus().setAttribute(Boolean.TRUE); - return ignored; + // it's a new node + node.insertCut(limit); + node.setAttribute(null); + node.getPlus().setAttribute(Boolean.FALSE); + node.getMinus().setAttribute(Boolean.TRUE); } - - } - - /** Add an arc end to a BSP tree under construction. - *

- * Note that this method MUST be called in increasing angle order. - *

- * @param tree BSP tree under construction - * @param alpha arc end - * @param ignored if true, some end points have been ignored previously - * @return true if some points have been ignored, taking this arc end into account - */ - private boolean addArcEnd(final BSPTree tree, final double alpha, final boolean ignored) { - - final BSPTree last = getLastLeaf(tree); - - if (alpha >= MathUtils.TWO_PI - getTolerance()) { - - // don't add a spurious cut hyperplane at the end of the circle, - last.setAttribute(Boolean.TRUE); - return true; - - } else { - last.insertCut(new LimitAngle(new S1Point(alpha), true, getTolerance())); - last.setAttribute(null); - last.getPlus().setAttribute(Boolean.FALSE); - last.getMinus().setAttribute(Boolean.TRUE); - return ignored; - } - } /** Create a split part. * @param tree BSP tree containing the limit angles of the split part - * @param ignored if true, some end points have been ignored previously * @return split part (may be null) */ - private ArcsSet createSplitPart(final BSPTree tree, final boolean ignored) { - - if (ignored) { - // ensure consistent state at 0 / 2 \pi crossing - - final BSPTree first = getFirstLeaf(tree); - final boolean firstState = (Boolean) first.getAttribute(); - final BSPTree last = getLastLeaf(tree); - final boolean lastState = (Boolean) last.getAttribute(); - if (firstState ^ lastState) { - // there should be a real boundary at the crossing. Since it is not accurately - // representable due to S1Point normalizing the angles between 0 (included) - // and 2 \pi (excluded), we insert it at the *beginning* of the tree, - // with an angle forced to 0.0 - first.insertCut(new LimitAngle(new S1Point(0.0), true, getTolerance())); - first.getPlus().setAttribute(firstState); - first.getMinus().setAttribute(lastState); - } - } - + private ArcsSet createSplitPart(final BSPTree tree) { if (tree.getCut() == null && !(Boolean) tree.getAttribute()) { return null; } else { return new ArcsSet(tree, getTolerance()); } - } /** Class holding the results of the {@link #split split} method. 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 7af53fbea..300987d08 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 @@ -73,7 +73,7 @@ public class ArcsSetTest { ArcsSet set = new ArcsSet(1.0e-10); Arc arc = new Arc(1.5 * FastMath.PI, 2.5 * FastMath.PI, 1.0e-10); ArcsSet.Split split = set.split(arc); - for (double alpha = 0; alpha <= MathUtils.TWO_PI; alpha += 0.01) { + for (double alpha = 0.0; alpha <= MathUtils.TWO_PI; alpha += 0.01) { S1Point p = new S1Point(alpha); if (alpha < 0.5 * FastMath.PI || alpha > 1.5 * FastMath.PI) { Assert.assertEquals(Location.OUTSIDE, split.getPlus().checkPoint(p)); @@ -445,8 +445,8 @@ public class ArcsSetTest { ArcsSet s16 = new ArcsSet(1.0, 6.0, 1.0e-10); ArcsSet.Split split1 = s16.split(new Arc(3.0, 5.0, 1.0e-10)); - ArcsSet split1Plus = (ArcsSet) split1.getPlus(); - ArcsSet split1Minus = (ArcsSet) split1.getMinus(); + ArcsSet split1Plus = split1.getPlus(); + ArcsSet split1Minus = split1.getMinus(); Assert.assertEquals(3.0, split1Plus.getSize(), 1.0e-10); Assert.assertEquals(2, split1Plus.asList().size()); Assert.assertEquals(1.0, split1Plus.asList().get(0).getInf(), 1.0e-10); @@ -459,8 +459,8 @@ public class ArcsSetTest { Assert.assertEquals(5.0, split1Minus.asList().get(0).getSup(), 1.0e-10); ArcsSet.Split split2 = s16.split(new Arc(5.0, 3.0 + MathUtils.TWO_PI, 1.0e-10)); - ArcsSet split2Plus = (ArcsSet) split2.getPlus(); - ArcsSet split2Minus = (ArcsSet) split2.getMinus(); + ArcsSet split2Plus = split2.getPlus(); + ArcsSet split2Minus = split2.getMinus(); Assert.assertEquals(2.0, split2Plus.getSize(), 1.0e-10); Assert.assertEquals(1, split2Plus.asList().size()); Assert.assertEquals(3.0, split2Plus.asList().get(0).getInf(), 1.0e-10); @@ -473,8 +473,8 @@ public class ArcsSetTest { Assert.assertEquals(6.0, split2Minus.asList().get(1).getSup(), 1.0e-10); ArcsSet.Split split3 = s35.split(new Arc(1.0, 6.0, 1.0e-10)); - ArcsSet split3Plus = (ArcsSet) split3.getPlus(); - ArcsSet split3Minus = (ArcsSet) split3.getMinus(); + ArcsSet split3Plus = split3.getPlus(); + ArcsSet split3Minus = split3.getMinus(); Assert.assertNull(split3Plus); Assert.assertEquals(2.0, split3Minus.getSize(), 1.0e-10); Assert.assertEquals(1, split3Minus.asList().size()); @@ -482,8 +482,8 @@ public class ArcsSetTest { Assert.assertEquals(5.0, split3Minus.asList().get(0).getSup(), 1.0e-10); ArcsSet.Split split4 = s35.split(new Arc(6.0, 1.0 + MathUtils.TWO_PI, 1.0e-10)); - ArcsSet split4Plus = (ArcsSet) split4.getPlus(); - ArcsSet split4Minus = (ArcsSet) split4.getMinus(); + ArcsSet split4Plus = split4.getPlus(); + ArcsSet split4Minus = split4.getMinus(); Assert.assertEquals(2.0, split4Plus.getSize(), 1.0e-10); Assert.assertEquals(1, split4Plus.asList().size()); Assert.assertEquals(3.0, split4Plus.asList().get(0).getInf(), 1.0e-10); @@ -499,8 +499,8 @@ public class ArcsSetTest { ArcsSet s46 = new ArcsSet(4.0, 6.0, 1.0e-10); ArcsSet.Split split1 = s46.split(new Arc(3.0, 5.0, 1.0e-10)); - ArcsSet split1Plus = (ArcsSet) split1.getPlus(); - ArcsSet split1Minus = (ArcsSet) split1.getMinus(); + ArcsSet split1Plus = split1.getPlus(); + ArcsSet split1Minus = split1.getMinus(); Assert.assertEquals(1.0, split1Plus.getSize(), 1.0e-10); Assert.assertEquals(1, split1Plus.asList().size()); Assert.assertEquals(5.0, split1Plus.asList().get(0).getInf(), 1.0e-10); @@ -511,8 +511,8 @@ public class ArcsSetTest { Assert.assertEquals(5.0, split1Minus.asList().get(0).getSup(), 1.0e-10); ArcsSet.Split split2 = s46.split(new Arc(5.0, 3.0 + MathUtils.TWO_PI, 1.0e-10)); - ArcsSet split2Plus = (ArcsSet) split2.getPlus(); - ArcsSet split2Minus = (ArcsSet) split2.getMinus(); + ArcsSet split2Plus = split2.getPlus(); + ArcsSet split2Minus = split2.getMinus(); Assert.assertEquals(1.0, split2Plus.getSize(), 1.0e-10); Assert.assertEquals(1, split2Plus.asList().size()); Assert.assertEquals(4.0, split2Plus.asList().get(0).getInf(), 1.0e-10); @@ -523,8 +523,8 @@ public class ArcsSetTest { Assert.assertEquals(6.0, split2Minus.asList().get(0).getSup(), 1.0e-10); ArcsSet.Split split3 = s35.split(new Arc(4.0, 6.0, 1.0e-10)); - ArcsSet split3Plus = (ArcsSet) split3.getPlus(); - ArcsSet split3Minus = (ArcsSet) split3.getMinus(); + ArcsSet split3Plus = split3.getPlus(); + ArcsSet split3Minus = split3.getMinus(); Assert.assertEquals(1.0, split3Plus.getSize(), 1.0e-10); Assert.assertEquals(1, split3Plus.asList().size()); Assert.assertEquals(3.0, split3Plus.asList().get(0).getInf(), 1.0e-10); @@ -535,8 +535,8 @@ public class ArcsSetTest { Assert.assertEquals(5.0, split3Minus.asList().get(0).getSup(), 1.0e-10); ArcsSet.Split split4 = s35.split(new Arc(6.0, 4.0 + MathUtils.TWO_PI, 1.0e-10)); - ArcsSet split4Plus = (ArcsSet) split4.getPlus(); - ArcsSet split4Minus = (ArcsSet) split4.getMinus(); + ArcsSet split4Plus = split4.getPlus(); + ArcsSet split4Minus = split4.getMinus(); Assert.assertEquals(1.0, split4Plus.getSize(), 1.0e-10); Assert.assertEquals(1, split4Plus.asList().size()); Assert.assertEquals(4.0, split4Plus.asList().get(0).getInf(), 1.0e-10); @@ -547,4 +547,22 @@ public class ArcsSetTest { Assert.assertEquals(4.0, split4Minus.asList().get(0).getSup(), 1.0e-10); } + + @Test + public void testFarSplit() { + ArcsSet set = new ArcsSet(FastMath.PI, 2.5 * FastMath.PI, 1.0e-10); + ArcsSet.Split split = set.split(new Arc(0.5 * FastMath.PI, 1.5 * FastMath.PI, 1.0e-10)); + ArcsSet splitPlus = split.getPlus(); + ArcsSet splitMinus = split.getMinus(); + Assert.assertEquals(1, splitMinus.asList().size()); + Assert.assertEquals(1.0 * FastMath.PI, splitMinus.asList().get(0).getInf(), 1.0e-10); + Assert.assertEquals(1.5 * FastMath.PI, splitMinus.asList().get(0).getSup(), 1.0e-10); + Assert.assertEquals(0.5 * FastMath.PI, splitMinus.getSize(), 1.0e-10); + Assert.assertEquals(1, splitPlus.asList().size()); + Assert.assertEquals(1.5 * FastMath.PI, splitPlus.asList().get(0).getInf(), 1.0e-10); + Assert.assertEquals(2.5 * FastMath.PI, splitPlus.asList().get(0).getSup(), 1.0e-10); + Assert.assertEquals(1.0 * FastMath.PI, splitPlus.getSize(), 1.0e-10); + + } + }