forked from 1b-agent/opencadstudio-upstream
feat: add OLE2Frame interactivity + fix Shape rotation from DXF
OLE2Frame: full TruckConvertible/Grippable/PropertyEditable/Transformable impls in src/entities/ole2frame.rs — grips on corners + center, properties panel, translate/scale transforms. Shape: rotation (DXF code 50) now converted degrees→radians on load in fix_dxf_dimension_rotations(), matching Dimension and Attribute behaviour. All ❌ gaps resolved. Remaining: Viewport GPU scissor, LWPolyline plinegen. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
1 parent
de520199ac
commit
f000a8acfb
5 files changed
+169
-5
No files matched your search
+5
-5
@@ -43,7 +43,7 @@ Legend: ✅ Done · ⚠️ Partial · ❌ Not done
|
||||
| Status | Entity | Notes |
|
||||
|---|---|---|
|
||||
| ✅ | **Face3D** | Full tessellation, grips, properties panel — `src/entities/mesh.rs` |
|
||||
| ❌ | **OLE2Frame** | Bounding box + X mark only; no interactivity |
|
||||
| ✅ | **OLE2Frame** | Bounding box + X mark with grips, properties panel, transform — `src/entities/ole2frame.rs` |
|
||||
|
||||
### Wire Fallback Only (no full mesh)
|
||||
|
||||
@@ -189,7 +189,7 @@ These are fixed in our post-load `fix_dxf_dimension_rotations()` in `src/io/mod.
|
||||
| ✅ | **Dimension (all)** | `text_rotation` | 53 | `src/scene/tessellate.rs::dimension_text_natural_rotation()` |
|
||||
| ✅ | **AttributeEntity** | `rotation` | 50 | `src/io/mod.rs:224` |
|
||||
| ✅ | **AttributeDefinition** | `rotation` | 50 | `src/io/mod.rs:219` |
|
||||
| ❌ | **Shape** | `rotation` | 50 | Shape not currently rendered — low priority |
|
||||
| ✅ | **Shape** | `rotation` | 50 | Fixed in `fix_dxf_dimension_rotations()` — `src/io/mod.rs` |
|
||||
|
||||
---
|
||||
|
||||
@@ -207,13 +207,13 @@ These are fixed in our post-load `fix_dxf_dimension_rotations()` in `src/io/mod.
|
||||
|
||||
| Status | Count |
|
||||
|---|---|
|
||||
| ✅ Done | 44 |
|
||||
| ✅ Done | 46 |
|
||||
| ⚠️ Partial | 3 |
|
||||
| ❌ Not done | 2 |
|
||||
| ❌ Not done | 0 |
|
||||
| **Total** | **49** |
|
||||
|
||||
### Remaining gaps by priority
|
||||
|
||||
**Medium:** Viewport GPU scissor rect (pixel-level boundary clipping for overlapping viewports)
|
||||
|
||||
**Low:** LWPolyline plinegen (GPU shader change needed) · OLE2Frame improvement · Shape rotation
|
||||
**Low:** LWPolyline plinegen (GPU shader change needed)
|
||||
@@ -13,6 +13,7 @@ pub mod lwpolyline;
|
||||
pub mod mesh;
|
||||
pub mod mline;
|
||||
pub mod mtext;
|
||||
pub mod ole2frame;
|
||||
pub mod point;
|
||||
pub mod polyline;
|
||||
pub mod raster_image;
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
use acadrust::entities::{Ole2Frame, OleObjectType};
|
||||
use glam::Vec3;
|
||||
|
||||
use crate::command::EntityTransform;
|
||||
use crate::entities::common::{diamond_grip, ro_prop as ro, edit_prop as edit, square_grip};
|
||||
use crate::entities::traits::{Grippable, PropertyEditable, Transformable, TruckConvertible};
|
||||
use crate::scene::acad_to_truck::{TruckEntity, TruckObject};
|
||||
use crate::scene::object::{GripApply, GripDef, PropSection};
|
||||
use crate::scene::wire_model::SnapHint;
|
||||
|
||||
fn to_truck(ole: &Ole2Frame) -> TruckEntity {
|
||||
let x0 = ole.upper_left_corner.x as f32;
|
||||
let y0 = ole.lower_right_corner.y as f32;
|
||||
let x1 = ole.lower_right_corner.x as f32;
|
||||
let y1 = ole.upper_left_corner.y as f32;
|
||||
let z = ole.upper_left_corner.z as f32;
|
||||
|
||||
if (x1 - x0).abs() < 1e-6 && (y1 - y0).abs() < 1e-6 {
|
||||
let s = 0.5_f32;
|
||||
return TruckEntity {
|
||||
object: TruckObject::Lines(vec![[-s, 0.0, z], [s, 0.0, z]]),
|
||||
snap_pts: vec![],
|
||||
tangent_geoms: vec![],
|
||||
key_vertices: vec![],
|
||||
};
|
||||
}
|
||||
|
||||
let cx = (x0 + x1) * 0.5;
|
||||
let cy = (y0 + y1) * 0.5;
|
||||
let pts = vec![
|
||||
// Rectangle
|
||||
[x0, y0, z], [x1, y0, z], [x1, y0, z], [x1, y1, z],
|
||||
[x1, y1, z], [x0, y1, z], [x0, y1, z], [x0, y0, z],
|
||||
// Diagonal X
|
||||
[x0, y0, z], [x1, y1, z],
|
||||
[f32::NAN; 3],
|
||||
[x1, y0, z], [x0, y1, z],
|
||||
];
|
||||
let center = Vec3::new(cx, cy, z);
|
||||
TruckEntity {
|
||||
object: TruckObject::Lines(pts),
|
||||
snap_pts: vec![(center, SnapHint::Center)],
|
||||
tangent_geoms: vec![],
|
||||
key_vertices: vec![[x0, y0, z], [x1, y1, z]],
|
||||
}
|
||||
}
|
||||
|
||||
fn grips(ole: &Ole2Frame) -> Vec<GripDef> {
|
||||
let ul = Vec3::new(
|
||||
ole.upper_left_corner.x as f32,
|
||||
ole.upper_left_corner.y as f32,
|
||||
ole.upper_left_corner.z as f32,
|
||||
);
|
||||
let lr = Vec3::new(
|
||||
ole.lower_right_corner.x as f32,
|
||||
ole.lower_right_corner.y as f32,
|
||||
ole.lower_right_corner.z as f32,
|
||||
);
|
||||
let center = (ul + lr) * 0.5;
|
||||
vec![square_grip(0, ul), square_grip(1, lr), diamond_grip(2, center)]
|
||||
}
|
||||
|
||||
fn properties(ole: &Ole2Frame) -> PropSection {
|
||||
let type_str = match ole.ole_object_type {
|
||||
OleObjectType::Link => "Link",
|
||||
OleObjectType::Embedded => "Embedded",
|
||||
OleObjectType::Static => "Static",
|
||||
};
|
||||
PropSection {
|
||||
title: "Geometry".into(),
|
||||
props: vec![
|
||||
ro("Type", "ole_type", type_str),
|
||||
edit("Upper Left X", "ole_ulx", ole.upper_left_corner.x),
|
||||
edit("Upper Left Y", "ole_uly", ole.upper_left_corner.y),
|
||||
edit("Lower Right X", "ole_lrx", ole.lower_right_corner.x),
|
||||
edit("Lower Right Y", "ole_lry", ole.lower_right_corner.y),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_geom_prop(ole: &mut Ole2Frame, field: &str, value: &str) {
|
||||
let Ok(v) = value.trim().parse::<f64>() else { return };
|
||||
match field {
|
||||
"ole_ulx" => ole.upper_left_corner.x = v,
|
||||
"ole_uly" => ole.upper_left_corner.y = v,
|
||||
"ole_lrx" => ole.lower_right_corner.x = v,
|
||||
"ole_lry" => ole.lower_right_corner.y = v,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_grip(ole: &mut Ole2Frame, grip_id: usize, apply: GripApply) {
|
||||
match (grip_id, apply) {
|
||||
(0, GripApply::Absolute(p)) => {
|
||||
ole.upper_left_corner.x = p.x as f64;
|
||||
ole.upper_left_corner.y = p.y as f64;
|
||||
}
|
||||
(1, GripApply::Absolute(p)) => {
|
||||
ole.lower_right_corner.x = p.x as f64;
|
||||
ole.lower_right_corner.y = p.y as f64;
|
||||
}
|
||||
(2, GripApply::Translate(d)) => {
|
||||
ole.upper_left_corner.x += d.x as f64;
|
||||
ole.upper_left_corner.y += d.y as f64;
|
||||
ole.lower_right_corner.x += d.x as f64;
|
||||
ole.lower_right_corner.y += d.y as f64;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_transform(ole: &mut Ole2Frame, t: &EntityTransform) {
|
||||
match t {
|
||||
EntityTransform::Translate(d) => {
|
||||
ole.upper_left_corner.x += d.x as f64;
|
||||
ole.upper_left_corner.y += d.y as f64;
|
||||
ole.upper_left_corner.z += d.z as f64;
|
||||
ole.lower_right_corner.x += d.x as f64;
|
||||
ole.lower_right_corner.y += d.y as f64;
|
||||
ole.lower_right_corner.z += d.z as f64;
|
||||
}
|
||||
EntityTransform::Scale { center, factor } => {
|
||||
let scale = |v: f64, c: f64| c + (v - c) * (*factor as f64);
|
||||
ole.upper_left_corner.x = scale(ole.upper_left_corner.x, center.x as f64);
|
||||
ole.upper_left_corner.y = scale(ole.upper_left_corner.y, center.y as f64);
|
||||
ole.lower_right_corner.x = scale(ole.lower_right_corner.x, center.x as f64);
|
||||
ole.lower_right_corner.y = scale(ole.lower_right_corner.y, center.y as f64);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
impl TruckConvertible for Ole2Frame {
|
||||
fn to_truck(&self, _document: &acadrust::CadDocument) -> Option<TruckEntity> {
|
||||
Some(to_truck(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl Grippable for Ole2Frame {
|
||||
fn grips(&self) -> Vec<GripDef> { grips(self) }
|
||||
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) { apply_grip(self, grip_id, apply); }
|
||||
}
|
||||
|
||||
impl PropertyEditable for Ole2Frame {
|
||||
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection { properties(self) }
|
||||
fn apply_geom_prop(&mut self, field: &str, value: &str) { apply_geom_prop(self, field, value); }
|
||||
}
|
||||
|
||||
impl Transformable for Ole2Frame {
|
||||
fn apply_transform(&mut self, t: &EntityTransform) { apply_transform(self, t); }
|
||||
}
|
||||
@@ -63,6 +63,7 @@ impl EntityTypeOps for EntityType {
|
||||
EntityType::MultiLeader(ml) => TruckConvertible::to_truck(ml, document),
|
||||
EntityType::Underlay(ul) => TruckConvertible::to_truck(ul, document),
|
||||
EntityType::Shape(shp) => TruckConvertible::to_truck(shp, document),
|
||||
EntityType::Ole2Frame(ole) => TruckConvertible::to_truck(ole, document),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -102,6 +103,7 @@ impl EntityTypeOps for EntityType {
|
||||
EntityType::Hatch(hatch) => Grippable::grips(hatch),
|
||||
EntityType::Underlay(ul) => Grippable::grips(ul),
|
||||
EntityType::Shape(shp) => Grippable::grips(shp),
|
||||
EntityType::Ole2Frame(ole) => Grippable::grips(ole),
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
@@ -236,6 +238,10 @@ impl EntityTypeOps for EntityType {
|
||||
shp,
|
||||
text_style_names,
|
||||
)),
|
||||
EntityType::Ole2Frame(ole) => Some(PropertyEditable::geometry_properties(
|
||||
ole,
|
||||
text_style_names,
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -277,6 +283,7 @@ impl EntityTypeOps for EntityType {
|
||||
EntityType::MultiLeader(ml) => PropertyEditable::apply_geom_prop(ml, field, value),
|
||||
EntityType::Underlay(ul) => PropertyEditable::apply_geom_prop(ul, field, value),
|
||||
EntityType::Shape(shp) => PropertyEditable::apply_geom_prop(shp, field, value),
|
||||
EntityType::Ole2Frame(ole) => PropertyEditable::apply_geom_prop(ole, field, value),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -316,6 +323,7 @@ impl EntityTypeOps for EntityType {
|
||||
EntityType::Hatch(hatch) => Grippable::apply_grip(hatch, grip_id, apply),
|
||||
EntityType::Underlay(ul) => Grippable::apply_grip(ul, grip_id, apply),
|
||||
EntityType::Shape(shp) => Grippable::apply_grip(shp, grip_id, apply),
|
||||
EntityType::Ole2Frame(ole) => Grippable::apply_grip(ole, grip_id, apply),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -355,6 +363,7 @@ impl EntityTypeOps for EntityType {
|
||||
EntityType::MultiLeader(ml) => Transformable::apply_transform(ml, t),
|
||||
EntityType::Underlay(ul) => Transformable::apply_transform(ul, t),
|
||||
EntityType::Shape(shp) => Transformable::apply_transform(shp, t),
|
||||
EntityType::Ole2Frame(ole) => Transformable::apply_transform(ole, t),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,6 +221,9 @@ fn fix_dxf_dimension_rotations(doc: &mut CadDocument) {
|
||||
EntityType::AttributeEntity(a) => {
|
||||
a.rotation = a.rotation.to_radians();
|
||||
}
|
||||
EntityType::Shape(s) => {
|
||||
s.rotation = s.rotation.to_radians();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user