togo 0.7.2

A library for 2D geometry, providing geometric algorithms for intersection/distance between circular arcs/line segments.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
#![allow(dead_code)]

use crate::constants::CIRCLE_TOLERANCE;
use crate::point::point;
use crate::utils::diff_of_prod;
use crate::{circle::Circle, point::Point};

// #00019
/// Configuration for circle-circle intersection results.
#[derive(Debug, PartialEq)]
pub enum CircleCircleConfig {
    NoIntersection(),
    NoncocircularOnePoint(Point),         // point[0]
    NoncocircularTwoPoints(Point, Point), // point[0], point[1]
    SameCircles(),
}

const ZERO: f64 = 0f64;

/// Computes the intersection of two circles.
///
/// This function determines the intersection points of two circles defined by their centers and radii.
///
/// # Arguments
/// * `circle0` - The first circle.
/// * `circle1` - The second circle.
///
/// # Returns
/// Returns a `CircleCircleConfig` enum indicating the result of the intersection test.
///
/// # Circle Intersection Logic
/// The circles are defined by the equations:
/// /// - |X - C0| = R0
/// /// - |X - C1| = R1
/// /// The vector U = C1 - C0 is computed, and its squared length is used to determine the relationship between the circles.
///
/// # Conditions for Intersection
/// The circles can have the following relationships:
///     - **Same Circles**: If the centers and radii are identical, they are the same circle.
///     - **No Intersection**: If the distance between centers is greater than the sum of the radii or less than the absolute difference of the radii, they do not intersect.
///     - **Tangent Circles**: If the distance equals the sum or absolute difference of the radii, they touch at one point.
///     - **Intersecting Circles**: If the distance is strictly between the absolute difference and sum of the radii, they intersect at two points.
///
/// # Examples
/// ```
/// use togo::prelude::*;
///
/// let circle0 = circle(point(0.0, 0.0), 1.0);
/// let circle1 = circle(point(1.0, 0.0), 1.0);
/// let result = int_circle_circle(circle0, circle1);
/// // result should be CircleCircleConfig::NoncocircularTwoPoints(Point(0.5, 0.8660254037844386), Point(0.5, -0.8660254037844386))
/// let circle0 = circle(point(0.0, 0.0), 1.0);
/// let circle1 = circle(point(2.0, 0.0), 1.0);
/// let result = int_circle_circle(circle0, circle1);
/// // result should be CircleCircleConfig::NoIntersection()
/// ```
pub fn int_circle_circle(circle0: Circle, circle1: Circle) -> CircleCircleConfig {
    debug_assert!(circle0.r.is_finite());
    debug_assert!(circle1.r.is_finite());

    let u = circle1.c - circle0.c;
    let usqr_len = u.dot(u);
    let r0 = circle0.r;
    let r1 = circle1.r;
    let r0_m_r1 = r0 - r1;
    
    if usqr_len < CIRCLE_TOLERANCE * CIRCLE_TOLERANCE && r0_m_r1.abs() < CIRCLE_TOLERANCE {
        // Circles are the same (or nearly identical within tolerance)
        return CircleCircleConfig::SameCircles();
    }

    let r0_m_r1_sqr = r0_m_r1 * r0_m_r1;
    if usqr_len < r0_m_r1_sqr {
        // The circles do not intersect.
        return CircleCircleConfig::NoIntersection();
    }

    let r0_p_r1 = r0 + r1;
    let r0_p_r1_sqr = r0_p_r1 * r0_p_r1;
    if usqr_len > r0_p_r1_sqr {
        // The circles do not intersect.
        return CircleCircleConfig::NoIntersection();
    }

    if usqr_len < r0_p_r1_sqr {
        if r0_m_r1_sqr < usqr_len {
            //let inv_usqr_len = 1.0 / usqr_len;
            // let s = 0.5 * ((r0 * r0 - r1 * r1) * inv_usqr_len + 1.0);
            let s = 0.5 * (diff_of_prod(r0, r0, r1, r1) / usqr_len + 1.0);
            //let s = 0.5 * (((r1 + r0) / (usqr_len / (r0 - r1))) + 1.0);
            //let s = (0.5 / (usqr_len / (r1 + r0))).mul_add(r0 - r1, 0.5);

            // In theory, discr is nonnegative.  However, numerical round-off
            // errors can make it slightly negative.  Clamp it to zero.
            //let mut discr = r0 * r0 * inv_usqr_len - s * s;
            let mut discr = diff_of_prod(r0 / usqr_len, r0, s, s);
            //println!("{:.40} {:.40}", discr, discr);
            if discr < ZERO {
                discr = ZERO;
            }
            let t = discr.sqrt();
            let v = point(u.y, -u.x);
            let tmp = circle0.c + u * s;
            let p0 = tmp - v * t;
            let p1 = tmp + v * t;
            
            // Bounds check: intersection points should have finite coordinates.
            // If they are non-finite (inf, -inf, NaN), it indicates numerical issues.
            if !p0.x.is_finite() || !p0.y.is_finite() || !p1.x.is_finite() || !p1.y.is_finite() {
                return CircleCircleConfig::NoIntersection();
            }
            
            if t > 0f64 {
                CircleCircleConfig::NoncocircularTwoPoints(p0, p1)
            } else {
                // t==0.0
                CircleCircleConfig::NoncocircularOnePoint(p0)
            }
        } else {
            // |U| = |R0-R1|, circles are tangent.
            let p0 = circle0.c + u * (r0 / r0_m_r1);
            
            // Bounds check: tangent point should have finite coordinates
            if !p0.x.is_finite() || !p0.y.is_finite() {
                return CircleCircleConfig::NoIntersection();
            }
            
            CircleCircleConfig::NoncocircularOnePoint(p0)
        }
    } else {
        // |U| = |R0+R1|, circles are tangent.
        let p0 = circle0.c + u * (r0 / r0_p_r1);
        
        // Bounds check: tangent point should have finite coordinates
        if !p0.x.is_finite() || !p0.y.is_finite() {
            return CircleCircleConfig::NoIntersection();
        }
        
        CircleCircleConfig::NoncocircularOnePoint(p0)
    }
}

