feat: EXPLODE now supports Dimension entities
Decomposes Dimension (Linear, Aligned, Radius, Diameter, Angular2Ln, Angular3Pt, Ordinate) into constituent Lines (extension lines, dimension line) plus a Text entity for the dimension label value. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d3d4ec4a08
commit
7a07ef8710
2 changed files with 99 additions and 4 deletions
|
|
@ -122,7 +122,7 @@ Underlay (PDF/DWF/DGN)
|
|||
| FILLET (F) | 🔧 | LwPolyline desteği yok |
|
||||
| CHAMFER (CHA) | ✅ | — |
|
||||
| JOIN (J) | ✅ | — |
|
||||
| EXPLODE (X) | 🔧 | Dimension eksik |
|
||||
| EXPLODE (X) | ✅ | — |
|
||||
| PEDIT (PE) | ✅ | — |
|
||||
| STRETCH (SS) | ✅ | — |
|
||||
| SPLINEDIT | ⬜ | — |
|
||||
|
|
@ -303,8 +303,7 @@ Underlay (PDF/DWF/DGN)
|
|||
|
||||
### Yüksek Öncelik
|
||||
1. **TRIM / EXTEND / OFFSET / BREAK / LENGTHEN → Spline desteği**
|
||||
2. **EXPLODE → Dimension desteği**
|
||||
3. **FILLET → LwPolyline desteği**
|
||||
2. **FILLET → LwPolyline desteği**
|
||||
|
||||
### Orta Öncelik
|
||||
5. **Solid3D tessellation** tamamlama (ACIS → truck pipeline)
|
||||
|
|
|
|||
|
|
@ -10,13 +10,16 @@
|
|||
// Polyline → Lines
|
||||
// Insert → constituent entities (via acadrust explode_from_document)
|
||||
// MLine → Lines (spine + offset lines per miter direction)
|
||||
// Dimension → Lines (extension + dimension + arrows) + Text
|
||||
//
|
||||
// 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, MLine};
|
||||
use acadrust::entities::{
|
||||
Arc as ArcEnt, Circle as CircleEnt, Dimension, Line as LineEnt, LwPolyline, MLine,
|
||||
};
|
||||
use acadrust::entities::{Polyline, Polyline2D};
|
||||
use acadrust::types::Vector3;
|
||||
use acadrust::{CadDocument, EntityType, Handle};
|
||||
|
|
@ -52,6 +55,7 @@ pub fn explode_entity(entity: &EntityType, document: &CadDocument) -> Vec<Entity
|
|||
.map(normalize_insert_entity)
|
||||
.collect(),
|
||||
EntityType::MLine(ml) => explode_mline(ml),
|
||||
EntityType::Dimension(dim) => explode_dimension(dim),
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
|
|
@ -333,6 +337,98 @@ fn explode_mline(ml: &MLine) -> Vec<EntityType> {
|
|||
result
|
||||
}
|
||||
|
||||
// ── Dimension explode ──────────────────────────────────────────────────────
|
||||
|
||||
/// Convert a Dimension entity into Lines (geometry) + Text (label).
|
||||
fn explode_dimension(dim: &Dimension) -> Vec<EntityType> {
|
||||
use acadrust::entities::Text;
|
||||
|
||||
let base = dim.base();
|
||||
let common = base.common.clone();
|
||||
let mut result: Vec<EntityType> = Vec::new();
|
||||
|
||||
// Helper: make a line segment
|
||||
let make_seg = |a: &Vector3, b: &Vector3, common: &EntityCommon| -> EntityType {
|
||||
let mut c = common.clone();
|
||||
c.handle = Handle::NULL;
|
||||
EntityType::Line(LineEnt { common: c, start: a.clone(), end: b.clone(), ..LineEnt::new() })
|
||||
};
|
||||
|
||||
let v3 = |x: f64, y: f64, z: f64| Vector3::new(x, y, z);
|
||||
|
||||
match dim {
|
||||
Dimension::Aligned(d) => {
|
||||
let fx = d.first_point.x; let fy = d.first_point.y;
|
||||
let sx = d.second_point.x; let sy = d.second_point.y;
|
||||
let dx_s = sx - fx; let dy_s = sy - fy;
|
||||
let len = (dx_s*dx_s + dy_s*dy_s).sqrt().max(1e-12);
|
||||
let axis_angle = dy_s.atan2(dx_s);
|
||||
let perp_x = -(axis_angle.sin()); let perp_y = axis_angle.cos();
|
||||
let offset = (d.definition_point.x - fx) * perp_x + (d.definition_point.y - fy) * perp_y;
|
||||
let d1 = v3(fx + perp_x * offset, fy + perp_y * offset, d.first_point.z);
|
||||
let d2 = v3(sx + perp_x * offset, sy + perp_y * offset, d.second_point.z);
|
||||
result.push(make_seg(&d.first_point, &d1, &common));
|
||||
result.push(make_seg(&d.second_point, &d2, &common));
|
||||
result.push(make_seg(&d1, &d2, &common));
|
||||
let _ = len;
|
||||
}
|
||||
Dimension::Linear(d) => {
|
||||
let angle = d.rotation.to_radians();
|
||||
let perp_x = -(angle.sin()); let perp_y = angle.cos();
|
||||
let fx = d.first_point.x; let fy = d.first_point.y;
|
||||
let sx = d.second_point.x; let sy = d.second_point.y;
|
||||
let offset = (d.definition_point.x - fx) * perp_x + (d.definition_point.y - fy) * perp_y;
|
||||
let d1 = v3(fx + perp_x * offset, fy + perp_y * offset, d.first_point.z);
|
||||
let d2 = v3(sx + perp_x * offset, sy + perp_y * offset, d.second_point.z);
|
||||
result.push(make_seg(&d.first_point, &d1, &common));
|
||||
result.push(make_seg(&d.second_point, &d2, &common));
|
||||
result.push(make_seg(&d1, &d2, &common));
|
||||
}
|
||||
Dimension::Radius(d) => {
|
||||
result.push(make_seg(&d.angle_vertex, &d.definition_point, &common));
|
||||
}
|
||||
Dimension::Diameter(d) => {
|
||||
result.push(make_seg(&d.angle_vertex, &d.definition_point, &common));
|
||||
}
|
||||
Dimension::Angular2Ln(d) => {
|
||||
result.push(make_seg(&d.first_point, &d.angle_vertex, &common));
|
||||
result.push(make_seg(&d.second_point, &d.angle_vertex, &common));
|
||||
}
|
||||
Dimension::Angular3Pt(d) => {
|
||||
result.push(make_seg(&d.first_point, &d.angle_vertex, &common));
|
||||
result.push(make_seg(&d.second_point, &d.angle_vertex, &common));
|
||||
}
|
||||
Dimension::Ordinate(d) => {
|
||||
result.push(make_seg(&d.feature_location, &d.definition_point, &common));
|
||||
result.push(make_seg(&d.definition_point, &d.leader_endpoint, &common));
|
||||
}
|
||||
}
|
||||
|
||||
// Text entity for the dimension label
|
||||
let text_val = if let Some(u) = &base.user_text {
|
||||
if !u.trim().is_empty() { u.clone() } else { format!("{:.4}", dim.measurement()) }
|
||||
} else if !base.text.trim().is_empty() {
|
||||
base.text.clone()
|
||||
} else {
|
||||
match dim {
|
||||
Dimension::Radius(_) => format!("R{:.4}", dim.measurement()),
|
||||
Dimension::Diameter(_) => format!("Ø{:.4}", dim.measurement()),
|
||||
Dimension::Angular2Ln(_) | Dimension::Angular3Pt(_) =>
|
||||
format!("{:.2}°", dim.measurement()),
|
||||
_ => format!("{:.4}", dim.measurement()),
|
||||
}
|
||||
};
|
||||
|
||||
let mut text = Text::with_value(text_val, base.text_middle_point.clone())
|
||||
.with_height(base.line_spacing_factor.abs().max(0.1))
|
||||
.with_rotation(base.text_rotation);
|
||||
text.common = common.clone();
|
||||
text.common.handle = Handle::NULL;
|
||||
result.push(EntityType::Text(text));
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
// ── Command stub (kept for future interactive selection mode) ───────────────
|
||||
|
||||
pub struct ExplodeCommand;
|
||||
|
|
|
|||
Loading…
Reference in a new issue