Commit Graph
3954 Commits
Author SHA1 Message Date
yztink fa1b4db490 fix(command-line): prevent duplicate paste in command line and text fields 2026-09-24 23:37:32 -07:00
Karim Jerbi 631c0c97aa fix(command-line): Enter runs the highlighted autocomplete pre-selection 2026-09-24 23:38:01 +01:00
Karim Jerbi bd1fdcc1c5 refactor(chprop): convert choice arms to apply_property_op, fix CTB snapshot leak
Converts 12 selection arms of on_prop_geom_choice_changed to the shared helper: transparency, material, tol text and dim styles, dim overrides, viewport scale, UCS, named views, loft, history, surface and table style. Miss paths no longer push no-op undo entries.

Fixes a leaked undo snapshot: changing plot style in CTB mode is a no-op but pushed an entry. Guard hoisted before the shared snapshot, with a regression test.

Left manual by design: mleader, leader, block and fallback arms, all no-selection arms, and on_prop_geom_commit, whose constraint-aware invalidation the helper cannot express.
2026-09-24 23:16:29 +01:00
Karim Jerbi acc3e05001 refactor(clipboard): share table and block merge copies
merge_dependencies and merge_clipboard_blocks duplicated the table-record and block-definition merge logic already ported into paste_entities_kernel. Extract merge_table_records and merge_block_defs as the single shared copies; both the methods and the kernel delegate to them. The method keeps one batched geometry rebuild instead of one per definition.
2026-09-24 23:16:29 +01:00
Hakan SevenandClaude Opus 5.5 56c04408d6 Merge remote-tracking branch 'origin/main'
The command driver was split into command_driver/ upstream; the PDF
underlay and XCLIP additions to the old file move with it: their
CmdResult arms into the router (mod.rs) and the block-reference
selection filter with its clip lookup into utilities.rs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-25 00:05:11 +03:00
Hakan SevenandClaude Opus 5.5 2fcdf43f44 fix(ribbon): follow-ups to the Reference panel merge
- The palette launcher arrow is recoloured from the theme like the other
  interface icons, instead of drawing the raw SVG.
- The Frames dropdown shares one icon constant; its entries were left
  misindented.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 23:57:20 +03:00
Hakan Seven 0ea8599f86 Merge pull request #1476 from ramox81:codex/insert-reference-panel 2026-09-24 23:48:30 +03:00
Karim Jerbi 7052016dce refactor(kernels): extract reusable clipboard and matchprop kernels
Publishes app-free domain logic for shared use: match_special_props and PolylineMatchStyle move to entities::match_props; xdict trio usable headlessly; new match_layer, copy_to_clipboard, paste_entities and match_properties kernels over CadDocument. Handlers stay thin shells keeping undo, dirty flags, selection and command-line echo.

Adds cross-document copy, paste and property-match tests plus a headless proof driving copy, paste and match with no app instance.
2026-09-24 21:47:14 +01:00
Karim Jerbi e4fa5232f6 refactor(command_driver): split 11.5k-line driver into domain modules
Moves the exhaustive CmdResult router and its 116 handlers out of a single file into command_driver/: thin router stays in mod.rs (no wildcard, compiler-enforced coverage); handlers grouped by domain (entity_commit, clipboard, property_match, modify, solid3d, transform, viewport, text_edit, constraint, dim_edit); shared helpers in utilities/parameters; tests in tests.rs. All moves verbatim 1:1; all entry-point signatures and visibilities unchanged, so every existing caller (ribbon, commands, headless, plugins) resolves untouched.
2026-09-24 21:47:14 +01:00
Hakan SevenandClaude Opus 5.5 6d9365ea88 fix(xclip): follow-ups to the XCLIP merge
- An inverted clip's roundtrip record goes in the filter's extension
  dictionary through the codec's own API (ensure_extension_dictionary /
  xrecord / extension_dictionary_handle) instead of a scan of every
  object, which the renderer ran for each clipped reference.
- Pin cadcodec 1c3be0c (the DXF writer now links a spatial filter's
  extension dictionary, so that record is not left unreferenced) and
  cadkernel deb529b; plugin crates and the Python plugin lock follow.
