Commit Graph
15 Commits
Author SHA1 Message Date
Hakan SevenandClaude Opus 4.8 b9cebab951 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 <[email protected]>
2026-07-02 23:03:18 +03:00
Hakan SevenandClaude Opus 4.8 b2b2bfb246 refactor(properties): entity property groups return Vec<PropSection>
Groundwork for making the Properties panel conform to the per-entity group/row
spec (PROPERTIES.md). The panel already renders a Vec of sections, but each
entity could only express a single geometry section.

Change PropertyEditable::geometry_properties (and the EntityTypeOps enum
dispatch) to return Vec<PropSection>, update the two impl macros, and flatten
in properties_sectioned so the panel shows [General] + the entity's groups.
Every entity builder is wrapped to return its existing section as a one-element
Vec — pure mechanical change, no rows or titles altered, panel output identical.

Enables Phase 2: rewriting each entity's groups/rows to match the spec.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-02 22:46:19 +03:00
Hakan SevenandClaude Opus 4.8 7fe7e0230d refactor(scene): group modules into role-based subfolders
Move the 30 flat modules under src/scene/ into six folders by role:
convert (entity→geometry), text (fonts/shaping), model (render models),
pick (hit-test/selection/grips/xclip), view (camera/transform/render),
cache (block + property caches). pipeline/ is unchanged.

Full path migration — all `scene::X` references become
`scene::<group>::X`, no compatibility re-exports. render.rs items that
were `pub(super)` (parent was scene) become `pub(in crate::scene)` to
keep their original scene-wide visibility.

No behavior change; build and tests are green.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-16 11:33:46 +03:00
Hakan SevenandClaude Opus 4.8 25715d1b03 fix(grips): compute grip positions in f64 so they sit on the wire
Grip markers drew visibly offset from the entity on large-coordinate
(UTM-scale) drawings: every Grippable impl cast the f64 entity coordinates
to f32 BEFORE the world-offset subtraction, and at 1e7 magnitude an f32
holds ~0.9 drawing units of rounding error. The wires subtract the offset
in f64 first (precision-preserving), so the grips landed up to ~1 unit
away from the geometry they belong to.

GripDef.world is now DVec3: producers fill it straight from the f64
entity data, refresh_selected_grips subtracts the world offset in f64,
and only the small offset-local result is cast to f32 for screen-space
projection (grips_to_screen / find_hit_grip) and drag state.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 00:04:37 +03:00
Hakan Seven 559cd76369 feat(grip): value-prompt actions Lengthen/Radius/Arc Length
Lengthen / Radius / Arc Length need a number after the pick. Stash
`grip_pending` on the picked action, push prompt to command line,
route next `CommandSubmit` parse into `apply_grip_menu_value`.
Escape cancels.

- `Grippable::grip_menu_value_prompt` returns label when action
  wants value; `apply_grip_menu_value` runs the edit. Dispatched
  via `EntityTypeOps`.
- Line: Lengthen extends either endpoint along line direction.
- Arc: Radius sets radius; Arc Length redrives end angle from
  `value / radius`; Lengthen extends start / end angle the same
  way.
2026-05-29 14:58:35 +03:00
Hakan Seven a4c65649e1 feat(grip): entity-specific popup menus for Line/Arc/Dimension
- Line: endpoint grips expose Stretch + Lengthen; midpoint exposes
  Stretch only.
- Arc: endpoint exposes Stretch + Lengthen; midpoint exposes
  Stretch + Radius + Arc Length; centre exposes Stretch.
- Dimension text grip exposes the full text-position vocabulary
  (Move with Dim Line / with Leader / Independent, Reset Text,
  Rotate Text, Above Dim Line, Center). Dim-line-position grip
  exposes Stretch + Reverse Arrows. Extension origins keep the
  default Stretch.
- Each affected entity drops `impl_entity_basics!` and writes the
  three trait impls (Grippable, PropertyEditable, Transformable)
  manually so `grip_menu` / `apply_grip_menu` can override.
- `apply_grip_menu` handles Reset Text (clear text override) and
  Center (snap text to midpoint of extension origins) inline;
  remaining actions stub to no-op pending the follow-up
  prompt / drag plumbing.
2026-05-29 09:46:05 +03:00
Hakan Seven 5755c2e130 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
Hakan SevenandClaude Opus 4.7 9b5073752d refactor(entities): collapse trait wrapper boilerplate via macro
Every entity file ended with the same three-trait wrapper block:

    impl Grippable for T {
        fn grips(&self) -> Vec<GripDef> { grips(self) }
        fn apply_grip(&mut self, ...) { apply_grip(self, ...) }
    }
    impl PropertyEditable for T { ... }
    impl Transformable for T { ... }

— 23 lines of pure delegation around five same-named free functions.

Replace with `crate::impl_entity_basics!(T);` (a macro in
entities/traits.rs that expands to the three trait impls).

