1#![doc = include_str!("../README.md")]
2pub mod data;
3pub mod utils;
4pub use data::read_shp;
5use num_traits::{Float, FloatConst};
6pub use rangemap::RangeMap;
7use std::cmp::{max, min, Ordering::*};
8use std::collections::BinaryHeap;
9use std::fmt::Debug;
10use utils::float_cmp;
11pub use utils::{ProjLine, ProjSegment};
12
13pub fn skymask<T, LT>(lines: impl Iterator<Item = ProjSegment<T, LT>>, eps: T) -> RangeMap<T, LT>
25where
26 T: Copy + Float + FloatConst + Ord + Debug,
27 LT: ProjLine<T> + Debug,
28{
29 let mut heap = BinaryHeap::from_iter(lines);
30 let mut rmap: RangeMap<T, LT> = RangeMap::new();
31 let (mut lower, mut fill_all) = (T::infinity(), false);
32
33 while let Some(l) = heap.pop() {
34 if fill_all {
35 if l.top_endpoint() < lower {
36 break;
37 }
38 } else {
39 if rmap.gaps(&(-T::PI()..T::PI())).next().is_none() {
40 fill_all = true;
41 }
42 }
43 let doms = [l.dom, (l.dom.0, T::PI()), (-T::PI(), l.dom.1)];
44 for &(dom_s, dom_e) in &doms[if l.dom.0 < l.dom.1 { 0..1 } else { 1..3 }] {
45 let mut updates = vec![];
46 for (seg_dom, seg_func) in rmap.overlapping(dom_s..dom_e) {
47 let dom = max(dom_s, seg_dom.start)..min(dom_e, seg_dom.end);
48 match (
49 float_cmp(l.line.at(dom.start), seg_func.at(dom.start), eps),
50 float_cmp(l.line.at(dom.end), seg_func.at(dom.end), eps),
51 ) {
52 (Less | Equal, Less | Equal) => {}
53 (Greater | Equal, Greater | Equal) => {
54 updates.push((dom, l.line));
55 }
56 (Less, Greater) => {
57 let cross = l.line.cross_point(seg_func, &dom).unwrap();
58 updates.push((cross..dom.end, l.line));
59 }
60 (Greater, Less) => {
61 let cross = l.line.cross_point(seg_func, &dom).unwrap();
62 updates.push((dom.start..cross, l.line));
63 }
64 }
65 }
66 if !fill_all {
67 for gap in rmap.gaps(&(dom_s..dom_e)) {
68 updates.push((gap, l.line));
69 }
70 }
71 updates.into_iter().for_each(|(dom, func)| {
72 lower = min(lower, min(func.at(dom.start), func.at(dom.end)));
73 rmap.insert(dom, func);
74 });
75 }
76 }
77 rmap
78}