Commit Graph
3405 Commits
Author SHA1 Message Date
Christopher OverbeckandClaude Fable 5.1 dbdddb7dc2 feat(app): record accepted snaps per point step and guard dimension inference
Point input now keeps an `AcceptedSnap` alongside each point a command
collects: the paper point, the model point it came from, the viewport and
frame it was seen through, and the geometry identity the snap engine
attributed. Interactive picks record in the click handler, typed / dynamic /
headless points record in `feed_command`, and the list is cleared whenever a
command starts or the active space changes. Commands that don't care keep
consuming the plain paper point unchanged; PR2 reads the model point and
frame, PR3 the source.

Dimension association inference is suppressed when the dimension's points came
through a viewport. Inference matches geometry against the dimension's own
definition points in whatever space it is handed, so paper definition points
projected from a viewport would associate with unrelated paper-sheet geometry
at those coordinates, or match model geometry using paper coordinates. An
empty source list makes `attach_dimension_association` a no-op. PR3 replaces
this with real viewport-aware associations.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 12:27:33 -05:00
Christopher OverbeckandClaude Fable 5.1 6def465ba5 feat(snap): snap paper space through layout viewports
Paper-space commands could not pick model geometry displayed by a layout
viewport: `hit_test_wires` deliberately excludes viewport content in PSPACE,
and that has to stay true for selection. This adds the capability as a separate
query rather than by changing those semantics.

`OpenCADStudio::paper_viewport_snap` walks the current layout's displayed
content viewports top-most first, skips those whose display is off or whose
clip boundary excludes the cursor, and for each one runs the EXISTING snap
engine against that viewport's model wires using the viewport's own camera and
screen rectangle (`viewport_edit_frame_for`). The accepted model point is
mapped back onto the sheet with `ViewportFrame::model_to_paper`, so everything
downstream keeps working in paper coordinates — LINE still draws at the
projected paper point. Grid snap and the paper-space rubber-band origin are
suppressed for that pass; results outside the clip are rejected so no snap
lands on a clip cut. Locked viewports snap like unlocked ones.

No projected geometry is rebuilt per pointer event: the wire set is the
renderer's resident per-viewport Arc (`model_wires_for_viewport_arc`) and the
broad phase reuses the shared interaction index over it.

The result is merged with the ordinary paper-sheet snap by `snap::merge_snap`,
which applies the engine's own priority-then-distance rule, in both the
cursor-move and the click paths.

`SnapResult` gains Copy fields `viewport: Option<Handle>` and
`source: Option<DimensionAssociationSource>`; the engine fills `source` from
the owning wire wherever it knows it. `AcceptedSnap::from_snap` converts a
result plus frame into the shared PR2/PR3 contract type.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 12:27:25 -05:00
Christopher OverbeckandClaude Fable 5.1 53576fabdf feat(scene): build a planar ViewportFrame from a layout viewport's live camera
`Scene::viewport_frame` derives the paper<->model mapping (paper_center,
model_target, paper-per-model scale, in-plane twist, lock state) from
`camera_for_viewport` — the same camera the renderer displays the viewport's
contents with — so a snap computed through the frame lands on the pixels the
GPU drew. Oblique / mirrored / perspective viewports return None.

Also generalises the MSPACE editing adapter: `viewport_edit_frame_for(handle)`
returns the camera + screen rect for any viewport, and `viewport_edit_frame`
becomes a wrapper over it for the active one. Adds
`viewport_displays_paper_point` (rectangular bounds plus a non-rectangular clip
boundary polygon, tested in paper coordinates) and public accessors for the
layout's content viewports and their VP ON state.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 12:27:13 -05:00
Christopher OverbeckandClaude Fable 5.1 49fe48f89c Add shared viewport frame, accepted snap, and measurement scale interfaces
Contract module for the viewport snapping, viewport dimension measurement,
and dimension association work that builds on it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 12:10:28 -05:00
Christopher Overbeck 37cfa06b02 Preserve fractional viewport placement when compositing paper space
Keep fractional raster placement and matching integer texture coverage
through compositing. Apply parent clipping without changing the scale.