/// Circle Circle intersect
#[cfg(test)]
mod tests_circle {
    use super::*;
    use crate::circle::circle;

    // short funtion
    fn ff(circle0: Circle, circle1: Circle) -> CircleCircleConfig {
        int_circle_circle(circle0, circle1)
    }

    #[test]
    fn test_same_circles_01() {
        let circle0 = circle(point(100.0, -100.0), 1.0);
        let circle1 = circle(point(100.0, -100.0), 1.0);
        assert_eq!(ff(circle0, circle1), CircleCircleConfig::SameCircles());
    }

    #[test]
    fn test_same_non_intersection_01() {
        let circle0 = circle(point(1000.0, -1000.0), 1.01);
        let circle1 = circle(point(1000.0, -1000.0), 1.0);
        assert_eq!(ff(circle0, circle1), CircleCircleConfig::NoIntersection());
    }

    #[test]
    fn test_same_non_intersection_02() {
        let circle0 = circle(point(1000.0, -1000.0), 1.0);
        let circle1 = circle(point(1002.0, -1002.0), 1.0);
        assert_eq!(ff(circle0, circle1), CircleCircleConfig::NoIntersection());
    }

    #[test]
    fn test_noncircular_two_points() {
        let eps = f64::EPSILON * 10.0;
        let circle0 = circle(point(10.0, -10.0), 1.0);
        let circle1 = circle(point(10.0, -12.0 + eps), 1.0);
        let point0 = point(10.000000042146848, -11.0);
        let point1 = point(9.999999957853152, -11.0);
        let res = ff(circle0, circle1);
        assert_eq!(
            res,
            CircleCircleConfig::NoncocircularTwoPoints(point0, point1)
        );
    }

    #[test]
    fn test_noncircular_one_point_01() {
        let eps = f64::EPSILON * 2.0;
        let circle0 = circle(point(10.0, -10.0), 1.0);
        let circle1 = circle(point(10.0, -12.0 + eps), 1.0);
        let point0 = point(10.0, -11.0);
        let res = ff(circle0, circle1);
        assert_eq!(res, CircleCircleConfig::NoncocircularOnePoint(point0));
    }

