1
1
//! This module defines a curve and primitive functions on them
2
2
//! Most common manipulations are projecting a point on the curve
3
3
//! and otherway round find the coordinates of a point along the curve
4
- //! For now the implementation is based on a [LineString],
4
+ //! For now the implementation is based on a [` LineString` ],
5
5
//! but other implementations could be considered such as splines
6
6
7
7
use geo:: kernels:: RobustKernel ;
8
8
use geo:: prelude:: * ;
9
9
use geo:: { coord, Line , LineString , Point , Rect } ;
10
10
use thiserror:: Error ;
11
11
12
- /// A `Curve` is the fundamental building block for an LRM.
12
+ /// A [ `Curve`] is the fundamental building block for an LRM.
13
13
/// It provides basic primitives to locate/project points on it.
14
- /// A `Curve` can be part of a larger `Curve` (e.g. for optimisation purposes and to have better bounding boxes).
15
- /// The `Curve` can be implemented.
14
+ /// A [ `Curve`] can be part of a larger [ `Curve`] (e.g. for optimisation purposes and to have better bounding boxes).
15
+ /// The [ `Curve`] can be implemented.
16
16
pub trait Curve {
17
- /// Builds a new `Curve` from a [LineString].
17
+ /// Builds a new[ `Curve`] from a [` LineString` ].
18
18
/// `max_extent` is the maximum distance that is considered to be “on the curve”.
19
19
/// `max_extent` plays a role in the bounding box.
20
20
fn new ( geom : LineString , max_extent : f64 ) -> Self ;
21
21
22
- /// Projects the [Point] to the closest position on the `Curve`.
23
- /// Will fail if the `Curve` is invalid (e.g. no `Point` on it)
24
- /// or if the `Point` is too far away.
25
- /// If the `Curve` is a piece of a larger `Curve` (`start_offset > 0`)
26
- /// then the `distance_along_curve` if from the whole `Curve`, not just the current piece.
22
+ /// Projects the [` Point` ] to the closest position on the [ `Curve`] .
23
+ /// Will fail if the [ `Curve`] is invalid (e.g. no [ `Point`] on it)
24
+ /// or if the [ `Point`] is too far away.
25
+ /// If the [ `Curve`] is a piece of a larger [ `Curve`] (`start_offset > 0`)
26
+ /// then the `distance_along_curve` if from the whole [ `Curve`] , not just the current piece.
27
27
fn project ( & self , point : Point ) -> Result < CurveProjection , CurveError > ;
28
28
29
- /// Returns the geographical position of a [Point] on the `Curve`.
30
- /// Will return an error if the `CurveProjection` is not on this `Curve`.
29
+ /// Returns the geographical position of a [` Point` ] on the [ `Curve`] .
30
+ /// Will return an error if the `CurveProjection` is not on this [ `Curve`] .
31
31
fn resolve ( & self , projection : CurveProjection ) -> Result < Point , CurveError > ;
32
32
33
- /// Bounding box of the `Curve` with a buffer of `max_extent`.
33
+ /// Bounding box of the [ `Curve`] with a buffer of `max_extent`.
34
34
fn bbox ( & self ) -> Rect ;
35
35
36
- /// The length of the `Curve`.
36
+ /// The length of the [ `Curve`] .
37
37
fn length ( & self ) -> f64 ;
38
38
39
- /// Computes the normal at a given offset on the `Curve`.
40
- /// Will return an error if the `Curve` is invalid or the offset is outside of the `Curve`.
39
+ /// Computes the normal at a given offset on the [ `Curve`] .
40
+ /// Will return an error if the [ `Curve`] is invalid or the offset is outside of the [ `Curve`] .
41
41
/// Points to the positive side (left).
42
42
fn get_normal ( & self , offset : f64 ) -> Result < ( f64 , f64 ) , CurveError > ;
43
43
44
- /// Returns the [Point] where the `Curve` and the segment intersect.
45
- /// If the segment intersects the `Curve` multiple times, an intersection is chosen randomly.
46
- /// When the segment is colinear with the `Curve` it is ignored.
44
+ /// Returns the [` Point` ] where the [ `Curve`] and the segment intersect.
45
+ /// If the segment intersects the [ `Curve`] multiple times, an intersection is chosen randomly.
46
+ /// When the segment is colinear with the [ `Curve`] it is ignored.
47
47
fn intersect_segment ( & self , segment : Line ) -> Option < Point > ;
48
48
49
49
/// Is the geometry valid. Depending on the representation.
50
50
/// It must have at least two coordinates.
51
51
/// If there are exactly two coordinates, they must be different.
52
52
fn is_valid ( & self ) -> bool ;
53
53
54
- /// How far from the `Curve` could be considered to be still on the `Curve`.
54
+ /// How far from the [ `Curve`] could be considered to be still on the [ `Curve`] .
55
55
fn max_extent ( & self ) -> f64 ;
56
56
}
57
57
58
- /// Errors when manipulating the [Curve] objects .
58
+ /// Errors when manipulating the [` Curve`]s .
59
59
#[ derive( Error , Debug , PartialEq ) ]
60
60
pub enum CurveError {
61
- /// The condition of validity might differ depending on the [Curve] implementation.
61
+ /// The condition of validity might differ depending on the [` Curve` ] implementation.
62
62
#[ error( "the curve geometry is not valid" ) ]
63
63
InvalidGeometry ,
64
64
/// At least one coordinate is non a finite number (`NaN`, `infinite`).
65
65
#[ error( "the coordinates are not finite" ) ]
66
66
NotFiniteCoordinates ,
67
- /// The considered [Point] is not on the [Curve].
67
+ /// The considered [` Point` ] is not on the [` Curve` ].
68
68
#[ error( "the point is not on the curve" ) ]
69
69
NotOnTheCurve ,
70
70
}
71
71
72
- /// Implementation based on [LineString]:
73
- /// the [Curve] is a string of continous [Line].
72
+ /// Implementation based on [`LineString`]:
73
+ /// the [`Curve`] is a string of continous [`Line`]s.
74
+ /// Each [`Line`] made up of 2 [`Coord`]s.
75
+ /// This implementation doesn't take in account the ellipsoidal model of the earth.
74
76
/// The coordinates are reprensented by `f64`.
75
- /// That means a precison of about 1_000_000th of a mm for a `Curve` that spans around the Earth.
76
- pub struct LineStringCurve {
77
- /// When a [Curve] might be a piece of a longer `Curve`
78
- /// then the `start_offset` allows to know how fare along the longer `Curve` we are.
77
+ /// That means a precison of about 1_000_000th of a mm for a [ `Curve`] that spans around the Earth.
78
+ pub struct PlanarLineStringCurve {
79
+ /// When a [` Curve` ] might be a piece of a longer [ `Curve`]
80
+ /// then the `start_offset` allows to know how far along the longer [ `Curve`] we are.
79
81
pub start_offset : f64 ,
80
82
81
- /// The max distance that is considered of being part of the [Curve].
83
+ /// The max distance that is considered of being part of the [` Curve` ].
82
84
/// It is used to compute the bounding box.
83
85
pub max_extent : f64 ,
84
86
@@ -89,8 +91,8 @@ pub struct LineStringCurve {
89
91
length : f64 ,
90
92
}
91
93
92
- impl LineStringCurve {
93
- /// Splits the [LineString] into smaller [Curve] objects of at most `max_len` length.
94
+ impl PlanarLineStringCurve {
95
+ /// Splits the [` LineString` ] into smaller [` Curve`]s of at most `max_len` length.
94
96
/// If the initial geometry is invalid, it returns an empty vector.
95
97
pub fn new_fragmented ( geom : LineString , max_len : f64 , max_extent : f64 ) -> Vec < Self > {
96
98
let n = ( geom. euclidean_length ( ) / max_len) . ceil ( ) as usize ;
@@ -106,7 +108,7 @@ impl LineStringCurve {
106
108
}
107
109
}
108
110
109
- impl Curve for LineStringCurve {
111
+ impl Curve for PlanarLineStringCurve {
110
112
fn new ( geom : LineString , max_extent : f64 ) -> Self {
111
113
let length = geom. euclidean_length ( ) ;
112
114
Self {
@@ -211,8 +213,8 @@ impl Curve for LineStringCurve {
211
213
Ok ( ( result. end . x , result. end . y ) )
212
214
}
213
215
214
- /// It must have at least two coordinates
215
- /// If there are exactly two coordinates , they must be different
216
+ /// It must have at least two [`Coord`]s.
217
+ /// If there are exactly two [`Coord`]s , they must be different.
216
218
fn is_valid ( & self ) -> bool {
217
219
self . geom . coords_count ( ) >= 2 && ( self . geom . coords_count ( ) > 2 || !self . geom . is_closed ( ) )
218
220
}
@@ -222,16 +224,16 @@ impl Curve for LineStringCurve {
222
224
}
223
225
}
224
226
225
- /// Represents a [Point] in space projected on the [Curve]
227
+ /// Represents a [` Point` ] in space projected on the [` Curve`].
226
228
#[ derive( Clone , Copy ) ]
227
229
pub struct CurveProjection {
228
- /// How far from the [Curve] start is located the [Point]
229
- /// If the `Curve` is part of a larger `Curve`, `start_offset` is strictly positive
230
+ /// How far from the [` Curve` ] start is located the [` Point` ]
231
+ /// If the [ `Curve`] is part of a larger [ `Curve`] , `start_offset` is strictly positive
230
232
/// and the `start_offset` will be considered
231
233
pub distance_along_curve : f64 ,
232
- /// How far is the [Point] from the [Curve] (euclidian distance)
233
- /// It is positive if the `Point` is located on the left of the `Curve`
234
- /// and negative if the `Point` is on the right
234
+ /// How far is the [` Point` ] from the [` Curve` ] (euclidian distance)
235
+ /// It is positive if the [ `Point`] is located on the left of the [ `Curve`]
236
+ /// and negative if the [ `Point`] is on the right
235
237
pub offset : f64 ,
236
238
}
237
239
@@ -243,14 +245,14 @@ mod tests {
243
245
use geo:: point;
244
246
245
247
#[ test]
246
- fn length ( ) {
247
- let c = LineStringCurve :: new ( line_string ! [ ( x: 0. , y: 0. ) , ( x: 2. , y: 0. ) ] , 1. ) ;
248
+ fn planar_length ( ) {
249
+ let c = PlanarLineStringCurve :: new ( line_string ! [ ( x: 0. , y: 0. ) , ( x: 2. , y: 0. ) ] , 1. ) ;
248
250
assert_eq ! ( 2. , c. length( ) ) ;
249
251
}
250
252
251
253
#[ test]
252
254
fn projection ( ) {
253
- let mut c = LineStringCurve :: new ( line_string ! [ ( x: 0. , y: 0. ) , ( x: 2. , y: 0. ) ] , 1. ) ;
255
+ let mut c = PlanarLineStringCurve :: new ( line_string ! [ ( x: 0. , y: 0. ) , ( x: 2. , y: 0. ) ] , 1. ) ;
254
256
255
257
let projected = c. project ( point ! { x: 1. , y: 1. } ) . unwrap ( ) ;
256
258
assert_eq ! ( 1. , projected. distance_along_curve) ;
@@ -267,7 +269,7 @@ mod tests {
267
269
268
270
#[ test]
269
271
fn resolve ( ) {
270
- let mut c = LineStringCurve :: new ( line_string ! [ ( x: 0. , y: 0. ) , ( x: 2. , y: 0. ) ] , 1. ) ;
272
+ let mut c = PlanarLineStringCurve :: new ( line_string ! [ ( x: 0. , y: 0. ) , ( x: 2. , y: 0. ) ] , 1. ) ;
271
273
272
274
let mut projection = CurveProjection {
273
275
distance_along_curve : 1. ,
@@ -287,7 +289,7 @@ mod tests {
287
289
288
290
#[ test]
289
291
fn bbox ( ) {
290
- let c = LineStringCurve :: new ( line_string ! [ ( x: 0. , y: 0. ) , ( x: 2. , y: 0. ) ] , 1. ) ;
292
+ let c = PlanarLineStringCurve :: new ( line_string ! [ ( x: 0. , y: 0. ) , ( x: 2. , y: 0. ) ] , 1. ) ;
291
293
let bbox = c. bbox ( ) ;
292
294
293
295
assert_eq ! ( bbox. min( ) , coord! { x: -1. , y: -1. } ) ;
@@ -297,7 +299,7 @@ mod tests {
297
299
#[ test]
298
300
fn intersect_segment ( ) {
299
301
// Right angle
300
- let c = LineStringCurve :: new ( line_string ! [ ( x: 0. , y: 0. ) , ( x: 2. , y: 0. ) ] , 1. ) ;
302
+ let c = PlanarLineStringCurve :: new ( line_string ! [ ( x: 0. , y: 0. ) , ( x: 2. , y: 0. ) ] , 1. ) ;
301
303
let segment = Line :: new ( coord ! { x: 1. , y: 1. } , coord ! { x: 1. , y: -1. } ) ;
302
304
let intersection = c. intersect_segment ( segment) ;
303
305
assert_eq ! ( intersection, Some ( point! { x: 1. , y: 0. } ) ) ;
@@ -311,7 +313,7 @@ mod tests {
311
313
assert ! ( c. intersect_segment( segment) . is_none( ) ) ;
312
314
313
315
// Multiple intersection
314
- let c = LineStringCurve :: new (
316
+ let c = PlanarLineStringCurve :: new (
315
317
line_string ! [ ( x: 0. , y: 0. ) , ( x: 1. , y: 2. ) , ( x: 2. , y: 0. ) ] ,
316
318
1. ,
317
319
) ;
@@ -322,14 +324,14 @@ mod tests {
322
324
#[ test]
323
325
fn fragmented ( ) {
324
326
let c =
325
- LineStringCurve :: new_fragmented ( line_string ! [ ( x: 0. , y: 0. ) , ( x: 2. , y: 0. ) ] , 1. , 1. ) ;
327
+ PlanarLineStringCurve :: new_fragmented ( line_string ! [ ( x: 0. , y: 0. ) , ( x: 2. , y: 0. ) ] , 1. , 1. ) ;
326
328
assert_eq ! ( 2 , c. len( ) ) ;
327
329
assert_eq ! ( 1. , c[ 0 ] . length( ) ) ;
328
330
}
329
331
330
332
#[ test]
331
333
fn normal ( ) {
332
- let c = LineStringCurve :: new ( line_string ! [ ( x: 0. , y: 0. ) , ( x: 2. , y: 0. ) ] , 1. ) ;
334
+ let c = PlanarLineStringCurve :: new ( line_string ! [ ( x: 0. , y: 0. ) , ( x: 2. , y: 0. ) ] , 1. ) ;
333
335
let normal = c. get_normal ( 1. ) . unwrap ( ) ;
334
336
assert_relative_eq ! ( normal. 0 , 0. ) ;
335
337
assert_relative_eq ! ( normal. 1 , 1. ) ;
0 commit comments