1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4use crate::{
5 Array, BlockModel, Element, Grid2, Location, Orient2, Vector3,
6 array::Constraint,
7 array_type,
8 validate::{Validate, Validator},
9};
10
11pub(crate) fn zero_origin(v: &Vector3) -> bool {
12 *v == [0.0, 0.0, 0.0]
13}
14
15#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
17#[serde(tag = "type")]
18pub enum Geometry {
19 PointSet(PointSet),
20 LineSet(LineSet),
21 Surface(Surface),
22 GridSurface(GridSurface),
23 BlockModel(BlockModel),
24 Composite(Composite),
25}
26
27impl Geometry {
28 pub fn valid_locations(&self) -> &'static [Location] {
30 match self {
31 Self::PointSet(_) => &[Location::Vertices],
32 Self::LineSet(_) => &[Location::Vertices, Location::Primitives],
33 Self::Surface(_) => &[Location::Vertices, Location::Primitives],
34 Self::GridSurface(_) => &[Location::Vertices, Location::Primitives],
35 Self::Composite(_) => &[Location::Elements],
36 Self::BlockModel(b) if b.has_subblocks() => {
37 &[Location::Subblocks, Location::Primitives]
38 }
39 Self::BlockModel(_) => &[Location::Primitives],
40 }
41 }
42
43 pub fn location_len(&self, location: Location) -> Option<u64> {
45 if location == Location::Projected {
46 Some(0)
47 } else {
48 match self {
49 Self::PointSet(p) => p.location_len(location),
50 Self::LineSet(l) => l.location_len(location),
51 Self::Surface(s) => s.location_len(location),
52 Self::GridSurface(t) => t.location_len(location),
53 Self::BlockModel(b) => b.location_len(location),
54 Self::Composite(c) => c.location_len(location),
55 }
56 }
57 }
58
59 pub(crate) fn type_name(&self) -> &'static str {
60 match self {
61 Self::PointSet(_) => "PointSet",
62 Self::LineSet(_) => "LineSet",
63 Self::Surface(_) => "Surface",
64 Self::GridSurface(_) => "GridSurface",
65 Self::Composite(_) => "Composite",
66 Self::BlockModel(b) if b.has_subblocks() => "BlockModel(sub-blocked)",
67 Self::BlockModel(_) => "BlockModel",
68 }
69 }
70}
71
72impl From<PointSet> for Geometry {
73 fn from(value: PointSet) -> Self {
74 Self::PointSet(value)
75 }
76}
77
78impl From<LineSet> for Geometry {
79 fn from(value: LineSet) -> Self {
80 Self::LineSet(value)
81 }
82}
83
84impl From<Surface> for Geometry {
85 fn from(value: Surface) -> Self {
86 Self::Surface(value)
87 }
88}
89
90impl From<GridSurface> for Geometry {
91 fn from(value: GridSurface) -> Self {
92 Self::GridSurface(value)
93 }
94}
95
96impl From<BlockModel> for Geometry {
97 fn from(value: BlockModel) -> Self {
98 Self::BlockModel(value)
99 }
100}
101
102impl From<Composite> for Geometry {
103 fn from(value: Composite) -> Self {
104 Self::Composite(value)
105 }
106}
107
108#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
114pub struct PointSet {
115 #[serde(default, skip_serializing_if = "zero_origin")]
117 pub origin: Vector3,
118 pub vertices: Array<array_type::Vertex>,
123}
124
125impl PointSet {
126 pub fn new(vertices: Array<array_type::Vertex>) -> Self {
127 Self::with_origin(vertices, Default::default())
128 }
129
130 pub fn with_origin(vertices: Array<array_type::Vertex>, origin: Vector3) -> Self {
131 Self { origin, vertices }
132 }
133
134 pub fn location_len(&self, location: Location) -> Option<u64> {
135 match location {
136 Location::Vertices => Some(self.vertices.item_count()),
137 _ => None,
138 }
139 }
140}
141
142#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
150pub struct LineSet {
151 #[serde(default, skip_serializing_if = "zero_origin")]
153 pub origin: Vector3,
154 pub vertices: Array<array_type::Vertex>,
159 pub segments: Array<array_type::Segment>,
161}
162
163impl LineSet {
164 pub fn new(vertices: Array<array_type::Vertex>, segments: Array<array_type::Segment>) -> Self {
165 Self::with_origin(vertices, segments, Default::default())
166 }
167
168 pub fn with_origin(
169 vertices: Array<array_type::Vertex>,
170 segments: Array<array_type::Segment>,
171 origin: Vector3,
172 ) -> Self {
173 Self {
174 origin,
175 vertices,
176 segments,
177 }
178 }
179
180 pub fn location_len(&self, location: Location) -> Option<u64> {
181 match location {
182 Location::Vertices => Some(self.vertices.item_count()),
183 Location::Primitives => Some(self.segments.item_count()),
184 _ => None,
185 }
186 }
187}
188
189#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
197pub struct Surface {
198 #[serde(default, skip_serializing_if = "zero_origin")]
200 pub origin: Vector3,
201 pub vertices: Array<array_type::Vertex>,
206 pub triangles: Array<array_type::Triangle>,
209}
210
211impl Surface {
212 pub fn new(
213 vertices: Array<array_type::Vertex>,
214 triangles: Array<array_type::Triangle>,
215 ) -> Self {
216 Self::with_origin(vertices, triangles, Default::default())
217 }
218
219 pub fn with_origin(
220 vertices: Array<array_type::Vertex>,
221 triangles: Array<array_type::Triangle>,
222 origin: Vector3,
223 ) -> Self {
224 Self {
225 origin,
226 vertices,
227 triangles,
228 }
229 }
230
231 pub fn location_len(&self, location: Location) -> Option<u64> {
232 match location {
233 Location::Vertices => Some(self.vertices.item_count()),
234 Location::Primitives => Some(self.triangles.item_count()),
235 _ => None,
236 }
237 }
238}
239
240#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
248pub struct GridSurface {
249 pub orient: Orient2,
251 pub grid: Grid2,
253 pub heights: Option<Array<array_type::Scalar>>,
256}
257
258impl GridSurface {
259 pub fn new(orient: Orient2, grid: Grid2, heights: Option<Array<array_type::Scalar>>) -> Self {
260 Self {
261 orient,
262 grid,
263 heights,
264 }
265 }
266
267 pub fn location_len(&self, location: Location) -> Option<u64> {
268 match location {
269 Location::Vertices => Some(self.grid.flat_corner_count()),
270 Location::Primitives => Some(self.grid.flat_count()),
271 _ => None,
272 }
273 }
274}
275
276#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
282pub struct Composite {
283 #[serde(default)]
284 pub elements: Vec<Element>,
285}
286
287impl Composite {
288 pub fn new(elements: Vec<Element>) -> Self {
289 Self { elements }
290 }
291
292 pub fn location_len(&self, location: Location) -> Option<u64> {
293 match location {
294 Location::Elements => Some(self.elements.len().try_into().expect("usize fits in u64")),
295 _ => None,
296 }
297 }
298}
299
300impl Validate for Geometry {
301 fn validate_inner(&mut self, val: &mut Validator) {
302 let v = val.enter("Geometry");
303 match self {
304 Self::PointSet(x) => v.obj(x),
305 Self::LineSet(x) => v.obj(x),
306 Self::Surface(x) => v.obj(x),
307 Self::GridSurface(x) => v.obj(x),
308 Self::BlockModel(x) => v.obj(x),
309 Self::Composite(x) => v.obj(x),
310 };
311 }
312}
313
314impl Validate for PointSet {
315 fn validate_inner(&mut self, val: &mut Validator) {
316 val.enter("PointSet")
317 .finite_seq(self.origin, "origin")
318 .array(&mut self.vertices, Constraint::Vertex, "vertices");
319 }
320}
321
322impl Validate for LineSet {
323 fn validate_inner(&mut self, val: &mut Validator) {
324 val.enter("LineSet")
325 .finite_seq(self.origin, "origin")
326 .array(&mut self.vertices, Constraint::Vertex, "vertices")
327 .array(
328 &mut self.segments,
329 Constraint::Segment(self.vertices.item_count()),
330 "segments",
331 );
332 }
333}
334
335impl Validate for Surface {
336 fn validate_inner(&mut self, val: &mut Validator) {
337 val.enter("Surface")
338 .finite_seq(self.origin, "origin")
339 .array(&mut self.vertices, Constraint::Vertex, "vertices")
340 .array(
341 &mut self.triangles,
342 Constraint::Triangle(self.vertices.item_count()),
343 "triangles",
344 );
345 }
346}
347
348impl Validate for GridSurface {
349 fn validate_inner(&mut self, val: &mut Validator) {
350 let mut val = val
351 .enter("GridSurface")
352 .obj(&mut self.orient)
353 .obj(&mut self.grid)
354 .array_opt(self.heights.as_mut(), Constraint::Scalar, "heights")
355 .array_size_opt(
356 self.heights.as_ref().map(|h| h.item_count()),
357 self.grid.flat_corner_count(),
358 "heights",
359 );
360 self.orient.validate_ortho(&mut val);
361 }
362}
363
364impl Validate for Composite {
365 fn validate_inner(&mut self, val: &mut Validator) {
366 val.enter("Composite").objs(&mut self.elements).unique(
367 self.elements.iter().map(|e| &e.name),
368 "elements[..]::name",
369 false,
370 );
371 }
372}