pub fn connect_contour_segments(mut segments: Vec<Deque2>) -> Vec<Deque2> {
  let mut contour_lines = vec![];

  'outer: loop {
    // grab random segment
    match segments.pop() {
      None => break 'outer,
      Some(mut line) => {
        'inner: loop {
          // find segments that join at the head of the line.
          // if we find a point that matches, we must take the other point from the segment, so
          // we continue to build a line moving forwards with no duplicate points.
          let cloned_segments = segments.clone();
          let mut head_segments: Vec<(usize, &Deque2)> = cloned_segments
            .iter()
            .enumerate()
            .filter(|(_i, seg)| {
              is_near(line.back().unwrap(), &seg[0]) || is_near(line.back().unwrap(), &seg[1])
            })
            .collect();
          let no_head_segments = head_segments.is_empty();
          match head_segments.pop() {
            None => (),
            Some((index, new_seg)) => {
              if is_near(&new_seg[0], line.back().unwrap()) {
                line.push_back(new_seg[0]);
                line.push_back(new_seg[1]);
              } else {
                line.push_back(new_seg[1]);
                line.push_back(new_seg[0]);
              }
              segments.remove(index);
            }
          }

          // find segments that join at the tail of the line
          // if we find a point that matches, we must take the other point from the segment
          // and insert it at the beginning of the line
          let cloned_segments = segments.clone();
          let mut tail_segments: Vec<(usize, &Deque2)> = cloned_segments
            .iter()
            .enumerate()
            .filter(|(_i, seg)| is_near(&line[0], &seg[0]) || is_near(&line[0], &seg[1]))
            .collect();
          let no_tail_segments = tail_segments.is_empty();
          match tail_segments.pop() {
            None => (),
            Some((index, new_seg)) => {
              if is_near(&new_seg[0], &line[0]) {
                line.push_front(new_seg[0]);
                line.push_front(new_seg[1]);
              } else {
                line.push_front(new_seg[1]);
                line.push_front(new_seg[0]);
              }
              segments.remove(index);
            }
          }

          // when no matching segments were found, push the line and start again!
          // Otherwise, iterate
          if no_head_segments && no_tail_segments {
            contour_lines.push(line);
            break 'inner;
          }
        }
      }
    }
  }
  contour_lines
}
/// Kind of a tricky thing, building contiguous lines from a collection of segments!
/// This algorithm takes a mutable collection of segments, and iteratively builds
/// contiguous contour lines by
/// 1. popping a random segment from the stack
/// 2. finding all segments that could connect to the "head" of the line
/// 3. finding all segments that could connect to the "end" of the line
/// 4. concatenating the relevant points to the line
/// 5. breaking once no head or tail points are found.
///
/// The result is a collection of lines, each at the same threshold.
/// The reason it is a collection of lines is that each threshold could
/// theoretically exist as a closed line in multiple places on the topography,
/// e.g. in localized peaks and valleys.
///
/// This is not a perfect algorithm,
/// it sometimes returns unclosed lines that should be closed
Kind of a tricky thing, building contiguous lines from a collection of segments.
This algorithm takes a mutable collection of segments, and iteratively builds
contiguous contour lines by
1. popping a random segment from the stack
2. finding all segments that could connect to the "head" of the line
3. finding all segments that could connect to the "end" of the line
4. concatenating the relevant points to the line
5. breaking once no head or tail points are found.

The result is a collection of lines, each at the same threshold.
The reason it is a collection of lines is that each threshold could
theoretically exist as a closed line in multiple places on the topography,
e.g. in localized peaks and valleys.

