#1688 accepted any degree (falling back to 3 on a malformed value) and
overwrote the degree the codec had clamped to the control-point count, so
a two-point default spline stored degree 3 against a degree-1 knot vector.
Reject a non-integer or out-of-range degree, too few control points for
the degree, a knot vector that is not control_points + degree + 1
non-decreasing values, and weights that are not one positive value per
control point.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
#1666 sets group 295 on extrusion history records, which makes the kernel
read the embedded profile and path where they stand and ignore the
matrices. The planar fallback profile (a region-derived LWPOLYLINE) was
stored in its plane's local frame with the frame as matrix, so with the
flag it rebuilt at the origin. Re-express it in its own OCS (normal and
elevation) when the record is built.
Pins the kernel and graph at upstream (opencadkernel#84 merged as f051138)
instead of the ramox81/cadkernel [patch].
Co-Authored-By: Claude Opus 5.5 <[email protected]>
#1681 places a dimension's picture block by its insertion point, rotation
and scale. Edits (move/rotate/scale/mirror, copy, paste) transform the
picture's sub-entities in world space, and the codec's dimension transform
moves the insertion point too, so a rotated or copied dimension would get
the placement applied twice. Fold the placement into the subs before the
edit and leave the dimension at the identity placement afterwards.
The picture insert no longer takes the dimension's extrusion: OCS bakes
picture sub-entities in world coordinates, so only the stored insertion
point goes through the OCS. A zero insertion-scale component counts as 1.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The informational clippy job fails on two pre-existing literals
(also failing on main, surfaced on this PR's merge): the trim
tangency test's angle list used 3.14 where pi was meant — use the
constant; the point-cloud light-direction fixture in render.rs uses
a hand-tuned 0.318 component that only looks like 1/pi — keep the
tuned value and allow the lint on that statement.
Resolve conflicts from main's rustfmt pass by taking main's versions of
command.rs, style.rs, view/mod.rs, scene/mod.rs, ui/window/mod.rs and
ui/properties.rs and re-applying this branch's Graphic Attributes changes.
Add the Graphic Attributes strings to the new lo-LA catalog.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01E1QnME6WJbD5iGFae1eeCb
The internal per-call push_undo fractured plugin-composed operations:
history has no nested scopes, so each push finished the plugin's
still-pending scope and opened its own — an operation of several
writes became several undo steps and the plugin's label was lost
(measured: 3 creates + update + delete in one scope = 5 steps).
Follow the entity-write contract instead: a mutation inside a
plugin-opened push_undo scope joins it, so the whole operation is a
single undo step under the plugin's label; a scope-less mutation opens
and finishes its own scope, keeping one undo step per call; refusals
record no undo step in either regime. Document the contract on the
trait methods and the host docs; the composition experiment becomes
the permanent xrecord_writes_join_a_plugin_initiated_undo_scope test.
Resolved conflicts:
- app/update/mod.rs: keep the dock's dock_open_at_default for the XREF
manager; take main's stable xref row identity (row_index(&id)).
- app/view/mod.rs: keep the edge layout from app::dock; drop main's copy
of the old edge-stack code (main only reformatted it there).
- ui/window/layers.rs: keep main's new visible_indices next to the
branch's view_panel.
Files the branch only reformatted take main's version. Adds the Lao
(lo-LA) translations for the new dock texts.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
Add create/read/update/delete/list for XRecord objects under
named-object-dictionary paths to the plugin HostApi, with five additive
PluginRequest/PluginResponse variants, dispatch through the shared
handler, in-process HostSession methods and both out-of-process proxies.
- dictionary paths walk from the NOD root; create seeds missing
dictionaries (ensure_image_dictionary bootstrap) and refuses existing
names; update refuses missing ones; refusals precede the undo step
- entry group codes validated (1..=369, never 5/105); payload content is
the plugin's own
- each mutating call is one undo step: the pending history snapshot
restores the objects map byte-exactly, auto-created dictionaries
included (tested)
- typed entries survive DWG and DXF write/reload round-trips (tested);
update drops verbatim raw bytes so saves emit the new content
- bump API_VERSION 7 -> 8 with the build.rs version_info in lockstep,
mirroring the v7 addition; MIN_SUPPORTED stays 3
A focused text field reports Status::Captured, so the key dispatch
dropped SPACE and a CUI rebind of SPACE to FINALIZE never ran while the
command line held focus (#1710). Dispatch a captured SPACE as a shortcut
only when SPACE is bound to something other than COMMANDSPACE, so the
default binding still types a space. The closure stays a plain fn, so a
static flag mirrors the binding and is refreshed wherever the bindings
change.
- Implement Apollonius PPC (Point-Point-Curve) and multi-tangent CCP solvers for lines in arc.rs
- Support tangent line snapping for all 3-input arc combinations (Tangent-Point-Point, Point-Tangent-Point, Tangent-Tangent-Point, Tangent-Point-Tangent, Point-Tangent-Tangent)
- Resolve TangentGeom::Line f32 truncation in snap.rs to preserve true f64 key vertices during tangent evaluation and TangentObject construction
- Preserve strict CUT_TOLERANCE (1e-7) in trim.rs while ensuring tangent contact points are detected accurately
- Add unit tests for line tangency solvers, tangent trim detection, and angular precision sweeps
Kernel: fillets and chamfers along plane-cylinder rulings; blend
booleans refused when they change the solid by more than their tool.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Kernel: spline normals and tangents kept while a body is meshed —
solid display of spline-heavy drawings up to 2.7 times faster.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
style_new/copy/delete funneled through a load_style_bufs no-op for Table/MLine, leaving stale editor buffers pointed at the fresh style; both arms now route to the existing loaders. Table cell text-style typos persisted as dangling names; unknown names are now rejected with command-line feedback, keeping the buffer text for correction. Silent numeric parse-drops deliberately untouched (codebase-wide keep-old-valid norm). Tests: table_new_reloads_cell_buffers plus table_cell_unknown_text_style_is_rejected incl. retention assert (RED each verified by temporary revert). Full suite: 2048 passed / 0 failed / 25 ignored, zero warnings.
Tests previously ran on Ubuntu only, so Windows- and macOS-specific breakage went unseen. Add a 3-OS test matrix and a separate lint job for rustfmt and clippy. Lint is continue-on-error because the tree is not yet fmt-clean or clippy-clean.
Also add BEDIT characterization tests that pin current session, undo and refusal behavior ahead of the editor refactor. Locked tests guard behavior that must survive; documenting tests record questionable behavior expected to change.
The edge-stack closure duplicated dock_panel_visible arm-for-arm; it now delegates (tab is provably the active tab at that site). Ribbon.layer_names was written but never read outside one test; deleted, test reads via layer_infos. Faces and combo-refresh sub-items investigated and dropped (already unified upstream; no live stale path). Tests: dock visibility parity pins incl. Start-tab. Full suite: 2046 passed / 0 failed / 25 ignored, zero warnings.
XrefManagerSelect/RightClick/RowOp/PathPick/FindReplace carried positional display indices that rescans could retarget. New XrefRowId{key,saved_path} (the identity refresh uses) in all 5 variants, resolved via row_index at dispatch with graceful no-op; panel selection stays index-based. display.index remains for view-time styling/lookup only. Tests: xref_rowop_unknown_id_is_noop (RED first); existing dialog/simulator/click tests migrated to ids. Full suite: 2044 passed / 0 failed / 25 ignored.
AnnoObjectScaleToggle had three silent no-op paths (no target, locked layer, unknown scale); each now pushes command-line info mirroring the open-path guards. Xref empty-state hardcoded grey now uses muted_style. DD_BOUNDS eviction and attr-clamp changes investigated and deliberately dropped (no reachable defect in either). Tests: anno_scale_toggle_tests cover all three paths (RED: silence). Full suite: 2032 passed / 0 failed / 25 ignored, zero warnings.
editor_layer_row and view_editor took Vec<String>, cloning N strings per row per frame (times two build-closure runs). Both take Arc<[String]> now; a plain borrow cannot cross the twice-run closure (E0373), hence the Arc. Cow empty-filter short-circuit for both search queries. Test: view_editor_accepts_shared_linetypes (RED first). Full suite: 2029 passed / 0 failed / 25 ignored, zero warnings.
Kernel: fillets and chamfers round plane-cylinder/cone circles (hole and
boss rims, countersinks), shell for any planar solid, NURBS projection
onto the right pass of a looping curve, straight rational profile
pieces, slice section precision.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Allow users to temporarily override object snaps during active point prompts by typing at least the first 3 letters of any snap mode (e.g. MID, END, CEN, PER, NON). The override activates for the next point pick only and automatically restores running snaps once consumed or cancelled.
VP-freeze columns used the global-freeze glyph; shift-ranges swept filtered-out rows into bulk ops. Glyph swapped to layer_vp_freeze (ribbon precedent); new visible_indices helper shared by the view loop and the shift arm. Test: shift_select_skips_filtered_out_rows (RED: hidden row in range). Full suite: 2028 passed / 0 failed / 25 ignored.
A region's loop area sums its pieces with Curve::chain_area, the
composable share: enclosed_area closes an open polyline by its chord.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The pill number used the first-content fallback while the label and sync badge used explicit-only resolution, showing e.g. a 1:50 number beside a 1:1 label with no badge. Label and badge now resolve through target_viewport_handle like the number; render-path handle fn, set-paths and Model branches untouched. Tests: scale_pill_sources_agree_without_targeted_viewport (RED: live probe Some(0.02)/1:1/None) plus Model-unchanged pin. Full suite: 2027 passed / 0 failed / 25 ignored.
props_asym_scale was app-global keyed by raw handle values, but fresh documents restart numbering at seed 1, leaking one tab's unchecked Uniform box into another tab reusing the value. The set moves to DocumentTab; all uses tab-scoped. Also removes a dead destructure left in overlay.rs. Test: asym_scale_opt_out_does_not_leak_across_tabs with handle-reuse premise assert (RED first). Full suite: 2025 passed / 0 failed / 25 ignored, zero warnings.
- Only docked pallets have a width divider, so the Width drag and
WidthReset no longer carry a branch for an undocked pallet; remove the
then unused DockState::set_width / reset_width. Per-pallet widths are
still read (older configs, floating size). Tests now size groups.
- on_dock hands hover messages to dock_hover and the release to
dock_drag_release.
- dock_slot_spans and dock_landing share dock_open_spans.
No behaviour change.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt