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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
use crate::cad_topology::CadTopology;
use nalgebra;

pub struct Vertex {
    pub pos: nalgebra::Vector2<f64>,
}

impl Vertex {
    fn new(x: f64, y: f64) -> Self {
        Self { pos: nalgebra::Vector2::<f64>::new(x, y) }
    }
}

/* -------------------------------- */

pub struct Edge {
    pub p0: nalgebra::Vector2<f64>,
    pub p1: nalgebra::Vector2<f64>,
}

impl Edge {
    fn new() -> Self {
        Self {
            p0: nalgebra::Vector2::<f64>::new(0., 0.),
            p1: nalgebra::Vector2::<f64>::new(0., 0.),
        }
    }

    pub fn arc_length(&self) -> f64 {
        (self.p0 - self.p1).norm()
    }

    pub fn get_area_arc_origin(&self) -> f64 {
        del_geo::tri2::area(&[0., 0.], self.p0.as_slice(), self.p1.as_slice())
    }

    pub fn get_position(&self, ratio: f64) -> nalgebra::Vector2::<f64> {
        self.p0.scale(1_f64 - ratio) + self.p1.scale(ratio)
    }

    pub fn get_winding_number(&self, po: &nalgebra::Vector2<f64>) -> f64 {
        del_geo::edge2::winding_number(&self.p0, &self.p1, po)
    }

    pub fn gen_mesh(&self, ndiv: usize) -> Vec<f64> {
        let mut xyw = Vec::<f64>::new();
        assert!(ndiv > 0);
        for ip in 1..ndiv {
            let r2 = ip as f64 / ndiv as f64;
            let v2: nalgebra::Vector2::<f64> = (1_f64 - r2) * self.p0 + r2 * self.p1;
            xyw.push(v2.x);
            xyw.push(v2.y);
            xyw.push(r2);
        }
        xyw
    }
}

pub struct Loop<'a> {
    idx_loop: usize,
    cad: &'a Cad2,
}

impl<'a> Loop<'a> {
    pub fn area(&self) -> f64 {
        let mut area = 0_f64;
        for &(ie, r) in self.cad.topology.loops[self.idx_loop].idx2edge_dir.iter() {
            let a0 = self.cad.edges[ie].get_area_arc_origin();
            if r { area += a0; } else { area -= a0; }
        }
        area
    }

    pub fn winding_number_at_edge(
        &self,
        idx_edge: usize,
        ratio: f64) -> f64 {
        let p0 = self.cad.edges[idx_edge].get_position(ratio);
        let mut wn: f64 = 0.0;
        let lp = &self.cad.topology.loops[self.idx_loop];
        if lp.v != usize::MAX {
            assert_ne!(self.idx_loop, 0);
        } else {
            for &edge_dir1 in lp.idx2edge_dir.iter() {
                if edge_dir1.0 == idx_edge {
                    wn += 0.5;
                } else {
                    wn += self.cad.edges[edge_dir1.0].get_winding_number(&p0);
                }
            }
        }
        wn
    }

    pub fn check_if_winding_number_is_constant(&self) {
        let mut wns = vec!(0_f64; 0);
        let lp = &self.cad.topology.loops[self.idx_loop];
        if lp.v != usize::MAX {
            assert_ne!(self.idx_loop, 0); // the root loop should not be point
        } else {
            for &edge_dir0 in lp.idx2edge_dir.iter() {
                let wn = self.winding_number_at_edge(
                    edge_dir0.0, 0.5_f64);
                wns.push(wn);
            }
        }
        let ave: f64 = wns.iter().sum::<f64>() / wns.len() as f64;
        for &x in wns.iter() {
            assert!((x - ave).abs() < 1.0e-5);
        }
    }
}

pub struct Face<'a> {
    idx_face: usize,
    cad: &'a Cad2,
}

impl<'a> Face<'a> {
    pub fn area(&self) -> f64 {
        let mut area = 0_f64;
        for &idx_lp in self.cad.topology.faces[self.idx_face].idx2loop.iter() {
            area += self.cad.get_loop(idx_lp).area();
        }
        area
    }

    pub fn winding_number_at_edge(
        &self,
        idx_edge: usize,
        ratio: f64) -> f64 {
        let mut wn: f64 = 0.0;
        for &idx_loop in self.cad.topology.faces[self.idx_face].idx2loop.iter() {
            wn += self.cad.get_loop(idx_loop).winding_number_at_edge(idx_edge, ratio);
        }
        wn
    }
}