Fixes #1267
2026-09-14 17:07:57 -05:00
Hakan Seven 7aff9fa046 ui(parametric): enlarge constraint ribbon tools 2026-09-14 21:18:11 +03:00
Hakan Seven caec8dc53b Merge remote-tracking branch 'origin/main' 2026-09-14 20:24:54 +03:00
Hakan Seven c9350d7b7b fix(web): disable unsupported folder picker 2026-09-14 20:24:34 +03:00
Hakan Seven 6c0badbdc8 fix: resolve annotation pull request findings 2026-09-14 20:16:46 +03:00
Hakan Seven 293d0796fb Merge pull request #1246 2026-09-14 19:58:35 +03:00
Hakan Seven f2fd2ae5ad fix: address open pull request review findings 2026-09-14 19:58:35 +03:00
Hakan Seven 2d20bdd51c Merge pull request #1251 2026-09-14 19:51:57 +03:00
Hakan Seven f79594db38 Merge pull request #1260 2026-09-14 19:49:24 +03:00
Hakan Seven b48157a5af Merge pull request #1258 2026-09-14 19:49:24 +03:00
Hakan Seven 05baa82241 Merge pull request #1256 2026-09-14 19:49:24 +03:00
Hakan Seven 17f345953e Merge pull request #1253 2026-09-14 19:49:24 +03:00
Hakan Seven 61289bfa60 Merge pull request #1252 2026-09-14 19:49:24 +03:00
Hakan Seven b58d21a2c9 Merge pull request #1250 2026-09-14 19:49:24 +03:00
Hakan Seven ddabc2658a Merge pull request #1249 2026-09-14 19:49:24 +03:00
Karim Jerbi a0d784502a feat(ui): modernize DSETTINGS dialog with tabbed layout and action controls
- Redesign drafting settings window to landscape 700x480 proportions while preserving interactive resizing
- Add 7-tab navigation: Snap and Grid, Polar Tracking, Object Snap, 3D Object Snap, Dynamic Input, Quick Properties, and Selection Cycling
- Distribute existing drafting modes, snap options, and isometric tools into their respective tabs
- Implement OK, Apply, and Close action buttons with unsaved changes confirmation guard
2026-09-14 17:45:47 +01:00
Karim Jerbi ddeddeca31 perf(snap): optimize OSNAP cursor tracking broadphase and tangent gating (22.7x speedup)
- Implement zero-allocation InRangeWires stack buffer (up to 16 wires) to eliminate repetitive linear full-scene passes in Snapper::snap
- Add early-exit when cursor hovers whitespace (<1 µs latency)
- Add wire_in_range AABB guard to Tangent snap, cutting ~10,000 redundant 3D-to-screen matrix projections per query
- Add pairwise count guards (>= 2) to Intersection and ApparentIntersection, eliminating 120 KB of heap allocations per query in ApparentIntersection
- Add comprehensive regression tests in snap::ext_tests
- Benchmark gains:
  * Quick mode (1,000 entities): 33.98 µs -> 1.50 µs (22.7x faster, +2,024% throughput)
  * Full mode (5,000 entities): ~165.0 µs -> 7.46 µs (22.1x faster, +2,133% throughput)
2026-09-14 16:12:35 +01:00
ramox81 0cabe113c8 Fix helix height from point input 2026-09-14 17:36:33 +03:00
ramox81 a28a9088d7 Use viewport UCS status fields 2026-09-14 16:57:58 +03:00
ramox81 88839b783a Match active view properties palette 2026-09-14 16:56:48 +03:00
Karim Jerbi 509d746dd0 perf(scene): chunked batch accumulation for spatial InteractionIndex build
Optimize InteractionIndex::build by eliminating per-wire vector allocation churn
and combining wire handle / ordinal resolution:

1. Introduced WireIndexBatch to chunk wires into batches of 256 wires. Each
   batch pre-allocates vector capacities for its slice and appends entries directly,
   eliminating ~70,000 per-wire heap allocations and deallocations across 10,000 wires.
2. Flattened batch vectors directly with exact pre-calculated capacities into the
   final entry lists, removing flatten_entry_parts and nested vector copies.
3. Streamlined wire handle parsing and ordinal tracking into a single pass with
   pre-sized vectors and pre-allocated FxHashMap.

Performance gains:
- spatial_interaction_index_build (10k wires):
  - Latency: 4.88 ms -> 4.01 ms (-17.8%)
  - Mean latency: 4.93 ms -> 4.05 ms (-17.8%)
  - Throughput: 2.05M wires/s -> 2.53M wires/s (+23.4%)
