IntervalTest.java
/*
* 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
*
* https://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.geometry.euclidean.oned;
import org.apache.commons.geometry.core.RegionLocation;
import org.apache.commons.geometry.core.partitioning.Split;
import org.apache.commons.geometry.core.partitioning.SplitLocation;
import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
import org.apache.commons.numbers.core.Precision;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class IntervalTest {
private static final double TEST_EPS = 1e-15;
private static final Precision.DoubleEquivalence TEST_PRECISION =
Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
@Test
void testOf_doubles() {
// act/assert
checkInterval(Interval.of(0, 0, TEST_PRECISION), 0, 0);
checkInterval(Interval.of(1, 2, TEST_PRECISION), 1, 2);
checkInterval(Interval.of(2, 1, TEST_PRECISION), 1, 2);
checkInterval(Interval.of(-2, -1, TEST_PRECISION), -2, -1);
checkInterval(Interval.of(-1, -2, TEST_PRECISION), -2, -1);
checkInterval(Interval.of(1, Double.POSITIVE_INFINITY, TEST_PRECISION),
1, Double.POSITIVE_INFINITY);
checkInterval(Interval.of(Double.POSITIVE_INFINITY, 1, TEST_PRECISION),
1, Double.POSITIVE_INFINITY);
checkInterval(Interval.of(Double.NEGATIVE_INFINITY, 1, TEST_PRECISION),
Double.NEGATIVE_INFINITY, 1);
checkInterval(Interval.of(1, Double.NEGATIVE_INFINITY, TEST_PRECISION),
Double.NEGATIVE_INFINITY, 1);
checkInterval(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION),
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
checkInterval(Interval.of(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, TEST_PRECISION),
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
}
@Test
void testOf_doubles_invalidIntervals() {
// act/assert
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(1, Double.NaN, TEST_PRECISION));
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(Double.NaN, 1, TEST_PRECISION));
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(Double.NaN, Double.NaN, TEST_PRECISION));
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION));
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, TEST_PRECISION));
}
@Test
void testOf_points() {
// act/assert
checkInterval(Interval.of(Vector1D.of(1), Vector1D.of(2), TEST_PRECISION), 1, 2);
checkInterval(Interval.of(Vector1D.of(Double.POSITIVE_INFINITY), Vector1D.of(Double.NEGATIVE_INFINITY), TEST_PRECISION),
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
}
@Test
void testOf_points_invalidIntervals() {
// act/assert
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(Vector1D.of(1), Vector1D.of(Double.NaN), TEST_PRECISION));
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(Vector1D.of(Double.POSITIVE_INFINITY), Vector1D.of(Double.POSITIVE_INFINITY), TEST_PRECISION));
}
@Test
void testOf_hyperplanes() {
// act/assert
Assertions.assertSame(Interval.full(), Interval.of(null, null));
checkInterval(Interval.of(
OrientedPoints.fromLocationAndDirection(1, true, TEST_PRECISION),
OrientedPoints.fromLocationAndDirection(1, false, TEST_PRECISION)), 1, 1);
checkInterval(Interval.of(
OrientedPoints.fromLocationAndDirection(1, false, TEST_PRECISION),
OrientedPoints.fromLocationAndDirection(1, true, TEST_PRECISION)), 1, 1);
checkInterval(Interval.of(
OrientedPoints.fromLocationAndDirection(-2, false, TEST_PRECISION),
OrientedPoints.fromLocationAndDirection(5, true, TEST_PRECISION)), -2, 5);
checkInterval(Interval.of(
OrientedPoints.fromLocationAndDirection(5, true, TEST_PRECISION),
OrientedPoints.fromLocationAndDirection(-2, false, TEST_PRECISION)), -2, 5);
checkInterval(Interval.of(
null,
OrientedPoints.fromLocationAndDirection(5, true, TEST_PRECISION)), Double.NEGATIVE_INFINITY, 5);
checkInterval(Interval.of(
OrientedPoints.fromLocationAndDirection(5, true, TEST_PRECISION),
null), Double.NEGATIVE_INFINITY, 5);
checkInterval(Interval.of(
OrientedPoints.fromLocationAndDirection(Double.NEGATIVE_INFINITY, false, TEST_PRECISION),
OrientedPoints.fromLocationAndDirection(5, true, TEST_PRECISION)), Double.NEGATIVE_INFINITY, 5);
checkInterval(Interval.of(
null,
OrientedPoints.fromLocationAndDirection(5, false, TEST_PRECISION)), 5, Double.POSITIVE_INFINITY);
checkInterval(Interval.of(
OrientedPoints.fromLocationAndDirection(5, false, TEST_PRECISION),
null), 5, Double.POSITIVE_INFINITY);
checkInterval(Interval.of(
OrientedPoints.fromLocationAndDirection(Double.POSITIVE_INFINITY, true, TEST_PRECISION),
OrientedPoints.fromLocationAndDirection(5, false, TEST_PRECISION)), 5, Double.POSITIVE_INFINITY);
}
@Test
void testOf_hyperplanes_invalidArgs() {
// act/assert
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(
OrientedPoints.fromLocationAndDirection(1, false, TEST_PRECISION),
OrientedPoints.fromLocationAndDirection(1, false, TEST_PRECISION)));
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(
OrientedPoints.fromLocationAndDirection(2, false, TEST_PRECISION),
OrientedPoints.fromLocationAndDirection(1, true, TEST_PRECISION)));
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(
OrientedPoints.fromLocationAndDirection(Double.POSITIVE_INFINITY, false, TEST_PRECISION),
OrientedPoints.fromLocationAndDirection(Double.POSITIVE_INFINITY, true, TEST_PRECISION)));
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(
OrientedPoints.fromLocationAndDirection(Double.NaN, false, TEST_PRECISION),
OrientedPoints.fromLocationAndDirection(1, true, TEST_PRECISION)));
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(
OrientedPoints.fromLocationAndDirection(1, false, TEST_PRECISION),
OrientedPoints.fromLocationAndDirection(Double.NaN, true, TEST_PRECISION)));
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(
OrientedPoints.fromLocationAndDirection(Double.NaN, false, TEST_PRECISION),
OrientedPoints.fromLocationAndDirection(Double.NaN, true, TEST_PRECISION)));
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(
null,
OrientedPoints.fromLocationAndDirection(Double.NaN, true, TEST_PRECISION)));
}
@Test
void testPoint() {
// act/assert
checkInterval(Interval.point(0, TEST_PRECISION), 0, 0);
checkInterval(Interval.point(1, TEST_PRECISION), 1, 1);
checkInterval(Interval.point(-1, TEST_PRECISION), -1, -1);
}
@Test
void testPoint_invalidArgs() {
// act/assert
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.point(Double.NEGATIVE_INFINITY, TEST_PRECISION));
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.point(Double.POSITIVE_INFINITY, TEST_PRECISION));
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.point(Double.NaN, TEST_PRECISION));
}
@Test
void testMin() {
// act/assert
checkInterval(Interval.min(Double.NEGATIVE_INFINITY, TEST_PRECISION),
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
checkInterval(Interval.min(0, TEST_PRECISION), 0, Double.POSITIVE_INFINITY);
checkInterval(Interval.min(1, TEST_PRECISION), 1, Double.POSITIVE_INFINITY);
checkInterval(Interval.min(-1, TEST_PRECISION), -1, Double.POSITIVE_INFINITY);
}
@Test
void testMin_invalidArgs() {
// act/assert
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.min(Double.POSITIVE_INFINITY, TEST_PRECISION));
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.min(Double.NaN, TEST_PRECISION));
}
@Test
void testMax() {
// act/assert
checkInterval(Interval.max(Double.POSITIVE_INFINITY, TEST_PRECISION),
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
checkInterval(Interval.max(0, TEST_PRECISION), Double.NEGATIVE_INFINITY, 0);
checkInterval(Interval.max(1, TEST_PRECISION), Double.NEGATIVE_INFINITY, 1);
checkInterval(Interval.max(-1, TEST_PRECISION), Double.NEGATIVE_INFINITY, -1);
}
@Test
void testMax_invalidArgs() {
// act/assert
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.max(Double.NEGATIVE_INFINITY, TEST_PRECISION));
Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.max(Double.NaN, TEST_PRECISION));
}
@Test
void testIsInfinite() {
// act/assert
Assertions.assertFalse(Interval.of(1, 2, TEST_PRECISION).isInfinite());
Assertions.assertTrue(Interval.of(Double.NEGATIVE_INFINITY, 2, TEST_PRECISION).isInfinite());
Assertions.assertTrue(Interval.of(2, Double.POSITIVE_INFINITY, TEST_PRECISION).isInfinite());
Assertions.assertTrue(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).isInfinite());
}
@Test
void testIsFinite() {
// act/assert
Assertions.assertTrue(Interval.of(1, 2, TEST_PRECISION).isFinite());
Assertions.assertFalse(Interval.of(Double.NEGATIVE_INFINITY, 2, TEST_PRECISION).isFinite());
Assertions.assertFalse(Interval.of(2, Double.POSITIVE_INFINITY, TEST_PRECISION).isFinite());
Assertions.assertFalse(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).isFinite());
}
@Test
void testClassify_finite() {
// arrange
final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
final Interval interval = Interval.of(-1, 1, precision);
// act/assert
checkClassify(interval, RegionLocation.OUTSIDE,
Double.NEGATIVE_INFINITY, -2, -1.1,
1.1, 2, Double.POSITIVE_INFINITY);
checkClassify(interval, RegionLocation.BOUNDARY,
-1.001, -1, -0.999,
0.999, 1, 1.001);
checkClassify(interval, RegionLocation.INSIDE, -0.9, 0, 0.9);
checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
}
@Test
void testClassify_singlePoint() {
// arrange
final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
final Interval interval = Interval.of(1, 1, precision);
// act/assert
checkClassify(interval, RegionLocation.OUTSIDE,
Double.NEGATIVE_INFINITY, 0, 0.9, 1.1, 2, Double.POSITIVE_INFINITY);
checkClassify(interval, RegionLocation.BOUNDARY,
0.999, 1, 1.0001);
checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
}
@Test
void testClassify_maxInfinite() {
// arrange
final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
final Interval interval = Interval.of(-1, Double.POSITIVE_INFINITY, precision);
// act/assert
checkClassify(interval, RegionLocation.OUTSIDE,
Double.NEGATIVE_INFINITY, -2, -1.1);
checkClassify(interval, RegionLocation.BOUNDARY,
-1.001, -1, -0.999);
checkClassify(interval, RegionLocation.INSIDE,
-0.9, 0, 1.0, Double.POSITIVE_INFINITY);
checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
}
@Test
void testClassify_minInfinite() {
// arrange
final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
final Interval interval = Interval.of(Double.NEGATIVE_INFINITY, 1, precision);
// act/assert
checkClassify(interval, RegionLocation.INSIDE,
Double.NEGATIVE_INFINITY, 0, 0.9);
checkClassify(interval, RegionLocation.BOUNDARY,
0.999, 1, 1.001);
checkClassify(interval, RegionLocation.OUTSIDE,
1.1, 2, Double.POSITIVE_INFINITY);
checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
}
@Test
void testClassify_minMaxInfinite() {
// arrange
final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
final Interval interval = Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, precision);
// act/assert
checkClassify(interval, RegionLocation.INSIDE,
Double.NEGATIVE_INFINITY, -1, 0, 1, Double.POSITIVE_INFINITY);
checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
}
@Test
void testContains_finite() {
// arrange
final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
final Interval interval = Interval.of(-1, 1, precision);
// act/assert
checkContains(interval, true,
-1.001, -1, -0.999,
0.999, 1, 1.001,
-0.9, 0, 0.9);
checkContains(interval, false,
Double.NEGATIVE_INFINITY, -2, -1.1,
1.1, 2, Double.POSITIVE_INFINITY);
checkContains(interval, false, Double.NaN);
}
@Test
void testIsFull() {
// act/assert
Assertions.assertFalse(Interval.of(1, 1, TEST_PRECISION).isFull());
Assertions.assertFalse(Interval.of(-2, 2, TEST_PRECISION).isFull());
Assertions.assertFalse(Interval.of(1, Double.POSITIVE_INFINITY, TEST_PRECISION).isFull());
Assertions.assertFalse(Interval.of(Double.NEGATIVE_INFINITY, 1, TEST_PRECISION).isFull());
Assertions.assertTrue(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).isFull());
}
@Test
void testGetSize() {
// act/assert
Assertions.assertEquals(0, Interval.of(1, 1, TEST_PRECISION).getSize(), TEST_EPS);
Assertions.assertEquals(4, Interval.of(-2, 2, TEST_PRECISION).getSize(), TEST_EPS);
Assertions.assertEquals(5, Interval.of(2, -3, TEST_PRECISION).getSize(), TEST_EPS);
Assertions.assertEquals(Double.POSITIVE_INFINITY,
Interval.of(1, Double.POSITIVE_INFINITY, TEST_PRECISION).getSize(), TEST_EPS);
Assertions.assertEquals(Double.POSITIVE_INFINITY,
Interval.of(Double.NEGATIVE_INFINITY, 1, TEST_PRECISION).getSize(), TEST_EPS);
Assertions.assertEquals(Double.POSITIVE_INFINITY,
Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).getSize(), TEST_EPS);
}
@Test
void testGetBoundarySize() {
// act/assert
Assertions.assertEquals(0, Interval.of(1, 1, TEST_PRECISION).getBoundarySize(), TEST_EPS);
Assertions.assertEquals(0, Interval.of(-2, 5, TEST_PRECISION).getBoundarySize(), TEST_EPS);
Assertions.assertEquals(0, Interval.full().getBoundarySize(), TEST_EPS);
}
@Test
void testGetCentroid() {
// act/assert
EuclideanTestUtils.assertCoordinatesEqual(Vector1D.ZERO,
Interval.of(-1, 1, TEST_PRECISION).getCentroid(), TEST_EPS);
EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(10),
Interval.of(10, 10, TEST_PRECISION).getCentroid(), TEST_EPS);
EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(2),
Interval.of(1, 3, TEST_PRECISION).getCentroid(), TEST_EPS);
EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(-1),
Interval.of(-2, 0, TEST_PRECISION).getCentroid(), TEST_EPS);
Assertions.assertNull(Interval.of(1, Double.POSITIVE_INFINITY, TEST_PRECISION).getCentroid());
Assertions.assertNull(Interval.of(Double.NEGATIVE_INFINITY, 1, TEST_PRECISION).getCentroid());
Assertions.assertNull(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).getCentroid());
}
@Test
void checkToTree_finite() {
// arrange
final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
final Interval interval = Interval.of(-1, 1, precision);
// act
final RegionBSPTree1D tree = interval.toTree();
// assert
Assertions.assertEquals(5, tree.count());
checkClassify(tree, RegionLocation.OUTSIDE,
Double.NEGATIVE_INFINITY, -2, -1.1,
1.1, 2, Double.POSITIVE_INFINITY);
checkClassify(tree, RegionLocation.BOUNDARY,
-1.001, -1, -0.999,
0.999, 1, 1.001);
checkClassify(tree, RegionLocation.INSIDE, -0.9, 0, 0.9);
checkClassify(tree, RegionLocation.OUTSIDE, Double.NaN);
}
@Test
void checkToTree_singlePoint() {
// arrange
final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
final Interval interval = Interval.of(1, 1, precision);
// act
final RegionBSPTree1D tree = interval.toTree();
// assert
Assertions.assertEquals(5, tree.count());
checkClassify(tree, RegionLocation.OUTSIDE,
Double.NEGATIVE_INFINITY, 0, 0.9, 1.1, 2, Double.POSITIVE_INFINITY);
checkClassify(tree, RegionLocation.BOUNDARY,
0.999, 1, 1.0001);
checkClassify(tree, RegionLocation.OUTSIDE, Double.NaN);
}
@Test
void checkToTree_maxInfinite() {
// arrange
final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
final Interval interval = Interval.of(-1, Double.POSITIVE_INFINITY, precision);
// act
final RegionBSPTree1D tree = interval.toTree();
// assert
Assertions.assertEquals(3, tree.count());
checkClassify(tree, RegionLocation.OUTSIDE,
Double.NEGATIVE_INFINITY, -2, -1.1);
checkClassify(tree, RegionLocation.BOUNDARY,
-1.001, -1, -0.999);
checkClassify(tree, RegionLocation.INSIDE,
-0.9, 0, 1.0, Double.POSITIVE_INFINITY);
checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
}
@Test
void checkToTree_minInfinite() {
// arrange
final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
final Interval interval = Interval.of(Double.NEGATIVE_INFINITY, 1, precision);
// act
final RegionBSPTree1D tree = interval.toTree();
// assert
Assertions.assertEquals(3, tree.count());
checkClassify(tree, RegionLocation.INSIDE,
Double.NEGATIVE_INFINITY, 0, 0.9);
checkClassify(tree, RegionLocation.BOUNDARY,
0.999, 1, 1.001);
checkClassify(tree, RegionLocation.OUTSIDE,
1.1, 2, Double.POSITIVE_INFINITY);
checkClassify(tree, RegionLocation.OUTSIDE, Double.NaN);
}
@Test
void checkToTree_minMaxInfinite() {
// arrange
final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
final Interval interval = Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, precision);
// act
final RegionBSPTree1D tree = interval.toTree();
// assert
Assertions.assertEquals(1, tree.count());
checkClassify(tree, RegionLocation.INSIDE,
Double.NEGATIVE_INFINITY, -1, 0, 1, Double.POSITIVE_INFINITY);
checkClassify(tree, RegionLocation.OUTSIDE, Double.NaN);
}
@Test
void testProjectToBoundary_full() {
// arrange
final Interval full = Interval.full();
// act/assert
Assertions.assertNull(full.project(Vector1D.of(Double.NEGATIVE_INFINITY)));
Assertions.assertNull(full.project(Vector1D.of(0)));
Assertions.assertNull(full.project(Vector1D.of(Double.POSITIVE_INFINITY)));
}
@Test
void testProjectToBoundary_singlePoint() {
// arrange
final Interval interval = Interval.point(1, TEST_PRECISION);
// act/assert
checkBoundaryProjection(interval, -1, 1);
checkBoundaryProjection(interval, 0, 1);
checkBoundaryProjection(interval, 1, 1);
checkBoundaryProjection(interval, 2, 1);
checkBoundaryProjection(interval, 3, 1);
checkBoundaryProjection(interval, Double.NEGATIVE_INFINITY, 1);
checkBoundaryProjection(interval, Double.POSITIVE_INFINITY, 1);
}
@Test
void testProjectToBoundary_closedInterval() {
// arrange
final Interval interval = Interval.of(1, 3, TEST_PRECISION);
// act/assert
checkBoundaryProjection(interval, -1, 1);
checkBoundaryProjection(interval, 0, 1);
checkBoundaryProjection(interval, 1, 1);
checkBoundaryProjection(interval, 1.9, 1);
checkBoundaryProjection(interval, 2, 1);
checkBoundaryProjection(interval, 2.1, 3);
checkBoundaryProjection(interval, 3, 3);
checkBoundaryProjection(interval, 4, 3);
checkBoundaryProjection(interval, 5, 3);
checkBoundaryProjection(interval, Double.NEGATIVE_INFINITY, 1);
checkBoundaryProjection(interval, Double.POSITIVE_INFINITY, 3);
}
@Test
void testProjectToBoundary_noMinBoundary() {
// arrange
final Interval interval = Interval.of(Double.NEGATIVE_INFINITY, 1, TEST_PRECISION);
// act/assert
checkBoundaryProjection(interval, -1, 1);
checkBoundaryProjection(interval, 0, 1);
checkBoundaryProjection(interval, 1, 1);
checkBoundaryProjection(interval, 2, 1);
checkBoundaryProjection(interval, 3, 1);
checkBoundaryProjection(interval, Double.NEGATIVE_INFINITY, 1);
checkBoundaryProjection(interval, Double.POSITIVE_INFINITY, 1);
}
@Test
void testProjectToBoundary_noMaxBoundary() {
// arrange
final Interval interval = Interval.of(1, Double.POSITIVE_INFINITY, TEST_PRECISION);
// act/assert
checkBoundaryProjection(interval, -1, 1);
checkBoundaryProjection(interval, 0, 1);
checkBoundaryProjection(interval, 1, 1);
checkBoundaryProjection(interval, 2, 1);
checkBoundaryProjection(interval, 3, 1);
checkBoundaryProjection(interval, Double.NEGATIVE_INFINITY, 1);
checkBoundaryProjection(interval, Double.POSITIVE_INFINITY, 1);
}
@Test
void testTransform() {
// arrange
final AffineTransformMatrix1D transform = AffineTransformMatrix1D.createScale(2);
// act/assert
checkInterval(Interval.of(-1, 2, TEST_PRECISION).transform(transform), -2, 4);
checkInterval(Interval.of(Double.NEGATIVE_INFINITY, 2, TEST_PRECISION).transform(transform),
Double.NEGATIVE_INFINITY, 4);
checkInterval(Interval.of(-1, Double.POSITIVE_INFINITY, TEST_PRECISION).transform(transform), -2,
Double.POSITIVE_INFINITY);
checkInterval(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).transform(transform),
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
}
@Test
void testTransform_reflection() {
// arrange
final AffineTransformMatrix1D transform = AffineTransformMatrix1D.createScale(-1);
// act/assert
checkInterval(Interval.of(-1, 2, TEST_PRECISION).transform(transform), -2, 1);
checkInterval(Interval.of(Double.NEGATIVE_INFINITY, 2, TEST_PRECISION).transform(transform),
-2, Double.POSITIVE_INFINITY);
checkInterval(Interval.of(-1, Double.POSITIVE_INFINITY, TEST_PRECISION).transform(transform),
Double.NEGATIVE_INFINITY, 1);
}
@Test
void testSplit_full_positiveFacingSplitter() {
// arrange
final Interval interval = Interval.full();
final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
Vector1D.of(1), true, TEST_PRECISION);
// act
final Split<Interval> split = interval.split(splitter);
// assert
Assertions.assertEquals(SplitLocation.BOTH, split.getLocation());
checkInterval(split.getMinus(), Double.NEGATIVE_INFINITY, 1);
checkInterval(split.getPlus(), 1, Double.POSITIVE_INFINITY);
}
@Test
void testSplit_full_negativeFacingSplitter() {
// arrange
final Interval interval = Interval.full();
final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
Vector1D.of(1), false, TEST_PRECISION);
// act
final Split<Interval> split = interval.split(splitter);
// assert
Assertions.assertEquals(SplitLocation.BOTH, split.getLocation());
checkInterval(split.getMinus(), 1, Double.POSITIVE_INFINITY);
checkInterval(split.getPlus(), Double.NEGATIVE_INFINITY, 1);
}
@Test
void testSplit_halfSpace_positiveFacingSplitter() {
// arrange
final Interval interval = Interval.min(-1, TEST_PRECISION);
final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
Vector1D.of(1), true, TEST_PRECISION);
// act
final Split<Interval> split = interval.split(splitter);
// assert
Assertions.assertEquals(SplitLocation.BOTH, split.getLocation());
checkInterval(split.getMinus(), -1, 1);
checkInterval(split.getPlus(), 1, Double.POSITIVE_INFINITY);
}
@Test
void testSplit_halfSpace_negativeFacingSplitter() {
// arrange
final Interval interval = Interval.min(-1, TEST_PRECISION);
final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
Vector1D.of(1), false, TEST_PRECISION);
// act
final Split<Interval> split = interval.split(splitter);
// assert
Assertions.assertEquals(SplitLocation.BOTH, split.getLocation());
checkInterval(split.getMinus(), 1, Double.POSITIVE_INFINITY);
checkInterval(split.getPlus(), -1, 1);
}
@Test
void testSplit_splitterBelowInterval() {
// arrange
final Interval interval = Interval.of(5, 10, TEST_PRECISION);
final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
Vector1D.of(1), true, TEST_PRECISION);
// act
final Split<Interval> split = interval.split(splitter);
// assert
Assertions.assertEquals(SplitLocation.PLUS, split.getLocation());
Assertions.assertSame(interval, split.getPlus());
}
@Test
void testSplit_splitterOnMinBoundary() {
// arrange
final Interval interval = Interval.of(5, 10, TEST_PRECISION);
final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
Vector1D.of(5), false, TEST_PRECISION);
// act
final Split<Interval> split = interval.split(splitter);
// assert
Assertions.assertEquals(SplitLocation.MINUS, split.getLocation());
Assertions.assertSame(interval, split.getMinus());
}
@Test
void testSplit_splitterAboveInterval() {
// arrange
final Interval interval = Interval.of(5, 10, TEST_PRECISION);
final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
Vector1D.of(11), true, TEST_PRECISION);
// act
final Split<Interval> split = interval.split(splitter);
// assert
Assertions.assertEquals(SplitLocation.MINUS, split.getLocation());
Assertions.assertSame(interval, split.getMinus());
}
@Test
void testSplit_splitterOnMaxBoundary() {
// arrange
final Interval interval = Interval.of(5, 10, TEST_PRECISION);
final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
Vector1D.of(10), false, TEST_PRECISION);
// act
final Split<Interval> split = interval.split(splitter);
// assert
Assertions.assertEquals(SplitLocation.PLUS, split.getLocation());
Assertions.assertSame(interval, split.getPlus());
}
@Test
void testSplit_point_minusOnly() {
// arrange
final Interval interval = Interval.point(2, TEST_PRECISION);
final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
Vector1D.of(1), false, TEST_PRECISION);
// act
final Split<Interval> split = interval.split(splitter);
// assert
Assertions.assertEquals(SplitLocation.MINUS, split.getLocation());
checkInterval(split.getMinus(), 2, 2);
Assertions.assertNull(split.getPlus());
}
@Test
void testSplit_point_plusOnly() {
// arrange
final Interval interval = Interval.point(2, TEST_PRECISION);
final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
Vector1D.of(1), true, TEST_PRECISION);
// act
final Split<Interval> split = interval.split(splitter);
// assert
Assertions.assertEquals(SplitLocation.PLUS, split.getLocation());
Assertions.assertNull(split.getMinus());
checkInterval(split.getPlus(), 2, 2);
}
@Test
void testSplit_point_onPoint() {
// arrange
final Interval interval = Interval.point(1, TEST_PRECISION);
final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
Vector1D.of(1), true, TEST_PRECISION);
// act
final Split<Interval> split = interval.split(splitter);
// assert
Assertions.assertEquals(SplitLocation.NEITHER, split.getLocation());
Assertions.assertNull(split.getMinus());
Assertions.assertNull(split.getPlus());
}
@Test
void testToString() {
// arrange
final Interval interval = Interval.of(2, 1, TEST_PRECISION);
// act
final String str = interval.toString();
// assert
Assertions.assertTrue(str.contains("Interval"));
Assertions.assertTrue(str.contains("min= 1.0"));
Assertions.assertTrue(str.contains("max= 2.0"));
}
@Test
void testFull() {
// act
final Interval full = Interval.full();
// assert
Assertions.assertTrue(full.isFull());
Assertions.assertFalse(full.isEmpty());
Assertions.assertFalse(full.hasMinBoundary());
Assertions.assertFalse(full.hasMaxBoundary());
Assertions.assertTrue(full.isInfinite());
Assertions.assertEquals(RegionLocation.INSIDE, full.classify(Double.NEGATIVE_INFINITY));
Assertions.assertEquals(RegionLocation.INSIDE, full.classify(Double.POSITIVE_INFINITY));
}
private static void checkContains(final Interval interval, final boolean contains, final double... points) {
for (final double x : points) {
final String msg = "Unexpected contains status for point " + x;
Assertions.assertEquals(contains, interval.contains(x), msg);
Assertions.assertEquals(contains, interval.contains(Vector1D.of(x)), msg);
}
}
private static void checkClassify(final Interval interval, final RegionLocation loc, final double... points) {
for (final double x : points) {
final String msg = "Unexpected location for point " + x;
Assertions.assertEquals(loc, interval.classify(x), msg);
Assertions.assertEquals(loc, interval.classify(Vector1D.of(x)), msg);
}
}
private static void checkClassify(final RegionBSPTree1D tree, final RegionLocation loc, final double... points) {
for (final double x : points) {
final String msg = "Unexpected location for point " + x;
Assertions.assertEquals(loc, tree.classify(x), msg);
Assertions.assertEquals(loc, tree.classify(Vector1D.of(x)), msg);
}
}
private static void checkBoundaryProjection(final Interval interval, final double location, final double projectedLocation) {
final Vector1D pt = Vector1D.of(location);
final Vector1D proj = interval.project(pt);
Assertions.assertEquals(projectedLocation, proj.getX(), TEST_EPS);
}
/** Check that the given interval matches the arguments and is internally consistent.
* @param interval
* @param min
* @param max
*/
private static void checkInterval(final Interval interval, final double min, final double max) {
Assertions.assertEquals(min, interval.getMin(), TEST_EPS);
Assertions.assertEquals(max, interval.getMax(), TEST_EPS);
final boolean finiteMin = Double.isFinite(min);
final boolean finiteMax = Double.isFinite(max);
Assertions.assertEquals(finiteMin, interval.hasMinBoundary());
Assertions.assertEquals(finiteMax, interval.hasMaxBoundary());
if (finiteMin) {
Assertions.assertEquals(min, interval.getMinBoundary().getLocation(), TEST_EPS);
} else {
Assertions.assertNull(interval.getMinBoundary());
}
if (finiteMax) {
Assertions.assertEquals(max, interval.getMaxBoundary().getLocation(), TEST_EPS);
} else {
Assertions.assertNull(interval.getMaxBoundary());
}
Assertions.assertFalse(interval.isEmpty()); // always false
}
}