    #[test]
    fn test_noncircular_one_point_02() {
        let circle0 = circle(point(10.0, -10.0), 1.0);
        let circle1 = circle(point(10.0, -10.5), 0.5);
        let point0 = point(10.0, -11.0);
        let res = ff(circle0, circle1);
        assert_eq!(res, CircleCircleConfig::NoncocircularOnePoint(point0));
    }

    #[test]
    fn test_noncircular_two_points_1() {
        let eps = f64::EPSILON * 5.0;
        let circle0 = circle(point(10.0, -10.0), 1.0);
        let circle1 = circle(point(10.0, -10.5 - eps), 0.5);
        let point0 = point(10.000000059604645, -10.999999999999998);
        let point1 = point(9.999999940395355, -10.999999999999998);
        let res = ff(circle0, circle1);
        assert_eq!(
            res,
            CircleCircleConfig::NoncocircularTwoPoints(point0, point1)
        );
    }

    #[test]
    // Test for numerical stability
    fn test_noncircular_one_point_03() {
        let eps = f64::EPSILON * 2.0;
        let circle0 = circle(point(1000.0, -1000.0), 100.0);
        let circle1 = circle(point(1000.0, -1200.0 + eps), 100.0);
        let point0 = point(1000.0, -1100.0);
        let res = ff(circle0, circle1);
        assert_eq!(res, CircleCircleConfig::NoncocircularOnePoint(point0));
    }

    #[test]
    // Test tolerance boundary at CIRCLE_TOLERANCE = 1e-10
    fn test_tolerance_boundary_within_tolerance() {
        // Circles separated by distance < 1e-10 with same radii should be treated as same
        let tolerance = 1e-10;
        let circle0 = circle(point(0.0, 0.0), 1.0);
        let circle1 = circle(point(tolerance * 0.5, 0.0), 1.0); // Well within tolerance
        let res = ff(circle0, circle1);
        assert_eq!(res, CircleCircleConfig::SameCircles());
    }

    #[test]
    // Test tolerance boundary just outside tolerance
    fn test_tolerance_boundary_outside_tolerance() {
        // Circles separated by distance > 1e-10 with same radii should intersect
        let tolerance = 1e-10;
        let circle0 = circle(point(0.0, 0.0), 1.0);
        let circle1 = circle(point(tolerance * 2.0, 0.0), 1.0); // Beyond tolerance
        let res = ff(circle0, circle1);
        // Should have two intersection points (circles overlap)
        match res {
            CircleCircleConfig::NoncocircularTwoPoints(_, _) => {
                // Correct: circles overlap with two points
            }
            _ => panic!("Expected two intersection points for circles beyond tolerance"),
        }
    }

    #[test]
    // Test nearly identical radii at tolerance boundary
    fn test_radius_tolerance_boundary() {
        let tolerance = 1e-10;
        let circle0 = circle(point(0.0, 0.0), 1.0);
        let circle1 = circle(point(0.0, 0.0), 1.0 + tolerance * 0.5); // Radius diff < tolerance
        let res = ff(circle0, circle1);
        // Should be treated as same circle (within tolerance)
        assert_eq!(res, CircleCircleConfig::SameCircles());
    }

    #[test]
    // Test one circle inside another without touching
    fn test_one_inside_other_no_intersection() {
        let circle0 = circle(point(0.0, 0.0), 10.0);
        let circle1 = circle(point(0.0, 0.0), 5.0);
        let res = ff(circle0, circle1);
        assert_eq!(res, CircleCircleConfig::NoIntersection());
    }

    #[test]
    // Test external tangency
    fn test_external_tangent() {
        let circle0 = circle(point(0.0, 0.0), 1.0);
        let circle1 = circle(point(2.0, 0.0), 1.0); // Distance = sum of radii
        let res = ff(circle0, circle1);
        match res {
            CircleCircleConfig::NoncocircularOnePoint(_) => {
                // Correct: external tangent
            }
            _ => panic!("Expected one point for external tangent circles"),
        }
    }