- The XCLIP boundary preview stays f64.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 23:46:50 +03:00
Hakan Seven 58671b191c Merge pull request #1475 from ramox81:codex/xclip-command 2026-09-24 23:30:38 +03:00
Hakan SevenandClaude Opus 5.5 d5016c7044 fix(pdf): follow-ups to the PDF underlay merge
- Pin cadcodec upstream at d290dbe (the merged underlay change) and
  cadkernel at 4134ae3, which follows it; drop the fork patch, move the
  plugin-API and web-worker crates and the Python plugin lock to the same
  codec so one copy is built.
- "Import as block" with raster images left IMAGE entities without an
  image definition: block definition now creates it like add_entity does,
  through one shared helper.
- The three preview outlines (attach frame, clip boundary, import area)
  stay f64 instead of casting world points to f32.
- Page size / total / PDF scale entries use the catalog's positional
  placeholder; the bare {name} form failed to format in 20 locales.
- The Underlay Layers bulb is the SVG layer icon, not a text glyph.
- PDF dialogs use the shared dialog buttons and radios.
- Options opened from a PDF dialog clears its saved state on return.
- Paper-space underlay background reuses the model block handle already
  resolved; dead `let _ = i` lines and a misplaced doc comment removed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 23:24:51 +03:00
Hakan Seven 2e60c4da1b Merge pull request #1472 from ramox81:codex/pdf-attach-parity 2026-09-24 23:24:43 +03:00
7ed6a362dc feat(ui): show ribbon command icons in menus and suggestions
The ribbon definition beside each command stays the one source of its
label and icon. One cached lookup (modules::registry::ribbon_commands)
walks the core ribbon and the expanded Draw/Modify panels; the shortcut
list, the right-click menu, the grip menu and the command-line
suggestions read it.

- Context menu: command rows carry their ribbon icon; Undo/Redo and
  Isolate use interface glyphs, Draw Order its ribbon icon; icons and
  the caret fade on disabled rows.
- Grip menu: Stretch, Move, Rotate, Scale, Mirror and Copy icons.
- Suggestions: an icon column, aligned when a command has none.
- Shortcut list: dropdown entries were read as (label, command) though
  the ribbon stores (command, label), so they never got a label or icon.

Reworked from #1449.

