solstice_2d/d3/shapes/
arc_geometry.rs1use crate::{Geometry, Point3D, Sphere, Vertex3D};
2
3#[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 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}