Commit Graph
1016 Commits
Author SHA1 Message Date
Hakan SevenandClaude Opus 4.7 cd1d3bb619 refactor(snap): producers emit f64 snap points (world_offset removal P3)
TruckEntity.snap_pts is now DVec3 and every entity producer builds snap
candidates straight from the acadrust f64 coordinates instead of casting
to f32 first (text, mtext, arc, circle, ellipse, point, shape, solid,
mline, mtext, attribute, tolerance, table, underlay, ole2frame, mesh,
multileader, dimension, block-cache). offset_snap_pts stays f64
throughout. Still offset-relative (inert) — but snap precision is no
longer capped at ~0.5 m by an early f32 cast, which fixes a latent
UTM-scale snap error and sets up the absolute-coordinate switch.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-06-23 22:10:29 +03:00
Hakan SevenandClaude Opus 4.7 a7a1fac09a refactor(snap): widen snap_pts to f64 (world_offset removal P2)
WireModel/LocalWire/TruckEntity snap buffers and the producers/consumers
now carry snap candidates as DVec3 (offset_snap_pts, dimension/multileader
producers, block-cache transform, pick/xclip, snap module). Still
offset-relative, so behaviour is unchanged — this just lets the snap
transport survive the upcoming switch to absolute coordinates without an
extra f32 quantization. The snap module still resolves in f32 (as_vec3 at
entry), matching today's precision.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-06-23 18:52:42 +03:00
Hakan SevenandClaude Opus 4.7 ab7cd63dec feat(camera): f64 CPU project/unproject helpers (world_offset removal P1)
Add camera-relative-f64 world↔screen on Camera (project_f64,
unproject_on_plane_f64): the point is made eye-relative in f64 before the
rotation-only projection, so CPU picking / overlay stay exact at large
absolute coordinates — the CPU twin of the GPU's relative-to-eye path.
Additive and inert for now; the upcoming phases route overlay, pick/snap
and coordinate readout through these so world_offset can be dropped.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-06-23 18:35:32 +03:00
Hakan SevenandClaude Opus 4.7 b3a1119b04 fix(camera): precise zoom-to-cursor pivot at large coordinates
zoom_about_point picked the world point under the cursor twice via
view_proj.inverse() (the full f32 matrix) and shifted target by their
difference. At UTM coordinates that inverse carries ~0.5 m of f32 error
that didn't cancel between the two picks, so target drifted every zoom
step and the whole scene jumped as a block.

Compute the pivot as the cursor's offset *relative to target* in the
camera frame (small numbers, rotated to world) instead — it never touches
the large absolute target, so the before/after difference is exact and
the scene stays put while zooming.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-06-23 18:28:52 +03:00
Hakan SevenandClaude Opus 4.7 65413a2c2a refactor(render): drop dead camera_pos from the shared uniform
No GPU pipeline reads camera_pos any more — lighting and all transforms
moved to the relative-to-eye path (view_rot + eye_high/eye_low). Remove
the field from the shared Uniforms and every shader struct, plus the now
unused Camera::position_vec4. view_proj stays: the CPU frustum-cull /
scissor / LOD passes still project offset-relative AABBs with it (it is
no longer part of any GPU draw).

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-06-23 18:28:52 +03:00
Hakan SevenandClaude Opus 4.7 ddf6344dbe feat(render): double-single vertices for the mesh pipeline
3D solid / surface meshes were the last single-f32 path. truck's mesh
tessellation now returns a paired verts_low residual (TruckTessResult::Mesh,
polygon_to_result), MeshModel/MeshLodSet carry it, the model-space offset
and block-instance transforms reconstruct the f64 position and re-split it
after subtracting world_offset, MeshVertex gains position_low (location 3),
and mesh.wgsl reconstructs the eye-relative position. Native SAT / ACIS /
OBJ mesh paths default to a zero residual (no regression — they were never
sub-f32 precise).

