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
use std::{array, borrow::Borrow};

use fj_interop::ext::ArrayExt;
use fj_math::Point;

use crate::{
    objects::{Cycle, Face, HalfEdge, Region, Surface, Vertex},
    operations::{
        build::{BuildCycle, BuildRegion, BuildSurface},
        insert::{Insert, IsInserted, IsInsertedNo},
    },
    services::Services,
    storage::Handle,
};

/// Build a [`Face`]
///
/// See [module-level documentation] for context.
///
/// [module-level documentation]: super
pub trait BuildFace {
    /// Build a face with an empty exterior, no interiors, and no color
    fn unbound(surface: Handle<Surface>, services: &mut Services) -> Face {
        let exterior = Cycle::empty().insert(services);
        let region = Region::new(exterior, [], None).insert(services);
        Face::new(surface, region)
    }

    /// Build a triangle
    fn triangle(
        points: [impl Into<Point<3>>; 3],
        services: &mut Services,
    ) -> Polygon<3> {
        let (surface, points_surface) = Surface::plane_from_points(points);
        let surface = surface.insert(services);

        let face = Face::polygon(surface, points_surface, services);

        let half_edges = {
            let mut edges =
                face.region().exterior().half_edges().iter().cloned();

            let array = array::from_fn(|_| edges.next()).map(|edge| {
                edge.expect("Just asserted that there are three edges")
            });

            assert!(edges.next().is_none());

            array
        };
        let vertices = half_edges
            .each_ref_ext()
            .map(|edge: &Handle<HalfEdge>| edge.start_vertex().clone());

        Polygon {
            face,
            half_edges,
            vertices,
        }
    }

    /// Build a polygon
    fn polygon<P, Ps>(
        surface: Handle<Surface>,
        points: Ps,
        services: &mut Services,
    ) -> Face
    where
        P: Into<Point<2>>,
        Ps: IntoIterator<Item = P>,
        Ps::IntoIter: Clone + ExactSizeIterator,
    {
        let region = Region::polygon(points, services).insert(services);
        Face::new(surface, region)
    }
}

impl BuildFace for Face {}

/// A polygon
///
/// # Implementation Note
///
/// Currently code that deals with `Polygon` might assume that the polygon has
/// no holes. Unless you create a `Polygon` yourself, or modify a `Polygon`'s
/// `face` field to have interior cycles, this should not affect you.
pub struct Polygon<const D: usize, I: IsInserted = IsInsertedNo> {
    /// The face that forms the polygon
    pub face: I::T<Face>,

    /// The half-edges of the polygon
    pub half_edges: [Handle<HalfEdge>; D],

    /// The vertices of the polygon
    pub vertices: [Handle<Vertex>; D],
}

impl<const D: usize, I: IsInserted> Polygon<D, I> {
    /// Replace the face of the polygon
    ///
    /// Returns a new instance of `Polygon` with the replaced face. Also updates
    /// the other fields of `Polygon` to match the new face.
    pub fn replace_face(&self, face: I::T<Face>) -> Self {
        let half_edges = array::from_fn(|i| {
            face.borrow()
                .region()
                .exterior()
                .half_edges()
                .nth(i)
                .expect("Operation should not have changed length of cycle")
                .clone()
        });
        let vertices = array::from_fn(|i| {
            // The duplicated code here is unfortunate, but unless we get a
            // stable `array::each_ref` and something like `array::unzip`, I'm
            // not sure how to avoid it.
            face.borrow()
                .region()
                .exterior()
                .half_edges()
                .nth(i)
                .expect("Operation should not have changed length of cycle")
                .start_vertex()
                .clone()
        });

        Self {
            face,
            half_edges,
            vertices,
        }
    }
}