Commit Graph
3970 Commits
Author SHA1 Message Date
HakanandClaude Sonnet 4.6 321433ee45 fix(render): cap wire segments to prevent GPU memory exhaustion
Adds two-layer protection against large entities crashing the renderer:
- MAX_SEGS_PER_WIRE (100K): per-entity hard cap, excess segments truncated
- MAX_TOTAL_SEGS (3M): scene-level budget in upload_wires, excess wires skipped

Both limits log a warning to stderr when triggered.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-07 17:24:28 +03:00
HakanandClaude Sonnet 4.6 4b4c0d31d2 chore: switch acadrust to GitHub source, fix removed is_annotative field
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-07 09:50:02 +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 Seven ca9ec8f47d fix(scene): bump geometry epoch after cache assignment on file open
populate_*_from_document() each called bump_geometry(); direct cache
assignment skipped it, leaving the wire cache stale on first open.
2026-05-06 23:10:35 +03:00
Hakan Seven d30f80f963 chore: suppress dead_code warning on compute_and_set_world_offset 2026-05-06 23:07:37 +03:00
Hakan Seven 2da3640b45 perf: build hatch/image/mesh caches off the UI thread
Parsing + DerivedCaches construction now runs entirely in a dedicated
OS thread inside open_path(). FileOpened handler only assigns the
pre-built caches, keeping the UI thread free during file load.

- Add build_derived_caches(): parallel hatch + mesh tessellation via rayon
- Extend Message::FileOpened / open_path return type with DerivedCaches
- Drop populate_*_from_document() calls from FileOpened handler
2026-05-06 23:04:53 +03:00
Hakan Seven 45f9f96c93 perf: implement L–S performance improvements
- L: pre-project wire endpoints to screen before ApparentIntersection pair loops
- O+S: tight per-segment AABB cull + move a0/a1 Vec3 outside inner snap loop
- P: epoch-cached entity→block reverse map replaces O(E×B) scan
- Q: lazy per-point projection in hit tests eliminates per-wire Vec<Point> alloc
- R: HatchModel.boundary Arc<Vec> so clone is pointer bump not heap alloc
2026-05-06 22:42:22 +03:00
Hakan SevenandClaude Sonnet 4.6 b83c982bc2 fix(scene): hatch pattern scale and per-entity annotative check
- Hatch pattern_scale multiplied by annotation_scale in model space so
  pattern density stays consistent when CANNOSCALE changes
- Annotative check now uses AcAnnoPO xdata (R2007+ marker) instead of
  relying solely on group-code-293 flag; falls back to is_annotative
  for files with no xdata (old DXF backward compat)
- acadrust patched to local path for is_annotative field

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-06 22:19:28 +03:00
HakanandClaude Sonnet 4.6 0e5dec0948 feat: annotation scale system (CANNOSCALE, PSLTSCALE, MultiLeader, Leader)
- Scale popup dropdown replaces cycle behavior; paper-space viewport scale
  editable when a viewport is active/selected
- CANNOSCALE persisted via DXF $USERR1 (read on open, write on save)
- PSLTSCALE: linetype dash lengths scaled by viewport anno_scale so dashes
  appear uniform physical size in paper space
- MultiLeader: arrow size, dogleg length, and text height scale with
  anno_scale; leader line paths (world coords) stay fixed
- Leader: arrow size and hookline length scale with anno_scale; also
  corrects world_offset subtraction that was previously deferred to the
  TruckObject::Lines path

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-06 17:50:46 +03:00
Hakan 534e4ff26b feat: implement Grippable and PropertyEditable traits for Solid3D, Region, and Body; add snap points and geometry properties 2026-05-06 10:00:37 +03:00
Hakan SevenandClaude Sonnet 4.6 899b3f4796 feat: GPU scissor rect for paper-space viewport wires
Viewport-projected wires now clip at pixel level to their viewport boundary.

- WireModel.vp_scissor: Option<[f32; 4]> — paper-space bbox set on projection
- WireGpu.vp_scissor carries it through to the draw loop
- Pipeline.compute_wire_scissors() converts paper→NDC→pixel each frame
- render() calls set_scissor_rect() per wire, reset after viewport group
- INTEGRATION_GAPS.md: Viewport ⚠️ → ✅, all 51 gaps resolved

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-06 07:12:05 +03:00
Hakan SevenandClaude Sonnet 4.6 27aca41dd1 feat: plinegen + SAB parsing for Solid3D/Region/Body
LwPolyline PLINEGEN=0 (DXF default): emit SegmentedLines with NaN
separators between vertex-to-vertex segments; wire_gpu resets
arc-length to 0 after each NaN so linetype pattern restarts per vertex.
PLINEGEN=1: existing Contour path unchanged (continuous pattern).
WireModel gains plinegen field propagated through tessellate pipeline.

