1use crate::{Line, Mesh, Point, Vector, Xform};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
10#[serde(tag = "type", rename = "Arrow")]
11pub struct Arrow {
12 pub line: Line,
13 pub mesh: Mesh,
14 pub radius: f32,
15 pub guid: String,
16 pub name: String,
17 #[serde(default = "Xform::identity")]
18 pub xform: Xform,
19}
20
21impl Arrow {
22 pub fn new(line: Line, radius: f32) -> Self {
33 let mesh = Self::create_arrow_mesh(&line, radius);
34 Self {
35 line,
36 mesh,
37 radius,
38 guid: Uuid::new_v4().to_string(),
39 name: "my_arrow".to_string(),
40 xform: Xform::identity(),
41 }
42 }
43
44 fn create_arrow_mesh(line: &Line, radius: f32) -> Mesh {
45 let start = line.start();
46 let line_vec = line.to_vector();
47 let length = line.length();
48
49 let z_axis = line_vec.normalize();
50 let x_axis = if z_axis.z().abs() < 0.9 {
51 Vector::new(0.0, 0.0, 1.0).cross(&z_axis).normalize()
52 } else {
53 Vector::new(1.0, 0.0, 0.0).cross(&z_axis).normalize()
54 };
55 let y_axis = z_axis.cross(&x_axis).normalize();
56
57 let cone_length = length * 0.2;
58 let body_length = length * 0.8;
59
60 let body_center = Point::new(
61 start.x() + line_vec.x() * 0.4,
62 start.y() + line_vec.y() * 0.4,
63 start.z() + line_vec.z() * 0.4,
64 );
65
66 let cone_base_center = Point::new(
67 start.x() + line_vec.x() * 0.9,
68 start.y() + line_vec.y() * 0.9,
69 start.z() + line_vec.z() * 0.9,
70 );
71
72 let body_scale = Xform::scale_xyz(radius * 2.0, radius * 2.0, body_length);
73 let rotation = Xform::from_cols(x_axis, y_axis, z_axis);
74 let body_translation =
75 Xform::translation(body_center.x(), body_center.y(), body_center.z());
76 let body_xform = &body_translation * &(&rotation * &body_scale);
77
78 let cone_scale = Xform::scale_xyz(radius * 3.0, radius * 3.0, cone_length);
79 let cone_translation = Xform::translation(
80 cone_base_center.x(),
81 cone_base_center.y(),
82 cone_base_center.z(),
83 );
84 let cone_xform = &cone_translation * &(&rotation * &cone_scale);
85
86 let body_geometry = Self::unit_cylinder_geometry();
87 let cone_geometry = Self::unit_cone_geometry();
88
89 let mut mesh = Mesh::new();
90
91 let mut body_vertex_map = Vec::new();
92 for v in &body_geometry.0 {
93 let transformed = body_xform.transformed_point(v);
94 let key = mesh.add_vertex(transformed, None);
95 body_vertex_map.push(key);
96 }
97
98 for tri in &body_geometry.1 {
99 let face_vertices = vec![
100 body_vertex_map[tri[0]],
101 body_vertex_map[tri[1]],
102 body_vertex_map[tri[2]],
103 ];
104 mesh.add_face(face_vertices, None);
105 }
106
107 let mut cone_vertex_map = Vec::new();
108 for v in &cone_geometry.0 {
109 let transformed = cone_xform.transformed_point(v);
110 let key = mesh.add_vertex(transformed, None);
111 cone_vertex_map.push(key);
112 }
113
114 for tri in &cone_geometry.1 {
115 let face_vertices = vec![
116 cone_vertex_map[tri[0]],
117 cone_vertex_map[tri[1]],
118 cone_vertex_map[tri[2]],
119 ];
120 mesh.add_face(face_vertices, None);
121 }
122
123 mesh
124 }
125
126 fn unit_cylinder_geometry() -> (Vec<Point>, Vec<[usize; 3]>) {
127 let vertices = vec![
128 Point::new(0.5, 0.0, -0.5),
129 Point::new(0.404508, 0.293893, -0.5),
130 Point::new(0.154508, 0.475528, -0.5),
131 Point::new(-0.154508, 0.475528, -0.5),
132 Point::new(-0.404508, 0.293893, -0.5),
133 Point::new(-0.5, 0.0, -0.5),
134 Point::new(-0.404508, -0.293893, -0.5),
135 Point::new(-0.154508, -0.475528, -0.5),
136 Point::new(0.154508, -0.475528, -0.5),
137 Point::new(0.404508, -0.293893, -0.5),
138 Point::new(0.5, 0.0, 0.5),
139 Point::new(0.404508, 0.293893, 0.5),
140 Point::new(0.154508, 0.475528, 0.5),
141 Point::new(-0.154508, 0.475528, 0.5),
142 Point::new(-0.404508, 0.293893, 0.5),
143 Point::new(-0.5, 0.0, 0.5),
144 Point::new(-0.404508, -0.293893, 0.5),
145 Point::new(-0.154508, -0.475528, 0.5),
146 Point::new(0.154508, -0.475528, 0.5),
147 Point::new(0.404508, -0.293893, 0.5),
148 ];
149
150 let triangles = vec![
151 [0, 1, 11],
152 [0, 11, 10],
153 [1, 2, 12],
154 [1, 12, 11],
155 [2, 3, 13],
156 [2, 13, 12],
157 [3, 4, 14],
158 [3, 14, 13],
159 [4, 5, 15],
160 [4, 15, 14],
161 [5, 6, 16],
162 [5, 16, 15],
163 [6, 7, 17],
164 [6, 17, 16],
165 [7, 8, 18],
166 [7, 18, 17],
167 [8, 9, 19],
168 [8, 19, 18],
169 [9, 0, 10],
170 [9, 10, 19],
171 ];
172
173 (vertices, triangles)
174 }
175
176 fn unit_cone_geometry() -> (Vec<Point>, Vec<[usize; 3]>) {
177 let vertices = vec![
178 Point::new(0.0, 0.0, 0.5),
179 Point::new(0.5, 0.0, -0.5),
180 Point::new(0.353553, -0.353553, -0.5),
181 Point::new(0.0, -0.5, -0.5),
182 Point::new(-0.353553, -0.353553, -0.5),
183 Point::new(-0.5, 0.0, -0.5),
184 Point::new(-0.353553, 0.353553, -0.5),
185 Point::new(0.0, 0.5, -0.5),
186 Point::new(0.353553, 0.353553, -0.5),
187 ];
188
189 let triangles = vec![
190 [0, 2, 1],
191 [0, 3, 2],
192 [0, 4, 3],
193 [0, 5, 4],
194 [0, 6, 5],
195 [0, 7, 6],
196 [0, 8, 7],
197 [0, 1, 8],
198 ];
199
200 (vertices, triangles)
201 }
202
203 pub fn jsondump(&self) -> Result<String, Box<dyn std::error::Error>> {
209 let data = serde_json::json!({
210 "type": "Arrow",
211 "guid": self.guid,
212 "name": self.name,
213 "radius": self.radius,
214 "line": self.line,
215 "mesh": self.mesh.jsondump()
216 });
217 Ok(serde_json::to_string_pretty(&data)?)
218 }
219
220 pub fn jsonload(json_data: &str) -> Result<Self, Box<dyn std::error::Error>> {
222 Ok(serde_json::from_str(json_data)?)
223 }
224
225 pub fn to_json(&self, filepath: &str) -> Result<(), Box<dyn std::error::Error>> {
227 let json = self.jsondump()?;
228 std::fs::write(filepath, json)?;
229 Ok(())
230 }
231
232 pub fn from_json(filepath: &str) -> Result<Self, Box<dyn std::error::Error>> {
234 let json = std::fs::read_to_string(filepath)?;
235 Self::jsonload(&json)
236 }
237}
238
239#[cfg(test)]
240#[path = "arrow_test.rs"]
241mod arrow_test;