Skip to content

Commit a1097f6

Browse files
committed
LrmScale: add get_measure and get_position to work on scale positions
1 parent 876156f commit a1097f6

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

src/lrm_scale.rs

+66
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,34 @@ impl LrmScale {
231231
})
232232
}
233233

234+
/// Returns a measure given a distance along the `LrmScale`.
235+
/// The corresponding [Anchor] is the named `Anchor` that gives the smallest positive `offset`.
236+
/// If such an `Anchor` does not exists, the first named `Anchor` is used.
237+
pub fn get_measure(
238+
&self,
239+
scale_position: ScalePosition,
240+
) -> Result<LrmScaleMeasure, LrmScaleError> {
241+
let named_anchor = self
242+
.scale_nearest_named(scale_position)
243+
.ok_or(LrmScaleError::NoAnchorFound)?;
244+
245+
Ok(LrmScaleMeasure {
246+
anchor_name: named_anchor.id,
247+
scale_offset: scale_position - named_anchor.scale_position,
248+
})
249+
}
250+
251+
/// Locates a point along the scale given an [Anchor] and an `offset`,
252+
/// which might be negative.
253+
pub fn get_position(&self, measure: LrmScaleMeasure) -> Result<ScalePosition, LrmScaleError> {
254+
let named_anchor = self
255+
.iter_named()
256+
.find(|anchor| anchor.id == measure.anchor_name)
257+
.ok_or(LrmScaleError::UnknownAnchorName)?;
258+
259+
Ok(named_anchor.scale_position + measure.scale_offset)
260+
}
261+
234262
fn nearest_named(&self, curve_position: CurvePosition) -> Option<NamedAnchor> {
235263
// Tries to find the Anchor whose curve_position is the biggest possible, yet smaller than Curve position
236264
// Otherwise take the first named
@@ -246,6 +274,14 @@ impl LrmScale {
246274
.or_else(|| self.iter_named().next())
247275
}
248276

277+
fn scale_nearest_named(&self, scale_position: ScalePosition) -> Option<NamedAnchor> {
278+
// Like nearest_named, but our position is along the scale
279+
self.iter_named()
280+
.rev()
281+
.find(|anchor| anchor.scale_position <= scale_position)
282+
.or_else(|| self.iter_named().next())
283+
}
284+
249285
// Finds the closest Anchor before the Anchor having the name `name`
250286
fn previous_anchor(&self, name: &str) -> Option<&Anchor> {
251287
self.anchors
@@ -383,4 +419,34 @@ mod tests {
383419
assert_eq!(measure.anchor_name, "b");
384420
assert_eq!(measure.scale_offset, 2.);
385421
}
422+
423+
#[test]
424+
fn get_measure() {
425+
let measure = scale().get_measure(5.).unwrap();
426+
assert_eq!(measure.anchor_name, "a");
427+
assert_eq!(measure.scale_offset, 5.);
428+
429+
let measure = scale().get_measure(25.).unwrap();
430+
assert_eq!(measure.anchor_name, "b");
431+
assert_eq!(measure.scale_offset, 15.);
432+
}
433+
434+
#[test]
435+
fn get_position() {
436+
let position = scale()
437+
.get_position(LrmScaleMeasure {
438+
anchor_name: "a".to_string(),
439+
scale_offset: 5.,
440+
})
441+
.unwrap();
442+
assert_eq!(position, 5.);
443+
444+
let position = scale()
445+
.get_position(LrmScaleMeasure {
446+
anchor_name: "b".to_string(),
447+
scale_offset: 15.,
448+
})
449+
.unwrap();
450+
assert_eq!(position, 25.);
451+
}
386452
}

0 commit comments

Comments
 (0)