1use std::cmp::Ordering;
2
3use super::*;
4use crate::{line_intersection::line_intersection, Coord, LineIntersection};
5
6#[derive(Debug, Clone)]
12pub(crate) struct Crossing<C: Cross> {
13 pub cross: C,
15
16 pub line: LineOrPoint<C::Scalar>,
24
25 pub first_segment: bool,
27
28 pub has_overlap: bool,
37
38 pub at_left: bool,
41
42 pub(super) segment: IMSegment<C>,
43}
44
45pub(crate) fn compare_crossings<X: Cross>(a: &Crossing<X>, b: &Crossing<X>) -> Ordering {
46 a.at_left.cmp(&b.at_left).then_with(|| {
47 let ord = a.segment.partial_cmp(&b.segment).unwrap();
48 if a.at_left {
49 ord
50 } else {
51 ord.reverse()
52 }
53 })
54}
55
56impl<C: Cross + Clone> Crossing<C> {
57 pub(super) fn from_segment(segment: &IMSegment<C>, event_ty: EventType) -> Crossing<C> {
59 Crossing {
60 cross: segment.cross_cloned(),
61 line: segment.geom(),
62 first_segment: segment.is_first_segment(),
63 has_overlap: segment.is_overlapping(),
64 at_left: event_ty == EventType::LineLeft,
65 segment: segment.clone(),
66 }
67 }
68}
69
70pub(crate) struct CrossingsIter<C>
104where
105 C: Cross + Clone,
106{
107 sweep: Sweep<C>,
108 segments: Vec<Crossing<C>>,
109}
110
111impl<C> CrossingsIter<C>
112where
113 C: Cross + Clone,
114{
115 pub fn new_simple<I: IntoIterator<Item = C>>(iter: I) -> Self {
118 Self::new_ex(iter, true)
119 }
120
121 pub fn intersections_mut(&mut self) -> &mut [Crossing<C>] {
124 &mut self.segments
125 }
126
127 pub fn intersections(&self) -> &[Crossing<C>] {
128 &self.segments
129 }
130
131 pub(crate) fn prev_active(&self, c: &Crossing<C>) -> Option<(LineOrPoint<C::Scalar>, C)> {
132 self.sweep
133 .with_prev_active(c, |s| (s.geom, s.cross.clone()))
134 }
135
136 fn new_ex<T: IntoIterator<Item = C>>(iter: T, is_simple: bool) -> Self {
137 let iter = iter.into_iter();
138 let size = {
139 let (min_size, max_size) = iter.size_hint();
140 max_size.unwrap_or(min_size)
141 };
142 let sweep = Sweep::new(iter, is_simple);
143 let segments = Vec::with_capacity(4 * size);
144 Self { sweep, segments }
145 }
146}
147
148impl<C> FromIterator<C> for CrossingsIter<C>
149where
150 C: Cross + Clone,
151{
152 fn from_iter<T: IntoIterator<Item = C>>(iter: T) -> Self {
153 Self::new_ex(iter, false)
154 }
155}
156
157impl<C> Iterator for CrossingsIter<C>
158where
159 C: Cross + Clone,
160{
161 type Item = Coord<C::Scalar>;
162
163 fn next(&mut self) -> Option<Self::Item> {
164 let segments = &mut self.segments;
165
166 segments.clear();
167 let mut last_point = self.sweep.peek_point();
168 debug!("pt: {last_point:?}");
169 while last_point == self.sweep.peek_point() && self.sweep.peek_point().is_some() {
170 last_point = self.sweep.next_event(|seg, ty| {
171 trace!(
172 "cb: {seg:?} {ty:?} (crossable = {cross:?})",
173 cross = seg.cross_cloned().line()
174 );
175 segments.push(Crossing::from_segment(seg, ty))
176 });
177 }
178
179 if segments.is_empty() {
180 None
181 } else {
182 last_point.map(|p| *p)
183 }
184 }
185}
186
187pub struct Intersections<C: Cross + Clone> {
222 inner: CrossingsIter<C>,
223 idx: usize,
224 jdx: usize,
225 is_overlap: bool,
226 pt: Option<Coord<C::Scalar>>,
227}
228
229impl<C> FromIterator<C> for Intersections<C>
230where
231 C: Cross + Clone,
232{
233 fn from_iter<T: IntoIterator<Item = C>>(iter: T) -> Self {
234 Self {
235 inner: FromIterator::from_iter(iter),
236 idx: 0,
237 jdx: 0,
238 is_overlap: false,
239 pt: None,
240 }
241 }
242}
243
244impl<C> Intersections<C>
245where
246 C: Cross + Clone,
247{
248 fn intersection(&mut self) -> Option<(C, C, LineIntersection<C::Scalar>)> {
249 let (si, sj) = {
250 let segments = self.inner.intersections();
251 (&segments[self.idx], &segments[self.jdx])
252 };
253 debug!(
254 "comparing intersection: [{iso}]",
255 iso = if self.is_overlap { "OVL" } else { "" }
256 );
257 for i in [si, sj] {
258 debug!(
259 "\t{geom:?} ({at_left}) [{ovl}] [{first}]",
260 geom = i.cross.line(),
261 first = if i.first_segment { "FIRST" } else { "" },
262 at_left = if i.at_left { "S" } else { "E" },
263 ovl = if i.has_overlap { "OVL" } else { "" },
264 );
265 }
266 let should_compute = if self.is_overlap {
268 debug_assert_eq!(si.at_left, sj.at_left);
271 si.at_left && (si.first_segment && sj.first_segment)
272 } else {
273 (!si.at_left || si.first_segment) && (!sj.at_left || sj.first_segment)
274 };
275
276 if should_compute {
277 let si = si.cross.clone();
278 let sj = sj.cross.clone();
279
280 let int = line_intersection(si.line().line(), sj.line().line())
281 .expect("line_intersection returned `None` disagreeing with `CrossingsIter`");
282
283 Some((si, sj, int))
284 } else {
285 None
286 }
287 }
288
289 fn step(&mut self) -> bool {
290 let seg_len = self.inner.intersections_mut().len();
291 if 1 + self.jdx < seg_len {
292 self.is_overlap =
293 self.is_overlap && self.inner.intersections_mut()[self.jdx].has_overlap;
294 self.jdx += 1;
295 } else {
296 self.idx += 1;
297 if 1 + self.idx >= seg_len {
298 loop {
299 self.pt = self.inner.next();
300 if self.pt.is_none() {
301 return false;
302 }
303 if self.inner.intersections_mut().len() > 1 {
304 break;
305 }
306 }
307 self.idx = 0;
308 }
309 self.is_overlap = self.inner.intersections_mut()[self.idx].has_overlap;
310 self.jdx = self.idx + 1;
311 }
312 true
313 }
314}
315
316impl<C> Iterator for Intersections<C>
317where
318 C: Cross + Clone,
319{
320 type Item = (C, C, LineIntersection<C::Scalar>);
321
322 fn next(&mut self) -> Option<Self::Item> {
323 loop {
324 if !self.step() {
325 return None;
326 }
327 let it = self.intersection();
328 debug!("\t{it:?}", it = it.is_some());
329 if let Some(result) = it {
330 return Some(result);
331 }
332 }
333 }
334}
335
336#[cfg(test)]
337pub(super) mod tests {
338 use crate::Line;
339 use log::info;
340 use pretty_env_logger::env_logger;
341 use std::{io::Write, rc::Rc};
342
343 use super::*;
344
345 pub(super) fn init_log() {
346 let _ = env_logger::builder()
347 .format(|buf, record| writeln!(buf, "{} - {}", record.level(), record.args()))
348 .try_init();
349 }
350
351 #[test]
352 fn simple_iter() {
353 let input = vec![
354 Rc::from(Line::from([(1., 0.), (0., 1.)])),
355 Line::from([(0., 0.), (1., 1.)]).into(),
356 ];
357 let iter: CrossingsIter<_> = input.into_iter().collect();
358 assert_eq!(iter.count(), 5);
359 }
360
361 #[test]
362 fn overlap_intersect() {
363 init_log();
364
365 let input = vec![
366 Line::from([(0., 0.), (1., 1.)]),
367 [(1., 0.), (0., 1.)].into(),
368 [(0., 0.5), (1., 0.5)].into(),
369 [(-1., 0.5), (0.5, 0.5)].into(),
370 [(0.5, 0.5), (0.5, 0.5)].into(),
371 [(0., 0.), (0., 0.)].into(),
372 ];
373 let mut verify = 0;
378 for (i, l1) in input.iter().enumerate() {
379 for (j, l2) in input.iter().enumerate() {
380 if j <= i {
381 continue;
382 }
383 if line_intersection(*l1, *l2).is_some() {
384 let lp_a = LineOrPoint::from(*l1);
385 let lp_b = LineOrPoint::from(*l2);
386 eprintln!("{lp_a:?} intersects {lp_b:?}",);
387 verify += 1;
388 }
389 }
390 }
391
392 let iter: Intersections<_> = input.iter().collect();
393 let count = iter
394 .inspect(|(a, b, _int)| {
395 let lp_a = LineOrPoint::from(**a);
396 let lp_b = LineOrPoint::from(**b);
397 eprintln!("{lp_a:?} intersects {lp_b:?}",);
398 })
399 .count();
400 assert_eq!(count, verify);
401 }
402
403 #[test]
404 #[ignore]
405 fn check_adhoc_crossings() {
406 init_log();
407
408 let input = vec![
409 Line::from([(0., 0.), (1., 1.)]),
410 [(1., 0.), (0., 1.)].into(),
411 [(0., 0.5), (1., 0.5)].into(),
412 [(-1., 0.5), (0.5, 0.5)].into(),
413 [(0.5, 0.5), (0.5, 0.5)].into(),
414 [(0., 0.), (0., 0.)].into(),
415 ];
416
417 let mut iter: CrossingsIter<_> = input.into_iter().collect();
418 while let Some(pt) = iter.next() {
419 info!("pt: {pt:?}");
420 iter.intersections().iter().for_each(|i| {
421 info!(
422 "\t{geom:?} ({at_left}) {ovl}",
423 geom = i.line,
424 at_left = if i.at_left { "S" } else { "E" },
425 ovl = if i.has_overlap { "[OVL] " } else { "" },
426 );
427 });
428 }
429 }
430}