With this every world-space pipeline (wire, hatch, image, face3d, mesh)
is full double-single relative-to-eye; large-coordinate jitter is gone.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-06-23 18:28:52 +03:00
Hakan SevenandClaude Opus 4.7 c0f3d0de5e feat(render): double-single fills for the face3d pipeline
Table / PolyfaceMesh / greek-text / mleader-background fills go through
the face3d pipeline; their vertices were single f32 and quantized at UTM
scale. WireModel now carries a fill_tris_low residual (filled by the
tessellate Lines path), Face3DVertex gains position_low (location 3), and
face3d.wgsl reconstructs the eye-relative position from the pair. 3DFACE
quads built from key_vertices use a zero residual (no low source).

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-06-23 18:28:52 +03:00
Hakan SevenandClaude Opus 4.7 bd12cc2f5a feat(render): double-single corners for the image pipeline
Raster-image quad corners derive from a large f64 insertion point plus
small u/v spans; the single-f32 cast quantized them at UTM scale. The
ImageModel now keeps a corners_low residual, ImageVertex carries pos_low
(location 2), and image.wgsl reconstructs the eye-relative position from
the high/low pair.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-06-23 18:28:52 +03:00
Hakan SevenandClaude Opus 4.7 0f7920dc2c feat(render): double-single anchors for both hatch pipelines
The hatch anchor (world_origin / pattern origin) was cast to a single
f32, quantizing UTM-scale fills to ~0.5 m and reintroducing jitter the
wire path no longer had. Both the batched and per-hatch pipelines now
carry the anchor as a high/low f32 pair (HatchInstance.world_origin_low,
HatchUniformData.origin_low) and reconstruct the eye-relative position in
the shader as (origin_high - eye_high) + (local + origin_low - eye_low).

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-06-23 18:28:52 +03:00
Hakan SevenandClaude Opus 4.7 6a74f12a92 feat(render): double-single vertex positions for the wire pipeline
Vertices now carry the low residual alongside the high half all the way
to the GPU: tessellation splits the offset-relative f64 coordinate into
(high, low) f32 (TruckTessResult::Lines/Point, the Text path, Lines /
SegmentedLines, and the block-cache instance transform), WireModel and
the block batch carry a paired points_low buffer, WireInstance gains
pos_a_low/pos_b_low (locations 10/11), and wire.wgsl reconstructs
rel = (pos_high - eye_high) + (pos_low - eye_low).

This is the piece the camera-only RTE was missing: at UTM-scale
coordinates the single-f32 vertex was quantized to ~0.5 m, so it snapped
each time the eye crossed an f32 boundary on pan. With the low half the
position is exact and the cross-drawing-paste jitter is gone.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-06-23 18:28:52 +03:00
Hakan SevenandClaude Opus 4.7 97d6993768 refactor(wire): add WireModel.points_low parallel buffer (empty default)
Foundation for double-single positions: WireModel now carries an
index-paired f32 residual buffer (`points_low`) next to the existing
`points` high half. Empty means "all-zero residual", so every existing
constructor (interactive draw, previews) is unchanged in behaviour;
tessellation from CAD f64 will fill it in the next steps so vertex
precision survives at UTM-scale coordinates.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-06-23 18:28:52 +03:00
Hakan SevenandClaude Opus 4.8 a0b4968ad2 feat(render): relative-to-eye for mesh, image, face3d and hatch pipelines
Switch the remaining world-space shaders (mesh, image, face3d, hatch,
hatch_batched) to the same relative-to-eye transform the wire pipeline
uses: subtract the eye (high+low f32) per vertex and multiply by the
rotation-only view-projection. Each shader's Uniforms struct is widened
to the full shared layout so the appended RTE fields land at the correct
offsets. Math is unchanged (proj·R·(pos−eye)); large coordinates no
longer jitter on camera movement.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-23 18:28:52 +03:00
Hakan SevenandClaude Opus 4.8 2a9416464e feat(render): relative-to-eye for the wire pipeline
The wire shader now subtracts the eye (high+low f32) per endpoint and
transforms by the rotation-only view-projection instead of multiplying
absolute positions by a view-projection that bakes in a large eye
translation. The math is identical (proj·R·(pos−eye)) but the large eye
no longer enters the f32 matrix, so lines stop jittering on
pan/zoom/rotate at large (UTM) coordinates and far from world_offset.

