togo 0.4.0

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
# TOGO - Basic 2D geometric operations
![Build](https://github.com/radevgit/togo/actions/workflows/rust.yml/badge.svg)

This library provides 2D geometric operations for arcs and line segments. 
It is used in my other projects and **may not implement** all possible geometric operations.


## Adding the library to Cargo.toml

```toml
[dependencies]
togo = "0.4.0"
```
![](https://raw.githubusercontent.com/radevgit/togo/refs/heads/main/examples/img/arc_segment_intersect.png "arc_segment_intersect")

![](https://raw.githubusercontent.com/radevgit/togo/refs/heads/main/examples/img/bounding.png "bounding")

## Documentation

[<https://docs.rs/togo>](https://docs.rs/togo)

## Implemented Features

- Point creation and manipulation
- Line segments and circle arcs
- Distance calculations between points, line segments, and circle arcs
- Intersection tests for various geometric primitives
- Arc representation and manipulation
- Support for polylines and vertex manipulation

## Distance Functions
- dist_arc_arc
- dist_line_circle
- dist_point_arc
- dist_point_circle
- dist_point_segment
- dist_segment_arc
- dist_segment_circle
- dist_segment_segment

## Intersection Functions
- int_arc_arc
- int_circle_circle
- int_interval_interval
- int_line_arc
- int_line_circle
- int_line_line
- int_segment_arc
- int_segment_circle
- int_segment_segment
- if_really_intersecting_arc_arc
- if_really_intersecting_segment_arc
- if_really_intersecting_segment_segment

## Geometric Primitives

- Points
- Line Segments
- Circles
- Circle Arcs
- Polylines
- Intervals
- PVertices (point, bulge)

## Point (vector) Manipulation
- add, sub, neg, mul(f64), div(f64)
- dot
- perp
- norm
- normalize
- almost_eq (ULP-s)
- close_enough (eps)
- lerp
- sort_colinear_points

## Utilities functions
- almost_equal_as_int (ULP-s)
- perturbed_ulps_as_int (ULP-s)
- close_enough (eps)
- diff_of_prod
- sum_of_prod

## Algorithms
- Convex Hull (Pointline)
- Convexity Detection (Pointline)
- Area Calculations (Pointline and Arcline)
- Bounding Circle (Arc)
- Bounding Rectangle (Arc)

## Examples

### Creating and working with points (vectors)
```rust
use togo::prelude::*;
// Create points using the constructor or convenience function
let p1 = Point::new(1.0, 2.0);
let p2 = point(3.0, 4.0);
// Points support arithmetic operations
let sum = p1 + p2;
assert_eq!(sum.x, 4.0);
assert_eq!(sum.y, 6.0);
// Calculate distance between points
let distance = (p2 - p1).norm();
assert!((distance - 2.828427124746190).abs() < 1e-10);
```

### Working with geometric primitives
```rust
use togo::prelude::*;
// Create a circle and segment
let center = point(0.0, 0.0);
let c = circle(center, 5.0);
let seg = segment(point(-3.0, 0.0), point(3.0, 0.0));
assert_eq!(c.c, center);  // Circle center field is 'c'
assert_eq!(c.r, 5.0);     // Circle radius field is 'r'
assert_eq!(seg.a.x, -3.0);
assert_eq!(seg.b.x, 3.0);
```

### Distance computations
```rust
use togo::prelude::*;
// Distance from point to circle returns (distance, closest_point, is_equidistant)
let p = point(10.0, 0.0);
let c = circle(point(0.0, 0.0), 5.0);
let (dist, closest, _is_equidistant) = dist_point_circle(&p, &c);
assert_eq!(dist, 5.0);
// Distance from point to segment returns (distance, closest_point)
let seg = segment(point(0.0, 0.0), point(5.0, 0.0));
let p = point(2.5, 3.0);
let (dist, _closest) = dist_point_segment(&p, &seg);
assert_eq!(dist, 3.0);
```

### Intersection computations
```rust
use togo::prelude::*;
// Test intersection between two circles
let c1 = circle(point(0.0, 0.0), 3.0);
let c2 = circle(point(4.0, 0.0), 3.0);
let result = int_circle_circle(c1, c2);
// Two circles with overlapping areas should intersect at two points
match result {
    CircleCircleConfig::NoncocircularTwoPoints(_, _) => {
        // Two intersection points found
        assert!(true);
    },
    _ => {
        // No intersection or other cases
        assert!(false);
    }
}
```

### Working with arcs


> [!IMPORTANT]
> Arcs are always CCW (counter-clockwise) in this library.


```rust
use togo::prelude::*;
// Create an arc from three points and radius (start, end, center, radius)
let start = point(1.0, 0.0);
let end = point(0.0, 1.0);
let center = point(0.0, 0.0);
let a = arc(start, end, center, 1.0);
assert_eq!(a.a, start);   // Arc start point field is 'a'
assert_eq!(a.b, end);     // Arc end point field is 'b'
assert_eq!(a.c, center);  // Arc center field is 'c'
assert_eq!(a.r, 1.0);     // Arc radius field is 'r'
```

### Working with lines
```rust
use togo::prelude::*;
// Create a line from a point and direction vector
let origin = point(0.0, 0.0);
let direction = point(1.0, 1.0);
let l = line(origin, direction);
assert_eq!(l.origin, origin);
assert_eq!(l.dir, direction);
```

### Working with intervals
```rust
use togo::prelude::*;
// Create an interval (tuple struct with two f64 values)
let iv = interval(1.0, 5.0);
assert_eq!(iv.0, 1.0);  // First endpoint
assert_eq!(iv.1, 5.0);  // Second endpoint
// Test if a value is contained in the interval
assert!(iv.contains(3.0));
assert!(!iv.contains(6.0));
```

### Working with polylines (PVertex)
```rust
use togo::prelude::*;
// Create vertices for a polyline
let p1 = pvertex(point(0.0, 0.0), 0.0);
let p2 = pvertex(point(1.0, 0.0), 0.0);
let p3 = pvertex(point(1.0, 1.0), 0.0);
let polyline = vec![p1, p2, p3];
// Translate the polyline (returns a new polyline)
let offset = point(2.0, 3.0);
let translated = polyline_translate(&polyline, offset);
assert_eq!(translated[0].p.x, 2.0);
assert_eq!(translated[0].p.y, 3.0);
```

### Arc-arc distance computation
```rust
use togo::prelude::*;
// Create two separate arcs
let a1 = arc(point(1.0, 0.0), point(-1.0, 0.0), point(0.0, 0.0), 1.0);
let a2 = arc(point(4.0, 0.0), point(2.0, 0.0), point(3.0, 0.0), 1.0);
// Compute distance between arcs (returns just the distance as f64)
let dist = dist_arc_arc(&a1, &a2);
assert_eq!(dist, 1.0); // Distance between the arc edges
```

### Line-circle intersection
```rust
use togo::prelude::*;
// Create a line and circle that intersect
let l = line(point(-3.0, 0.0), point(1.0, 0.0)); // Horizontal line through origin
let c = circle(point(0.0, 0.0), 2.0);
let result = int_line_circle(&l, &c);
match result {
    LineCircleConfig::TwoPoints(..) => {
        // Line intersects circle at two points
        assert!(true);
    },
    _ => assert!(false),
}
```

### Segment-segment intersection
```rust
use togo::prelude::*;
// Create two intersecting segments
let seg1 = segment(point(0.0, 0.0), point(2.0, 2.0));
let seg2 = segment(point(0.0, 2.0), point(2.0, 0.0));
let result = int_segment_segment(&seg1, &seg2);
match result {
    SegmentSegmentConfig::OnePoint(pt, ..) => {
        // Segments intersect at one point (should be around (1,1))
        assert!(point(1.0, 1.0).close_enough(pt, 1e-10));
    },
    _ => assert!(false),
}
```

### Utility functions
```rust
use togo::prelude::*;
// Test floating point equality with tolerance
assert!(close_enough(1.0, 1.0000001, 1e-5));
assert!(!close_enough(1.0, 1.1, 1e-5));
// Check if two floats are almost equal using integer comparison
assert!(almost_equal_as_int(1.0, 1.0, 0));
```

### Arc-Arc intersection
```rust
use togo::prelude::*;
// Create two intersecting arcs
let a1 = arc(point(1.0, 0.0), point(0.0, 1.0), point(0.0, 0.0), 1.0);
    let a2 = arc(point(1.0, 1.0), point(0.0, 0.0), point(1.0, 0.0), 1.0);
    let result = int_arc_arc(&a1, &a2);
    match result {
        ArcArcConfig::NonCocircularOnePoint(pt) => {
            // Arcs intersect at one point
            assert_eq!(point(0.5, 0.8660254037844386), pt);
        },
        _ => {
            // Could be two points, no intersection, or other cases
            assert!(false); // Accept other valid intersection results
        }
    }
```

### Distance computations
```rust
use togo::prelude::*;
let l = line(point(0.0, 3.0), point(1.0, 0.0)); // Line with point and direction
let c = circle(point(0.0, 0.0), 2.0);
let result = dist_line_circle(&l, &c);
match result {
    DistLineCircleConfig::OnePair(dist, _param, _line_pt, _circle_pt) => {
        assert_eq!(1.0, dist);
    }
    _ => assert!(false), // Accept other valid distance results
}
// Distance from point to arc
let p = point(2.0, 0.0);
let a = arc(point(0.0, 1.0), point(1.0, 0.0), point(0.0, 0.0), 1.0);
match dist_point_arc(&p, &a) {
    DistPointArcConfig::OnePoint(dist, _) => {
        assert_eq!(1.0, dist);
    }
    _ => assert!(false), // Accept other valid distance results
}
// Distance from segment to arc
let seg = segment(point(3.0, 0.0), point(4.0, 0.0));
let a = arc(point(0.0, 1.0), point(1.0, 0.0), point(0.0, 0.0), 1.0);
let dist = dist_segment_arc(&seg, &a);
    assert_eq!(2.0, dist);
```

```rust
use togo::prelude::*;
// Distance from segment to circle
let seg = segment(point(3.0, 0.0), point(4.0, 0.0));
let c = circle(point(0.0, 0.0), 1.0);
let result = dist_segment_circle(&seg, &c);
// Function returns DistSegmentCircleConfig enum
match result {
    DistSegmentCircleConfig::OnePoint(dist, closest) => {
        assert_eq!(2.0, dist); // Distance should be non-negative
    }
    _ => assert!(false), // Accept any valid distance result
}
// Distance between two segments
let seg1 = segment(point(0.0, 0.0), point(1.0, 0.0));
let seg2 = segment(point(0.0, 2.0), point(1.0, 2.0));
let dist = dist_segment_segment(&seg1, &seg2);
assert_eq!(dist, 2.0); // Parallel segments 2 units apart
```

### Intersection computations
```rust
use togo::prelude::*;
let seg1 = segment(point(0.0, 0.0), point(1.0, 0.0));
let seg2 = segment(point(0.0, 2.0), point(1.0, 2.0));
let dist = dist_segment_segment(&seg1, &seg2);
assert_eq!(dist, 2.0); // Parallel segments 2 units apart
```

### Intersection computations
```rust
use togo::prelude::*;
// Interval-interval intersection
let iv1 = interval(1.0, 5.0);
let iv2 = interval(3.0, 7.0);
let result = int_interval_interval(iv1, iv2);
match result {
    IntervalConfig::Overlap(start, end) => {
        // Intervals overlap from 3.0 to 5.0
        assert_eq!(start, 3.0);
        assert_eq!(end, 5.0);
    },
    _ => assert!(false), // Accept other valid intersection results
}
// Line-line intersection
let l1 = line(point(0.0, 0.0), point(1.0, 0.0)); // Line with origin and direction
let l2 = line(point(0.0, 0.0), point(0.0, 1.0)); // Line with origin and direction
let result = int_line_line(&l1, &l2);
match result {
    LineLineConfig::OnePoint(pt, _param1, _param2) => {
        // Lines intersect at origin
        assert_eq!(point(0.0, 0.0), pt);
    },
    _ => assert!(false), // Accept other valid intersection results
}
```

### Area Calculations
```rust
use togo::prelude::*;
use togo::algo::{pointline_area, arcline_area};

// Calculate area of a polygon defined by points
let triangle = vec![
    point(0.0, 0.0),
    point(4.0, 0.0),
    point(2.0, 3.0),
    point(0.0, 0.0)  // Close the polygon
];
let area = pointline_area(&triangle);
assert_eq!(area, 6.0); // Triangle area = 0.5 * base * height = 0.5 * 4 * 3 = 6

// Calculate area of a shape with both line segments and arcs
let square_with_arc = vec![
    arc(point(0.0, 0.0), point(2.0, 0.0), point(0.0, 0.0), 0.0),  // Bottom edge (line)
    arc(point(2.0, 0.0), point(2.0, 2.0), point(0.0, 0.0), 0.0),  // Right edge (line)
    arc(point(2.0, 2.0), point(0.0, 2.0), point(1.0, 3.0), 1.0),  // Top edge (semicircle)
    arc(point(0.0, 2.0), point(0.0, 0.0), point(0.0, 0.0), 0.0),  // Left edge (line)
];
let area_with_arc = arcline_area(&square_with_arc);
// Area includes the square plus the semicircular bulge
assert_eq!(area_with_arc, 5.356194490192345);
```

### Bounding Calculations
```rust
use togo::prelude::*;
use togo::algo::{arc_bounding_circle, arc_bounding_rect};

// Find the smallest circle that contains an arc
let quarter_arc = arc(point(1.0, 0.0), point(0.0, 1.0), point(0.0, 0.0), 1.0);
let bounding_circle = arc_bounding_circle(&quarter_arc);
// For a quarter circle, the bounding circle is smaller than the arc's own circle
assert_eq!(bounding_circle.r, 0.7071067811865476); // sqrt(2)/2

// Find the smallest axis-aligned rectangle that contains an arc
let semicircle = arc(point(-1.0, 0.0), point(1.0, 0.0), point(0.0, 0.0), 1.0);
let bounding_rect = arc_bounding_rect(&semicircle);
// Rectangle should span from -1 to 1 in x, and include the arc's extremes
assert_eq!(bounding_rect.p1.x, -1.0); // min_x
assert_eq!(bounding_rect.p2.x, 1.0);  // max_x

// Bounding rectangle for a line segment
let line_segment = arcseg(point(1.0, 2.0), point(4.0, 6.0));
let line_rect = arc_bounding_rect(&line_segment);
assert_eq!(line_rect.p1, point(1.0, 2.0)); // Bottom-left corner
assert_eq!(line_rect.p2, point(4.0, 6.0)); // Top-right corner
```

#### Convex Hull Computation
```rust
use togo::prelude::*;
use togo::algo::{pointline_convex_hull, is_convex_pointline};

// Find the convex hull of a set of points
let points = vec![
    point(0.0, 0.0),
    point(2.0, 1.0),
    point(1.0, 2.0),    // Interior point (will be excluded)
    point(3.0, 0.0),
    point(2.0, 3.0),
    point(0.0, 2.0),
];
let hull = pointline_convex_hull(&points);
// Hull should contain only the exterior points
assert_eq!(hull.len(), 4); // 4 points on the convex hull

// Check if a polygon is convex
let convex_polygon = vec![
    point(0.0, 0.0),
    point(2.0, 0.0),
    point(2.0, 2.0),
    point(0.0, 2.0),
];
assert!(is_convex_pointline(&convex_polygon)); // Square is convex

let concave_polygon = vec![
    point(0.0, 0.0),
    point(2.0, 0.0),
    point(2.0, 2.0),
    point(1.0, 1.0),    // Creates concave indentation
    point(0.0, 2.0),
];
assert!(!is_convex_pointline(&concave_polygon)); // This shape is concave
```