| /* |
| * 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.geometry.euclidean.twod; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.apache.commons.numbers.angle.PlaneAngleRadians; |
| import org.apache.commons.geometry.core.GeometryTestUtils; |
| import org.apache.commons.geometry.core.RegionLocation; |
| import org.apache.commons.geometry.core.exception.GeometryException; |
| import org.apache.commons.geometry.core.partitioning.Split; |
| import org.apache.commons.geometry.core.partitioning.SplitLocation; |
| import org.apache.commons.geometry.core.precision.DoublePrecisionContext; |
| import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext; |
| import org.apache.commons.geometry.euclidean.EuclideanTestUtils; |
| import org.junit.Assert; |
| import org.junit.Test; |
| |
| public class ConvexAreaTest { |
| |
| private static final double TEST_EPS = 1e-10; |
| |
| private static final DoublePrecisionContext TEST_PRECISION = |
| new EpsilonDoublePrecisionContext(TEST_EPS); |
| |
| @Test |
| public void testFull() { |
| // act |
| ConvexArea area = ConvexArea.full(); |
| |
| // assert |
| Assert.assertTrue(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| Assert.assertEquals(0.0, area.getBoundarySize(), TEST_EPS); |
| GeometryTestUtils.assertPositiveInfinity(area.getSize()); |
| Assert.assertNull(area.getBarycenter()); |
| } |
| |
| @Test |
| public void testToTree() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds( |
| Line.fromPointAndAngle(Vector2D.ZERO, 0.0, TEST_PRECISION), |
| Line.fromPointAndAngle(Vector2D.of(1, 0), PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION), |
| Line.fromPointAndAngle(Vector2D.of(1, 1), PlaneAngleRadians.PI, TEST_PRECISION), |
| Line.fromPointAndAngle(Vector2D.of(0, 1), PlaneAngleRadians.MINUS_PI_OVER_TWO, TEST_PRECISION) |
| ); |
| |
| // act |
| RegionBSPTree2D tree = area.toTree(); |
| |
| // assert |
| Assert.assertEquals(1, tree.getSize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 0.5), tree.getBarycenter(), TEST_EPS); |
| } |
| |
| @Test |
| public void testTransform_full() { |
| // arrange |
| Transform2D transform = FunctionTransform2D.from(v -> v.multiply(3)); |
| ConvexArea area = ConvexArea.full(); |
| |
| // act |
| ConvexArea transformed = area.transform(transform); |
| |
| // assert |
| Assert.assertSame(area, transformed); |
| } |
| |
| @Test |
| public void testTransform_infinite() { |
| // arrange |
| AffineTransformMatrix2D mat = AffineTransformMatrix2D |
| .createRotation(Vector2D.of(0, 1), PlaneAngleRadians.PI_OVER_TWO) |
| .scale(Vector2D.of(3, 2)); |
| |
| ConvexArea area = ConvexArea.fromBounds( |
| Line.fromPointAndAngle(Vector2D.ZERO, 0.25 * PlaneAngleRadians.PI, TEST_PRECISION), |
| Line.fromPointAndAngle(Vector2D.ZERO, -0.25 * PlaneAngleRadians.PI, TEST_PRECISION)); |
| |
| // act |
| ConvexArea transformed = area.transform(mat); |
| |
| // assert |
| Assert.assertNotSame(area, transformed); |
| |
| List<Polyline> paths = transformed.getBoundaryPaths(); |
| Assert.assertEquals(1, paths.size()); |
| |
| List<Segment> segments = paths.get(0).getSegments(); |
| Assert.assertEquals(2, segments.size()); |
| |
| Segment firstSegment = segments.get(0); |
| Assert.assertNull(firstSegment.getStartPoint()); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(3, 2), firstSegment.getEndPoint(), TEST_EPS); |
| Assert.assertEquals(Math.atan2(2, 3), firstSegment.getLine().getAngle(), TEST_EPS); |
| |
| Segment secondSegment = segments.get(1); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(3, 2), secondSegment.getStartPoint(), TEST_EPS); |
| Assert.assertNull(secondSegment.getEndPoint()); |
| Assert.assertEquals(Math.atan2(2, -3), secondSegment.getLine().getAngle(), TEST_EPS); |
| } |
| |
| @Test |
| public void testTransform_finite() { |
| // arrange |
| AffineTransformMatrix2D mat = AffineTransformMatrix2D.createScale(Vector2D.of(1, 2)); |
| |
| ConvexArea area = ConvexArea.fromVertexLoop(Arrays.asList( |
| Vector2D.of(1, 1), Vector2D.of(2, 1), |
| Vector2D.of(2, 2), Vector2D.of(1, 2) |
| ), TEST_PRECISION); |
| |
| // act |
| ConvexArea transformed = area.transform(mat); |
| |
| // assert |
| Assert.assertNotSame(area, transformed); |
| |
| List<Segment> segments = transformed.getBoundaries(); |
| Assert.assertEquals(4, segments.size()); |
| |
| Assert.assertEquals(2, transformed.getSize(), TEST_EPS); |
| Assert.assertEquals(6, transformed.getBoundarySize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1.5, 3), transformed.getBarycenter(), TEST_EPS); |
| |
| checkRegion(transformed, RegionLocation.BOUNDARY, |
| Vector2D.of(1, 2), Vector2D.of(2, 2), Vector2D.of(2, 4), Vector2D.of(1, 4)); |
| checkRegion(transformed, RegionLocation.INSIDE, transformed.getBarycenter()); |
| } |
| |
| @Test |
| public void testTransform_finite_withSingleReflection() { |
| // arrange |
| AffineTransformMatrix2D mat = AffineTransformMatrix2D.createScale(Vector2D.of(-1, 2)); |
| |
| ConvexArea area = ConvexArea.fromVertexLoop(Arrays.asList( |
| Vector2D.of(1, 1), Vector2D.of(2, 1), |
| Vector2D.of(2, 2), Vector2D.of(1, 2) |
| ), TEST_PRECISION); |
| |
| // act |
| ConvexArea transformed = area.transform(mat); |
| |
| // assert |
| Assert.assertNotSame(area, transformed); |
| |
| List<Segment> segments = transformed.getBoundaries(); |
| Assert.assertEquals(4, segments.size()); |
| |
| Assert.assertEquals(2, transformed.getSize(), TEST_EPS); |
| Assert.assertEquals(6, transformed.getBoundarySize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-1.5, 3), transformed.getBarycenter(), TEST_EPS); |
| |
| checkRegion(transformed, RegionLocation.BOUNDARY, |
| Vector2D.of(-1, 2), Vector2D.of(-2, 2), Vector2D.of(-2, 4), Vector2D.of(-1, 4)); |
| checkRegion(transformed, RegionLocation.INSIDE, transformed.getBarycenter()); |
| } |
| |
| @Test |
| public void testTransform_finite_withDoubleReflection() { |
| // arrange |
| AffineTransformMatrix2D mat = AffineTransformMatrix2D.createScale(Vector2D.of(-1, -2)); |
| |
| ConvexArea area = ConvexArea.fromVertexLoop(Arrays.asList( |
| Vector2D.of(1, 1), Vector2D.of(2, 1), |
| Vector2D.of(2, 2), Vector2D.of(1, 2) |
| ), TEST_PRECISION); |
| |
| // act |
| ConvexArea transformed = area.transform(mat); |
| |
| // assert |
| Assert.assertNotSame(area, transformed); |
| |
| List<Segment> segments = transformed.getBoundaries(); |
| Assert.assertEquals(4, segments.size()); |
| |
| Assert.assertEquals(2, transformed.getSize(), TEST_EPS); |
| Assert.assertEquals(6, transformed.getBoundarySize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-1.5, -3), transformed.getBarycenter(), TEST_EPS); |
| |
| checkRegion(transformed, RegionLocation.BOUNDARY, |
| Vector2D.of(-1, -2), Vector2D.of(-2, -2), Vector2D.of(-2, -4), Vector2D.of(-1, -4)); |
| checkRegion(transformed, RegionLocation.INSIDE, transformed.getBarycenter()); |
| } |
| |
| @Test |
| public void testGetVertices_full() { |
| // arrange |
| ConvexArea area = ConvexArea.full(); |
| |
| // act/assert |
| Assert.assertEquals(0, area.getVertices().size()); |
| } |
| |
| @Test |
| public void testGetVertices_twoParallelLines() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds( |
| Line.fromPointAndAngle(Vector2D.of(0, 1), PlaneAngleRadians.PI, TEST_PRECISION), |
| Line.fromPointAndAngle(Vector2D.of(0, -1), 0.0, TEST_PRECISION) |
| ); |
| |
| // act/assert |
| Assert.assertEquals(0, area.getVertices().size()); |
| } |
| |
| @Test |
| public void testGetVertices_infiniteWithVertices() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds( |
| Line.fromPointAndAngle(Vector2D.of(0, 1), PlaneAngleRadians.PI, TEST_PRECISION), |
| Line.fromPointAndAngle(Vector2D.of(0, -1), 0.0, TEST_PRECISION), |
| Line.fromPointAndAngle(Vector2D.of(1, 0), PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION) |
| ); |
| |
| // act |
| List<Vector2D> vertices = area.getVertices(); |
| |
| // assert |
| Assert.assertEquals(2, vertices.size()); |
| |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, -1), vertices.get(0), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, 1), vertices.get(1), TEST_EPS); |
| } |
| |
| @Test |
| public void testGetVertices_finite() { |
| // arrange |
| ConvexArea area = ConvexArea.fromVertexLoop(Arrays.asList( |
| Vector2D.ZERO, |
| Vector2D.Unit.PLUS_X, |
| Vector2D.Unit.PLUS_Y |
| ), TEST_PRECISION); |
| |
| // act |
| List<Vector2D> vertices = area.getVertices(); |
| |
| // assert |
| Assert.assertEquals(4, vertices.size()); |
| |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.ZERO, vertices.get(0), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.Unit.PLUS_X, vertices.get(1), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.Unit.PLUS_Y, vertices.get(2), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.ZERO, vertices.get(3), TEST_EPS); |
| } |
| |
| @Test |
| public void testProject_full() { |
| // arrange |
| ConvexArea area = ConvexArea.full(); |
| |
| // act/assert |
| Assert.assertNull(area.project(Vector2D.ZERO)); |
| Assert.assertNull(area.project(Vector2D.Unit.PLUS_X)); |
| } |
| |
| @Test |
| public void testProject_halfSpace() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds( |
| Line.fromPointAndAngle(Vector2D.ZERO, PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION)); |
| |
| // act/assert |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, 1), area.project(Vector2D.of(1, 1)), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, 2), area.project(Vector2D.of(-2, 2)), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, -3), area.project(Vector2D.of(1, -3)), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, -4), area.project(Vector2D.of(-2, -4)), TEST_EPS); |
| } |
| |
| @Test |
| public void testProject_square() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds(createSquareBoundingLines(Vector2D.ZERO, 1, 1)); |
| |
| // act/assert |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, 1), area.project(Vector2D.of(1, 1)), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, 1), area.project(Vector2D.of(2, 2)), TEST_EPS); |
| |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.ZERO, area.project(Vector2D.ZERO), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.ZERO, area.project(Vector2D.of(-1, -1)), TEST_EPS); |
| |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, 0.5), area.project(Vector2D.of(0.1, 0.5)), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.2, 1), area.project(Vector2D.of(0.2, 0.9)), TEST_EPS); |
| |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 0), area.project(Vector2D.of(0.5, 0.5)), TEST_EPS); |
| } |
| |
| @Test |
| public void testTrim_full() { |
| // arrange |
| ConvexArea area = ConvexArea.full(); |
| Segment segment = Segment.fromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_Y, TEST_PRECISION); |
| |
| // act |
| Segment trimmed = area.trim(segment); |
| |
| // assert |
| Assert.assertSame(segment, trimmed); |
| } |
| |
| @Test |
| public void testTrim_halfSpace() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds(Line.fromPointAndAngle(Vector2D.ZERO, 0.0, TEST_PRECISION)); |
| Segment segment = Line.fromPoints(Vector2D.Unit.MINUS_Y, Vector2D.Unit.PLUS_Y, TEST_PRECISION).span(); |
| |
| // act |
| Segment trimmed = area.trim(segment); |
| |
| // assert |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.ZERO, trimmed.getStartPoint(), TEST_EPS); |
| GeometryTestUtils.assertPositiveInfinity(trimmed.getSubspaceEnd()); |
| } |
| |
| @Test |
| public void testTrim_square() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds(createSquareBoundingLines(Vector2D.ZERO, 1, 1)); |
| Segment segment = Line.fromPoints(Vector2D.of(0.5, 0), Vector2D.of(0.5, 1), TEST_PRECISION).span(); |
| |
| // act |
| Segment trimmed = area.trim(segment); |
| |
| // assert |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 0), trimmed.getStartPoint(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 1), trimmed.getEndPoint(), TEST_EPS); |
| } |
| |
| @Test |
| public void testTrim_segmentOutsideOfRegion() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds(createSquareBoundingLines(Vector2D.ZERO, 1, 1)); |
| Segment segment = Line.fromPoints(Vector2D.of(-0.5, 0), Vector2D.of(-0.5, 1), TEST_PRECISION).span(); |
| |
| // act |
| Segment trimmed = area.trim(segment); |
| |
| // assert |
| Assert.assertNull(trimmed); |
| } |
| |
| @Test |
| public void testTrim_segmentDirectlyOnBoundaryOfRegion() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds(createSquareBoundingLines(Vector2D.ZERO, 1, 1)); |
| Segment segment = Line.fromPoints(Vector2D.of(1, 0), Vector2D.of(1, 1), TEST_PRECISION).span(); |
| |
| // act |
| Segment trimmed = area.trim(segment); |
| |
| // assert |
| Assert.assertNull(trimmed); |
| } |
| |
| @Test |
| public void testSplit_full() { |
| // arrange |
| ConvexArea input = ConvexArea.full(); |
| |
| Line splitter = Line.fromPointAndAngle(Vector2D.ZERO, 0.0, TEST_PRECISION); |
| |
| // act |
| Split<ConvexArea> split = input.split(splitter); |
| |
| // act |
| Assert.assertEquals(SplitLocation.BOTH, split.getLocation()); |
| |
| ConvexArea minus = split.getMinus(); |
| Assert.assertFalse(minus.isFull()); |
| Assert.assertFalse(minus.isEmpty()); |
| |
| GeometryTestUtils.assertPositiveInfinity(minus.getBoundarySize()); |
| GeometryTestUtils.assertPositiveInfinity(minus.getSize()); |
| Assert.assertNull(minus.getBarycenter()); |
| |
| List<Segment> minusSegments = minus.getBoundaries(); |
| Assert.assertEquals(1,minusSegments.size()); |
| Assert.assertEquals(splitter, minusSegments.get(0).getLine()); |
| |
| ConvexArea plus = split.getPlus(); |
| Assert.assertFalse(plus.isFull()); |
| Assert.assertFalse(plus.isEmpty()); |
| |
| GeometryTestUtils.assertPositiveInfinity(plus.getBoundarySize()); |
| GeometryTestUtils.assertPositiveInfinity(plus.getSize()); |
| Assert.assertNull(plus.getBarycenter()); |
| |
| List<Segment> plusSegments = plus.getBoundaries(); |
| Assert.assertEquals(1, plusSegments.size()); |
| Assert.assertEquals(splitter, plusSegments.get(0).getLine().reverse()); |
| } |
| |
| @Test |
| public void testSplit_halfSpace_split() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds(Line.fromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION)); |
| Line splitter = Line.fromPointAndAngle(Vector2D.ZERO, 0.25 * PlaneAngleRadians.PI, TEST_PRECISION); |
| |
| // act |
| Split<ConvexArea> split = area.split(splitter); |
| |
| // assert |
| Assert.assertEquals(SplitLocation.BOTH, split.getLocation()); |
| |
| ConvexArea minus = split.getMinus(); |
| Assert.assertFalse(minus.isFull()); |
| Assert.assertFalse(minus.isEmpty()); |
| |
| GeometryTestUtils.assertPositiveInfinity(minus.getBoundarySize()); |
| GeometryTestUtils.assertPositiveInfinity(minus.getSize()); |
| Assert.assertNull(minus.getBarycenter()); |
| |
| Assert.assertEquals(2, minus.getBoundaries().size()); |
| |
| ConvexArea plus = split.getPlus(); |
| Assert.assertFalse(plus.isFull()); |
| Assert.assertFalse(plus.isEmpty()); |
| |
| GeometryTestUtils.assertPositiveInfinity(plus.getBoundarySize()); |
| GeometryTestUtils.assertPositiveInfinity(plus.getSize()); |
| Assert.assertNull(plus.getBarycenter()); |
| |
| Assert.assertEquals(2, plus.getBoundaries().size()); |
| } |
| |
| @Test |
| public void testSplit_halfSpace_splitOnBoundary() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds(Line.fromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION)); |
| Line splitter = Line.fromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION); |
| |
| // act |
| Split<ConvexArea> split = area.split(splitter); |
| |
| // assert |
| Assert.assertEquals(SplitLocation.MINUS, split.getLocation()); |
| |
| Assert.assertSame(area, split.getMinus()); |
| Assert.assertNull(split.getPlus()); |
| } |
| |
| @Test |
| public void testSplit_halfSpace_splitOnBoundaryWithReversedSplitter() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds(Line.fromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION)); |
| Line splitter = Line.fromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION).reverse(); |
| |
| // act |
| Split<ConvexArea> split = area.split(splitter); |
| |
| // assert |
| Assert.assertEquals(SplitLocation.PLUS, split.getLocation()); |
| |
| Assert.assertNull(split.getMinus()); |
| Assert.assertSame(area, split.getPlus()); |
| } |
| |
| @Test |
| public void testSplit_square_split() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds(createSquareBoundingLines(Vector2D.of(1, 1), 2, 1)); |
| Line splitter = Line.fromPointAndAngle(Vector2D.of(2, 1), PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION); |
| |
| // act |
| Split<ConvexArea> split = area.split(splitter); |
| |
| // assert |
| Assert.assertEquals(SplitLocation.BOTH, split.getLocation()); |
| |
| ConvexArea minus = split.getMinus(); |
| Assert.assertFalse(minus.isFull()); |
| Assert.assertFalse(minus.isEmpty()); |
| |
| Assert.assertEquals(4, minus.getBoundarySize(), TEST_EPS); |
| Assert.assertEquals(1, minus.getSize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1.5, 1.5), minus.getBarycenter(), TEST_EPS); |
| |
| Assert.assertEquals(4, minus.getBoundaries().size()); |
| |
| ConvexArea plus = split.getPlus(); |
| Assert.assertFalse(plus.isFull()); |
| Assert.assertFalse(plus.isEmpty()); |
| |
| Assert.assertEquals(4, plus.getBoundarySize(), TEST_EPS); |
| Assert.assertEquals(1, plus.getSize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(2.5, 1.5), plus.getBarycenter(), TEST_EPS); |
| |
| Assert.assertEquals(4, plus.getBoundaries().size()); |
| } |
| |
| @Test |
| public void testSplit_square_splitOnVertices() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds(createSquareBoundingLines(Vector2D.of(1, 1), 1, 1)); |
| Line splitter = Line.fromPoints(Vector2D.of(1, 1), Vector2D.of(2, 2), TEST_PRECISION); |
| |
| // act |
| Split<ConvexArea> split = area.split(splitter); |
| |
| // assert |
| Assert.assertEquals(SplitLocation.BOTH, split.getLocation()); |
| |
| ConvexArea minus = split.getMinus(); |
| Assert.assertFalse(minus.isFull()); |
| Assert.assertFalse(minus.isEmpty()); |
| |
| Assert.assertEquals(2 + Math.sqrt(2), minus.getBoundarySize(), TEST_EPS); |
| Assert.assertEquals(0.5, minus.getSize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(4.0 / 3.0, 5.0 / 3.0), minus.getBarycenter(), TEST_EPS); |
| |
| Assert.assertEquals(3, minus.getBoundaries().size()); |
| |
| ConvexArea plus = split.getPlus(); |
| Assert.assertFalse(plus.isFull()); |
| Assert.assertFalse(plus.isEmpty()); |
| |
| Assert.assertEquals(2 + Math.sqrt(2), plus.getBoundarySize(), TEST_EPS); |
| Assert.assertEquals(0.5, plus.getSize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(5.0 / 3.0, 4.0 / 3.0), plus.getBarycenter(), TEST_EPS); |
| |
| Assert.assertEquals(3, plus.getBoundaries().size()); |
| } |
| |
| @Test |
| public void testSplit_square_splitOnVerticesWithReversedSplitter() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds(createSquareBoundingLines(Vector2D.of(1, 1), 1, 1)); |
| Line splitter = Line.fromPoints(Vector2D.of(1, 1), Vector2D.of(2, 2), TEST_PRECISION).reverse(); |
| |
| // act |
| Split<ConvexArea> split = area.split(splitter); |
| |
| // assert |
| Assert.assertEquals(SplitLocation.BOTH, split.getLocation()); |
| |
| ConvexArea minus = split.getMinus(); |
| Assert.assertFalse(minus.isFull()); |
| Assert.assertFalse(minus.isEmpty()); |
| |
| Assert.assertEquals(2 + Math.sqrt(2), minus.getBoundarySize(), TEST_EPS); |
| Assert.assertEquals(0.5, minus.getSize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(5.0 / 3.0, 4.0 / 3.0), minus.getBarycenter(), TEST_EPS); |
| |
| Assert.assertEquals(3, minus.getBoundaries().size()); |
| |
| ConvexArea plus = split.getPlus(); |
| Assert.assertFalse(plus.isFull()); |
| Assert.assertFalse(plus.isEmpty()); |
| |
| Assert.assertEquals(2 + Math.sqrt(2), plus.getBoundarySize(), TEST_EPS); |
| Assert.assertEquals(0.5, plus.getSize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(4.0 / 3.0, 5.0 / 3.0), plus.getBarycenter(), TEST_EPS); |
| |
| Assert.assertEquals(3, plus.getBoundaries().size()); |
| } |
| |
| @Test |
| public void testSplit_square_entirelyOnMinus() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds(createSquareBoundingLines(Vector2D.of(1, 1), 1, 1)); |
| Line splitter = Line.fromPoints(Vector2D.of(3, 1), Vector2D.of(3, 2), TEST_PRECISION); |
| |
| // act |
| Split<ConvexArea> split = area.split(splitter); |
| |
| // assert |
| Assert.assertEquals(SplitLocation.MINUS, split.getLocation()); |
| Assert.assertSame(area, split.getMinus()); |
| Assert.assertNull(split.getPlus()); |
| } |
| |
| @Test |
| public void testSplit_square_onMinusBoundary() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds(createSquareBoundingLines(Vector2D.of(1, 1), 1, 1)); |
| Line splitter = Line.fromPoints(Vector2D.of(2, 1), Vector2D.of(2, 2), TEST_PRECISION); |
| |
| // act |
| Split<ConvexArea> split = area.split(splitter); |
| |
| // assert |
| Assert.assertEquals(SplitLocation.MINUS, split.getLocation()); |
| Assert.assertSame(area, split.getMinus()); |
| Assert.assertNull(split.getPlus()); |
| } |
| |
| @Test |
| public void testSplit_square_entirelyOnPlus() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds(createSquareBoundingLines(Vector2D.of(1, 1), 1, 1)); |
| Line splitter = Line.fromPoints(Vector2D.of(0, 1), Vector2D.of(0, 2), TEST_PRECISION); |
| |
| // act |
| Split<ConvexArea> split = area.split(splitter); |
| |
| // assert |
| Assert.assertEquals(SplitLocation.PLUS, split.getLocation()); |
| Assert.assertNull(split.getMinus()); |
| Assert.assertSame(area, split.getPlus()); |
| } |
| |
| @Test |
| public void testSplit_square_onPlusBoundary() { |
| // arrange |
| ConvexArea area = ConvexArea.fromBounds(createSquareBoundingLines(Vector2D.of(1, 1), 1, 1)); |
| Line splitter = Line.fromPoints(Vector2D.of(1, 1), Vector2D.of(1, 2), TEST_PRECISION); |
| |
| // act |
| Split<ConvexArea> split = area.split(splitter); |
| |
| // assert |
| Assert.assertEquals(SplitLocation.PLUS, split.getLocation()); |
| Assert.assertNull(split.getMinus()); |
| Assert.assertSame(area, split.getPlus()); |
| } |
| |
| @Test |
| public void testToString() { |
| // arrange |
| ConvexArea area = ConvexArea.full(); |
| |
| // act |
| String str = area.toString(); |
| |
| // assert |
| Assert.assertTrue(str.contains("ConvexArea")); |
| Assert.assertTrue(str.contains("boundaries= ")); |
| } |
| |
| @Test |
| public void testFromVertices_noVertices() { |
| // act |
| ConvexArea area = ConvexArea.fromVertices(Arrays.asList(), TEST_PRECISION); |
| |
| // assert |
| Assert.assertTrue(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| Assert.assertEquals(0, area.getBoundarySize(), TEST_EPS); |
| GeometryTestUtils.assertPositiveInfinity(area.getSize()); |
| Assert.assertNull(area.getBarycenter()); |
| } |
| |
| @Test |
| public void testFromVertices_singleUniqueVertex() { |
| // arrange |
| DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-3); |
| |
| // act/assert |
| GeometryTestUtils.assertThrows(() -> { |
| ConvexArea.fromVertices(Arrays.asList(Vector2D.ZERO), precision); |
| }, IllegalStateException.class); |
| |
| GeometryTestUtils.assertThrows(() -> { |
| ConvexArea.fromVertices(Arrays.asList(Vector2D.ZERO, Vector2D.of(1e-4, 1e-4)), precision); |
| }, IllegalStateException.class); |
| } |
| |
| @Test |
| public void testFromVertices_twoVertices() { |
| // act |
| ConvexArea area = ConvexArea.fromVertices(Arrays.asList( |
| Vector2D.ZERO, |
| Vector2D.Unit.PLUS_X |
| ), TEST_PRECISION); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| GeometryTestUtils.assertPositiveInfinity(area.getSize()); |
| GeometryTestUtils.assertPositiveInfinity(area.getBoundarySize()); |
| Assert.assertNull(area.getBarycenter()); |
| |
| Assert.assertTrue(area.contains(Vector2D.Unit.PLUS_Y)); |
| Assert.assertFalse(area.contains(Vector2D.Unit.MINUS_Y)); |
| } |
| |
| @Test |
| public void testFromVertices_threeVertices() { |
| // act |
| ConvexArea area = ConvexArea.fromVertices(Arrays.asList( |
| Vector2D.ZERO, |
| Vector2D.Unit.PLUS_X, |
| Vector2D.of(1, 1) |
| ), TEST_PRECISION); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| GeometryTestUtils.assertPositiveInfinity(area.getSize()); |
| GeometryTestUtils.assertPositiveInfinity(area.getBoundarySize()); |
| Assert.assertNull(area.getBarycenter()); |
| |
| Assert.assertTrue(area.contains(Vector2D.Unit.PLUS_Y)); |
| Assert.assertFalse(area.contains(Vector2D.Unit.MINUS_Y)); |
| Assert.assertFalse(area.contains(Vector2D.of(2, 2))); |
| } |
| |
| @Test |
| public void testFromVertices_finite() { |
| // act |
| ConvexArea area = ConvexArea.fromVertices(Arrays.asList( |
| Vector2D.ZERO, |
| Vector2D.Unit.PLUS_X, |
| Vector2D.of(1, 1), |
| Vector2D.Unit.PLUS_Y, |
| Vector2D.ZERO |
| ), TEST_PRECISION); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| Assert.assertEquals(1, area.getSize(), TEST_EPS); |
| Assert.assertEquals(4, area.getBoundarySize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 0.5), area.getBarycenter(), TEST_EPS); |
| } |
| |
| @Test |
| public void testFromVertices_handlesDuplicatePoints() { |
| // arrange |
| double eps = 1e-3; |
| DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(eps); |
| |
| // act |
| ConvexArea area = ConvexArea.fromVertices(Arrays.asList( |
| Vector2D.ZERO, |
| Vector2D.of(1e-4, 1e-4), |
| Vector2D.Unit.PLUS_X, |
| Vector2D.of(1, 1e-4), |
| Vector2D.of(1, 1), |
| Vector2D.of(0, 1), |
| Vector2D.of(1e-4, 1), |
| Vector2D.of(1e-4, 1e-4) |
| ), precision); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| Assert.assertEquals(1, area.getSize(), eps); |
| Assert.assertEquals(4, area.getBoundarySize(), eps); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 0.5), area.getBarycenter(), eps); |
| } |
| |
| @Test |
| public void testFromVertices_clockwiseWinding() { |
| // act |
| GeometryTestUtils.assertThrows(() -> { |
| ConvexArea.fromVertices( |
| Arrays.asList( |
| Vector2D.ZERO, |
| Vector2D.Unit.PLUS_Y, |
| Vector2D.of(1, 1), |
| Vector2D.Unit.PLUS_X, |
| Vector2D.ZERO |
| ),TEST_PRECISION); |
| }, GeometryException.class); |
| } |
| |
| @Test |
| public void testFromVertexLoops_noVertices() { |
| // act |
| ConvexArea area = ConvexArea.fromVertexLoop(Arrays.asList(), TEST_PRECISION); |
| |
| // assert |
| Assert.assertTrue(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| Assert.assertEquals(0, area.getBoundarySize(), TEST_EPS); |
| GeometryTestUtils.assertPositiveInfinity(area.getSize()); |
| Assert.assertNull(area.getBarycenter()); |
| } |
| |
| @Test |
| public void testFromVertexLoop_singleUniqueVertex() { |
| // arrange |
| DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-3); |
| |
| // act/assert |
| GeometryTestUtils.assertThrows(() -> { |
| ConvexArea.fromVertexLoop(Arrays.asList(Vector2D.ZERO), precision); |
| }, IllegalStateException.class); |
| |
| GeometryTestUtils.assertThrows(() -> { |
| ConvexArea.fromVertexLoop(Arrays.asList(Vector2D.ZERO, Vector2D.of(1e-4, 1e-4)), precision); |
| }, IllegalStateException.class); |
| } |
| |
| @Test |
| public void testFromVertexLoop_twoVertices_fails() { |
| // act/assert |
| GeometryTestUtils.assertThrows(() -> { |
| ConvexArea.fromVertexLoop(Arrays.asList(Vector2D.ZERO, Vector2D.Unit.PLUS_X), TEST_PRECISION); |
| }, GeometryException.class); |
| } |
| |
| @Test |
| public void testFromVertexLoop_square_closeRequired() { |
| // act |
| ConvexArea area = ConvexArea.fromVertexLoop(Arrays.asList( |
| Vector2D.ZERO, |
| Vector2D.Unit.PLUS_X, |
| Vector2D.of(1, 1), |
| Vector2D.of(0, 1) |
| ), TEST_PRECISION); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| Assert.assertEquals(1, area.getSize(), TEST_EPS); |
| Assert.assertEquals(4, area.getBoundarySize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 0.5), area.getBarycenter(), TEST_EPS); |
| } |
| |
| @Test |
| public void testFromVertexLoop_square_closeNotRequired() { |
| // act |
| ConvexArea area = ConvexArea.fromVertexLoop(Arrays.asList( |
| Vector2D.ZERO, |
| Vector2D.Unit.PLUS_X, |
| Vector2D.of(1, 1), |
| Vector2D.of(0, 1), |
| Vector2D.ZERO |
| ), TEST_PRECISION); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| Assert.assertEquals(1, area.getSize(), TEST_EPS); |
| Assert.assertEquals(4, area.getBoundarySize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 0.5), area.getBarycenter(), TEST_EPS); |
| } |
| |
| @Test |
| public void testFromVertexLoop_handlesDuplicatePoints() { |
| // arrange |
| double eps = 1e-3; |
| DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(eps); |
| |
| // act |
| ConvexArea area = ConvexArea.fromVertexLoop(Arrays.asList( |
| Vector2D.ZERO, |
| Vector2D.of(1e-4, 1e-4), |
| Vector2D.Unit.PLUS_X, |
| Vector2D.of(1, 1e-4), |
| Vector2D.of(1, 1), |
| Vector2D.of(0, 1), |
| Vector2D.of(1e-4, 1), |
| Vector2D.of(1e-4, 1e-4) |
| ), precision); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| Assert.assertEquals(1, area.getSize(), eps); |
| Assert.assertEquals(4, area.getBoundarySize(), eps); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 0.5), area.getBarycenter(), eps); |
| } |
| |
| @Test |
| public void testFromVertexLoop_clockwiseWinding() { |
| // act |
| GeometryTestUtils.assertThrows(() -> { |
| ConvexArea.fromVertexLoop( |
| Arrays.asList( |
| Vector2D.ZERO, |
| Vector2D.Unit.PLUS_Y, |
| Vector2D.of(1, 1), |
| Vector2D.Unit.PLUS_X |
| ),TEST_PRECISION); |
| }, GeometryException.class); |
| } |
| |
| @Test |
| public void testFromPath_empty() { |
| // act |
| ConvexArea area = ConvexArea.fromPath(Polyline.empty()); |
| |
| // assert |
| Assert.assertTrue(area.isFull()); |
| } |
| |
| @Test |
| public void testFromPath_infinite() { |
| // act |
| ConvexArea area = ConvexArea.fromPath(Polyline.fromVertices( |
| Arrays.asList(Vector2D.ZERO, Vector2D.Unit.PLUS_X),TEST_PRECISION)); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| GeometryTestUtils.assertPositiveInfinity(area.getBoundarySize()); |
| GeometryTestUtils.assertPositiveInfinity(area.getSize()); |
| Assert.assertNull(area.getBarycenter()); |
| |
| checkRegion(area, RegionLocation.INSIDE, Vector2D.Unit.PLUS_Y); |
| checkRegion(area, RegionLocation.BOUNDARY, Vector2D.ZERO); |
| checkRegion(area, RegionLocation.OUTSIDE, Vector2D.Unit.MINUS_Y); |
| } |
| |
| @Test |
| public void testFromPath_finite() { |
| // act |
| ConvexArea area = ConvexArea.fromPath(Polyline.fromVertexLoop( |
| Arrays.asList( |
| Vector2D.ZERO, |
| Vector2D.Unit.PLUS_X, |
| Vector2D.of(1, 1), |
| Vector2D.Unit.PLUS_Y |
| ),TEST_PRECISION)); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| Assert.assertEquals(1, area.getSize(), TEST_EPS); |
| Assert.assertEquals(4, area.getBoundarySize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 0.5), area.getBarycenter(), TEST_EPS); |
| } |
| |
| @Test |
| public void testFromPath_clockwiseWinding() { |
| // act |
| GeometryTestUtils.assertThrows(() -> { |
| ConvexArea.fromPath(Polyline.fromVertexLoop( |
| Arrays.asList( |
| Vector2D.ZERO, |
| Vector2D.Unit.PLUS_Y, |
| Vector2D.of(1, 1), |
| Vector2D.Unit.PLUS_X |
| ),TEST_PRECISION)); |
| }, GeometryException.class); |
| } |
| |
| @Test |
| public void testFromBounds_noLines() { |
| // act |
| ConvexArea area = ConvexArea.fromBounds(Collections.emptyList()); |
| |
| // assert |
| Assert.assertSame(ConvexArea.full(), area); |
| } |
| |
| @Test |
| public void testFromBounds_singleLine() { |
| // arrange |
| Line line = Line.fromPoints(Vector2D.of(0, 1), Vector2D.of(1, 3), TEST_PRECISION); |
| |
| // act |
| ConvexArea area = ConvexArea.fromBounds(line); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| GeometryTestUtils.assertPositiveInfinity(area.getBoundarySize()); |
| GeometryTestUtils.assertPositiveInfinity(area.getSize()); |
| Assert.assertNull(area.getBarycenter()); |
| |
| List<Segment> segments = area.getBoundaries(); |
| Assert.assertEquals(1, segments.size()); |
| Assert.assertSame(line, segments.get(0).getLine()); |
| |
| checkRegion(area, RegionLocation.INSIDE, Vector2D.of(-1, 1), Vector2D.of(0, 2)); |
| checkRegion(area, RegionLocation.BOUNDARY, Vector2D.of(0, 1), Vector2D.of(2, 5)); |
| checkRegion(area, RegionLocation.OUTSIDE, Vector2D.ZERO, Vector2D.of(2, 3)); |
| } |
| |
| @Test |
| public void testFromBounds_twoLines() { |
| // arrange |
| Line a = Line.fromPointAndAngle(Vector2D.ZERO, PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION); |
| Line b = Line.fromPointAndAngle(Vector2D.ZERO, PlaneAngleRadians.PI, TEST_PRECISION); |
| |
| // act |
| ConvexArea area = ConvexArea.fromBounds(a, b); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| GeometryTestUtils.assertPositiveInfinity(area.getBoundarySize()); |
| GeometryTestUtils.assertPositiveInfinity(area.getSize()); |
| Assert.assertNull(area.getBarycenter()); |
| |
| List<Segment> segments = area.getBoundaries(); |
| Assert.assertEquals(2, segments.size()); |
| |
| checkRegion(area, RegionLocation.INSIDE, Vector2D.of(-1, -1)); |
| checkRegion(area, RegionLocation.BOUNDARY, |
| Vector2D.ZERO, Vector2D.of(-1, 0), Vector2D.of(0, -1)); |
| checkRegion(area, RegionLocation.OUTSIDE, |
| Vector2D.of(-1, 1), Vector2D.of(1, 1), Vector2D.of(1, -1)); |
| } |
| |
| @Test |
| public void testFromBounds_triangle() { |
| // arrange |
| Line a = Line.fromPointAndAngle(Vector2D.ZERO, PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION); |
| Line b = Line.fromPointAndAngle(Vector2D.ZERO, PlaneAngleRadians.PI, TEST_PRECISION); |
| Line c = Line.fromPointAndAngle(Vector2D.of(-2, 0), -0.25 * PlaneAngleRadians.PI, TEST_PRECISION); |
| |
| // act |
| ConvexArea area = ConvexArea.fromBounds(a, b, c); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| Assert.assertEquals(4 + (2 * Math.sqrt(2)), area.getBoundarySize(), TEST_EPS); |
| Assert.assertEquals(2, area.getSize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-2.0 / 3.0, -2.0 / 3.0), area.getBarycenter(), TEST_EPS); |
| |
| List<Segment> segments = area.getBoundaries(); |
| Assert.assertEquals(3, segments.size()); |
| |
| checkRegion(area, RegionLocation.INSIDE, Vector2D.of(-0.5, -0.5)); |
| checkRegion(area, RegionLocation.BOUNDARY, |
| Vector2D.ZERO, Vector2D.of(-1, 0), Vector2D.of(0, -1)); |
| checkRegion(area, RegionLocation.OUTSIDE, |
| Vector2D.of(-1, 1), Vector2D.of(1, 1), Vector2D.of(1, -1), Vector2D.of(-2, -2)); |
| } |
| |
| @Test |
| public void testFromBounds_square() { |
| // arrange |
| List<Line> square = createSquareBoundingLines(Vector2D.ZERO, 1, 1); |
| |
| // act |
| ConvexArea area = ConvexArea.fromBounds(square); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| Assert.assertEquals(4, area.getBoundarySize(), TEST_EPS); |
| Assert.assertEquals(1, area.getSize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 0.5), area.getBarycenter(), TEST_EPS); |
| |
| List<Segment> segments = area.getBoundaries(); |
| Assert.assertEquals(4, segments.size()); |
| |
| checkRegion(area, RegionLocation.INSIDE, Vector2D.of(0.5, 0.5)); |
| checkRegion(area, RegionLocation.BOUNDARY, |
| Vector2D.ZERO, Vector2D.of(1, 1), |
| Vector2D.of(0.5, 0), Vector2D.of(0.5, 1), |
| Vector2D.of(0, 0.5), Vector2D.of(1, 0.5)); |
| checkRegion(area, RegionLocation.OUTSIDE, |
| Vector2D.of(-1, -1), Vector2D.of(2, 2)); |
| } |
| |
| @Test |
| public void testFromBounds_square_extraLines() { |
| // arrange |
| List<Line> extraLines = new ArrayList<>(); |
| extraLines.add(Line.fromPoints(Vector2D.of(10, 10), Vector2D.of(10, 11), TEST_PRECISION)); |
| extraLines.add(Line.fromPoints(Vector2D.of(-10, 10), Vector2D.of(-10, 9), TEST_PRECISION)); |
| extraLines.add(Line.fromPoints(Vector2D.of(0, 10), Vector2D.of(-1, 11), TEST_PRECISION)); |
| extraLines.addAll(createSquareBoundingLines(Vector2D.ZERO, 1, 1)); |
| |
| // act |
| ConvexArea area = ConvexArea.fromBounds(extraLines); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| Assert.assertEquals(4, area.getBoundarySize(), TEST_EPS); |
| Assert.assertEquals(1, area.getSize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 0.5), area.getBarycenter(), TEST_EPS); |
| |
| List<Segment> segments = area.getBoundaries(); |
| Assert.assertEquals(4, segments.size()); |
| |
| checkRegion(area, RegionLocation.INSIDE, Vector2D.of(0.5, 0.5)); |
| checkRegion(area, RegionLocation.BOUNDARY, |
| Vector2D.ZERO, Vector2D.of(1, 1), |
| Vector2D.of(0.5, 0), Vector2D.of(0.5, 1), |
| Vector2D.of(0, 0.5), Vector2D.of(1, 0.5)); |
| checkRegion(area, RegionLocation.OUTSIDE, |
| Vector2D.of(-1, -1), Vector2D.of(2, 2)); |
| } |
| |
| @Test |
| public void testFromBounds_square_duplicateLines() { |
| // arrange |
| List<Line> duplicateLines = new ArrayList<>(); |
| duplicateLines.addAll(createSquareBoundingLines(Vector2D.ZERO, 1, 1)); |
| duplicateLines.addAll(createSquareBoundingLines(Vector2D.ZERO, 1, 1)); |
| |
| // act |
| ConvexArea area = ConvexArea.fromBounds(duplicateLines); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| Assert.assertEquals(4, area.getBoundarySize(), TEST_EPS); |
| Assert.assertEquals(1, area.getSize(), TEST_EPS); |
| EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 0.5), area.getBarycenter(), TEST_EPS); |
| |
| List<Segment> segments = area.getBoundaries(); |
| Assert.assertEquals(4, segments.size()); |
| |
| checkRegion(area, RegionLocation.INSIDE, Vector2D.of(0.5, 0.5)); |
| checkRegion(area, RegionLocation.BOUNDARY, |
| Vector2D.ZERO, Vector2D.of(1, 1), |
| Vector2D.of(0.5, 0), Vector2D.of(0.5, 1), |
| Vector2D.of(0, 0.5), Vector2D.of(1, 0.5)); |
| checkRegion(area, RegionLocation.OUTSIDE, |
| Vector2D.of(-1, -1), Vector2D.of(2, 2)); |
| } |
| |
| @Test |
| public void testFromBounds_duplicateLines_similarOrientation() { |
| // arrange |
| Line a = Line.fromPointAndAngle(Vector2D.of(0, 1), 0.0, TEST_PRECISION); |
| Line b = Line.fromPointAndAngle(Vector2D.of(0, 1), 0.0, TEST_PRECISION); |
| Line c = Line.fromPointAndAngle(Vector2D.of(0, 1), 0.0, TEST_PRECISION); |
| |
| // act |
| ConvexArea area = ConvexArea.fromBounds(a, b, c); |
| |
| // assert |
| Assert.assertFalse(area.isFull()); |
| Assert.assertFalse(area.isEmpty()); |
| |
| GeometryTestUtils.assertPositiveInfinity(area.getBoundarySize()); |
| GeometryTestUtils.assertPositiveInfinity(area.getSize()); |
| Assert.assertNull(area.getBarycenter()); |
| |
| List<Segment> segments = area.getBoundaries(); |
| Assert.assertEquals(1, segments.size()); |
| |
| checkRegion(area, RegionLocation.BOUNDARY, Vector2D.of(0, 1), Vector2D.of(1, 1), Vector2D.of(-1, 1)); |
| checkRegion(area, RegionLocation.INSIDE, Vector2D.of(0, 2), Vector2D.of(1, 2), Vector2D.of(-1, 2)); |
| checkRegion(area, RegionLocation.OUTSIDE, Vector2D.of(0, 0), Vector2D.of(1, 0), Vector2D.of(-1, 0)); |
| } |
| |
| @Test |
| public void testFromBounds_duplicateLines_differentOrientation() { |
| // arrange |
| Line a = Line.fromPointAndAngle(Vector2D.of(0, 1), 0.0, TEST_PRECISION); |
| Line b = Line.fromPointAndAngle(Vector2D.of(0, 1), PlaneAngleRadians.PI, TEST_PRECISION); |
| Line c = Line.fromPointAndAngle(Vector2D.of(0, 1), 0.0, TEST_PRECISION); |
| |
| // act/assert |
| GeometryTestUtils.assertThrows(() -> { |
| ConvexArea.fromBounds(a, b, c); |
| }, GeometryException.class); |
| } |
| |
| @Test |
| public void testFromBounds_boundsDoNotProduceAConvexRegion() { |
| // act/assert |
| GeometryTestUtils.assertThrows(() -> { |
| ConvexArea.fromBounds(Arrays.asList( |
| Line.fromPointAndAngle(Vector2D.ZERO, 0.0, TEST_PRECISION), |
| Line.fromPointAndAngle(Vector2D.of(0, -1), PlaneAngleRadians.PI, TEST_PRECISION), |
| Line.fromPointAndAngle(Vector2D.ZERO, PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION) |
| )); |
| }, GeometryException.class); |
| } |
| |
| private static void checkRegion(ConvexArea area, RegionLocation loc, Vector2D ... pts) { |
| for (Vector2D pt : pts) { |
| Assert.assertEquals("Unexpected region location for point " + pt, loc, area.classify(pt)); |
| } |
| } |
| |
| private static List<Line> createSquareBoundingLines(final Vector2D lowerLeft, final double width, final double height) { |
| final Vector2D lowerRight = Vector2D.of(lowerLeft.getX() + width, lowerLeft.getY()); |
| final Vector2D upperRight = Vector2D.of(lowerLeft.getX() + width, lowerLeft.getY() + height); |
| final Vector2D upperLeft = Vector2D.of(lowerLeft.getX(), lowerLeft.getY() + height); |
| |
| return Arrays.asList( |
| Line.fromPoints(lowerLeft, lowerRight, TEST_PRECISION), |
| Line.fromPoints(upperRight, upperLeft, TEST_PRECISION), |
| Line.fromPoints(lowerRight, upperRight, TEST_PRECISION), |
| Line.fromPoints(upperLeft, lowerLeft, TEST_PRECISION) |
| ); |
| } |
| } |