Geometry low bits are intentionally dropped: (pos − eye_high) is exact in
f32 for same-magnitude operands (Sterbenz) and eye_low corrects the eye,
so the only residual is a static sub-f32 position error, not motion
jitter — no per-vertex low buffer needed. view_rot is cropped in lock-step
with view_proj for tiled panes.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-23 18:28:52 +03:00
Hakan SevenandClaude Opus 4.8 8f16ba1ac2 feat(render): add relative-to-eye uniform fields (inert)
Append a rotation-only view-projection plus the eye split into high/low
f32 (double-single) to the shared Uniforms buffer, and the matching
Camera helpers (view_proj_rte, eye_high_low). Fields are added at the end
so existing field offsets — and every shader still reading only the
legacy view_proj — are unaffected. No shader consumes them yet; the wire
pipeline migrates first in the next step.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-23 18:28:52 +03:00
Hakan SevenandClaude Opus 4.8 091b8e1805 refactor(camera): store orbit target in f64
Foundation for relative-to-eye rendering: the pivot the camera orbits
must stay precise at large offset-relative coordinates so the derived eye
(which the RTE path subtracts per vertex) is exact. `Camera::target` is
now DVec3 and `eye_f64()` exposes the full-precision eye; `view_proj`
still casts to f32 at the matrix, so behaviour is unchanged for now.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-23 18:28:52 +03:00
Hakan Seven 4100044c01 Update registry.json 2026-06-23 00:22:08 +03:00
Hakan Seven 2351c7495a Merge pull request #165 from KevinGriffin-new/add-landsurvey-to-registry
registry: add Land Survey plugin
2026-06-23 00:19:56 +03:00
Kevin Griffin 08c59cab23 registry: add Land Survey plugin 2026-06-22 14:11:23 -07:00
Hakan Seven d5b585e52b Merge pull request #163 from mf4633/add-hydrocomplete-registry
Add HydroComplete to plugin marketplace registry
2026-06-22 22:46:01 +03:00
Michael Flynn 53ef6b19ee Add HydroComplete to plugin marketplace registry 2026-06-22 15:25:40 -04:00
Hakan SevenandClaude Opus 4.8 e507e6615b chore(release): v0.6.5
Co-Authored-By: Claude Opus 4.8 <[email protected]>
v0.6.5
2026-06-22 20:16:02 +03:00
Hakan SevenandClaude Opus 4.8 e39c4b4424 fix(clipboard): refresh blocks/meshes on PASTEORIG and PASTEBLOCK
PASTECLIP recreated missing block definitions, tessellated pasted solids,
and refreshed the layer panel after a paste; PASTEORIG and PASTEBLOCK did
not. A block pasted through either of those rendered empty because its
definition was never recreated in the target drawing.

Both paths now call merge_clipboard_blocks (so referenced/nested block
definitions exist) and populate_meshes_from_document (so pasted ACIS
solids tessellate); PASTEORIG also refreshes the layer panel.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 19:50:58 +03:00
Hakan SevenandClaude Opus 4.8 5291a3fb82 fix(text): keep text anchors in f64 and honour space advance
Single-line TEXT and ATTRIB/ATTDEF cast the insertion/alignment point to
f32 before computing the stroke origin. At large coordinates (UTM ~4.5M)
the f32 ulp is ~0.5, snapping text baselines onto a coarse grid so
adjacent rows collapse onto each other and overlap. Keep the anchor in
f64 throughout.

Horizontal alignment now uses the pen advance box [0, advance] instead of
the inked min_x/max_x, so leading/trailing spaces keep their width and
space-aligned columns no longer shift. text_local_bounds returns
TextLocalBounds { ink_min, ink_max, advance }.

TABLE laid out its whole grid in an f32 world frame; switch to a local
f32 frame plus an f64 base added at the widening step, fixing cell-text
baseline snap and the i32 overflow in the border-dedup keys.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 18:47:45 +03:00
Hakan SevenandClaude Opus 4.8 33314a5889 feat(ucs): orient text-bearing annotations to the active UCS
New annotations now place their text and reading geometry along the
active UCS X axis (identity = world), so they read square to the user's
coordinate system instead of world-horizontal:

- TEXT / MTEXT: rotation defaults to the UCS X angle
  (DocumentTab::ucs_rotation_angle, model space only).
- Linear dimensions: measure along the UCS axis the span is nearest, and
  bake the UCS X angle as the text rotation so the value reads square
  even under a style that forces horizontal text. DIMCONTINUE / DIMBASELINE
  derive their axis from the base dim's rotation (any angle), not a
  world H/V test.
- LEADER: the MText annotation rotates to the UCS, and the hookline runs
  along the leader's horizontal_direction (set to UCS X), used by the
  renderer instead of world horizontal.