- batch_entity_transform_mutation (1k entities translated & re-indexed):
  - Latency: 10.92 ms -> 8.95 ms (-18.0%)
  - Mean latency: 11.28 ms -> 9.52 ms (-15.6%)
  - Throughput: 92.4k entities/s -> 111.3k entities/s (+20.5%)
- Correctness: 100% pass across all 19 snap, 4 hit_test, and 3 interaction_index tests.
2026-09-14 14:55:18 +01:00
ramox81 7dabc48fd3 Match Region properties palette 2026-09-14 16:16:20 +03:00
ramox81 666b28ffe3 fix(annotate): reject invalid linked ranges 2026-09-14 15:07:51 +03:00
ramox81 a35c996f9f fix(annotate): complete table and data workflows 2026-09-14 14:54:55 +03:00
Karim Jerbi cc1e78cc70 perf(ui): add MRU inline cache to themed_handle for fast icon lookups
Optimize themed_handle in src/ui/icons.rs by adding an inline 2-entry MRU cache
ahead of the full FxHashMap table:

1. Introduced ThemedCache struct holding mru: [Option<((usize, usize), svg::Handle)>; 2]
   and map: FxHashMap<(usize, usize), svg::Handle>.
2. Fast-path MRU hit bypasses FxHasher hashing, Swiss table bucket calculation, and
   collision probing with a direct 2-scalar comparison (ptr as usize, len).
3. Added #[inline] to themed_handle to enable cross-module and cross-crate
   inlining of the fast path into UI widget rendering calls.
4. Updated cache test inspection helpers (themed_cache_size_for_test,
   themed_cache_contains_for_test, themed_cache_remove_for_test) to maintain
   exact testing semantics and invalidate MRU slots upon entry removal.

Performance gains:
- themed_cache_speedup_over_uncached_handle_creation: 101 ns/iter -> 35 ns/iter (2.9x speedup)
- ui_icon_handle_cached: 80.19M lookups/s (12.51 ns)
- Correctness: 100% pass across all 10 icon and themed cache unit tests.
2026-09-14 12:50:43 +01:00
kevin9327andClaude Opus 5 85e942bdd2 fix(step): keep the own plane of small triangles
The vertex-normal fallback compared the cross product's length with
f64::EPSILON, an area-scale threshold, so a valid triangle small enough
fell back to the leaning vertex normal again. Fall back only when the
cross product is zero.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 20:45:11 +09:00
kevin9327andClaude Opus 5 d77a3bd774 fix(stl): keep the own normal of small facets
The vertex-normal fallback compared the cross product's length with
f32::EPSILON, an area-scale threshold, so a valid facet with 1e-4 edges
(cross product 1e-8) took the leaning vertex normal again. Fall back only
when the cross product is zero.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 20:37:49 +09:00
Karim Jerbi 546a6af186 perf(entities): direct quad-strip triangulation for wide arc tessellation
Optimize wide and tapered arc fill mesh generation by eliminating general
ear-clipping triangulation and optimizing arc boundary evaluation:

1. Replaced triangulate_planar with triangulate_band_ring and direct
   quad-strip vertex construction in wide_band_tris. Polyline band fills
   possess strict quad-strip topology (straight segments: 4-vertex trapezoid;
   arc segments: 2m-vertex annular sector). Generating triangles directly in
   O(N) time avoids Newell normal calculation, planar projection, Delaunay
   triangulation, and O(N^2) ear-clipping searches.
2. Exact buffer capacity pre-allocation in wide_band_tris based on ring
   lengths, eliminating dynamic reallocation during triangle emission.
3. Replaced top and bottom cap triangulation in thick_band_tube with
   triangulate_band_ring.
4. Unified inner and outer arc point calculation in polyline_segment_fill
   into a single loop using ang.sin_cos(), halving trigonometric calls and
   eliminating dynamic vector resizing.