    #[test]
    // Test internal tangency
    fn test_internal_tangent() {
        let circle0 = circle(point(0.0, 0.0), 2.0);
        let circle1 = circle(point(1.0, 0.0), 1.0); // Distance = |r0 - r1|
        let res = ff(circle0, circle1);
        match res {
            CircleCircleConfig::NoncocircularOnePoint(_) => {
                // Correct: internal tangent
            }
            _ => panic!("Expected one point for internal tangent circles"),
        }
    }

    #[test]
    // Test circles with zero radius (degenerate points)
    fn test_circles_with_zero_radius_same_center() {
        let circle0 = circle(point(0.0, 0.0), 0.0);
        let circle1 = circle(point(0.0, 0.0), 0.0);
        let res = ff(circle0, circle1);
        assert_eq!(res, CircleCircleConfig::SameCircles());
    }

    #[test]
    // Test circles with zero radius at different centers
    fn test_circles_with_zero_radius_different_center() {
        let circle0 = circle(point(0.0, 0.0), 0.0);
        let circle1 = circle(point(1.0, 1.0), 0.0);
        let res = ff(circle0, circle1);
        assert_eq!(res, CircleCircleConfig::NoIntersection());
    }
}

#[cfg(test)]
mod tests_circle_old {

    // Old tests
    ///////////////////////
    use super::*;
    use crate::{circle::circle, utils::perturbed_ulps_as_int};

    // short funtion
    fn ff(circle0: Circle, circle1: Circle) -> CircleCircleConfig {
        int_circle_circle(circle0, circle1)
    }

    #[test]
    fn test_same_circles01() {
        // Circles are the same
        let circle0 = circle(point(0.0, 0.0), 1.0);
        let circle1 = circle(point(0.0, 0.0), 1.0);
        assert_eq!(ff(circle0, circle1), CircleCircleConfig::SameCircles());
    }
    #[test]
    fn test_same_circles02() {
        // Circles are the same, radius zero
        let circle0 = circle(point(0.0, 0.0), 0.0);
        let circle1 = circle(point(0.0, 0.0), 0.0);
        assert_eq!(ff(circle0, circle1), CircleCircleConfig::SameCircles());
    }
    #[test]
    fn test_same_circles03() {
        // Circles are the same, radius is large
        let circle0 = circle(point(0.0, 0.0), f64::MAX);
        let circle1 = circle(point(0.0, 0.0), f64::MAX);
        assert_eq!(ff(circle0, circle1), CircleCircleConfig::SameCircles());
    }
    #[test]
    fn test_same_circles04() {
        // Circles are the same, center is large
        let circle0 = circle(point(f64::MAX, f64::MAX), f64::MAX);
        let circle1 = circle(point(f64::MAX, f64::MAX), f64::MAX);
        assert_eq!(ff(circle0, circle1), CircleCircleConfig::SameCircles());
    }

    #[test]
    fn test_donot_intersect01() {
        // The circles do not intersect.
        let r = perturbed_ulps_as_int(1.0, -2);
        let circle0 = circle(point(-1.0, 0.0), r);
        let circle1 = circle(point(1.0, 0.0), 1.0);
        assert_eq!(ff(circle0, circle1), CircleCircleConfig::NoIntersection());
    }
    #[test]
    fn test_donot_intersect02() {
        // The circles do not intersect.
        let x = perturbed_ulps_as_int(1.0, 2);
        let circle0 = circle(point(-1.0, 0.0), 1.0);
        let circle1 = circle(point(x, 0.0), 1.0);
        assert_eq!(ff(circle0, circle1), CircleCircleConfig::NoIntersection());
    }

    #[test]
    fn test_tangent01() {
        // The circles touch in one point.
        let x = perturbed_ulps_as_int(1.0, 1);
        let circle0 = circle(point(-1.0, 0.0), 1.0);
        let circle1 = circle(point(x, 0.0), 1.0);
        assert_eq!(
            ff(circle0, circle1),
            CircleCircleConfig::NoncocircularOnePoint(point(0.0, 0.0))
        );
    }