- MLEADER: context.text_direction = UCS X drives both the text rotation
  and, in the renderer, the text side and dogleg/landing direction.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 18:18:35 +03:00
Hakan SevenandClaude Opus 4.8 0c2a97e17e feat(ucs): build axis-aligned shapes in the active UCS
Commands that construct geometry with implicit axis directions ignored
the UCS, so a rectangle drawn under a rotated UCS came out world-aligned.
Give commands the UCS and build square to it:

- CadCommand::set_ucs(Mat4) (UCS→wire affine, default no-op); the host
  pushes the current UCS via App::push_ucs_to_cmd before each point /
  preview / text dispatch (DocumentTab::ucs_wire_affine, identity outside
  model space). New axis-aligned commands just override set_ucs.
- RECT (two-corner) and RECT_CEN (center) place their derived corners on
  the UCS axes (ucs_box_corners / ucs_box_around_center).
- ARRAYRECT row/column offsets run along the UCS axes.

RECT_ROT, POLYGON, and ELLIPSE already take their orientation from picked
points, so they need no change.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 17:30:42 +03:00
Hakan SevenandClaude Opus 4.8 d63602161f fix(ucs): resolve typed dynamic-input values in the active UCS
The dynamic-input boxes displayed deltas/angle in the UCS, but
dyn_resolve_point still resolved the typed (and live) values on the world
axes, so committing a typed coordinate ignored the UCS. It now rotates
the cursor delta into the UCS, interprets the typed cartesian/polar
values in that frame, and maps the relative result back to world via
UcsXform::vec_to_wcs — display and commit now agree. Absolute first-point
fields (no base) stay world; identity UCS is unchanged.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 11:33:55 +03:00
Hakan SevenandClaude Opus 4.8 481adba66b fix(ucs): grid axis lines and grid snap follow the active UCS
Two leftovers from the UCS grid work:
- The coloured X/Y/Z axis lines (draw_axes) were drawn at the world
  origin along world axes; they now run through the UCS origin along the
  UCS axes, matching the grid lines.
- Grid snap rounded the cursor on the world XYZ lattice; it now rounds in
  the UCS grid frame (to-UCS, round, back-to-world) so it lands on the
  grid the user sees. The UCS origin (wire space) + rotation reach the
  snapper via DocumentTab::ucs_grid_basis; identity outside model space.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 11:27:34 +03:00
Hakan SevenandClaude Opus 4.8 2509396ba0 fix(ucs): object snap tracking rays follow the active UCS
OTRACK alignment rays (0°/90° and polar steps, plus the polar pencil from
the last point) were built along world X/Y. They now rotate with the
active UCS via a Mat4 passed into otrack_snap (scene.viewcube_ucs_mat() —
the UCS in model space, identity in paper), so tracking lines and the
intersection lock align to the user's coordinate system like ortho,
polar, and the grid. sync_ucs_to_scene now reuses UcsXform::rotation_mat.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 11:17:55 +03:00
Hakan SevenandClaude Opus 4.8 98142ee4af fix(ucs): snap ViewCube face views square to the active UCS
Clicking a ViewCube face rotated the gaze into the UCS frame but derived
the up vector from world X/Y/Z, so the snapped view landed world-aligned
(most visibly Top, where the UCS shares world Z and only the in-plane
roll differs). snap_to_direction now takes the UCS basis and picks its up
from the UCS axes, so a face snap lands square to the user's coordinate
system. Identity UCS reproduces the world-aligned snap.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 11:12:43 +03:00
Hakan SevenandClaude Opus 4.8 b676874a6f feat(ucs): dynamic-input deltas and angle in the active UCS
The on-canvas dynamic-input boxes measured relative X/Y deltas and the
polar angle in world axes. They now read in the active UCS plane (via
UcsXform::vec_to_ucs on the offset-invariant delta), matching the UCS
ortho/polar constraints and coordinate readout. Identity UCS reproduces
the world-frame values; absolute first-point fields are unchanged.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 10:13:47 +03:00
Hakan SevenandClaude Opus 4.8 d78ed60582 feat(ucs): orient the ViewCube to the active UCS
The ViewCube showed world Front/Top/Right. It now composes the camera
rotation with the active UCS (scene.viewcube_ucs, synced from the tab's
active_ucs), so its faces follow the user's coordinate system in model
space. Render uniform, hover/click hit-test, and the click→snap direction
all go through scene.viewcube_ucs_mat() so they stay in lock-step;
identity outside model space leaves paper-viewport navigation unchanged.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 10:10:47 +03:00
Hakan SevenandClaude Opus 4.8 88bf2e57dc feat(ucs): align the model grid to the active UCS
The grid ruled along world X/Y/Z through the world origin. It now rules
along the active UCS axes through the UCS origin (passed in render/wire
space), so it lines up with the user's coordinate system. Paper space
stays plain WCS; identity UCS reproduces the old world-aligned grid.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 10:03:35 +03:00
Hakan SevenandClaude Opus 4.8 746a2c97be feat(ucs): ortho/polar constrain in the active UCS plane
Ortho and polar drawing constraints snapped to world X/Y; under an active
UCS they now snap to the UCS axes, routed through the shared UcsXform
(identity = unchanged world-XY behaviour). Applied at all three input
sites (grip drag, command point, command preview). Typed coordinates
already flow through the converter via ucs_to_wcs / ucs_rotate_vec.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 10:00:53 +03:00
Hakan SevenandClaude Opus 4.8 4aa1e90dcf feat(ucs): central WCS↔UCS converter; adopt file UCS, drive readout + icon
Introduce one bridge between WCS (how geometry and the file are stored)
and the active UCS (the coordinate system the user works in), so every
UCS-aware system routes through it instead of re-deriving axis math.

