Mkirk/perf 2 (#370)

* perf: return Line iterator rather than Vec

avoids allocating vector memory, cleans up some call sites too.
This commit is contained in:
Michael Kirk 2020-10-20 11:51:00 -07:00 committed by GitHub
parent d8910ad04f
commit 6025d89598
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -177,12 +177,10 @@ impl PolyLine {
self.pts
}
// Makes a copy :\
pub fn lines(&self) -> Vec<Line> {
pub fn lines(&self) -> impl Iterator<Item = Line> + '_ {
self.pts
.windows(2)
.map(|pair| Line::must_new(pair[0], pair[1]))
.collect()
}
pub fn length(&self) -> Distance {
@ -212,7 +210,7 @@ impl PolyLine {
let mut result: Vec<Pt2D> = Vec::new();
let mut dist_so_far = Distance::ZERO;
for line in self.lines().iter() {
for line in self.lines() {
let length = line.length();
// Does this line contain the first point of the slice?
@ -307,7 +305,7 @@ impl PolyLine {
let mut dist_left = dist_along;
let mut length_remeasured = Distance::ZERO;
for (idx, l) in self.lines().iter().enumerate() {
for (idx, l) in self.lines().enumerate() {
let length = l.length();
length_remeasured += length;
let epsilon = if idx == self.pts.len() - 2 {
@ -624,23 +622,30 @@ impl PolyLine {
assert_ne!(self, other);
// There could be several collisions. Pick the "first" from self's perspective.
let mut closest_intersection: Option<(Pt2D, Angle)> = None;
let mut closest_intersection_distance: Option<Distance> = None;
for l1 in self.lines() {
let mut hits: Vec<(Pt2D, Angle)> = Vec::new();
for l2 in other.lines() {
if let Some(pt) = l1.intersection(&l2) {
hits.push((pt, l1.angle()));
if let Some(new_distance) = self.get_slice_ending_at(pt).map(|pl| pl.length()) {
match closest_intersection_distance {
None => {
closest_intersection = Some((pt, l1.angle()));
closest_intersection_distance = Some(new_distance);
}
Some(existing_distance) if existing_distance > new_distance => {
closest_intersection = Some((pt, l1.angle()));
closest_intersection_distance = Some(new_distance);
}
_ => {}
}
}
}
}
if let Some(hit) = hits.into_iter().min_by_key(|(pt, _)| {
self.get_slice_ending_at(*pt)
.map(|pl| pl.length())
.unwrap_or(Distance::ZERO)
}) {
return Some(hit);
}
}
None
closest_intersection
}
// TODO Also distance along
@ -660,7 +665,7 @@ impl PolyLine {
return None;
}
if let Some(idx) = self.lines().iter().position(|l| l.contains_pt(pt)) {
if let Some(idx) = self.lines().position(|l| l.contains_pt(pt)) {
let mut pts = self.pts.clone();
pts.truncate(idx + 1);
// Make sure the last line isn't too tiny
@ -683,7 +688,7 @@ impl PolyLine {
return None;
}
if let Some(idx) = self.lines().iter().position(|l| l.contains_pt(pt)) {
if let Some(idx) = self.lines().position(|l| l.contains_pt(pt)) {
let mut pts = self.pts.clone();
pts = pts.split_off(idx + 1);
if pt != pts[0] {
@ -773,7 +778,7 @@ fn fix_angles(orig: &PolyLine, result: PolyLine) -> Result<PolyLine, String> {
let mut pts = result.pts.clone();
// Check that the angles roughly match up between the original and shifted line
for (idx, (orig_l, shifted_l)) in orig.lines().iter().zip(result.lines().iter()).enumerate() {
for (idx, (orig_l, shifted_l)) in orig.lines().zip(result.lines()).enumerate() {
let orig_angle = orig_l.angle();
let shifted_angle = shifted_l.angle();