Files
OneCAD-Draft/src/entities/solid3d.rs
T
Hakan SevenandClaude Opus 4.7 0b4facc50d feat(entities): surface remaining 2D + Region fields in properties
Closes out the 2D-entity audit (and the Region partner that ships next
to Solid3D / Body). Round-trip-only metadata fields plus a few editable
ones gain Properties-panel rows so the values the parser populates are
visible and don't get silently dropped on save:

- Hatch: seed_points count, pixel_size, normal
- Polyline2D: smooth_surface, default_start_width, default_end_width,
  thickness, normal (with editors for the widths/thickness)
- Region: uid, silhouettes (shared file with Solid3D / Body)
- Underlay: clip_inverted
- RasterImage: class_version, definition_handle, definition_reactor_handle
- Wipeout: class_version, clip_mode, definition_handle,
  definition_reactor_handle
- Leader: annotation_handle, override_color
- Tolerance: dimension_style_name, dimension_style_handle, dimension_gap,
  text_height (editable), direction, normal
- MLine: style_handle, style_element_count, justification picker
- Ole2Frame: version, source_application, binary_data size, dwg_mode,
  dwg_trailing_byte, is_paper_space
- Viewport: snap_base/spacing/angle, twist_angle, front/back clip Z,
  circle_sides, grid_flags, grid_major, base_ucs_handle, ucs_ortho_type,
  background_handle, shade_plot_handle, visual_style_handle,
  default_lighting, default_lighting_type, ambient_color (with editors
  for the snap / clip / circle_sides values)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 21:28:16 +03:00

254 lines
8.4 KiB
Rust