Co-Authored-By: MarcelP102 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 22:46:32 +03:00
ramox81andClaude Opus 5.5 cfa4b186c5 PDF underlays: adjusting for a dark background turns every colour's lightness over
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 20:04:53 +03:00
ramox81andClaude Opus 5.5 5f294035db Reference panel launcher: arrow icon
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 19:39:23 +03:00
ramox81andClaude Opus 5.5 13ccb82d8e Reference panel: the palette launcher sits beside the title
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 19:39:23 +03:00
ramox81andClaude Opus 5.5 95e2bae0d2 Insert Reference panel: one Attach, labelled underlay tools, slide-out with Edit Reference and xref fading
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 19:39:23 +03:00
ramox81andClaude Opus 5.5 32467adcef XCLIP: roundtrip record keeps its cloning flag
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 19:39:09 +03:00
ramox81andClaude Opus 5.5 2078fc02f8 XCLIP and CLIP: clip boundaries on block references, CLIP routed by the picked object
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 19:39:09 +03:00
ramox81 c1ecb0edaf Merge remote-tracking branch 'origin/main' into codex/pdf-attach-parity
# Conflicts:
#	locales/ar-SA/opencadstudio.ftl
#	locales/bg-BG/opencadstudio.ftl
#	locales/cs-CZ/opencadstudio.ftl
#	locales/de-DE/opencadstudio.ftl
#	locales/el-GR/opencadstudio.ftl
#	locales/en-US/opencadstudio.ftl
#	locales/es-ES/opencadstudio.ftl
#	locales/fi-FI/opencadstudio.ftl
#	locales/fr-FR/opencadstudio.ftl
#	locales/hi-IN/opencadstudio.ftl
#	locales/hu-HU/opencadstudio.ftl
#	locales/it-IT/opencadstudio.ftl
#	locales/ja-JP/opencadstudio.ftl
#	locales/ko-KR/opencadstudio.ftl
#	locales/nl-NL/opencadstudio.ftl
#	locales/pl-PL/opencadstudio.ftl
#	locales/pt-BR/opencadstudio.ftl
#	locales/ru-RU/opencadstudio.ftl
#	locales/tr-TR/opencadstudio.ftl
#	locales/zh-CN/opencadstudio.ftl
#	locales/zh-TW/opencadstudio.ftl
#	src/app/control/actions.rs
#	src/app/mod.rs
#	src/app/update/mod.rs
#	src/app/view/modal.rs
#	src/io/xref.rs
#	src/ui/window/mod.rs
2026-09-24 19:38:48 +03:00
Karim Jerbi 6b37476687 feat(ui): migrate dialogs across application to shared dialog_button and form_radio builders 2026-09-24 17:33:45 +01:00
ramox81andClaude Opus 5.5 b7a897b414 Import PDF dialog shows the PDF scale
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 19:23:14 +03:00
ramox81andClaude Opus 5.5 c9426a5d6d Automation: ribbon tab and dropdown actions; _PDFIMPORTFILE takes a path
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 19:10:41 +03:00
ramox81andClaude Opus 5.5 28853cd32e PDF import keeps drawing order when joining strokes; automation: layer toggle and page selection
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 19:02:47 +03:00
ramox81andClaude Opus 5.5 f63e351a12 Automation: pdf_dialog_ok presses the open PDF dialog's OK
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 18:55:30 +03:00
Karim Jerbi 1a6279e841 feat(blocks): implement WBLOCK dialog and unify dialog buttons and radio builders 2026-09-24 16:44:24 +01:00
ramox81andClaude Opus 5.5 3f6bdf8c59 PDF underlays: attach dialog with pages, underlay tab, layers, import settings and file import, unload on the definition
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 18:31:40 +03:00
Luis MartinezandClaude Opus 5.5 dddf60d79e Add audited, versioned MCP save workflow (#1452)
- `--export ... --target-version`, and explicit target_format /
  target_version on automation and protocol saves; a conversion that
  would drop unsupported records is refused unless allow_lossy is set.
- `audit` read op: dangling layers/blocks, duplicate handles, non-finite
  bounds, serialization, lossy records and the source DXF handle graph.
- `save_verified`: writes the requested version from the same snapshot a
  normal save writes, reopens it, checks the version and the entity
  manifest, audits the ASCII DXF handle graph and returns a SHA-256.
- ZOOM EXTENTS includes SDF text glyphs.
- Live MCP acceptance script and an optional reference-console audit
  runner under docs/automation.

Squashed from the PR with review fixes: merged with the DWT save path,
the save snapshot, the tool lists added since, and vendor-neutral
harness names; the dated verification record is left out.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 16:49:11 +03:00
Hakan SevenandClaude Opus 5.5 0f99b77004 test(plot): pin the paper-scale tests to millimetre drawing units
New drawings now default to metre insertion units, and the plot dialog
reads a ratio against the drawing's units, so these tests (written for
millimetres) saw 1:100 as 10 mm per unit. The metre case keeps its own
test.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 16:38:21 +03:00
Hakan Seven 3619e00033 Merge pull request #1463 from ramox81:codex/new-drawing-meters 2026-09-24 16:32:56 +03:00
ramox81andClaude Opus 5.5 0c50013ca7 PDF underlays: attach prompts and definitions, display adjustments and clipping, Properties, snapping, PDFCLIP and PDFIMPORT
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 16:00:12 +03:00
Hakan SevenandClaude Opus 5.5 eae5662099 fix(test): keep tests out of the user's config folder
Tests resolved the real per-user config dir. When the alias table
version moved, parallel tests migrated and rewrote the user's alias
file concurrently and one left it holding a single alias. Under test,
config_dir() is a per-process temp folder and the alias table comes
from the shipped defaults with no file I/O.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 15:37:00 +03:00
Hakan SevenandClaude Opus 5.5 163763c42a fix(xref): follow-ups to the xref attach parity merge
- `XREF <args>` runs whole: probing the bare verb first now opens the
  External References palette, which refreshed every entry and toggled
  the palette before `XREF Reload A` / `XREF ?` ran.
- Update the two tests that encoded the old behaviour: `-XREF ?` prints
  the reference table, and attaching a missing file is rejected.
- Drop the duplicate "Specify On-screen" catalog entry that shadowed the
  translated common key, with its unused ftl keys.
