2026-03-22 14:56:27 +03:00
|
|
|
|
use acadrust::entities::{HooklineDirection, Leader, LeaderCreationType, LeaderPathType};
|
|
|
|
|
|
use acadrust::Entity;
|
|
|
|
|
|
use glam::Vec3;
|
|
|
|
|
|
|
|
|
|
|
|
use crate::command::EntityTransform;
|
refactor(grip): square-only marker set + oriented stretch handles
Phase 1 of bringing the grip vocabulary in line with the standard
CAD convention: drop the per-position-type shape encoding (Diamond
for translate, Circle for parameter) and use a plain square for
every endpoint / vertex / centre grip. The behavioural midpoint vs
vertex distinction stays — it lives on `GripDef::is_midpoint` and
drives `Translate` vs `Absolute` in the grip-edit dispatcher — only
the marker shape collapses.
- `GripShape` keeps `Square`, `Rectangle`, `Triangle`. Diamond /
Circle are gone.
- `GripDef` gains `dir: Option<[f32; 2]>` — a world-XY direction
vector consumed by `Rectangle` to orient the box along its
segment.
- `entities::common` exposes `square_grip`, `center_grip` (same
square marker, flagged as translate), `rectangle_grip(id, world,
dir)` for oriented mid-segment handles, and a kept-for-Phase-2
`triangle_grip`.
- `overlay::GripMarker` / `grips_to_screen[_paper]` thread `dir`
through to the canvas painter; the Rectangle path rotates the
box around the grip centre using the world-XY direction (flipping
the sin for screen-Y).
Every existing `diamond_grip(id, w)` call becomes `center_grip(id,
w)` — the visual change is square-replacing-diamond at line
midpoints / arc midpoints / circle centres / ellipse centres /
viewport / hatch loop centroids / dimension grips / image corners /
multileader / ray / underlay / ole2frame / solid3d.
`LwPolyline` grows a stretch handle on every segment (straight or
arc), drawn as the new oriented rectangle. The grip-edit path
translates both segment endpoints for straight segments and
adjusts the arc bulge from the new midpoint for arc segments.
2026-05-29 02:07:34 +03:00
|
|
|
|
use crate::entities::common::{center_grip, edit_prop as edit, ro_prop as ro, square_grip};
|
2026-06-11 00:04:37 +03:00
|
|
|
|
use crate::entities::traits::TruckConvertible;
|
2026-06-16 11:33:46 +03:00
|
|
|
|
use crate::scene::convert::acad_to_truck::{TruckEntity, TruckObject};
|
|
|
|
|
|
use crate::scene::model::object::{GripApply, GripDef, PropSection, PropValue, Property};
|
|
|
|
|
|
use crate::scene::model::wire_model::TangentGeom;
|
2026-03-22 14:56:27 +03:00
|
|
|
|
|
|
|
|
|
|
// ── TruckConvertible (used for snap/grip key-vertices) ─────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
fn to_truck(leader: &Leader) -> TruckEntity {
|
|
|
|
|
|
let verts = &leader.vertices;
|
2026-05-12 23:47:40 +03:00
|
|
|
|
let nan = [f64::NAN; 3];
|
|
|
|
|
|
let p3 = |v: &acadrust::types::Vector3| -> [f64; 3] { [v.x, v.y, v.z] };
|
2026-06-11 00:04:37 +03:00
|
|
|
|
let p3f = |v: &acadrust::types::Vector3| -> [f32; 3] { [v.x as f32, v.y as f32, v.z as f32] };
|
2026-03-22 14:56:27 +03:00
|
|
|
|
|
2026-05-12 23:47:40 +03:00
|
|
|
|
let mut points: Vec<[f64; 3]> = Vec::new();
|
2026-03-22 14:56:27 +03:00
|
|
|
|
let mut tangents: Vec<TangentGeom> = Vec::new();
|
2026-05-12 23:47:40 +03:00
|
|
|
|
let mut key_verts: Vec<[f64; 3]> = Vec::new();
|
2026-03-22 14:56:27 +03:00
|
|
|
|
|
|
|
|
|
|
// Main leader path
|
|
|
|
|
|
for v in verts {
|
|
|
|
|
|
points.push(p3(v));
|
|
|
|
|
|
key_verts.push(p3(v));
|
|
|
|
|
|
}
|
|
|
|
|
|
for i in 0..verts.len().saturating_sub(1) {
|
2026-05-12 23:47:40 +03:00
|
|
|
|
// TangentGeom uses f32 (UI-only); cast at construction.
|
2026-05-12 10:36:15 +03:00
|
|
|
|
tangents.push(TangentGeom::Line {
|
2026-05-12 23:47:40 +03:00
|
|
|
|
p1: p3f(&verts[i]),
|
|
|
|
|
|
p2: p3f(&verts[i + 1]),
|
2026-05-12 10:36:15 +03:00
|
|
|
|
});
|
2026-03-22 14:56:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Arrowhead at vertex[0]
|
|
|
|
|
|
if leader.arrow_enabled && verts.len() >= 2 {
|
|
|
|
|
|
let tip = &verts[0];
|
|
|
|
|
|
let next = &verts[1];
|
2026-05-12 23:47:40 +03:00
|
|
|
|
let dx = next.x - tip.x;
|
|
|
|
|
|
let dy = next.y - tip.y;
|
2026-03-22 14:56:27 +03:00
|
|
|
|
let len = (dx * dx + dy * dy).sqrt().max(1e-9);
|
|
|
|
|
|
let (dx, dy) = (dx / len, dy / len);
|
2026-06-03 16:17:29 +03:00
|
|
|
|
// Arrowhead sized to the text height, matching the MLEADER arrowhead.
|
|
|
|
|
|
let sz = (leader.text_height).max(1.0);
|
2026-05-12 23:47:40 +03:00
|
|
|
|
let a = std::f64::consts::PI / 6.0;
|
2026-03-22 14:56:27 +03:00
|
|
|
|
let (s, c) = a.sin_cos();
|
|
|
|
|
|
let tip_f = p3(tip);
|
|
|
|
|
|
points.push(nan);
|
2026-05-12 10:36:15 +03:00
|
|
|
|
points.push([
|
|
|
|
|
|
tip_f[0] + (dx * c - dy * s) * sz,
|
|
|
|
|
|
tip_f[1] + (dx * s + dy * c) * sz,
|
|
|
|
|
|
tip_f[2],
|
|
|
|
|
|
]);
|
2026-03-22 14:56:27 +03:00
|
|
|
|
points.push(tip_f);
|
2026-05-12 10:36:15 +03:00
|
|
|
|
points.push([
|
|
|
|
|
|
tip_f[0] + (dx * c + dy * s) * sz,
|
|
|
|
|
|
tip_f[1] + (-dx * s + dy * c) * sz,
|
|
|
|
|
|
tip_f[2],
|
|
|
|
|
|
]);
|
2026-03-22 14:56:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Landing line at last vertex
|
|
|
|
|
|
if leader.hookline_enabled && verts.len() >= 2 {
|
|
|
|
|
|
let last = verts.last().unwrap();
|
|
|
|
|
|
let prev = &verts[verts.len() - 2];
|
2026-06-22 18:18:35 +03:00
|
|
|
|
// Landing runs along the leader's horizontal direction (UCS X for
|
|
|
|
|
|
// UCS-placed leaders, world X otherwise), on the side the leader
|
|
|
|
|
|
// approaches from.
|
|
|
|
|
|
let (hx, hy) = {
|
|
|
|
|
|
let h = leader.horizontal_direction;
|
|
|
|
|
|
let l = (h.x * h.x + h.y * h.y).sqrt();
|
|
|
|
|
|
if l > 1e-9 {
|
|
|
|
|
|
(h.x / l, h.y / l)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
(1.0, 0.0)
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
let sign = if (last.x - prev.x) * hx + (last.y - prev.y) * hy >= 0.0 {
|
2026-06-11 00:04:37 +03:00
|
|
|
|
1.0_f64
|
|
|
|
|
|
} else {
|
|
|
|
|
|
-1.0_f64
|
|
|
|
|
|
};
|
2026-05-12 23:47:40 +03:00
|
|
|
|
let len = leader.text_height * 1.5;
|
2026-03-22 14:56:27 +03:00
|
|
|
|
let last_f = p3(last);
|
|
|
|
|
|
points.push(nan);
|
|
|
|
|
|
points.push(last_f);
|
2026-06-22 18:18:35 +03:00
|
|
|
|
points.push([
|
|
|
|
|
|
last_f[0] + sign * len * hx,
|
|
|
|
|
|
last_f[1] + sign * len * hy,
|
|
|
|
|
|
last_f[2],
|
|
|
|
|
|
]);
|
2026-03-22 14:56:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TruckEntity {
|
|
|
|
|
|
object: TruckObject::Lines(points),
|
|
|
|
|
|
snap_pts: vec![],
|
|
|
|
|
|
tangent_geoms: tangents,
|
|
|
|
|
|
key_vertices: key_verts,
|
2026-05-06 23:24:26 +03:00
|
|
|
|
fill_tris: vec![],
|
2026-03-22 14:56:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ── Grips ──────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
fn grips(leader: &Leader) -> Vec<GripDef> {
|
|
|
|
|
|
let n = leader.vertices.len();
|
|
|
|
|
|
let mut grips: Vec<GripDef> = leader
|
|
|
|
|
|
.vertices
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
.enumerate()
|
2026-06-11 00:04:37 +03:00
|
|
|
|
.map(|(i, v)| square_grip(i, glam::DVec3::new(v.x, v.y, v.z)))
|
2026-03-22 14:56:27 +03:00
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
|
|
if n >= 2 {
|
2026-06-11 00:04:37 +03:00
|
|
|
|
let sum = leader.vertices.iter().fold(glam::DVec3::ZERO, |acc, v| {
|
|
|
|
|
|
acc + glam::DVec3::new(v.x, v.y, v.z)
|
2026-03-22 14:56:27 +03:00
|
|
|
|
});
|
2026-06-11 00:04:37 +03:00
|
|
|
|
grips.push(center_grip(n, sum / n as f64));
|
2026-03-22 14:56:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
grips
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn apply_grip(leader: &mut Leader, grip_id: usize, apply: GripApply) {
|
|
|
|
|
|
let n = leader.vertices.len();
|
|
|
|
|
|
if grip_id < n {
|
|
|
|
|
|
if let Some(v) = leader.vertices.get_mut(grip_id) {
|
|
|
|
|
|
match apply {
|
|
|
|
|
|
GripApply::Absolute(p) => {
|
|
|
|
|
|
v.x = p.x as f64;
|
|
|
|
|
|
v.y = p.y as f64;
|
|
|
|
|
|
v.z = p.z as f64;
|
|
|
|
|
|
}
|
|
|
|
|
|
GripApply::Translate(d) => {
|
|
|
|
|
|
v.x += d.x as f64;
|
|
|
|
|
|
v.y += d.y as f64;
|
|
|
|
|
|
v.z += d.z as f64;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if let GripApply::Translate(d) = apply {
|
|
|
|
|
|
leader.translate(acadrust::types::Vector3::new(
|
2026-05-12 10:36:15 +03:00
|
|
|
|
d.x as f64, d.y as f64, d.z as f64,
|
2026-03-22 14:56:27 +03:00
|
|
|
|
));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ── Properties ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
fn bool_toggle(label: &str, field: &'static str, value: bool) -> Property {
|
|
|
|
|
|
Property {
|
|
|
|
|
|
label: label.into(),
|
|
|
|
|
|
field,
|
|
|
|
|
|
value: PropValue::BoolToggle { field, value },
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn choice_prop(label: &str, field: &'static str, selected: &str, options: &[&str]) -> Property {
|
|
|
|
|
|
Property {
|
|
|
|
|
|
label: label.into(),
|
|
|
|
|
|
field,
|
|
|
|
|
|
value: PropValue::Choice {
|
|
|
|
|
|
selected: selected.to_string(),
|
|
|
|
|
|
options: options.iter().map(|s| s.to_string()).collect(),
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn path_type_str(pt: &LeaderPathType) -> &'static str {
|
|
|
|
|
|
match pt {
|
|
|
|
|
|
LeaderPathType::StraightLine => "Straight",
|
|
|
|
|
|
LeaderPathType::Spline => "Spline",
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn creation_type_str(ct: &LeaderCreationType) -> &'static str {
|
|
|
|
|
|
match ct {
|
|
|
|
|
|
LeaderCreationType::WithText => "With Text",
|
|
|
|
|
|
LeaderCreationType::WithTolerance => "With Tolerance",
|
|
|
|
|
|
LeaderCreationType::WithBlock => "With Block",
|
|
|
|
|
|
LeaderCreationType::NoAnnotation => "No Annotation",
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat(properties): conform entity property groups to PROPERTIES.md
Rewrite each entity's property builder to the per-entity group/row spec:
the correct sections (Geometry, Misc, Text, Pattern, Lines & Arrows, Leaders,
Block, …) with the spec's rows and real computed values — Diameter,
Circumference, Area, Delta X/Y/Z, Angle, Total angle, Arc length, Radius ratio,
etc. — plus apply routing for the editable rows.
Covers ~26 entities (Line, Circle, Arc, Point, Ellipse, Spline, polylines,
Ray/XLine, Insert, Text, MText, Hatch, Leader, MultiLeader, Tolerance, Solid,
Solid3D/Region/Body, meshes, MLine, Raster/Wipeout, Underlay, Table, Viewport,
Attribute, OLE). The 3D Visualization/Material group and the full Dimension
spec are deferred (they need document access for material/dimstyle name
resolution). Rows whose data is not in the pinned acadrust revision are shown
as empty placeholders, to be filled when the dependency is bumped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:03:18 +03:00
|
|
|
|
fn color_str(c: &acadrust::types::Color) -> String {
|
|
|
|
|
|
match c.rgb() {
|
|
|
|
|
|
Some((r, g, b)) => format!("RGB({},{},{})", r, g, b),
|
|
|
|
|
|
None => format!("{:?}", c),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-02 22:46:19 +03:00
|
|
|
|
fn properties(leader: &Leader) -> Vec<PropSection> {
|
2026-03-22 14:56:27 +03:00
|
|
|
|
let n = leader.vertices.len();
|
feat(properties): conform entity property groups to PROPERTIES.md
Rewrite each entity's property builder to the per-entity group/row spec:
the correct sections (Geometry, Misc, Text, Pattern, Lines & Arrows, Leaders,
Block, …) with the spec's rows and real computed values — Diameter,
Circumference, Area, Delta X/Y/Z, Angle, Total angle, Arc length, Radius ratio,
etc. — plus apply routing for the editable rows.
Covers ~26 entities (Line, Circle, Arc, Point, Ellipse, Spline, polylines,
Ray/XLine, Insert, Text, MText, Hatch, Leader, MultiLeader, Tolerance, Solid,
Solid3D/Region/Body, meshes, MLine, Raster/Wipeout, Underlay, Table, Viewport,
Attribute, OLE). The 3D Visualization/Material group and the full Dimension
spec are deferred (they need document access for material/dimstyle name
resolution). Rows whose data is not in the pinned acadrust revision are shown
as empty placeholders, to be filled when the dependency is bumped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:03:18 +03:00
|
|
|
|
|
|
|
|
|
|
let arrow_size = leader.text_height.max(1.0);
|
|
|
|
|
|
|
|
|
|
|
|
let misc = vec![
|
2026-03-22 14:56:27 +03:00
|
|
|
|
choice_prop(
|
feat(properties): conform entity property groups to PROPERTIES.md
Rewrite each entity's property builder to the per-entity group/row spec:
the correct sections (Geometry, Misc, Text, Pattern, Lines & Arrows, Leaders,
Block, …) with the spec's rows and real computed values — Diameter,
Circumference, Area, Delta X/Y/Z, Angle, Total angle, Arc length, Radius ratio,
etc. — plus apply routing for the editable rows.
Covers ~26 entities (Line, Circle, Arc, Point, Ellipse, Spline, polylines,
Ray/XLine, Insert, Text, MText, Hatch, Leader, MultiLeader, Tolerance, Solid,
Solid3D/Region/Body, meshes, MLine, Raster/Wipeout, Underlay, Table, Viewport,
Attribute, OLE). The 3D Visualization/Material group and the full Dimension
spec are deferred (they need document access for material/dimstyle name
resolution). Rows whose data is not in the pinned acadrust revision are shown
as empty placeholders, to be filled when the dependency is bumped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:03:18 +03:00
|
|
|
|
"Type",
|
2026-03-22 14:56:27 +03:00
|
|
|
|
"path_type",
|
|
|
|
|
|
path_type_str(&leader.path_type),
|
|
|
|
|
|
&["Straight", "Spline"],
|
|
|
|
|
|
),
|
|
|
|
|
|
choice_prop(
|
feat(properties): conform entity property groups to PROPERTIES.md
Rewrite each entity's property builder to the per-entity group/row spec:
the correct sections (Geometry, Misc, Text, Pattern, Lines & Arrows, Leaders,
Block, …) with the spec's rows and real computed values — Diameter,
Circumference, Area, Delta X/Y/Z, Angle, Total angle, Arc length, Radius ratio,
etc. — plus apply routing for the editable rows.
Covers ~26 entities (Line, Circle, Arc, Point, Ellipse, Spline, polylines,
Ray/XLine, Insert, Text, MText, Hatch, Leader, MultiLeader, Tolerance, Solid,
Solid3D/Region/Body, meshes, MLine, Raster/Wipeout, Underlay, Table, Viewport,
Attribute, OLE). The 3D Visualization/Material group and the full Dimension
spec are deferred (they need document access for material/dimstyle name
resolution). Rows whose data is not in the pinned acadrust revision are shown
as empty placeholders, to be filled when the dependency is bumped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:03:18 +03:00
|
|
|
|
"Annotation type",
|
2026-03-22 14:56:27 +03:00
|
|
|
|
"creation_type",
|
|
|
|
|
|
creation_type_str(&leader.creation_type),
|
|
|
|
|
|
&["With Text", "With Tolerance", "With Block", "No Annotation"],
|
|
|
|
|
|
),
|
feat(properties): conform entity property groups to PROPERTIES.md
Rewrite each entity's property builder to the per-entity group/row spec:
the correct sections (Geometry, Misc, Text, Pattern, Lines & Arrows, Leaders,
Block, …) with the spec's rows and real computed values — Diameter,
Circumference, Area, Delta X/Y/Z, Angle, Total angle, Arc length, Radius ratio,
etc. — plus apply routing for the editable rows.
Covers ~26 entities (Line, Circle, Arc, Point, Ellipse, Spline, polylines,
Ray/XLine, Insert, Text, MText, Hatch, Leader, MultiLeader, Tolerance, Solid,
Solid3D/Region/Body, meshes, MLine, Raster/Wipeout, Underlay, Table, Viewport,
Attribute, OLE). The 3D Visualization/Material group and the full Dimension
spec are deferred (they need document access for material/dimstyle name
resolution). Rows whose data is not in the pinned acadrust revision are shown
as empty placeholders, to be filled when the dependency is bumped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:03:18 +03:00
|
|
|
|
bool_toggle("Arrowhead", "arrow_enabled", leader.arrow_enabled),
|
|
|
|
|
|
Property {
|
|
|
|
|
|
label: "Dim style".into(),
|
|
|
|
|
|
field: "dimension_style",
|
|
|
|
|
|
value: PropValue::EditText(leader.dimension_style.clone()),
|
|
|
|
|
|
},
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
let lines_arrows = vec![
|
|
|
|
|
|
ro("Dim line color", "override_color", color_str(&leader.override_color)),
|
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
|
|
|
|
ro(
|
feat(properties): conform entity property groups to PROPERTIES.md
Rewrite each entity's property builder to the per-entity group/row spec:
the correct sections (Geometry, Misc, Text, Pattern, Lines & Arrows, Leaders,
Block, …) with the spec's rows and real computed values — Diameter,
Circumference, Area, Delta X/Y/Z, Angle, Total angle, Arc length, Radius ratio,
etc. — plus apply routing for the editable rows.
Covers ~26 entities (Line, Circle, Arc, Point, Ellipse, Spline, polylines,
Ray/XLine, Insert, Text, MText, Hatch, Leader, MultiLeader, Tolerance, Solid,
Solid3D/Region/Body, meshes, MLine, Raster/Wipeout, Underlay, Table, Viewport,
Attribute, OLE). The 3D Visualization/Material group and the full Dimension
spec are deferred (they need document access for material/dimstyle name
resolution). Rows whose data is not in the pinned acadrust revision are shown
as empty placeholders, to be filled when the dependency is bumped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:03:18 +03:00
|
|
|
|
"Dim line lineweight",
|
|
|
|
|
|
"line_weight",
|
|
|
|
|
|
format!("{:?}", leader.common.line_weight),
|
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
|
|
|
|
),
|
feat(properties): conform entity property groups to PROPERTIES.md
Rewrite each entity's property builder to the per-entity group/row spec:
the correct sections (Geometry, Misc, Text, Pattern, Lines & Arrows, Leaders,
Block, …) with the spec's rows and real computed values — Diameter,
Circumference, Area, Delta X/Y/Z, Angle, Total angle, Arc length, Radius ratio,
etc. — plus apply routing for the editable rows.
Covers ~26 entities (Line, Circle, Arc, Point, Ellipse, Spline, polylines,
Ray/XLine, Insert, Text, MText, Hatch, Leader, MultiLeader, Tolerance, Solid,
Solid3D/Region/Body, meshes, MLine, Raster/Wipeout, Underlay, Table, Viewport,
Attribute, OLE). The 3D Visualization/Material group and the full Dimension
spec are deferred (they need document access for material/dimstyle name
resolution). Rows whose data is not in the pinned acadrust revision are shown
as empty placeholders, to be filled when the dependency is bumped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:03:18 +03:00
|
|
|
|
ro("Dim line linetype", "linetype", leader.common.linetype.clone()),
|
|
|
|
|
|
bool_toggle("Arrowhead", "arrow_enabled", leader.arrow_enabled),
|
|
|
|
|
|
ro("Arrow size", "arrow_size", format!("{:.4}", arrow_size)),
|
2026-03-22 14:56:27 +03:00
|
|
|
|
];
|
|
|
|
|
|
|
feat(properties): conform entity property groups to PROPERTIES.md
Rewrite each entity's property builder to the per-entity group/row spec:
the correct sections (Geometry, Misc, Text, Pattern, Lines & Arrows, Leaders,
Block, …) with the spec's rows and real computed values — Diameter,
Circumference, Area, Delta X/Y/Z, Angle, Total angle, Arc length, Radius ratio,
etc. — plus apply routing for the editable rows.
Covers ~26 entities (Line, Circle, Arc, Point, Ellipse, Spline, polylines,
Ray/XLine, Insert, Text, MText, Hatch, Leader, MultiLeader, Tolerance, Solid,
Solid3D/Region/Body, meshes, MLine, Raster/Wipeout, Underlay, Table, Viewport,
Attribute, OLE). The 3D Visualization/Material group and the full Dimension
spec are deferred (they need document access for material/dimstyle name
resolution). Rows whose data is not in the pinned acadrust revision are shown
as empty placeholders, to be filled when the dependency is bumped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:03:18 +03:00
|
|
|
|
let text = vec![
|
|
|
|
|
|
edit("Text height", "text_height", leader.text_height),
|
|
|
|
|
|
ro("Text offset", "text_offset", String::new()),
|
|
|
|
|
|
ro("Text style", "text_style", String::new()),
|
|
|
|
|
|
ro("Text color", "text_color", color_str(&leader.override_color)),
|
|
|
|
|
|
ro("Text position vert", "text_pos_vert", String::new()),
|
|
|
|
|
|
];
|
2026-03-22 14:56:27 +03:00
|
|
|
|
|
feat(properties): conform entity property groups to PROPERTIES.md
Rewrite each entity's property builder to the per-entity group/row spec:
the correct sections (Geometry, Misc, Text, Pattern, Lines & Arrows, Leaders,
Block, …) with the spec's rows and real computed values — Diameter,
Circumference, Area, Delta X/Y/Z, Angle, Total angle, Arc length, Radius ratio,
etc. — plus apply routing for the editable rows.
Covers ~26 entities (Line, Circle, Arc, Point, Ellipse, Spline, polylines,
Ray/XLine, Insert, Text, MText, Hatch, Leader, MultiLeader, Tolerance, Solid,
Solid3D/Region/Body, meshes, MLine, Raster/Wipeout, Underlay, Table, Viewport,
Attribute, OLE). The 3D Visualization/Material group and the full Dimension
spec are deferred (they need document access for material/dimstyle name
resolution). Rows whose data is not in the pinned acadrust revision are shown
as empty placeholders, to be filled when the dependency is bumped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:03:18 +03:00
|
|
|
|
let fit = vec![ro("Dim scale overall", "dim_scale_overall", String::new())];
|
|
|
|
|
|
|
|
|
|
|
|
let mut geometry = vec![ro("Vertex", "vertex_count", n.to_string())];
|
|
|
|
|
|
if let Some(a) = leader.arrow_point() {
|
|
|
|
|
|
geometry.push(edit("Vertex X", "vertex_x", a.x));
|
|
|
|
|
|
geometry.push(edit("Vertex Y", "vertex_y", a.y));
|
|
|
|
|
|
geometry.push(edit("Vertex Z", "vertex_z", a.z));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
geometry.push(ro("Vertex X", "vertex_x", String::new()));
|
|
|
|
|
|
geometry.push(ro("Vertex Y", "vertex_y", String::new()));
|
|
|
|
|
|
geometry.push(ro("Vertex Z", "vertex_z", String::new()));
|
2026-03-22 14:56:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
feat(properties): conform entity property groups to PROPERTIES.md
Rewrite each entity's property builder to the per-entity group/row spec:
the correct sections (Geometry, Misc, Text, Pattern, Lines & Arrows, Leaders,
Block, …) with the spec's rows and real computed values — Diameter,
Circumference, Area, Delta X/Y/Z, Angle, Total angle, Arc length, Radius ratio,
etc. — plus apply routing for the editable rows.
Covers ~26 entities (Line, Circle, Arc, Point, Ellipse, Spline, polylines,
Ray/XLine, Insert, Text, MText, Hatch, Leader, MultiLeader, Tolerance, Solid,
Solid3D/Region/Body, meshes, MLine, Raster/Wipeout, Underlay, Table, Viewport,
Attribute, OLE). The 3D Visualization/Material group and the full Dimension
spec are deferred (they need document access for material/dimstyle name
resolution). Rows whose data is not in the pinned acadrust revision are shown
as empty placeholders, to be filled when the dependency is bumped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:03:18 +03:00
|
|
|
|
vec![
|
|
|
|
|
|
PropSection {
|
|
|
|
|
|
title: "Misc".into(),
|
|
|
|
|
|
props: misc,
|
|
|
|
|
|
},
|
|
|
|
|
|
PropSection {
|
|
|
|
|
|
title: "Lines & Arrows".into(),
|
|
|
|
|
|
props: lines_arrows,
|
|
|
|
|
|
},
|
|
|
|
|
|
PropSection {
|
|
|
|
|
|
title: "Text".into(),
|
|
|
|
|
|
props: text,
|
|
|
|
|
|
},
|
|
|
|
|
|
PropSection {
|
|
|
|
|
|
title: "Fit".into(),
|
|
|
|
|
|
props: fit,
|
|
|
|
|
|
},
|
|
|
|
|
|
PropSection {
|
|
|
|
|
|
title: "Geometry".into(),
|
|
|
|
|
|
props: geometry,
|
|
|
|
|
|
},
|
|
|
|
|
|
]
|
2026-03-22 14:56:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn apply_geom_prop(leader: &mut Leader, field: &str, value: &str) {
|
|
|
|
|
|
let f64 = |s: &str| -> Option<f64> { s.trim().parse().ok() };
|
|
|
|
|
|
|
|
|
|
|
|
match field {
|
|
|
|
|
|
"dimension_style" => leader.dimension_style = value.to_string(),
|
|
|
|
|
|
"path_type" => {
|
|
|
|
|
|
leader.path_type = match value {
|
|
|
|
|
|
"Spline" => LeaderPathType::Spline,
|
|
|
|
|
|
_ => LeaderPathType::StraightLine,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
"creation_type" => {
|
|
|
|
|
|
leader.creation_type = match value {
|
|
|
|
|
|
"With Tolerance" => LeaderCreationType::WithTolerance,
|
|
|
|
|
|
"With Block" => LeaderCreationType::WithBlock,
|
|
|
|
|
|
"No Annotation" => LeaderCreationType::NoAnnotation,
|
|
|
|
|
|
_ => LeaderCreationType::WithText,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2026-05-12 10:36:15 +03:00
|
|
|
|
"arrow_enabled" => {
|
|
|
|
|
|
leader.arrow_enabled = if value == "toggle" {
|
|
|
|
|
|
!leader.arrow_enabled
|
|
|
|
|
|
} else {
|
|
|
|
|
|
value == "true"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"hookline_enabled" => {
|
|
|
|
|
|
leader.hookline_enabled = if value == "toggle" {
|
|
|
|
|
|
!leader.hookline_enabled
|
|
|
|
|
|
} else {
|
|
|
|
|
|
value == "true"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-22 14:56:27 +03:00
|
|
|
|
"hookline_direction" => {
|
|
|
|
|
|
leader.hookline_direction = match value {
|
|
|
|
|
|
"Same" => HooklineDirection::Same,
|
|
|
|
|
|
_ => HooklineDirection::Opposite,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
"text_height" => {
|
|
|
|
|
|
if let Some(v) = f64(value) {
|
|
|
|
|
|
leader.text_height = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"text_width" => {
|
|
|
|
|
|
if let Some(v) = f64(value) {
|
|
|
|
|
|
leader.text_width = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"normal_x" => {
|
|
|
|
|
|
if let Some(v) = f64(value) {
|
|
|
|
|
|
leader.normal.x = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"normal_y" => {
|
|
|
|
|
|
if let Some(v) = f64(value) {
|
|
|
|
|
|
leader.normal.y = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"normal_z" => {
|
|
|
|
|
|
if let Some(v) = f64(value) {
|
|
|
|
|
|
leader.normal.z = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"h_dir_x" => {
|
|
|
|
|
|
if let Some(v) = f64(value) {
|
|
|
|
|
|
leader.horizontal_direction.x = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"h_dir_y" => {
|
|
|
|
|
|
if let Some(v) = f64(value) {
|
|
|
|
|
|
leader.horizontal_direction.y = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"h_dir_z" => {
|
|
|
|
|
|
if let Some(v) = f64(value) {
|
|
|
|
|
|
leader.horizontal_direction.z = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"block_offset_x" => {
|
|
|
|
|
|
if let Some(v) = f64(value) {
|
|
|
|
|
|
leader.block_offset.x = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"block_offset_y" => {
|
|
|
|
|
|
if let Some(v) = f64(value) {
|
|
|
|
|
|
leader.block_offset.y = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"block_offset_z" => {
|
|
|
|
|
|
if let Some(v) = f64(value) {
|
|
|
|
|
|
leader.block_offset.z = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"ann_offset_x" => {
|
|
|
|
|
|
if let Some(v) = f64(value) {
|
|
|
|
|
|
leader.annotation_offset.x = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"ann_offset_y" => {
|
|
|
|
|
|
if let Some(v) = f64(value) {
|
|
|
|
|
|
leader.annotation_offset.y = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"ann_offset_z" => {
|
|
|
|
|
|
if let Some(v) = f64(value) {
|
|
|
|
|
|
leader.annotation_offset.z = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
feat(properties): conform entity property groups to PROPERTIES.md
Rewrite each entity's property builder to the per-entity group/row spec:
the correct sections (Geometry, Misc, Text, Pattern, Lines & Arrows, Leaders,
Block, …) with the spec's rows and real computed values — Diameter,
Circumference, Area, Delta X/Y/Z, Angle, Total angle, Arc length, Radius ratio,
etc. — plus apply routing for the editable rows.
Covers ~26 entities (Line, Circle, Arc, Point, Ellipse, Spline, polylines,
Ray/XLine, Insert, Text, MText, Hatch, Leader, MultiLeader, Tolerance, Solid,
Solid3D/Region/Body, meshes, MLine, Raster/Wipeout, Underlay, Table, Viewport,
Attribute, OLE). The 3D Visualization/Material group and the full Dimension
spec are deferred (they need document access for material/dimstyle name
resolution). Rows whose data is not in the pinned acadrust revision are shown
as empty placeholders, to be filled when the dependency is bumped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:03:18 +03:00
|
|
|
|
"vertex_x" => {
|
2026-03-22 14:56:27 +03:00
|
|
|
|
if let (Some(v), Some(vert)) = (f64(value), leader.vertices.get_mut(0)) {
|
|
|
|
|
|
vert.x = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
feat(properties): conform entity property groups to PROPERTIES.md
Rewrite each entity's property builder to the per-entity group/row spec:
the correct sections (Geometry, Misc, Text, Pattern, Lines & Arrows, Leaders,
Block, …) with the spec's rows and real computed values — Diameter,
Circumference, Area, Delta X/Y/Z, Angle, Total angle, Arc length, Radius ratio,
etc. — plus apply routing for the editable rows.
Covers ~26 entities (Line, Circle, Arc, Point, Ellipse, Spline, polylines,
Ray/XLine, Insert, Text, MText, Hatch, Leader, MultiLeader, Tolerance, Solid,
Solid3D/Region/Body, meshes, MLine, Raster/Wipeout, Underlay, Table, Viewport,
Attribute, OLE). The 3D Visualization/Material group and the full Dimension
spec are deferred (they need document access for material/dimstyle name
resolution). Rows whose data is not in the pinned acadrust revision are shown
as empty placeholders, to be filled when the dependency is bumped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:03:18 +03:00
|
|
|
|
"vertex_y" => {
|
2026-03-22 14:56:27 +03:00
|
|
|
|
if let (Some(v), Some(vert)) = (f64(value), leader.vertices.get_mut(0)) {
|
|
|
|
|
|
vert.y = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
feat(properties): conform entity property groups to PROPERTIES.md
Rewrite each entity's property builder to the per-entity group/row spec:
the correct sections (Geometry, Misc, Text, Pattern, Lines & Arrows, Leaders,
Block, …) with the spec's rows and real computed values — Diameter,
Circumference, Area, Delta X/Y/Z, Angle, Total angle, Arc length, Radius ratio,
etc. — plus apply routing for the editable rows.
Covers ~26 entities (Line, Circle, Arc, Point, Ellipse, Spline, polylines,
Ray/XLine, Insert, Text, MText, Hatch, Leader, MultiLeader, Tolerance, Solid,
Solid3D/Region/Body, meshes, MLine, Raster/Wipeout, Underlay, Table, Viewport,
Attribute, OLE). The 3D Visualization/Material group and the full Dimension
spec are deferred (they need document access for material/dimstyle name
resolution). Rows whose data is not in the pinned acadrust revision are shown
as empty placeholders, to be filled when the dependency is bumped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:03:18 +03:00
|
|
|
|
"vertex_z" => {
|
2026-03-22 14:56:27 +03:00
|
|
|
|
if let (Some(v), Some(vert)) = (f64(value), leader.vertices.get_mut(0)) {
|
|
|
|
|
|
vert.z = v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => {}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ── Transform ──────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
fn apply_transform(leader: &mut Leader, t: &EntityTransform) {
|
2026-06-16 11:33:46 +03:00
|
|
|
|
crate::scene::view::transform::apply_standard_entity_transform(leader, t, |entity, p1, p2| {
|
2026-03-22 14:56:27 +03:00
|
|
|
|
for v in &mut entity.vertices {
|
2026-06-16 11:33:46 +03:00
|
|
|
|
crate::scene::view::transform::reflect_xy_point(&mut v.x, &mut v.y, p1, p2);
|
2026-03-22 14:56:27 +03:00
|
|
|
|
}
|
2026-06-16 11:33:46 +03:00
|
|
|
|
crate::scene::view::transform::reflect_xy_point(
|
2026-03-22 14:56:27 +03:00
|
|
|
|
&mut entity.block_offset.x,
|
|
|
|
|
|
&mut entity.block_offset.y,
|
|
|
|
|
|
p1,
|
|
|
|
|
|
p2,
|
|
|
|
|
|
);
|
2026-06-16 11:33:46 +03:00
|
|
|
|
crate::scene::view::transform::reflect_xy_point(
|
2026-03-22 14:56:27 +03:00
|
|
|
|
&mut entity.annotation_offset.x,
|
|
|
|
|
|
&mut entity.annotation_offset.y,
|
|
|
|
|
|
p1,
|
|
|
|
|
|
p2,
|
|
|
|
|
|
);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ── Trait impls ────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
impl TruckConvertible for Leader {
|
|
|
|
|
|
fn to_truck(&self, _document: &acadrust::CadDocument) -> Option<TruckEntity> {
|
2026-05-12 10:36:15 +03:00
|
|
|
|
if self.vertices.is_empty() {
|
|
|
|
|
|
return None;
|
|
|
|
|
|
}
|
2026-03-22 14:56:27 +03:00
|
|
|
|
Some(to_truck(self))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat(grip): popup menus for polylines, spline, mline, hatch, leaders, text
Vocabulary added: AddFitPoint, RemoveFitPoint, Refit, RefineVertices,
TangentDirection, MoveWithText, StackText, UnstackText.
Polyline/Polyline2D/Polyline3D: vertex Add/Remove. MLine: same.
Spline: CV Add/Remove plus Refine Vertices (chord-midpoint insertion,
weights kept in sync, knots cleared so to_truck rebuilds uniform vec).
Hatch: centroid Origin/Angle/Scale (Angle and Scale prompt for value).
Leader: vertex Add/Remove (arrow + centroid stay Stretch-only).
MultiLeader: vertex Add/Remove Leader; MText location Move-with-Leader /
Move-Independent (menu live, structural edits stubbed). Text/MText:
Rotate prompts for degrees and sets rotation.
Spline, Leader, MultiLeader switched from impl_entity_basics! to manual
trait impls so grip_menu can be overridden.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 15:14:43 +03:00
|
|
|
|
impl crate::entities::traits::Grippable for Leader {
|
|
|
|
|
|
fn grips(&self) -> Vec<GripDef> {
|
|
|
|
|
|
grips(self)
|
|
|
|
|
|
}
|
|
|
|
|
|
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
|
|
|
|
|
|
apply_grip(self, grip_id, apply);
|
|
|
|
|
|
}
|
2026-06-16 11:33:46 +03:00
|
|
|
|
fn grip_menu(&self, grip_id: usize) -> Vec<crate::scene::model::object::GripMenuItem> {
|
|
|
|
|
|
use crate::scene::model::object::{GripMenuAction, GripMenuItem};
|
feat(grip): popup menus for polylines, spline, mline, hatch, leaders, text
Vocabulary added: AddFitPoint, RemoveFitPoint, Refit, RefineVertices,
TangentDirection, MoveWithText, StackText, UnstackText.
Polyline/Polyline2D/Polyline3D: vertex Add/Remove. MLine: same.
Spline: CV Add/Remove plus Refine Vertices (chord-midpoint insertion,
weights kept in sync, knots cleared so to_truck rebuilds uniform vec).
Hatch: centroid Origin/Angle/Scale (Angle and Scale prompt for value).
Leader: vertex Add/Remove (arrow + centroid stay Stretch-only).
MultiLeader: vertex Add/Remove Leader; MText location Move-with-Leader /
Move-Independent (menu live, structural edits stubbed). Text/MText:
Rotate prompts for degrees and sets rotation.
Spline, Leader, MultiLeader switched from impl_entity_basics! to manual
trait impls so grip_menu can be overridden.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 15:14:43 +03:00
|
|
|
|
let n = self.vertices.len();
|
|
|
|
|
|
if grip_id == 0 {
|
|
|
|
|
|
// Arrow head — stretch only.
|
2026-06-11 00:04:37 +03:00
|
|
|
|
vec![GripMenuItem {
|
|
|
|
|
|
label: "Stretch",
|
|
|
|
|
|
action: GripMenuAction::Stretch,
|
|
|
|
|
|
}]
|
feat(grip): popup menus for polylines, spline, mline, hatch, leaders, text
Vocabulary added: AddFitPoint, RemoveFitPoint, Refit, RefineVertices,
TangentDirection, MoveWithText, StackText, UnstackText.
Polyline/Polyline2D/Polyline3D: vertex Add/Remove. MLine: same.
Spline: CV Add/Remove plus Refine Vertices (chord-midpoint insertion,
weights kept in sync, knots cleared so to_truck rebuilds uniform vec).
Hatch: centroid Origin/Angle/Scale (Angle and Scale prompt for value).
Leader: vertex Add/Remove (arrow + centroid stay Stretch-only).
MultiLeader: vertex Add/Remove Leader; MText location Move-with-Leader /
Move-Independent (menu live, structural edits stubbed). Text/MText:
Rotate prompts for degrees and sets rotation.
Spline, Leader, MultiLeader switched from impl_entity_basics! to manual
trait impls so grip_menu can be overridden.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 15:14:43 +03:00
|
|
|
|
} else if grip_id < n {
|
|
|
|
|
|
vec![
|
2026-06-11 00:04:37 +03:00
|
|
|
|
GripMenuItem {
|
|
|
|
|
|
label: "Stretch",
|
|
|
|
|
|
action: GripMenuAction::Stretch,
|
|
|
|
|
|
},
|
|
|
|
|
|
GripMenuItem {
|
|
|
|
|
|
label: "Add Vertex",
|
|
|
|
|
|
action: GripMenuAction::AddVertex,
|
|
|
|
|
|
},
|
|
|
|
|
|
GripMenuItem {
|
|
|
|
|
|
label: "Remove Vertex",
|
|
|
|
|
|
action: GripMenuAction::RemoveVertex,
|
|
|
|
|
|
},
|
feat(grip): popup menus for polylines, spline, mline, hatch, leaders, text
Vocabulary added: AddFitPoint, RemoveFitPoint, Refit, RefineVertices,
TangentDirection, MoveWithText, StackText, UnstackText.
Polyline/Polyline2D/Polyline3D: vertex Add/Remove. MLine: same.
Spline: CV Add/Remove plus Refine Vertices (chord-midpoint insertion,
weights kept in sync, knots cleared so to_truck rebuilds uniform vec).
Hatch: centroid Origin/Angle/Scale (Angle and Scale prompt for value).
Leader: vertex Add/Remove (arrow + centroid stay Stretch-only).
MultiLeader: vertex Add/Remove Leader; MText location Move-with-Leader /
Move-Independent (menu live, structural edits stubbed). Text/MText:
Rotate prompts for degrees and sets rotation.
Spline, Leader, MultiLeader switched from impl_entity_basics! to manual
trait impls so grip_menu can be overridden.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 15:14:43 +03:00
|
|
|
|
]
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Centroid grip — move whole leader.
|
2026-06-11 00:04:37 +03:00
|
|
|
|
vec![GripMenuItem {
|
|
|
|
|
|
label: "Stretch",
|
|
|
|
|
|
action: GripMenuAction::Stretch,
|
|
|
|
|
|
}]
|
feat(grip): popup menus for polylines, spline, mline, hatch, leaders, text
Vocabulary added: AddFitPoint, RemoveFitPoint, Refit, RefineVertices,
TangentDirection, MoveWithText, StackText, UnstackText.
Polyline/Polyline2D/Polyline3D: vertex Add/Remove. MLine: same.
Spline: CV Add/Remove plus Refine Vertices (chord-midpoint insertion,
weights kept in sync, knots cleared so to_truck rebuilds uniform vec).
Hatch: centroid Origin/Angle/Scale (Angle and Scale prompt for value).
Leader: vertex Add/Remove (arrow + centroid stay Stretch-only).
MultiLeader: vertex Add/Remove Leader; MText location Move-with-Leader /
Move-Independent (menu live, structural edits stubbed). Text/MText:
Rotate prompts for degrees and sets rotation.
Spline, Leader, MultiLeader switched from impl_entity_basics! to manual
trait impls so grip_menu can be overridden.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 15:14:43 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-06-16 11:33:46 +03:00
|
|
|
|
fn apply_grip_menu(&mut self, grip_id: usize, action: crate::scene::model::object::GripMenuAction) {
|
|
|
|
|
|
use crate::scene::model::object::GripMenuAction as A;
|
feat(grip): popup menus for polylines, spline, mline, hatch, leaders, text
Vocabulary added: AddFitPoint, RemoveFitPoint, Refit, RefineVertices,
TangentDirection, MoveWithText, StackText, UnstackText.
Polyline/Polyline2D/Polyline3D: vertex Add/Remove. MLine: same.
Spline: CV Add/Remove plus Refine Vertices (chord-midpoint insertion,
weights kept in sync, knots cleared so to_truck rebuilds uniform vec).
Hatch: centroid Origin/Angle/Scale (Angle and Scale prompt for value).
Leader: vertex Add/Remove (arrow + centroid stay Stretch-only).
MultiLeader: vertex Add/Remove Leader; MText location Move-with-Leader /
Move-Independent (menu live, structural edits stubbed). Text/MText:
Rotate prompts for degrees and sets rotation.
Spline, Leader, MultiLeader switched from impl_entity_basics! to manual
trait impls so grip_menu can be overridden.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 15:14:43 +03:00
|
|
|
|
let n = self.vertices.len();
|
|
|
|
|
|
match action {
|
|
|
|
|
|
A::AddVertex if grip_id < n => {
|
|
|
|
|
|
let i1 = (grip_id + 1).min(n - 1);
|
|
|
|
|
|
if i1 == grip_id {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
let v0 = &self.vertices[grip_id];
|
|
|
|
|
|
let v1 = &self.vertices[i1];
|
|
|
|
|
|
let mid = acadrust::types::Vector3::new(
|
|
|
|
|
|
(v0.x + v1.x) * 0.5,
|
|
|
|
|
|
(v0.y + v1.y) * 0.5,
|
|
|
|
|
|
(v0.z + v1.z) * 0.5,
|
|
|
|
|
|
);
|
|
|
|
|
|
self.vertices.insert(i1, mid);
|
|
|
|
|
|
}
|
|
|
|
|
|
A::RemoveVertex if grip_id < n && n > 2 => {
|
|
|
|
|
|
self.vertices.remove(grip_id);
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => {}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl crate::entities::traits::PropertyEditable for Leader {
|
2026-07-02 22:46:19 +03:00
|
|
|
|
fn geometry_properties(&self, _text_style_names: &[String]) -> Vec<PropSection> {
|
feat(grip): popup menus for polylines, spline, mline, hatch, leaders, text
Vocabulary added: AddFitPoint, RemoveFitPoint, Refit, RefineVertices,
TangentDirection, MoveWithText, StackText, UnstackText.
Polyline/Polyline2D/Polyline3D: vertex Add/Remove. MLine: same.
Spline: CV Add/Remove plus Refine Vertices (chord-midpoint insertion,
weights kept in sync, knots cleared so to_truck rebuilds uniform vec).
Hatch: centroid Origin/Angle/Scale (Angle and Scale prompt for value).
Leader: vertex Add/Remove (arrow + centroid stay Stretch-only).
MultiLeader: vertex Add/Remove Leader; MText location Move-with-Leader /
Move-Independent (menu live, structural edits stubbed). Text/MText:
Rotate prompts for degrees and sets rotation.
Spline, Leader, MultiLeader switched from impl_entity_basics! to manual
trait impls so grip_menu can be overridden.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 15:14:43 +03:00
|
|
|
|
properties(self)
|
|
|
|
|
|
}
|
|
|
|
|
|
fn apply_geom_prop(&mut self, field: &str, value: &str) {
|
|
|
|
|
|
apply_geom_prop(self, field, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl crate::entities::traits::Transformable for Leader {
|
|
|
|
|
|
fn apply_transform(&mut self, t: &EntityTransform) {
|
|
|
|
|
|
apply_transform(self, t);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
refactor(tess): move per-entity tessellation into entities/
Each entity's tessellation now lives alongside its definition in
entities/*.rs, attached to the entity type via a local trait:
LegacyTess — Viewport / Insert / Hatch / Ole2Frame
(fallback path for entities not on the truck pipeline)
LeaderTess — Leader
MultiLeaderTess — MultiLeader
DimensionTess — Dimension (carries its dim-only helpers too:
~1700 lines of dim_geometry, dim_text_*, format_*,
tolerance, suppression, etc.)
scene/tessellate.rs keeps only the cross-entity dispatcher plus the
shared dim machinery reused by leader/multileader/dimension
(ArrowKind, DimGeom, append_arrow, arrow_from_block, add_segment,
add_polyline, normalized_or, push_tri, color_or_inherit, entity_z,
offset_snap_pts). Cross-entity arc helpers + aci_to_rgba moved to
scene/tess_util.rs.
scene/tessellate.rs shrinks from ~3300 to 809 lines. Compile clean,
all 9 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 23:12:27 +03:00
|
|
|
|
|
|
|
|
|
|
/// Per-entity tessellation entry for `Leader`. Lives here so all leader
|
|
|
|
|
|
/// tess code stays alongside the entity definition. Cross-entity dim
|
2026-06-16 11:33:46 +03:00
|
|
|
|
/// machinery (arrow shapes, `DimGeom`) lives in `scene::convert::tessellate` and
|
refactor(tess): move per-entity tessellation into entities/
Each entity's tessellation now lives alongside its definition in
entities/*.rs, attached to the entity type via a local trait:
LegacyTess — Viewport / Insert / Hatch / Ole2Frame
(fallback path for entities not on the truck pipeline)
LeaderTess — Leader
MultiLeaderTess — MultiLeader
DimensionTess — Dimension (carries its dim-only helpers too:
~1700 lines of dim_geometry, dim_text_*, format_*,
tolerance, suppression, etc.)
scene/tessellate.rs keeps only the cross-entity dispatcher plus the
shared dim machinery reused by leader/multileader/dimension
(ArrowKind, DimGeom, append_arrow, arrow_from_block, add_segment,
add_polyline, normalized_or, push_tri, color_or_inherit, entity_z,
offset_snap_pts). Cross-entity arc helpers + aci_to_rgba moved to
scene/tess_util.rs.
scene/tessellate.rs shrinks from ~3300 to 809 lines. Compile clean,
all 9 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 23:12:27 +03:00
|
|
|
|
/// is reused via the dim arrow emitter so the leader matches the active
|
|
|
|
|
|
/// DIMSTYLE.
|
|
|
|
|
|
pub trait LeaderTess {
|
|
|
|
|
|
fn tessellate(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
document: &acadrust::CadDocument,
|
|
|
|
|
|
handle: acadrust::Handle,
|
|
|
|
|
|
selected: bool,
|
|
|
|
|
|
entity_color: [f32; 4],
|
|
|
|
|
|
line_weight_px: f32,
|
|
|
|
|
|
anno_scale: f32,
|
2026-06-16 11:33:46 +03:00
|
|
|
|
) -> crate::scene::model::wire_model::WireModel;
|
refactor(tess): move per-entity tessellation into entities/
Each entity's tessellation now lives alongside its definition in
entities/*.rs, attached to the entity type via a local trait:
LegacyTess — Viewport / Insert / Hatch / Ole2Frame
(fallback path for entities not on the truck pipeline)
LeaderTess — Leader
MultiLeaderTess — MultiLeader
DimensionTess — Dimension (carries its dim-only helpers too:
~1700 lines of dim_geometry, dim_text_*, format_*,
tolerance, suppression, etc.)
scene/tessellate.rs keeps only the cross-entity dispatcher plus the
shared dim machinery reused by leader/multileader/dimension
(ArrowKind, DimGeom, append_arrow, arrow_from_block, add_segment,
add_polyline, normalized_or, push_tri, color_or_inherit, entity_z,
offset_snap_pts). Cross-entity arc helpers + aci_to_rgba moved to
scene/tess_util.rs.
scene/tessellate.rs shrinks from ~3300 to 809 lines. Compile clean,
all 9 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 23:12:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl LeaderTess for Leader {
|
|
|
|
|
|
fn tessellate(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
document: &acadrust::CadDocument,
|
|
|
|
|
|
handle: acadrust::Handle,
|
|
|
|
|
|
selected: bool,
|
|
|
|
|
|
entity_color: [f32; 4],
|
|
|
|
|
|
line_weight_px: f32,
|
|
|
|
|
|
anno_scale: f32,
|
2026-06-16 11:33:46 +03:00
|
|
|
|
) -> crate::scene::model::wire_model::WireModel {
|
|
|
|
|
|
use crate::scene::convert::tessellate::{append_arrow, arrow_from_block, ArrowKind, DimGeom};
|
|
|
|
|
|
use crate::scene::model::wire_model::WireModel;
|
refactor(tess): move per-entity tessellation into entities/
Each entity's tessellation now lives alongside its definition in
entities/*.rs, attached to the entity type via a local trait:
LegacyTess — Viewport / Insert / Hatch / Ole2Frame
(fallback path for entities not on the truck pipeline)
LeaderTess — Leader
MultiLeaderTess — MultiLeader
DimensionTess — Dimension (carries its dim-only helpers too:
~1700 lines of dim_geometry, dim_text_*, format_*,
tolerance, suppression, etc.)
scene/tessellate.rs keeps only the cross-entity dispatcher plus the
shared dim machinery reused by leader/multileader/dimension
(ArrowKind, DimGeom, append_arrow, arrow_from_block, add_segment,
add_polyline, normalized_or, push_tri, color_or_inherit, entity_z,
offset_snap_pts). Cross-entity arc helpers + aci_to_rgba moved to
scene/tess_util.rs.
scene/tessellate.rs shrinks from ~3300 to 809 lines. Compile clean,
all 9 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 23:12:27 +03:00
|
|
|
|
let color = if selected {
|
|
|
|
|
|
WireModel::SELECTED
|
|
|
|
|
|
} else {
|
|
|
|
|
|
entity_color
|
|
|
|
|
|
};
|
|
|
|
|
|
let name = handle.value().to_string();
|
|
|
|
|
|
let p3 = |v: &acadrust::types::Vector3| -> [f32; 3] {
|
2026-06-24 18:38:23 +03:00
|
|
|
|
[(v.x) as f32, (v.y) as f32, (v.z) as f32]
|
refactor(tess): move per-entity tessellation into entities/
Each entity's tessellation now lives alongside its definition in
entities/*.rs, attached to the entity type via a local trait:
LegacyTess — Viewport / Insert / Hatch / Ole2Frame
(fallback path for entities not on the truck pipeline)
LeaderTess — Leader
MultiLeaderTess — MultiLeader
DimensionTess — Dimension (carries its dim-only helpers too:
~1700 lines of dim_geometry, dim_text_*, format_*,
tolerance, suppression, etc.)
scene/tessellate.rs keeps only the cross-entity dispatcher plus the
shared dim machinery reused by leader/multileader/dimension
(ArrowKind, DimGeom, append_arrow, arrow_from_block, add_segment,
add_polyline, normalized_or, push_tri, color_or_inherit, entity_z,
offset_snap_pts). Cross-entity arc helpers + aci_to_rgba moved to
scene/tess_util.rs.
scene/tessellate.rs shrinks from ~3300 to 809 lines. Compile clean,
all 9 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 23:12:27 +03:00
|
|
|
|
};
|
|
|
|
|
|
let nan = [f32::NAN; 3];
|
|
|
|
|
|
|
|
|
|
|
|
let verts = &self.vertices;
|
|
|
|
|
|
|
|
|
|
|
|
if verts.len() < 2 {
|
|
|
|
|
|
return WireModel {
|
|
|
|
|
|
name,
|
|
|
|
|
|
points: vec![],
|
2026-06-23 17:08:54 +03:00
|
|
|
|
points_low: Vec::new(),
|
refactor(tess): move per-entity tessellation into entities/
Each entity's tessellation now lives alongside its definition in
entities/*.rs, attached to the entity type via a local trait:
LegacyTess — Viewport / Insert / Hatch / Ole2Frame
(fallback path for entities not on the truck pipeline)
LeaderTess — Leader
MultiLeaderTess — MultiLeader
DimensionTess — Dimension (carries its dim-only helpers too:
~1700 lines of dim_geometry, dim_text_*, format_*,
tolerance, suppression, etc.)
scene/tessellate.rs keeps only the cross-entity dispatcher plus the
shared dim machinery reused by leader/multileader/dimension
(ArrowKind, DimGeom, append_arrow, arrow_from_block, add_segment,
add_polyline, normalized_or, push_tri, color_or_inherit, entity_z,
offset_snap_pts). Cross-entity arc helpers + aci_to_rgba moved to
scene/tess_util.rs.
scene/tessellate.rs shrinks from ~3300 to 809 lines. Compile clean,
all 9 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 23:12:27 +03:00
|
|
|
|
color,
|
|
|
|
|
|
selected,
|
|
|
|
|
|
aci: 0,
|
|
|
|
|
|
pattern_length: 0.0,
|
|
|
|
|
|
pattern: [0.0; 8],
|
|
|
|
|
|
line_weight_px,
|
|
|
|
|
|
snap_pts: vec![],
|
|
|
|
|
|
tangent_geoms: vec![],
|
|
|
|
|
|
key_vertices: vec![],
|
|
|
|
|
|
aabb: WireModel::UNBOUNDED_AABB,
|
|
|
|
|
|
plinegen: true,
|
|
|
|
|
|
vp_scissor: None,
|
|
|
|
|
|
fill_tris: vec![],
|
2026-06-23 18:03:40 +03:00
|
|
|
|
fill_tris_low: Vec::new(),
|
refactor(tess): move per-entity tessellation into entities/
Each entity's tessellation now lives alongside its definition in
entities/*.rs, attached to the entity type via a local trait:
LegacyTess — Viewport / Insert / Hatch / Ole2Frame
(fallback path for entities not on the truck pipeline)
LeaderTess — Leader
MultiLeaderTess — MultiLeader
DimensionTess — Dimension (carries its dim-only helpers too:
~1700 lines of dim_geometry, dim_text_*, format_*,
tolerance, suppression, etc.)
scene/tessellate.rs keeps only the cross-entity dispatcher plus the
shared dim machinery reused by leader/multileader/dimension
(ArrowKind, DimGeom, append_arrow, arrow_from_block, add_segment,
add_polyline, normalized_or, push_tri, color_or_inherit, entity_z,
offset_snap_pts). Cross-entity arc helpers + aci_to_rgba moved to
scene/tess_util.rs.
scene/tessellate.rs shrinks from ~3300 to 809 lines. Compile clean,
all 9 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 23:12:27 +03:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let mut points: Vec<[f32; 3]> = verts.iter().map(|v| p3(v)).collect();
|
|
|
|
|
|
let mut tangents: Vec<TangentGeom> = Vec::new();
|
2026-06-23 22:23:56 +03:00
|
|
|
|
let key_vertices: Vec<[f64; 3]> = verts.iter().map(|v| [v.x, v.y, v.z]).collect();
|
refactor(tess): move per-entity tessellation into entities/
Each entity's tessellation now lives alongside its definition in
entities/*.rs, attached to the entity type via a local trait:
LegacyTess — Viewport / Insert / Hatch / Ole2Frame
(fallback path for entities not on the truck pipeline)
LeaderTess — Leader
MultiLeaderTess — MultiLeader
DimensionTess — Dimension (carries its dim-only helpers too:
~1700 lines of dim_geometry, dim_text_*, format_*,
tolerance, suppression, etc.)
scene/tessellate.rs keeps only the cross-entity dispatcher plus the
shared dim machinery reused by leader/multileader/dimension
(ArrowKind, DimGeom, append_arrow, arrow_from_block, add_segment,
add_polyline, normalized_or, push_tri, color_or_inherit, entity_z,
offset_snap_pts). Cross-entity arc helpers + aci_to_rgba moved to
scene/tess_util.rs.
scene/tessellate.rs shrinks from ~3300 to 809 lines. Compile clean,
all 9 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 23:12:27 +03:00
|
|
|
|
let mut fill_tris: Vec<[f32; 3]> = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
for i in 0..verts.len().saturating_sub(1) {
|
|
|
|
|
|
tangents.push(TangentGeom::Line {
|
|
|
|
|
|
p1: p3(&verts[i]),
|
|
|
|
|
|
p2: p3(&verts[i + 1]),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if self.arrow_enabled {
|
|
|
|
|
|
// Resolve the active dim style → DIMLDRBLK to pick the arrow shape.
|
|
|
|
|
|
// DIMASZ × DIMSCALE drives the size when available; otherwise fall
|
|
|
|
|
|
// back to the legacy text-height heuristic.
|
|
|
|
|
|
let style = document.dim_styles.iter().find(|s| {
|
|
|
|
|
|
s.name.eq_ignore_ascii_case(&self.dimension_style)
|
|
|
|
|
|
|| (self.dimension_style.trim().is_empty()
|
|
|
|
|
|
&& s.name.eq_ignore_ascii_case("Standard"))
|
|
|
|
|
|
});
|
|
|
|
|
|
let dim_scale = style
|
|
|
|
|
|
.map(|s| {
|
|
|
|
|
|
if s.dimscale > 1e-6 {
|
|
|
|
|
|
s.dimscale
|
|
|
|
|
|
} else {
|
|
|
|
|
|
anno_scale as f64
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.unwrap_or(anno_scale as f64);
|
|
|
|
|
|
let arrow_size = match style {
|
|
|
|
|
|
Some(s) => (s.dimasz * dim_scale) as f32,
|
2026-06-03 16:17:29 +03:00
|
|
|
|
None => (self.text_height as f32).max(1.0) * anno_scale,
|
refactor(tess): move per-entity tessellation into entities/
Each entity's tessellation now lives alongside its definition in
entities/*.rs, attached to the entity type via a local trait:
LegacyTess — Viewport / Insert / Hatch / Ole2Frame
(fallback path for entities not on the truck pipeline)
LeaderTess — Leader
MultiLeaderTess — MultiLeader
DimensionTess — Dimension (carries its dim-only helpers too:
~1700 lines of dim_geometry, dim_text_*, format_*,
tolerance, suppression, etc.)
scene/tessellate.rs keeps only the cross-entity dispatcher plus the
shared dim machinery reused by leader/multileader/dimension
(ArrowKind, DimGeom, append_arrow, arrow_from_block, add_segment,
add_polyline, normalized_or, push_tri, color_or_inherit, entity_z,
offset_snap_pts). Cross-entity arc helpers + aci_to_rgba moved to
scene/tess_util.rs.
scene/tessellate.rs shrinks from ~3300 to 809 lines. Compile clean,
all 9 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 23:12:27 +03:00
|
|
|
|
};
|
|
|
|
|
|
let arrow = match style {
|
|
|
|
|
|
Some(s) => arrow_from_block(document, s.dimldrblk, arrow_size.max(0.001)),
|
|
|
|
|
|
None => ArrowKind::Triangle {
|
|
|
|
|
|
size: arrow_size.max(0.001),
|
|
|
|
|
|
filled: true,
|
|
|
|
|
|
size_mul: 1.0,
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let tip = &verts[0];
|
|
|
|
|
|
let next = &verts[1];
|
|
|
|
|
|
let dx = (next.x - tip.x) as f32;
|
|
|
|
|
|
let dy = (next.y - tip.y) as f32;
|
|
|
|
|
|
let len = (dx * dx + dy * dy).sqrt().max(1e-9);
|
|
|
|
|
|
let dir = Vec3::new(dx / len, dy / len, 0.0);
|
|
|
|
|
|
let tip_f = p3(tip);
|
|
|
|
|
|
let tip_v = Vec3::new(tip_f[0], tip_f[1], tip_f[2]);
|
|
|
|
|
|
// Reuse the dim arrow emitter so the leader shape matches the
|
|
|
|
|
|
// DIMSTYLE in use (Closed Filled by default, Dot, Tick, …).
|
|
|
|
|
|
let mut arrow_pts: Vec<[f32; 3]> = Vec::new();
|
|
|
|
|
|
let mut arrow_geom = DimGeom::new();
|
|
|
|
|
|
append_arrow(&mut arrow_geom, tip_v, dir, &arrow);
|
|
|
|
|
|
if !arrow_geom.dim_lines.is_empty() {
|
|
|
|
|
|
arrow_pts.push(nan);
|
|
|
|
|
|
arrow_pts.extend(arrow_geom.dim_lines);
|
|
|
|
|
|
}
|
|
|
|
|
|
points.extend(arrow_pts);
|
|
|
|
|
|
fill_tris.extend(arrow_geom.arrow_fill);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if self.hookline_enabled {
|
|
|
|
|
|
let last = verts.last().unwrap();
|
|
|
|
|
|
let prev = &verts[verts.len() - 2];
|
|
|
|
|
|
let sign = if (last.x - prev.x) >= 0.0 {
|
|
|
|
|
|
1.0_f32
|
|
|
|
|
|
} else {
|
|
|
|
|
|
-1.0_f32
|
|
|
|
|
|
};
|
|
|
|
|
|
let land_len = self.text_height as f32 * 1.5 * anno_scale;
|
|
|
|
|
|
let last_f = p3(last);
|
|
|
|
|
|
points.push(nan);
|
|
|
|
|
|
points.push(last_f);
|
|
|
|
|
|
points.push([last_f[0] + sign * land_len, last_f[1], last_f[2]]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
WireModel {
|
|
|
|
|
|
name,
|
|
|
|
|
|
points,
|
2026-06-23 17:08:54 +03:00
|
|
|
|
points_low: Vec::new(),
|
refactor(tess): move per-entity tessellation into entities/
Each entity's tessellation now lives alongside its definition in
entities/*.rs, attached to the entity type via a local trait:
LegacyTess — Viewport / Insert / Hatch / Ole2Frame
(fallback path for entities not on the truck pipeline)
LeaderTess — Leader
MultiLeaderTess — MultiLeader
DimensionTess — Dimension (carries its dim-only helpers too:
~1700 lines of dim_geometry, dim_text_*, format_*,
tolerance, suppression, etc.)
scene/tessellate.rs keeps only the cross-entity dispatcher plus the
shared dim machinery reused by leader/multileader/dimension
(ArrowKind, DimGeom, append_arrow, arrow_from_block, add_segment,
add_polyline, normalized_or, push_tri, color_or_inherit, entity_z,
offset_snap_pts). Cross-entity arc helpers + aci_to_rgba moved to
scene/tess_util.rs.
scene/tessellate.rs shrinks from ~3300 to 809 lines. Compile clean,
all 9 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 23:12:27 +03:00
|
|
|
|
color,
|
|
|
|
|
|
selected,
|
|
|
|
|
|
aci: 0,
|
|
|
|
|
|
pattern_length: 0.0,
|
|
|
|
|
|
pattern: [0.0; 8],
|
|
|
|
|
|
line_weight_px,
|
|
|
|
|
|
snap_pts: vec![],
|
|
|
|
|
|
tangent_geoms: tangents,
|
|
|
|
|
|
key_vertices,
|
|
|
|
|
|
aabb: WireModel::UNBOUNDED_AABB,
|
|
|
|
|
|
plinegen: true,
|
|
|
|
|
|
vp_scissor: None,
|
|
|
|
|
|
fill_tris,
|
2026-06-23 18:03:40 +03:00
|
|
|
|
fill_tris_low: Vec::new(),
|
refactor(tess): move per-entity tessellation into entities/
Each entity's tessellation now lives alongside its definition in
entities/*.rs, attached to the entity type via a local trait:
LegacyTess — Viewport / Insert / Hatch / Ole2Frame
(fallback path for entities not on the truck pipeline)
LeaderTess — Leader
MultiLeaderTess — MultiLeader
DimensionTess — Dimension (carries its dim-only helpers too:
~1700 lines of dim_geometry, dim_text_*, format_*,
tolerance, suppression, etc.)
scene/tessellate.rs keeps only the cross-entity dispatcher plus the
shared dim machinery reused by leader/multileader/dimension
(ArrowKind, DimGeom, append_arrow, arrow_from_block, add_segment,
add_polyline, normalized_or, push_tri, color_or_inherit, entity_z,
offset_snap_pts). Cross-entity arc helpers + aci_to_rgba moved to
scene/tess_util.rs.
scene/tessellate.rs shrinks from ~3300 to 809 lines. Compile clean,
all 9 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 23:12:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|