1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
use crate::scalar::Scalar;
use crate::{point, Box2D, LineSegment, Point, Vector};

use core::ops::Range;

/// Common APIs to segment types.
pub trait Segment: Copy + Sized {
    type Scalar: Scalar;

    /// Start of the curve.
    fn from(&self) -> Point<Self::Scalar>;

    /// End of the curve.
    fn to(&self) -> Point<Self::Scalar>;

    /// Sample the curve at t (expecting t between 0 and 1).
    fn sample(&self, t: Self::Scalar) -> Point<Self::Scalar>;

    /// Sample x at t (expecting t between 0 and 1).
    fn x(&self, t: Self::Scalar) -> Self::Scalar {
        self.sample(t).x
    }

    /// Sample y at t (expecting t between 0 and 1).
    fn y(&self, t: Self::Scalar) -> Self::Scalar {
        self.sample(t).y
    }

    /// Sample the derivative at t (expecting t between 0 and 1).
    fn derivative(&self, t: Self::Scalar) -> Vector<Self::Scalar>;

    /// Sample x derivative at t (expecting t between 0 and 1).
    fn dx(&self, t: Self::Scalar) -> Self::Scalar {
        self.derivative(t).x
    }

    /// Sample y derivative at t (expecting t between 0 and 1).
    fn dy(&self, t: Self::Scalar) -> Self::Scalar {
        self.derivative(t).y
    }

    /// Split this curve into two sub-curves.
    fn split(&self, t: Self::Scalar) -> (Self, Self);

    /// Return the curve before the split point.
    fn before_split(&self, t: Self::Scalar) -> Self;

    /// Return the curve after the split point.
    fn after_split(&self, t: Self::Scalar) -> Self;

    /// Return the curve inside a given range of t.
    ///
    /// This is equivalent splitting at the range's end points.
    fn split_range(&self, t_range: Range<Self::Scalar>) -> Self;

    /// Swap the direction of the segment.
    fn flip(&self) -> Self;

    /// Compute the length of the segment using a flattened approximation.
    fn approximate_length(&self, tolerance: Self::Scalar) -> Self::Scalar;

    /// Approximates the curve with sequence of line segments.
    ///
    /// The `tolerance` parameter defines the maximum distance between the curve and
    /// its approximation.
    ///
    /// The parameter `t` at the final segment is guaranteed to be equal to `1.0`.
    #[allow(clippy::type_complexity)]
    fn for_each_flattened_with_t(
        &self,
        tolerance: Self::Scalar,
        callback: &mut dyn FnMut(&LineSegment<Self::Scalar>, Range<Self::Scalar>),
    );
}

pub trait BoundingBox {
    type Scalar: Scalar;

    /// Returns the smallest rectangle that contains the curve.
    fn bounding_box(&self) -> Box2D<Self::Scalar> {
        let (min_x, max_x) = self.bounding_range_x();
        let (min_y, max_y) = self.bounding_range_y();

        Box2D {
            min: point(min_x, min_y),
            max: point(max_x, max_y),
        }
    }

    /// Returns a conservative rectangle that contains the curve.
    ///
    /// This does not necessarily return the smallest possible bounding rectangle.
    fn fast_bounding_box(&self) -> Box2D<Self::Scalar> {
        let (min_x, max_x) = self.fast_bounding_range_x();
        let (min_y, max_y) = self.fast_bounding_range_y();

        Box2D {
            min: point(min_x, min_y),
            max: point(max_x, max_y),
        }
    }

    /// Returns a range of x values that contains the curve.
    fn bounding_range_x(&self) -> (Self::Scalar, Self::Scalar);

    /// Returns a range of y values that contains the curve.
    fn bounding_range_y(&self) -> (Self::Scalar, Self::Scalar);

    /// Returns a range of x values that contains the curve.
    fn fast_bounding_range_x(&self) -> (Self::Scalar, Self::Scalar);

    /// Returns a range of y values that contains the curve.
    fn fast_bounding_range_y(&self) -> (Self::Scalar, Self::Scalar);
}

macro_rules! impl_segment {
    ($S:ty) => {
        type Scalar = $S;
        fn from(&self) -> Point<$S> {
            self.from()
        }
        fn to(&self) -> Point<$S> {
            self.to()
        }
        fn sample(&self, t: $S) -> Point<$S> {
            self.sample(t)
        }
        fn x(&self, t: $S) -> $S {
            self.x(t)
        }
        fn y(&self, t: $S) -> $S {
            self.y(t)
        }
        fn derivative(&self, t: $S) -> Vector<$S> {
            self.derivative(t)
        }
        fn dx(&self, t: $S) -> $S {
            self.dx(t)
        }
        fn dy(&self, t: $S) -> $S {
            self.dy(t)
        }
        fn split(&self, t: $S) -> (Self, Self) {
            self.split(t)
        }
        fn before_split(&self, t: $S) -> Self {
            self.before_split(t)
        }
        fn after_split(&self, t: $S) -> Self {
            self.after_split(t)
        }
        fn split_range(&self, t_range: Range<$S>) -> Self {
            self.split_range(t_range)
        }
        fn flip(&self) -> Self {
            self.flip()
        }
        fn approximate_length(&self, tolerance: $S) -> $S {
            self.approximate_length(tolerance)
        }
    };
}