runmat_geometry_core/model/
geometry.rs1use serde::{Deserialize, Serialize};
2
3use crate::diagnostics::Diagnostic;
4use crate::selection::EntityKind;
5
6use super::{
7 MeshDescriptor, Region, RegionEntityMapping, SourceGeometry, SurfaceMesh, TessellationProfile,
8 UnitSystem,
9};
10
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12pub struct GeometryAsset {
13 pub geometry_id: String,
14 pub source: GeometrySource,
15 pub source_geometry: SourceGeometry,
16 pub tessellation_profile: TessellationProfile,
17 pub units: UnitSystem,
18 pub revision: u32,
19 pub meshes: Vec<MeshDescriptor>,
20 #[serde(default, skip_serializing_if = "Vec::is_empty")]
21 pub surface_meshes: Vec<SurfaceMesh>,
22 pub regions: Vec<Region>,
23 #[serde(default, skip_serializing_if = "Vec::is_empty")]
24 pub region_entity_mappings: Vec<RegionEntityMapping>,
25 pub diagnostics: Vec<Diagnostic>,
26}
27
28impl GeometryAsset {
29 pub fn validate(&self) -> Result<(), &'static str> {
30 if self.units == UnitSystem::Unspecified {
31 return Err("geometry units must be specified");
32 }
33 for surface_mesh in &self.surface_meshes {
34 surface_mesh.validate()?;
35 if !self
36 .meshes
37 .iter()
38 .any(|mesh| mesh.mesh_id == surface_mesh.mesh_id)
39 {
40 return Err("surface mesh must reference a declared mesh descriptor");
41 }
42 }
43 for mapping in &self.region_entity_mappings {
44 if !self
45 .regions
46 .iter()
47 .any(|region| region.region_id == mapping.region_id)
48 {
49 return Err("region entity mapping must reference a declared region");
50 }
51 let Some(mesh) = self
52 .meshes
53 .iter()
54 .find(|mesh| mesh.mesh_id == mapping.mesh_id)
55 else {
56 return Err("region entity mapping must reference a declared mesh");
57 };
58 let entity_count = match mapping.entity_kind {
59 EntityKind::Node => mesh.vertex_count,
60 EntityKind::Edge => 0,
61 EntityKind::Face | EntityKind::Element => mesh.element_count,
62 };
63 for range in &mapping.ranges {
64 if range.count == 0 {
65 return Err("region entity mapping ranges must not be empty");
66 }
67 let Some(end) = range.end_exclusive() else {
68 return Err("region entity mapping range overflows");
69 };
70 if end > entity_count {
71 return Err("region entity mapping range out of bounds");
72 }
73 }
74 }
75 Ok(())
76 }
77}
78
79#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
80pub struct GeometrySource {
81 pub path: String,
82 pub sha256: String,
83 pub importer_version: String,
84}