- UcsXform (app/helpers.rs): the converter — to_wcs/to_ucs (points),
  vec_to_wcs/vec_to_ucs (directions), axes(), is_identity(). Orthonormal
  axes, so the inverse is the transpose. The old ucs_to_wcs / ucs_rotate_vec
  free fns now delegate to it (one implementation).
- DocumentTab::ucs_xform() builds it from the tab's active_ucs (None = WCS).
- DocumentTab::adopt_active_ucs_from_header() loads the document's saved
  current UCS (header model-space UCS) into active_ucs on open, so the file's
  coordinate system is live immediately; called from both load paths.
- Status-bar coordinate readout reports the cursor in the active UCS.
- UCS icon tripod projects the active UCS axes, so it rotates to the UCS
  instead of always showing world X/Y/Z.

First slice of routing the app's coordinate systems through the converter;
input/picking, grid, ViewCube, and the remaining readouts follow.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 09:57:39 +03:00
Hakan SevenandClaude Opus 4.8 44d2df9361 fix(view): unify model VPORT / paper VIEWPORT view handling
Model-space tiled VPORTs and paper-space floating VIEWPORTs each carried
their own copy of the saved-view→camera math, so a fix to one drifted
from the other (the recurring grid/twist regressions). Route both, plus
the View-table and sheet-viewport paths, through one decoder and fix the
bugs that the duplication hid.

Decoder unification:
- New camera_from_view(direction, target, center, height, twist,
  world_offset): the single saved-view→Camera decoder. camera_from_vport
  (tiled), camera_for_viewport (floating, + auto-fit), and the View-entry
  / sheet-viewport apply paths all delegate to it. Tiled vs floating now
  differ only in field source and the floating auto-fit fallback.

Twist round-trips on layout switch and file save:
- camera_from_view applies roll = -twist; the write path was dropping it,
  so model→paper→model (and reload) reset the view to raw orientation.
- New Camera::roll() recovers the camera roll; sync_camera_to_document,
  write_camera_view_entry, and vport_from_camera now store -roll as the
  view twist on the *Active VPort, the OpenCADStudio_Camera_Model View
  entry, the per-tile VPorts, and the paper sheet viewport.

Rotation-aware frustum cull:
- New view_cull_aabb(): the entity-cull rectangle is built from the
  camera's right/up basis (so a twisted/rotated view's rotated rectangle
  is enclosed) instead of world X/Y axes; returns None for tilted views
  to disable the flat-XY cull rather than wrongly hide geometry. Applied
  to the model-tile and paper-viewport cull sites.

Paper viewport scale:
- The floating-viewport auto-fit overlap test summed view_target +
  view_center raw; under a twist view_center is a DCS offset, so the sum
  landed far from the real WCS centre and wrongly tripped the auto-fit,
  rendering content at the wrong zoom. It now tests the decoded
  (twist-folded, wire-space) target. The CPU projection path derives its
  scale from that same camera, locking hit-test/snap to the GPU render.

