Skip to content

Commit bfdc814

Browse files
authored
Merge pull request #14 from osrd-project/lrs
Lrs: basic implementation
2 parents d964441 + 81104dd commit bfdc814

File tree

3 files changed

+883
-19
lines changed

3 files changed

+883
-19
lines changed

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ mod lrs_generated;
99
pub mod curves;
1010
#[deny(missing_docs)]
1111
pub mod lrm_scale;
12+
#[deny(missing_docs)]
13+
pub mod lrs;
1214
pub use lrs_generated::*;
1315

1416
#[test]

src/lrm_scale.rs

+88-19
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ impl ScaleBuilder {
153153
/// A measure defines a location on the [LrmScale].
154154
/// It is given as an [Anchor] name and an `offset` on that scale.
155155
/// It is often represented as `12+100` to say `“100 scale units after the Anchor 12`”.
156+
#[derive(Clone, Debug)]
156157
pub struct LrmScaleMeasure {
157158
/// `Name` of the [Anchor]. While it is often named after a kilometer position,
158159
/// it can be anything (a letter, a landmark).
@@ -231,6 +232,34 @@ impl LrmScale {
231232
})
232233
}
233234

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+
234263
fn nearest_named(&self, curve_position: CurvePosition) -> Option<NamedAnchor> {
235264
// Tries to find the Anchor whose curve_position is the biggest possible, yet smaller than Curve position
236265
// Otherwise take the first named
@@ -246,6 +275,14 @@ impl LrmScale {
246275
.or_else(|| self.iter_named().next())
247276
}
248277

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+
249286
// Finds the closest Anchor before the Anchor having the name `name`
250287
fn previous_anchor(&self, name: &str) -> Option<&Anchor> {
251288
self.anchors
@@ -270,9 +307,9 @@ impl LrmScale {
270307
}
271308

272309
#[cfg(test)]
273-
mod tests {
310+
pub mod tests {
274311
use super::*;
275-
fn scale() -> LrmScale {
312+
pub fn scale() -> LrmScale {
276313
ScaleBuilder::new(Anchor::new("a", 0., 0.))
277314
.add_named("b", 10., 100.)
278315
.build("id")
@@ -282,9 +319,8 @@ mod tests {
282319
#[test]
283320
fn builder() {
284321
// 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.);
288324

289325
// Missing named Anchor
290326
let b = ScaleBuilder::new(Anchor::new_unnamed(0., 0.));
@@ -303,21 +339,25 @@ mod tests {
303339

304340
#[test]
305341
fn locate_point() {
306-
let scale = scale();
307-
308342
// 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+
);
311351

312352
// Negative offsets
313353
assert_eq!(
314-
scale.locate_point(&LrmScaleMeasure::new("a", -5.)),
354+
scale().locate_point(&LrmScaleMeasure::new("a", -5.)),
315355
Ok(-50.)
316356
);
317357

318358
// Unknown Anchor
319359
assert_eq!(
320-
scale.locate_point(&LrmScaleMeasure::new("c", 5.)),
360+
scale().locate_point(&LrmScaleMeasure::new("c", 5.)),
321361
Err(LrmScaleError::UnknownAnchorName)
322362
);
323363
}
@@ -337,20 +377,15 @@ mod tests {
337377

338378
#[test]
339379
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();
346381
assert_eq!(measure.anchor_name, "a");
347382
assert_eq!(measure.scale_offset, 4.);
348383

349-
let measure = scale.locate_anchor(150.).unwrap();
384+
let measure = scale().locate_anchor(150.).unwrap();
350385
assert_eq!(measure.anchor_name, "b");
351386
assert_eq!(measure.scale_offset, 5.);
352387

353-
let measure = scale.locate_anchor(-10.).unwrap();
388+
let measure = scale().locate_anchor(-10.).unwrap();
354389
assert_eq!(measure.anchor_name, "a");
355390
assert_eq!(measure.scale_offset, -1.);
356391
}
@@ -385,4 +420,38 @@ mod tests {
385420
assert_eq!(measure.anchor_name, "b");
386421
assert_eq!(measure.scale_offset, 2.);
387422
}
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+
}
388457
}

0 commit comments

Comments
 (0)