@@ -153,6 +153,7 @@ impl ScaleBuilder {
153
153
/// A measure defines a location on the [LrmScale].
154
154
/// It is given as an [Anchor] name and an `offset` on that scale.
155
155
/// It is often represented as `12+100` to say `“100 scale units after the Anchor 12`”.
156
+ #[ derive( Clone , Debug ) ]
156
157
pub struct LrmScaleMeasure {
157
158
/// `Name` of the [Anchor]. While it is often named after a kilometer position,
158
159
/// it can be anything (a letter, a landmark).
@@ -231,6 +232,34 @@ impl LrmScale {
231
232
} )
232
233
}
233
234
235
+ /// Returns a measure given a distance along the `LrmScale`.
236
+ /// The corresponding [Anchor] is the named `Anchor` that gives the smallest positive `offset`.
237
+ /// If such an `Anchor` does not exists, the first named `Anchor` is used.
238
+ pub fn get_measure (
239
+ & self ,
240
+ scale_position : ScalePosition ,
241
+ ) -> Result < LrmScaleMeasure , LrmScaleError > {
242
+ let named_anchor = self
243
+ . scale_nearest_named ( scale_position)
244
+ . ok_or ( LrmScaleError :: NoAnchorFound ) ?;
245
+
246
+ Ok ( LrmScaleMeasure {
247
+ anchor_name : named_anchor. id ,
248
+ scale_offset : scale_position - named_anchor. scale_position ,
249
+ } )
250
+ }
251
+
252
+ /// Locates a point along the scale given an [Anchor] and an `offset`,
253
+ /// which might be negative.
254
+ pub fn get_position ( & self , measure : LrmScaleMeasure ) -> Result < ScalePosition , LrmScaleError > {
255
+ let named_anchor = self
256
+ . iter_named ( )
257
+ . find ( |anchor| anchor. id == measure. anchor_name )
258
+ . ok_or ( LrmScaleError :: UnknownAnchorName ) ?;
259
+
260
+ Ok ( named_anchor. scale_position + measure. scale_offset )
261
+ }
262
+
234
263
fn nearest_named ( & self , curve_position : CurvePosition ) -> Option < NamedAnchor > {
235
264
// Tries to find the Anchor whose curve_position is the biggest possible, yet smaller than Curve position
236
265
// Otherwise take the first named
@@ -246,6 +275,14 @@ impl LrmScale {
246
275
. or_else ( || self . iter_named ( ) . next ( ) )
247
276
}
248
277
278
+ fn scale_nearest_named ( & self , scale_position : ScalePosition ) -> Option < NamedAnchor > {
279
+ // Like nearest_named, but our position is along the scale
280
+ self . iter_named ( )
281
+ . rev ( )
282
+ . find ( |anchor| anchor. scale_position <= scale_position)
283
+ . or_else ( || self . iter_named ( ) . next ( ) )
284
+ }
285
+
249
286
// Finds the closest Anchor before the Anchor having the name `name`
250
287
fn previous_anchor ( & self , name : & str ) -> Option < & Anchor > {
251
288
self . anchors
@@ -270,9 +307,9 @@ impl LrmScale {
270
307
}
271
308
272
309
#[ cfg( test) ]
273
- mod tests {
310
+ pub mod tests {
274
311
use super :: * ;
275
- fn scale ( ) -> LrmScale {
312
+ pub fn scale ( ) -> LrmScale {
276
313
ScaleBuilder :: new ( Anchor :: new ( "a" , 0. , 0. ) )
277
314
. add_named ( "b" , 10. , 100. )
278
315
. build ( "id" )
@@ -282,9 +319,8 @@ mod tests {
282
319
#[ test]
283
320
fn builder ( ) {
284
321
// Everything as planed
285
- let scale = scale ( ) ;
286
- assert_eq ! ( scale. anchors[ 0 ] . curve_position, 0. ) ;
287
- assert_eq ! ( scale. anchors[ 1 ] . curve_position, 100. ) ;
322
+ assert_eq ! ( scale( ) . anchors[ 0 ] . curve_position, 0. ) ;
323
+ assert_eq ! ( scale( ) . anchors[ 1 ] . curve_position, 100. ) ;
288
324
289
325
// Missing named Anchor
290
326
let b = ScaleBuilder :: new ( Anchor :: new_unnamed ( 0. , 0. ) ) ;
@@ -303,21 +339,25 @@ mod tests {
303
339
304
340
#[ test]
305
341
fn locate_point ( ) {
306
- let scale = scale ( ) ;
307
-
308
342
// Everything a usual
309
- assert_eq ! ( scale. locate_point( & LrmScaleMeasure :: new( "a" , 5. ) ) , Ok ( 50. ) ) ;
310
- assert_eq ! ( scale. locate_point( & LrmScaleMeasure :: new( "b" , 5. ) ) , Ok ( 150. ) ) ;
343
+ assert_eq ! (
344
+ scale( ) . locate_point( & LrmScaleMeasure :: new( "a" , 5. ) ) ,
345
+ Ok ( 50. )
346
+ ) ;
347
+ assert_eq ! (
348
+ scale( ) . locate_point( & LrmScaleMeasure :: new( "b" , 5. ) ) ,
349
+ Ok ( 150. )
350
+ ) ;
311
351
312
352
// Negative offsets
313
353
assert_eq ! (
314
- scale. locate_point( & LrmScaleMeasure :: new( "a" , -5. ) ) ,
354
+ scale( ) . locate_point( & LrmScaleMeasure :: new( "a" , -5. ) ) ,
315
355
Ok ( -50. )
316
356
) ;
317
357
318
358
// Unknown Anchor
319
359
assert_eq ! (
320
- scale. locate_point( & LrmScaleMeasure :: new( "c" , 5. ) ) ,
360
+ scale( ) . locate_point( & LrmScaleMeasure :: new( "c" , 5. ) ) ,
321
361
Err ( LrmScaleError :: UnknownAnchorName )
322
362
) ;
323
363
}
@@ -337,20 +377,15 @@ mod tests {
337
377
338
378
#[ test]
339
379
fn locate_anchor ( ) {
340
- let scale = ScaleBuilder :: new ( Anchor :: new ( "a" , 0. , 0. ) )
341
- . add_named ( "b" , 10. , 100. )
342
- . build ( "id" )
343
- . unwrap ( ) ;
344
-
345
- let measure = scale. locate_anchor ( 40. ) . unwrap ( ) ;
380
+ let measure = scale ( ) . locate_anchor ( 40. ) . unwrap ( ) ;
346
381
assert_eq ! ( measure. anchor_name, "a" ) ;
347
382
assert_eq ! ( measure. scale_offset, 4. ) ;
348
383
349
- let measure = scale. locate_anchor ( 150. ) . unwrap ( ) ;
384
+ let measure = scale ( ) . locate_anchor ( 150. ) . unwrap ( ) ;
350
385
assert_eq ! ( measure. anchor_name, "b" ) ;
351
386
assert_eq ! ( measure. scale_offset, 5. ) ;
352
387
353
- let measure = scale. locate_anchor ( -10. ) . unwrap ( ) ;
388
+ let measure = scale ( ) . locate_anchor ( -10. ) . unwrap ( ) ;
354
389
assert_eq ! ( measure. anchor_name, "a" ) ;
355
390
assert_eq ! ( measure. scale_offset, -1. ) ;
356
391
}
@@ -385,4 +420,38 @@ mod tests {
385
420
assert_eq ! ( measure. anchor_name, "b" ) ;
386
421
assert_eq ! ( measure. scale_offset, 2. ) ;
387
422
}
423
+
424
+ #[ test]
425
+ fn get_measure ( ) {
426
+ // a(scale 0)----measure(scale 5)----b(scale 10)
427
+ let measure = scale ( ) . get_measure ( 5. ) . unwrap ( ) ;
428
+ assert_eq ! ( measure. anchor_name, "a" ) ;
429
+ assert_eq ! ( measure. scale_offset, 5. ) ;
430
+
431
+ // a(scale 0)----b(scale 10)----measure(scale 25)
432
+ let measure = scale ( ) . get_measure ( 25. ) . unwrap ( ) ;
433
+ assert_eq ! ( measure. anchor_name, "b" ) ;
434
+ assert_eq ! ( measure. scale_offset, 15. ) ;
435
+ }
436
+
437
+ #[ test]
438
+ fn get_position ( ) {
439
+ // a(scale 0)----position(scale a+5)----b(scale 10)
440
+ let position = scale ( )
441
+ . get_position ( LrmScaleMeasure {
442
+ anchor_name : "a" . to_string ( ) ,
443
+ scale_offset : 5. ,
444
+ } )
445
+ . unwrap ( ) ;
446
+ assert_eq ! ( position, 5. ) ;
447
+
448
+ // a(scale 0)----b(scale 10)----position(scale b+15)
449
+ let position = scale ( )
450
+ . get_position ( LrmScaleMeasure {
451
+ anchor_name : "b" . to_string ( ) ,
452
+ scale_offset : 15. ,
453
+ } )
454
+ . unwrap ( ) ;
455
+ assert_eq ! ( position, 25. ) ;
456
+ }
388
457
}
0 commit comments