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;