solstice_2d/d3/shapes/
arc_geometry.rs

1use crate::{Geometry, Point3D, Sphere, Vertex3D};
2
3/// Differs from a Sphere in that when "open" on an axis, additional geometry si generated creating
4/// sides connected to the centroid.
5#[derive(Clone, Debug, PartialEq)]
6pub struct Arc3D(pub Sphere);
7
8impl Arc3D {
9    pub fn new(sphere: Sphere) -> Self {
10        Self(sphere)
11    }
12
13    fn vertices(&self) -> Vec<Vertex3D> {
14        let Sphere {
15            radius,
16            width_segments,
17            height_segments,
18            phi_start,
19            phi_length,
20            theta_start,
21            theta_length,
22        } = self.0;
23        let mut vertices = vec![];
24        let theta_end = std::f32::consts::PI.min(theta_start.0 + theta_length.0);
25
26        for y in 0..=height_segments {
27            let v = y as f32 / height_segments as f32;
28
29            vertices.push(Vertex3D {
30                normal: [0., v, 0.],
31                position: [0., radius * (theta_start.0 + v * theta_length.0).cos(), 0.],
32                uv: [0., v],
33                color: [1., 1., 1., 1.],
34            });
35
36            // special consideration for the poles
37            let u_offset = if y == 0 && theta_start.0 == 0. {
38                0.5 / width_segments as f32
39            } else if y == height_segments && theta_end == std::f32::consts::PI {
40                -0.5 / width_segments as f32
41            } else {
42                0.
43            };
44
45            for x in 0..=width_segments {
46                let u = x as f32 / width_segments as f32;
47
48                let position = Point3D::from([
49                    -radius
50                        * (phi_start.0 + u * phi_length.0).cos()
51                        * (theta_start.0 + v * theta_length.0).sin(),
52                    radius * (theta_start.0 + v * theta_length.0).cos(),
53                    radius
54                        * (phi_start.0 + u * phi_length.0).sin()
55                        * (theta_start.0 + v * theta_length.0).sin(),
56                ]);
57                vertices.push(Vertex3D {
58                    normal: position.normalize().into(),
59                    position: position.into(),
60                    uv: [u + u_offset, v],
61                    color: [1., 1., 1., 1.],
62                });
63            }
64        }
65
66        vertices
67    }
68
69    fn indices(&self) -> Vec<u32> {
70        let Sphere {
71            width_segments,
72            height_segments,
73            theta_start,
74            theta_length,
75            ..
76        } = self.0;
77        let mut indices = vec![];
78        let theta_end = std::f32::consts::PI.min(theta_start.0 + theta_length.0);
79
80        let mut index = 0;
81        let mut grid = vec![];
82        for _y in 0..=height_segments {
83            let mut vertices_row = vec![];
84            vertices_row.push(index);
85            index += 1;
86            for _x in 0..=width_segments {
87                vertices_row.push(index);
88                index += 1;
89            }
90            vertices_row.push(index);
91            grid.push(vertices_row);
92        }
93
94        for iy in 0..height_segments as usize {
95            for ix in 0..(width_segments + 2) as usize {
96                let a = grid[iy][ix + 1];
97                let b = grid[iy][ix];
98                let c = grid[iy + 1][ix];
99                let d = grid[iy + 1][ix + 1];
100
101                if iy as u32 != 0 || theta_start.0 > 0. {
102                    indices.extend_from_slice(&[a, b, d]);
103                }
104                if iy as u32 != height_segments - 1 || theta_end < std::f32::consts::PI {
105                    indices.extend_from_slice(&[b, c, d]);
106                }
107            }
108        }
109
110        indices
111    }
112}
113
114impl From<&Arc3D> for Geometry<'_, Vertex3D> {
115    fn from(arc: &Arc3D) -> Self {
116        Self::new(arc.vertices(), Some(arc.indices()))
117    }
118}
119
120impl From<Arc3D> for Geometry<'_, Vertex3D> {
121    fn from(arc: Arc3D) -> Self {
122        (&arc).into()
123    }
124}