Commit Graph
42 Commits
Author SHA1 Message Date
ramox81andClaude Opus 5.5 c8167c54ee -VIEW sEttings Background dialog and view backgrounds
Color, Gradient and Image at the background prompt open a Background
dialog (None / Solid / Gradient / Image, preview, solid colour, two- or
three-colour gradient with rotation, image file with position and
scale). Apply links the view to a new background object in
ACAD_BACKGROUND; restoring a view gives the model viewport a copy of
it (or none), and saving a view copies the viewport's background.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 10:50:00 +03:00
Karim Jerbi 9cf9ff2c5c style: apply cargo fmt across workspace 2026-10-11 03:14:29 +01:00
Karim Jerbi 7aafd9c710 refactor(selection): split 31-field SelectionState into five sub-structs
SelectionState now holds view, gesture, input, menu and orbit sub-structs; all 450 access sites updated mechanically with no behavior change. Deletes three write-only dead fields (box_last, box_last_crossing, poly_last_crossing). Hand-rolled clears in commands and dim_viewport route through the new clear methods; bench fixture updated. Full suite: 1976 passed / 0 failed / 25 ignored.
2026-10-06 20:22:04 +01:00
Hakan SevenandClaude Opus 5.5 8b9049c604 fix(view): keep named views of earlier versions at their place, in f64
A VIEW record's centre is an offset from its target in view coordinates.
Views saved by earlier versions stored the target itself as the centre;
treating that as an offset put them (and VIEW plots) at about twice the
coordinates. One shared `named_view_center` now resolves the centre in
f64 (DVec3/DQuat), taking a centre equal to a non-zero target as the old
convention; VIEW RESTORE, the view plot window and Place on Sheet use it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 09:29:22 +03:00
ramox81andClaude Opus 5.5 a3c79be278 Sheet sets: fly-out submenus, block previews, window-aspect named views
- Row menus open Set category / Place Callout Block as fly-out submenus
  (hover or right press; leftwards when the palette is docked right).
- List of Blocks and Select Block show the Blocks palette's preview.
- VIEW SAVE keeps the window's width/height ratio.
- Placing view content in model space is refused with the reference message.
- Drawings read for views, placement and blocks are cached by modification time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 16:05:47 +03:00
ramox81andClaude Opus 5.5 0d0fbafaa8 Sheet sets: Place on Sheet, sheet view menus, block lists, missing status, field refresh
Model Views lists named model views and places them on the current sheet
(xref, viewport, paper-space named view, view label with navigation
fields, sheet view record); sheet view rows get Display, Rename & Renumber
View, Set category, Place Callout Block and Place View Label Block; the
View Category dialog's Add Blocks opens List of Blocks / Select Block; a
sheet whose relative path is gone shows missing; sheet set fields store
their values when a set changes; named views keep their centre relative to
the target. Codec pin moves to the revision with these field helpers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 15:13:33 +03:00
PanosandClaude Opus 5 d596b5a6be fix(view): zoom cursor per navigation tool, and ZOOM EXTENTS frames everything
Two viewport-navigation defects, both measured against commercial solutions.

The cursor stayed a hand during a zoom. `selection_overlay` took one boolean
for all three interactive navigation tools, so ZOOM Dynamic and ORBIT both
showed PAN's grab hand — which reads as "drag the sheet", the wrong promise
for either. Split it into a `NavCursor` enum: PAN keeps the open/closed hand,
ORBIT gets four-way arrows, and ZOOM Dynamic gets the magnifier carrying the
sign of the zoom actually under way — "+" dragging up, "-" dragging down,
latched with a 2 px dead zone so a hand held still cannot strobe the glyph.
ZOOM Dynamic also reused `box_anchor` to remember where a drag began, so a
selection marquee rubber-banded across the screen while the view zoomed; the
drawing is now suppressed, the state left alone for `reproject_box_anchor`.

