Skip to main content

runmat_meshing/solid/
mod.rs

1use runmat_geometry_core::{CadCurveEvaluationSample, GeometryAsset};
2use runmat_meshing_cad::{
3    build_cad_evaluation_model, build_cad_topology, extract_source_topology, project_to_face,
4    CadEvaluationModel,
5};
6use runmat_meshing_core::{
7    quality::predicate::Point3, AnalysisMeshArtifact, MeshBackendKind, MeshSizingField,
8    TopologyEntityId, VolumeMeshingOptions,
9};
10use runmat_meshing_curve::{
11    build_curve_mesh_contract, discretize_cad_topology_curves_with_sizing_and_provider,
12    CadCurveEvaluationRequest, CadCurveEvaluatorProvider, CurveValidationOptions,
13};
14use runmat_meshing_plc::build::build_protected_boundary_complex;
15use runmat_meshing_surface::{
16    build_surface_mesh_contract, discretize_cad_topology_surfaces_with_cad_curves_and_sizing,
17    validate_cad_topology_surface_discretization, SurfaceValidationOptions,
18};
19use runmat_meshing_tetrahedron::{
20    optimize::{
21        optimize_recovered_tetrahedron_mesh, RecoveredTetrahedronMeshOptimizationOptions,
22        TetrahedronBoundarySmoothingProjection, TetrahedronBoundarySmoothingProjector,
23    },
24    recover::recover_tetrahedron_mesh_from_plc,
25    structured_grid,
26};
27
28mod artifact;
29mod error;
30mod options;
31mod sizing;
32mod stage_options;
33mod tetrahedron_stage;
34
35use artifact::{
36    analysis_artifact_from_tetrahedron_mesh, backend_quality_evidence_from_tetrahedron_mesh,
37};
38pub use error::SolidMeshingError;
39use options::validate_solid_options;
40use sizing::sizing_with_application_evidence;
41use stage_options::{curve_discretization_options, surface_discretization_options};
42use tetrahedron_stage::generate_solid_tetrahedron_mesh;
43
44pub fn generate_analysis_mesh(
45    geometry: &GeometryAsset,
46    options: VolumeMeshingOptions,
47) -> Result<AnalysisMeshArtifact, SolidMeshingError> {
48    match options.backend {
49        MeshBackendKind::Auto | MeshBackendKind::Solid => generate_solid_analysis_mesh(
50            geometry,
51            &VolumeMeshingOptions {
52                backend: MeshBackendKind::Solid,
53                ..options
54            },
55        ),
56        MeshBackendKind::StructuredGridTetrahedron => {
57            structured_grid::generate_analysis_mesh(geometry, options)
58                .map_err(SolidMeshingError::StructuredGrid)
59        }
60    }
61}
62
63pub fn generate_analysis_mesh_with_sizing(
64    geometry: &GeometryAsset,
65    options: VolumeMeshingOptions,
66    sizing: &MeshSizingField,
67) -> Result<AnalysisMeshArtifact, SolidMeshingError> {
68    match options.backend {
69        MeshBackendKind::Auto | MeshBackendKind::Solid => generate_solid_analysis_mesh_with_sizing(
70            geometry,
71            &VolumeMeshingOptions {
72                backend: MeshBackendKind::Solid,
73                ..options
74            },
75            sizing,
76        ),
77        MeshBackendKind::StructuredGridTetrahedron => {
78            structured_grid::generate_analysis_mesh_with_sizing(geometry, options, sizing)
79                .map_err(SolidMeshingError::StructuredGrid)
80        }
81    }
82}
83
84pub fn generate_solid_analysis_mesh(
85    geometry: &GeometryAsset,
86    options: &VolumeMeshingOptions,
87) -> Result<AnalysisMeshArtifact, SolidMeshingError> {
88    generate_solid_analysis_mesh_with_sizing(geometry, options, &MeshSizingField::default())
89}
90
91pub fn generate_solid_analysis_mesh_with_sizing(
92    geometry: &GeometryAsset,
93    options: &VolumeMeshingOptions,
94    sizing: &MeshSizingField,
95) -> Result<AnalysisMeshArtifact, SolidMeshingError> {
96    validate_solid_options(options)?;
97
98    let topology = extract_source_topology(geometry).map_err(SolidMeshingError::SourceTopology)?;
99    let cad_topology =
100        build_cad_topology(geometry, &topology).map_err(SolidMeshingError::CadTopology)?;
101    let cad_evaluation = build_cad_evaluation_model(&cad_topology, &topology)
102        .map_err(SolidMeshingError::CadEvaluation)?;
103    let curve_options = curve_discretization_options(options, geometry);
104    let cad_curves = discretize_cad_topology_curves_with_sizing_and_provider(
105        &topology,
106        &cad_topology,
107        curve_options,
108        Some(sizing),
109        &GeometryCadCurveEvaluatorProvider { geometry },
110    )
111    .map_err(SolidMeshingError::Curve)?;
112    let _curve_mesh_contract = build_curve_mesh_contract(
113        "solid_curve_mesh",
114        &topology,
115        &cad_curves.curves,
116        CurveValidationOptions::default(),
117    )
118    .map_err(SolidMeshingError::CurveValidation)?;
119    let surface = discretize_cad_topology_surfaces_with_cad_curves_and_sizing(
120        &cad_topology,
121        &topology,
122        &cad_evaluation,
123        &cad_curves,
124        surface_discretization_options(),
125        Some(sizing),
126    )
127    .map_err(SolidMeshingError::Surface)?;
128    let artifact_sizing =
129        sizing_with_application_evidence(sizing, &topology, curve_options, &surface);
130    let surface_validation = validate_cad_topology_surface_discretization(
131        &cad_topology,
132        &topology,
133        &surface,
134        SurfaceValidationOptions::default(),
135    )
136    .map_err(SolidMeshingError::SurfaceValidation)?;
137    let surface_mesh_contract =
138        build_surface_mesh_contract("solid_surface_mesh", &surface, &surface_validation);
139    let plc = build_protected_boundary_complex(&surface_mesh_contract)
140        .map_err(SolidMeshingError::ProtectedBoundaryComplex)?;
141    let tetrahedron_mesh = generate_solid_tetrahedron_mesh(&plc)?;
142    let mut recovery = recover_tetrahedron_mesh_from_plc(&plc, tetrahedron_mesh)
143        .map_err(SolidMeshingError::TetrahedronRecovery)?;
144    let initial_backend_quality =
145        backend_quality_evidence_from_tetrahedron_mesh(&recovery.tetrahedron_mesh);
146    optimize_recovered_tetrahedron_mesh(
147        &mut recovery.tetrahedron_mesh,
148        &CadFaceBoundarySmoothingProjector {
149            cad_evaluation: &cad_evaluation,
150        },
151        RecoveredTetrahedronMeshOptimizationOptions::default(),
152    );
153
154    Ok(analysis_artifact_from_tetrahedron_mesh(
155        geometry,
156        &artifact_sizing,
157        &surface_mesh_contract,
158        &recovery.recovery_queue,
159        initial_backend_quality,
160        recovery.tetrahedron_mesh,
161    ))
162}
163
164struct GeometryCadCurveEvaluatorProvider<'a> {
165    geometry: &'a GeometryAsset,
166}
167
168impl CadCurveEvaluatorProvider for GeometryCadCurveEvaluatorProvider<'_> {
169    fn evaluate_curve(
170        &self,
171        request: &CadCurveEvaluationRequest<'_>,
172    ) -> Vec<CadCurveEvaluationSample> {
173        self.geometry
174            .source_geometry
175            .cad_evaluators
176            .iter()
177            .flat_map(|set| set.curves.iter())
178            .filter(|curve| {
179                request
180                    .imported_curve_id
181                    .is_some_and(|curve_id| curve.imported_curve_id == curve_id)
182                    && request
183                        .evaluator_id
184                        .is_none_or(|evaluator_id| curve.evaluator_id == evaluator_id)
185            })
186            .flat_map(|curve| curve.evaluation_samples.iter())
187            .filter(|sample| {
188                request
189                    .parameters
190                    .iter()
191                    .any(|parameter| (*parameter - sample.parameter).abs() <= 1.0e-12)
192            })
193            .cloned()
194            .collect()
195    }
196}
197
198struct CadFaceBoundarySmoothingProjector<'a> {
199    cad_evaluation: &'a CadEvaluationModel,
200}
201
202impl TetrahedronBoundarySmoothingProjector for CadFaceBoundarySmoothingProjector<'_> {
203    fn project_to_source_face(
204        &self,
205        source_face_id: &TopologyEntityId,
206        point_m: Point3,
207    ) -> Option<TetrahedronBoundarySmoothingProjection> {
208        let source_face_id = source_face_id.id.parse::<u32>().ok()?;
209        let frame = self
210            .cad_evaluation
211            .face_frames
212            .iter()
213            .find(|frame| frame.source_face_id == source_face_id)?;
214        let projection = project_to_face(frame, point_m);
215        Some(TetrahedronBoundarySmoothingProjection {
216            point_m: projection.point_m,
217            distance_m: projection.distance_m,
218            in_bounds: projection.uv_in_bounds,
219        })
220    }
221}
222
223#[cfg(test)]
224mod tests;