Grid enumeration:
- ViewportInstance gains grid_on; the two grid-view collectors collapse
  into one grid_views() derived from the same active_viewports() list the
  renderer uses, so the grid overlay can no longer drift from the views
  on screen.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 09:35:06 +03:00
Hakan SevenandClaude Opus 4.8 7a1988e851 fix(view): apply saved view twist as camera roll on load
Drawings authored under a rotated UCS save a view twist so they open
square. camera_from_vport ignored VPort.view_twist (roll hardcoded 0),
so such files rendered in raw world orientation and looked tilted.

Feed -view_twist in as the camera roll: the twist rotates world-X onto
screen-right, so the direction that becomes horizontal is its negative.
The roll rides the camera quaternion, surviving render and orbit.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 08:52:20 +03:00
Hakan SevenandClaude Opus 4.8 10e4c18ba7 chore: silence native and wasm build warnings
Gate target-specific code so neither build warns about the other's items:
native-only helpers (view, window icon, file dialogs, file association, plugin
host/guard/registry, self-update) are cfg'd to non-wasm; the wasm-only font
fallback (script_of / cjk_lang / request) is cfg'd to wasm. Drop an unused mut,
allow the few genuinely-conditional dead items (mesh_click_hit, GPU layout
helpers, parity stubs), and gate the embedded PlotSettings-unrelated dead
constants. Both targets now build clean (only the unavoidable nom/quick-xml
future-incompat dependency notice remains).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 02:03:34 +03:00
Hakan SevenandClaude Opus 4.8 2de5c7668f chore(deps): update lock so the wasm build compiles again
A toolchain/libc shift broke the previously-locked transitive set on wasm32
(memchr 1.0.2's libc::memchr binding stopped resolving), failing the web/Pages
deploy. Re-resolve within the existing version requirements — no Cargo.toml
change needed. Native and wasm32 both build.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 01:40:26 +03:00
Hakan SevenandClaude Opus 4.8 7fa12b757b chore(release): bump to 0.6.4
Co-Authored-By: Claude Opus 4.8 <[email protected]>
v0.6.4
2026-06-22 01:12:03 +03:00
Hakan SevenandClaude Opus 4.8 e7352cfc24 chore(deps): bump acadrust for block header owned-handle fix
Picks up the fix that keeps a block's owned-handle list in sync with the
entities actually written, so AutoCAD no longer drops model-space geometry from
OCS-saved files.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 01:05:30 +03:00
Hakan SevenandClaude Opus 4.8 429f3035b1 fix(layout): fully remove a deleted layout's record and references
delete_layout removed the Layout object and its entities but left the paper
space block record, the ACAD_LAYOUT dictionary entry and any standalone
PlotSettings behind. AutoCAD pairs every paper-space block record with a layout,
so the deleted tab could reappear on reopen. Also drop the block record, the
dictionary entry and the page setup so the layout is gone for good.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 00:37:58 +03:00
Hakan SevenandClaude Opus 4.8 26479b6faa fix(grid): independent, clipped grid per viewport
Grid (and grid-snap) state was shared through the global show_grid flag, so
toggling it in model space also turned it on in paper space, and a floating
viewport's grid painted across the whole paper — and beyond the 3-D view when
zoomed in.

- Store grid/snap per view: a model tile in model space, the active floating
  viewport or the layout's sheet viewport in paper space, round-tripped via the
  viewport status flags.
- adopt_view_display on layout switch and viewport enter/exit so the live
  toggle follows the view you are in.
- Render one grid per view (paper_viewport_grid_views): the sheet over the
  paper, each floating viewport clipped to its screen rectangle.
- Clamp the grid clip to the widget so an overflowing viewport rectangle never
  paints grid outside the 3-D view.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 00:18:01 +03:00
Hakan SevenandClaude Opus 4.8 ba834fb166 fix(layout): faithful paper-space round-trip and page setup (#156)
Builds on the acadrust viewport/PlotSettings round-trip fixes:

- Write the sheet viewport's view position into view_center (DCS) with
  view_target at the origin, matching AutoCAD; the old view_target form shifted
  the layout.
- PAGESETUP now writes paper size, rotation, origin and units onto the Layout's
  embedded PlotSettings (not just a side object), and bumps geometry, so an edit
  shows on the sheet immediately and survives a save.
- Draw the printable-area guide (paper inset by plot margins, rotation-aware) as
  a dashed rectangle, matching AutoCAD's layout view.
- Plot/PDF export falls back to the Layout's embedded PlotSettings via
  effective_plot_settings(), so a loaded file's rotation/origin/scale apply.

Bumps acadrust to pick up the viewport-status and PlotSettings round-trip fixes.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-21 23:47:36 +03:00
Hakan SevenandClaude Opus 4.8 9d5ee75bcc fix(layout): place sheet viewport center in the paper plane (#156)
The overall (sheet) viewport was created with its center as (x, 0, z) —
carrying the paper-height midpoint in z with y = 0. AutoCAD/TrueView read a
paper-space viewport center as (x, y), so the sheet view ended up centered at
y = 0, shifting the whole layout half a page down; activating the layout in
AutoCAD could fault on the off-plane viewport. Store the center as (x, y, 0),
matching the convention MVIEW already uses for floating viewports. Verified: a
newly created paper-space viewport no longer faults AutoCAD on layout switch.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-21 13:20:16 +03:00
Hakan SevenandClaude Opus 4.8 c80cc3292c docs(commands): sync COMMANDS.md with implemented commands
Mark commands that are wired and dispatching as done: 3DARRAY, the solid
booleans (UNION/SUBTRACT/INTERSECT), the CONE/WEDGE/TORUS primitives,
LAYISO/LAYUNISO, DIST/ID/LIST inquiry, named-view VIEW, and QUIT. Refresh the
summary totals (done 141 -> 158, missing 91 -> 74).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-21 12:28:42 +03:00
Hakan SevenandClaude Opus 4.8 a72df6a805 feat(command): surface one-shot commands in command-line autocomplete
File/view/layer/style/undo-redo and similar one-shot commands dispatch a
single action instead of installing an interactive CadCommand, so they had no
module to register from and never appeared in autocomplete. Add a consolidated
CommandRegistration covering all 132 user-typeable one-shots (NEW, OPEN, SAVE,
SAVEAS, PLOT, PURGE, UNDO, REDO, ZOOM, LAYER, XREF, …). Internal dispatch
tokens the user never types (REFEDIT_BEGIN, REFCLOSE_SAVE, REFCLOSE_DISCARD)
stay excluded.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-21 12:24:34 +03:00
Hakan SevenandClaude Opus 4.8 5673612047 fix(command): register remaining interactive commands for autocomplete
ARRAY3D/3DARRAY, ATTEDIT/ATE, DDEDIT/ED and WIPEOUT/WO dispatched on literal
matches but had no CommandRegistration entry, so none surfaced in command-line
autocomplete. Add the inventory submit in each command's module, matching the
convention used by the other interactive commands. Audit confirms no remaining
active_cmd dispatch lacks a registration.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-21 12:20:36 +03:00
Hakan SevenandClaude Opus 4.8 895937913f fix(modify): register TORIENT in the autocomplete command registry
TORIENT dispatched on a literal match but had no CommandRegistration entry,
so it never surfaced in command-line autocomplete. Add the inventory submit
like the other interactive commands.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-21 12:16:35 +03:00
Hakan SevenandClaude Opus 4.8 b134aff4e3 refactor(annotate): route TEXTEDIT Mode entry through parse_texteditmode
Fold the Single/Multiple value parsing in TexteditCommand's Mode step into
the shared parse_texteditmode() helper, and report unrecognized input to
the user — the Mode step now stays active and re-prompts with
"Requires Single or Multiple." instead of silently ignoring the value.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-21 12:10:39 +03:00
Hakan SevenandClaude Opus 4.8 8c48233dcf merge: TEXTEDIT command + TEXTEDITMODE sysvar (#130)
Merge PR #130 (KarimJerbi) and resolve review findings:

- Conflict (settings.rs): keep current persisted-settings layout, append
  texteditmode field.
- Conflict (command/mod.rs): keep both new CmdResult variants — main's
  live-entity ops and the PR's text-edit suspend/resume.
- Bug: invalid TEXTEDITMODE value no longer aborts via the Measurement
  arm; it now re-prompts with the error and stays active.
- Dedup: single parse_texteditmode() helper replaces the value parsing
  duplicated across commands.rs, settings.rs and textedit.rs.
- Strip trailing whitespace.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-21 12:05:54 +03:00