Performance gains (wide_and_tapered_arc_tessellation benchmark across 7,500 entities):
- Latency: 27.34 ms -> 23.30 ms (-14.8%)
- Mean latency: 28.08 ms -> 24.15 ms (-14.0%)
- Throughput: 265.6k entities/s -> 321.9k entities/s (+21.2%)
- Correctness: 100% pass across all 45 polyline and 5 tessellation unit tests.
2026-09-14 12:31:07 +01:00
kevin9327andClaude Opus 5 762705f4a4 fix(plot-style): keep the full scale factor when saving a plot style table
PlotStyleTable::to_text wrote scale_factor with one decimal, and saving
from the plot style panel rewrites the whole loaded table. A table with
apply_factor on and scale_factor=0.25 came back as 0.2, thinning every
scaled lineweight by a fifth.

Write the factor in full, keeping the decimal point on a whole value.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 20:29:03 +09:00
Hakan Seven 912b217d26 fix: delegate dimension transforms to cadcodec 2026-09-14 14:22:10 +03:00
kevin9327andClaude Opus 5 96a54b809c fix(linetypes): load .lin definitions whose header has no description
In a .lin file the description is optional and the comma goes with it, so
"*PLAIN" followed by "A,.5,-.25" is a complete definition. parse only kept
a header that contained a comma, so such a linetype was dropped silently
and a CENTERLTYPE naming it then reported that it was not loaded.

Take the whole header as the name when there is no comma.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 20:19:20 +09:00
Marcel a2adb3f6e3 Refactor grip dynamic input and polyline arc geometry 2026-09-14 13:15:57 +02:00
Hakan Seven 247e48bfe8 Merge pull request #1248 from kevin9327/fix/dimension-rotate-mirror-off-world-z 2026-09-14 14:15:11 +03:00
kevin9327andClaude Opus 5 6219af60ed fix(stl): write each facet's own normal
build_stl took the facet normal from the first vertex's normal whenever the
mesh had normals. On smoothed meshes (tessellated curved solids, OBJ imports
with vn) that normal leans off the triangle, while STL defines the facet
normal as the triangle's own unit normal.

Use the triangle's own normal, and keep the vertex normal only for a
triangle with no area. Meshes without normals export as before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 20:11:30 +09:00
kevin9327andClaude Opus 5 bc3e63ff53 fix(step): place each exported face on its triangle's own plane
build_step took the PLANE normal from the first vertex's normal whenever
the mesh had normals. On smoothed meshes (tessellated curved solids, OBJ
imports with vn) that normal leans off the triangle, so the plane missed
two of the face's corners and the first edge was no longer perpendicular
to the placement axis.

Use the triangle's own normal, and keep the vertex normal only for a
triangle with no area. Meshes without normals export as before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 20:04:00 +09:00
kevin9327andClaude Opus 5 23cd448c7f fix(dimension): rotate and mirror dimensions in working planes off world Z
With a working plane other than world XY, ROTATE and MIRROR handed a
non-ordinate dimension to acadrust's Entity::apply_transform, which only
translates those dimension types by where the transform sends the origin.
The definition points, plane and angles stayed unturned, so the dimension
jumped back once its block was baked again.

Send both through the existing Affine branch, which ALIGN already uses and
which transforms points, normal and stored angles together. The world-Z
paths are unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:52:20 +09:00
Marcel dfc859dcf5 Restrict parallel offsets to straight polyline segments 2026-09-14 12:47:17 +02:00
Marcel 9ae1e6dd76 Preserve valid grip preview when edits have no geometric solution 2026-09-14 12:30:51 +02:00
Marcel 6f008faa9a Preserve connected arc geometry when moving polyline segments 2026-09-14 12:19:03 +02:00
Hakan Seven cba64631b8 fix: render PDF attachments on every platform
Fixes #1243
2026-09-14 12:53:06 +03:00
Marcel e67872386e Preserve connected arc geometry when moving polyline segments 2026-09-14 11:42:30 +02:00
Marcel fb352c34fb Add radius grip editing for LWPOLYLINE arcs 2026-09-14 10:58:45 +02:00
ramox81 6505b27818 fix(annotate): align annotation ribbon workflows 2026-09-14 11:55:08 +03:00
Hakan Seven 010d23fa95 chore: sync reviewed dependency mains 2026-09-14 10:02:49 +03:00
Hakan Seven 2f741d689f fix: address open PR review findings 2026-09-14 09:45:37 +03:00
Hakan Seven 3fe91fa6e1 Merge pull request #1240 from kevin9327/fix/step-export-large-coordinates 2026-09-14 09:29:08 +03:00