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 org.apache.commons.geometry.core.GeometryTestUtils;
20  import org.apache.commons.geometry.core.RegionLocation;
21  import org.apache.commons.geometry.core.partitioning.Split;
22  import org.apache.commons.geometry.core.partitioning.SplitLocation;
23  import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
24  import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
25  import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
26  import org.junit.Assert;
27  import org.junit.Test;
28  
29  public class IntervalTest {
30  
31      private static final double TEST_EPS = 1e-15;
32  
33      private static final DoublePrecisionContext TEST_PRECISION =
34              new EpsilonDoublePrecisionContext(TEST_EPS);
35  
36      @Test
37      public void testOf_doubles() {
38          // act/assert
39          checkInterval(Interval.of(0, 0, TEST_PRECISION), 0, 0);
40  
41          checkInterval(Interval.of(1, 2, TEST_PRECISION), 1, 2);
42          checkInterval(Interval.of(2, 1, TEST_PRECISION), 1, 2);
43  
44          checkInterval(Interval.of(-2, -1, TEST_PRECISION), -2, -1);
45          checkInterval(Interval.of(-1, -2, TEST_PRECISION), -2, -1);
46  
47          checkInterval(Interval.of(1, Double.POSITIVE_INFINITY, TEST_PRECISION),
48                  1, Double.POSITIVE_INFINITY);
49          checkInterval(Interval.of(Double.POSITIVE_INFINITY, 1, TEST_PRECISION),
50                  1, Double.POSITIVE_INFINITY);
51  
52          checkInterval(Interval.of(Double.NEGATIVE_INFINITY, 1, TEST_PRECISION),
53                  Double.NEGATIVE_INFINITY, 1);
54          checkInterval(Interval.of(1, Double.NEGATIVE_INFINITY, TEST_PRECISION),
55                  Double.NEGATIVE_INFINITY, 1);
56  
57          checkInterval(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION),
58                  Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
59  
60          checkInterval(Interval.of(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, TEST_PRECISION),
61                  Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
62      }
63  
64      @Test
65      public void testOf_doubles_invalidIntervals() {
66          // arrange
67          final Class<?> excType = IllegalArgumentException.class;
68  
69          // act/assert
70          GeometryTestUtils.assertThrows(() -> Interval.of(1, Double.NaN, TEST_PRECISION), excType);
71          GeometryTestUtils.assertThrows(() -> Interval.of(Double.NaN, 1, TEST_PRECISION), excType);
72          GeometryTestUtils.assertThrows(() -> Interval.of(Double.NaN, Double.NaN, TEST_PRECISION), excType);
73  
74          GeometryTestUtils.assertThrows(
75              () -> Interval.of(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION), excType);
76          GeometryTestUtils.assertThrows(
77              () -> Interval.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, TEST_PRECISION), excType);
78      }
79  
80      @Test
81      public void testOf_points() {
82          // act/assert
83          checkInterval(Interval.of(Vector1D.of(1), Vector1D.of(2), TEST_PRECISION), 1, 2);
84          checkInterval(Interval.of(Vector1D.of(Double.POSITIVE_INFINITY), Vector1D.of(Double.NEGATIVE_INFINITY), TEST_PRECISION),
85                  Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
86      }
87  
88      @Test
89      public void testOf_points_invalidIntervals() {
90          // arrange
91          final Class<?> excType = IllegalArgumentException.class;
92  
93          // act/assert
94          GeometryTestUtils.assertThrows(
95              () -> Interval.of(Vector1D.of(1), Vector1D.of(Double.NaN), TEST_PRECISION), excType);
96          GeometryTestUtils.assertThrows(
97              () -> Interval.of(Vector1D.of(Double.POSITIVE_INFINITY), Vector1D.of(Double.POSITIVE_INFINITY), TEST_PRECISION), excType);
98      }
99  
100     @Test
101     public void testOf_hyperplanes() {
102         // act/assert
103         checkInterval(Interval.of(
104                 OrientedPoints.fromLocationAndDirection(1, true, TEST_PRECISION),
105                 OrientedPoints.fromLocationAndDirection(1, false, TEST_PRECISION)), 1, 1);
106         checkInterval(Interval.of(
107                 OrientedPoints.fromLocationAndDirection(1, false, TEST_PRECISION),
108                 OrientedPoints.fromLocationAndDirection(1, true, TEST_PRECISION)), 1, 1);
109 
110         checkInterval(Interval.of(
111                 OrientedPoints.fromLocationAndDirection(-2, false, TEST_PRECISION),
112                 OrientedPoints.fromLocationAndDirection(5, true, TEST_PRECISION)), -2, 5);
113         checkInterval(Interval.of(
114                 OrientedPoints.fromLocationAndDirection(5, true, TEST_PRECISION),
115                 OrientedPoints.fromLocationAndDirection(-2, false, TEST_PRECISION)), -2, 5);
116 
117         checkInterval(Interval.of(
118                 null,
119                 OrientedPoints.fromLocationAndDirection(5, true, TEST_PRECISION)), Double.NEGATIVE_INFINITY, 5);
120         checkInterval(Interval.of(
121                 OrientedPoints.fromLocationAndDirection(5, true, TEST_PRECISION),
122                 null), Double.NEGATIVE_INFINITY, 5);
123         checkInterval(Interval.of(
124                 OrientedPoints.fromLocationAndDirection(Double.NEGATIVE_INFINITY, false, TEST_PRECISION),
125                 OrientedPoints.fromLocationAndDirection(5, true, TEST_PRECISION)), Double.NEGATIVE_INFINITY, 5);
126 
127         checkInterval(Interval.of(
128                 null,
129                 OrientedPoints.fromLocationAndDirection(5, false, TEST_PRECISION)), 5, Double.POSITIVE_INFINITY);
130         checkInterval(Interval.of(
131                 OrientedPoints.fromLocationAndDirection(5, false, TEST_PRECISION),
132                 null), 5, Double.POSITIVE_INFINITY);
133         checkInterval(Interval.of(
134                 OrientedPoints.fromLocationAndDirection(Double.POSITIVE_INFINITY, true, TEST_PRECISION),
135                 OrientedPoints.fromLocationAndDirection(5, false, TEST_PRECISION)), 5, Double.POSITIVE_INFINITY);
136     }
137 
138     @Test
139     public void testOf_hyperplanes_invalidArgs() {
140         // arrange
141         final Class<?> excType = IllegalArgumentException.class;
142 
143         // act/assert
144         GeometryTestUtils.assertThrows(
145             () -> Interval.of(
146                     OrientedPoints.fromLocationAndDirection(1, false, TEST_PRECISION),
147                     OrientedPoints.fromLocationAndDirection(1, false, TEST_PRECISION)), excType);
148 
149         GeometryTestUtils.assertThrows(
150             () -> Interval.of(
151                     OrientedPoints.fromLocationAndDirection(2, false, TEST_PRECISION),
152                     OrientedPoints.fromLocationAndDirection(1, true, TEST_PRECISION)), excType);
153 
154         GeometryTestUtils.assertThrows(
155             () -> Interval.of(
156                     OrientedPoints.fromLocationAndDirection(Double.POSITIVE_INFINITY, false, TEST_PRECISION),
157                     OrientedPoints.fromLocationAndDirection(Double.POSITIVE_INFINITY, true, TEST_PRECISION)), excType);
158 
159         GeometryTestUtils.assertThrows(
160             () -> Interval.of(
161                     OrientedPoints.fromLocationAndDirection(Double.NaN, false, TEST_PRECISION),
162                     OrientedPoints.fromLocationAndDirection(1, true, TEST_PRECISION)), excType);
163 
164         GeometryTestUtils.assertThrows(
165             () -> Interval.of(
166                     OrientedPoints.fromLocationAndDirection(1, false, TEST_PRECISION),
167                     OrientedPoints.fromLocationAndDirection(Double.NaN, true, TEST_PRECISION)), excType);
168 
169         GeometryTestUtils.assertThrows(
170             () -> Interval.of(
171                     OrientedPoints.fromLocationAndDirection(Double.NaN, false, TEST_PRECISION),
172                     OrientedPoints.fromLocationAndDirection(Double.NaN, true, TEST_PRECISION)), excType);
173     }
174 
175     @Test
176     public void testPoint() {
177         // act/assert
178         checkInterval(Interval.point(0, TEST_PRECISION), 0, 0);
179         checkInterval(Interval.point(1, TEST_PRECISION), 1, 1);
180         checkInterval(Interval.point(-1, TEST_PRECISION), -1, -1);
181     }
182 
183     @Test
184     public void testPoint_invalidArgs() {
185         // arrange
186         final Class<?> excType = IllegalArgumentException.class;
187 
188         // act/assert
189         GeometryTestUtils.assertThrows(
190             () -> Interval.point(Double.NEGATIVE_INFINITY, TEST_PRECISION), excType);
191         GeometryTestUtils.assertThrows(
192             () -> Interval.point(Double.POSITIVE_INFINITY, TEST_PRECISION), excType);
193         GeometryTestUtils.assertThrows(
194             () -> Interval.point(Double.NaN, TEST_PRECISION), excType);
195     }
196 
197     @Test
198     public void testMin() {
199         // act/assert
200         checkInterval(Interval.min(Double.NEGATIVE_INFINITY, TEST_PRECISION),
201                 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
202 
203         checkInterval(Interval.min(0, TEST_PRECISION), 0, Double.POSITIVE_INFINITY);
204         checkInterval(Interval.min(1, TEST_PRECISION), 1, Double.POSITIVE_INFINITY);
205         checkInterval(Interval.min(-1, TEST_PRECISION), -1, Double.POSITIVE_INFINITY);
206     }
207 
208     @Test
209     public void testMin_invalidArgs() {
210         // arrange
211         final Class<?> excType = IllegalArgumentException.class;
212 
213         // act/assert
214         GeometryTestUtils.assertThrows(
215             () -> Interval.min(Double.POSITIVE_INFINITY, TEST_PRECISION), excType);
216         GeometryTestUtils.assertThrows(
217             () -> Interval.min(Double.NaN, TEST_PRECISION), excType);
218     }
219 
220     @Test
221     public void testMax() {
222         // act/assert
223         checkInterval(Interval.max(Double.POSITIVE_INFINITY, TEST_PRECISION),
224                 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
225 
226         checkInterval(Interval.max(0, TEST_PRECISION), Double.NEGATIVE_INFINITY, 0);
227         checkInterval(Interval.max(1, TEST_PRECISION), Double.NEGATIVE_INFINITY, 1);
228         checkInterval(Interval.max(-1, TEST_PRECISION), Double.NEGATIVE_INFINITY, -1);
229     }
230 
231     @Test
232     public void testMax_invalidArgs() {
233         // arrange
234         final Class<?> excType = IllegalArgumentException.class;
235 
236         // act/assert
237         GeometryTestUtils.assertThrows(
238             () -> Interval.max(Double.NEGATIVE_INFINITY, TEST_PRECISION), excType);
239         GeometryTestUtils.assertThrows(
240             () -> Interval.max(Double.NaN, TEST_PRECISION), excType);
241     }
242 
243     @Test
244     public void testIsInfinite() {
245         // act/assert
246         Assert.assertFalse(Interval.of(1, 2, TEST_PRECISION).isInfinite());
247 
248         Assert.assertTrue(Interval.of(Double.NEGATIVE_INFINITY, 2, TEST_PRECISION).isInfinite());
249         Assert.assertTrue(Interval.of(2, Double.POSITIVE_INFINITY, TEST_PRECISION).isInfinite());
250         Assert.assertTrue(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).isInfinite());
251     }
252 
253     @Test
254     public void testIsFinite() {
255         // act/assert
256         Assert.assertTrue(Interval.of(1, 2, TEST_PRECISION).isFinite());
257 
258         Assert.assertFalse(Interval.of(Double.NEGATIVE_INFINITY, 2, TEST_PRECISION).isFinite());
259         Assert.assertFalse(Interval.of(2, Double.POSITIVE_INFINITY, TEST_PRECISION).isFinite());
260         Assert.assertFalse(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).isFinite());
261     }
262 
263     @Test
264     public void testClassify_finite() {
265         // arrange
266         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-2);
267         final Interval interval = Interval.of(-1, 1, precision);
268 
269         // act/assert
270         checkClassify(interval, RegionLocation.OUTSIDE,
271                 Double.NEGATIVE_INFINITY, -2, -1.1,
272                 1.1, 2, Double.POSITIVE_INFINITY);
273 
274         checkClassify(interval, RegionLocation.BOUNDARY,
275                 -1.001, -1, -0.999,
276                 0.999, 1, 1.001);
277 
278         checkClassify(interval, RegionLocation.INSIDE, -0.9, 0, 0.9);
279 
280         checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
281     }
282 
283     @Test
284     public void testClassify_singlePoint() {
285         // arrange
286         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-2);
287         final Interval interval = Interval.of(1, 1, precision);
288 
289         // act/assert
290         checkClassify(interval, RegionLocation.OUTSIDE,
291                 Double.NEGATIVE_INFINITY, 0, 0.9, 1.1, 2, Double.POSITIVE_INFINITY);
292 
293         checkClassify(interval, RegionLocation.BOUNDARY,
294                 0.999, 1, 1.0001);
295 
296         checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
297     }
298 
299     @Test
300     public void testClassify_maxInfinite() {
301         // arrange
302         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-2);
303         final Interval interval = Interval.of(-1, Double.POSITIVE_INFINITY, precision);
304 
305         // act/assert
306         checkClassify(interval, RegionLocation.OUTSIDE,
307                 Double.NEGATIVE_INFINITY, -2, -1.1);
308 
309         checkClassify(interval, RegionLocation.BOUNDARY,
310                 -1.001, -1, -0.999);
311 
312         checkClassify(interval, RegionLocation.INSIDE,
313                 -0.9, 0, 1.0, Double.POSITIVE_INFINITY);
314 
315         checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
316     }
317 
318     @Test
319     public void testClassify_minInfinite() {
320         // arrange
321         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-2);
322         final Interval interval = Interval.of(Double.NEGATIVE_INFINITY, 1, precision);
323 
324         // act/assert
325         checkClassify(interval, RegionLocation.INSIDE,
326                 Double.NEGATIVE_INFINITY, 0, 0.9);
327 
328         checkClassify(interval, RegionLocation.BOUNDARY,
329                 0.999, 1, 1.001);
330 
331         checkClassify(interval, RegionLocation.OUTSIDE,
332                 1.1, 2, Double.POSITIVE_INFINITY);
333 
334         checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
335     }
336 
337     @Test
338     public void testClassify_minMaxInfinite() {
339         // arrange
340         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-2);
341         final Interval interval = Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, precision);
342 
343         // act/assert
344         checkClassify(interval, RegionLocation.INSIDE,
345                 Double.NEGATIVE_INFINITY, -1, 0, 1, Double.POSITIVE_INFINITY);
346 
347         checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
348     }
349 
350     @Test
351     public void testContains_finite() {
352         // arrange
353         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-2);
354         final Interval interval = Interval.of(-1, 1, precision);
355 
356         // act/assert
357         checkContains(interval, true,
358                 -1.001, -1, -0.999,
359                 0.999, 1, 1.001,
360 
361                 -0.9, 0, 0.9);
362 
363         checkContains(interval, false,
364                 Double.NEGATIVE_INFINITY, -2, -1.1,
365                 1.1, 2, Double.POSITIVE_INFINITY);
366 
367         checkContains(interval, false, Double.NaN);
368     }
369 
370     @Test
371     public void testIsFull() {
372         // act/assert
373         Assert.assertFalse(Interval.of(1, 1, TEST_PRECISION).isFull());
374         Assert.assertFalse(Interval.of(-2, 2, TEST_PRECISION).isFull());
375 
376         Assert.assertFalse(Interval.of(1, Double.POSITIVE_INFINITY, TEST_PRECISION).isFull());
377         Assert.assertFalse(Interval.of(Double.NEGATIVE_INFINITY, 1, TEST_PRECISION).isFull());
378 
379         Assert.assertTrue(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).isFull());
380     }
381 
382     @Test
383     public void testGetSize() {
384         // act/assert
385         Assert.assertEquals(0, Interval.of(1, 1, TEST_PRECISION).getSize(), TEST_EPS);
386 
387         Assert.assertEquals(4, Interval.of(-2, 2, TEST_PRECISION).getSize(), TEST_EPS);
388         Assert.assertEquals(5, Interval.of(2, -3, TEST_PRECISION).getSize(), TEST_EPS);
389 
390         Assert.assertEquals(Double.POSITIVE_INFINITY,
391                 Interval.of(1, Double.POSITIVE_INFINITY, TEST_PRECISION).getSize(), TEST_EPS);
392         Assert.assertEquals(Double.POSITIVE_INFINITY,
393                 Interval.of(Double.NEGATIVE_INFINITY, 1, TEST_PRECISION).getSize(), TEST_EPS);
394 
395         Assert.assertEquals(Double.POSITIVE_INFINITY,
396                 Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).getSize(), TEST_EPS);
397     }
398 
399     @Test
400     public void testGetBoundarySize() {
401         // act/assert
402         Assert.assertEquals(0, Interval.of(1, 1, TEST_PRECISION).getBoundarySize(), TEST_EPS);
403         Assert.assertEquals(0, Interval.of(-2, 5, TEST_PRECISION).getBoundarySize(), TEST_EPS);
404         Assert.assertEquals(0, Interval.full().getBoundarySize(), TEST_EPS);
405     }
406 
407     @Test
408     public void testGetCentroid() {
409         // act/assert
410         EuclideanTestUtils.assertCoordinatesEqual(Vector1D.ZERO,
411                 Interval.of(-1, 1, TEST_PRECISION).getCentroid(), TEST_EPS);
412         EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(10),
413                 Interval.of(10, 10, TEST_PRECISION).getCentroid(), TEST_EPS);
414 
415         EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(2),
416                 Interval.of(1, 3, TEST_PRECISION).getCentroid(), TEST_EPS);
417         EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(-1),
418                 Interval.of(-2, 0, TEST_PRECISION).getCentroid(), TEST_EPS);
419 
420         Assert.assertNull(Interval.of(1, Double.POSITIVE_INFINITY, TEST_PRECISION).getCentroid());
421         Assert.assertNull(Interval.of(Double.NEGATIVE_INFINITY, 1, TEST_PRECISION).getCentroid());
422         Assert.assertNull(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).getCentroid());
423     }
424 
425     @Test
426     public void checkToTree_finite() {
427         // arrange
428         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-2);
429         final Interval interval = Interval.of(-1, 1, precision);
430 
431         // act
432         final RegionBSPTree1D tree = interval.toTree();
433 
434         // assert
435         Assert.assertEquals(5, tree.count());
436 
437         checkClassify(tree, RegionLocation.OUTSIDE,
438                 Double.NEGATIVE_INFINITY, -2, -1.1,
439                 1.1, 2, Double.POSITIVE_INFINITY);
440 
441         checkClassify(tree, RegionLocation.BOUNDARY,
442                 -1.001, -1, -0.999,
443                 0.999, 1, 1.001);
444 
445         checkClassify(tree, RegionLocation.INSIDE, -0.9, 0, 0.9);
446 
447         checkClassify(tree, RegionLocation.OUTSIDE, Double.NaN);
448     }
449 
450     @Test
451     public void checkToTree_singlePoint() {
452         // arrange
453         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-2);
454         final Interval interval = Interval.of(1, 1, precision);
455 
456         // act
457         final RegionBSPTree1D tree = interval.toTree();
458 
459         // assert
460         Assert.assertEquals(5, tree.count());
461 
462         checkClassify(tree, RegionLocation.OUTSIDE,
463                 Double.NEGATIVE_INFINITY, 0, 0.9, 1.1, 2, Double.POSITIVE_INFINITY);
464 
465         checkClassify(tree, RegionLocation.BOUNDARY,
466                 0.999, 1, 1.0001);
467 
468         checkClassify(tree, RegionLocation.OUTSIDE, Double.NaN);
469     }
470 
471     @Test
472     public void checkToTree_maxInfinite() {
473         // arrange
474         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-2);
475         final Interval interval = Interval.of(-1, Double.POSITIVE_INFINITY, precision);
476 
477         // act
478         final RegionBSPTree1D tree = interval.toTree();
479 
480         // assert
481         Assert.assertEquals(3, tree.count());
482 
483         checkClassify(tree, RegionLocation.OUTSIDE,
484                 Double.NEGATIVE_INFINITY, -2, -1.1);
485 
486         checkClassify(tree, RegionLocation.BOUNDARY,
487                 -1.001, -1, -0.999);
488 
489         checkClassify(tree, RegionLocation.INSIDE,
490                 -0.9, 0, 1.0, Double.POSITIVE_INFINITY);
491 
492         checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
493     }
494 
495     @Test
496     public void checkToTree_minInfinite() {
497         // arrange
498         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-2);
499         final Interval interval = Interval.of(Double.NEGATIVE_INFINITY, 1, precision);
500 
501         // act
502         final RegionBSPTree1D tree = interval.toTree();
503 
504         // assert
505         Assert.assertEquals(3, tree.count());
506 
507         checkClassify(tree, RegionLocation.INSIDE,
508                 Double.NEGATIVE_INFINITY, 0, 0.9);
509 
510         checkClassify(tree, RegionLocation.BOUNDARY,
511                 0.999, 1, 1.001);
512 
513         checkClassify(tree, RegionLocation.OUTSIDE,
514                 1.1, 2, Double.POSITIVE_INFINITY);
515 
516         checkClassify(tree, RegionLocation.OUTSIDE, Double.NaN);
517     }
518 
519     @Test
520     public void checkToTree_minMaxInfinite() {
521         // arrange
522         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-2);
523         final Interval interval = Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, precision);
524 
525         // act
526         final RegionBSPTree1D tree = interval.toTree();
527 
528         // assert
529         Assert.assertEquals(1, tree.count());
530 
531         checkClassify(tree, RegionLocation.INSIDE,
532                 Double.NEGATIVE_INFINITY, -1, 0, 1, Double.POSITIVE_INFINITY);
533 
534         checkClassify(tree, RegionLocation.OUTSIDE, Double.NaN);
535     }
536 
537     @Test
538     public void testProjectToBoundary_full() {
539         // arrange
540         final Interval full = Interval.full();
541 
542 
543         // act/assert
544         Assert.assertNull(full.project(Vector1D.of(Double.NEGATIVE_INFINITY)));
545         Assert.assertNull(full.project(Vector1D.of(0)));
546         Assert.assertNull(full.project(Vector1D.of(Double.POSITIVE_INFINITY)));
547     }
548 
549     @Test
550     public void testProjectToBoundary_singlePoint() {
551         // arrange
552         final Interval interval = Interval.point(1, TEST_PRECISION);
553 
554         // act/assert
555         checkBoundaryProjection(interval, -1, 1);
556         checkBoundaryProjection(interval, 0, 1);
557 
558         checkBoundaryProjection(interval, 1, 1);
559 
560         checkBoundaryProjection(interval, 2, 1);
561         checkBoundaryProjection(interval, 3, 1);
562 
563         checkBoundaryProjection(interval, Double.NEGATIVE_INFINITY, 1);
564         checkBoundaryProjection(interval, Double.POSITIVE_INFINITY, 1);
565     }
566 
567     @Test
568     public void testProjectToBoundary_closedInterval() {
569         // arrange
570         final Interval interval = Interval.of(1, 3, TEST_PRECISION);
571 
572         // act/assert
573         checkBoundaryProjection(interval, -1, 1);
574         checkBoundaryProjection(interval, 0, 1);
575         checkBoundaryProjection(interval, 1, 1);
576 
577         checkBoundaryProjection(interval, 1.9, 1);
578         checkBoundaryProjection(interval, 2, 1);
579         checkBoundaryProjection(interval, 2.1, 3);
580 
581         checkBoundaryProjection(interval, 3, 3);
582         checkBoundaryProjection(interval, 4, 3);
583         checkBoundaryProjection(interval, 5, 3);
584 
585         checkBoundaryProjection(interval, Double.NEGATIVE_INFINITY, 1);
586         checkBoundaryProjection(interval, Double.POSITIVE_INFINITY, 3);
587     }
588 
589     @Test
590     public void testProjectToBoundary_noMinBoundary() {
591         // arrange
592         final Interval interval = Interval.of(Double.NEGATIVE_INFINITY, 1, TEST_PRECISION);
593 
594         // act/assert
595         checkBoundaryProjection(interval, -1, 1);
596         checkBoundaryProjection(interval, 0, 1);
597         checkBoundaryProjection(interval, 1, 1);
598         checkBoundaryProjection(interval, 2, 1);
599         checkBoundaryProjection(interval, 3, 1);
600 
601         checkBoundaryProjection(interval, Double.NEGATIVE_INFINITY, 1);
602         checkBoundaryProjection(interval, Double.POSITIVE_INFINITY, 1);
603     }
604 
605     @Test
606     public void testProjectToBoundary_noMaxBoundary() {
607         // arrange
608         final Interval interval = Interval.of(1, Double.POSITIVE_INFINITY, TEST_PRECISION);
609 
610         // act/assert
611         checkBoundaryProjection(interval, -1, 1);
612         checkBoundaryProjection(interval, 0, 1);
613         checkBoundaryProjection(interval, 1, 1);
614         checkBoundaryProjection(interval, 2, 1);
615         checkBoundaryProjection(interval, 3, 1);
616 
617         checkBoundaryProjection(interval, Double.NEGATIVE_INFINITY, 1);
618         checkBoundaryProjection(interval, Double.POSITIVE_INFINITY, 1);
619     }
620 
621     @Test
622     public void testTransform() {
623         // arrange
624         final AffineTransformMatrix1D transform = AffineTransformMatrix1D.createScale(2);
625 
626         // act/assert
627         checkInterval(Interval.of(-1, 2, TEST_PRECISION).transform(transform), -2, 4);
628 
629         checkInterval(Interval.of(Double.NEGATIVE_INFINITY, 2, TEST_PRECISION).transform(transform),
630                 Double.NEGATIVE_INFINITY, 4);
631 
632         checkInterval(Interval.of(-1, Double.POSITIVE_INFINITY, TEST_PRECISION).transform(transform), -2,
633                 Double.POSITIVE_INFINITY);
634 
635         checkInterval(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).transform(transform),
636                 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
637     }
638 
639     @Test
640     public void testTransform_reflection() {
641         // arrange
642         final AffineTransformMatrix1D transform = AffineTransformMatrix1D.createScale(-1);
643 
644         // act/assert
645         checkInterval(Interval.of(-1, 2, TEST_PRECISION).transform(transform), -2, 1);
646 
647         checkInterval(Interval.of(Double.NEGATIVE_INFINITY, 2, TEST_PRECISION).transform(transform),
648                 -2, Double.POSITIVE_INFINITY);
649 
650         checkInterval(Interval.of(-1, Double.POSITIVE_INFINITY, TEST_PRECISION).transform(transform),
651                 Double.NEGATIVE_INFINITY, 1);
652     }
653 
654     @Test
655     public void testSplit_full_positiveFacingSplitter() {
656         // arrange
657         final Interval interval = Interval.full();
658         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
659                 Vector1D.of(1), true, TEST_PRECISION);
660 
661         // act
662         final Split<Interval> split = interval.split(splitter);
663 
664         // assert
665         Assert.assertEquals(SplitLocation.BOTH, split.getLocation());
666 
667         checkInterval(split.getMinus(), Double.NEGATIVE_INFINITY, 1);
668         checkInterval(split.getPlus(), 1, Double.POSITIVE_INFINITY);
669     }
670 
671     @Test
672     public void testSplit_full_negativeFacingSplitter() {
673         // arrange
674         final Interval interval = Interval.full();
675         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
676                 Vector1D.of(1), true, TEST_PRECISION);
677 
678         // act
679         final Split<Interval> split = interval.split(splitter);
680 
681         // assert
682         Assert.assertEquals(SplitLocation.BOTH, split.getLocation());
683 
684         checkInterval(split.getMinus(), Double.NEGATIVE_INFINITY, 1);
685         checkInterval(split.getPlus(), 1, Double.POSITIVE_INFINITY);
686     }
687 
688     @Test
689     public void testSplit_halfSpace_positiveFacingSplitter() {
690         // arrange
691         final Interval interval = Interval.min(-1, TEST_PRECISION);
692         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
693                 Vector1D.of(1), false, TEST_PRECISION);
694 
695         // act
696         final Split<Interval> split = interval.split(splitter);
697 
698         // assert
699         Assert.assertEquals(SplitLocation.BOTH, split.getLocation());
700 
701         checkInterval(split.getMinus(), 1, Double.POSITIVE_INFINITY);
702         checkInterval(split.getPlus(), -1, 1);
703     }
704 
705 
706     @Test
707     public void testSplit_halfSpace_negativeFacingSplitter() {
708         // arrange
709         final Interval interval = Interval.min(-1, TEST_PRECISION);
710         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
711                 Vector1D.of(1), false, TEST_PRECISION);
712 
713         // act
714         final Split<Interval> split = interval.split(splitter);
715 
716         // assert
717         Assert.assertEquals(SplitLocation.BOTH, split.getLocation());
718 
719         checkInterval(split.getMinus(), 1, Double.POSITIVE_INFINITY);
720         checkInterval(split.getPlus(), -1, 1);
721     }
722 
723     @Test
724     public void testSplit_splitterBelowInterval() {
725         // arrange
726         final Interval interval = Interval.of(5, 10, TEST_PRECISION);
727         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
728                 Vector1D.of(1), true, TEST_PRECISION);
729 
730         // act
731         final Split<Interval> split = interval.split(splitter);
732 
733         // assert
734         Assert.assertEquals(SplitLocation.PLUS, split.getLocation());
735 
736         Assert.assertSame(interval, split.getPlus());
737     }
738 
739     @Test
740     public void testSplit_splitterOnMinBoundary() {
741         // arrange
742         final Interval interval = Interval.of(5, 10, TEST_PRECISION);
743         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
744                 Vector1D.of(5), false, TEST_PRECISION);
745 
746         // act
747         final Split<Interval> split = interval.split(splitter);
748 
749         // assert
750         Assert.assertEquals(SplitLocation.MINUS, split.getLocation());
751 
752         Assert.assertSame(interval, split.getMinus());
753     }
754 
755     @Test
756     public void testSplit_splitterAboveInterval() {
757         // arrange
758         final Interval interval = Interval.of(5, 10, TEST_PRECISION);
759         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
760                 Vector1D.of(11), true, TEST_PRECISION);
761 
762         // act
763         final Split<Interval> split = interval.split(splitter);
764 
765         // assert
766         Assert.assertEquals(SplitLocation.MINUS, split.getLocation());
767 
768         Assert.assertSame(interval, split.getMinus());
769     }
770 
771     @Test
772     public void testSplit_splitterOnMaxBoundary() {
773         // arrange
774         final Interval interval = Interval.of(5, 10, TEST_PRECISION);
775         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
776                 Vector1D.of(10), false, TEST_PRECISION);
777 
778         // act
779         final Split<Interval> split = interval.split(splitter);
780 
781         // assert
782         Assert.assertEquals(SplitLocation.PLUS, split.getLocation());
783 
784         Assert.assertSame(interval, split.getPlus());
785     }
786 
787     @Test
788     public void testSplit_point_minusOnly() {
789         // arrange
790         final Interval interval = Interval.point(2, TEST_PRECISION);
791         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
792                 Vector1D.of(1), false, TEST_PRECISION);
793 
794         // act
795         final Split<Interval> split = interval.split(splitter);
796 
797         // assert
798         Assert.assertEquals(SplitLocation.MINUS, split.getLocation());
799 
800         checkInterval(split.getMinus(), 2, 2);
801         Assert.assertNull(split.getPlus());
802     }
803 
804     @Test
805     public void testSplit_point_plusOnly() {
806         // arrange
807         final Interval interval = Interval.point(2, TEST_PRECISION);
808         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
809                 Vector1D.of(1), true, TEST_PRECISION);
810 
811         // act
812         final Split<Interval> split = interval.split(splitter);
813 
814         // assert
815         Assert.assertEquals(SplitLocation.PLUS, split.getLocation());
816 
817         Assert.assertNull(split.getMinus());
818         checkInterval(split.getPlus(), 2, 2);
819     }
820 
821     @Test
822     public void testSplit_point_onPoint() {
823         // arrange
824         final Interval interval = Interval.point(1, TEST_PRECISION);
825         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
826                 Vector1D.of(1), true, TEST_PRECISION);
827 
828         // act
829         final Split<Interval> split = interval.split(splitter);
830 
831         // assert
832         Assert.assertEquals(SplitLocation.NEITHER, split.getLocation());
833 
834         Assert.assertNull(split.getMinus());
835         Assert.assertNull(split.getPlus());
836     }
837 
838     @Test
839     public void testToString() {
840         // arrange
841         final Interval interval = Interval.of(2, 1, TEST_PRECISION);
842 
843         // act
844         final String str = interval.toString();
845 
846         // assert
847         Assert.assertTrue(str.contains("Interval"));
848         Assert.assertTrue(str.contains("min= 1.0"));
849         Assert.assertTrue(str.contains("max= 2.0"));
850     }
851 
852     @Test
853     public void testFull() {
854         // act
855         final Interval full = Interval.full();
856 
857         // assert
858         Assert.assertTrue(full.isFull());
859         Assert.assertFalse(full.isEmpty());
860         Assert.assertFalse(full.hasMinBoundary());
861         Assert.assertFalse(full.hasMaxBoundary());
862         Assert.assertTrue(full.isInfinite());
863 
864         Assert.assertEquals(RegionLocation.INSIDE, full.classify(Double.NEGATIVE_INFINITY));
865         Assert.assertEquals(RegionLocation.INSIDE, full.classify(Double.POSITIVE_INFINITY));
866     }
867 
868     private static void checkContains(final Interval interval, final boolean contains, final double... points) {
869         for (final double x : points) {
870             final String msg = "Unexpected contains status for point " + x;
871 
872             Assert.assertEquals(msg, contains, interval.contains(x));
873             Assert.assertEquals(msg, contains, interval.contains(Vector1D.of(x)));
874         }
875     }
876 
877     private static void checkClassify(final Interval interval, final RegionLocation loc, final double... points) {
878         for (final double x : points) {
879             final String msg = "Unexpected location for point " + x;
880 
881             Assert.assertEquals(msg, loc, interval.classify(x));
882             Assert.assertEquals(msg, loc, interval.classify(Vector1D.of(x)));
883         }
884     }
885 
886     private static void checkClassify(final RegionBSPTree1D tree, final RegionLocation loc, final double... points) {
887         for (final double x : points) {
888             final String msg = "Unexpected location for point " + x;
889 
890             Assert.assertEquals(msg, loc, tree.classify(x));
891             Assert.assertEquals(msg, loc, tree.classify(Vector1D.of(x)));
892         }
893     }
894 
895     private static void checkBoundaryProjection(final Interval interval, final double location, final double projectedLocation) {
896         final Vector1D pt = Vector1D.of(location);
897 
898         final Vector1D proj = interval.project(pt);
899 
900         Assert.assertEquals(projectedLocation, proj.getX(), TEST_EPS);
901     }
902 
903     /** Check that the given interval matches the arguments and is internally consistent.
904      * @param interval
905      * @param min
906      * @param max
907      */
908     private static void checkInterval(final Interval interval, final double min, final double max) {
909         checkInterval(interval, min, max, TEST_PRECISION);
910     }
911 
912     /** Check that the given interval matches the arguments and is internally consistent.
913      * @param interval
914      * @param min
915      * @param max
916      * @param precision
917      */
918     private static void checkInterval(final Interval interval, final double min, final double max, final DoublePrecisionContext precision) {
919         Assert.assertEquals(min, interval.getMin(), TEST_EPS);
920         Assert.assertEquals(max, interval.getMax(), TEST_EPS);
921 
922         final boolean finiteMin = Double.isFinite(min);
923         final boolean finiteMax = Double.isFinite(max);
924 
925         Assert.assertEquals(finiteMin, interval.hasMinBoundary());
926         Assert.assertEquals(finiteMax, interval.hasMaxBoundary());
927 
928         if (finiteMin) {
929             Assert.assertEquals(min, interval.getMinBoundary().getLocation(), TEST_EPS);
930         } else {
931             Assert.assertNull(interval.getMinBoundary());
932         }
933 
934         if (finiteMax) {
935             Assert.assertEquals(max, interval.getMaxBoundary().getLocation(), TEST_EPS);
936         } else {
937             Assert.assertNull(interval.getMaxBoundary());
938         }
939 
940         Assert.assertFalse(interval.isEmpty()); // always false
941     }
942 }