Applied where the file already follows the free-fn delegation
convention (Arc, Circle, Ellipse, Insert, Leader, Line, LwPolyline,
MultiLeader, Ole2Frame, Point, Spline, Viewport). Files that inlined
the trait method bodies directly (Ray, XLine, Shape, Solid, Tolerance,
MLine, Mesh, Solid3D/Region/Body, Table, RasterImage, Wipeout,
Underlay, Hatch, Polyline, Polyline2D, Polyline3D, Dimension) left
alone — they already skip the indirection. Text/MText/Attribute use
the with-text-style flavour and will move once that variant is needed
beyond the existing two manual impls.

A second macro `impl_entity_basics_with_text_styles!` is included for
the text-like flavour but no entity uses it yet.

Net: -204 lines.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-26 17:16:06 +03:00
Hakan SevenandClaude Opus 4.7 e78321190a refactor(commands): per-entity MassProps + TextContent traits
Two free helpers in app/commands.rs lived as big match-on-EntityType
blocks: massprop_entity (Circle/Arc/Line/LwPolyline/Ellipse area +
perimeter + centroid, ~140 lines) and entity_text_content /
replace_entity_text (Text/MText/AttributeDefinition/AttributeEntity).

Move each to its own trait in entities/traits.rs and implement
per-entity:

  MassPropsCalc  — Circle, Arc, Line, LwPolyline, Ellipse
  TextContent    — Text, MText, AttributeDefinition, AttributeEntity

EntityTypeOps gets dispatch shims that route to the trait via the
existing macro, so callsites just call entity.mass_props() /
entity.text_content() / entity.replace_text(search, rep).

The remaining free helpers in commands.rs (entity_list_details,
entity_extra_info, entity_type_name, build_data_extraction_csv) are
single-command formatting helpers tightly coupled to LIST / EXTRACT /
text-format output. Distributing them as per-entity methods would
inflate every entity file with command-side formatting concerns
without making the command-side any cleaner — left in place.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-23 23:30:34 +03:00
Hakan Seven 288ccff95a fix(render): preserve f64 precision until world_offset subtraction
Entity converters were casting WCS coordinates to f32 before the renderer
subtracted world_offset, which destroyed sub-unit precision on drawings
sitting at large coordinates (typical UTM-style CAD files). The multileader
case made it visible — glyphs warped under rotation — but every entity
that emits TruckObject::Lines/SegmentedLines/key_vertices/fill_tris was
affected.

Type changes (in src/scene/acad_to_truck.rs):
- TruckObject::Lines / SegmentedLines: Vec<[f32; 3]> → Vec<[f64; 3]>
- TruckEntity::key_vertices / fill_tris: f32 → f64

All ~17 producer files updated to keep WCS coordinates in f64 right up to
the TruckEntity boundary. The consumer in scene/tessellate.rs now performs
`(x - ox) as f32` (f64 subtract, then cast) for points, key_vertices, and
fill_tris — preserving precision near the camera origin even when the
drawing sits at million-unit coordinates.

catmull_rom_pts (multileader spline) is now f64; the scene path widens its
offset-relative f32 ctrl points to f64 around the call and narrows back at
the output.

Notes:
- Table layout still uses glam::Vec3 (f32) internally; widened to f64 only
  at the TruckEntity boundary for type compatibility. Separate cleanup to
  switch its internal math to f64 is tracked.
- snap_pts and tangent_geoms remain f32 — they are UI feedback (snap
  candidates, tangent hints) and the precision is sufficient there.
2026-05-12 23:47:40 +03:00
Hakan ca07268c7c cargo fmt 2026-05-12 10:36:15 +03:00
Hakan Seven 048bb41aef feat(render): solid fill for PolyfaceMesh and PolygonMesh entities
PolyfaceMesh and PolygonMesh were wireframe-only. They now render with
the same flat-color solid fill as Face3D entities.

- Add fill_tris: Vec<[f32;3]> to TruckEntity and WireModel
- PolyfaceMesh: fan-triangulate each face into fill_tris
- PolygonMesh: triangulate each grid quad into fill_tris
- tessellate.rs Lines branch: apply world_offset to fill_tris
- Face3DGpu::from_wires: collect fill_tris from all wires in addition
  to Face3D key_vertices quads
- upload_face3d: pass all_wires so fill_tris are batched into one draw call
2026-05-06 23:24:26 +03:00
Hakan SevenandClaude Sonnet 4.6 ce17e8abdf feat: extrude Line thickness along WCS normal
When line.thickness != 0, renders 4 NaN-separated wire segments
(bottom, top, left wall, right wall) using TruckObject::Lines.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 20:27:15 +03:00
Hakan SevenandClaude Sonnet 4.6 674a94f756 feat: implement OCS→WCS transform for Arc, Circle, and Line
Entities carrying a non-standard extrusion normal (normal ≠ (0,0,1)) were
rendered flat in the XY plane. The DXF arbitrary-axis algorithm is now
implemented in scene::transform::{ocs_axes, ocs_point_to_wcs} and applied
during tessellation of Arc, Circle, and Line so they render correctly on
tilted planes in 3D DXF files.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 17:13:42 +03:00
Hakan Seven d2fdac7f1e first commit 2026-03-22 14:56:27 +03:00