refactor(commands): per-entity MassProps + TextContent traits
Two free helpers in app/commands.rs lived as big match-on-EntityType blocks: massprop_entity (Circle/Arc/Line/LwPolyline/Ellipse area + perimeter + centroid, ~140 lines) and entity_text_content / replace_entity_text (Text/MText/AttributeDefinition/AttributeEntity). Move each to its own trait in entities/traits.rs and implement per-entity: MassPropsCalc — Circle, Arc, Line, LwPolyline, Ellipse TextContent — Text, MText, AttributeDefinition, AttributeEntity EntityTypeOps gets dispatch shims that route to the trait via the existing macro, so callsites just call entity.mass_props() / entity.text_content() / entity.replace_text(search, rep). The remaining free helpers in commands.rs (entity_list_details, entity_extra_info, entity_type_name, build_data_extraction_csv) are single-command formatting helpers tightly coupled to LIST / EXTRACT / text-format output. Distributing them as per-entity methods would inflate every entity file with command-side formatting concerns without making the command-side any cleaner — left in place. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
40180e9089
commit
e78321190a
10 changed files with 266 additions and 193 deletions
|
|
@ -549,3 +549,50 @@ pub(crate) fn wide_fills(pl: &acadrust::entities::LwPolyline) -> Vec<Vec<[f32; 2
|
|||
}
|
||||
out
|
||||
}
|
||||
|
||||
impl crate::entities::traits::MassPropsCalc for acadrust::entities::LwPolyline {
|
||||
fn mass_props(&self) -> crate::entities::traits::MassProps {
|
||||
let p = self;
|
||||
let n = p.vertices.len();
|
||||
if n < 2 {
|
||||
return crate::entities::traits::MassProps {
|
||||
area: 0.0,
|
||||
perimeter: 0.0,
|
||||
cx: 0.0,
|
||||
cy: 0.0,
|
||||
};
|
||||
}
|
||||
// Shoelace area + perimeter
|
||||
let mut area_sum = 0.0f64;
|
||||
let mut perimeter = 0.0f64;
|
||||
let mut cx_sum = 0.0f64;
|
||||
let mut cy_sum = 0.0f64;
|
||||
let n_segs = if p.is_closed { n } else { n - 1 };
|
||||
for idx in 0..n_segs {
|
||||
let v0 = &p.vertices[idx];
|
||||
let v1 = &p.vertices[(idx + 1) % n];
|
||||
let x0 = v0.location.x;
|
||||
let y0 = v0.location.y;
|
||||
let x1 = v1.location.x;
|
||||
let y1 = v1.location.y;
|
||||
area_sum += x0 * y1 - x1 * y0;
|
||||
perimeter += ((x1 - x0).powi(2) + (y1 - y0).powi(2)).sqrt();
|
||||
cx_sum += (x0 + x1) * (x0 * y1 - x1 * y0);
|
||||
cy_sum += (y0 + y1) * (x0 * y1 - x1 * y0);
|
||||
}
|
||||
let area = (area_sum / 2.0).abs();
|
||||
let (cx, cy) = if area > 1e-12 {
|
||||
(cx_sum / (6.0 * area), cy_sum / (6.0 * area))
|
||||
} else {
|
||||
let sx: f64 = p.vertices.iter().map(|v| v.location.x).sum::<f64>() / n as f64;
|
||||
let sy: f64 = p.vertices.iter().map(|v| v.location.y).sum::<f64>() / n as f64;
|
||||
(sx, sy)
|
||||
};
|
||||
crate::entities::traits::MassProps {
|
||||
area,
|
||||
perimeter,
|
||||
cx,
|
||||
cy,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue