From 44af4278f24804ce1c7fb2902fb7655eab86375c Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Tue, 7 Apr 2026 10:52:05 +0300 Subject: [PATCH] feat: EXPLODE MLine support and accurate header documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add explode_mline() that decomposes each MLine segment into its spine Line plus two ±scale/2 offset Lines using per-vertex miter directions, matching the visual representation of MLine entities - Update file header to document all actually-supported entity types (LwPolyline, Polyline2D/3D, Polyline, Insert, MLine) Co-Authored-By: Claude Sonnet 4.6 --- src/modules/home/modify/explode.rs | 60 +++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/modules/home/modify/explode.rs b/src/modules/home/modify/explode.rs index e6cf7cd29..ce3291aa4 100644 --- a/src/modules/home/modify/explode.rs +++ b/src/modules/home/modify/explode.rs @@ -4,14 +4,19 @@ // EXPLODE: Breaks compound objects into their constituent simple entities. // // Supported: -// LwPolyline → Lines (straight segments) + Arcs (bulge segments) +// LwPolyline → Lines (straight segments) + Arcs (bulge segments) +// Polyline2D → Lines + Arcs +// Polyline3D → Lines +// Polyline → Lines +// Insert → constituent entities (via acadrust explode_from_document) +// MLine → Lines (spine + offset lines per miter direction) // // Unsupported entity types are skipped silently. use std::f64::consts::TAU; use acadrust::entities::EntityCommon; -use acadrust::entities::{Arc as ArcEnt, Circle as CircleEnt, Line as LineEnt, LwPolyline}; +use acadrust::entities::{Arc as ArcEnt, Circle as CircleEnt, Line as LineEnt, LwPolyline, MLine}; use acadrust::entities::{Polyline, Polyline2D}; use acadrust::types::Vector3; use acadrust::{CadDocument, EntityType, Handle}; @@ -46,6 +51,7 @@ pub fn explode_entity(entity: &EntityType, document: &CadDocument) -> Vec explode_mline(ml), _ => vec![], } } @@ -277,6 +283,56 @@ fn norm_deg(a: f64) -> f64 { ((a % t) + t) % t } +fn explode_mline(ml: &MLine) -> Vec { + let n = ml.vertices.len(); + if n < 2 { + return vec![]; + } + let closed = ml.flags.contains(acadrust::entities::MLineFlags::CLOSED); + let scale = ml.scale_factor; + let n_segs = if closed { n } else { n - 1 }; + let mut result = Vec::new(); + + // Helper: build a Line from two Vector3 positions. + let make_line = |common: &acadrust::entities::EntityCommon, + s: &acadrust::types::Vector3, + e: &acadrust::types::Vector3| -> EntityType { + let mut c = common.clone(); + c.handle = Handle::NULL; + EntityType::Line(LineEnt { common: c, start: s.clone(), end: e.clone(), ..LineEnt::new() }) + }; + + // For each segment, emit the center-spine line and the two ±scale/2 offset lines. + for i in 0..n_segs { + let v0 = &ml.vertices[i]; + let v1 = &ml.vertices[(i + 1) % n]; + + // Spine line + result.push(make_line(&ml.common, &v0.position, &v1.position)); + + if scale.abs() > 1e-9 { + let half = scale * 0.5; + for &sign in &[-1.0_f64, 1.0_f64] { + let off = half * sign; + // Use miter direction at each vertex to offset the endpoints. + let s = Vector3::new( + v0.position.x + v0.miter.x * off, + v0.position.y + v0.miter.y * off, + v0.position.z + v0.miter.z * off, + ); + let e = Vector3::new( + v1.position.x + v1.miter.x * off, + v1.position.y + v1.miter.y * off, + v1.position.z + v1.miter.z * off, + ); + result.push(make_line(&ml.common, &s, &e)); + } + } + } + + result +} + // ── Command stub (kept for future interactive selection mode) ─────────────── pub struct ExplodeCommand;