@@ -29,13 +29,36 @@ pub enum LrmScaleError {
2929 NoAnchorFound ,
3030}
3131
32- /// An `Anchor` is a reference point that is well known from which the location is computed.
32+ /// An unnamed anchor is an anchor that is not a landmark, and no point will be referenced from that anchor.
33+ ///
34+ /// It is used to match a scale position with a `Curve` position.
35+ /// This can happen when an object between two `NamedAnchor` has a bad offset:
36+ /// if it is said to be 300m away from the previous named anchor, but in reality it is 322m.
37+ /// This makes sure that an object label at +310m is located after the one at +300m.
3338#[ derive( PartialEq , Debug , Clone ) ]
34- pub struct Anchor {
35- /// Some `Anchor` objects might not be named,
36- /// e.g. the first anchor of the LRM.
37- pub id : Option < String > ,
39+ pub struct UnnamedAnchor {
40+ /// Distance from the start of the scale in the scale space, can be negative.
41+ pub scale_position : ScalePosition ,
42+
43+ /// Real distance from the start of the `Curve`.
44+ /// The `Curve` might not start at the same 0 (e.g. the `Curve` is longer than the scale),
45+ /// or the `Curve` might not progress at the same rate (e.g. the `Curve` is a schematic representation that distorts distances).
46+ pub curve_position : CurvePosition ,
47+
48+ /// Position of the anchor on the `Curve`.
49+ pub point : Option < Point > ,
3850
51+ /// Metadata to describe the node
52+ pub properties : Properties ,
53+ }
54+
55+ /// A named anchor is an anchor that is a known reference point.
56+ ///
57+ /// It often is a milestone (such a km 42), but it can be any landmark (a bridge, a notable building…)
58+ #[ derive( PartialEq , Debug , Clone ) ]
59+ pub struct NamedAnchor {
60+ /// The name that identifies the anchor. It must be unique within the `LrmScale`.
61+ pub name : String ,
3962 /// Distance from the start of the scale in the scale space, can be negative.
4063 pub scale_position : ScalePosition ,
4164
@@ -51,54 +74,90 @@ pub struct Anchor {
5174 pub properties : Properties ,
5275}
5376
77+ /// An anchor is a reference point on a `LrmScale`.
78+ ///
79+ /// It can either be a `NamedAnchor` or an `UnnamedAnchor`.
80+ #[ derive( Debug , PartialEq , Clone ) ]
81+ pub enum Anchor {
82+ /// A `NamedAnchor`
83+ Named ( NamedAnchor ) ,
84+ /// An `UnnamedAnchor`
85+ Unnamed ( UnnamedAnchor ) ,
86+ }
87+
5488impl Anchor {
5589 /// Builds a named `Anchor`.
56- pub fn new (
90+ pub fn new_named (
5791 name : & str ,
5892 scale_position : ScalePosition ,
5993 curve_position : CurvePosition ,
6094 point : Option < Point > ,
6195 properties : Properties ,
6296 ) -> Self {
63- Self {
64- id : Some ( name. to_owned ( ) ) ,
97+ Self :: Named ( NamedAnchor {
98+ name : name. to_owned ( ) ,
6599 scale_position,
66100 curve_position,
67101 point,
68102 properties,
69- }
103+ } )
70104 }
71105
72- /// Builds an unnamed `Anchor` .
106+ /// Create an unnamed anchor .
73107 pub fn new_unnamed (
74108 scale_position : ScalePosition ,
75109 curve_position : CurvePosition ,
76110 point : Option < Point > ,
77111 properties : Properties ,
78112 ) -> Self {
79- Self {
80- id : None ,
113+ Self :: Unnamed ( UnnamedAnchor {
81114 scale_position,
82115 curve_position,
83116 point,
84117 properties,
118+ } )
119+ }
120+
121+ /// Position of the anchor on the scale.
122+ ///
123+ /// This value is arbitrary. It typically is expressed in meters, but can be any unit.
124+ /// It is common, but not necessary that the scale starts at 0 at the start of the curve.
125+ pub fn scale_position ( & self ) -> ScalePosition {
126+ match self {
127+ Anchor :: Named ( anchor) => anchor. scale_position ,
128+ Anchor :: Unnamed ( anchor) => anchor. scale_position ,
85129 }
86130 }
87131
88- fn as_named ( & self ) -> Option < NamedAnchor > {
89- self . id . as_ref ( ) . map ( |id| NamedAnchor {
90- id : id. to_owned ( ) ,
91- scale_position : self . scale_position ,
92- curve_position : self . curve_position ,
93- } )
132+ /// Position of the anchor on the curve.
133+ ///
134+ /// The value is between 0 and 1 and represents a fraction of the curve.
135+ /// The can sometimes be negative to represent an anchor located before the curve starts.
136+ pub fn curve_position ( & self ) -> ScalePosition {
137+ match self {
138+ Anchor :: Named ( anchor) => anchor. curve_position ,
139+ Anchor :: Unnamed ( anchor) => anchor. curve_position ,
140+ }
141+ }
142+
143+ /// Properties of the anchor
144+ pub fn properties ( & self ) -> & Properties {
145+ match self {
146+ Anchor :: Named ( anchor) => & anchor. properties ,
147+ Anchor :: Unnamed ( anchor) => & anchor. properties ,
148+ }
94149 }
95- }
96150
97- // Private struct to be used when we only deal with Anchor that has name.
98- struct NamedAnchor {
99- id : String ,
100- scale_position : ScalePosition ,
101- curve_position : CurvePosition ,
151+ /// Geographical position of the anchor
152+ ///
153+ /// The location can be outside of the curve (a landmark visible from the curve)
154+ /// It is optional as it might be defined only with the curve position
155+ pub fn point ( & self ) -> Option < Point > {
156+ match self {
157+ Anchor :: Named ( anchor) => anchor. point ,
158+ Anchor :: Unnamed ( anchor) => anchor. point ,
159+ }
160+ }
102161}
103162
104163/// A measure defines a location on the [LrmScale].
@@ -125,7 +184,7 @@ impl LrmScaleMeasure {
125184}
126185
127186/// Represents an `LrmScale` and allows to map [Measure] to a position along a `Curve`.
128- #[ derive( PartialEq , Debug ) ]
187+ #[ derive( PartialEq , Debug , Clone ) ]
129188pub struct LrmScale {
130189 /// Unique identifier.
131190 pub id : String ,
@@ -140,21 +199,21 @@ impl LrmScale {
140199 pub fn locate_point ( & self , measure : & LrmScaleMeasure ) -> Result < CurvePosition , LrmScaleError > {
141200 let named_anchor = self
142201 . iter_named ( )
143- . find ( |anchor| anchor. id == measure. anchor_name )
202+ . find ( |anchor| anchor. name == measure. anchor_name )
144203 . ok_or ( LrmScaleError :: UnknownAnchorName ) ?;
145204
146205 let scale_position = named_anchor. scale_position + measure. scale_offset ;
147206 let anchors = self
148207 . anchors
149208 . windows ( 2 )
150- . find ( |window| window[ 1 ] . scale_position >= scale_position)
209+ . find ( |window| window[ 1 ] . scale_position ( ) >= scale_position)
151210 . or_else ( || self . anchors . windows ( 2 ) . last ( ) )
152211 . ok_or ( LrmScaleError :: NoAnchorFound ) ?;
153212
154- let scale_interval = anchors[ 0 ] . scale_position - anchors[ 1 ] . scale_position ;
155- let curve_interval = anchors[ 0 ] . curve_position - anchors[ 1 ] . curve_position ;
156- Ok ( anchors[ 0 ] . curve_position
157- + curve_interval * ( scale_position - anchors[ 0 ] . scale_position ) / scale_interval)
213+ let scale_interval = anchors[ 0 ] . scale_position ( ) - anchors[ 1 ] . scale_position ( ) ;
214+ let curve_interval = anchors[ 0 ] . curve_position ( ) - anchors[ 1 ] . curve_position ( ) ;
215+ Ok ( anchors[ 0 ] . curve_position ( )
216+ + curve_interval * ( scale_position - anchors[ 0 ] . scale_position ( ) ) / scale_interval)
158217 }
159218
160219 /// Returns a measure given a distance along the `Curve`.
@@ -172,19 +231,19 @@ impl LrmScale {
172231 // Then we search the nearest Anchor that will be the reference
173232 // to convert from Curve units to scale units.
174233 let nearest_anchor = if named_anchor. curve_position < curve_position {
175- self . next_anchor ( & named_anchor. id )
176- . or ( self . previous_anchor ( & named_anchor. id ) )
234+ self . next_anchor ( & named_anchor. name )
235+ . or ( self . previous_anchor ( & named_anchor. name ) )
177236 } else {
178- self . previous_anchor ( & named_anchor. id )
179- . or ( self . next_anchor ( & named_anchor. id ) )
237+ self . previous_anchor ( & named_anchor. name )
238+ . or ( self . next_anchor ( & named_anchor. name ) )
180239 }
181240 . ok_or ( LrmScaleError :: NoAnchorFound ) ?;
182241
183- let ratio = ( nearest_anchor. scale_position - named_anchor. scale_position )
184- / ( nearest_anchor. curve_position - named_anchor. curve_position ) ;
242+ let ratio = ( nearest_anchor. scale_position ( ) - named_anchor. scale_position )
243+ / ( nearest_anchor. curve_position ( ) - named_anchor. curve_position ) ;
185244
186245 Ok ( LrmScaleMeasure {
187- anchor_name : named_anchor. id ,
246+ anchor_name : named_anchor. name . clone ( ) ,
188247 scale_offset : ( curve_position - named_anchor. curve_position ) * ratio,
189248 } )
190249 }
@@ -201,7 +260,7 @@ impl LrmScale {
201260 . ok_or ( LrmScaleError :: NoAnchorFound ) ?;
202261
203262 Ok ( LrmScaleMeasure {
204- anchor_name : named_anchor. id ,
263+ anchor_name : named_anchor. name . clone ( ) ,
205264 scale_offset : scale_position - named_anchor. scale_position ,
206265 } )
207266 }
@@ -211,13 +270,13 @@ impl LrmScale {
211270 pub fn get_position ( & self , measure : LrmScaleMeasure ) -> Result < ScalePosition , LrmScaleError > {
212271 let named_anchor = self
213272 . iter_named ( )
214- . find ( |anchor| anchor. id == measure. anchor_name )
273+ . find ( |anchor| anchor. name == measure. anchor_name )
215274 . ok_or ( LrmScaleError :: UnknownAnchorName ) ?;
216275
217276 Ok ( named_anchor. scale_position + measure. scale_offset )
218277 }
219278
220- fn nearest_named ( & self , curve_position : CurvePosition ) -> Option < NamedAnchor > {
279+ fn nearest_named ( & self , curve_position : CurvePosition ) -> Option < & NamedAnchor > {
221280 // Tries to find the Anchor whose curve_position is the biggest possible, yet smaller than Curve position
222281 // Otherwise take the first named
223282 // Anchor names ----A----B----
@@ -232,7 +291,7 @@ impl LrmScale {
232291 . or_else ( || self . iter_named ( ) . next ( ) )
233292 }
234293
235- fn scale_nearest_named ( & self , scale_position : ScalePosition ) -> Option < NamedAnchor > {
294+ fn scale_nearest_named ( & self , scale_position : ScalePosition ) -> Option < & NamedAnchor > {
236295 // Like nearest_named, but our position is along the scale
237296 self . iter_named ( )
238297 . rev ( )
@@ -245,28 +304,35 @@ impl LrmScale {
245304 self . anchors
246305 . iter ( )
247306 . rev ( )
248- . skip_while ( |anchor| anchor. id . as_deref ( ) != Some ( name) )
307+ . skip_while ( |anchor| match anchor {
308+ Anchor :: Named ( anchor) => anchor. name != name,
309+ Anchor :: Unnamed ( _) => true ,
310+ } )
249311 . nth ( 1 )
250312 }
251313
252314 // Finds the closest Anchor after the Anchor having the name `name`
253315 fn next_anchor ( & self , name : & str ) -> Option < & Anchor > {
254316 self . anchors
255317 . iter ( )
256- . skip_while ( |anchor| anchor. id . as_deref ( ) != Some ( name) )
318+ . skip_while ( |anchor| match anchor {
319+ Anchor :: Named ( anchor) => anchor. name != name,
320+ Anchor :: Unnamed ( _) => true ,
321+ } )
257322 . nth ( 1 )
258323 }
259324
260325 // Iterates only on named Anchor objects
261- fn iter_named ( & self ) -> impl DoubleEndedIterator < Item = NamedAnchor > + ' _ {
262- self . anchors . iter ( ) . filter_map ( |anchor| anchor. as_named ( ) )
326+ fn iter_named ( & self ) -> impl DoubleEndedIterator < Item = & NamedAnchor > + ' _ {
327+ self . anchors . iter ( ) . filter_map ( |anchor| match anchor {
328+ Anchor :: Named ( anchor) => Some ( anchor) ,
329+ Anchor :: Unnamed ( _) => None ,
330+ } )
263331 }
264332}
265333
266334#[ cfg( test) ]
267335pub ( crate ) mod tests {
268- use geo:: point;
269-
270336 use crate :: properties;
271337
272338 use super :: * ;
@@ -275,8 +341,8 @@ pub(crate) mod tests {
275341 LrmScale {
276342 id : "id" . to_owned ( ) ,
277343 anchors : vec ! [
278- Anchor :: new ( "a" , 0. , 0. , Some ( point! { x : 0. , y : 0. } ) , properties!( ) ) ,
279- Anchor :: new ( "b" , 10. , 0.5 , Some ( point! { x : 0. , y : 0. } ) , properties!( ) ) ,
344+ Anchor :: new_named ( "a" , 0. , 0. , None , properties!( ) ) ,
345+ Anchor :: new_named ( "b" , 10. , 0.5 , None , properties!( ) ) ,
280346 ] ,
281347 }
282348 }
@@ -311,15 +377,15 @@ pub(crate) mod tests {
311377 let scale = LrmScale {
312378 id : "id" . to_owned ( ) ,
313379 anchors : vec ! [
314- Anchor :: new ( "a" , 0. , 2. , Some ( point! { x : 0. , y : 0. } ) , properties!( ) ) ,
315- Anchor :: new ( "b" , 10. , 3. , Some ( point! { x : 0. , y : 0. } ) , properties!( ) ) ,
380+ Anchor :: new_named ( "a" , 0. , 2. , None , properties!( ) ) ,
381+ Anchor :: new_named ( "b" , 10. , 3. , None , properties!( ) ) ,
316382 ] ,
317383 } ;
318384
319- assert_eq ! ( scale. nearest_named( 2.1 ) . unwrap( ) . id , "a" ) ;
320- assert_eq ! ( scale. nearest_named( 2.9 ) . unwrap( ) . id , "a" ) ;
321- assert_eq ! ( scale. nearest_named( 1.5 ) . unwrap( ) . id , "a" ) ;
322- assert_eq ! ( scale. nearest_named( 3.5 ) . unwrap( ) . id , "b" ) ;
385+ assert_eq ! ( scale. nearest_named( 2.1 ) . unwrap( ) . name , "a" ) ;
386+ assert_eq ! ( scale. nearest_named( 2.9 ) . unwrap( ) . name , "a" ) ;
387+ assert_eq ! ( scale. nearest_named( 1.5 ) . unwrap( ) . name , "a" ) ;
388+ assert_eq ! ( scale. nearest_named( 3.5 ) . unwrap( ) . name , "b" ) ;
323389 }
324390
325391 #[ test]
@@ -343,10 +409,10 @@ pub(crate) mod tests {
343409 let scale = LrmScale {
344410 id : "id" . to_owned ( ) ,
345411 anchors : vec ! [
346- Anchor :: new_unnamed( 0. , 100. , Some ( point! { x : 0. , y : 0. } ) , properties!( ) ) ,
347- Anchor :: new ( "a" , 1. , 200. , Some ( point! { x : 0. , y : 0. } ) , properties!( ) ) ,
348- Anchor :: new ( "b" , 3. , 300. , Some ( point! { x : 0. , y : 0. } ) , properties!( ) ) ,
349- Anchor :: new_unnamed( 4. , 400. , Some ( point! { x : 0. , y : 0. } ) , properties!( ) ) ,
412+ Anchor :: new_unnamed( 0. , 100. , None , properties!( ) ) ,
413+ Anchor :: new_named ( "a" , 1. , 200. , None , properties!( ) ) ,
414+ Anchor :: new_named ( "b" , 3. , 300. , None , properties!( ) ) ,
415+ Anchor :: new_unnamed( 4. , 400. , None , properties!( ) ) ,
350416 ] ,
351417 } ;
352418
@@ -414,7 +480,7 @@ pub(crate) mod tests {
414480 let scale = LrmScale {
415481 id : "id" . to_owned ( ) ,
416482 anchors : vec ! [
417- Anchor :: new ( "a" , 1000. + 0. , -2. , None , properties!( ) ) ,
483+ Anchor :: new_named ( "a" , 1000. + 0. , -2. , None , properties!( ) ) ,
418484 Anchor :: new_unnamed( 1000. + 300. , 1. , None , properties!( ) ) ,
419485 ] ,
420486 } ;
@@ -437,7 +503,7 @@ pub(crate) mod tests {
437503 let scale = LrmScale {
438504 id : "id" . to_owned ( ) ,
439505 anchors : vec ! [
440- Anchor :: new ( "a" , 0. , 0. , None , properties!( ) ) ,
506+ Anchor :: new_named ( "a" , 0. , 0. , None , properties!( ) ) ,
441507 Anchor :: new_unnamed( 1. , 0.4 , None , properties!( ) ) ,
442508 Anchor :: new_unnamed( 9. , 0.6 , None , properties!( ) ) ,
443509 ] ,
0 commit comments