- Move `remove_pipe_symbols`' doc comment back above its function.
- Note in `document_for_save` that resolved xref content stays out.
- Gate the desktop-only preview cap and tab index for wasm.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 15:37:00 +03:00
Hakan Seven 1988424638 Merge pull request #1462 from ramox81:codex/xref-attach-parity 2026-09-24 15:09:56 +03:00
Hakan SevenandClaude Opus 5.5 73b560de99 fix(plugin): append the multi-entity command steps after the existing ones
#1469 inserted `CommitMany` and `CommitManyAndEnd` between `Commit`,
`CommitAndEnd` and `Done`. `CommandStep` crosses the plugin IPC, which
encodes a variant by its position, so a plugin built against the previous
API that answered `Done` would have been read as `CommitAndEnd` — or
rejected as undecodable — by the new host. The two variants now sit after
`Cancel`, as the other additions to the v7 wire types do.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 15:09:01 +03:00
Hakan Seven 8ae804d921 Merge pull request #1469 from yztink:feat/plugin-interactive-preview 2026-09-24 15:02:00 +03:00
Hakan Seven 9cf9184d9a Merge pull request #1460 from lalomalvi:codex/missing-font-prompt-hardening-pr 2026-09-24 15:01:55 +03:00
Hakan Seven 43c7a213f0 Merge pull request #1455 from lalomalvi:codex/plot-preview-test-isolation 2026-09-24 15:01:54 +03:00
Hakan Seven 2462817dfc Merge pull request #1454 from lalomalvi:codex/psetupin-windows-json
# Conflicts:
#	src/app/update/page_setup_import.rs
2026-09-24 15:01:53 +03:00
Hakan Seven cc9d5edbff Merge origin/main 2026-09-24 13:41:45 +03:00
Hakan SevenandClaude Opus 5.5 5f17d9d9a6 Merge pull request #1383 from huaninstratech:pr/api-spec
The specification this pull request adds now describes code that exists:
the operations it documents came in with the previous commit. The file
keeps the fork's later revision, rewritten against that code, which also
carries the map of the surface's pieces.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 13:41:19 +03:00
huanldandClaude Opus 5.5 279a87418e feat(automation): entity, block, publishing and REST operations from the fork
The operations docs/automation/API-SPEC.md (PR #1383) describes, brought
over from huaninstratech/OpenCADStudio so the specification no longer runs
ahead of the code:

- entity CRUD: entities_create, entities_delete, entities_transform,
  entities_copy_to, and `where` filters on query
- blocks and export: block_define, block_delete, a normalised wblock
- publishing: layout_create, page_setup_set, plot (per_page included)
- metadata: sysvar, xdata_set / xdata_get, file_identity
- collections: group_create, selection_set_save / load
- control plane: batch, events, view_focus, close
- the REST transport: `--http <port>`, the /api/v1 routes and their
  OpenAPI 3 description
- person-in-the-loop picks: user_select and getpoint, hosted by the GUI
  over the same REST routes, with on-screen pending signals

Taken from the fork's commits b7a7ed80, 69396b42, 64f1cf6a, c3aafc8e,
bb5a7bfa, 52317a5c, 50d293ba, b90e194f, 517c6397, 53a5c4c9, a49ac045,
37de5a46, a78b1822, 6d9aed2a, 33f522da, 5b5cafe2, 02a7e78d, 94df40dc,
fd5bc14d, 485fac61 and 2c5fc994.

Left out on purpose: 37de5a46 also removed the donation surface (the
Patreon fetch, the donation prompt, the Start-page supporters rail, the
DONATE command and its locale strings) and replaced the About dialog's call
to action; that is the fork's own product decision and stays out. The
fork's version bump and its unrelated IFC/BIM work are not part of this.

Adapted while porting: the REST server and the GUI bridge are desktop-only
and a template start is refused in the web build, so the wasm target still
compiles; the two plot tests read the PDF through the shared stream helper,
because exported streams are Flate-compressed; the benches set the new
crosshair field; comments and docs describe each operation in its own
terms rather than by another product's API names.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 13:41:07 +03:00
Karim Jerbi 5e34796dca feat(i18n): implement translations for block creation window and units
- Localize block description placeholder via BlockDefinitionState field
- Add lookup mappings to locale_catalog for block definition dialog,
  validation messages, on-screen prompts, and insertion units
- Add Fluent strings for all 41 keys across all 21 supported locales
2026-09-24 11:14:26 +01:00
Karim Jerbi 531ba44faa chore(lints): fix compiler warnings and clippy array suggestions 2026-09-24 10:37:52 +01:00
Karim Jerbi 66fccc217e fix(test): resolve test runner thread stack overflow and JSON path formatting
Fix two test failures affecting CI and local test runs:

1. Cross-platform test runner thread stack overflow:
   In debug builds (opt-level = 0), `app.view(wid)` constructs the entire Iced UI
   widget tree (ribbon, tool panels, palettes, command line, status bar).
   Because libtest spawns test worker threads without setting an explicit stack
   size, the default thread stack allocated by the OS (2MB on Linux glibc, 1-2MB
   on Windows) overflows during recursive un-inlined view construction in
   `app::automation::tests::test_pline_line_then_arc`.
   - Set `[env] RUST_MIN_STACK = "8388608"` in `.cargo/config.toml` so `cargo test`
     allocates 8MB per test thread across all platforms (Linux CI, macOS, Windows).
   - Wrapped `test_pline_line_then_arc` in an explicit 8MB thread via
     `std::thread::Builder` to guarantee immunity even when invoked without env vars.

2. Windows temporary path formatting in JSON payload:
   In `app::update::page_setup_import::tests::psetupin_imports_named_setups_from_a_saved_drawing`,
   interpolating `source.display()` directly into a raw JSON string resulted in
   unescaped backslashes from Windows paths, causing JSON deserialization to fail.
   Replaced backslashes with forward slashes to ensure cross-platform valid JSON strings.
2026-09-24 10:22:02 +01:00
Karim Jerbi eff55b27f1 perf(tessellate): optimize polyline arc sampling and skip wide fills on thin polylines
Directly sample double-single coordinates with sin_cos, short-circuit
wide fill processing on thin polylines, and preallocate band capacities.

1. Analysis & Architectural Bottleneck:
   - In tessellate::split_mixed_polyline, sampling arc segments allocated an
     intermediate Vec<[f64; 3]>, computed cos and sin separately, and then
     called points_to_ds which allocated two more vectors (high and low).
   - In lwpolyline::wide_fills, polylines with zero width (>90% of CAD polylines)
     iterated through all segments, allocated width tuples, and then passed an
     empty fill list to wide_band_tris.
   - In common::tapered_band_points, vector capacities were unreserved.

2. Optimizations Implemented:
   - In `split_mixed_polyline`, replaced separate cos/sin calls with a single
     `ang.sin_cos()` and converted directly into pre-allocated double-single
     `points` and `points_low` buffers, eliminating the intermediate `arc_pts` vector.
   - In `points_to_ds`, added early exit if capacity is 0.
   - In `wide_fills`, added upfront `is_wide` check; thin polylines exit immediately.
   - In `wide_band_tris`, added immediate return for empty fills.
   - In `tapered_band_points`, reserved vector capacity `seg_count + 1` upfront.

3. Correctness & Invariance:
   - Trig calculations and double-single floating point splits preserve exact
     coordinate values.
   - Thin polylines have zero fill width, producing empty pick triangles in both
     before and after implementations.
   - Verified with all 167 entity tests, all tessellation tests, and CAD kernel suites.

4. Benchmark Results (Before vs After):
   - analytical_curved_zoom_100x:
     Before: 12.75M FPS (0.01 ms)
     After:  14.08M FPS (0.01 ms)
     Improvement: -9.4% latency (+10.4% FPS throughput)
   - scene_entity_ingestion_10k:
     Before: 1.99 ms (1.01M entities/s)
     After:  1.82 ms (1.10M entities/s)
     Improvement: -8.5% latency (+8.9% throughput)
   - spatial_interaction_index_build:
     Before: 0.77 ms (2.47M wires/s)
     After:  0.71 ms (2.68M wires/s)
     Improvement: -8.2% latency (+8.5% throughput)
   - draworder_depth_map_incremental_patch:
     Before: 0.40 µs (2.50M patches/s)
     After:  0.36 µs (2.78M patches/s)
     Improvement: -10.0% latency (+11.2% throughput)
   - wide_and_tapered_arc_tessellation:
     Before: 6.36 ms (235.8k entities/s)
     After:  5.97 ms (251.1k entities/s)
     Improvement: -6.0% latency (+6.5% throughput)
   - analytical_curved_tessellation:
     Before: 7.79 ms (359.5k entities/s)
     After:  7.38 ms (379.2k entities/s)
     Improvement: -5.2% latency (+5.5% throughput)
   - wire_partitioning_per_frame:
     Before: 0.18 ms
     After:  0.06 ms
     Improvement: -64.9% latency (3x faster)
2026-09-24 09:05:08 +01:00
Karim Jerbi 3efd62b6ef perf(scene): optimize render environment scan and avoid insert clone in style spec
Eliminate full Insert entity cloning in block style evaluation, unify
document object environment scans, and guard viewport override queries.

1. Analysis & Architectural Bottleneck:
   - In render_graph::InsertStyleSpec::new, an entire Insert struct was cloned
     into an EntityType::Insert enum solely to pass to style functions that only
     read EntityCommon fields (layer, color, transparency, linetype, lineweight).
   - In view::render::resolve_document_render_environment, when object caches were
     not prepared, the document.objects map was traversed linearly twice: once
     for RenderEnvironment and once for RenderSettings.
   - Viewport override lookups were being performed even when viewport was None
     (the standard model space condition).

2. Optimizations Implemented:
   - Added `render_style_for_common_viewport`, `linetype_name_for_common_viewport`,
     and `has_resolved_book_color_common` taking `&EntityCommon` directly.
   - Constructed `InsertStyleSpec::new` without cloning the Insert entity.
   - Fused the two linear scans of `self.document.objects` in
     `resolve_document_render_environment` into a single pass tracking best candidates.
   - Guarded viewport override lookups with `if viewport.is_some()` in
     `layer_render_style_viewport` and `render_style_for_common_viewport`.

3. Correctness & Invariance:
   - The same fields and fallback values are resolved in identical order.
   - Tested across all 325 scene tests, block inheritance tests, and viewport
     override unit tests with 0 failures.

4. Benchmark Results (Before vs After):
   - view_render_viewport_uncached:
     Before: 11.00 µs (90.9k FPS)
     After:   5.00 µs (200.0k FPS)
     Improvement: -54.5% latency (2.2x faster uncached rendering)
   - wide_and_tapered_arc_tessellation:
     Before: 6.36 ms (235.8k entities/s)
     After:  5.41 ms (277.4k entities/s)
     Improvement: -14.9% latency (+17.6% throughput)
   - analytical_curved_tessellation:
     Before: 7.79 ms (359.5k entities/s)
     After:  7.01 ms (399.6k entities/s)
     Improvement: -10.1% latency (+11.1% throughput)
   - spatial_interaction_index_build:
     Before: 0.77 ms (2.47M wires/s)
     After:  0.73 ms (2.66M wires/s)
     Improvement: -5.1% latency (+7.7% throughput)
   - ui_grip_budget_build:
     Before: 424.50 µs
     After:  380.25 µs
     Improvement: -10.4% latency
   - ui_ribbon_view_construction:
     Before: 455.50 µs
     After:  382.30 µs
     Improvement: -16.1% latency
2026-09-24 09:05:08 +01:00
Karim Jerbi 895f9a0f33 perf(wire): skip wire distance math for solid lines and optimize handle parsing
Bypass expensive Euclidean distance calculation for continuous lines and
replace standard library ASCII decimal parsing for entity handle IDs.

1. Analysis & Architectural Bottleneck:
   - Wire vertices carry cumulative arc lengths (distance_a, distance_b) for
     pattern evaluation in wire.wgsl. However, wire shaders only read in.distance
     when in.pattern_length > 0.0. Solid lines (pattern_length <= 0) ignore
     distance entirely. Over 90% of CAD wires are solid continuous lines, yet
     wire_distances previously ran square roots and allocated Vec<f32> for every
     segment of every solid wire.
   - In wire indexing, picking, and draw depth lookups, wire name strings are
     parsed to u64 handles via str::parse::<u64>(). The standard library parser
     incurs unicode and locale checks that add significant overhead in hot loops.

2. Optimizations Implemented:
   - In wire_gpu.rs, introduced inlined `fast_parse_u64` for ASCII decimal integers.
   - Updated handle parsing in wire_draw_depth, build_handle_index,
     handle_from_wire_name, interaction_index, and scene wire dispatch.
   - In emit_wire_packed and emit_wire_native, checked `wire.pattern_length > 1e-6`.
     For solid lines, skipped wire_distances entirely and emitted (0.0, 0.0),
     bypassing sqrt loops and vector allocations.

3. Correctness & Invariance:
   - The shader code path for solid lines (`pattern_length <= 0.0`) explicitly
     does not use in.distance. Emitting 0.0 produces visually and mathematically
     identical pixels.
   - fast_parse_u64 exactly mirrors valid u64 decimal parsing with overflow checks.
   - Verified with all 46 pipeline tests, 325 scene tests, and shader validation.

4. Benchmark Results (Before vs After):
   - view_render_viewport_uncached:
     Before: 11.00 µs (90.9k FPS)
     After:   6.00 µs (166.7k FPS)
     Improvement: -45.5% latency (+83.4% frame throughput)
   - view_render_viewport_cached:
     Before:  8.00 µs (125.0k FPS)
     After:   4.00 µs (250.0k FPS)
     Improvement: -50.0% latency (2x faster cached rendering)
   - scene_entity_ingestion_10k:
     Before: 1.99 ms (1.01M entities/s)
     After:  1.85 ms (1.08M entities/s)
     Improvement: -6.7% latency (+6.9% throughput)
   - ui_ribbon_view_construction:
     Before: 455.50 µs
     After:  400.00 µs
     Improvement: -12.2% latency
   - ui_grip_budget_build:
     Before: 424.50 µs
     After:  398.20 µs
     Improvement: -6.2% latency
2026-09-24 09:05:08 +01:00
Karim Jerbi 490de91fbb perf(render): optimize analytical instancing and wire partitioning
Eliminate intermediate heap vector allocations during wire classification
and analytical instance extraction for circle and ellipse GPU pipelines.

1. Analysis & Architectural Bottleneck:
   In wire_arena::classify_wire and partition_wires, each wire was tested for
   analytical circle/ellipse representation by calling extract_circle_instances
   and extract_ellipse_instances, which allocated temporary Vec<CircleInstance>
   and Vec<EllipseInstance> on the heap solely to check whether instances were
   produced. Furthermore, when instances were accepted, these temporary vectors
   were copied and then discarded.

2. Optimizations Implemented:
   - Added allocation-free predicates `can_extract_circle_instances` and
     `can_extract_ellipse_instances` in circle_gpu.rs and ellipse_gpu.rs.
   - Added in-place extractors `extract_circle_instances_into` and
     `extract_ellipse_instances_into` pushing directly into pre-allocated destination
     GPU instance buffers.
   - In wire_arena.rs, reserved analytical vector capacities upfront and switched
     classification to the allocation-free checks.
   - In pipeline/mod.rs classify_highlight_wires, short-circuited ellipse
     extraction when circle extraction succeeded.

3. Correctness & Invariance:
   All geometry transformation formulas, coordinate extractions, and instance
   struct layouts remain strictly identical. Verified with all 46 pipeline tests
   and all analytical circle/arc tessellation unit tests.

4. Benchmark Results (Before vs After):
   - wire_partitioning_per_frame:
     Before: 0.18 ms (mean 0.19 ms, p95 0.38 ms)
     After:  0.06 ms (mean 0.07 ms, p95 0.28 ms)
     Improvement: -63.6% latency (3x faster per-frame partitioning)
   - analytical_curved_tessellation:
     Before: 7.79 ms (359.5k entities/s)
     After:  6.87 ms (407.7k entities/s)
     Improvement: -11.8% latency (+13.4% throughput)
   - wide_and_tapered_arc_tessellation:
     Before: 6.36 ms (235.8k entities/s)
     After:  5.48 ms (273.8k entities/s)
     Improvement: -13.8% latency (+16.1% throughput)
   - analytical_curved_zoom_100x:
     Before: 12.75M FPS (0.01 ms)
     After:  13.97M FPS (0.01 ms)
     Improvement: +9.6% FPS
2026-09-24 09:05:08 +01:00