ZOOM EXTENTS did not reach the whole drawing, for three separate reasons, now
answered by one shared `Scene::visible_block_bounds`:

  - A quartile filter dropped any wire whose centroid sat outside the
    inter-quartile consensus of the others. It was meant to stop one junk wire
    from a bad parse poisoning the box, but it could not tell parser junk from
    an outlying detail, a survey point, or a block placed away from the rest,
    and silently refused to frame them. Gone; the absolute 1e16 sentinel gate
    the paper path already used is the only filter, and the XLine / Ray display
    segments that motivated the heuristic are handled explicitly.

  - HATCH tessellates to no wires at all, and the model path never read the
    fill models, so a drawing whose outermost geometry is a fill — or which is
    nothing but fills — had nothing to frame. It now folds them in, reusing the
    renderer's own warm cache on the hot path rather than re-exploding every
    INSERT per ZOOM EXTENTS.

  - Inside a floating viewport the fit came from `compute_model_space_extents`,
    which walked only `key_vertices` — empty for every tessellated curve.
    Circles, arcs, ellipses and splines contributed nothing. Fixing it also
    corrects plot Extents, sheet-set framing, viewport auto-fit and SpaceMouse
    model bounds, which all inherited that blind spot.

Bounds stay f64 into the camera: a UTM drawing lost whole metres to the old
f32 round-trip. Drawing extents also no longer read the camera — the result is
cached per geometry epoch, and a floating viewport's camera is derived FROM
the extents, so `camera_for_viewport` recursed into a stack overflow.

`model_space_extents_mixed_entities_accuracy` asserted the curve-blind result;
it now asserts the true bounds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-01 16:27:26 +03:00
ramox81andClaude Opus 5.5 56ecf786f1 DWF/DGN underlays: clipping, layers, text, 3D DGN, colours and zoom extents
- PDFOSNAP, DWFOSNAP and DGNOSNAP are separate; UOSNAP sets them all and
  reads 2 while they differ. Enable Snap switches the selected kind's.
- DWFCLIP / DGNCLIP clip their own kind with the kind's prompts and message;
  CLIP routes DWF and DGN underlays there; Enter at a corner asks again.
- The right-edge underlay tools show for DWF and DGN too (import is PDF
  only).
- Underlay layers: DGN levels (V8 level table, "Default" listed as "0"; V7
  used levels named from the level name table), hidden through the layer
  override data with the DGN placeholder string first; a plotted DWF has
  none.
- V8 colour read from its colour word (by level, index, or a true colour
  drawn as its nearest index); 3D V8 elements drawn in plan (lines, line
  strings, ellipses and arcs by their orientation, text); a model's extent
  includes its text.
- DWF 6 TrueType text (font, height, rotation from the font opcode) and DWFx
  glyph runs are drawn; the default W2D colour map is the measured one.
- Contrast pulls lightness towards a per-kind pivot as measured (PDF 0.5,
  DWF 0.243, DGN 0.65).
- Zoom extents includes raster images and underlays whose frames are hidden.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:10:01 +03:00
Hakan SevenandClaude Opus 5.5 f537aff75c feat: node graph overlay; move to opencadcodec/opencadkernel/opencadgraph
The codec and kernel repositories and crates are renamed opencadcodec and
opencadkernel. Inside OCS they are depended on under short keys, so code
reads `codec::`, `kernel::` and the new `graph::` (opencadgraph, the node
graph engine). File-format and protocol spellings stay as they were: the
ACIS product id `acadrust`, the ACADRUST_* switches and the plugin
version keys `acadrust_version` / `acadrust_source`.