Solid3D/Region/Body: call SabReader::read() when parse_sat() returns
None due to binary SAB format (DWG files / newer AutoCAD exports).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-06 06:55:28 +03:00
Hakan SevenandClaude Sonnet 4.6 63b17547f9 fix: warn on missing non-ASCII CXF glyphs; close ellipse snap gap
cxf.rs: missing non-ASCII glyphs now emit eprintln! once per font+char
pair via a global Mutex<HashSet> dedup set. ASCII chars silent (expected).

INTEGRATION_GAPS.md: ellipse partial arc snap marked done — endpoints are
correctly emitted via key_vertices → SnapType::Endpoint in snap engine.
Unicode warning gap closed. plinegen behaviour documented.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-05 20:20:16 +03:00
Hakan SevenandClaude Sonnet 4.6 f000a8acfb 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]>
2026-05-05 20:12:44 +03:00
Hakan SevenandClaude Sonnet 4.6 fe954fa3ff feat: extrude LwPolyline and Polyline2D thickness along WCS normal
Tessellates bottom + top paths with NaN-separated walls at each vertex.
Arc segments (bulge != 0) use 16-step parametric tessellation.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-05 20:06:35 +03:00
Hakan Seven 603d07412e refactor: replace angle calculations with radians for consistency 2026-05-03 21:58:38 +03:00
Hakan Seven d7422b9396 fix: store arc angles in radians 2026-05-03 20:14:28 +03:00
Hakan Seven 1b4c5e13e5 fix: keep open drawing when creating new file 2026-05-03 19:55:38 +03:00
Hakan SevenandClaude Sonnet 4.6 c51eeb4ad0 feat: extrude Arc and Circle thickness along WCS normal
Arc: tessellates bottom + top arcs (32 segs each) with 2 endpoint walls.
Circle: tessellates bottom + top circles (64 segs each) with 4 quadrant walls.
Both use TruckObject::Lines with NaN-separated segments.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 20:30:30 +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 9b29db61d4 feat: apply OCS→WCS transform to Hatch wire outline boundary edges
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 20:24:38 +03:00
Hakan SevenandClaude Sonnet 4.6 4527819b2d chore: remove stale multi-viewport limitation comment from ViewportPaneMode
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 20:18:08 +03:00
Hakan SevenandClaude Sonnet 4.6 9dcb5ad718 feat: apply OCS→WCS to Text and Attribute insertion snap points
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 20:06:22 +03:00
Hakan SevenandClaude Sonnet 4.6 5297aea001 feat: apply OCS→WCS transform for Polyline2D (elevation + normal)
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 20:04:30 +03:00
Hakan SevenandClaude Sonnet 4.6 ece2069c9d feat: apply clip_boundary outline for RasterImage when clipping enabled
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 20:01:21 +03:00
Hakan SevenandClaude Sonnet 4.6 645737b3f9 feat: add Node snap points for MLine vertices
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 19:59:37 +03:00
Hakan SevenandClaude Sonnet 4.6 60be861cbe feat: add Node snap points for MultiLeader vertices and connection points
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 19:59:11 +03:00
Hakan SevenandClaude Sonnet 4.6 f4160c4e8a feat: apply OCS→WCS transform for LwPolyline (elevation + normal)
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 19:56:23 +03:00
Hakan SevenandClaude Sonnet 4.6 e64eb0f463 feat: apply correct OCS→WCS transform for Ellipse entity
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 17:20:25 +03:00
Hakan SevenandClaude Sonnet 4.6 3c414f43a3 feat: apply OCS→WCS transform for Point entity
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 17:18:54 +03:00
Hakan SevenandClaude Sonnet 4.6 5a7ebbbb38 feat: add Node snap points to dimension defpoints
Dimension measurement origin points (first_point, second_point,
definition_point, angle_vertex, etc.) are now emitted as Node snap
hints so OSNAP Node mode can locate them precisely without relying on
the tessellated geometry wire alone.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 17:15:41 +03:00
Hakan SevenandClaude Sonnet 4.6 000f74f951 feat: render CircularArc and EllipticArc hatch boundary edges
Hatch boundaries with arc or ellipse edges were silently dropped from
the wire outline, leaving gaps in the hatch contour. CircularArc and
EllipticArc boundary edges are now tessellated as polyline segments and
their centers are emitted as Center snap hints.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 17:15:02 +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 SevenandClaude Sonnet 4.6 7b7186a470 feat: use rational NURBS (NurbsCurve) when spline weights are present
Splines backed by rational NURBS (circles, conics) were tessellated as
uniform B-splines, losing the weighting that defines the curve shape.
Now BSplineCurve<Point3> is used only when weights are absent or empty;
when weight data is present a NurbsCurve<Vector4> is built from the
homogeneous control points so circles and conics render accurately.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 17:10:38 +03:00
Hakan SevenandClaude Sonnet 4.6 c7b050fb09 feat: emit Insertion snap point for block references
Block INSERTs are expanded into sub-entity wires for rendering but the
OSNAP Insertion hint at the block reference origin was never generated.
Now a zero-geometry WireModel carrying the Insertion snap hint is appended
so OSNAP Insertion mode can locate the block origin.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 17:08:20 +03:00
Hakan SevenandClaude Sonnet 4.6 2eb19a21bb fix: identify DWG sheet viewport by center=(0,0) instead of scale heuristic
Debug output revealed the sheet viewport has id=0 (DWG reader never sets
the field), scale=0.8965 (not ≈1.0, so the 0.02 tolerance missed it),
and center=(0.0, 0.0) — exactly at the paper-space origin.

