|
4 | 4 | use geo::{Coord, Point}; |
5 | 5 |
|
6 | 6 | use crate::curves::{Curve, SphericalLineStringCurve}; |
7 | | -use crate::lrm_scale::Anchor; |
8 | | -use crate::lrm_scale::LrmScaleMeasure; |
9 | | -use crate::lrs::Properties; |
10 | | -use crate::lrs::{self, TraversalPosition}; |
11 | | -use crate::lrs::{LrsBase, LrsError}; |
| 7 | +use crate::lrm_scale::{Anchor, LrmScaleMeasure}; |
| 8 | +use crate::lrs::{self, LrmProjection, LrsBase, LrsError, Properties, TraversalPosition}; |
12 | 9 |
|
13 | 10 | type Lrs = lrs::Lrs<SphericalLineStringCurve>; |
14 | 11 |
|
@@ -101,4 +98,72 @@ impl ExtLrs { |
101 | 98 | pub fn anchor_properties(&self, lrm_index: usize, anchor_index: usize) -> &Properties { |
102 | 99 | self.lrs.lrms[lrm_index].scale.anchors[anchor_index].properties() |
103 | 100 | } |
| 101 | + |
| 102 | + /// Projects a [`Point`] on all [`Lrm`] where the [`Point`] is in the bounding box. |
| 103 | + /// The result is sorted by `orthogonal_offset`: the nearest [`Lrm`] to the [`Point`] is the first item. |
| 104 | + pub fn lookup_lrms(&self, point: Point) -> Vec<LrmProjection> { |
| 105 | + self.lrs.lookup_lrms(point) |
| 106 | + } |
| 107 | +} |
| 108 | + |
| 109 | +#[cfg(test)] |
| 110 | +pub(crate) mod tests { |
| 111 | + use geo::{Coord, coord, point}; |
| 112 | + |
| 113 | + use crate::builder::{AnchorOnLrm, Builder, SegmentOfTraversal}; |
| 114 | + use crate::{lrs, properties}; |
| 115 | + |
| 116 | + fn build_lrm(builder: &mut Builder, name: &str, coords: &[Coord]) { |
| 117 | + let segment_index = builder.add_segment("name", coords, 0, 1); |
| 118 | + let sot = SegmentOfTraversal { |
| 119 | + segment_index, |
| 120 | + reversed: false, |
| 121 | + }; |
| 122 | + let traversal_index = builder.add_traversal(name, &[sot]); |
| 123 | + let start_anchor = AnchorOnLrm { |
| 124 | + anchor_index: builder.add_anchor("start", Some("start"), coords[0], properties!()), |
| 125 | + distance_along_lrm: 0.0, |
| 126 | + }; |
| 127 | + let end_anchor = AnchorOnLrm { |
| 128 | + anchor_index: builder.add_anchor( |
| 129 | + "end", |
| 130 | + Some("end"), |
| 131 | + *coords.last().unwrap(), |
| 132 | + properties!(), |
| 133 | + ), |
| 134 | + distance_along_lrm: 1.0, |
| 135 | + }; |
| 136 | + builder.add_lrm( |
| 137 | + name, |
| 138 | + traversal_index, |
| 139 | + &[start_anchor, end_anchor], |
| 140 | + properties!(), |
| 141 | + ); |
| 142 | + } |
| 143 | + |
| 144 | + #[test] |
| 145 | + fn test() { |
| 146 | + let mut b = Builder::new(); |
| 147 | + build_lrm(&mut b, "lrm1", &[coord! {x:0., y:0.}, coord! {x:2., y:0.}]); |
| 148 | + build_lrm(&mut b, "lrm2", &[coord! {x:0., y:1.}, coord! {x:2., y:1.}]); |
| 149 | + build_lrm(&mut b, "lrm3", &[coord! {x:1., y:1.}, coord! {x:1., y:-1.}]); |
| 150 | + let lrs = b.build_lrs(properties!()).unwrap(); |
| 151 | + |
| 152 | + let nearest0 = lrs.lookup_lrms(point! {x: 1.0001, y:0.0}); |
| 153 | + assert_eq!(nearest0.len(), 2); |
| 154 | + assert_eq!(nearest0[0].measure.lrm, lrs::LrmHandle(0)); |
| 155 | + assert_eq!(nearest0[1].measure.lrm, lrs::LrmHandle(2)); |
| 156 | + |
| 157 | + let nearest1 = lrs.lookup_lrms(point! {x: 0.5, y:1.0}); |
| 158 | + assert_eq!(nearest1.len(), 1); |
| 159 | + assert_eq!(nearest1[0].measure.lrm, lrs::LrmHandle(1)); |
| 160 | + |
| 161 | + let nearest2 = lrs.lookup_lrms(point! {x:1., y:-0.0001}); |
| 162 | + assert_eq!(nearest2.len(), 2); |
| 163 | + assert_eq!(nearest2[0].measure.lrm, lrs::LrmHandle(2)); |
| 164 | + assert_eq!(nearest2[1].measure.lrm, lrs::LrmHandle(0)); |
| 165 | + |
| 166 | + let nearest3 = lrs.lookup_lrms(point! {x:2.35, y:48.98}); |
| 167 | + assert!(nearest3.is_empty()); |
| 168 | + } |
104 | 169 | } |
0 commit comments