@@ -22,6 +22,12 @@ import (
22
22
"github.com/golang/geo/s1"
23
23
)
24
24
25
+ // pointNear reports if each component of the two points is within the given epsilon.
26
+ // This is similar to Point/Vector.ApproxEqual but with a user supplied epsilon.
27
+ func pointNear (a , b Point , ε float64 ) bool {
28
+ return math .Abs (a .X - b .X ) < ε && math .Abs (a .Y - b .Y ) < ε && math .Abs (a .Z - b .Z ) < ε
29
+ }
30
+
25
31
func TestOriginPoint (t * testing.T ) {
26
32
if math .Abs (OriginPoint ().Norm ()- 1 ) > 1e-15 {
27
33
t .Errorf ("Origin point norm = %v, want 1" , OriginPoint ().Norm ())
@@ -341,3 +347,117 @@ func TestPointRotate(t *testing.T) {
341
347
}
342
348
}
343
349
}
350
+
351
+ func TestPointIsNormalizable (t * testing.T ) {
352
+ tests := []struct {
353
+ have Point
354
+ want bool
355
+ }{
356
+ {
357
+ // 0,0,0 is not normalizeable.
358
+ have : Point {r3.Vector {X : 0 , Y : 0 , Z : 0 }},
359
+ want : false ,
360
+ },
361
+ {
362
+ have : Point {r3.Vector {X : 1 , Y : 1 , Z : 1 }},
363
+ want : true ,
364
+ },
365
+
366
+ // The approximate cutoff is ~1.4149498560666738e-73
367
+ {
368
+ have : Point {r3.Vector {X : 1 , Y : 0 , Z : 0 }},
369
+ want : true ,
370
+ },
371
+ {
372
+ // Only one too small component.
373
+ have : Point {r3.Vector {X : 1e-75 , Y : 1 , Z : 1 }},
374
+ want : true ,
375
+ },
376
+ {
377
+ // All three components exact boundary case.
378
+ have : Point {r3.Vector {
379
+ X : math .Ldexp (1 , - 242 ),
380
+ Y : math .Ldexp (1 , - 242 ),
381
+ Z : math .Ldexp (1 , - 242 )}},
382
+ want : true ,
383
+ },
384
+ {
385
+ // All three components too small.
386
+ have : Point {r3.Vector {
387
+ X : math .Ldexp (1 , - 243 ),
388
+ Y : math .Ldexp (1 , - 243 ),
389
+ Z : math .Ldexp (1 , - 243 )}},
390
+ want : false ,
391
+ },
392
+ }
393
+
394
+ for _ , test := range tests {
395
+ if got := test .have .IsNormalizable (); got != test .want {
396
+ t .Errorf ("%+v.IsNormalizable() = %t, want %t" , test .have , got , test .want )
397
+ }
398
+ }
399
+ }
400
+
401
+ func TestPointEnsureNormalizable (t * testing.T ) {
402
+ tests := []struct {
403
+ have Point
404
+ want Point
405
+ }{
406
+ {
407
+ // 0,0,0 is not normalizeable.
408
+ have : Point {r3.Vector {X : 0 , Y : 0 , Z : 0 }},
409
+ want : Point {r3.Vector {X : 0 , Y : 0 , Z : 0 }},
410
+ },
411
+ {
412
+ have : Point {r3.Vector {X : 1 , Y : 0 , Z : 0 }},
413
+ want : Point {r3.Vector {X : 1 , Y : 0 , Z : 0 }},
414
+ },
415
+ {
416
+ // All three components exact border for still normalizeable.
417
+ have : Point {r3.Vector {
418
+ X : math .Ldexp (1 , - 242 ),
419
+ Y : math .Ldexp (1 , - 242 ),
420
+ Z : math .Ldexp (1 , - 242 ),
421
+ }},
422
+ want : Point {r3.Vector {
423
+ X : math .Ldexp (1 , - 242 ),
424
+ Y : math .Ldexp (1 , - 242 ),
425
+ Z : math .Ldexp (1 , - 242 ),
426
+ }},
427
+ },
428
+ {
429
+ // All three components too small but the same.
430
+ have : Point {r3.Vector {
431
+ X : math .Ldexp (1 , - 243 ),
432
+ Y : math .Ldexp (1 , - 243 ),
433
+ Z : math .Ldexp (1 , - 243 ),
434
+ }},
435
+ want : Point {r3.Vector {
436
+ X : 1 ,
437
+ Y : 1 ,
438
+ Z : 1 ,
439
+ }},
440
+ },
441
+ {
442
+ // All three components too small but different.
443
+ have : Point {r3.Vector {
444
+ X : math .Ldexp (1 , - 243 ),
445
+ Y : math .Ldexp (1 , - 486 ),
446
+ Z : math .Ldexp (1 , - 729 ),
447
+ }},
448
+ want : Point {r3.Vector {
449
+ X : 1 ,
450
+ Y : 0 ,
451
+ Z : 0 ,
452
+ }},
453
+ },
454
+ }
455
+
456
+ for _ , test := range tests {
457
+ got := test .have .EnsureNormalizable ()
458
+ if ! pointNear (got , test .want , 1e-50 ) {
459
+ t .Errorf ("%+v.EnsureNormalizable() = %+v, want %+v" ,
460
+ test .have , got , test .want )
461
+ }
462
+ }
463
+ }
0 commit comments