A button left of MCP on the command line opens a translucent node graph
over the viewport, with a palette of object, input, math, logic, list,
text and geometry nodes added by click or drag. An object node owns
drawing entities and its rows are the Properties panel's own rows for
them: the single-object page is extracted from refresh_properties as
entity_property_sections, values use the control protocol's
property_json, and writes go through set_property_value with a property
target override, so the panel, MCP and the graph share one read/write
path. A list reaching an object row makes one entity per element. Each
graph action is one undo step; the canvas pans and zooms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 07:34:23 +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 <noreply@anthropic.com>
2026-09-24 16:49:11 +03: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
Chris YehandClaude Opus 5 24f8e124d5 fix(text): re-lay-out cached glyph quads after the SDF atlas grows
Glyph quads bake the atlas UV of their tile. `grow_height` rescales every
cached entry's V and bumps the atlas generation, and the tessellation memo
folds that generation in — but the caches that hold finished wires do not:
the resident wire set is keyed by geometry epoch, block definitions by
block epoch, and a full build can grow the atlas part-way through (a CJK
sheet set bakes thousands of tiles on first sight). Text tessellated before
the growth then samples the wrong tiles for as long as those caches live,
which on a big drawing is forever: whole tables of scrambled glyphs, and
the block contents stayed scrambled even after a REGEN.

- `resident_wires_for` rebuilds (dropping the block definition cache) until
  the atlas generation is stable across the pass.
- `Scene::update` compares the live generation with the one the scene's
  caches were built against and bumps geometry once when it moved, so a
  later growth (opening a layout, editing text) re-lays-out everything.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 21:01:05 +08:00
Christopher Overbeck 4816652c1f Remove comments that repeat association operations 2026-09-15 16:03:17 -05:00
Christopher OverbeckandClaude Fable 5.1 f80130560e Regenerate viewport dimensions when the viewport view changes
Panning, zooming, twisting or rescaling a layout viewport moves model
geometry across the sheet without touching that geometry, so nothing in
the ordinary entity-change path noticed and the dimensions drawn through
the viewport stayed where they were — detached from what they measure.

`Scene::notify_viewport_changed` announces the viewport itself as a
modified entity. That is all it takes: every trans-space reference
carries the viewport handle as the first link of its chain, so the
dependency lookup in `refresh_associative_dimensions` already finds the
associations from there, and the refresh re-places and re-measures them.

Called from each mutator that changes the paper<->model mapping: pan,
zoom, fit-to-bounds, view normalisation on entering MSPACE, the
view-direction/twist snaps, the viewcube camera path, and both
annotation-scale setters.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 12:46:04 -05:00
Karim Jerbi f0cc4ffba8 fix(camera): prevent near-plane clipping during 3D orbit on wide strokes and flat drawings 2026-09-09 13:02:02 +01:00
Hakan Seven 3088e641aa fix(view): stabilize 3D navigation and hidden lines
Refresh stale depth bounds after geometry edits, allow orbiting through camera poles, and preserve hidden-line occlusion for selected solids.\n\nFixes #957
2026-09-03 20:22:35 +03:00
Hakan Seven 6606da5029 fix(blocks): complete block-backed instance rendering 2026-09-01 22:41:12 +03:00
Hakan Seven 19629d1246 fix(blocks): unify block-backed content
Route pictures, table cells, leader content, symbols, and arrows through one dependency and transform graph.\n\nRefs #864
2026-08-31 01:09:32 +03:00
Hakan Seven 81de94fdbb fix(zoom): include inserted block extents
Use current rendered geometry instead of load-time cluster spans when fitting model extents.

Refs #853
2026-08-25 22:11:18 +03:00
Hakan Seven e94cbedaa2 fix(save): preserve 3D view and thumbnails
Persist camera, render state, and solid fallback geometry across saves. Generate previews from a clean live viewport and refresh recent-file thumbnails immediately.
2026-08-23 17:59:12 +03:00
Hakan Seven 15ab027d70 fix(scene): preserve viewport settings
Reuse full VPort records during camera and tile synchronization so
navigation cannot replace file-defined display state with defaults.

