diff --git a/crates/fj-kernel/src/algorithms/approx/curve.rs b/crates/fj-kernel/src/algorithms/approx/curve.rs index a77cf749a..ba4169ffa 100644 --- a/crates/fj-kernel/src/algorithms/approx/curve.rs +++ b/crates/fj-kernel/src/algorithms/approx/curve.rs @@ -83,6 +83,10 @@ fn approx_circle( points.push(ApproxPoint::new(point_curve, point_global)); } + if range.is_reversed() { + points.reverse(); + } + points } @@ -102,12 +106,40 @@ fn number_of_vertices_for_circle( #[derive(Clone, Copy, Debug)] pub struct RangeOnCurve { boundary: [Vertex; 2], + is_reversed: bool, } impl RangeOnCurve { /// Construct an instance of `RangeOnCurve` - pub fn new(boundary: [Vertex; 2]) -> Self { - Self { boundary } + /// + /// Ranges are normalized on construction, meaning that the order of + /// vertices passed to this constructor does not influence the range that is + /// constructed. + /// + /// This is done to prevent bugs during mesh construction: The curve + /// approximation code is regularly faced with ranges that are reversed + /// versions of each other. This can lead to slightly different + /// approximations, which in turn leads to the aforementioned invalid + /// meshes. + /// + /// The caller can use `is_reversed` to determine, if the range was reversed + /// during normalization, to adjust the approximation accordingly. + pub fn new([a, b]: [Vertex; 2]) -> Self { + let (boundary, is_reversed) = if a < b { + ([a, b], false) + } else { + ([b, a], true) + }; + + Self { + boundary, + is_reversed, + } + } + + /// Indicate whether the range was reversed during normalization + pub fn is_reversed(&self) -> bool { + self.is_reversed } /// Access the start of the range