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
use fj_math::{Circle, Line, Point, Vector};

use crate::{
    local::Local,
    objects::{Curve, Cycle, CyclesInFace, Edge, Face},
};

/// Reverse the direction of a face
pub fn reverse_face(face: &Face) -> Face {
    let face = match face {
        Face::Face(face) => face,
        Face::Triangles(_) => {
            panic!("Reversing tri-rep faces is not supported")
        }
    };

    let surface = face.surface().reverse();

    let exteriors = reverse_local_coordinates_in_cycle(&face.exteriors);
    let interiors = reverse_local_coordinates_in_cycle(&face.interiors);

    Face::new(surface, exteriors, interiors, face.color)
}

fn reverse_local_coordinates_in_cycle(
    cycles: &CyclesInFace,
) -> impl Iterator<Item = Cycle> + '_ {
    let cycles = cycles.as_local().map(|cycle| {
        let edges = cycle
            .edges
            .iter()
            .map(|edge| {
                let curve = {
                    let local = match edge.curve.local() {
                        Curve::Circle(Circle { center, a, b }) => {
                            let center = Point::from([center.u, -center.v]);

                            let a = Vector::from([a.u, -a.v]);
                            let b = Vector::from([b.u, -b.v]);

                            Curve::Circle(Circle { center, a, b })
                        }
                        Curve::Line(Line { origin, direction }) => {
                            let origin = Point::from([origin.u, -origin.v]);
                            let direction =
                                Vector::from([direction.u, -direction.v]);

                            Curve::Line(Line { origin, direction })
                        }
                    };

                    Local::new(local, edge.curve.global())
                };
                let vertices = edge.vertices.clone();

                Edge { curve, vertices }
            })
            .collect();

        Cycle { edges }
    });

    cycles
}

#[cfg(test)]
mod tests {
    use pretty_assertions::assert_eq;

    use crate::objects::{Face, Surface};

    #[test]
    fn reverse_face() {
        let original = Face::builder(Surface::xy_plane())
            .with_exterior_polygon([[0., 0.], [1., 0.], [0., 1.]])
            .build();

        let reversed = super::reverse_face(&original);

        let expected = Face::builder(Surface::xy_plane().reverse())
            .with_exterior_polygon([[0., 0.], [1., 0.], [0., -1.]])
            .build();

        assert_eq!(expected, reversed);
    }
}