output_event.rs
1 use crate::{num::CheapOrderedFloat, SegIdx}; 2 3 /// Describes the interaction between a line segment and a sweep-line. 4 /// 5 /// In exact math, a non-horizontal line segment can interact with a sweep-line 6 /// in exactly one way: by intersecting it at a point. When dealing with inexact 7 /// math, intersections and re-orderings between line segments might force 8 /// our sweep-line algorithm to perturb the line segment. In that case, even 9 /// a non-horizontal line segment might enter and leave the sweep-line at two 10 /// different points. 11 /// 12 /// `OutputEvent` is ordered by the smallest horizontal coordinate where 13 /// it intersects the sweep-line (i.e. [`OutputEvent::smaller_x`]). 14 /// 15 /// The two points, `x0` and `x1`, are in sweep-line order. This doesn't 16 /// necessarily mean that `x0` is smaller than `x1`! Instead, it means that 17 /// when traversing the segment in sweep-line order (i.e. in increasing `y`, 18 /// and increasing `x` if the segment is horizontal) then it visits `x0` 19 /// before `x1`. 20 #[derive(Clone, Debug, PartialEq)] 21 pub struct OutputEvent { 22 /// The first horizontal coordinate on this sweep-line that we'd hit if 23 /// we were traversing the segment in sweep-line orientation. 24 pub x0: f64, 25 /// Does this line segment extend "above" (i.e. smaller `y`) this sweep-line? 26 /// 27 /// If so, it will extend up from `x0`, because that's what the "sweep-line order" 28 /// means. 29 pub connected_above: bool, 30 /// The last horizontal coordinate on this sweep-line that we'd hit if 31 /// we were traversing the segment in sweep-line orientation. 32 pub x1: f64, 33 /// Does this line segment extend "below" (i.e. larger `y`) this sweep-line? 34 /// 35 /// If so, it will extend down from `x1`, because that's what the "sweep-line order" 36 /// means. 37 pub connected_below: bool, 38 /// The segment that's interacting with the sweep line. 39 pub seg_idx: SegIdx, 40 /// The segment's index in the new sweep line (`None` for horizontal segments). 41 pub sweep_idx: Option<usize>, 42 /// The segment's index in the old sweep line (`None` for horizontal segments). 43 pub old_sweep_idx: Option<usize>, 44 } 45 46 impl Eq for OutputEvent {} 47 48 impl OutputEvent { 49 /// The smallest `x` coordinate at which the line segment touches the sweep-line. 50 pub fn smaller_x(&self) -> f64 { 51 self.x0.min(self.x1) 52 } 53 54 /// The largest `x` coordinate at which the line segment touches the sweep-line. 55 pub fn larger_x(&self) -> f64 { 56 self.x0.max(self.x1) 57 } 58 59 pub(crate) fn new( 60 seg_idx: SegIdx, 61 x0: f64, 62 connected_above: bool, 63 x1: f64, 64 connected_below: bool, 65 sweep_idx: Option<usize>, 66 old_sweep_idx: Option<usize>, 67 ) -> Self { 68 Self { 69 x0, 70 connected_above, 71 x1, 72 connected_below, 73 seg_idx, 74 sweep_idx, 75 old_sweep_idx, 76 } 77 } 78 79 /// Does the line segment extend up from the horizontal coordinate `x`? 80 pub fn connected_above_at(&self, x: f64) -> bool { 81 x == self.x0 && self.connected_above 82 } 83 84 /// Does the line segment extend down from the horizontal coordinate `x`? 85 pub fn connected_below_at(&self, x: f64) -> bool { 86 x == self.x1 && self.connected_below 87 } 88 } 89 90 impl Ord for OutputEvent { 91 fn cmp(&self, other: &Self) -> std::cmp::Ordering { 92 CheapOrderedFloat::from(self.smaller_x()) 93 .cmp(&CheapOrderedFloat::from(other.smaller_x())) 94 .then_with(|| { 95 CheapOrderedFloat::from(self.larger_x()) 96 .cmp(&CheapOrderedFloat::from(other.larger_x())) 97 }) 98 } 99 } 100 101 impl PartialOrd for OutputEvent { 102 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { 103 Some(self.cmp(other)) 104 } 105 }