    #[test]
    fn test_tangent02() {
        // Circles with larger shift to exceed tolerance and intersect in two points
        let circle0 = circle(point(1.0, 0.0), 1.0);
        let circle1 = circle(point(1.0 + 1e-9, 0.0), 1.0); // Beyond CIRCLE_TOLERANCE (1e-10)
        let res = int_circle_circle(circle0, circle1);
        // Now they intersect in two points (execution path: usqr_len < r0_p_r1_sqr && r0_m_r1_sqr < usqr_len)
        match res {
            CircleCircleConfig::NoncocircularTwoPoints(p0, p1) => {
                // Points shift slightly due to offset, but still two distinct points
                assert!((p0.x - 1.0).abs() < 1e-7);
                assert!((p0.y - 1.0).abs() < 1e-7);
                assert!((p1.x - 1.0).abs() < 1e-7);
                assert!((p1.y + 1.0).abs() < 1e-7);
            }
            _ => panic!("Expected two intersection points"),
        }
    }

    #[test]
    fn test_tangent03() {
        // Circles with very small shift are same (cocircular)
        let _0 = perturbed_ulps_as_int(0.0, 1);
        let _1 = perturbed_ulps_as_int(1.0, -1);
        let circle0 = circle(point(0.0, 0.0), 1.0);
        let circle1 = circle(point(_0, 0.0), 1.0);
        let res = ff(circle0, circle1);
        assert_eq!(res, CircleCircleConfig::SameCircles());
    }

    #[test]
    fn test_tangent04() {
        // Different radius beyond tolerance to trigger no intersection path
        let circle0 = circle(point(0.0, 0.0), 1.0);
        let circle1 = circle(point(0.0, 0.0), 1.0 - 1e-9); // Beyond CIRCLE_TOLERANCE
        let res = ff(circle0, circle1);
        // Now circles have different radii beyond tolerance, no intersection (execution path: usqr_len < r0_m_r1_sqr)
        assert_eq!(res, CircleCircleConfig::NoIntersection());
    }

    #[test]
    fn test_tangent05() {
        // Differences that create internal tangency (execution path: |U| = |R0-R1|)
        let circle0 = circle(point(1.0, 0.0), 1.0);
        let circle1 = circle(point(1.0 + 5e-10, 0.0), 1.0 - 5e-10); // Creates tangency
        let res = ff(circle0, circle1);
        // Circles are internally tangent
        match res {
            CircleCircleConfig::NoncocircularOnePoint(p) => {
                // Internal tangency at approximately (2.0, 0.0)
                assert!((p.x - 2.0).abs() < 1e-8);
                assert!((p.y - 0.0).abs() < 1e-8);
            }
            _ => panic!("Expected tangent point, got {:?}", res),
        }
    }

    #[test]
    fn test_tangent06() {
        // Smaller differences - just beyond tolerance to get two intersection points
        let circle0 = circle(point(1.0, 0.0), 1.0);
        let circle1 = circle(point(1.0 + 1e-9, 0.0), 1.0 - 1e-9); // Beyond tolerance with overlap
        let res = ff(circle0, circle1);
        // Two distinct intersection points (execution path: usqr_len < r0_p_r1_sqr && r0_m_r1_sqr < usqr_len)
        match res {
            CircleCircleConfig::NoncocircularTwoPoints(_, _) => {
                // Correct: two intersection points
            }
            _ => panic!("Expected two intersection points, got {:?}", res),
        }
    }

    #[test]
    fn test_no_intersection2() {
        let c0 = circle(point(0.5, 0.0), 0.5);
        let c1 = circle(point(-1.0, 0.0), 1.0);
        let res = ff(c0, c1);
        assert_eq!(
            res,
            CircleCircleConfig::NoncocircularOnePoint(point(0.0, 0.0))
        );
    }

