Skip to main content

runmat_geometry_core/model/
geometry.rs

1use 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}