From e66905e9b12c857e5402956721c7e6034cb1c22c Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Tue, 26 May 2026 17:22:02 +0300 Subject: [PATCH] refactor(entities): Solid3D/Region/Body accessor trio in entities/solid3d.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The same three-arm `match entity { Solid3D | Region | Body }` block appeared at five callsites — twice in tessellate.rs (point_of_reference, fallback wires) and three times in scene/mod.rs (mesh tess dispatch, apply_grip pre/post position). Add three accessors in entities/solid3d.rs: point_of_reference(e) → Option<&Vector3> fallback_wires(e) → Option<&[Wire]> tessellate_volume(e, color, facet_res) → Option Callsites shrink from 5–8 lines to one call. The apply_grip path collapses two parallel pre/post matches plus the entity-list `matches!` guard. Co-Authored-By: Claude Opus 4.7 --- src/entities/solid3d.rs | 49 +++++++++++++++++++++++ src/scene/mod.rs | 88 +++++++++++------------------------------ src/scene/tessellate.rs | 16 ++------ 3 files changed, 74 insertions(+), 79 deletions(-) diff --git a/src/entities/solid3d.rs b/src/entities/solid3d.rs index 637c48679..accd15039 100644 --- a/src/entities/solid3d.rs +++ b/src/entities/solid3d.rs @@ -251,3 +251,52 @@ impl PropertyEditable for Body { fn apply_geom_prop(&mut self, _field: &str, _value: &str) {} } + +// ── Accessors for the Solid3D / Region / Body trio ───────────────────────── +// +// These three entity types share a common subset of fields (ACIS data +// + point_of_reference + wires fallback). Code that needs to treat them +// uniformly (mesh tess dispatch, fallback wires, grip translate) used +// to repeat a three-arm `match entity` block at every callsite — the +// helpers below collapse those to a single call. + +use acadrust::{types::Vector3, EntityType}; +use crate::scene::mesh_model::MeshLodSet; +use crate::scene::solid3d_tess; + +/// `point_of_reference` of an ACIS-backed volume entity, if applicable. +pub fn point_of_reference(e: &EntityType) -> Option<&Vector3> { + match e { + EntityType::Solid3D(s) => Some(&s.point_of_reference), + EntityType::Region(r) => Some(&r.point_of_reference), + EntityType::Body(b) => Some(&b.point_of_reference), + _ => None, + } +} + +/// Pre-stored edge-wire fallback list (used when the SAT/SAB kernel +/// can't produce a mesh — drawings authored by SOLVIEW / 3DPLOT carry +/// these explicitly). +pub fn fallback_wires(e: &EntityType) -> Option<&[acadrust::entities::Wire]> { + match e { + EntityType::Solid3D(s) => Some(&s.wires), + EntityType::Region(r) => Some(&r.wires), + EntityType::Body(b) => Some(&b.wires), + _ => None, + } +} + +/// Run the appropriate `solid3d_tess::tessellate_*` for the entity, +/// returning `None` for non-volume entities or when the kernel fails. +pub fn tessellate_volume( + e: &EntityType, + color: [f32; 4], + facet_res: f64, +) -> Option { + match e { + EntityType::Solid3D(s) => solid3d_tess::tessellate_solid3d(s, color, facet_res), + EntityType::Region(r) => solid3d_tess::tessellate_region(r, color, facet_res), + EntityType::Body(b) => solid3d_tess::tessellate_body(b, color, facet_res), + _ => None, + } +} diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 8f97cee31..0bfed43be 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -213,13 +213,8 @@ pub fn build_derived_caches(doc: &CadDocument) -> DerivedCaches { .filter_map(|&handle| { let e = doc.get_entity(handle)?; let color = tess_util::aci_to_rgba(&e.common().color); - let model = match e { - EntityType::Solid3D(s) => solid3d_tess::tessellate_solid3d(s, color, facet_res), - EntityType::Region(r) => solid3d_tess::tessellate_region(r, color, facet_res), - EntityType::Body(b) => solid3d_tess::tessellate_body(b, color, facet_res), - _ => None, - }; - model.map(|m| (handle, m)) + crate::entities::solid3d::tessellate_volume(e, color, facet_res) + .map(|m| (handle, m)) }) .collect(); @@ -2377,20 +2372,14 @@ impl Scene { None }; let facet_res = self.document.header.facet_resolution; - let mesh_seed = match &entity { - EntityType::Solid3D(s3d) => { - let color = self.render_style(&entity).0; - solid3d_tess::tessellate_solid3d(s3d, color, facet_res) - } - EntityType::Region(r) => { - let color = self.render_style(&entity).0; - solid3d_tess::tessellate_region(r, color, facet_res) - } - EntityType::Body(b) => { - let color = self.render_style(&entity).0; - solid3d_tess::tessellate_body(b, color, facet_res) - } - _ => None, + let mesh_seed = if matches!( + &entity, + EntityType::Solid3D(_) | EntityType::Region(_) | EntityType::Body(_) + ) { + let color = self.render_style(&entity).0; + crate::entities::solid3d::tessellate_volume(&entity, color, facet_res) + } else { + None }; // Auto-create an ImageDefinition object for new RasterImage entities @@ -3230,15 +3219,8 @@ impl Scene { self.meshes = entries .into_par_iter() .filter_map(|(handle, entity, color)| { - let model = match &entity { - EntityType::Solid3D(s) => { - solid3d_tess::tessellate_solid3d(s, color, facet_res) - } - EntityType::Region(r) => solid3d_tess::tessellate_region(r, color, facet_res), - EntityType::Body(b) => solid3d_tess::tessellate_body(b, color, facet_res), - _ => None, - }; - model.map(|m| (handle, m)) + crate::entities::solid3d::tessellate_volume(&entity, color, facet_res) + .map(|m| (handle, m)) }) .collect(); @@ -3642,24 +3624,11 @@ impl Scene { // For Solid3D / Region / Body, record the old point_of_reference so we // can translate the pre-tessellated MeshModel by the same delta after // the grip is applied (the ACIS data itself is not modified). - let old_por: Option<[f64; 3]> = match self.document.get_entity(handle) { - Some(EntityType::Solid3D(s)) => Some([ - s.point_of_reference.x, - s.point_of_reference.y, - s.point_of_reference.z, - ]), - Some(EntityType::Region(r)) => Some([ - r.point_of_reference.x, - r.point_of_reference.y, - r.point_of_reference.z, - ]), - Some(EntityType::Body(b)) => Some([ - b.point_of_reference.x, - b.point_of_reference.y, - b.point_of_reference.z, - ]), - _ => None, - }; + let old_por: Option<[f64; 3]> = self + .document + .get_entity(handle) + .and_then(crate::entities::solid3d::point_of_reference) + .map(|p| [p.x, p.y, p.z]); if let Some(entity) = self.document.get_entity_mut(handle) { dispatch::apply_grip(entity, grip_id, apply); @@ -3667,24 +3636,11 @@ impl Scene { // Translate MeshModel vertices by the same delta the grip applied. if let Some(old) = old_por { - let new_por: Option<[f64; 3]> = match self.document.get_entity(handle) { - Some(EntityType::Solid3D(s)) => Some([ - s.point_of_reference.x, - s.point_of_reference.y, - s.point_of_reference.z, - ]), - Some(EntityType::Region(r)) => Some([ - r.point_of_reference.x, - r.point_of_reference.y, - r.point_of_reference.z, - ]), - Some(EntityType::Body(b)) => Some([ - b.point_of_reference.x, - b.point_of_reference.y, - b.point_of_reference.z, - ]), - _ => None, - }; + let new_por: Option<[f64; 3]> = self + .document + .get_entity(handle) + .and_then(crate::entities::solid3d::point_of_reference) + .map(|p| [p.x, p.y, p.z]); if let Some(new) = new_por { let dx = (new[0] - old[0]) as f32; let dy = (new[1] - old[1]) as f32; diff --git a/src/scene/tessellate.rs b/src/scene/tessellate.rs index c68be7525..f0be0a2f1 100644 --- a/src/scene/tessellate.rs +++ b/src/scene/tessellate.rs @@ -413,13 +413,7 @@ pub fn tessellate( let mut wm = WireModel::solid(name, wire_pts, color, selected); // Add insertion snap at point_of_reference. let [ox, oy, oz] = world_offset; - let por = match entity { - EntityType::Solid3D(s) => Some(&s.point_of_reference), - EntityType::Region(r) => Some(&r.point_of_reference), - EntityType::Body(b) => Some(&b.point_of_reference), - _ => None, - }; - if let Some(p) = por { + if let Some(p) = crate::entities::solid3d::point_of_reference(entity) { let sp = Vec3::new((p.x - ox) as f32, (p.y - oy) as f32, (p.z - oz) as f32); wm.snap_pts.push((sp, SnapHint::Insertion)); } @@ -632,13 +626,9 @@ fn fallback_geometry(entity: &EntityType, world_offset: [f64; 3]) -> Geometry { /// produces no mesh (e.g. binary SAB data or unsupported geometry). fn solid_wire_fallback(entity: &EntityType, world_offset: [f64; 3]) -> Vec<[f32; 3]> { let [ox, oy, oz] = world_offset; - let wires: &[acadrust::entities::Wire] = match entity { - EntityType::Solid3D(s) => &s.wires, - EntityType::Region(r) => &r.wires, - EntityType::Body(b) => &b.wires, - _ => return vec![], + let Some(wires) = crate::entities::solid3d::fallback_wires(entity) else { + return vec![]; }; - if wires.is_empty() { return vec![]; }