/* -------------------------------- */

pub struct Cad2 {
    pub topology: CadTopology,
    pub vertices: Vec<Vertex>,
    pub edges: Vec<Edge>,
}

impl Cad2 {
    pub fn new() -> Self {
        Self {
            topology: CadTopology::new(),
            vertices: vec!(),
            edges: vec!(),
        }
    }

    pub fn get_face(&self, idx_face: usize) -> Face {
        Face { idx_face: idx_face, cad: self }
    }

    pub fn get_loop(&self, idx_loop: usize) -> Loop {
        Loop { idx_loop: idx_loop, cad: self }
    }

    pub fn num_edge(&self) -> usize {
        self.edges.len()
    }

    pub fn check(&self) -> bool {
        assert!(self.topology.check());
        if self.vertices.len() != self.topology.num_vertex {
            return false;
        }
        if self.edges.len() != self.topology.edges.len() {
            return false;
        }
        // check the winding number of each face
        for idx_loop in 0..self.topology.loops.len() {
            self.get_loop(idx_loop).check_if_winding_number_is_constant();
        }
        return true;
    }

    pub fn add_polygon(
        &mut self,
        vtx2xy: &[f64]) -> usize {
        let np = vtx2xy.len() / 2;
        let idx_loop = self.topology.add_polygon(np);
        for ip in 0..np {
            self.vertices.push(Vertex::new(vtx2xy[ip * 2 + 0], vtx2xy[ip * 2 + 1]));
        }
        for _ie in 0..np {
            self.edges.push(Edge::new());
        }
        self.copy_vertex_positions_to_edges();
        debug_assert!(self.check());
        idx_loop
    }

    pub fn add_vertex_to_face(
        &mut self,
        x0: f64,
        y0: f64,
        ifc_add: usize) {
        if ifc_add >= self.topology.faces.len() { return; }
        self.topology.add_vertex_to_face(ifc_add);
        debug_assert!(self.topology.check());
        self.vertices.push(Vertex::new(x0, y0));
        self.copy_vertex_positions_to_edges();
        debug_assert!(self.check());
    }

    pub fn add_new_vertex_to_edge(
        &mut self,
        x: f64, y: f64, idx_edge: usize) -> usize {
        if idx_edge >= self.topology.edges.len() { return usize::MAX; }
        let idx_vtx_new = self.topology.add_new_vertex_to_edge(idx_edge);
        debug_assert!(self.topology.check());
        self.vertices.push(Vertex::new(x, y));
        self.edges.push(Edge::new());
        self.copy_vertex_positions_to_edges();
        debug_assert!(self.check());
        idx_vtx_new
    }

    pub fn add_vertex_to_edge(
        &mut self,
        idx_vtx: usize,
        idx_edge: usize) -> bool {
        if idx_edge >= self.topology.edges.len() { return false; }
        if idx_vtx >= self.topology.num_vertex { return false; }
        let res = self.topology.add_existing_vertex_to_edge(idx_vtx, idx_edge);
        if !res { return false; }
        self.edges.push(Edge::new());
        self.copy_vertex_positions_to_edges();
        debug_assert!(self.check());
        true
    }

    /// internal
    fn copy_vertex_positions_to_edges(&mut self) {
        for ie in 0..self.topology.edges.len() {
            let iv0 = self.topology.edges[ie].v0;
            let iv1 = self.topology.edges[ie].v1;
            self.edges[ie].p0 = self.vertices[iv0].pos;
            self.edges[ie].p1 = self.vertices[iv1].pos;
        }
    }
}


#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        let mut cad2 = Cad2::new();
        let i0_face = cad2.add_polygon(&[
            0., 0.,
            1., 0.,
            1., 1.]);
        assert!(cad2.check());
        assert!((cad2.get_face(i0_face).area() - 0.5).abs() < 1.0e-5);
        //
        let i1_face = cad2.add_polygon(&[
            1.1, 0.2,
            2.1, 0.2,
            2.1, 1.2,
            1.1, 1.2]);
        assert!(cad2.check());
        assert!((cad2.get_face(i1_face).area() - 1.0).abs() < 1.0e-5);
    }
}