In DWG format the overall/sheet viewport always has its center at the
origin. Content viewports are placed at their actual paper positions and
always have a non-zero center. Switching from the scale heuristic to the
center-position check makes the detection reliable regardless of what
scale value the sheet viewport happens to carry.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 15:15:13 +03:00
Hakan SevenandClaude Sonnet 4.6 b346eb4d6e fix: remove dead code warning and fix sheet viewport double-click in DWG files
Remove unused `screen_delta_to_world` camera method (superseded by the
corrected pan_active_viewport formula).

Fix `is_content_viewport`: the old geometry fallback required the viewport
center to be near the origin, but DWG files never write the viewport id
field (stays 0) and the sheet viewport center is the paper centre
(e.g. 105, 148.5 mm for A4) — not the origin. This caused the sheet
viewport to be classified as a content viewport in DWG files, making it
both tessellated (border visible) and enterable via double-click.

The new heuristic uses only the scale: a sheet viewport has scale ≈ 1:1
(view_height ≈ paper height); true content viewports have deliberate
drawing scales (1:50, 1:100, …) that are far from 1.0.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-02 14:55:12 +03:00
Hakan SevenandClaude Sonnet 4.6 fbb6a20f10 fix: correct MSPACE viewport pan speed to match mouse movement
The old formula (distance × 0.001) was a fixed approximation that ignored
the paper camera's current zoom level and the viewport's paper-space size,
causing panning to feel sluggish.

New formula: model_per_pixel = (2 × paper_half_h / canvas_height) × (view_height / vp_height)
This converts screen pixels → paper-space mm → model units correctly,
making the content follow the cursor regardless of paper zoom or scale.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-01 21:39:05 +03:00
Hakan SevenandClaude Sonnet 4.6 2434427583 fix: viewport grip resize preserves scale instead of zooming content
When a corner grip is dragged, view_height is now updated proportionally
with the new frame height so that scale = height/view_height stays constant.
The visible model-space area grows/shrinks with the frame instead of the
content appearing to zoom.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-01 21:26:02 +03:00
Hakan SevenandClaude Sonnet 4.6 49d5cf1c61 feat: disable OSNAP by default
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-01 21:22:01 +03:00
Hakan SevenandClaude Sonnet 4.6 928e7df274 fix: don't add model-space world_offset to paper-space grip absolute positions
GripApply::Absolute adds world_offset to convert local-space coordinates
back to DXF space for model-space entities. Paper-space entities (viewports,
etc.) use sheet mm coordinates with no world_offset, but the grip drag code
was unconditionally adding scene.world_offset — causing grips to jump by the
full model-space centroid offset (potentially hundreds of km for UTM drawings).

Now world_offset is only applied when current_layout == "Model".

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-01 21:19:09 +03:00
Hakan SevenandClaude Sonnet 4.6 93614ab554 fix: apply global LTSCALE to linetype pattern rendering
Entity linetype_scale is a per-entity multiplier applied on top of the
document-level $LTSCALE header variable. The previous code used only the
entity scale (defaulting to 1.0), ignoring $LTSCALE entirely. Drawings
with a non-default LTSCALE showed dash patterns at the wrong size.

Effective scale is now: document.header.linetype_scale * entity linetype_scale.
Applied in both render::render_style_for and the complex-linetype path in
tessellate_entity.

Fixes part of #10

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-01 21:13:56 +03:00
Hakan SevenandClaude Sonnet 4.6 ebef467720 fix: hide sheet viewport border and improve crossing selection
Two layout-related fixes:

1. Sheet viewport (id=1) was rendered as a grey rectangle border in
   paper-space layouts. It is the paper boundary, not a user viewport,
   and should not appear. Now filtered via is_content_viewport() before
   tessellation. The redundant id==1 color branch is removed.