    use crate::svg::svg;
    #[test]
    fn test_intersection_issue_01() {
        let mut svg = svg(150.0, 200.0);
        let c0 = circle(point(100.0, 130.0), 20.0);
        let c1 = circle(point(75.0, 40.0), 85.0);
        svg.circle(&c0, "red");
        svg.circle(&c1, "blue");
        let p0 = point(113.87064429562277, 115.59148769566033);
        let p1 = point(80.68522962987866, 124.80965843614482);

        svg.circle(&circle(p0, 1.0), "red");
        svg.write();
        let res = ff(c0, c1);
        assert_eq!(res, CircleCircleConfig::NoncocircularTwoPoints(p0, p1));
    }

    #[test]
    fn test_external_tangent_exact() {
        // Test external tangency: |U| == R0 + R1 (execution path: usqr_len == r0_p_r1_sqr)
        // This tests the else branch at line 117 (line 118 in the function)
        let circle0 = circle(point(0.0, 0.0), 1.0);
        let circle1 = circle(point(2.0, 0.0), 1.0); // Distance = 2.0 = 1.0 + 1.0 (exactly)
        let res = ff(circle0, circle1);
        match res {
            CircleCircleConfig::NoncocircularOnePoint(p) => {
                // External tangency at point (1.0, 0.0)
                assert!((p.x - 1.0).abs() < 1e-10);
                assert!((p.y - 0.0).abs() < 1e-10);
            }
            _ => panic!("Expected external tangent point, got {:?}", res),
        }
    }

    #[test]
    fn test_discriminant_zero_path() {
        // Test the path where t == 0.0 at line 112 (discriminant == 0 path)
        // This is when the discriminant computation produces exactly 0
        // For equal radii circles: s = 0.5
        // We need: s² = r0²/usqr_len, so 0.25 = r0²/usqr_len
        // Therefore: distance = 2*r0 (circles exactly opposite at equal distance)
        let circle0 = circle(point(0.0, 0.0), 1.0);
        let circle1 = circle(point(2.0, 0.0), 1.0); // Distance = 2.0 = 2 * radius
        let res = ff(circle0, circle1);
        // This should produce t=0, giving NoncocircularOnePoint
        match res {
            CircleCircleConfig::NoncocircularOnePoint(p) => {
                // Tangent point should be at (1.0, 0.0)
                assert!((p.x - 1.0).abs() < 1e-10);
                assert!((p.y - 0.0).abs() < 1e-10);
            }
            _ => panic!("Expected NoncocircularOnePoint from discriminant zero path, got {:?}", res),
        }
    }

    #[test]
    fn test_bounds_check_non_finite_intersection_points() {
        // Test that non-finite intersection points are rejected for two-point case
        // Create circles with extreme coordinates that might produce non-finite results
        let circle0 = circle(point(0.0, 0.0), 1.0);
        let circle1 = circle(point(1e100, 0.0), 1e100);
        let res = ff(circle0, circle1);
        // Should either be NoIntersection or have finite points
        match res {
            CircleCircleConfig::NoIntersection() => {
                // Acceptable - circles are far apart
            }
            CircleCircleConfig::NoncocircularOnePoint(p) => {
                assert!(p.x.is_finite() && p.y.is_finite(), "Point coordinates should be finite");
            }
            CircleCircleConfig::NoncocircularTwoPoints(p0, p1) => {
                assert!(p0.x.is_finite() && p0.y.is_finite(), "p0 should be finite");
                assert!(p1.x.is_finite() && p1.y.is_finite(), "p1 should be finite");
            }
            _ => {}
        }
    }

    #[test]
    fn test_bounds_check_tangent_non_finite_point() {
        // Test that non-finite tangent points are rejected
        let circle0 = circle(point(0.0, 0.0), 1.0);
        let circle1 = circle(point(2.0, 0.0), 1e-100); // Very small circle far away
        let res = ff(circle0, circle1);
        // Should handle gracefully
        match res {
            CircleCircleConfig::NoIntersection() => {
                // Expected - circles don't intersect
            }
            CircleCircleConfig::NoncocircularOnePoint(p) => {
                assert!(p.x.is_finite() && p.y.is_finite(), "Tangent point should be finite");
            }
            _ => {}
        }
    }
}