1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.euclidean.twod;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collections;
22 import java.util.Comparator;
23 import java.util.regex.Pattern;
24
25 import org.apache.commons.geometry.core.GeometryTestUtils;
26 import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
27 import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
28 import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
29 import org.apache.commons.numbers.angle.PlaneAngleRadians;
30 import org.apache.commons.numbers.core.Precision;
31 import org.junit.Assert;
32 import org.junit.Test;
33
34 public class Vector2DTest {
35
36 private static final double EPS = Math.ulp(1d);
37
38 @Test
39 public void testConstants() {
40
41 checkVector(Vector2D.ZERO, 0, 0);
42 checkVector(Vector2D.Unit.PLUS_X, 1, 0);
43 checkVector(Vector2D.Unit.MINUS_X, -1, 0);
44 checkVector(Vector2D.Unit.PLUS_Y, 0, 1);
45 checkVector(Vector2D.Unit.MINUS_Y, 0, -1);
46 checkVector(Vector2D.NaN, Double.NaN, Double.NaN);
47 checkVector(Vector2D.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
48 checkVector(Vector2D.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
49 }
50
51 @Test
52 public void testConstants_normalize() {
53
54 GeometryTestUtils.assertThrows(Vector2D.ZERO::normalize, IllegalArgumentException.class);
55 GeometryTestUtils.assertThrows(Vector2D.NaN::normalize, IllegalArgumentException.class);
56 GeometryTestUtils.assertThrows(Vector2D.POSITIVE_INFINITY::normalize, IllegalArgumentException.class);
57 GeometryTestUtils.assertThrows(Vector2D.NEGATIVE_INFINITY::normalize, IllegalArgumentException.class);
58
59 Assert.assertSame(Vector2D.Unit.PLUS_X, Vector2D.Unit.PLUS_X.normalize());
60 Assert.assertSame(Vector2D.Unit.MINUS_X, Vector2D.Unit.MINUS_X.normalize());
61
62 Assert.assertSame(Vector2D.Unit.PLUS_Y, Vector2D.Unit.PLUS_Y.normalize());
63 Assert.assertSame(Vector2D.Unit.MINUS_Y, Vector2D.Unit.MINUS_Y.normalize());
64 }
65
66 @Test
67 public void testCoordinateAscendingOrder() {
68
69 final Comparator<Vector2D> cmp = Vector2D.COORDINATE_ASCENDING_ORDER;
70
71
72 Assert.assertEquals(0, cmp.compare(Vector2D.of(1, 2), Vector2D.of(1, 2)));
73
74 Assert.assertEquals(-1, cmp.compare(Vector2D.of(0, 2), Vector2D.of(1, 2)));
75 Assert.assertEquals(-1, cmp.compare(Vector2D.of(1, 1), Vector2D.of(1, 2)));
76
77 Assert.assertEquals(1, cmp.compare(Vector2D.of(2, 2), Vector2D.of(1, 2)));
78 Assert.assertEquals(1, cmp.compare(Vector2D.of(1, 3), Vector2D.of(1, 2)));
79
80 Assert.assertEquals(-1, cmp.compare(Vector2D.of(1, 3), null));
81 Assert.assertEquals(1, cmp.compare(null, Vector2D.of(1, 2)));
82 Assert.assertEquals(0, cmp.compare(null, null));
83 }
84
85 @Test
86 public void testCoordinates() {
87
88 final Vector2D v = Vector2D.of(1, 2);
89
90
91 Assert.assertEquals(1.0, v.getX(), EPS);
92 Assert.assertEquals(2.0, v.getY(), EPS);
93 }
94
95 @Test
96 public void testToArray() {
97
98 final Vector2D oneTwo = Vector2D.of(1, 2);
99
100
101 final double[] array = oneTwo.toArray();
102
103
104 Assert.assertEquals(2, array.length);
105 Assert.assertEquals(1.0, array[0], EPS);
106 Assert.assertEquals(2.0, array[1], EPS);
107 }
108
109 @Test
110 public void testDimension() {
111
112 final Vector2D v = Vector2D.of(1, 2);
113
114
115 Assert.assertEquals(2, v.getDimension());
116 }
117
118 @Test
119 public void testNaN() {
120
121 Assert.assertTrue(Vector2D.of(0, Double.NaN).isNaN());
122 Assert.assertTrue(Vector2D.of(Double.NaN, 0).isNaN());
123
124 Assert.assertFalse(Vector2D.of(1, 1).isNaN());
125 Assert.assertFalse(Vector2D.of(1, Double.NEGATIVE_INFINITY).isNaN());
126 Assert.assertFalse(Vector2D.of(Double.POSITIVE_INFINITY, 1).isNaN());
127 }
128
129 @Test
130 public void testInfinite() {
131
132 Assert.assertTrue(Vector2D.of(0, Double.NEGATIVE_INFINITY).isInfinite());
133 Assert.assertTrue(Vector2D.of(Double.NEGATIVE_INFINITY, 0).isInfinite());
134 Assert.assertTrue(Vector2D.of(0, Double.POSITIVE_INFINITY).isInfinite());
135 Assert.assertTrue(Vector2D.of(Double.POSITIVE_INFINITY, 0).isInfinite());
136
137 Assert.assertFalse(Vector2D.of(1, 1).isInfinite());
138 Assert.assertFalse(Vector2D.of(0, Double.NaN).isInfinite());
139 Assert.assertFalse(Vector2D.of(Double.NEGATIVE_INFINITY, Double.NaN).isInfinite());
140 Assert.assertFalse(Vector2D.of(Double.NaN, Double.NEGATIVE_INFINITY).isInfinite());
141 Assert.assertFalse(Vector2D.of(Double.POSITIVE_INFINITY, Double.NaN).isInfinite());
142 Assert.assertFalse(Vector2D.of(Double.NaN, Double.POSITIVE_INFINITY).isInfinite());
143 }
144
145 @Test
146 public void testFinite() {
147
148 Assert.assertTrue(Vector2D.ZERO.isFinite());
149 Assert.assertTrue(Vector2D.of(1, 1).isFinite());
150
151 Assert.assertFalse(Vector2D.of(0, Double.NEGATIVE_INFINITY).isFinite());
152 Assert.assertFalse(Vector2D.of(Double.NEGATIVE_INFINITY, 0).isFinite());
153 Assert.assertFalse(Vector2D.of(0, Double.POSITIVE_INFINITY).isFinite());
154 Assert.assertFalse(Vector2D.of(Double.POSITIVE_INFINITY, 0).isFinite());
155
156 Assert.assertFalse(Vector2D.of(0, Double.NaN).isFinite());
157 Assert.assertFalse(Vector2D.of(Double.NEGATIVE_INFINITY, Double.NaN).isFinite());
158 Assert.assertFalse(Vector2D.of(Double.NaN, Double.NEGATIVE_INFINITY).isFinite());
159 Assert.assertFalse(Vector2D.of(Double.POSITIVE_INFINITY, Double.NaN).isFinite());
160 Assert.assertFalse(Vector2D.of(Double.NaN, Double.POSITIVE_INFINITY).isFinite());
161 }
162
163 @Test
164 public void testGetZero() {
165
166 checkVector(Vector2D.of(1.0, 1.0).getZero(), 0, 0);
167 }
168
169 @Test
170 public void testNorm() {
171
172 Assert.assertEquals(0.0, Vector2D.of(0, 0).norm(), EPS);
173
174 Assert.assertEquals(5.0, Vector2D.of(3, 4).norm(), EPS);
175 Assert.assertEquals(5.0, Vector2D.of(3, -4).norm(), EPS);
176 Assert.assertEquals(5.0, Vector2D.of(-3, 4).norm(), EPS);
177 Assert.assertEquals(5.0, Vector2D.of(-3, -4).norm(), EPS);
178
179 Assert.assertEquals(Math.sqrt(5.0), Vector2D.of(-1, -2).norm(), EPS);
180 }
181
182 @Test
183 public void testNorm_unitVectors() {
184
185 final Vector2D v = Vector2D.of(2.0, 3.0).normalize();
186
187
188 Assert.assertEquals(1.0, v.norm(), 0.0);
189 }
190
191 @Test
192 public void testNormSq() {
193
194 Assert.assertEquals(0.0, Vector2D.of(0, 0).normSq(), EPS);
195
196 Assert.assertEquals(25.0, Vector2D.of(3, 4).normSq(), EPS);
197 Assert.assertEquals(25.0, Vector2D.of(3, -4).normSq(), EPS);
198 Assert.assertEquals(25.0, Vector2D.of(-3, 4).normSq(), EPS);
199 Assert.assertEquals(25.0, Vector2D.of(-3, -4).normSq(), EPS);
200
201 Assert.assertEquals(5.0, Vector2D.of(-1, -2).normSq(), EPS);
202 }
203
204 @Test
205 public void testNormSq_unitVectors() {
206
207 final Vector2D v = Vector2D.of(2.0, 3.0).normalize();
208
209
210 Assert.assertEquals(1.0, v.normSq(), 0.0);
211 }
212
213 @Test
214 public void testWithNorm() {
215
216 checkVector(Vector2D.of(3, 4).withNorm(1.0), 0.6, 0.8);
217 checkVector(Vector2D.of(4, 3).withNorm(1.0), 0.8, 0.6);
218
219 checkVector(Vector2D.of(-3, 4).withNorm(0.5), -0.3, 0.4);
220 checkVector(Vector2D.of(3, -4).withNorm(2.0), 1.2, -1.6);
221 checkVector(Vector2D.of(-3, -4).withNorm(3.0), -1.8, 3.0 * Math.sin(Math.atan2(-4, -3)));
222
223 checkVector(Vector2D.of(0.5, 0.5).withNorm(2), Math.sqrt(2), Math.sqrt(2));
224 }
225
226 @Test
227 public void testWithNorm_illegalNorm() {
228
229 GeometryTestUtils.assertThrows(() -> Vector2D.ZERO.withNorm(2.0),
230 IllegalArgumentException.class);
231 GeometryTestUtils.assertThrows(() -> Vector2D.NaN.withNorm(2.0),
232 IllegalArgumentException.class);
233 GeometryTestUtils.assertThrows(() -> Vector2D.POSITIVE_INFINITY.withNorm(2.0),
234 IllegalArgumentException.class);
235 GeometryTestUtils.assertThrows(() -> Vector2D.NEGATIVE_INFINITY.withNorm(2.0),
236 IllegalArgumentException.class);
237 }
238
239 @Test
240 public void testWithNorm_unitVectors() {
241
242 final double eps = 1e-14;
243 final Vector2D v = Vector2D.of(2.0, -3.0).normalize();
244
245
246 checkVector(Vector2D.Unit.PLUS_X.withNorm(2.5), 2.5, 0.0);
247 checkVector(Vector2D.Unit.MINUS_Y.withNorm(3.14), 0.0, -3.14);
248
249 for (int i = -10; i <= 10; i++) {
250 Assert.assertEquals(Math.abs((double) i), v.withNorm(i).norm(), eps);
251 }
252 }
253
254 @Test
255 public void testAdd() {
256
257 final Vector2D v1 = Vector2D.of(-1, 2);
258 final Vector2D v2 = Vector2D.of(3, -4);
259 final Vector2D v3 = Vector2D.of(5, 6);
260
261
262 checkVector(v1.add(v1), -2, 4);
263
264 checkVector(v1.add(v2), 2, -2);
265 checkVector(v2.add(v1), 2, -2);
266
267 checkVector(v1.add(v3), 4, 8);
268 checkVector(v3.add(v1), 4, 8);
269 }
270
271 @Test
272 public void testAdd_scaled() {
273
274 final Vector2D v1 = Vector2D.of(-1, 2);
275 final Vector2D v2 = Vector2D.of(3, -4);
276 final Vector2D v3 = Vector2D.of(5, 6);
277
278
279 checkVector(v1.add(2, v1), -3, 6);
280
281 checkVector(v1.add(0, v2), -1, 2);
282 checkVector(v2.add(1, v1), 2, -2);
283
284 checkVector(v1.add(-1, v3), -6, -4);
285 checkVector(v3.add(-2, v1), 7, 2);
286 }
287
288 @Test
289 public void testSubtract() {
290
291 final Vector2D v1 = Vector2D.of(-1, 2);
292 final Vector2D v2 = Vector2D.of(3, -4);
293 final Vector2D v3 = Vector2D.of(5, 6);
294
295
296 checkVector(v1.subtract(v1), 0, 0);
297
298 checkVector(v1.subtract(v2), -4, 6);
299 checkVector(v2.subtract(v1), 4, -6);
300
301 checkVector(v1.subtract(v3), -6, -4);
302 checkVector(v3.subtract(v1), 6, 4);
303 }
304
305 @Test
306 public void testSubtract_scaled() {
307
308 final Vector2D v1 = Vector2D.of(-1, 2);
309 final Vector2D v2 = Vector2D.of(3, -4);
310 final Vector2D v3 = Vector2D.of(5, 6);
311
312
313 checkVector(v1.subtract(2, v1), 1, -2);
314
315 checkVector(v1.subtract(0, v2), -1, 2);
316 checkVector(v2.subtract(1, v1), 4, -6);
317
318 checkVector(v1.subtract(-1, v3), 4, 8);
319 checkVector(v3.subtract(-2, v1), 3, 10);
320 }
321
322 @Test
323 public void testNormalize() {
324
325 checkVector(Vector2D.of(100, 0).normalize(), 1, 0);
326 checkVector(Vector2D.of(-100, 0).normalize(), -1, 0);
327 checkVector(Vector2D.of(0, 100).normalize(), 0, 1);
328 checkVector(Vector2D.of(0, -100).normalize(), 0, -1);
329 checkVector(Vector2D.of(-1, 2).normalize(), -1.0 / Math.sqrt(5), 2.0 / Math.sqrt(5));
330 }
331
332 @Test
333 public void testNormalize_illegalNorm() {
334
335 GeometryTestUtils.assertThrows(Vector2D.ZERO::normalize, IllegalArgumentException.class);
336 GeometryTestUtils.assertThrows(Vector2D.NaN::normalize, IllegalArgumentException.class);
337 GeometryTestUtils.assertThrows(Vector2D.POSITIVE_INFINITY::normalize, IllegalArgumentException.class);
338 GeometryTestUtils.assertThrows(Vector2D.NEGATIVE_INFINITY::normalize, IllegalArgumentException.class);
339 }
340
341 @Test
342 public void testNormalize_isIdempotent() {
343
344 final double invSqrt2 = 1.0 / Math.sqrt(2);
345 final Vector2D v = Vector2D.of(2, 2).normalize();
346
347
348 Assert.assertSame(v, v.normalize());
349 checkVector(v.normalize(), invSqrt2, invSqrt2);
350 }
351
352 @Test
353 public void testNegate() {
354
355 checkVector(Vector2D.of(1, 2).negate(), -1, -2);
356 checkVector(Vector2D.of(-3, -4).negate(), 3, 4);
357 checkVector(Vector2D.of(5, -6).negate().negate(), 5, -6);
358 }
359
360 @Test
361 public void testNegate_unitVectors() {
362
363 final Vector2D v1 = Vector2D.of(1.0, 1.0).normalize();
364 final Vector2D v2 = Vector2D.of(-1.0, -2.0).normalize();
365 final Vector2D v3 = Vector2D.of(2.0, -3.0).normalize();
366
367
368 checkVector(v1.negate(), -1.0 / Math.sqrt(2.0), -1.0 / Math.sqrt(2.0));
369 checkVector(v2.negate(), 1.0 / Math.sqrt(5.0), 2.0 / Math.sqrt(5.0));
370 checkVector(v3.negate(), -2.0 / Math.sqrt(13.0), 3.0 / Math.sqrt(13.0));
371 }
372
373 @Test
374 public void testScalarMultiply() {
375
376 checkVector(Vector2D.of(1, 2).multiply(0), 0, 0);
377
378 checkVector(Vector2D.of(1, 2).multiply(3), 3, 6);
379 checkVector(Vector2D.of(1, 2).multiply(-3), -3, -6);
380
381 checkVector(Vector2D.of(2, 3).multiply(1.5), 3, 4.5);
382 checkVector(Vector2D.of(2, 3).multiply(-1.5), -3, -4.5);
383 }
384
385 @Test
386 public void testDistance() {
387
388 final Vector2D v1 = Vector2D.of(1, 1);
389 final Vector2D v2 = Vector2D.of(4, 5);
390 final Vector2D v3 = Vector2D.of(-1, 0);
391
392
393 Assert.assertEquals(0, v1.distance(v1), EPS);
394
395 Assert.assertEquals(5, v1.distance(v2), EPS);
396 Assert.assertEquals(5, v2.distance(v1), EPS);
397
398 Assert.assertEquals(Math.sqrt(5), v1.distance(v3), EPS);
399 Assert.assertEquals(Math.sqrt(5), v3.distance(v1), EPS);
400 }
401
402 @Test
403 public void testDistanceSq() {
404
405 final Vector2D v1 = Vector2D.of(1, 1);
406 final Vector2D v2 = Vector2D.of(4, 5);
407 final Vector2D v3 = Vector2D.of(-1, 0);
408
409
410 Assert.assertEquals(0, v1.distanceSq(v1), EPS);
411
412 Assert.assertEquals(25, v1.distanceSq(v2), EPS);
413 Assert.assertEquals(25, v2.distanceSq(v1), EPS);
414
415 Assert.assertEquals(5, v1.distanceSq(v3), EPS);
416 Assert.assertEquals(5, v3.distanceSq(v1), EPS);
417 }
418
419 @Test
420 public void testDotProduct() {
421
422 final Vector2D v1 = Vector2D.of(1, 1);
423 final Vector2D v2 = Vector2D.of(4, 5);
424 final Vector2D v3 = Vector2D.of(-1, 0);
425
426
427 Assert.assertEquals(2, v1.dot(v1), EPS);
428 Assert.assertEquals(41, v2.dot(v2), EPS);
429 Assert.assertEquals(1, v3.dot(v3), EPS);
430
431 Assert.assertEquals(9, v1.dot(v2), EPS);
432 Assert.assertEquals(9, v2.dot(v1), EPS);
433
434 Assert.assertEquals(-1, v1.dot(v3), EPS);
435 Assert.assertEquals(-1, v3.dot(v1), EPS);
436
437 Assert.assertEquals(1, Vector2D.Unit.PLUS_X.dot(Vector2D.Unit.PLUS_X), EPS);
438 Assert.assertEquals(0, Vector2D.Unit.PLUS_X.dot(Vector2D.Unit.PLUS_Y), EPS);
439 Assert.assertEquals(-1, Vector2D.Unit.PLUS_X.dot(Vector2D.Unit.MINUS_X), EPS);
440 Assert.assertEquals(0, Vector2D.Unit.PLUS_X.dot(Vector2D.Unit.MINUS_Y), EPS);
441 }
442
443 @Test
444 public void testOrthogonal() {
445
446 final double invSqrt2 = 1.0 / Math.sqrt(2.0);
447
448
449 checkVector(Vector2D.of(3, 0).orthogonal(), 0.0, 1.0);
450 checkVector(Vector2D.of(1.0, 1.0).orthogonal(), -invSqrt2, invSqrt2);
451
452 checkVector(Vector2D.of(0, 2).orthogonal(), -1.0, 0.0);
453 checkVector(Vector2D.of(-1.0, 1.0).orthogonal(), -invSqrt2, -invSqrt2);
454
455 checkVector(Vector2D.Unit.MINUS_X.orthogonal(), 0.0, -1.0);
456 checkVector(Vector2D.of(-1.0, -1.0).orthogonal(), invSqrt2, -invSqrt2);
457
458 checkVector(Vector2D.Unit.MINUS_Y.orthogonal(), 1.0, 0.0);
459 checkVector(Vector2D.of(1.0, -1.0).orthogonal(), invSqrt2, invSqrt2);
460 }
461
462 @Test
463 public void testOrthogonal_fullCircle() {
464 for (double az = 0.0; az <= PlaneAngleRadians.TWO_PI; az += 0.25) {
465
466 final Vector2D v = PolarCoordinates.toCartesian(Math.PI, az);
467
468
469 final Vector2D ortho = v.orthogonal();
470
471
472 Assert.assertEquals(1.0, ortho.norm(), EPS);
473 Assert.assertEquals(0.0, v.dot(ortho), EPS);
474 }
475 }
476
477 @Test
478 public void testOrthogonal_illegalNorm() {
479
480 GeometryTestUtils.assertThrows(Vector2D.ZERO::orthogonal, IllegalArgumentException.class);
481 GeometryTestUtils.assertThrows(Vector2D.NaN::orthogonal, IllegalArgumentException.class);
482 GeometryTestUtils.assertThrows(Vector2D.POSITIVE_INFINITY::orthogonal, IllegalArgumentException.class);
483 GeometryTestUtils.assertThrows(Vector2D.NEGATIVE_INFINITY::orthogonal, IllegalArgumentException.class);
484 }
485
486 @Test
487 public void testOrthogonal_givenDirection() {
488
489 final double invSqrt2 = 1.0 / Math.sqrt(2.0);
490
491
492 checkVector(Vector2D.Unit.PLUS_X.orthogonal(Vector2D.of(-1.0, 0.1)), 0.0, 1.0);
493 checkVector(Vector2D.Unit.PLUS_Y.orthogonal(Vector2D.of(2.0, 2.0)), 1.0, 0.0);
494
495 checkVector(Vector2D.of(2.9, 2.9).orthogonal(Vector2D.of(1.0, 0.22)), invSqrt2, -invSqrt2);
496 checkVector(Vector2D.of(2.9, 2.9).orthogonal(Vector2D.of(0.22, 1.0)), -invSqrt2, invSqrt2);
497 }
498
499 @Test
500 public void testOrthogonal_givenDirection_illegalNorm() {
501
502 GeometryTestUtils.assertThrows(() -> Vector2D.ZERO.orthogonal(Vector2D.Unit.PLUS_X),
503 IllegalArgumentException.class);
504 GeometryTestUtils.assertThrows(() -> Vector2D.NaN.orthogonal(Vector2D.Unit.PLUS_X),
505 IllegalArgumentException.class);
506 GeometryTestUtils.assertThrows(() -> Vector2D.POSITIVE_INFINITY.orthogonal(Vector2D.Unit.PLUS_X),
507 IllegalArgumentException.class);
508 GeometryTestUtils.assertThrows(() -> Vector2D.NEGATIVE_INFINITY.orthogonal(Vector2D.Unit.PLUS_X),
509 IllegalArgumentException.class);
510
511 GeometryTestUtils.assertThrows(() -> Vector2D.Unit.PLUS_X.orthogonal(Vector2D.ZERO),
512 IllegalArgumentException.class);
513 GeometryTestUtils.assertThrows(() -> Vector2D.Unit.PLUS_X.orthogonal(Vector2D.NaN),
514 IllegalArgumentException.class);
515 GeometryTestUtils.assertThrows(() -> Vector2D.Unit.PLUS_X.orthogonal(Vector2D.POSITIVE_INFINITY),
516 IllegalArgumentException.class);
517 GeometryTestUtils.assertThrows(() -> Vector2D.Unit.PLUS_X.orthogonal(Vector2D.NEGATIVE_INFINITY),
518 IllegalArgumentException.class);
519 }
520
521 @Test
522 public void testOrthogonal_givenDirection_directionIsCollinear() {
523
524 GeometryTestUtils.assertThrows(() -> Vector2D.Unit.PLUS_X.orthogonal(Vector2D.Unit.PLUS_X),
525 IllegalArgumentException.class);
526 GeometryTestUtils.assertThrows(() -> Vector2D.Unit.PLUS_X.orthogonal(Vector2D.Unit.MINUS_X),
527 IllegalArgumentException.class);
528 GeometryTestUtils.assertThrows(() -> Vector2D.of(1.0, 1.0).orthogonal(Vector2D.of(2.0, 2.0)),
529 IllegalArgumentException.class);
530 GeometryTestUtils.assertThrows(() -> Vector2D.of(-1.01, -1.01).orthogonal(Vector2D.of(20.1, 20.1)),
531 IllegalArgumentException.class);
532 }
533
534 @Test
535 public void testAngle() {
536
537 Assert.assertEquals(0, Vector2D.Unit.PLUS_X.angle(Vector2D.Unit.PLUS_X), EPS);
538
539 Assert.assertEquals(PlaneAngleRadians.PI, Vector2D.Unit.PLUS_X.angle(Vector2D.Unit.MINUS_X), EPS);
540 Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, Vector2D.Unit.PLUS_X.angle(Vector2D.Unit.PLUS_Y), EPS);
541 Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, Vector2D.Unit.PLUS_X.angle(Vector2D.Unit.MINUS_Y), EPS);
542
543 Assert.assertEquals(PlaneAngleRadians.PI / 4, Vector2D.of(1, 1).angle(Vector2D.of(1, 0)), EPS);
544 Assert.assertEquals(PlaneAngleRadians.PI / 4, Vector2D.of(1, 0).angle(Vector2D.of(1, 1)), EPS);
545
546 Assert.assertEquals(0.004999958333958323, Vector2D.of(20.0, 0.0).angle(Vector2D.of(20.0, 0.1)), EPS);
547 }
548
549
550 @Test
551 public void testAngle_illegalNorm() {
552
553 final Vector2D v = Vector2D.of(1.0, 1.0);
554
555
556 GeometryTestUtils.assertThrows(() -> Vector2D.ZERO.angle(v),
557 IllegalArgumentException.class);
558 GeometryTestUtils.assertThrows(() -> Vector2D.NaN.angle(v),
559 IllegalArgumentException.class);
560 GeometryTestUtils.assertThrows(() -> Vector2D.POSITIVE_INFINITY.angle(v),
561 IllegalArgumentException.class);
562 GeometryTestUtils.assertThrows(() -> Vector2D.NEGATIVE_INFINITY.angle(v),
563 IllegalArgumentException.class);
564
565 GeometryTestUtils.assertThrows(() -> v.angle(Vector2D.ZERO),
566 IllegalArgumentException.class);
567 GeometryTestUtils.assertThrows(() -> v.angle(Vector2D.NaN),
568 IllegalArgumentException.class);
569 GeometryTestUtils.assertThrows(() -> v.angle(Vector2D.POSITIVE_INFINITY),
570 IllegalArgumentException.class);
571 GeometryTestUtils.assertThrows(() -> v.angle(Vector2D.NEGATIVE_INFINITY),
572 IllegalArgumentException.class);
573 }
574
575 @Test
576 public void testSignedArea() {
577
578 final double eps = 1e-10;
579
580 final Vector2D a = Vector2D.Unit.PLUS_X;
581 final Vector2D b = Vector2D.Unit.PLUS_Y;
582 final Vector2D c = Vector2D.of(1, 1).withNorm(2.0);
583 final Vector2D d = Vector2D.of(-1, 1).withNorm(3.0);
584
585
586 Assert.assertEquals(1.0, a.signedArea(b), eps);
587 Assert.assertEquals(-1.0, b.signedArea(a), eps);
588
589 final double xAxisAndCArea = 2 * Math.cos(0.25 * PlaneAngleRadians.PI);
590 Assert.assertEquals(xAxisAndCArea, a.signedArea(c), eps);
591 Assert.assertEquals(-xAxisAndCArea, c.signedArea(a), eps);
592
593 final double xAxisAndDArea = 3 * Math.cos(0.25 * PlaneAngleRadians.PI);
594 Assert.assertEquals(xAxisAndDArea, a.signedArea(d), eps);
595 Assert.assertEquals(-xAxisAndDArea, d.signedArea(a), eps);
596
597 Assert.assertEquals(6.0, c.signedArea(d), eps);
598 Assert.assertEquals(-6.0, d.signedArea(c), eps);
599 }
600
601 @Test
602 public void testSignedArea_collinear() {
603
604 final Vector2D a = Vector2D.Unit.PLUS_X;
605 final Vector2D b = Vector2D.Unit.PLUS_Y;
606 final Vector2D c = Vector2D.of(-3, 8);
607
608
609 Assert.assertEquals(0.0, a.signedArea(a), EPS);
610 Assert.assertEquals(0.0, b.signedArea(b), EPS);
611 Assert.assertEquals(0.0, c.signedArea(c), EPS);
612
613 Assert.assertEquals(0.0, a.signedArea(a.multiply(100.0)), EPS);
614 Assert.assertEquals(0.0, b.signedArea(b.negate()), EPS);
615 Assert.assertEquals(0.0, c.signedArea(c.multiply(-0.03)), EPS);
616 }
617
618 @Test
619 public void testProject() {
620
621 final Vector2D v1 = Vector2D.of(3.0, 4.0);
622 final Vector2D v2 = Vector2D.of(1.0, 4.0);
623
624
625 checkVector(Vector2D.ZERO.project(v1), 0.0, 0.0);
626
627 checkVector(v1.project(v1), 3.0, 4.0);
628 checkVector(v1.project(v1.negate()), 3.0, 4.0);
629
630 checkVector(v1.project(Vector2D.Unit.PLUS_X), 3.0, 0.0);
631 checkVector(v1.project(Vector2D.Unit.MINUS_X), 3.0, 0.0);
632
633 checkVector(v1.project(Vector2D.Unit.PLUS_Y), 0.0, 4.0);
634 checkVector(v1.project(Vector2D.Unit.MINUS_Y), 0.0, 4.0);
635
636 checkVector(v2.project(v1), (19.0 / 25.0) * 3.0, (19.0 / 25.0) * 4.0);
637 }
638
639 @Test
640 public void testProject_baseHasIllegalNorm() {
641
642 final Vector2D v = Vector2D.of(1.0, 1.0);
643
644
645 GeometryTestUtils.assertThrows(() -> v.project(Vector2D.ZERO),
646 IllegalArgumentException.class);
647 GeometryTestUtils.assertThrows(() -> v.project(Vector2D.NaN),
648 IllegalArgumentException.class);
649 GeometryTestUtils.assertThrows(() -> v.project(Vector2D.POSITIVE_INFINITY),
650 IllegalArgumentException.class);
651 GeometryTestUtils.assertThrows(() -> v.project(Vector2D.NEGATIVE_INFINITY),
652 IllegalArgumentException.class);
653 }
654
655 @Test
656 public void testReject() {
657
658 final Vector2D v1 = Vector2D.of(3.0, 4.0);
659 final Vector2D v2 = Vector2D.of(1.0, 4.0);
660
661
662 checkVector(Vector2D.ZERO.reject(v1), 0.0, 0.0);
663
664 checkVector(v1.reject(v1), 0.0, 0.0);
665 checkVector(v1.reject(v1.negate()), 0.0, 0.0);
666
667 checkVector(v1.reject(Vector2D.Unit.PLUS_X), 0.0, 4.0);
668 checkVector(v1.reject(Vector2D.Unit.MINUS_X), 0.0, 4.0);
669
670 checkVector(v1.reject(Vector2D.Unit.PLUS_Y), 3.0, 0.0);
671 checkVector(v1.reject(Vector2D.Unit.MINUS_Y), 3.0, 0.0);
672
673 checkVector(v2.reject(v1), -32.0 / 25.0, (6.0 / 25.0) * 4.0);
674 }
675
676 @Test
677 public void testReject_baseHasIllegalNorm() {
678
679 final Vector2D v = Vector2D.of(1.0, 1.0);
680
681
682 GeometryTestUtils.assertThrows(() -> v.reject(Vector2D.ZERO),
683 IllegalArgumentException.class);
684 GeometryTestUtils.assertThrows(() -> v.reject(Vector2D.NaN),
685 IllegalArgumentException.class);
686 GeometryTestUtils.assertThrows(() -> v.reject(Vector2D.POSITIVE_INFINITY),
687 IllegalArgumentException.class);
688 GeometryTestUtils.assertThrows(() -> v.reject(Vector2D.NEGATIVE_INFINITY),
689 IllegalArgumentException.class);
690 }
691
692 @Test
693 public void testProjectAndReject_areComplementary() {
694
695 final double eps = 1e-12;
696
697
698 checkProjectAndRejectFullCircle(Vector2D.of(1.0, 0.0), 1.0, eps);
699 checkProjectAndRejectFullCircle(Vector2D.of(0.0, 1.0), 2.0, eps);
700 checkProjectAndRejectFullCircle(Vector2D.of(1.0, 1.0), 3.0, eps);
701
702 checkProjectAndRejectFullCircle(Vector2D.of(-2.0, 0.0), 4.0, eps);
703 checkProjectAndRejectFullCircle(Vector2D.of(0.0, -2.0), 5.0, eps);
704 checkProjectAndRejectFullCircle(Vector2D.of(-2.0, -2.0), 6.0, eps);
705 }
706
707 private void checkProjectAndRejectFullCircle(final Vector2D vec, final double baseMag, final double eps) {
708 for (double theta = 0.0; theta <= PlaneAngleRadians.TWO_PI; theta += 0.5) {
709 final Vector2D base = PolarCoordinates.toCartesian(baseMag, theta);
710
711 final Vector2D proj = vec.project(base);
712 final Vector2D rej = vec.reject(base);
713
714
715 EuclideanTestUtils.assertCoordinatesEqual(vec, proj.add(rej), eps);
716
717 final double angle = base.angle(vec);
718
719
720
721
722 if (angle < PlaneAngleRadians.PI_OVER_TWO) {
723 Assert.assertEquals(0.0, proj.angle(base), eps);
724 } else if (angle > PlaneAngleRadians.PI_OVER_TWO) {
725 Assert.assertEquals(PlaneAngleRadians.PI, proj.angle(base), eps);
726 }
727
728
729
730
731 if (angle > 0.0 && angle < PlaneAngleRadians.PI) {
732 Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, rej.angle(base), eps);
733 }
734 }
735 }
736
737 @Test
738 public void testVectorTo() {
739
740 final Vector2D p1 = Vector2D.of(1, 1);
741 final Vector2D p2 = Vector2D.of(4, 5);
742 final Vector2D p3 = Vector2D.of(-1, 0);
743
744
745 checkVector(p1.vectorTo(p1), 0, 0);
746 checkVector(p1.vectorTo(p2), 3, 4);
747 checkVector(p2.vectorTo(p1), -3, -4);
748
749 checkVector(p1.vectorTo(p3), -2, -1);
750 checkVector(p3.vectorTo(p1), 2, 1);
751 }
752
753 @Test
754 public void testDirectionTo() {
755
756 final double invSqrt2 = 1.0 / Math.sqrt(2);
757
758 final Vector2D p1 = Vector2D.of(1, 1);
759 final Vector2D p2 = Vector2D.of(1, 5);
760 final Vector2D p3 = Vector2D.of(-2, -2);
761
762
763 checkVector(p1.directionTo(p2), 0, 1);
764 checkVector(p2.directionTo(p1), 0, -1);
765
766 checkVector(p1.directionTo(p3), -invSqrt2, -invSqrt2);
767 checkVector(p3.directionTo(p1), invSqrt2, invSqrt2);
768 }
769
770 @Test
771 public void testDirectionTo_illegalNorm() {
772
773 final Vector2D p = Vector2D.of(1, 2);
774
775
776 GeometryTestUtils.assertThrows(() -> Vector2D.ZERO.directionTo(Vector2D.ZERO),
777 IllegalArgumentException.class);
778 GeometryTestUtils.assertThrows(() -> p.directionTo(p),
779 IllegalArgumentException.class);
780 GeometryTestUtils.assertThrows(() -> p.directionTo(Vector2D.NaN),
781 IllegalArgumentException.class);
782 GeometryTestUtils.assertThrows(() -> Vector2D.NEGATIVE_INFINITY.directionTo(p),
783 IllegalArgumentException.class);
784 GeometryTestUtils.assertThrows(() -> p.directionTo(Vector2D.POSITIVE_INFINITY),
785 IllegalArgumentException.class);
786 }
787
788 @Test
789 public void testLerp() {
790
791 final Vector2D v1 = Vector2D.of(1, -5);
792 final Vector2D v2 = Vector2D.of(-4, 0);
793 final Vector2D v3 = Vector2D.of(10, -4);
794
795
796 checkVector(v1.lerp(v1, 0), 1, -5);
797 checkVector(v1.lerp(v1, 1), 1, -5);
798
799 checkVector(v1.lerp(v2, -0.25), 2.25, -6.25);
800 checkVector(v1.lerp(v2, 0), 1, -5);
801 checkVector(v1.lerp(v2, 0.25), -0.25, -3.75);
802 checkVector(v1.lerp(v2, 0.5), -1.5, -2.5);
803 checkVector(v1.lerp(v2, 0.75), -2.75, -1.25);
804 checkVector(v1.lerp(v2, 1), -4, 0);
805 checkVector(v1.lerp(v2, 1.25), -5.25, 1.25);
806
807 checkVector(v1.lerp(v3, 0), 1, -5);
808 checkVector(v1.lerp(v3, 0.25), 3.25, -4.75);
809 checkVector(v1.lerp(v3, 0.5), 5.5, -4.5);
810 checkVector(v1.lerp(v3, 0.75), 7.75, -4.25);
811 checkVector(v1.lerp(v3, 1), 10, -4);
812 }
813
814 @Test
815 public void testTransform() {
816
817 final AffineTransformMatrix2D transform = AffineTransformMatrix2D.identity()
818 .scale(2)
819 .translate(1, 2);
820
821 final Vector2D v1 = Vector2D.of(1, 2);
822 final Vector2D v2 = Vector2D.of(-4, -5);
823
824
825 checkVector(v1.transform(transform), 3, 6);
826 checkVector(v2.transform(transform), -7, -8);
827 }
828
829 @Test
830 public void testPrecisionEquals() {
831
832 final DoublePrecisionContext smallEps = new EpsilonDoublePrecisionContext(1e-6);
833 final DoublePrecisionContext largeEps = new EpsilonDoublePrecisionContext(1e-1);
834
835 final Vector2D vec = Vector2D.of(1, -2);
836
837
838 Assert.assertTrue(vec.eq(vec, smallEps));
839 Assert.assertTrue(vec.eq(vec, largeEps));
840
841 Assert.assertTrue(vec.eq(Vector2D.of(1.0000007, -2.0000009), smallEps));
842 Assert.assertTrue(vec.eq(Vector2D.of(1.0000007, -2.0000009), largeEps));
843
844 Assert.assertFalse(vec.eq(Vector2D.of(1.004, -2), smallEps));
845 Assert.assertFalse(vec.eq(Vector2D.of(1, -2.004), smallEps));
846 Assert.assertTrue(vec.eq(Vector2D.of(1.004, -2.004), largeEps));
847
848 Assert.assertFalse(vec.eq(Vector2D.of(1, -3), smallEps));
849 Assert.assertFalse(vec.eq(Vector2D.of(2, -2), smallEps));
850 Assert.assertFalse(vec.eq(Vector2D.of(1, -3), largeEps));
851 Assert.assertFalse(vec.eq(Vector2D.of(2, -2), largeEps));
852 }
853
854 @Test
855 public void testIsZero() {
856
857 final DoublePrecisionContext smallEps = new EpsilonDoublePrecisionContext(1e-6);
858 final DoublePrecisionContext largeEps = new EpsilonDoublePrecisionContext(1e-1);
859
860
861 Assert.assertTrue(Vector2D.of(0.0, -0.0).isZero(smallEps));
862 Assert.assertTrue(Vector2D.of(-0.0, 0.0).isZero(largeEps));
863
864 Assert.assertTrue(Vector2D.of(-1e-7, 1e-7).isZero(smallEps));
865 Assert.assertTrue(Vector2D.of(1e-7, 1e-7).isZero(largeEps));
866
867 Assert.assertFalse(Vector2D.of(1e-2, 0.0).isZero(smallEps));
868 Assert.assertFalse(Vector2D.of(0.0, 1e-2).isZero(smallEps));
869 Assert.assertTrue(Vector2D.of(1e-2, -1e-2).isZero(largeEps));
870
871 Assert.assertFalse(Vector2D.of(0.2, 0.0).isZero(smallEps));
872 Assert.assertFalse(Vector2D.of(0.0, 0.2).isZero(smallEps));
873 Assert.assertFalse(Vector2D.of(0.2, 0.2).isZero(smallEps));
874 Assert.assertFalse(Vector2D.of(-0.2, 0.0).isZero(largeEps));
875 Assert.assertFalse(Vector2D.of(0.0, -0.2).isZero(largeEps));
876 Assert.assertFalse(Vector2D.of(-0.2, -0.2).isZero(largeEps));
877 }
878
879 @Test
880 public void testHashCode() {
881
882 final Vector2D u = Vector2D.of(1, 1);
883 final Vector2D v = Vector2D.of(1 + 10 * Precision.EPSILON, 1 + 10 * Precision.EPSILON);
884 final Vector2D w = Vector2D.of(1, 1);
885
886
887 Assert.assertTrue(u.hashCode() != v.hashCode());
888 Assert.assertEquals(u.hashCode(), w.hashCode());
889
890 Assert.assertEquals(Vector2D.of(0, Double.NaN).hashCode(), Vector2D.NaN.hashCode());
891 Assert.assertEquals(Vector2D.of(Double.NaN, 0).hashCode(), Vector2D.NaN.hashCode());
892 Assert.assertEquals(Vector2D.of(0, Double.NaN).hashCode(), Vector2D.of(Double.NaN, 0).hashCode());
893 }
894
895 @Test
896 public void testEquals() {
897
898 final Vector2D u1 = Vector2D.of(1, 2);
899 final Vector2D u2 = Vector2D.of(1, 2);
900
901
902 Assert.assertFalse(u1.equals(null));
903 Assert.assertFalse(u1.equals(new Object()));
904
905 Assert.assertEquals(u1, u1);
906 Assert.assertEquals(u1, u2);
907
908 Assert.assertNotEquals(u1, Vector2D.of(-1, -2));
909 Assert.assertNotEquals(u1, Vector2D.of(1 + 10 * Precision.EPSILON, 2));
910 Assert.assertNotEquals(u1, Vector2D.of(1, 2 + 10 * Precision.EPSILON));
911
912 Assert.assertEquals(Vector2D.of(0, Double.NaN), Vector2D.of(Double.NaN, 0));
913
914 Assert.assertEquals(Vector2D.of(0, Double.POSITIVE_INFINITY), Vector2D.of(0, Double.POSITIVE_INFINITY));
915 Assert.assertNotEquals(Vector2D.of(Double.POSITIVE_INFINITY, 0), Vector2D.of(0, Double.POSITIVE_INFINITY));
916
917 Assert.assertEquals(Vector2D.of(Double.NEGATIVE_INFINITY, 0), Vector2D.of(Double.NEGATIVE_INFINITY, 0));
918 Assert.assertNotEquals(Vector2D.of(0, Double.NEGATIVE_INFINITY), Vector2D.of(Double.NEGATIVE_INFINITY, 0));
919 }
920
921 @Test
922 public void testEqualsAndHashCode_signedZeroConsistency() {
923
924 final Vector2D a = Vector2D.of(0.0, 0.0);
925 final Vector2D b = Vector2D.of(-0.0, -0.0);
926 final Vector2D c = Vector2D.of(0.0, 0.0);
927 final Vector2D d = Vector2D.of(-0.0, -0.0);
928
929
930 Assert.assertFalse(a.equals(b));
931
932 Assert.assertTrue(a.equals(c));
933 Assert.assertEquals(a.hashCode(), c.hashCode());
934
935 Assert.assertTrue(b.equals(d));
936 Assert.assertEquals(b.hashCode(), d.hashCode());
937 }
938
939 @Test
940 public void testToString() {
941
942 final Vector2D v = Vector2D.of(1, 2);
943 final Pattern pattern = Pattern.compile("\\(1.{0,2}, 2.{0,2}\\)");
944
945
946 final String str = v.toString();
947
948
949 Assert.assertTrue("Expected string " + str + " to match regex " + pattern,
950 pattern.matcher(str).matches());
951 }
952
953 @Test
954 public void testParse() {
955
956 checkVector(Vector2D.parse("(1, 2)"), 1, 2);
957 checkVector(Vector2D.parse("(-1, -2)"), -1, -2);
958
959 checkVector(Vector2D.parse("(0.01, -1e-3)"), 1e-2, -1e-3);
960
961 checkVector(Vector2D.parse("(NaN, -Infinity)"), Double.NaN, Double.NEGATIVE_INFINITY);
962
963 checkVector(Vector2D.parse(Vector2D.ZERO.toString()), 0, 0);
964 checkVector(Vector2D.parse(Vector2D.Unit.MINUS_X.toString()), -1, 0);
965 }
966
967 @Test(expected = IllegalArgumentException.class)
968 public void testParse_failure() {
969
970 Vector2D.parse("abc");
971 }
972
973 @Test
974 public void testOf() {
975
976 checkVector(Vector2D.of(0, 1), 0, 1);
977 checkVector(Vector2D.of(-1, -2), -1, -2);
978 checkVector(Vector2D.of(Math.PI, Double.NaN), Math.PI, Double.NaN);
979 checkVector(Vector2D.of(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY), Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY);
980 }
981
982 @Test
983 public void testOf_arrayArg() {
984
985 checkVector(Vector2D.of(new double[] {0, 1}), 0, 1);
986 checkVector(Vector2D.of(new double[] {-1, -2}), -1, -2);
987 checkVector(Vector2D.of(new double[] {Math.PI, Double.NaN}), Math.PI, Double.NaN);
988 checkVector(Vector2D.of(new double[] {Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY}), Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY);
989 }
990
991 @Test(expected = IllegalArgumentException.class)
992 public void testOf_arrayArg_invalidDimensions() {
993
994 Vector2D.of(new double[] {0.0});
995 }
996
997 @Test
998 public void testUnitFrom_coordinates() {
999
1000 final double invSqrt2 = 1.0 / Math.sqrt(2.0);
1001
1002
1003 checkVector(Vector2D.Unit.from(2.0, -2.0), invSqrt2, -invSqrt2);
1004 checkVector(Vector2D.Unit.from(-4.0, 4.0), -invSqrt2, invSqrt2);
1005 }
1006
1007 @Test
1008 public void testUnitFrom_vector() {
1009
1010 final double invSqrt2 = 1.0 / Math.sqrt(2.0);
1011 final Vector2D vec = Vector2D.of(2.0, -2.0);
1012 final Vector2D.Unit unitVec = Vector2D.Unit.from(2.0, -2.0);
1013
1014
1015 checkVector(Vector2D.Unit.from(vec), invSqrt2, -invSqrt2);
1016 Assert.assertSame(unitVec, Vector2D.Unit.from(unitVec));
1017 }
1018
1019 @Test
1020 public void testUnitFrom_illegalNorm() {
1021 GeometryTestUtils.assertThrows(() -> Vector2D.Unit.from(0.0, 0.0),
1022 IllegalArgumentException.class);
1023 GeometryTestUtils.assertThrows(() -> Vector2D.Unit.from(Double.NaN, 1.0),
1024 IllegalArgumentException.class);
1025 GeometryTestUtils.assertThrows(() -> Vector2D.Unit.from(1.0, Double.NEGATIVE_INFINITY),
1026 IllegalArgumentException.class);
1027 GeometryTestUtils.assertThrows(() -> Vector2D.Unit.from(1.0, Double.POSITIVE_INFINITY),
1028 IllegalArgumentException.class);
1029 }
1030
1031 @Test
1032 public void testMax() {
1033
1034 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-100, 1),
1035 Vector2D.max(Collections.singletonList(Vector2D.of(-100, 1))), EPS);
1036
1037 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, 1),
1038 Vector2D.max(Arrays.asList(Vector2D.of(-100, 1), Vector2D.of(0, 1))), EPS);
1039
1040 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-1, 0),
1041 Vector2D.max(Vector2D.of(-2, 0), Vector2D.of(-1, -5), Vector2D.of(-10, -10)), EPS);
1042 }
1043
1044 @Test
1045 public void testMax_noPointsGiven() {
1046
1047 final String msg = "Cannot compute vector max: no vectors given";
1048
1049
1050 GeometryTestUtils.assertThrows(() -> {
1051 Vector2D.max(new ArrayList<>());
1052 }, IllegalArgumentException.class, msg);
1053 }
1054
1055 @Test
1056 public void testMin() {
1057
1058 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-100, 1),
1059 Vector2D.min(Collections.singletonList(Vector2D.of(-100, 1))), EPS);
1060
1061 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-100, 1),
1062 Vector2D.min(Arrays.asList(Vector2D.of(-100, 1), Vector2D.of(0, 1))), EPS);
1063
1064 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-10, -10),
1065 Vector2D.min(Vector2D.of(-2, 0), Vector2D.of(-1, -5), Vector2D.of(-10, -10)), EPS);
1066 }
1067
1068 @Test
1069 public void testMin_noPointsGiven() {
1070
1071 final String msg = "Cannot compute vector min: no vectors given";
1072
1073
1074 GeometryTestUtils.assertThrows(() -> {
1075 Vector2D.min(new ArrayList<>());
1076 }, IllegalArgumentException.class, msg);
1077 }
1078
1079 @Test
1080 public void testCentroid() {
1081
1082 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, 2),
1083 Vector2D.centroid(Vector2D.of(1, 2)), EPS);
1084
1085 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(2.5, 3.5),
1086 Vector2D.centroid(Vector2D.of(1, 2), Vector2D.of(2, 3),
1087 Vector2D.of(3, 4), Vector2D.of(4, 5)), EPS);
1088
1089 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, 2),
1090 Vector2D.centroid(Collections.singletonList(Vector2D.of(1, 2))), EPS);
1091
1092 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 1),
1093 Vector2D.centroid(Arrays.asList(Vector2D.of(1, 2), Vector2D.of(1, 2),
1094 Vector2D.ZERO, Vector2D.ZERO)), EPS);
1095 }
1096
1097 @Test
1098 public void testCentroid_noPointsGiven() {
1099
1100 final String msg = "Cannot compute centroid: no points given";
1101
1102
1103 GeometryTestUtils.assertThrows(() -> {
1104 Vector2D.centroid(new ArrayList<>());
1105 }, IllegalArgumentException.class, msg);
1106 }
1107
1108 @Test
1109 public void testLinearCombination1() {
1110
1111 final Vector2D p1 = Vector2D.of(1, 2);
1112
1113
1114 checkVector(Vector2D.linearCombination(0, p1), 0, 0);
1115
1116 checkVector(Vector2D.linearCombination(1, p1), 1, 2);
1117 checkVector(Vector2D.linearCombination(-1, p1), -1, -2);
1118
1119 checkVector(Vector2D.linearCombination(0.5, p1), 0.5, 1);
1120 checkVector(Vector2D.linearCombination(-0.5, p1), -0.5, -1);
1121 }
1122
1123 @Test
1124 public void testLinearCombination2() {
1125
1126 final Vector2D p1 = Vector2D.of(1, 2);
1127 final Vector2D p2 = Vector2D.of(-3, -4);
1128
1129
1130 checkVector(Vector2D.linearCombination(2, p1, -3, p2), 11, 16);
1131 checkVector(Vector2D.linearCombination(-3, p1, 2, p2), -9, -14);
1132 }
1133
1134 @Test
1135 public void testLinearCombination3() {
1136
1137 final Vector2D p1 = Vector2D.of(1, 2);
1138 final Vector2D p2 = Vector2D.of(-3, -4);
1139 final Vector2D p3 = Vector2D.of(5, 6);
1140
1141
1142 checkVector(Vector2D.linearCombination(2, p1, -3, p2, 4, p3), 31, 40);
1143 checkVector(Vector2D.linearCombination(-3, p1, 2, p2, -4, p3), -29, -38);
1144 }
1145
1146 @Test
1147 public void testLinearCombination4() {
1148
1149 final Vector2D p1 = Vector2D.of(1, 2);
1150 final Vector2D p2 = Vector2D.of(-3, -4);
1151 final Vector2D p3 = Vector2D.of(5, 6);
1152 final Vector2D p4 = Vector2D.of(-7, -8);
1153
1154
1155 checkVector(Vector2D.linearCombination(2, p1, -3, p2, 4, p3, -5, p4), 66, 80);
1156 checkVector(Vector2D.linearCombination(-3, p1, 2, p2, -4, p3, 5, p4), -64, -78);
1157 }
1158
1159 @Test
1160 public void testUnitFactoryOptimization() {
1161
1162 final Vector2D v = Vector2D.of(4, 5).normalize();
1163 Assert.assertSame(v, v.normalize());
1164 }
1165
1166 private void checkVector(final Vector2D v, final double x, final double y) {
1167 checkVector(v, x, y, EPS);
1168 }
1169
1170 private void checkVector(final Vector2D v, final double x, final double y, final double eps) {
1171 Assert.assertEquals(x, v.getX(), eps);
1172 Assert.assertEquals(y, v.getY(), eps);
1173 }
1174 }