// Grippable + PropertyEditable for Solid3D, Region, Body.
//
// Geometry lives in ACIS data — we cannot edit it via the properties panel.
// We expose the point_of_reference as a translate grip and show ACIS size
// as read-only info. Grip translate also updates wire points so the wire
// fallback stays in sync; the caller (scene/mod.rs apply_grip) translates
// the MeshModel vertices to match.
use acadrust::entities::{Body, Region, Solid3D};
use glam::Vec3;
use crate::entities::common::{diamond_grip, ro_prop as ro};
use crate::entities::traits::{Grippable, PropertyEditable};
use crate::scene::object::{GripApply, GripDef, PropSection};
// ── shared helpers ────────────────────────────────────────────────────────────
fn por_to_vec3(v: &acadrust::types::Vector3) -> Vec3 {
Vec3::new(v.x as f32, v.y as f32, v.z as f32)
}
fn translate_wires(wires: &mut Vec<acadrust::entities::Wire>, d: Vec3) {
for wire in wires.iter_mut() {
for pt in wire.points.iter_mut() {
pt.x += d.x as f64;
pt.y += d.y as f64;
pt.z += d.z as f64;
}
}
}
fn acis_size_str(has_data: bool, sat_len: usize, sab_len: usize, is_binary: bool) -> String {
if !has_data {
return "none".to_string();
}
if is_binary {
format!("{} bytes (SAB)", sab_len)
} else {
format!("{} bytes (SAT)", sat_len)
}
}
// ── Solid3D ───────────────────────────────────────────────────────────────────
impl Grippable for Solid3D {
fn grips(&self) -> Vec<GripDef> {
vec![diamond_grip(0, por_to_vec3(&self.point_of_reference))]
}
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
if grip_id != 0 {
return;
}
if let GripApply::Translate(d) = apply {
self.point_of_reference.x += d.x as f64;
self.point_of_reference.y += d.y as f64;
self.point_of_reference.z += d.z as f64;
translate_wires(&mut self.wires, d);
}
}
}
impl PropertyEditable for Solid3D {
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
let size = acis_size_str(
self.acis_data.has_data(),
self.acis_data.sat_data.len(),
self.acis_data.sab_data.len(),
self.acis_data.is_binary,
);
PropSection {
title: "Geometry".into(),
props: vec![
ro(
"Ref Pt X",
"s3d_px",
format!("{:.4}", self.point_of_reference.x),
),
ro(
"Ref Pt Y",
"s3d_py",
format!("{:.4}", self.point_of_reference.y),
),
ro(
"Ref Pt Z",
"s3d_pz",
format!("{:.4}", self.point_of_reference.z),
),
ro("ACIS Data", "s3d_acis", size),
ro(
"UID",
"s3d_uid",
if self.uid.is_empty() {
"(none)".to_string()
} else {
self.uid.clone()
},
),
ro(
"Silhouettes",
"s3d_silhouettes",
self.silhouettes.len().to_string(),
),
ro(
"History",
"s3d_history",
match self.history_handle {
Some(h) if !h.is_null() => format!("{:X}", h.value()),
_ => "(none)".to_string(),
},
),
],
}
}
fn apply_geom_prop(&mut self, _field: &str, _value: &str) {}
}
// ── Region ────────────────────────────────────────────────────────────────────
impl Grippable for Region {
fn grips(&self) -> Vec<GripDef> {
vec![diamond_grip(0, por_to_vec3(&self.point_of_reference))]
}
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
if grip_id != 0 {
return;
}
if let GripApply::Translate(d) = apply {
self.point_of_reference.x += d.x as f64;
self.point_of_reference.y += d.y as f64;
self.point_of_reference.z += d.z as f64;
translate_wires(&mut self.wires, d);
}
}
}
impl PropertyEditable for Region {
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
let size = acis_size_str(
self.acis_data.has_data(),
self.acis_data.sat_data.len(),
self.acis_data.sab_data.len(),
self.acis_data.is_binary,
);
PropSection {
title: "Geometry".into(),
props: vec![
ro(
"Ref Pt X",
"rgn_px",
format!("{:.4}", self.point_of_reference.x),
),
ro(
"Ref Pt Y",
"rgn_py",
format!("{:.4}", self.point_of_reference.y),
),
ro(
"Ref Pt Z",
"rgn_pz",
format!("{:.4}", self.point_of_reference.z),
),
ro("ACIS Data", "rgn_acis", size),
ro(
"UID",
"rgn_uid",
if self.uid.is_empty() {
"(none)".to_string()
} else {
self.uid.clone()
},
),
ro(
"Silhouettes",
"rgn_silhouettes",
self.silhouettes.len().to_string(),
),
],
}
}
fn apply_geom_prop(&mut self, _field: &str, _value: &str) {}
}
// ── Body ──────────────────────────────────────────────────────────────────────
impl Grippable for Body {
fn grips(&self) -> Vec<GripDef> {
vec![diamond_grip(0, por_to_vec3(&self.point_of_reference))]
}
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
if grip_id != 0 {
return;
}
if let GripApply::Translate(d) = apply {
self.point_of_reference.x += d.x as f64;
self.point_of_reference.y += d.y as f64;
self.point_of_reference.z += d.z as f64;
translate_wires(&mut self.wires, d);
}
}
}
impl PropertyEditable for Body {
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
let size = acis_size_str(
self.acis_data.has_data(),
self.acis_data.sat_data.len(),
self.acis_data.sab_data.len(),
self.acis_data.is_binary,
);
PropSection {
title: "Geometry".into(),
props: vec![
ro(
"Ref Pt X",
"bdy_px",
format!("{:.4}", self.point_of_reference.x),
),
ro(
"Ref Pt Y",
"bdy_py",
format!("{:.4}", self.point_of_reference.y),
),
ro(
"Ref Pt Z",
"bdy_pz",
format!("{:.4}", self.point_of_reference.z),
),
ro("ACIS Data", "bdy_acis", size),
ro(
"UID",
"bdy_uid",
if self.uid.is_empty() {
"(none)".to_string()
} else {
self.uid.clone()
},
),
ro(
"Silhouettes",
"bdy_silhouettes",
self.silhouettes.len().to_string(),
),
],
}
}
fn apply_geom_prop(&mut self, _field: &str, _value: &str) {}
}