This is not a perfect algorithm,
it sometimes returns unclosed lines that should be closed
Kind of a tricky thing building contiguous lines from a collection of segments . This algorithm takes a mutable collection of segments and iteratively builds contiguous contour lines by 1 . popping a random segment from the stack 2 . finding all segments that could connect to the " head " of the line 3 . finding all segments that could connect to the " end " of the line 4 . concatenating the relevant points to the line 5 . breaking once no head or tail points are found . The result is a collection of lines each at the same threshold . The reason it is a collection of lines is that each threshold could theoretically exist as a closed line in multiple places on the topography e . g . in localized peaks and valleys . This is not a perfect algorithm it sometimes returns unclosed lines that should be closed
pub fn connect_contour_segments(mut segments: Vec<Deque2>) -> Vec<Deque2> {
  let mut contour_lines = vec![];
  'outer: loop {
    // grab random segment
    match segments.pop() {
      None => break 'outer,
      Some(mut line) => {
        'inner: loop {
          // find segments that join at the head of the line.
          // if we find a point that matches, we must take the other point from the segment, so
          // we continue to build a line moving forwards with no duplicate points.
          let cloned_segments = segments.clone();
          let mut head_segments: Vec<(usize, &Deque2)> = cloned_segments
            .iter()
            .enumerate()
            .filter(|(_i, seg)| {
              is_near(line.back().unwrap(), &seg[0]) || is_near(line.back().unwrap(), &seg[1])
            })
            .collect();
          let no_head_segments = head_segments.is_empty();
          match head_segments.pop() {
            None => (),
            Some((index, new_seg)) => {
              if is_near(&new_seg[0], line.back().unwrap()) {
                line.push_back(new_seg[0]);
                line.push_back(new_seg[1]);
              } else {
                line.push_back(new_seg[1]);
                line.push_back(new_seg[0]);
              }
              segments.remove(index);
            }
          }
          // find segments that join at the tail of the line
          // if we find a point that matches, we must take the other point from the segment
          // and insert it at the beginning of the line
          let cloned_segments = segments.clone();
          let mut tail_segments: Vec<(usize, &Deque2)> = cloned_segments
            .iter()
            .enumerate()
            .filter(|(_i, seg)| is_near(&line[0], &seg[0]) || is_near(&line[0], &seg[1]))
            .collect();
          let no_tail_segments = tail_segments.is_empty();
          match tail_segments.pop() {
            None => (),
            Some((index, new_seg)) => {
              if is_near(&new_seg[0], &line[0]) {
                line.push_front(new_seg[0]);
                line.push_front(new_seg[1]);
              } else {
                line.push_front(new_seg[1]);
                line.push_front(new_seg[0]);
              }
              segments.remove(index);
            }
          }
          // when no matching segments were found, push the line and start again!
          // Otherwise, iterate
          if no_head_segments && no_tail_segments {
            contour_lines.push(line);
            break 'inner;
          }
        }
      }
    }
  }
  contour_lines
}
pub fn connect_contour_segments ( mut segments : Vec < Deque2 > ) -> Vec < Deque2 > { let mut contour_lines = vec ! [ ] ; ' outer : loop { // grab random segment match segments . pop ( ) { None => break ' outer , Some ( mut line ) => { ' inner : loop { // find segments that join at the head of the line. // if we find a point that matches, we must take the other point from the segment, so // we continue to build a line moving forwards with no duplicate points. let cloned_segments = segments . clone ( ) ; let mut head_segments : Vec < ( usize , & Deque2 ) > = cloned_segments . iter ( ) . enumerate ( ) . filter ( | ( _i , seg ) | { is_near ( line . back ( ) . unwrap ( ) , & seg [ 0 ] ) || is_near ( line . back ( ) . unwrap ( ) , & seg [ 1 ] ) } ) . collect ( ) ; let no_head_segments = head_segments . is_empty ( ) ; match head_segments . pop ( ) { None => ( ) , Some ( ( index , new_seg ) ) => { if is_near ( & new_seg [ 0 ] , line . back ( ) . unwrap ( ) ) { line . push_back ( new_seg [ 0 ] ) ; line . push_back ( new_seg [ 1 ] ) ; } else { line . push_back ( new_seg [ 1 ] ) ; line . push_back ( new_seg [ 0 ] ) ; } segments . remove ( index ) ; } } // find segments that join at the tail of the line // if we find a point that matches, we must take the other point from the segment // and insert it at the beginning of the line let cloned_segments = segments . clone ( ) ; let mut tail_segments : Vec < ( usize , & Deque2 ) > = cloned_segments . iter ( ) . enumerate ( ) . filter ( | ( _i , seg ) | is_near ( & line [ 0 ] , & seg [ 0 ] ) || is_near ( & line [ 0 ] , & seg [ 1 ] ) ) . collect ( ) ; let no_tail_segments = tail_segments . is_empty ( ) ; match tail_segments . pop ( ) { None => ( ) , Some ( ( index , new_seg ) ) => { if is_near ( & new_seg [ 0 ] , & line [ 0 ] ) { line . push_front ( new_seg [ 0 ] ) ; line . push_front ( new_seg [ 1 ] ) ; } else { line . push_front ( new_seg [ 1 ] ) ; line . push_front ( new_seg [ 0 ] ) ; } segments . remove ( index ) ; } } // when no matching segments were found, push the line and start again! // Otherwise, iterate if no_head_segments && no_tail_segments { contour_lines . push ( line ) ; break ' inner ; } } } } } contour_lines }
Kind of a tricky thing, building contiguous lines from a collection of segments!
Kind of a tricky thing building contiguous lines from a collection of segments!
segments
Vec<Deque2>