2. Box crossing-selection (right-to-left drag) only detected wires whose
   vertex points fell inside the selection box. Large entities like viewport
   frames could be visually crossed without any corner inside the box and
   would not be selected. Added segment-box edge intersection tests so any
   wire segment that crosses the selection rectangle boundary is included.

Fixes part of #10

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-01 21:12:14 +03:00
Hakan SevenandClaude Sonnet 4.6 c0ee0d6edc fix: MODEL button in MSPACE now returns to paper space instead of Model tab
When editing inside a viewport (MSPACE), the status bar MODEL button was
sending LayoutSwitch("Model") which switched the entire layout to the
Model tab. The intended behavior (and what the comment documented) is
ExitViewport — just exit the active viewport back to PSPACE.

Fixes part of #10

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-01 21:06:41 +03:00
Hakan SevenandClaude Sonnet 4.6 7b7622910c fix: apply world_offset when committing interactively created entities
Commands receive click coordinates in local space (DXF coords minus
world_offset) for camera precision. Without correction, entities were
placed world_offset away from the clicked position in existing drawings
that have a non-zero centroid (e.g. UTM-coordinate drawings).

Re-add world_offset via acadrust::Transform::from_translation (f64
precision) in commit_entity before the entity is inserted into the
DXF document. Paper-space entities are exempt as they use sheet coords.

Fixes #11

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-01 21:00:27 +03:00
Hakan SevenandClaude Sonnet 4.6 7e8fc8ef88 feat: replace rfd Save As with native iced file chooser
Implements a full in-app file browser window for Save As, replacing the
rfd dialog that could not expose the selected filter index on Linux.
The new chooser includes directory navigation, a scrollable file list,
filename input, and a format drop-down (DWG/DXF × 2018/2013/2010/2007/2004/2000/R14).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-01 16:20:38 +03:00
Hakan SevenandClaude Sonnet 4.6 9cd8eff77f fix: replace broken version filters with custom Save As dialog
rfd does not expose the selected filter index, so the old DWG/DXF version
filters had no effect — every file was always saved as AC1032 (R2018).

Replace with a single custom iced Save As window that shows:
- File name text input
- Save-in folder input + Browse button (rfd folder picker)
- Format dropdown: DWG/DXF × 2018/2013/2010/2007/2004/2000/R14
- Save / Cancel buttons

The selected format is passed to save_as_version() which temporarily sets
doc.version before writing, so DwgWriter/DxfWriter emit the correct file
format. Also works in the unsaved-changes Save flow.

Closes #9

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-01 16:12:32 +03:00
Hakan SevenandClaude Sonnet 4.6 01943c5b8d fix: correct paper-space grip projection and MTEXT attachment point rendering
- Grip points in paper space now use the 2-D linear to_px transform
  (tx/ty/ortho_size) instead of the 3-D view_proj matrix, matching the
  coordinate system used by PaperCanvas
- world_offset is no longer subtracted from paper-space entity grip
  positions — paper-space coordinates are already unoffset (same rule
  as wire tessellation in wires_for_block)
- MTEXT v_offset corrected for all attachment points: CXF glyphs sit
  on the baseline and extend upward, so Top attachment needs v_offset=-h,
  Bottom needs (n_lines-1)*line_h, Middle is the midpoint of the two

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-01 12:16:46 +03:00
Hakan SevenandClaude Sonnet 4.6 3009639741 fix: decode all MTEXT escape codes correctly
Previously \\U+XXXX was in the "strip until ;" list, silently dropping
all Unicode character references (°, ±, ⌀, Ø, €, …).

Changes:
- \\U+XXXX / \\u+XXXX  decode to the actual Unicode character (was stripped)
- \\S upper/lower;     stacked fractions/tolerances render as "upper/lower"
                       or "upper^lower" instead of leaking as literal text
- \\t                  tab → four spaces (was leaking as literal 't')
- Unknown escapes      silently consume the code char (was leaking it)
- \\M+...;             DBCS multibyte — stripped (added to semicolon-arg list)
- \\X                  paragraph-align end marker — stripped cleanly

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-01 11:51:45 +03:00
Hakan SevenandClaude Sonnet 4.6 c5c5ba1b60 fix: correct MTEXT line spacing and preserve blank paragraph separators
Line spacing: DXF code 44 (line_spacing_factor) is a multiplier on
AutoCAD's default baseline-to-baseline distance of 5/3 × text_height.
The renderer was using factor × 1.0 instead of factor × 1.667, making
all MTEXT appear cramped.

Blank paragraphs: split_mtext_lines was filtering out empty strings, so
\\P\\P (double paragraph break used to separate sections) was silently
collapsed. Empty lines in the middle of the block are now preserved;
only leading/trailing blank lines are stripped.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-01 11:48:06 +03:00