1use std::{
21 cell::RefCell,
22 fmt::{self, Display, Formatter},
23 io::{self, Write},
24 marker::PhantomData,
25 ops::ControlFlow,
26};
27use rgb::*;
28
29mod approx_priority_queue;
34use approx_priority_queue as pq;
35
36mod linked_list;
37use linked_list as list;
38use list::List;
39
40#[derive(Debug, Clone, Copy, PartialEq)]
46pub struct BoundingBox {
47 pub xmin: f64,
48 pub xmax: f64,
49 pub ymin: f64,
50 pub ymax: f64,
51}
52
53impl BoundingBox {
54 #[inline]
55 pub(crate) fn empty() -> Self {
56 Self { xmin: f64::INFINITY, xmax: f64::NEG_INFINITY,
57 ymin: f64::INFINITY, ymax: f64::NEG_INFINITY }
58 }
59
60 #[inline]
62 pub fn is_empty(&self) -> bool {
63 !(self.xmin < self.xmax && self.ymin < self.ymax) }
65
66 #[inline]
69 fn contains<D>(&self, p: &Point<D>) -> bool {
70 let [x, y] = p.xy;
71 self.xmin <= x && x <= self.xmax && self.ymin <= y && y <= self.ymax
72 }
73
74 #[inline]
77 pub fn hull(&self, other: &Self) -> Self {
78 BoundingBox { xmin: self.xmin.min(other.xmin),
79 xmax: self.xmax.max(other.xmax),
80 ymin: self.ymin.min(other.ymin),
81 ymax: self.ymax.max(other.ymax) }
82 }
83}
84
85
86#[derive(Debug)]
98struct Point<D> {
99 t: f64, xy: [f64; 2],
101 data: D,
102 cost: f64, witness: RefCell<Option<pq::Witness<list::Witness<Point<D>>>>>,
108}
109
110#[derive(Clone, Copy, Debug)]
116struct Coord {
117 t: f64,
118 xy: [f64; 2],
119 cost: f64,
120}
121
122impl<D: Clone> Clone for Point<D> {
123 fn clone(&self) -> Self {
126 Self {
127 t: self.t, xy: self.xy,
128 data: self.data.clone(),
129 cost: self.cost,
130 witness: None.into(),
131 }
132 }
133}
134
135impl<D> Point<D> {
136 #[inline]
138 fn new_unchecked(t: f64, xy: [f64; 2], data: D) -> Self {
139 Point { t, xy, data, cost: 0.,
140 witness: None.into() }
141 }
142
143 #[inline]
145 fn cut(t: f64, data: D) -> Self {
146 Point { t, xy: [f64::NAN; 2], data,
147 cost: 0.,
148 witness: None.into() }
149 }
150
151 #[inline]
153 fn is_valid(&self) -> bool {
154 self.xy.iter().all(|z| z.is_finite())
155 }
156
157 #[inline]
159 fn opt(self) -> Point<Option<D>> {
160 Point {
161 t: self.t, xy: self.xy,
162 data: Some(self.data),
163 cost: self.cost,
164 witness: None.into(),
165 }
166 }
167
168 #[inline]
173 fn coord(&self) -> Coord {
174 Coord { t: self.t, xy: self.xy, cost: self.cost }
175 }
176}
177
178pub struct Sampling<D> {
184 pq: PQ<D>,
190 path: List<Point<D>>,
191 vp: Option<BoundingBox>, }
193
194type PQ<D> = pq::PQ<list::Witness<Point<D>>>;
195
196impl<D: Clone> Clone for Sampling<D> {
197 fn clone(&self) -> Self {
198 Self { pq: PQ::new(),
201 path: self.path.clone(),
202 vp: self.vp }
203 }
204}
205
206#[derive(Debug, Clone, Copy)]
209struct Lengths {
210 t: f64,
211 x: f64,
212 y: f64,
213}
214
215impl<D> Sampling<D> {
216 #[inline]
218 pub fn is_empty(&self) -> bool { self.path.is_empty() }
219
220 #[inline]
222 pub(crate) fn empty() -> Self {
223 Self { pq: PQ::new(),
224 path: List::new(),
225 vp: None }
226 }
227
228 #[inline]
229 pub(crate) fn singleton(p: Point<D>) -> Self {
230 debug_assert!(p.t.is_finite() && p.xy.iter().all(|z| z.is_finite()));
231 let mut path = List::new();
232 path.push_back(p);
233 Self { pq: PQ::new(), path, vp: None }
234 }
235
236 fn from_list(path: List<Point<D>>) -> Self {
237 Self {
238 pq: PQ::new(),
239 path,
240 vp: None,
241 }
242 }
243
244 #[inline]
245 pub(crate) fn set_vp(&mut self, bb: BoundingBox) {
246 self.vp = Some(bb);
247 }
248
249 pub(crate) fn lengths(&self) -> Option<Lengths> {
252 if self.is_empty() { return None }
253 let p0 = self.path.first().unwrap();
254 let p1 = self.path.last().unwrap();
255 let len_x;
256 let len_y;
257 match self.vp {
258 Some(vp) => {
259 len_x = vp.xmax - vp.xmin;
260 len_y = vp.ymax - vp.ymin;
261 }
262 None => {
263 len_x = 1.;
264 len_y = 1.;
265 }
266 }
267 Some(Lengths { t: (p1.t - p0.t).abs(), x: len_x, y: len_y })
268 }
269
270 pub fn len(&self) -> usize {
272 self.path.len()
273 }
274
275 pub fn iter(&self) -> Iter<'_, D> {
282 Iter { iter: self.iter_data() }
283 }
284
285 pub fn iter_data(&self) -> IterData<'_, D> {
288 IterData {
289 path: self.path.iter(),
290 prev_is_cut: true,
291 }
292 }
293
294 pub fn iter_mut(&mut self) -> IterMut<'_, D> {
300 IterMut { path: self.path.iter_mut() }
301 }
302
303 pub fn into_iter_data(self) -> IntoIterData<D> {
306 IntoIterData { path: self.path.into_iter() }
307 }
308
309 #[inline]
311 pub fn x(&self) -> Vec<f64> {
312 let mut v = Vec::with_capacity(self.path.len());
313 for [x, _] in self.iter() { v.push(x) }
314 v
315 }
316
317 #[inline]
319 pub fn y(&self) -> Vec<f64> {
320 let mut v = Vec::with_capacity(self.path.len());
321 for [_, y] in self.iter() { v.push(y) }
322 v
323 }
324}
325
326
327pub struct IterData<'a, D> {
331 path: list::Iter<'a, Point<D>>,
332 prev_is_cut: bool,
333}
334
335impl<'a, D> Iterator for IterData<'a, D> {
336 type Item = ([f64; 2], &'a D);
337
338 fn next(&mut self) -> Option<Self::Item> {
339 match self.path.next() {
340 None => None,
341 Some(p) => {
342 if p.is_valid() {
343 self.prev_is_cut = false;
344 Some((p.xy, &p.data))
345 } else if self.prev_is_cut {
346 let r = self.path.try_fold((), |_, p| {
349 if p.is_valid() {
350 ControlFlow::Break(((), p))
351 } else {
352 ControlFlow::Continue(())
353 }
354 });
355 match r {
356 ControlFlow::Continue(_) => {
357 None
359 }
360 ControlFlow::Break((_, p)) => {
361 self.prev_is_cut = false;
362 Some((p.xy, &p.data))
363 }
364 }
365 } else {
366 self.prev_is_cut = true;
367 Some(([f64::NAN; 2], &p.data))
368 }
369 }
370 }
371 }
372
373 fn size_hint(&self) -> (usize, Option<usize>) {
374 (0, Some(self.path.len()))
375 }
376}
377
378pub struct Iter<'a, D> {
382 iter: IterData<'a, D>,
383}
384
385impl<'a, D> Iterator for Iter<'a, D> {
386 type Item = [f64; 2];
387
388 #[inline]
389 fn next(&mut self) -> Option<Self::Item> {
390 self.iter.next().map(|(xy, _)| xy)
391 }
392
393 fn size_hint(&self) -> (usize, Option<usize>) {
394 self.iter.size_hint()
395 }
396}
397
398
399pub struct IterMut<'a, D> {
403 path: list::IterMut<'a, Point<D>>,
404}
405
406impl<'a, D> Iterator for IterMut<'a, D> {
407 type Item = &'a mut [f64; 2];
408
409 fn next(&mut self) -> Option<Self::Item> {
410 self.path.next().map(|p| &mut p.xy)
411 }
412
413 fn size_hint(&self) -> (usize, Option<usize>) {
414 (self.path.len(), Some(self.path.len()))
415 }
416}
417
418pub struct IntoIterData<D> {
422 path: list::IntoIter<Point<D>>,
423}
424
425impl<D> Iterator for IntoIterData<D> {
426 type Item = ([f64; 2], D);
427
428 fn next(&mut self) -> Option<Self::Item> {
429 self.path.next().map(|p| (p.xy, p.data))
430 }
431
432 fn size_hint(&self) -> (usize, Option<usize>) {
433 (self.path.len(), Some(self.path.len()))
434 }
435}
436
437
438#[derive(Debug)]
440enum Intersection<D> {
441 Empty,
442 Pt(Point<D>),
443 Seg(Point<D>, Point<D>),
444}
445
446impl<D> Sampling<D> {
447 pub fn bounding_box(&self) -> BoundingBox {
451 let mut points = self.iter().skip_while(|[x,_]| x.is_nan());
452 let mut bb = match &points.next() {
453 Some([x, y]) => BoundingBox { xmin: *x, xmax: *x,
454 ymin: *y, ymax: *y },
455 None => return BoundingBox::empty()
456 };
457 for [x, y] in points {
458 if x < bb.xmin { bb.xmin = x }
459 else if bb.xmax < x { bb.xmax = x };
460 if y < bb.ymin { bb.ymin = y }
461 else if bb.ymax < y { bb.ymax = y };
462 }
463 bb
464 }
465
466 pub fn transpose(&mut self) -> &mut Self {
468 for p in self.path.iter_mut() {
469 let [x, y] = p.xy;
470 p.xy = [y, x];
471 }
472 self
473 }
474
475 #[inline]
479 #[must_use]
480 fn intersect(
481 p0: Coord, p1: Coord, bb: BoundingBox
482 ) -> Option<Point<Option<D>>> {
483 let [x0, y0] = p0.xy;
484 let [x1, y1] = p1.xy;
485 let mut t = 1.; let dx = x1 - x0; let r = (if dx >= 0. {bb.xmax} else {bb.xmin} - x0) / dx;
488 if r < t { t = r } let dy = y1 - y0; let r = (if dy >= 0. {bb.ymax} else {bb.ymin} - y0) / dy;
491 if r < t { t = r };
492 if t <= 1e-14 {
493 None
494 } else {
495 Some(Point::new_unchecked(
496 p0.t + t * (p1.t - p0.t),
497 [x0 + t * dx, y0 + t * dy],
498 None))
499 }
500 }
501
502 #[inline]
507 #[must_use]
508 fn intersect_seg(
509 p0: Coord, p1: Coord, bb: BoundingBox,
510 ) -> Intersection<Option<D>> {
511 let [x0, y0] = p0.xy;
512 let [x1, y1] = p1.xy;
513 let mut t0 = 0.; let mut t1 = 1.; let dx = x1 - x0; let r0;
517 let r1; if dx >= 0. {
519 r0 = (bb.xmin - x0) / dx;
520 r1 = (bb.xmax - x0) / dx;
521 } else {
522 r0 = (bb.xmax - x0) / dx;
523 r1 = (bb.xmin - x0) / dx;
524 }
525 if r0 > 1. || r1 < 0. { return Intersection::Empty }
526 if r0 > 0. { t0 = r0 } if r1 < 1. { t1 = r1 }
528 let dy = y1 - y0; let r0;
530 let r1;
531 if dy >= 0. {
532 r0 = (bb.ymin - y0) / dy;
533 r1 = (bb.ymax - y0) / dy;
534 } else {
535 r0 = (bb.ymax - y0) / dy;
536 r1 = (bb.ymin - y0) / dy;
537 }
538 if r0 > t1 || r1 < t0 { return Intersection::Empty }
539 if r0 > t0 { t0 = r0 }
540 if r1 < t1 { t1 = r1 }
541 if t0 < t1 { let dt = p1.t - p0.t;
543 let q0 = Point::new_unchecked(p0.t + t0 * dt,
544 [x0 + t0 * dx, y0 + t0 * dy], None);
545 let q1 = Point::new_unchecked(p0.t + t1 * dt,
546 [x0 + t1 * dx, y0 + t1 * dy], None);
547 Intersection::Seg(q0, q1)
548 } else if t0 == t1 {
549 let q0 = Point::new_unchecked(
550 p0.t + t0 * (p1.t - p0.t),
551 [x0 + t0 * dx, y0 + t0 * dy], None);
552 Intersection::Pt(q0)
553 } else {
554 Intersection::Empty
555 }
556 }
557
558 #[must_use]
564 pub fn clip(self, bb: BoundingBox) -> Sampling<Option<D>> {
565 let mut path = Vec::new();
566 let mut p0_opt: Option<Coord> = None;
568 let mut p0_inside = false;
569 let mut prev_cut = true; for p1 in self.path.into_iter() {
571 if prev_cut {
572 match (p0_opt, p1.is_valid()) {
580 (Some(p0), true) => {
581 let p1_inside = bb.contains(&p1);
582 p0_opt = Some(p1.coord());
583 if p0_inside { if p1_inside {
586 path.push(p1.opt());
587 prev_cut = false;
588 } else if
589 let Some(p) = Self::intersect(p0, p1.coord(), bb) {
590 let t = p.t;
591 path.push(p);
592 path.push(Point::cut(t, None));
593 } else {
594 let c = Point::cut(p0.t, None);
595 path.push(c);
596 }
597 } else if p1_inside { if let Some(p) = Self::intersect(p1.coord(), p0, bb) {
599 path.push(p); }
601 path.push(p1.opt());
602 prev_cut = false;
603 } else { match Self::intersect_seg(p0, p1.coord(), bb) {
605 Intersection::Seg(q0, q1) => {
606 let t1 = q1.t;
607 path.push(q0);
608 path.push(q1);
609 path.push(Point::cut(t1, None));
610 }
611 Intersection::Pt(p) => {
612 let t = p.t;
613 path.push(p);
614 path.push(Point::cut(t, None));
615 }
616 Intersection::Empty => (),
617 }
618 }
619 p0_inside = p1_inside;
620 }
621 (None, true) => {
622 p0_inside = bb.contains(&p1);
623 p0_opt = Some(p1.coord());
624 if p0_inside {
625 path.push(p1.opt());
627 }
628 }
629 (Some(p0), false) => {
630 if p0_inside {
631 path.push(Point::cut(p0.t, None));
633 }
634 p0_opt = None;
635 }
636 (None, false) => (), }
638 } else {
639 let p0 = p0_opt.expect("No cut ⟹ previous point");
643 debug_assert!(p0_inside);
644 if p1.is_valid() {
645 p0_opt = Some(p1.coord());
646 p0_inside = bb.contains(&p1); if p0_inside { path.push(p1.opt());
649 } else { if let Some(p) = Self::intersect(p0, p1.coord(), bb) {
651 let t = p.t;
652 path.push(p);
653 path.push(Point::cut(t, None));
654 } else {
655 path.push(Point::cut(p0.t, None));
656 }
657 prev_cut = true;
658 }
659 } else { p0_opt = None;
661 path.push(p1.opt());
662 prev_cut = true
663 }
664 }
665 }
666 if prev_cut { path.pop(); }
667 let mut s = Sampling::from_list(path.into());
668 s.set_vp(bb);
669 s
670 }
671
672 fn from_point_iterator<P>(points: P) -> Self
675 where P: IntoIterator<Item = Point<D>> {
676 let mut s = Sampling::empty();
677 let mut points = points.into_iter();
678 macro_rules! skip_until_last_cut { () => {
679 let mut cut = None;
680 let mut first_pt = None;
681 while let Some(p) = points.next() {
682 if p.is_valid() { first_pt = Some(p); break; }
683 cut = Some(p);
684 }
685 match (cut, first_pt) {
686 (_, None) => {
687 return s
688 }
689 (None, Some(p)) => {
690 s.path.push_back(p);
691 }
692 (Some(c), Some(p)) => {
693 s.path.push_back(Point::cut(c.t, c.data));
694 s.path.push_back(p);
695 }
696 }
697 }}
698 skip_until_last_cut!();
699 while let Some(p) = points.next() {
700 if p.is_valid() {
701 s.path.push_back(p);
702 } else {
703 s.path.push_back(Point::cut(p.t, p.data));
704 skip_until_last_cut!();
705 }
706 }
707 s
708 }
709
710 fn from_vec(mut points: Vec<Point<D>>, incr: bool) -> Self {
715 if incr {
716 points.sort_unstable_by(|p1, p2| {
717 p1.t.partial_cmp(&p2.t).unwrap() });
719 } else {
720 points.sort_unstable_by(|p1, p2| {
721 p2.t.partial_cmp(&p1.t).unwrap() });
722 }
723 Self::from_point_iterator(points)
724 }
725}
726
727
728impl<D, Y> FromIterator<Y> for Sampling<D>
729where Y: Img<D> {
730 fn from_iter<P>(points: P) -> Self
733 where P: IntoIterator<Item = Y> {
734 Sampling::from_point_iterator(
735 points.into_iter().enumerate().map(|(i, y)| {
736 let t = i as f64;
737 let p = y.into_point(t);
738 let [x, y] = p.xy;
739 if x.is_finite() && y.is_finite() {
740 p
741 } else {
742 Point::cut(t, p.data)
743 } }))
744 }
745}
746
747pub trait Img<D> {
760 #[allow(private_interfaces)]
763 fn into_point(self, t: f64) -> Point<D>;
764}
765
766#[derive(Clone, Debug)]
768pub struct NoData {
769 marker: PhantomData<()>,
772}
773
774impl NoData {
775 fn new() -> Self { Self { marker: PhantomData } }
776}
777
778impl Img<NoData> for f64 {
779 #[allow(private_interfaces)]
780 #[inline]
781 fn into_point(self, t: f64) -> Point<NoData> {
782 Point::new_unchecked(t, [t, self], NoData::new())
783 }
784}
785
786impl Img<NoData> for [f64; 2] {
787 #[allow(private_interfaces)]
788 #[inline]
789 fn into_point(self, t: f64) -> Point<NoData> {
790 Point::new_unchecked(t, self, NoData::new())
791 }
792}
793
794impl Img<NoData> for (f64, f64) {
795 #[allow(private_interfaces)]
796 #[inline]
797 fn into_point(self, t: f64) -> Point<NoData> {
798 Point::new_unchecked(t, [self.0, self.1], NoData::new())
799 }
800}
801
802#[cfg(feature = "num-complex")]
803impl Img<num_complex::Complex<f64>> for num_complex::Complex<f64> {
804 #[allow(private_interfaces)]
805 #[inline]
806 fn into_point(self, t: f64) -> Point<num_complex::Complex<f64>> {
807 Point::new_unchecked(t, [self.re, self.im], self)
808 }
809}
810
811pub struct Data<D>(pub D);
815
816impl<D> Img<D> for (f64, Data::<D>) {
818 #[allow(private_interfaces)]
819 #[inline]
820 fn into_point(self, t: f64) -> Point<D> {
821 Point::new_unchecked(t, [t, self.0], self.1.0)
822 }
823}
824
825impl<D> Img<D> for ([f64; 2], Data::<D>) {
827 #[allow(private_interfaces)]
828 #[inline]
829 fn into_point(self, t: f64) -> Point<D> {
830 Point::new_unchecked(t, self.0, self.1.0)
831 }
832}
833
834#[cfg(feature = "num-complex")]
835impl<D> Img<D> for (num_complex::Complex<f64>, Data::<D>) {
836 #[allow(private_interfaces)]
837 #[inline]
838 fn into_point(self, t: f64) -> Point<D> {
839 Point::new_unchecked(t, [self.0.re, self.0.im], self.1.0)
840 }
841}
842
843
844macro_rules! new_sampling_fn {
851 ($(#[$docfn: meta])*, $(#[$docfn_extra: meta])* $fun: ident -> $ft: ty,
853 $(#[$doc: meta])* $struct: ident,
855 $wrap_f: ident
856 ) => {
857 impl<D> Sampling<D> {
858 $(#[$docfn])*
859 $(#[$docfn_extra])*
863 #[must_use]
864 #[allow(deprecated)]
865 pub fn $fun<F, Y>(f: F, a: f64, b: f64) -> $struct<F, D>
866 where F: FnMut(f64) -> Y,
867 Y: Img<D> {
868 if !a.is_finite() {
869 panic!("curve_sampling::{}: a = {} must be finite",
870 stringify!($fun), a);
871 }
872 if !b.is_finite() {
873 panic!("curve_sampling::{}: b = {} must be finite",
874 stringify!($fun), b);
875 }
876 $struct { f,
877 a, b, n: 100,
879 viewport: None,
880 init: vec![],
881 init_pt: vec![],
882 }
883 }
884 }
885
886 $(#[$doc])*
887 pub struct $struct<F, D> {
888 f: F, a: f64, b: f64,
889 n: usize,
890 viewport: Option<BoundingBox>,
891 init: Vec<f64>,
892 init_pt: Vec<Point<D>>,
893 }
894
895 #[allow(deprecated)]
896 impl<F, Y, D> $struct<F, D>
897 where F: FnMut(f64) -> Y,
898 Y: Img<D>,
899 {
900 pub fn n(mut self, n: usize) -> Self {
903 if n < 2 {
904 panic!("curve_sampling: n = {} must at least be 2", n)
905 }
906 self.n = n;
907 self
908 }
909
910 pub fn viewport(mut self, vp: BoundingBox) -> Self {
913 self.viewport = Some(vp);
914 self
915 }
916
917 #[doc = stringify!(Sampling::$fun)]
919 pub fn init<'a, I>(mut self, ts: I) -> Self
923 where I: IntoIterator<Item = &'a f64> {
924 for &t in ts {
925 if self.a <= t && t <= self.b { self.init.push(t);
927 }
928 }
929 self
930 }
931
932 #[doc = stringify!(Sampling::$fun)]
938 pub fn init_pt<I>(mut self, pts: I) -> Self
940 where I: IntoIterator<Item = (f64, Y)>,
941 {
942 for (t, y) in pts {
943 if self.a <= t && t <= self.b { self.init_pt.push(y.into_point(t));
945 }
946 }
947 self
948 }
949
950 fn eval_init(&mut self) {
953 for &t in &self.init {
956 self.init_pt.push((self.f)(t).into_point(t))
957 }
958 self.init.clear()
959 }
960 }
961 }
962}
963
964new_sampling_fn!(
969 ,
975 uniform -> f64,
986 Uniform,
989 FnPoint);
990
991impl<F, Y, D> Uniform<F, D>
992where F: FnMut(f64) -> Y,
993 Y: Img<D> {
994 pub fn build(mut self) -> Sampling<D> {
996 if self.a == self.b {
997 let p = (self.f)(self.a).into_point(self.a);
999 if p.is_valid() {
1000 return Sampling::singleton(p);
1001 } else {
1002 return Sampling::empty()
1003 }
1004 }
1005 self.eval_init();
1006 let mut points = self.init_pt;
1010 let dt = (self.b - self.a) / (self.n - 1) as f64;
1011 for i in 0 .. self.n {
1012 let t = self.a + i as f64 * dt;
1013 points.push((self.f)(t).into_point(t));
1014 }
1015 Sampling::from_vec(points, self.a < self.b)
1016 }
1017}
1018
1019mod cost {
1024 use super::{Point, Coord, Lengths};
1025
1026 pub const HANGING_NODE: f64 = 5e5;
1052
1053 #[inline]
1056 pub(crate) fn set_middle<D>(
1057 p0: Coord, pm: &mut Point<D>, p1: Coord, len: Lengths
1058 ) {
1059 let [x0, y0] = p0.xy;
1060 let [xm, ym] = pm.xy;
1061 let [x1, y1] = p1.xy;
1062 let dx0m = (x0 - xm) / len.x;
1063 let dy0m = (y0 - ym) / len.y;
1064 let dx1m = (x1 - xm) / len.x;
1065 let dy1m = (y1 - ym) / len.y;
1066 let len0m = dx0m.hypot(dy0m);
1067 let len1m = dx1m.hypot(dy1m);
1068 if len0m == 0. || len1m == 0. {
1069 pm.cost = 0.; } else {
1071 let dx = - dx0m * dx1m - dy0m * dy1m;
1072 let dy = dy0m * dx1m - dx0m * dy1m;
1073 pm.cost = dy.atan2(dx); debug_assert!(!pm.cost.is_nan());
1075 }
1076 }
1077
1078 #[inline]
1081 pub(crate) fn segment_vp(
1082 p0: Coord,
1083 p1: Coord,
1084 len: Lengths,
1085 in_vp: bool
1086 ) -> f64 {
1087 if ! in_vp { return f64::NEG_INFINITY }
1088 segment(p0, p1, len)
1089 }
1090
1091 #[inline]
1094 pub(crate) fn segment(p0: Coord, p1: Coord, len: Lengths) -> f64 {
1095 let dt = (p1.t - p0.t).abs() / len.t; debug_assert!((0. ..=1.).contains(&dt), "dt = {dt} ∉ [0,1]");
1097 let [x0, y0] = p0.xy;
1101 let [x1, y1] = p1.xy;
1102 let dx = ((x1 - x0) / len.x).abs();
1103 let dy = ((y1 - y0) / len.y).abs();
1104 let mut cost = p0.cost.abs() + p1.cost.abs(); if p0.cost * p1.cost < 0. {
1106 if dx <= 0.01 && dy <= 0.01 { cost *= 0.5 }
1109 else if !(dx <= 0.05 && dy <= 0.05) { cost *= 8. }
1110 }
1111 if dt >= 0.8 { cost }
1112 else {
1113 let dt = dt / 0.8;
1114 dt * dt * (6. + (-8. + 3. * dt) * dt) * cost
1115 }
1116 }
1117
1118}
1119
1120fn push_segment<D>(
1125 pq: &mut PQ<D>,
1126 p0: &Point<D>, w0: &list::Witness<Point<D>>, p1: Coord,
1127 len: Lengths, in_vp: bool
1128) {
1129 let cost_segment = cost::segment_vp(p0.coord(), p1, len, in_vp);
1133 let w = pq.push(cost_segment, w0.clone());
1135 *p0.witness.borrow_mut() = Some(w);
1136}
1137
1138unsafe fn update_segment<D>(
1144 pq: &mut PQ<D>,
1145 p0: &Point<D>,
1146 p1: Coord,
1147 len: Lengths
1148) {
1149 match &*p0.witness.borrow() {
1150 Some(w) => {
1151 let priority = cost::segment(p0.coord(), p1, len);
1152 pq.increase_priority(w, priority)
1153 }
1154 None => panic!("Sampling::update_segment: unset witness"),
1155 }
1156}
1157
1158fn compute<D>(s: &mut Sampling<D>, in_vp: impl Fn(&Point<D>) -> bool) {
1165 if let Some(len) = s.lengths() {
1166 s.path.first_mut().unwrap().cost = 0.;
1167 s.path.last_mut().unwrap().cost = 0.;
1168 let segments = unsafe { s.path.iter_segments_mut() };
1169 for (p0, w0, pm, p1) in segments {
1170 let p0_is_valid = p0.is_valid();
1171 let p0_in_vp = p0_is_valid && in_vp(p0);
1172 let pm_is_valid = pm.is_valid();
1173 let pm_in_vp;
1174 if let Some(p1) = p1 {
1175 if pm_is_valid {
1176 pm_in_vp = in_vp(pm);
1177 if p0_is_valid && p1.is_valid() {
1178 let c0 = p0.coord();
1179 let c1 = p1.coord();
1180 cost::set_middle(c0, pm, c1, len);
1181 } else {
1182 pm.cost = cost::HANGING_NODE;
1183 }
1184 } else { pm_in_vp = false;
1186 pm.cost = 0.;
1187 }
1188 if p0_is_valid || pm_is_valid {
1189 push_segment(&mut s.pq, p0, &w0, pm.coord(), len,
1191 p0_in_vp || pm_in_vp);
1192 }
1193 } else { if p0_is_valid || pm_is_valid {
1195 let mut vp = p0_in_vp;
1196 if pm.is_valid() { vp = vp || in_vp(pm) };
1197 push_segment(&mut s.pq, p0, &w0, pm.coord(), len, vp);
1198 }
1199 }
1200 }
1201 }
1202}
1203
1204fn refine_gen<D>(
1205 s: &mut Sampling<D>, n: usize,
1206 mut f: impl FnMut(f64) -> Point<D>,
1207 in_vp: impl Fn(&Point<D>) -> bool
1208) {
1209 let len = match s.lengths() {
1210 Some(lengths) => lengths,
1211 None => return };
1212 macro_rules! r { ($x: ident) => { unsafe { s.path.get(&$x) } } }
1213 macro_rules! m { ($x: ident) => { unsafe { s.path.get_mut(&$x) } } }
1214 macro_rules! prev { ($x: ident) => { unsafe { s.path.prev(& $x) } } }
1215 macro_rules! next { ($x: ident) => { unsafe { s.path.next(& $x) } } }
1216 for _ in 0 .. n {
1217 let mut p0: list::Witness<Point<D>> = match s.pq.pop() {
1218 None => break,
1219 Some(p) => p };
1220 *r!(p0).witness.borrow_mut() = None; let p1 = next!(p0).unwrap();
1222 let t = (r!(p0).t + r!(p1).t) * 0.5;
1224 let mut pm = f(t);
1225 if r!(p0).is_valid() {
1226 if r!(p1).is_valid() {
1227 let pm = unsafe { s.path.insert_after(&mut p0, pm) };
1228 let mut pm_in_vp = false;
1229 if r!(pm).is_valid() {
1230 pm_in_vp = in_vp(r!(pm));
1231 let c0 = r!(p0).coord();
1232 let c1 = r!(p1).coord();
1233 cost::set_middle(c0, m!(pm), c1, len);
1234 let cm = r!(pm).coord();
1235 if let Some(p_1) = prev!(p0) {
1236 if r!(p_1).is_valid() {
1237 let c_1 = r!(p_1).coord();
1238 cost::set_middle(c_1, m!(p0), cm, len);
1239 let p_1 = r!(p_1);
1240 let p0 = r!(p0).coord();
1241 unsafe { update_segment(&mut s.pq, p_1, p0, len) }
1242 }
1243 if let Some(p2) = next!(p1) && r!(p2).is_valid() {
1244 let c2 = r!(p2).coord();
1245 cost::set_middle(cm, m!(p1), c2, len);
1246 let p1 = r!(p1);
1247 unsafe { update_segment(&mut s.pq, p1, c2, len) }
1248 }
1249 } else { m!(p0).cost = cost::HANGING_NODE;
1251 m!(pm).cost = 0.;
1252 m!(p1).cost = cost::HANGING_NODE;
1253 if let Some(p_1) = prev!(p0) {
1254 let p_1 = r!(p_1);
1255 let p0 = r!(p0).coord();
1256 unsafe { update_segment(&mut s.pq, p_1, p0, len) }
1257 }
1258 if let Some(p2) = next!(p1) {
1259 let p1 = r!(p1);
1260 let p2 = r!(p2).coord();
1261 unsafe { update_segment(&mut s.pq, p1, p2, len) }
1262 }
1263 }
1264 }
1265 let vp = pm_in_vp || in_vp(r!(p0));
1266 let cm = r!(pm).coord();
1267 push_segment(&mut s.pq, r!(p0), &p0, cm, len, vp);
1268 let vp = pm_in_vp || in_vp(r!(p1));
1269 let c1 = r!(p1).coord();
1270 push_segment(&mut s.pq, r!(pm), &pm, c1, len, vp);
1271 } else { if pm.is_valid() {
1274 pm.cost = cost::HANGING_NODE;
1275 let pm = unsafe { s.path.insert_after(&mut p0, pm) };
1276 if let Some(p_1) = prev!(p0) && r!(p_1).is_valid() {
1277 let c_1 = r!(p_1).coord();
1278 let pm = r!(pm).coord();
1279 cost::set_middle(c_1, m!(p0), pm, len);
1280 let p_1 = r!(p_1);
1281 let p0 = r!(p0).coord();
1282 unsafe{ update_segment(&mut s.pq, p_1, p0, len) }
1283 }
1284 let pm_in_vp = in_vp(r!(pm));
1285 let vp = pm_in_vp || in_vp(r!(p0));
1286 let cm = r!(pm).coord();
1287 let c1 = r!(p1).coord();
1288 push_segment(&mut s.pq, r!(p0), &p0, cm, len, vp);
1289 push_segment(&mut s.pq, r!(pm), &pm, c1, len, pm_in_vp)
1290 } else { pm.cost = 0.;
1297 let pm = {
1298 if r!(p1).witness.borrow().is_none() {
1299 unsafe { *s.path.get_mut(&p1) = pm } ;
1302 p1 } else {
1304 unsafe { s.path.insert_after(&mut p0, pm) }
1305 }
1306 };
1307 let vp = in_vp(r!(p0));
1308 let cm = r!(pm).coord();
1309 push_segment(&mut s.pq, r!(p0), &p0, cm, len, vp)
1310 }
1311 }
1312 } else { debug_assert!(r!(p1).is_valid());
1314 if pm.is_valid() {
1315 pm.cost = cost::HANGING_NODE;
1316 let pm = unsafe { s.path.insert_after(&mut p0, pm) };
1317 if let Some(p2) = next!(p1) && r!(p2).is_valid() {
1318 let pm = r!(pm).coord();
1319 let p2 = r!(p2).coord();
1320 cost::set_middle(pm, m!(p1), p2, len);
1321 let p1 = r!(p1);
1322 unsafe{ update_segment(&mut s.pq, p1, p2, len) }
1323 }
1324 let pm_in_vp = in_vp(r!(pm));
1325 let cm = r!(pm).coord();
1326 let c1 = r!(p1).coord();
1327 push_segment(&mut s.pq, r!(p0), &p0, cm, len, pm_in_vp);
1328 let in_vp = pm_in_vp || in_vp(r!(p1));
1329 push_segment(&mut s.pq, r!(pm), &pm, c1, len, in_vp);
1330 } else { pm.cost = 0.;
1333 let pm = {
1334 if let Some(p_1) = prev!(p0) {
1335 if r!(p_1).is_valid() {
1336 unsafe { s.path.insert_after(&mut p0, pm) }
1337 } else {
1338 unsafe { *s.path.get_mut(&p0) = pm };
1340 p0
1341 }
1342 } else {
1343 unsafe { s.path.insert_after(&mut p0, pm) }
1344 }
1345 };
1346 let vp = in_vp(r!(p1));
1347 let c1 = r!(p1).coord();
1348 push_segment(&mut s.pq, r!(pm), &pm, c1, len, vp)
1349 }
1350 }
1351 }
1352}
1353
1354fn push_almost_uniform_sampling<D>(
1355 points: &mut Vec<Point<D>>,
1356 f: &mut impl FnMut(f64) -> Point<D>,
1357 a: f64, b: f64, n: usize
1358) {
1359 debug_assert!(n >= 4);
1360 let dt = (b - a) / (n - 3) as f64;
1361 let mut random = (n as u32).wrapping_mul(1_000_000);
1366 const NORMALIZE_01: f64 = 1. / u32::MAX as f64;
1367 let mut rand = move || {
1368 random ^= random << 13;
1369 random ^= random >> 17;
1370 random ^= random << 5;
1371 random as f64 * NORMALIZE_01
1372 };
1373 points.push(f(a));
1374 points.push(f(a + 0.0625 * dt));
1375 for i in 1 ..= n - 4 {
1376 let j = i as f64 + rand() * 0.125 - 0.0625;
1377 points.push(f(a + j * dt));
1378 }
1379 points.push(f(b - 0.0625 * dt));
1380 points.push(f(b));
1381}
1382
1383impl<D> Sampling<D> {
1384 fn build(
1386 mut points: Vec<Point<D>>,
1387 mut f: impl FnMut(f64) -> Point<D>,
1388 a: f64, b: f64, n: usize,
1389 viewport: Option<BoundingBox>
1390 ) -> Self {
1391 if a == b {
1392 let p = f(a);
1393 if p.is_valid() {
1394 return Sampling::singleton(p);
1395 } else {
1396 return Sampling::empty()
1397 }
1398 }
1399 let n0 = (n / 10).max(10);
1402 push_almost_uniform_sampling(&mut points, &mut f, a, b, n0);
1404 let mut s = Sampling::from_vec(points, a < b);
1405 match viewport {
1406 Some(vp) => {
1407 let in_vp = |p: &Point<_>| vp.contains(p);
1408 compute(&mut s, in_vp);
1409 refine_gen(&mut s, n - n0, &mut f, in_vp)
1410 }
1411 None => {
1412 compute(&mut s, |_| true);
1413 refine_gen(&mut s, n - n0, &mut f, |_| true)
1414 }
1415 }
1416 s
1417 }
1418}
1419
1420
1421new_sampling_fn!(
1422 ,
1433 #[cfg_attr(feature = "num-complex", doc = "
1465With the feature `num-complex`, complex-valued functions may be used directly.
1466
1467```
1468use num_complex::Complex64 as C64;
1469use curve_sampling::{Sampling, Data};
1470# fn main() -> Result<(), Box<dyn std::error::Error>> {
1471fn f(t: f64) -> C64 {
1472 C64::i().powf(t)
1473}
1474let s = Sampling::fun(f, 0., 1.).build();
1475// ...
1476# Ok(()) }
1477```
1478")]
1479 fun -> f64,
1480 Fun,
1483 FnPoint);
1484
1485impl<F, Y, D> Fun<F, D>
1486where F: FnMut(f64) -> Y,
1487 Y: Img<D> {
1488 pub fn build(mut self) -> Sampling<D> {
1490 self.eval_init();
1491 Sampling::build(
1492 self.init_pt,
1493 |x| (self.f)(x).into_point(x),
1494 self.a, self.b, self.n, self.viewport)
1495 }
1496}
1497
1498
1499new_sampling_fn!(
1500 #[deprecated(note = "Use Sampling::fun instead")]
1501 ,
1504 param -> [f64; 2],
1515 #[deprecated(note = "See curve_sampling::Fun instead")]
1516 Param,
1519 ParamPoint);
1520
1521#[allow(deprecated)]
1522impl<F, Y, D> Param<F, D>
1523where F: FnMut(f64) -> Y,
1524 Y: Img<D> {
1525 pub fn build(mut self) -> Sampling<D> {
1527 self.eval_init();
1528 Sampling::build(
1529 self.init_pt,
1530 |t| (self.f)(t).into_point(t),
1531 self.a, self.b, self.n, self.viewport)
1532 }
1533}
1534
1535
1536pub struct LaTeX<'a, D> {
1553 sampling: &'a Sampling<D>,
1554 n: usize,
1555 color: Option<RGB8>,
1556 arrow: Option<&'a str>,
1557 arrow_pos: Option<f64>,
1558}
1559
1560impl<'a, D> LaTeX<'a, D> {
1561 #[inline]
1562 fn new(s: &'a Sampling<D>) -> Self {
1563 Self { sampling: s, n: 20_000, color: None,
1564 arrow: None, arrow_pos: None }
1565 }
1566
1567 pub fn n(&mut self, n: usize) -> &mut Self {
1571 self.n = n;
1572 self
1573 }
1574
1575 pub fn color(&mut self, color: RGB8) -> &mut Self {
1578 self.color = Some(color);
1579 self
1580 }
1581
1582 pub fn arrow(&mut self, arrow: &'a str) -> &mut Self {
1586 self.arrow = Some(arrow);
1587 self
1588 }
1589
1590 pub fn arrow_pos(&mut self, arrow_pos: f64) -> &mut Self {
1594 if ! arrow_pos.is_finite() {
1595 panic!("curve_sampling::LaTeX::arrow_pos: \
1596 position must be finite");
1597 }
1598 self.arrow_pos = Some(arrow_pos.clamp(0., 1.));
1599 self
1600 }
1601
1602 fn write_with_lines(&self, f: &mut impl Write) -> Result<(), io::Error> {
1604 let mut n = 0;
1605 let mut new_path = true;
1606 for [x,y] in self.sampling.iter() {
1607 if x.is_nan() {
1608 writeln!(f, "\\pgfusepath{{stroke}}")?;
1609 n = 0;
1610 new_path = true;
1611 } else {
1612 n += 1;
1613 if new_path {
1614 writeln!(f, "\\pgfpathmoveto{{\\pgfpointxy\
1615 {{{:.16}}}{{{:.16}}}}}", x, y)?
1616 } else if n >= self.n {
1617 write!(f, "\\pgfpathlineto{{\\pgfpointxy\
1618 {{{:.16}}}{{{:.16}}}}}\n\
1619 \\pgfusepath{{stroke}}\n\
1620 \\pgfpathmoveto{{\\pgfpointxy\
1621 {{{:.16}}}{{{:.16}}}}}\n", x, y, x, y)?;
1622 n = 0;
1623 } else {
1624 writeln!(f, "\\pgfpathlineto{{\\pgfpointxy\
1625 {{{:.16}}}{{{:.16}}}}}", x, y)?
1626 }
1627 new_path = false;
1628 }
1629 }
1630 Ok(())
1631 }
1632
1633 fn write_with_arrows(&self, f: &mut impl Write, arrow: &str,
1635 arrow_pos: f64) -> Result<(), io::Error> {
1636 let mut lens = vec![];
1638 let mut prev_pt: Option<[f64; 2]> = None;
1639 let mut cur_len = 0.;
1640 for p @ [x, y] in self.sampling.iter() {
1641 if x.is_nan() {
1642 lens.push(arrow_pos * cur_len);
1643 prev_pt = None;
1644 cur_len = 0.;
1645 } else {
1646 if let Some([x0, y0]) = prev_pt {
1647 cur_len += (x - x0).hypot(y - y0);
1648 }
1649 prev_pt = Some(p);
1650 }
1651 }
1652 lens.push(arrow_pos * cur_len);
1653 if lens.is_empty() { return Ok(()) }
1654 let mut lens = lens.iter();
1655 let mut rem_len = *lens.next().unwrap(); prev_pt = None;
1657 let mut n = 0;
1658 for p @ [x, y] in self.sampling.iter() {
1659 if x.is_nan() {
1660 writeln!(f, "\\pgfusepath{{stroke}}")?;
1661 rem_len = *lens.next().unwrap();
1662 prev_pt = None;
1663 } else {
1664 n += 1;
1665 if let Some([x0, y0]) = prev_pt {
1666 let dx = x - x0;
1667 let dy = y - y0;
1668 let l = dx.hypot(dy);
1669 if rem_len <= l {
1670 writeln!(f, "\\pgfusepath{{stroke}}")?;
1671 let pct = rem_len / l;
1674 if pct <= 1e-14 {
1675 write!(f, "\\pgfsetarrowsstart{{{}}}\n\
1676 \\pgfpathmoveto{{\\pgfpointxy
1677 {{{:.16}}}{{{:.16}}}}}\n\
1678 \\pgfpathlineto{{\\pgfpointxy\
1679 {{{:.16}}}{{{:.16}}}}}\n\
1680 \\pgfusepath{{stroke}}\n\
1681 \\pgfsetarrowsend{{}}\n\
1682 \\pgfpathmoveto{{\\pgfpointxy\
1683 {{{:.16}}}{{{:.16}}}}}\n",
1684 arrow, x0, y0, x, y, x, y)?;
1685 } else {
1686 let xm = x0 + pct * dx;
1687 let ym = y0 + pct * dy;
1688 write!(f, "\\pgfsetarrowsend{{{}}}\n\
1689 \\pgfpathmoveto{{\\pgfpointxy\
1690 {{{:.16}}}{{{:.16}}}}}\n\
1691 \\pgfpathlineto{{\\pgfpointxy\
1692 {{{:.16}}}{{{:.16}}}}}\n\
1693 \\pgfusepath{{stroke}}\n\
1694 \\pgfsetarrowsend{{}}\n\
1695 \\pgfpathmoveto{{\\pgfpointxy\
1696 {{{:.16}}}{{{:.16}}}}}\n\
1697 \\pgfpathlineto{{\\pgfpointxy\
1698 {{{:.16}}}{{{:.16}}}}}\n",
1699 arrow, x0, y0, xm, ym, xm, ym, x, y)?;
1700 n = 2;
1701 }
1702 rem_len = f64::INFINITY; } else if n >= self.n {
1704 write!(f, "\\pgfpathlineto{{\\pgfpointxy\
1705 {{{:.16}}}{{{:.16}}}}}\n\
1706 \\pgfusepath{{stroke}}\n\
1707 \\pgfpathmoveto{{\\pgfpointxy\
1708 {{{:.16}}}{{{:.16}}}}}\n", x, y, x, y)?;
1709 n = 0;
1710 } else {
1711 writeln!(f, "\\pgfpathlineto{{\\pgfpointxy\
1712 {{{:.16}}}{{{:.16}}}}}", x, y)?
1713 }
1714 rem_len -= l;
1715 } else {
1716 writeln!(f, "\\pgfpathmoveto{{\\pgfpointxy\
1718 {{{:.16}}}{{{:.16}}}}}", x, y)?
1719 }
1720 prev_pt = Some(p);
1721 }
1722 }
1723 Ok(())
1724 }
1725
1726 pub fn write(&self, f: &mut impl Write) -> Result<(), io::Error> {
1728 writeln!(f, "% Written by the Rust curve-sampling crate.")?;
1729 writeln!(f, "\\begin{{pgfscope}}")?;
1730 if let Some(RGB8 {r, g, b}) = self.color {
1731 write!(f, "\\definecolor{{RustCurveSamplingColor}}{{RGB}}\
1732 {{{},{},{}}}\n\
1733 \\pgfsetstrokecolor{{RustCurveSamplingColor}}\n",
1734 r, g, b)?
1735 }
1736 match (self.arrow, self.arrow_pos) {
1737 (None, None) => self.write_with_lines(f)?,
1738 (Some(arrow), None) =>
1739 self.write_with_arrows(f, arrow, 0.5)?,
1740 (None, Some(arrow_pos)) =>
1741 self.write_with_arrows(f, ">",arrow_pos)?,
1742 (Some(arrow), Some(arrow_pos)) =>
1743 self.write_with_arrows(f, arrow, arrow_pos)?,
1744 }
1745 write!(f, "\\pgfusepath{{stroke}}\n\\end{{pgfscope}}\n")
1746 }
1747}
1748
1749impl<D> Sampling<D> {
1751 pub fn latex(&self) -> LaTeX<'_, D> { LaTeX::new(self) }
1753
1754 pub fn write(&self, f: &mut impl Write) -> Result<(), io::Error> {
1759 for [x, y] in self.iter() {
1760 if x.is_nan() {
1761 writeln!(f)?
1762 } else {
1763 writeln!(f, "{:e} {:e}", x, y)?
1764 }
1765 }
1766 Ok(())
1767 }
1768}
1769
1770impl<D> Display for Sampling<D> {
1771 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
1776 for [x, y] in self.iter() {
1777 if x.is_nan() {
1778 writeln!(f)?
1779 } else {
1780 writeln!(f, "{:e} {:e}", x, y)?
1781 }
1782 }
1783 Ok(())
1784 }
1785}
1786
1787#[cfg(test)]
1792mod tests {
1793 use std::{error::Error,
1794 fs::File,
1795 io::Write, path::Path};
1796 use crate::{BoundingBox, Data, NoData, Point, Sampling};
1797
1798 type R<T> = Result<T, Box<dyn Error>>;
1799
1800 fn xy_of_sampling<D>(s: &Sampling<D>) -> Vec<Option<(f64, f64)>> {
1801 s.path.iter().map(|p| {
1802 if p.is_valid() { Some((p.xy[0], p.xy[1])) } else { None }
1803 })
1804 .collect()
1805 }
1806
1807 #[test]
1808 fn clone_sampling() {
1809 let s = Sampling::from_iter([[0.,0.], [1.,1.]]);
1810 let xy0: Vec<_> = s.iter().collect();
1811 let xy1: Vec<_> = s.clone().iter().collect();
1812 assert_eq!(xy0, xy1)
1813 }
1814
1815 #[test]
1816 fn io() {
1817 let s = Sampling::from_iter([[0.,0.], [1.,1.]]);
1818 assert_eq!(xy_of_sampling(&s), vec![Some((0.,0.)), Some((1.,1.))]);
1819 let s = Sampling::from_iter([[0.,0.], [1.,1.], [f64::NAN, 1.],
1820 [2.,2.]]);
1821 assert_eq!(xy_of_sampling(&s),
1822 vec![Some((0.,0.)), Some((1.,1.)), None, Some((2.,2.))]);
1823 }
1824
1825 #[test]
1826 fn bounding_box_singleton() {
1827 let s = Sampling::singleton(
1828 Point::new_unchecked(0., [1., 2.], NoData::new()));
1829 let bb = BoundingBox {xmin: 1., xmax: 1., ymin: 2., ymax: 2.};
1830 assert_eq!(s.bounding_box(), bb);
1831 }
1832
1833 fn test_clip(bb: BoundingBox,
1834 path: Vec<[f64;2]>,
1835 expected: Vec<Option<(f64,f64)>>) {
1836 let s = Sampling::from_iter(path).clip(bb);
1837 assert_eq!(xy_of_sampling(&s), expected);
1838 }
1839
1840 #[test]
1841 fn clip_base () {
1842 let bb = BoundingBox { xmin: 0., xmax: 3., ymin: 0., ymax: 2.};
1843 test_clip(bb, vec![[0.,1.], [2.,3.]],
1844 vec![Some((0.,1.)), Some((1.,2.))]);
1845 test_clip(bb,
1846 vec![[-1.,0.], [2.,3.], [4.,1.]],
1847 vec![Some((0.,1.)), Some((1.,2.)), None, Some((3., 2.))]);
1848 test_clip(bb,
1849 vec![[0.,1.], [2.,3.], [4.,1.], [2.,1.], [2., -1.],
1850 [0., -1.], [0., 1.] ],
1851 vec![Some((0.,1.)), Some((1.,2.)), None,
1852 Some((3., 2.)), None,
1853 Some((3., 1.)), Some((2., 1.)), Some((2., 0.)), None,
1854 Some((0., 0.)), Some((0., 1.))]);
1855 }
1856
1857 #[test]
1858 fn clip_empty() {
1859 let bb = BoundingBox {xmin: 0., xmax: 1., ymin: 0., ymax: 1.};
1860 let path = xy_of_sampling(&Sampling::<()>::empty().clip(bb));
1861 assert_eq!(path, vec![]);
1862 }
1863
1864 #[test]
1865 fn clip_double_cut() {
1866 let bb = BoundingBox { xmin: 0., xmax: 4., ymin: 0., ymax: 2.};
1867 test_clip(bb,
1868 vec![[1., 2.], [2.,3.], [5.,0.], [-1., 0.] ],
1869 vec![Some((1., 2.)), None,
1870 Some((3., 2.)), Some((4., 1.)), None,
1871 Some((4., 0.)), Some((0., 0.)) ]);
1872 }
1873
1874 #[test]
1875 fn clip_almost_horiz() {
1876 let bb = BoundingBox { xmin: 0., xmax: 2., ymin: -1., ymax: 1.};
1877 test_clip(bb,
1878 vec![[1., 1e-100], [3., -1e-100] ],
1879 vec![Some((1., 1e-100)), Some((2., 0.))]);
1880 }
1881
1882 #[test]
1883 fn clip_touches_1pt_cut() {
1884 let bb = BoundingBox {xmin: 0., xmax: 2., ymax: 0., ymin: -1.};
1885 let cut = [f64::NAN, f64::NAN];
1886 test_clip(bb,
1887 vec![[0.,1.], cut, [1., 0.], cut, cut, [2., 1.]],
1888 vec![Some((1., 0.))])
1889 }
1890
1891 #[test]
1892 fn clip_final_cut() {
1893 let bb = BoundingBox {xmin: 0., xmax: 1., ymin: 0., ymax: 2.};
1894 test_clip(bb,
1895 vec![[0., 0.], [2., 2.]],
1896 vec![Some((0., 0.)), Some((1., 1.))])
1897 }
1898
1899 #[test]
1900 fn uniform1() {
1901 let s = Sampling::uniform(|x| x, 0., 4.).n(3)
1902 .init(&[1.]).init_pt([(3., 0.)]).build();
1903 assert_eq!(xy_of_sampling(&s),
1904 vec![Some((0.,0.)), Some((1.,1.)), Some((2.,2.)),
1905 Some((3., 0.)), Some((4.,4.))]);
1906 }
1907
1908 #[test]
1909 fn uniform2() {
1910 let s = Sampling::uniform(|x| (4. - x).sqrt(), 0., 6.).n(4).build();
1911 assert_eq!(xy_of_sampling(&s),
1912 vec![Some((0.,2.)), Some((2., 2f64.sqrt())),
1913 Some((4., 0.)), None]);
1914 }
1915
1916 #[test]
1917 fn iter_data() {
1918 let s = Sampling::uniform(|x| (x, Data(x as i32)), 0., 4.).n(3)
1919 .init(&[1.]).init_pt([(3., (0., Data(-1)))]).build();
1920 let expected = vec![
1921 ([0.,0.], &0), ([1.,1.], &1), ([2.,2.], &2), ([3., 0.], &-1),
1922 ([4.,4.], &4)];
1923 let (_, size_hint) = s.iter_data().size_hint();
1924 assert_eq!(size_hint, Some(expected.len()));
1925 for (i, d) in s.iter_data().enumerate() {
1926 assert_eq!(d, expected[i]);
1927 }
1928 }
1929
1930 #[test]
1931 fn into_iter_data() {
1932 let s = Sampling::uniform(|x| (x, Data(x as i32)), 0., 4.).n(3)
1933 .init(&[1.]).init_pt([(3., (0., Data(-1)))]).build();
1934 let expected = vec![
1935 ([0.,0.], 0), ([1.,1.], 1), ([2.,2.], 2), ([3., 0.], -1),
1936 ([4.,4.], 4)];
1937 let (_, size_hint) = s.iter_data().size_hint();
1938 assert_eq!(size_hint, Some(expected.len()));
1939 for (i, d) in s.into_iter_data().enumerate() {
1940 assert_eq!(d, expected[i]);
1941 }
1942 }
1943
1944 fn write_with_point_costs<D>(
1947 s: &Sampling<D>,
1948 fname: impl AsRef<Path>
1949 ) -> R<()> {
1950 let mut fh = File::create(fname)?;
1951 for p in s.path.iter() {
1952 if p.is_valid() {
1953 let [x, y] = p.xy;
1954 writeln!(fh, "{x} {y} {}", p.cost)?;
1955 } else {
1956 writeln!(fh)?;
1957 }
1958 }
1959 Ok(())
1960 }
1961
1962 fn write_segments<D>(mut s: Sampling<D>, fname: impl AsRef<Path>) -> R<()> {
1963 let mut fh = File::create(fname)?;
1964 let mut seg = vec![];
1965 loop {
1966 let priority = s.pq.max_priority();
1967 if let Some(p0) = s.pq.pop() {
1968 let p1 = unsafe { s.path.next(&p0).unwrap() };
1969 let p1 = unsafe { s.path.get(&p1) };
1970 let p0 = unsafe { s.path.get(&p0) };
1971 let tm = (p0.t + p1.t) / 2.;
1972 seg.push((tm, p0.coord(), p1.coord(), priority))
1973 } else {
1974 break;
1975 }
1976 }
1977 seg.sort_by(|(t1,_,_,_), (t2,_,_,_)| t1.partial_cmp(t2).unwrap());
1978 for (tm, p0, p1, priority) in seg {
1979 writeln!(fh, "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
1980 tm, p0.t, p0.xy[0], p0.xy[1],
1981 p1.t, p1.xy[0], p1.xy[1], priority)?;
1982 }
1983 Ok(())
1984 }
1985
1986 #[derive(Clone)]
1987 struct Plot {
1988 xmin: f64, xmax: f64,
1989 ymin: f64, ymax: f64,
1990 n: usize,
1991 init: Vec<f64>,
1992 }
1993
1994 impl Plot {
1995 fn plot<F>(&self, f: F, title: &str) -> R<String>
1997 where F: FnMut(f64) -> f64 {
1998 let vp = BoundingBox { xmin: self.xmin, xmax: self.xmax,
1999 ymin: self.ymin, ymax: self.ymax };
2000 let s = Sampling::fun(f, self.xmin, self.xmax)
2001 .n(self.n).init(self.init.iter()).viewport(vp).build();
2002 static mut NDAT: usize = 0;
2003 let ndat = unsafe { NDAT += 1; NDAT };
2004 println!("Horror {ndat}");
2005 s.pq.print_stats();
2006 let dir = Path::new("target");
2007 let fname = format!("horror{}.dat", ndat);
2008 s.write(&mut File::create(dir.join(&fname))?)?;
2009 let fname_p = format!("horror{}_p.dat", ndat);
2010 write_with_point_costs(&s, dir.join(&fname_p))?;
2011 let fname_s = format!("horror{}_s.dat", ndat);
2012 write_segments(s, dir.join(&fname_s))?;
2013 Ok(format!(
2014 "unset title\n\
2015 unset y2tics\n\
2016 plot [{}:{}] \"{}\" with l lt 5 title \"{}\", \
2017 \"{}\" with p lt 3 pt 6 ps 0.2 title \"n={}\"\n\
2018 set title \"#{ndat} Restricted to viewport [{}:{}]×[{}:{}]\"\n\
2019 set y2tics\n\
2020 set y2range [-1e-6:]\n\
2021 plot [{}:{}] [{}:{}] \"{}\" with l lt 5 title \"{}\", \
2022 \"{}\" with p lt 3 pt 7 ps 0.2 title \"n={}\", \
2023 \"{}\" using 1:3 with lp ps 0.2 lt rgb \"#760b0b\" \
2024 title \"cost points\", \
2025 \"{}\" using 1:8 with lp ps 0.2 lt rgb \"#909090\" \
2026 axes x1y2 title \"cost segments\"\n",
2027 self.xmin, self.xmax, &fname, title, &fname, self.n,
2028 self.xmin, self.xmax, self.ymin, self.ymax,
2029 self.xmin, self.xmax, self.ymin, self.ymax, &fname, title,
2030 &fname, self.n, &fname_p, &fname_s))
2031 }
2032 }
2033
2034 #[test]
2035 #[cfg_attr(miri, ignore)] fn horror() -> R<()> {
2037 let d = Plot {
2038 xmin: -5., xmax: 5., ymin: -5., ymax: 5., n: 100, init: vec![] };
2039 macro_rules! p {
2040 ($($id:ident $l:tt $e:expr),*) => {
2041 Plot{ $($id: $e,)* ..d.clone() } };
2042 }
2043 let s = [
2044 p!(n: 10).plot(|_| 2., "x ↦ 2")?,
2045 p!().plot(|x| x, "x ↦ x")?,
2046 p!().plot(|x| 5. * x, "x ↦ 5x")?,
2047 p!().plot(|x| 1e6 * x, "x ↦ 10⁶ x")?, p!().plot(|x| 1e50 * x, "x ↦ 10⁵⁰ x")?, p!().plot(|x| 1. / x, "x ↦ 1/x")?, p!(xmin: 0., xmax: 5., ymax: 100.).plot(
2051 |x| 1. / x, "x ↦ 1/x")?, p!(xmin: -0.4, xmax: 2., ymin: 0., ymax: 1.6, n: 50).plot(
2053 |x| x.sqrt(), "x ↦ √x")?,
2054 p!(xmin: -2., xmax: 1., ymin: 0., ymax: 1.6, n: 50).plot(
2056 |x| (-x).sqrt(), "x ↦ √(-x)")?,
2057 p!(n: 200).plot(|x| x.tan(), "tan")?,
2058 p!().plot(|x| 1. / x.abs(), "x ↦ 1/|x|")?,
2059 p!(xmin: -6., xmax: 6., ymin: -2., ymax: 2.).plot(
2060 |x| (1. + x.cos().sin()).ln(), "1 + sin(cos x)")?,
2061 p!(xmin: 0., xmax: 6.28, ymin: -1.5, ymax: 1.5, n: 400).plot(
2062 |x| x.powi(3).sin() + x.powi(3).cos(), "sin x³ + cos x³")?,
2063 p!(xmin: -5., xmax:200., ymin: -1., ymax: 1., n: 400).plot(
2064 |x| x.sin(), "sin")?,
2065 p!(xmin: -4., xmax: 4., ymin: -1., ymax: 1.).plot(
2069 |x| (300. * x).sin(), "sin(300 x)")?,
2070 p!(xmin: -4., xmax: 4., ymin: -1., ymax: 1., n: 1000).plot(
2071 |x| (300. * x).sin(), "sin(300 x)")?,
2072 p!(xmin: -2., xmax: 2., ymin: 0., ymax: 3.).plot(
2073 |x| 1. + x * x + 0.0125 * (1. - 3. * (x - 1.)).abs().ln(),
2074 "1 + x² + 0.0125 ln|1 - 3(x-1)|")?,
2075 p!(xmin: -2., xmax: 2., ymin: 0., ymax: 3., n: 300,
2076 init:vec![4. / 3.]).plot(
2077 |x| 1. + x * x + 0.0125 * (1. - 3. * (x - 1.)).abs().ln(),
2078 "1 + x² + 0.0125 ln|1 - 3(x-1)| (specifying x:4/3")?,
2079 p!(xmin: -0.5, xmax: 0.5, ymin: -1., ymax: 1.).plot(
2080 |x| x * (1. / x).sin(), "x sin(1/x)")?,
2081 p!(xmin: -0.5, xmax: 0.5, ymin: -1., ymax: 1., n:200).plot(
2082 |x| x * (1. / x).sin(), "x sin(1/x)")?,
2083 p!(xmin: -2., xmax: 2., ymin: -1., ymax: 1.).plot(
2084 |x| (1. / x).sin(), "sin(1/x)")?,
2085 p!(xmin: -2., xmax: 2., ymin: -1., ymax: 1., n: 400).plot(
2086 |x| (1. / x).sin(), "sin(1/x)")?,
2087 p!(xmin: -4., xmax: 4., ymin: -1., ymax: 1.).plot(
2088 |x| x.powi(4).sin(), "sin(x⁴)")?,
2089 p!(xmin: -4., xmax: 4., ymin: -1., ymax: 1., n: 600).plot(
2090 |x| x.powi(4).sin(), "sin(x⁴)")?,
2091 p!(xmin: -6., xmax: 6., ymin: -1., ymax: 1.).plot(
2092 |x| x.exp().sin(), "sin(exp x)")?,
2093 p!(xmin: -6., xmax: 6., ymin: -1., ymax: 1., n: 500).plot(
2094 |x| x.exp().sin(), "sin(exp x)")?,
2095 p!(xmin: -10., xmax: 10., ymin: 0., ymax: 10.).plot(
2096 |x| 1. / x.sin(), "1 / sin x")?,
2097 p!(xmin: -6., xmax: 6., ymin: -1., ymax: 1.).plot(
2098 |x| x.sin() / x, "(sin x)/x")?,
2099 p!(xmin: -2., xmax: 2., ymin: -15., ymax: 15.).plot(
2100 |x| (x.powi(3) - x + 1.).tan() + 1. / (x + 3. * x.exp()),
2101 "tan(x³ - x + 1) + 1/(x + 3 eˣ)")?,
2102 p!(xmin: 0., xmax: 17., ymin: 0., ymax: 2.).plot(
2103 |x| (1. + x.cos()) * (-0.1 * x).exp(),
2104 "(1 + cos x) exp(-x/10)")?,
2105 p!(xmin: -2., xmax: 17., ymin: 0., ymax: 2.).plot(
2106 |x| (1. + x.cos()) * (-0.1 * x).exp(),
2107 "(1 + cos x) exp(-x/10)")?,
2108 p!(xmin: 0., xmax: 17., ymin: 0., ymax: 2.).plot(
2109 |x| (1. + x.cos()) * (-0.01 * x * x).exp(),
2110 "(1 + cos x) exp(-x²/100)")?,
2111 ].join("");
2112 let mut fh = File::create("target/horror.gp")?;
2113 write!(fh, "set terminal pdfcairo\n\
2114 set output \"horror.pdf\"\n\
2115 set grid\n\
2116 {}\n", s)?;
2117 Ok(())
2118 }
2119
2120
2121}