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
use crate::{Geometry, Point3D, Sphere, Vertex3D};
#[derive(Clone, Debug, PartialEq)]
pub struct Arc3D(pub Sphere);
impl Arc3D {
pub fn new(sphere: Sphere) -> Self {
Self(sphere)
}
fn vertices(&self) -> Vec<Vertex3D> {
let Sphere {
radius,
width_segments,
height_segments,
phi_start,
phi_length,
theta_start,
theta_length,
} = self.0;
let mut vertices = vec![];
let theta_end = std::f32::consts::PI.min(theta_start.0 + theta_length.0);
for y in 0..=height_segments {
let v = y as f32 / height_segments as f32;
vertices.push(Vertex3D {
normal: [0., v, 0.],
position: [0., radius * (theta_start.0 + v * theta_length.0).cos(), 0.],
uv: [0., v],
color: [1., 1., 1., 1.],
});
let u_offset = if y == 0 && theta_start.0 == 0. {
0.5 / width_segments as f32
} else if y == height_segments && theta_end == std::f32::consts::PI {
-0.5 / width_segments as f32
} else {
0.
};
for x in 0..=width_segments {
let u = x as f32 / width_segments as f32;
let position = Point3D::from([
-radius
* (phi_start.0 + u * phi_length.0).cos()
* (theta_start.0 + v * theta_length.0).sin(),
radius * (theta_start.0 + v * theta_length.0).cos(),
radius
* (phi_start.0 + u * phi_length.0).sin()
* (theta_start.0 + v * theta_length.0).sin(),
]);
vertices.push(Vertex3D {
normal: position.normalize().into(),
position: position.into(),
uv: [u + u_offset, v],
color: [1., 1., 1., 1.],
});
}
}
vertices
}
fn indices(&self) -> Vec<u32> {
let Sphere {
width_segments,
height_segments,
theta_start,
theta_length,
..
} = self.0;
let mut indices = vec![];
let theta_end = std::f32::consts::PI.min(theta_start.0 + theta_length.0);
let mut index = 0;
let mut grid = vec![];
for _y in 0..=height_segments {
let mut vertices_row = vec![];
vertices_row.push(index);
index += 1;
for _x in 0..=width_segments {
vertices_row.push(index);
index += 1;
}
vertices_row.push(index);
grid.push(vertices_row);
}
for iy in 0..height_segments as usize {
for ix in 0..(width_segments + 2) as usize {
let a = grid[iy][ix + 1];
let b = grid[iy][ix];
let c = grid[iy + 1][ix];
let d = grid[iy + 1][ix + 1];
if iy as u32 != 0 || theta_start.0 > 0. {
indices.extend_from_slice(&[a, b, d]);
}
if iy as u32 != height_segments - 1 || theta_end < std::f32::consts::PI {
indices.extend_from_slice(&[b, c, d]);
}
}
}
indices
}
}
impl From<&Arc3D> for Geometry<'_, Vertex3D> {
fn from(arc: &Arc3D) -> Self {
Self::new(arc.vertices(), Some(arc.indices()))
}
}
impl From<Arc3D> for Geometry<'_, Vertex3D> {
fn from(arc: Arc3D) -> Self {
(&arc).into()
}
}