fj_kernel/algorithms/approx/
cycle.rs

1//! Cycle approximation
2//!
3//! See [`CycleApprox`].
4
5use std::ops::Deref;
6
7use fj_math::Segment;
8
9use crate::objects::{Cycle, Surface};
10
11use super::{
12    edge::{EdgeCache, HalfEdgeApprox},
13    Approx, ApproxPoint, Tolerance,
14};
15
16impl Approx for (&Cycle, &Surface) {
17    type Approximation = CycleApprox;
18    type Cache = EdgeCache;
19
20    fn approx_with_cache(
21        self,
22        tolerance: impl Into<Tolerance>,
23        cache: &mut Self::Cache,
24    ) -> Self::Approximation {
25        let (cycle, surface) = self;
26        let tolerance = tolerance.into();
27
28        let half_edges = cycle
29            .half_edges()
30            .map(|half_edge| {
31                (half_edge.deref(), surface).approx_with_cache(tolerance, cache)
32            })
33            .collect();
34
35        CycleApprox { half_edges }
36    }
37}
38
39/// An approximation of a [`Cycle`]
40#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
41pub struct CycleApprox {
42    /// The approximated edges that make up the approximated cycle
43    pub half_edges: Vec<HalfEdgeApprox>,
44}
45
46impl CycleApprox {
47    /// Compute the points that approximate the cycle
48    pub fn points(&self) -> Vec<ApproxPoint<2>> {
49        let mut points = Vec::new();
50
51        for approx in &self.half_edges {
52            points.extend(approx.points());
53        }
54
55        if let Some(point) = points.first() {
56            points.push(point.clone());
57        }
58
59        points
60    }
61
62    /// Construct the segments that approximate the cycle
63    pub fn segments(&self) -> Vec<Segment<3>> {
64        let mut segments = Vec::new();
65
66        for segment in self.points().windows(2) {
67            // This can't panic, as we passed `2` to `windows`. Can be cleaned
68            // up, once `array_windows` is stable.
69            let segment = [&segment[0], &segment[1]];
70
71            segments
72                .push(Segment::from(segment.map(|point| point.global_form)));
73        }
74
75        segments
76    }
77}