pub use super::*; #[derive(Clone, Copy, Debug)] struct SegmentPoint { input: RadianPoint, cartesian: Cartesian, projected: ProjectedPoint, } impl SegmentPoint { fn new

(projection: P, input: RadianPoint) -> Self where P: Projection, { SegmentPoint { input, cartesian: input.into(), projected: projection.project(input), } } } fn resample_segment(sink: &mut S, projection: &P, from: SegmentPoint, to: SegmentPoint, stroke: bool, recursion_limit: u32, resolution: f32) where P: Projection, S: DrawPath, { let cos_min_distance = 30.0f32.to_radians().cos(); let dx = to.projected.x - from.projected.x; let dy = to.projected.y - from.projected.y; let dist_square = dx*dx + dy*dy; if dist_square > (4.0 * resolution) && recursion_limit > 1 { let mid_cartesian = { // normalize mid point between from and to (onto sphere) let s = from.cartesian + to.cartesian; // normalizing anyway, drop `*0.5` s / (s * s).sqrt() }; let mid_lambda = if (mid_cartesian.c.abs() - 1.0).abs() < F32_PRECISION || (from.input.lambda - to.input.lambda).abs() < F32_PRECISION { // close to poles (a and b will be near zero, atan2 would fail) // or from/to lambdas close together (atan2 should work though in this case, but it would convert -pi to pi) (from.input.lambda + to.input.lambda) / 2.0 } else { f32::atan2(mid_cartesian.b, mid_cartesian.a) }; let mid_input = RadianPoint { phi: mid_cartesian.c.asin(), lambda: mid_lambda, }; let mid = SegmentPoint { input: mid_input, cartesian: mid_cartesian, projected: projection.project(mid_input), }; let dx2 = mid.projected.x - from.projected.x; let dy2 = mid.projected.y - from.projected.y; // (dy, -dx): orthogonal vector to (dx, dy) // norm(dy, -dx) * (dx2, dy2): (projected) distance of mid from line between from and to let mid_line_dist_square = { let d = dy*dx2 - dx*dy2; (d * d) / dist_square }; // norm(dx, dy) * (dx2, dy2): (projected) "progress" of mid *on* the line between from and to // let mid_progress = (dx*dx2 + dy*dy2) / dist_square; if mid_line_dist_square > resolution // perpendicular projected distance // /* this is broken and probably not needed */ || (mid_progress - 0.5).abs() > 0.3 // midpoint close to an end || (to.cartesian * from.cartesian) < cos_min_distance // angular distance { resample_segment(sink, projection, from, mid, stroke, recursion_limit - 1, resolution); sink.line(mid.projected, stroke); resample_segment(sink, projection, mid, to, stroke, recursion_limit - 1, resolution); } } } pub struct ResamplePath { projection: P, sink: S, resolution: f32, recursion_limit: u32, start_prev: Option<(bool, SegmentPoint, SegmentPoint)>, } impl> ResamplePath { pub fn new(projection: P, sink: S, resolution: f32) -> Self { Self { projection, sink, resolution, recursion_limit: 16, start_prev: None, } } } impl> PathTransformer for ResamplePath { type Sink = S; type Point = RadianPoint; fn sink(&mut self) -> &mut Self::Sink { &mut self.sink } fn transform_line(&mut self, to: Self::Point, stroke: bool) { let to = SegmentPoint::new(&self.projection, to); if let Some((_init_stroke, _start, prev)) = &mut self.start_prev { resample_segment(&mut self.sink, &self.projection, *prev, to, stroke, self.recursion_limit, self.resolution); self.sink.line(to.projected, stroke); *prev = to; } else { self.sink.line(to.projected, stroke); self.start_prev = Some((stroke, to, to)); } } fn transform_ring_end(&mut self) { if let Some((init_stroke, start, prev)) = self.start_prev.take() { resample_segment(&mut self.sink, &self.projection, prev, start, init_stroke, self.recursion_limit, self.resolution); } self.sink().ring_end(); } fn transform_path_end(&mut self) { self.start_prev = None; self.sink().path_end(); } }