View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.geometry.euclidean.oned;
18  
19  import java.util.List;
20  
21  import org.apache.commons.geometry.core.GeometryTestUtils;
22  import org.apache.commons.geometry.core.RegionLocation;
23  import org.apache.commons.geometry.core.Transform;
24  import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
25  import org.apache.commons.geometry.core.partitioning.HyperplaneLocation;
26  import org.apache.commons.geometry.core.partitioning.Split;
27  import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
28  import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
29  import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
30  import org.apache.commons.numbers.core.Precision;
31  import org.junit.Assert;
32  import org.junit.Test;
33  
34  public class OrientedPointTest {
35  
36      private static final double TEST_EPS = 1e-15;
37  
38      private static final DoublePrecisionContext TEST_PRECISION =
39              new EpsilonDoublePrecisionContext(TEST_EPS);
40  
41      @Test
42      public void testGetDirection() {
43          // act/assert
44          EuclideanTestUtils.assertCoordinatesEqual(Vector1D.Unit.PLUS,
45                  OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, TEST_PRECISION).getDirection(),
46                  TEST_EPS);
47          EuclideanTestUtils.assertCoordinatesEqual(Vector1D.Unit.MINUS,
48                  OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), false, TEST_PRECISION).getDirection(),
49                  TEST_EPS);
50      }
51  
52      @Test
53      public void testReverse() {
54          // act/assert
55          assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(0), true, TEST_PRECISION).reverse(),
56                  0.0, false, TEST_PRECISION);
57          assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(-1), false, TEST_PRECISION).reverse(),
58                  -1.0, true, TEST_PRECISION);
59          assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(1), true, TEST_PRECISION).reverse(),
60                  1.0, false, TEST_PRECISION);
61  
62          assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(0), true, TEST_PRECISION).reverse().reverse(),
63                  0.0, true, TEST_PRECISION);
64          assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(-1), false, TEST_PRECISION).reverse().reverse(),
65                  -1.0, false, TEST_PRECISION);
66          assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(1), true, TEST_PRECISION).reverse().reverse(),
67                  1.0, true, TEST_PRECISION);
68      }
69  
70      @Test
71      public void testTransform() {
72          // arrange
73          final AffineTransformMatrix1D scaleAndTranslate = AffineTransformMatrix1D
74                  .createScale(0.5)
75                  .translate(-10);
76  
77          final AffineTransformMatrix1D reflect = AffineTransformMatrix1D.createScale(-2);
78  
79          final OrientedPoint a = OrientedPoints.createPositiveFacing(Vector1D.of(2.0), TEST_PRECISION);
80          final OrientedPoint b = OrientedPoints.createNegativeFacing(Vector1D.of(-3.0), TEST_PRECISION);
81  
82          // act/assert
83          assertOrientedPoint(a.transform(scaleAndTranslate), -9.0, true, TEST_PRECISION);
84          assertOrientedPoint(b.transform(scaleAndTranslate), -11.5, false, TEST_PRECISION);
85  
86          assertOrientedPoint(a.transform(reflect), -4.0, false, TEST_PRECISION);
87          assertOrientedPoint(b.transform(reflect), 6.0, true, TEST_PRECISION);
88      }
89  
90      @Test
91      public void testTransform_locationAtInfinity() {
92          // arrange
93          final OrientedPoint pos = OrientedPoints.createNegativeFacing(Double.POSITIVE_INFINITY, TEST_PRECISION);
94          final OrientedPoint neg = OrientedPoints.createPositiveFacing(Double.NEGATIVE_INFINITY, TEST_PRECISION);
95  
96          final Transform<Vector1D> scaleAndTranslate = AffineTransformMatrix1D.identity().scale(10.0).translate(5.0);
97          final Transform<Vector1D> negate = AffineTransformMatrix1D.from(Vector1D::negate);
98  
99          // act/assert
100         assertOrientedPoint(pos.transform(scaleAndTranslate), Double.POSITIVE_INFINITY, false, TEST_PRECISION);
101         assertOrientedPoint(neg.transform(scaleAndTranslate), Double.NEGATIVE_INFINITY, true, TEST_PRECISION);
102 
103         assertOrientedPoint(pos.transform(negate), Double.NEGATIVE_INFINITY, true, TEST_PRECISION);
104         assertOrientedPoint(neg.transform(negate), Double.POSITIVE_INFINITY, false, TEST_PRECISION);
105     }
106 
107     @Test
108     public void testTransform_zeroScale() {
109         // arrange
110         final AffineTransformMatrix1D zeroScale = AffineTransformMatrix1D.createScale(0.0);
111 
112         final OrientedPoint pt = OrientedPoints.createPositiveFacing(Vector1D.of(2.0), TEST_PRECISION);
113 
114         // act/assert
115         GeometryTestUtils.assertThrows(
116             () -> pt.transform(zeroScale),
117             IllegalArgumentException.class, "Oriented point direction cannot be zero");
118     }
119 
120     @Test
121     public void testOffset_positiveFacing() {
122         // arrange
123         final OrientedPoint pt = OrientedPoints.fromPointAndDirection(Vector1D.of(-2.0), true, TEST_PRECISION);
124 
125         // act/assert
126         Assert.assertEquals(-98.0, pt.offset(Vector1D.of(-100)), Precision.EPSILON);
127         Assert.assertEquals(-0.1, pt.offset(Vector1D.of(-2.1)), Precision.EPSILON);
128         Assert.assertEquals(0.0, pt.offset(Vector1D.of(-2)), Precision.EPSILON);
129         Assert.assertEquals(0.99, pt.offset(Vector1D.of(-1.01)), Precision.EPSILON);
130         Assert.assertEquals(1.0, pt.offset(Vector1D.of(-1.0)), Precision.EPSILON);
131         Assert.assertEquals(1.01, pt.offset(Vector1D.of(-0.99)), Precision.EPSILON);
132         Assert.assertEquals(2.0, pt.offset(Vector1D.of(0)), Precision.EPSILON);
133         Assert.assertEquals(102, pt.offset(Vector1D.of(100)), Precision.EPSILON);
134     }
135 
136     @Test
137     public void testOffset_negativeFacing() {
138         // arrange
139         final OrientedPoint pt = OrientedPoints.fromPointAndDirection(Vector1D.of(-2.0), false, TEST_PRECISION);
140 
141         // act/assert
142         Assert.assertEquals(98.0, pt.offset(Vector1D.of(-100)), Precision.EPSILON);
143         Assert.assertEquals(0.1, pt.offset(Vector1D.of(-2.1)), Precision.EPSILON);
144         Assert.assertEquals(0.0, pt.offset(Vector1D.of(-2)), Precision.EPSILON);
145         Assert.assertEquals(-0.99, pt.offset(Vector1D.of(-1.01)), Precision.EPSILON);
146         Assert.assertEquals(-1.0, pt.offset(Vector1D.of(-1.0)), Precision.EPSILON);
147         Assert.assertEquals(-1.01, pt.offset(Vector1D.of(-0.99)), Precision.EPSILON);
148         Assert.assertEquals(-2, pt.offset(Vector1D.of(0)), Precision.EPSILON);
149         Assert.assertEquals(-102, pt.offset(Vector1D.of(100)), Precision.EPSILON);
150     }
151 
152     @Test
153     public void testOffset_infinityArguments() {
154         // arrange
155         final OrientedPoint pt = OrientedPoints.fromPointAndDirection(Vector1D.of(-2.0), true, TEST_PRECISION);
156 
157         // act/assert
158         GeometryTestUtils.assertPositiveInfinity(pt.offset(Vector1D.of(Double.POSITIVE_INFINITY)));
159         GeometryTestUtils.assertNegativeInfinity(pt.offset(Vector1D.of(Double.NEGATIVE_INFINITY)));
160     }
161 
162     @Test
163     public void testOffset_infinityLocation() {
164         // arrange
165         final OrientedPoint pt = OrientedPoints.fromPointAndDirection(Vector1D.of(Double.POSITIVE_INFINITY), true, TEST_PRECISION);
166 
167         // act/assert
168         Assert.assertTrue(Double.isNaN(pt.offset(Vector1D.of(Double.POSITIVE_INFINITY))));
169         GeometryTestUtils.assertNegativeInfinity(pt.offset(Vector1D.of(Double.NEGATIVE_INFINITY)));
170 
171         GeometryTestUtils.assertNegativeInfinity(pt.offset(Vector1D.of(0)));
172     }
173 
174     @Test
175     public void testClassify() {
176         // arrange
177         final DoublePrecisionContext smallPrecision = new EpsilonDoublePrecisionContext(1e-10);
178         final DoublePrecisionContext largePrecision = new EpsilonDoublePrecisionContext(1e-1);
179 
180         final OrientedPoint smallPosFacing = OrientedPoints.fromLocationAndDirection(1.0, true, smallPrecision);
181         final OrientedPoint largeNegFacing = OrientedPoints.fromLocationAndDirection(1.0, false, largePrecision);
182 
183         // act/assert
184         assertClassify(HyperplaneLocation.MINUS, smallPosFacing,
185                 Double.NEGATIVE_INFINITY, -10, 0, 0.9, 0.99999, 1 - 1e-9);
186         assertClassify(HyperplaneLocation.ON, smallPosFacing,
187                 1 - 1e-11, 1, 1 + 1e-11);
188         assertClassify(HyperplaneLocation.PLUS, smallPosFacing,
189                 1 + 1e-9, 2, 10, Double.POSITIVE_INFINITY);
190 
191         assertClassify(HyperplaneLocation.PLUS, largeNegFacing,
192                 Double.NEGATIVE_INFINITY, -10, 0, 0.89);
193         assertClassify(HyperplaneLocation.ON, largeNegFacing,
194                 0.91, 0.9999, 1, 1.001, 1.09);
195         assertClassify(HyperplaneLocation.MINUS, largeNegFacing,
196                 1.11, 2, 10, Double.POSITIVE_INFINITY);
197     }
198 
199     @Test
200     public void testSpan() {
201         // arrange
202         final OrientedPoint pt = OrientedPoints.fromPointAndDirection(Vector1D.of(1.0), false, TEST_PRECISION);
203 
204         // act
205         final HyperplaneConvexSubset<Vector1D> result = pt.span();
206 
207         // assert
208         Assert.assertSame(pt, result.getHyperplane());
209     }
210 
211     @Test
212     public void testSimilarOrientation() {
213         // arrange
214         final OrientedPoint negativeDir1 = OrientedPoints.fromPointAndDirection(Vector1D.of(1.0), false, TEST_PRECISION);
215         final OrientedPoint negativeDir2 = OrientedPoints.fromPointAndDirection(Vector1D.of(-1.0), false, TEST_PRECISION);
216         final OrientedPoint positiveDir1 = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, TEST_PRECISION);
217         final OrientedPoint positiveDir2 = OrientedPoints.fromPointAndDirection(Vector1D.of(-2.0), true, TEST_PRECISION);
218 
219         // act/assert
220         Assert.assertTrue(negativeDir1.similarOrientation(negativeDir1));
221         Assert.assertTrue(negativeDir1.similarOrientation(negativeDir2));
222         Assert.assertTrue(negativeDir2.similarOrientation(negativeDir1));
223 
224         Assert.assertTrue(positiveDir1.similarOrientation(positiveDir1));
225         Assert.assertTrue(positiveDir1.similarOrientation(positiveDir2));
226         Assert.assertTrue(positiveDir2.similarOrientation(positiveDir1));
227 
228         Assert.assertFalse(negativeDir1.similarOrientation(positiveDir1));
229         Assert.assertFalse(positiveDir1.similarOrientation(negativeDir1));
230     }
231 
232     @Test
233     public void testProject() {
234         // arrange
235         final OrientedPoint pt = OrientedPoints.fromPointAndDirection(Vector1D.of(1.0), true, TEST_PRECISION);
236 
237         // act/assert
238         Assert.assertEquals(1.0, pt.project(Vector1D.of(-1.0)).getX(), Precision.EPSILON);
239         Assert.assertEquals(1.0, pt.project(Vector1D.of(0.0)).getX(), Precision.EPSILON);
240         Assert.assertEquals(1.0, pt.project(Vector1D.of(1.0)).getX(), Precision.EPSILON);
241         Assert.assertEquals(1.0, pt.project(Vector1D.of(100.0)).getX(), Precision.EPSILON);
242     }
243 
244 
245     @Test
246     public void testEq() {
247         // arrange
248         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-3);
249 
250         final OrientedPoint a = OrientedPoints.createPositiveFacing(0, precision);
251         final OrientedPoint b = OrientedPoints.createPositiveFacing(0, TEST_PRECISION);
252 
253         final OrientedPoint c = OrientedPoints.createPositiveFacing(2e-3, precision);
254         final OrientedPoint d = OrientedPoints.createNegativeFacing(0, precision);
255         final OrientedPoint e = OrientedPoints.createPositiveFacing(1e-4, precision);
256 
257         // act/assert
258         Assert.assertTrue(a.eq(a, precision));
259         Assert.assertTrue(a.eq(b, precision));
260 
261         Assert.assertFalse(a.eq(c, precision));
262         Assert.assertFalse(a.eq(d, precision));
263 
264         Assert.assertTrue(a.eq(e, precision));
265         Assert.assertTrue(e.eq(a, precision));
266     }
267 
268     @Test
269     public void testHashCode() {
270         // arrange
271         final DoublePrecisionContext precisionA = new EpsilonDoublePrecisionContext(1e-10);
272         final DoublePrecisionContext precisionB = new EpsilonDoublePrecisionContext(1e-15);
273 
274         final OrientedPoint a = OrientedPoints.fromPointAndDirection(Vector1D.of(3.0), true, precisionA);
275         final OrientedPoint b = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), false, precisionA);
276         final OrientedPoint c = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, precisionB);
277 
278         final OrientedPoint d = OrientedPoints.fromPointAndDirection(Vector1D.of(3.0), true, precisionA);
279         final OrientedPoint e = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), false, precisionA);
280         final OrientedPoint f = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, precisionB);
281 
282         // act/assert
283         Assert.assertNotEquals(a.hashCode(), b.hashCode());
284         Assert.assertNotEquals(b.hashCode(), c.hashCode());
285         Assert.assertNotEquals(c.hashCode(), a.hashCode());
286 
287         Assert.assertEquals(a.hashCode(), d.hashCode());
288         Assert.assertEquals(b.hashCode(), e.hashCode());
289         Assert.assertEquals(c.hashCode(), f.hashCode());
290     }
291 
292     @Test
293     public void testEquals() {
294         // arrange
295         final DoublePrecisionContext precisionA = new EpsilonDoublePrecisionContext(1e-10);
296         final DoublePrecisionContext precisionB = new EpsilonDoublePrecisionContext(1e-15);
297 
298         final OrientedPoint a = OrientedPoints.fromPointAndDirection(Vector1D.of(1.0), true, precisionA);
299         final OrientedPoint b = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, precisionA);
300 
301         final OrientedPoint c = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, precisionA);
302         final OrientedPoint d = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), false, precisionA);
303 
304         final OrientedPoint e = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, precisionA);
305         final OrientedPoint f = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, precisionB);
306 
307         final OrientedPoint g = OrientedPoints.fromPointAndDirection(Vector1D.of(1.0), true, precisionA);
308 
309         // act/assert
310         Assert.assertFalse(a.equals(null));
311         Assert.assertFalse(a.equals(new Object()));
312 
313         Assert.assertNotEquals(a, b);
314         Assert.assertNotEquals(c, d);
315         Assert.assertNotEquals(e, f);
316 
317         Assert.assertEquals(a, a);
318         Assert.assertEquals(a, g);
319         Assert.assertEquals(g, a);
320     }
321 
322     @Test
323     public void testToString() {
324         // arrange
325         final OrientedPoint pt = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, TEST_PRECISION);
326 
327         // act
328         final String str = pt.toString();
329 
330         // assert
331         Assert.assertTrue(str.contains("OrientedPoint"));
332         Assert.assertTrue(str.contains("point= (2.0)"));
333         Assert.assertTrue(str.contains("direction= (1.0)"));
334     }
335 
336     @Test
337     public void testFromLocationAndDirection() {
338         // act/assert
339         assertOrientedPoint(OrientedPoints.fromLocationAndDirection(3.0, true, TEST_PRECISION),
340                 3.0, true, TEST_PRECISION);
341         assertOrientedPoint(OrientedPoints.fromLocationAndDirection(2.0, false, TEST_PRECISION),
342                 2.0, false, TEST_PRECISION);
343     }
344 
345     @Test
346     public void testFromPointAndDirection_pointAndBooleanArgs() {
347         // act/assert
348         assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(3.0), true, TEST_PRECISION),
349                 3.0, true, TEST_PRECISION);
350         assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), false, TEST_PRECISION),
351                 2.0, false, TEST_PRECISION);
352     }
353 
354     @Test
355     public void testFromPointAndDirection_pointAndVectorArgs() {
356         // act/assert
357         assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(-2.0), Vector1D.of(0.1), TEST_PRECISION),
358                 -2.0, true, TEST_PRECISION);
359         assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), Vector1D.of(-10.1), TEST_PRECISION),
360                 2.0, false, TEST_PRECISION);
361     }
362 
363     @Test
364     public void testFromPointAndDirection_invalidDirection() {
365         // arrange
366         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(0.1);
367 
368         // act/assert
369         GeometryTestUtils.assertThrows(
370             () -> OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), Vector1D.of(0.09), precision),
371             IllegalArgumentException.class, "Oriented point direction cannot be zero");
372         GeometryTestUtils.assertThrows(
373             () -> OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), Vector1D.of(-0.09), precision),
374             IllegalArgumentException.class, "Oriented point direction cannot be zero");
375     }
376 
377     @Test
378     public void testCreatePositiveFacing() {
379         // act/assert
380         assertOrientedPoint(OrientedPoints.createPositiveFacing(Vector1D.of(-2.0), TEST_PRECISION),
381                 -2.0, true, TEST_PRECISION);
382         assertOrientedPoint(OrientedPoints.createPositiveFacing(-4.0, TEST_PRECISION),
383                 -4.0, true, TEST_PRECISION);
384     }
385 
386     @Test
387     public void testCreateNegativeFacing() {
388         // act/assert
389         assertOrientedPoint(OrientedPoints.createNegativeFacing(Vector1D.of(2.0), TEST_PRECISION),
390                 2.0, false, TEST_PRECISION);
391         assertOrientedPoint(OrientedPoints.createNegativeFacing(4, TEST_PRECISION),
392                 4.0, false, TEST_PRECISION);
393     }
394 
395     @Test
396     public void testSubset_split() {
397         // arrange
398         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-3);
399 
400         final OrientedPoint pt = OrientedPoints.createPositiveFacing(-1.5, precision);
401         final HyperplaneConvexSubset<Vector1D> sub = pt.span();
402 
403         // act/assert
404         checkSplit(sub, OrientedPoints.createPositiveFacing(1.0, precision), true, false);
405         checkSplit(sub, OrientedPoints.createPositiveFacing(-1.5 + 1e-2, precision), true, false);
406 
407         checkSplit(sub, OrientedPoints.createNegativeFacing(1.0, precision), false, true);
408         checkSplit(sub, OrientedPoints.createNegativeFacing(-1.5 + 1e-2, precision), false, true);
409 
410         checkSplit(sub, OrientedPoints.createNegativeFacing(-1.5, precision), false, false);
411         checkSplit(sub, OrientedPoints.createNegativeFacing(-1.5 + 1e-4, precision), false, false);
412         checkSplit(sub, OrientedPoints.createNegativeFacing(-1.5 - 1e-4, precision), false, false);
413     }
414 
415     private void checkSplit(final HyperplaneConvexSubset<Vector1D> sub, final OrientedPoint splitter, final boolean minus, final boolean plus) {
416         final Split<? extends HyperplaneConvexSubset<Vector1D>> split = sub.split(splitter);
417 
418         Assert.assertSame(minus ? sub : null, split.getMinus());
419         Assert.assertSame(plus ? sub : null, split.getPlus());
420     }
421 
422     @Test
423     public void testSubset_simpleMethods() {
424         // arrange
425         final OrientedPoint pt = OrientedPoints.createPositiveFacing(2, TEST_PRECISION);
426         final HyperplaneConvexSubset<Vector1D> sub = pt.span();
427 
428         // act/assert
429         Assert.assertSame(pt, sub.getHyperplane());
430         Assert.assertFalse(sub.isFull());
431         Assert.assertFalse(sub.isEmpty());
432         Assert.assertFalse(sub.isInfinite());
433         Assert.assertTrue(sub.isFinite());
434         Assert.assertEquals(0.0, sub.getSize(), TEST_EPS);
435         EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(2), sub.getCentroid(), TEST_EPS);
436 
437         final List<? extends HyperplaneConvexSubset<Vector1D>> list = sub.toConvex();
438         Assert.assertEquals(1, list.size());
439         Assert.assertSame(sub, list.get(0));
440     }
441 
442     @Test
443     public void testSubset_classify() {
444         // arrange
445         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-1);
446         final OrientedPoint pt = OrientedPoints.createPositiveFacing(1, precision);
447         final HyperplaneConvexSubset<Vector1D> sub = pt.span();
448 
449         // act/assert
450         Assert.assertEquals(RegionLocation.BOUNDARY, sub.classify(Vector1D.of(0.95)));
451         Assert.assertEquals(RegionLocation.BOUNDARY, sub.classify(Vector1D.of(1)));
452         Assert.assertEquals(RegionLocation.BOUNDARY, sub.classify(Vector1D.of(1.05)));
453 
454         Assert.assertEquals(RegionLocation.OUTSIDE, sub.classify(Vector1D.of(1.11)));
455         Assert.assertEquals(RegionLocation.OUTSIDE, sub.classify(Vector1D.of(0.89)));
456 
457         Assert.assertEquals(RegionLocation.OUTSIDE, sub.classify(Vector1D.of(-3)));
458         Assert.assertEquals(RegionLocation.OUTSIDE, sub.classify(Vector1D.of(10)));
459 
460         Assert.assertEquals(RegionLocation.OUTSIDE, sub.classify(Vector1D.NEGATIVE_INFINITY));
461         Assert.assertEquals(RegionLocation.OUTSIDE, sub.classify(Vector1D.POSITIVE_INFINITY));
462     }
463 
464     @Test
465     public void testSubset_contains() {
466         // arrange
467         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-1);
468         final OrientedPoint pt = OrientedPoints.createPositiveFacing(1, precision);
469         final HyperplaneConvexSubset<Vector1D> sub = pt.span();
470 
471         // act/assert
472         Assert.assertTrue(sub.contains(Vector1D.of(0.95)));
473         Assert.assertTrue(sub.contains(Vector1D.of(1)));
474         Assert.assertTrue(sub.contains(Vector1D.of(1.05)));
475 
476         Assert.assertFalse(sub.contains(Vector1D.of(1.11)));
477         Assert.assertFalse(sub.contains(Vector1D.of(0.89)));
478 
479         Assert.assertFalse(sub.contains(Vector1D.of(-3)));
480         Assert.assertFalse(sub.contains(Vector1D.of(10)));
481 
482         Assert.assertFalse(sub.contains(Vector1D.NEGATIVE_INFINITY));
483         Assert.assertFalse(sub.contains(Vector1D.POSITIVE_INFINITY));
484     }
485 
486     @Test
487     public void testSubset_closestContained() {
488         // arrange
489         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-1);
490         final OrientedPoint pt = OrientedPoints.createPositiveFacing(1, precision);
491         final HyperplaneConvexSubset<Vector1D> sub = pt.span();
492 
493         // act/assert
494         EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(1), sub.closest(Vector1D.NEGATIVE_INFINITY), TEST_EPS);
495         EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(1), sub.closest(Vector1D.of(0)), TEST_EPS);
496         EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(1), sub.closest(Vector1D.of(1)), TEST_EPS);
497         EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(1), sub.closest(Vector1D.of(2)), TEST_EPS);
498         EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(1), sub.closest(Vector1D.POSITIVE_INFINITY), TEST_EPS);
499     }
500 
501     @Test
502     public void testSubset_transform() {
503         // arrange
504         final AffineTransformMatrix1D scaleAndTranslate = AffineTransformMatrix1D
505                 .createScale(0.5)
506                 .translate(-10);
507 
508         final AffineTransformMatrix1D reflect = AffineTransformMatrix1D.createScale(-2);
509 
510         final HyperplaneConvexSubset<Vector1D> a =
511                 OrientedPoints.createPositiveFacing(Vector1D.of(2.0), TEST_PRECISION).span();
512         final HyperplaneConvexSubset<Vector1D> b =
513                 OrientedPoints.createNegativeFacing(Vector1D.of(-3.0), TEST_PRECISION).span();
514 
515         // act/assert
516         assertOrientedPoint((OrientedPoint) a.transform(scaleAndTranslate).getHyperplane(),
517                 -9.0, true, TEST_PRECISION);
518         assertOrientedPoint((OrientedPoint) b.transform(scaleAndTranslate).getHyperplane(),
519                 -11.5, false, TEST_PRECISION);
520 
521         assertOrientedPoint((OrientedPoint) a.transform(reflect).getHyperplane(), -4.0, false, TEST_PRECISION);
522         assertOrientedPoint((OrientedPoint) b.transform(reflect).getHyperplane(), 6.0, true, TEST_PRECISION);
523     }
524 
525     @Test
526     public void testSubset_reverse() {
527         // arrange
528         final OrientedPoint pt = OrientedPoints.createPositiveFacing(2.0, TEST_PRECISION);
529         final HyperplaneConvexSubset<Vector1D> sub = pt.span();
530 
531         // act
532         final HyperplaneConvexSubset<Vector1D> result = sub.reverse();
533 
534         // assert
535         Assert.assertEquals(2.0, ((OrientedPoint) result.getHyperplane()).getLocation(), TEST_EPS);
536         Assert.assertFalse(((OrientedPoint) result.getHyperplane()).isPositiveFacing());
537 
538         Assert.assertEquals(sub.getHyperplane(), result.reverse().getHyperplane());
539     }
540 
541     @Test
542     public void testSubset_toString() {
543         // arrange
544         final OrientedPoint pt = OrientedPoints.createPositiveFacing(2, TEST_PRECISION);
545         final HyperplaneConvexSubset<Vector1D> sub = pt.span();
546 
547         // act
548         final String str = sub.toString();
549 
550         //assert
551         Assert.assertTrue(str.contains("OrientedPointConvexSubset"));
552         Assert.assertTrue(str.contains("point= (2.0)"));
553         Assert.assertTrue(str.contains("direction= (1.0)"));
554     }
555 
556     private static void assertOrientedPoint(final OrientedPoint pt, final double location, final boolean positiveFacing,
557                                             final DoublePrecisionContext precision) {
558         Assert.assertEquals(location, pt.getPoint().getX(), TEST_EPS);
559         Assert.assertEquals(location, pt.getLocation(), TEST_EPS);
560         Assert.assertEquals(positiveFacing ? 1.0 : -1.0, pt.getDirection().getX(), TEST_EPS);
561         Assert.assertEquals(positiveFacing, pt.isPositiveFacing());
562         Assert.assertSame(precision, pt.getPrecision());
563     }
564 
565     private static void assertClassify(final HyperplaneLocation expected, final OrientedPoint pt, final double... locations) {
566         for (final double location : locations) {
567             final String msg = "Unexpected classification for location " + location;
568 
569             Assert.assertEquals(msg, expected, pt.classify(location));
570             Assert.assertEquals(msg, expected, pt.classify(Vector1D.of(location)));
571         }
572     }
573 }