Honor image, ground, IBL, and sun-backed sky parameters in
background rendering.
2026-08-12 13:11:12 +03:00
Hakan Seven adb8ced8b5 feat(view): complete ZOOM options
Add command-line navigation modes and persistent wheel controls.\n\nRefs #412
2026-08-08 20:37:53 +03:00
Hakan Seven c45daeffb6 feat(render): add scene environment pipeline 2026-08-05 23:42:18 +03:00
Hakan Seven e07f4f959b fix(view): preserve projection framing
Use full 3D bounds to derive a safe perspective eye distance without changing the camera target, orientation, or field of view.

Refs #502
2026-08-05 12:47:46 +03:00
Hakan Seven e03e091b3c feat(annotation): integrate object contexts 2026-08-02 12:00:15 +03:00
Hakan Seven c9aab122f0 feat(find): add find and replace
Closes #583
2026-07-30 17:56:54 +03:00
Hakan Seven 3897fb2661 fix(viewports): fit extents per pane
Closes #554
2026-07-29 23:03:06 +03:00
Hakan Seven 00cc17ea55 fix(scene): isolate drawing-space state
Cancel stale interaction state across space changes and keep live previews and zoom extents in their active paper/model context.\n\nRefs #539\nRefs #540\nRefs #541
2026-07-28 18:51:20 +03:00
Hakan Seven 731df4a725 feat(cad): integrate standard codec coverage
Render, edit, query, select, and explode newly decoded standard entity variants. Pin acadifc de8d6b5 and preserve None color semantics.
2026-07-26 19:30:43 +03:00
Hakan Seven 12bf126646 perf: remove large drawing stalls
Keep resident geometry and GPU resources stable across edits, MSPACE zoom, and Model/Paper switches. Add unified PERF output for tracing remaining costs.
2026-07-25 13:34:48 +03:00
Hakan SevenandClaude Opus 4.8 2ff37b088b fix(camera): re-derive ortho near/far per frame so orbit never clips
The orthographic depth half-range was frozen at fit time and measured along
the fit-time eye direction. A 3-D drawing fitted straight-down (top view) got
a shallow depth span; orbiting only rotated the camera, never resized the
span, so the drawing's width loaded onto the eye axis and overran near/far —
clipping the model the moment it was tilted off top (#473).

Cache the model AABB on the camera and recompute the near/far depth from it
for the live eye direction every frame. This tracks orbit, viewcube snaps,
roll and restored views uniformly, and keeps the same tight, zoom-independent
depth precision (coincident solids / meshes / wires keep their draw order).
Falls back to the scalar half-range / distance-scaled span when no AABB is set.

Closes #473

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 14:57:16 +03:00
Hakan SevenandClaude Fable 5 ea860cab72 fix(view): ZOOM Extents fills the window at the real aspect (#364)
fit_to_bounds fitted the bounding box's circumscribed DIAGONAL into the
viewport height regardless of shape, so a wide drawing filled only a
small central patch. Fit against the actual viewport aspect instead —
required half-height = max(|y|, |x|/aspect) over the view-space corners
— and trim the border margin from 20% to 10%. ZOOM EXTENTS/ALL and
ZOOM WINDOW both pass the live pane aspect.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 23:09:37 +03:00
Hakan SevenandClaude Opus 4.8 251ad436d7 fix(viewport): frame model-documentation drawing views correctly
A floating viewport with a real saved view — a non-zero view target, as a model
documentation drawing view or a detail/section viewport carries — now uses that
view directly instead of running the median-cluster overlap test. That test
measured against the densest sub-cluster (a big symbol library beside the small
view geometry) and wrongly auto-fit these viewports onto the library. A fully
uninitialised view (target AND centre both zero) frames its saved origin and
stays empty rather than auto-fitting the whole model in; the auto-fit rescue is
kept only for a stale target=(0,0,0) paired with a non-zero pre-georeference
centre.

Also widen the restored-view ortho depth half-range (view_height ×4 → ×64): a
thin projection such as a section/side view has content far deeper than its
visible height (its cut plane sits ~half an object-depth from the view target),
so the tighter range clipped the view outline behind the far plane. Orthographic
depth precision is linear, so the wider range costs no z-fighting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 21:11:30 +03:00
Hakan SevenandClaude Opus 4.8 b30f9b9741 feat(scene): draw nonprint light, camera and geo-location glyphs
Lights, camera views and the geographic-location marker had no on-screen
representation. Add display glyphs for all three:

- Lights render through a new EntityType::Light: a cone/flashlight for spot
  lights, a wire sphere for point lights, a sun for distant lights, sized in
  screen space (fixed-world fallback).
- Camera views (perspective VIEW records) and the GEODATA "daisy" marker are
  synthesized into the model-space resident wire set from the document, since
  they are not entities.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 22:15:40 +03:00
Hakan SevenandClaude Opus 4.8 1b60924bbe fix(view): show geometry far off the drawing plane
A benchmark drawing carrying a circle and an ellipse 800 km below its own
plane showed neither, and ZOOM Extents zoomed out to 800 km to find them.
Both come from sizing the view off the wrong axis.

Zoom and clipping answer to different extents and are now measured that
way: the zoom frames what the view actually shows, the extent across the
screen plane, while near/far span what lies along the eye direction.
Sizing both from the 3-D diagonal let one far-off Z drag the horizontal
zoom out with it. The two agree on a flat drawing, which is why it went
unnoticed.

A camera restored from a file's saved view keeps its pose, but nothing
had sized its near/far, so the projection fell back to a guess scaled
from the zoom distance — far too narrow when geometry reaches off the
plane, and the geometry was silently clipped away. It now takes the
drawing's own recorded extent.

$EXTMIN/$EXTMAX is untrustworthy for positioning — stale after an edit,
or the sentinel when the writer never computed it — which is why fit_all
scans entities instead. It is the right input here: too wide only costs a
little depth precision, too narrow deletes geometry, so the drawing's own
claim errs in the safe direction. It also costs nothing on open.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 22:21:38 +03:00
Hakan SevenandClaude Opus 4.8 9838cd6d83 fix(dxf): stop writing a duplicate *Active viewport (#319)
Opening a DXF whose active viewport is stored uppercase (*ACTIVE),
editing and re-saving produced a file with two full-window model-space
viewports — the file's own *ACTIVE plus a fresh *Active we add on save.
The reserved viewport name is case-insensitive, so the two didn't
collapse and other CAD apps drew them one on top of the other, which
read as the copied objects being linked / "reacting as one".

save_model_tiles_to_vports dropped existing active viewports with a
case-sensitive `name != "*Active"` filter, so an uppercase *ACTIVE
survived and sat next to the new entry. Route every *Active comparison
(save filter + camera/tile restore) through a case-insensitive
is_active_vport_name helper so the file's record is recognised and
replaced instead of duplicated.

Also bumps acadrust to #99f75fe (merged PR #1): the ASCII DXF writer now
emits shortest round-trippable floats instead of the full 16-digit
expansion, halving the round-tripped file size.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 22:36:00 +03:00
Hakan SevenandClaude Opus 4.8 b50921923f chore: post-merge cleanup for #287/#289
- Reword the two new explanatory comments to describe the behaviour on its
  own instead of citing another product.
- window_to_sheet: drop the unused window_min parameter (the caller already
  derives its coordinate offset from the returned min-corner position) and fix
  the doc comment to match what the function returns.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 01:22:10 +03:00
Kevin GriffinandClaude Fable 5 a3107d95e4 fix(view): exclude XLine/Ray display segments from ZOOM Extents (#284)
XLine/Ray tessellate as +/-1e6 display segments (entities/ray.rs), and
both fit_all outlier defenses miss them: the IQR reject passes because a
construction line through the drawing has its centroid at its base
point, inside the consensus cluster; and the per-point lim filter passes
because local_extent_max is computed once at document load and stays at
the 1e9 default for drawings created fresh in-app. The far endpoints
then poison the bounds and the view fits +/-1e6, shrinking real
geometry to a dot.

Exclude XLine/Ray wires from the extents up front (AutoCAD likewise
ignores infinite lines in ZOOM Extents), falling back to fitting their
base points when the drawing holds nothing else.

Regression tests verified to fail without the fix (camera distance
3,000,000) and pass with it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 14:08:43 -07:00
Hakan SevenandClaude Opus 4.8 572e9aca01 fix(camera): keep ortho depth precision constant across zoom
The orthographic near/far span was ±1000x the camera distance, so
zooming out ballooned the depth range and collapsed z-buffer precision:
coincident solids, meshes and wires then flipped draw order (meshes drew
in front of solids only when zoomed out, correct order when zoomed in).

Size the depth half-range from the drawing's extent instead — the bbox
diagonal on fit_to_bounds, the view height on a restored saved view —
and hold it constant as the camera zooms, so precision no longer depends
on distance. Falls back to the old distance-scaled range when unset.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 01:23:27 +03:00
Hakan SevenandClaude Opus 4.8 ddf576765b fix(view): drop non-standard camera View record; restore from VPORT
OCS wrote an app-specific "OpenCADStudio_Camera_Model" entry to the VIEW
table and preferred it when restoring the model view. That record polluted
the file for other CAD programs and its DXF round-trip was broken, so a
drawing saved in TOP reopened from DXF at an isometric-ish angle.

The model view now persists and restores entirely via the standard *Active
VPORT entry (view direction / target / twist), which round-trips natively in
both DWG and DXF. The custom View record is no longer written; existing ones
in older files are left untouched. Paper space already used the standard
sheet viewport and keeps a read-only fallback for very old files.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 19:27:23 +03:00
Hakan SevenandClaude Opus 4.8 495b13ec4f refactor(viewport): migrate model-space tiling to iced pane_grid
Replace the custom model_tiles tiling with iced 0.14 pane_grid as the layout
source of truth, while paper-space floating viewports are left untouched (they
overlap/free-place, which pane_grid cannot model).

Each Model pane is its own shader widget rendering its camera into the pane
bounds; the renderer Primitive carries a base_slot so several shader widgets
share the type-keyed MultiPipeline storage on disjoint slots. A second pane_grid
of transparent mouse_areas (plus on_resize) layers above the crosshair overlay
to receive input — the overlay's Hidden cursor interaction otherwise levitates
the cursor and starves any layer beneath it. The active pane follows the cursor
(hover-activate), and grid / crosshair / UCS icon render per pane while the
ViewCube and render-mode picker stay on the active pane only.

Split / close / VPORTS presets and the VPort table round-trip now drive
pane_grid (guillotine reconstruction on load). Adds drag-to-swap via a controls
bar handle with a ghost-card preview, visible pane dividers from the pane_grid
split regions, a default model background of RGB(33,40,48), and removes all the
superseded custom-tile code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 11:50:11 +03:00
Hakan SevenandClaude Opus 4.8 9b8ee94c0c refactor: rename mislabeled scene files to match contents
Two names collided with the pick subsystem and misdescribed their files:

- scene/hittest.rs -> scene/camera_ops.rs. Its contents are camera/view
  operations (zoom, fit-all, named-view restore, camera<->document sync,
  per-tile grid/snap), not hit-testing — the real screen-space hit-test
  lives in scene/pick/hit_test.rs.
- scene/pick/selection.rs -> scene/pick/selection_state.rs. It holds only
  the SelectionState struct; the name clashed with scene/selection.rs
  (the Scene selection operations).

Callers are unaffected (the crate::scene::SelectionState re-export path is
unchanged). No behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 23:45:16 +03:00