Commit Graph
3576 Commits
Author SHA1 Message Date
Hakan Seven b2ec9ef863 Merge PR #1096: align history controls and fix browser history copy 2026-09-09 13:09:18 +03:00
ramox81 85abdf0c12 Merge remote-tracking branch 'origin/main' into codex/thicken-parity
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	crates/ocs_doc_api/Cargo.toml
2026-09-09 12:57:32 +03:00
ramox81 4b45e06cf8 Implement surface thickening workflow 2026-09-09 12:35:18 +03:00
Felix RiestraandClaude Sonnet 5 44deee2ac9 Port 6 audit-found bugs from the upstream OSNAP fix branch
Ports the fixes from fix/osnap-circle-arc-ellipse-intersection (and
this session's audit follow-up) onto this branch. All are independent
correctness/reliability fixes, unrelated to the parametric-constraint-
system work also in progress here.

1. OSNAP Intersection snap used a tessellated approximation instead of
   exact geometry (GitHub discussion #1052): a circle/arc always
   tessellates at a fixed 48 segments in the resident wire set
   regardless of radius or zoom, so every circle/arc intersection snap
   was off by construction. Added exact_circle_intersections, a
   closed-form, frame-independent circle/arc-vs-circle/arc solver,
   wired into both Intersection-snap code paths ahead of the
   tessellated sweep. This branch's TangentGeom predates the
   PlanarEllipse variant added upstream, so the ellipse/line
   generalization from the upstream fix isn't ported here — this
   covers the literal reported bug (a circle-circle case) using only
   variants this branch already has.

2. Unbounded MINSERT allocation: array_offsets() reserved one Vec
   element per array instance with row/column counts parsed as
   unchecked u16s — a corrupt 65535x65535 pair requests ~96 GiB.
   Fixed with a documented instance budget (20,000), enforced at both
   the load-time corrupt-entity filter and a render-graph failsafe.

3. MINSERT spacing was scaled by the block's own scale:
   insert_instance_transform composed the offset translation before
   the instance transform, so x/y block scale multiplied the row/
   column spacing too. Fixed by orienting the offset with rotation +
   OCS only, then translating the already-scaled instance transform.

4. Automation "open" skipped the finalization (block-origin
   normalization, raster-path resolution, source_path) and corrupt-
   entity purge a UI open always runs. Added
   io::load_bytes_finalized(path, bytes), used by automation's "open"
   handler, which now also reports the purge count.

5. Material maps were uploaded without checking
   device.limits().max_texture_dimension_2d, unlike raster-image
   rendering (which already tiles to that limit). A mesh material is
   sampled by UV, so it can't use the same tiling trick — instead,
   upload_rgba_texture now downscales an oversized image before
   upload, falling back to the 1x1 material color if malformed.

6. Sketch-constraint persistence/undo, audit-found while reviewing
   this branch's own constraint system:
   - Clearing every constraint in a scope after a prior non-empty save
     left the stale XRecord in place, resurrecting the deleted
     constraints on the next load. materialize_sketch_constraints_for_
     save now actively removes the XRecord when a scope goes back to
     empty.
   - ERASE removing an entity took its constraints with it (design
     doc's deletion policy), but sketch_constraints lives on Scene,
     outside document/document.objects, so nothing captured that
     mutation for undo — the erased geometry came back on undo, but
     its constraints didn't. refresh_sketch_constraints's deletion
     pass now records the touched scope's before-image into the same
     UndoRecording the entity removal rides in, threaded through a new
     sketch_constraints channel on DeltaSnapshot, so one undo restores
     both together. HistorySnapshot::Delta is now boxed (clippy
     flagged the resulting size skew across undo/redo stack variants).

31 new/adapted tests across all six fixes. Full workspace suite passes
except the one pre-existing, unrelated font-test failure also present
on main.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-09-09 10:46:28 +02:00
Felix RiestraandClaude Sonnet 5 78259c7aed Fix OSNAP Intersection snap using tessellated approximation
github.com/HakanSeven12/OpenCADStudio discussion #1052: constructing a
3-4-5 right triangle by drawing two circles (radius 3 and 4, centers 5
apart) and using OSNAP Intersection to find their crossing points gave
measured side lengths that didn't match the entered radii.

OSNAP's Intersection snap found candidate points by sweeping line
segments from each wire's *tessellated* polyline approximation, never
the entity's real geometry. Circles feeding the resident wire set
always tessellate at a fixed 48 segments (Scene::resident_wires_for
passes wpp=None deliberately, to avoid re-tessellating on every camera
pan/zoom) regardless of radius or zoom — so every circle/arc/ellipse
intersection snap was already off by construction, not just at extreme
zoom levels. Arcs, ellipses, and splines have the same problem via
their own fixed-angle tessellation.

Added an exact intersection path that bypasses tessellation entirely,
used by both call sites in the Intersection-snap code (the indexed/
local fast path and the brute-force wire-pair fallback), falling back
to the original tessellated sweep for anything it can't resolve:

- exact_circle_intersections: closed-form circle/circle intersection
  for any pair of Circle/Arc entities (frame-independent — each side's
  own arc sweep is checked against its own native axis, so two arcs in
  differently rotated coordinate frames still resolve correctly).
- exact_curve_intersections: a more general path for anything
  involving a line or an ellipse — embeds both entities into a shared
  working plane and dispatches to cadkernel::geom2d::intersect (an
  exact/tolerance-converged solver already vendored in this repo's own
  dependency but previously unused for this purpose). Handles a
  reflection hazard the naive version would miss: when an entity's own
  normal is anti-parallel to the shared embedding frame's normal, the
  mapping mirrors the parametrization and reverses which physical arc
  a [start, end] range refers to — both the Arc and PlanarEllipse
  branches detect this and swap start/end to compensate.

The only remaining case still going through the tessellated sweep is a
compound polyline chain with a bulge segment (not a single recognized
curve — it would need its own per-segment bookkeeping this pass
doesn't add).

12 new tests, including the reported 3-4-5 case verified against the
exact expected crossing points, arcs in differently rotated frames,
and the anti-parallel-normal reflection case for both Arc and Ellipse
(independently verified via a Python script for exact precision).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-09-09 10:13:30 +02:00
Felix RiestraandClaude Sonnet 5 86e3a0c794 Downscale oversized material maps to the GPU texture limit
Material map images (diffuse/specular/reflection/opacity/bump/
refraction/normal) were decoded at their original file dimensions and
uploaded to wgpu without checking device.limits().max_texture_dimension_2d,
unlike raster-image rendering, which already tiles to that same limit.
An oversized material map produced a wgpu validation error and left
the material unusable; the global error handler prevented a process
abort, but never produced a valid texture either.

A mesh material is sampled by UV across a surface, so it can't use the
same per-quad tiling trick raster images use. Instead,
upload_rgba_texture now checks the decoded image against the device's
texture-size limit and downscales it (aspect-preserving, via
image::imageops::resize) before upload when it's oversized, falling
back to the existing 1x1 material color if the decoded buffer is
malformed (its length doesn't match its reported dimensions).

3 new tests cover the resize math (aspect ratio preserved, both
dimensions respect the limit) and the malformed-input fallback.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-09-09 10:13:14 +02:00
Felix RiestraandClaude Sonnet 5 d0025d6ddf Make automation "open" run the same finalization as a UI open
Automation's "open" op called io::load_bytes directly and installed
the result as-is, skipping everything the canonical path-based loader
(load_file_for_open / finalize_loaded_outcome) runs after parsing:
block-origin normalization for legacy non-zero-origin blocks,
relative raster/material path resolution, source_path assignment,
and the corrupt-entity purge the UI open path always applies. The
same file opened two ways behaved differently, and headless/automation
use was more exposed to malformed geometry with no filter at all.

Added io::load_bytes_finalized(path, bytes), which runs load_bytes
plus that same normalization and purge using the real path (not just
its basename, which the old code passed to load_bytes as the "name"
parameter — losing the directory needed for raster-path resolution
and source_path). automation.rs's "open" handler now uses it and
reports the purge count as a "purged" field in the response.

load_bytes itself is unchanged, since the byte round-trip tests
(sketch_persist.rs, named_parameters_persist.rs) deliberately want
the simpler byte-only path with no real filesystem path behind it.

New test constructs a document with one normal and one corrupt
(zero-radius) entity, saves it, opens it through automation, and
checks the corrupt entity was purged and source_path was set —
proving the automation path now matches the UI path.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-09-09 10:13:06 +02:00
Felix RiestraandClaude Sonnet 5 8bc9e83c2e Fix unbounded MINSERT allocation and scale-multiplied spacing
Two independent MINSERT (array INSERT) bugs found while auditing
render_graph.rs:

1. array_offsets() reserved and filled one Vec element per array
   instance, with row_count/column_count parsed as unchecked u16s.
   A corrupt or adversarial 65535x65535 pair requests 4,294,836,225
   instances (~96 GiB) before any GPU-side chunking limit can help,
   and before the render graph even reaches the GPU. Fixed with a
   documented instance budget (20,000) enforced at both the load-time
   corrupt-entity filter (is_entity_corrupt, matching the existing
   polyline/spline vertex-count guards) and a failsafe clamp in
   array_offsets itself, for an insert built or edited some other way.

2. insert_instance_transform composed the per-instance row/column
   offset translation *before* the INSERT's own transform, so the
   block's x/y scale multiplied the spacing along with the block
   contents — an INSERT with x-scale 2 and column spacing 10 rendered
   20 units between columns instead of 10. The pinned CAD model's own
   Insert::array_points() confirms the correct behavior: spacing
   rotates with the insert but is never scaled. Fixed by orienting the
   offset with rotation + OCS only, then translating the already-
   composed (scaled) instance transform by that world-space vector.

7 new tests cover both: pathological/reasonable instance counts at
the load-time filter and the render-graph failsafe, and instance
transforms for scaled and rotated arrays.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-09-09 10:12:53 +02:00
ramox81 b9b9566120 Align generic solid properties palette 2026-09-09 11:05:44 +03:00
Hakan Seven 672297e732 chore: update DWG class metadata repair 2026-09-09 10:42:25 +03:00
Panos f9cacaec2b Say where a selection's hit-testing time goes, and stop hashing to skip wires
`hit` was one number covering five things: resolving candidate handles, the
wire box test, two hatch tests and two mesh tests. `select-commit` now
reports them apart, which immediately reframed the problem — at 186 468
entities the wire box test is 55 ms of 206, the hatch tests are 103, and
handle resolution is 47.

Two changes alongside it, both in the crossing scan.

Skipping a wire already in the selection was keyed by hashing its name, once
per triangle and once per glyph inside the box. A bitmap over wire indices
answers the same question with an array index. The name set stays behind it,
because several wires can share one entity's name and the output dedups by
name; a wire whose name is already in that set now gets tested once more
before being dropped, which costs one projection and changes no output.

The degenerate-wire loop that ends both the box and the lasso scans tested
`seen.contains(wire.name)` before the structural tests beside it. `||`
short-circuits, so with the name lookup last a wire with two or more points —
very nearly all of them — is dropped without hashing anything. That loop
walks every candidate, so it was one string hash per wire in the box.
2026-09-09 10:39:37 +03:00
Panos 273821658a Stop the properties panel walking the whole selection
Rebuilding the properties panel for a 186 468-entity selection took ~112 ms,
and four things in it scaled with the selection for no reason.

The panel filtered the selection down to the active group with
`group.handles.contains(handle)`, a linear scan of a `Vec`, once per selected
entity. The default group is "All", which holds every selected handle, so
both factors are the whole selection: 186 468 squared. Hashing the group once
makes it linear. The measured cost never showed this — 55 ms at 1 993
entities against 112 ms at 186 468 is not a quadratic curve — but the scan is
still wrong, and it is the shape of thing that turns a large selection into
an unresponsive window.

`entity_in_working_plane` clones the entity before it checks whether the
plane is the identity, so with no UCS in play the panel deep-cloned every
selected entity to get back what it was handed. It now borrows, and clones
only where a transform is applied.

`aggregate_sections` built every entity's property list, collected them all,
then folded them together and read each exactly once. A property list is
sections of labels and formatted values, every one an allocation, so a
whole-drawing selection held 186 468 of them in memory at the same time. It
now builds one, folds it, and drops it, and stops once nothing is left in
common. The fold order is unchanged, so the result is too.

The ribbon sync cloned each entity's linetype into a `String` only to compare
it, and kept walking after every field had been found mixed. Once all four
are mixed nothing further can change, so it stops there.

`aggregate_sections` and `merge_sections` had no tests, so the fold that
drives the whole multi-selection panel was resting on the compiler. Two now
cover it: a field the entities agree on keeps its value, one they differ on
reads as varying, and a single entity folds to its own rows.

`properties-detail` and `properties-panel` report the phases, which is how
the panel arm was ruled out as the remaining cost — it does not reach its
5 ms floor at 186 468 entities.
2026-09-09 10:38:12 +03:00
Panos f128ed3eaf Build the selection highlight in one pass instead of four
Highlighting a whole-drawing selection took 299 ms, and it runs when the
selection changes — directly between the click that completes a selection and
seeing it.

Most of that was asking the same question twice. Each wire went through the
circle and ellipse extractors at its draw depth to build the analytic
instances, then through both again at depth 0.0 purely to ask *whether* it is
a circle or an ellipse, allocating a vector each time and dropping it.
Neither extractor's `Some`/`None` answer depends on the depth: every
`return None` in them turns on the geometry — which `TangentGeom` variant,
the radius, the axis lengths, the parameters — and the depth is only written
into the instance, never read to decide. So the extraction that builds the
instances already answers the classification. One pass now does both, and
fans out across cores, since it reads a wire and writes nothing shared. That
took 173 ms of shape extraction and splitting down to 19 ms, and the whole
highlight from 299 ms to 150 ms.

Gathering the highlighted wires also cloned each handle's slot vector and
sorted the copy — one allocation and one sort per selected entity. The slots
are already ascending: both builders walk the wires in order and push as they
go, and `patch_handle_index` shifts a handle's slots by a constant, which
preserves it. A `debug_assert` on the slots actually read holds that in
place. The compat path of `from_highlight_refs` emitted its instances
sequentially while the native path beside it fans out; it now matches.

Nothing renders in a test, so a wrong bucket in the classification would
surface only as circles drawn wrong when selected. Two tests cover it: each
wire lands where the old predicate put it, and the colour override — always
for hover, and the configured tint or `SELECTED` for a selection — reaches
the instances.

`wire-highlight-detail` reports the phases: gathering, classifying,
uploading the analytic instances, the regular wires and the block ones.
2026-09-09 10:36:45 +03:00
Panos d5bf919414 Cut the cost of finding what a selection box contains
A window over a whole drawing spent 407 ms gathering candidates and 259 ms
testing them, of 825 ms total, at 186 468 entities.

**Gathering** ran eight spatial queries because that is what hover and
snapping need between them. An area selection reads five: the wires and their
segments, plus the fill triangles, pick triangles and glyphs that
`indexed_box_crossing_hits` uses to catch hatches and text inside the box.
The three that exist only for snapping are skipped.

That was worth 148 ms. The rest came from the queries themselves.
`SpatialGrid::query` sorts its result twice — once over the entry indices, to
remove the repeats an entry collects for spanning several cells, and once
over the values. Over a box covering the drawing that is two O(n log n)
passes across 4.4 M elements to remove a handful of duplicates.
`query_unordered` returns the same set in cell order with the duplicates left
in, and reserves the space it needs instead of growing a 17 MB vector in
steps. Gathering went from 515 ms to 69 ms on a synthetic set at that size,
and from 407 ms to 27-40 ms in the application.

Everything an area selection does with the result already dedups and does not
read the order. Click picking keeps the sorted `query`, where scan order
decides which of two overlapping entities a click lands on.

**Testing** projected both endpoints of every segment in the box, then threw
the result away for any wire already selected. A circle or a polyline
contributes one segment per tessellated span, so at 24 spans per wire that is
23 projection pairs out of 24 doing nothing. Skipping a wire once it is in
took a 4.4 M-segment scan from roughly a second to 42 ms.

The overlay path — active after any edit, so most of a working session —
needed the same treatment, including its own merge: `extend_indexed` sorts
and dedups every category, which would have put back the sorts this removes.
`extend_indexed_area` keeps the dedup on `wire_indices`, and must: the window
branch of `box_hit` walks it directly, so a wire left in twice would be
selected twice.

Tests cover the equivalence in both directions: the area query matches the
full one as a set in every category an area selection reads, and the merge
dedups `wire_indices` and nothing else.
2026-09-09 10:35:17 +03:00
Panos d02ce08349 Make a large selection scale with the drawing
Selecting a whole drawing was unusable on a 186 468-entity file. Four costs
scaled with the selection where they did not have to.

Every selected handle triggered a walk of the entire document to find LEADERs
pointing at it. On the file this came from, selecting 471 583 entities in a
585 786-entity drawing did not finish inside eight minutes. A reverse index
built once per geometry epoch answers the same question; a test asserts it
returns exactly what the walk returned, including the case of two leaders on
one annotation.

Group expansion asked the selection about every group: for each selected
handle it scanned each group's own member list. Asking each group once
whether it holds anything selected turns that around.

Selecting and deselecting went one entity at a time, and `deselect_entity`
rebuilt the ordered list with a `retain` per handle, so removing N of M
walked the order list N times. Both now take a slice.

Grips were built for every selected entity. AutoCAD stops at GRIPOBJLIMIT,
and the DWG header does not carry the variable, so its default of 100 stands
in for it.

The remaining two commits are measurement: `select-commit` reports the phases
of a selection separately, which is what showed the bulk paths had been added
to the press-drag branch while a click-move-click window goes through a
different one entirely.
2026-09-09 10:29:24 +03:00
JonathanandCopilot 73ba2ba615 Adjust: Add top padding to Copy/Clear buttons
- Add 2px top padding for breathing room above buttons
- Buttons now start above the resize slider area
- Improves visual spacing at top of command history panel

Co-authored-by: Copilot <[email protected]>
2026-09-09 09:10:35 +02:00
Marcel 6185369508 Add configurable block double-click editing modes 2026-09-09 09:06:34 +02:00
JonathanandCopilot 8fe3ceb2e4 Fix: Position Copy/Clear buttons at top of command history
- Remove top padding from panel container (0 instead of 4)
- Buttons now start flush at top edge above scrollbar
- Improves visual alignment and space usage

Co-authored-by: Copilot <[email protected]>
2026-09-09 09:04:26 +02:00
JonathanandCopilot 275f10d49b Fix: Align Copy/Clear buttons at right edge
- Increase header container right padding from 6 to 8 pixels
- Ensures Copy and Clear buttons align consistently with top alignment
- Improves visual spacing on the right side for cleaner UI appearance

Co-authored-by: Copilot <[email protected]>
2026-09-09 09:00:39 +02:00
JonathanandCopilot f98719cfd3 Fix: Enable clipboard copy for web/browser via system clipboard API
- Modify COPYCLIP command to write entities as JSON to system clipboard
- Modify CUTCLIP command to write cut entities as JSON to system clipboard
- Modify COPYBASE_AT command to write copied entities as JSON to system clipboard
- Entities are serialized as JSON with base point coordinates for cross-platform support
- Clipboard data format: OCS_CLIPBOARD_JSON header + base point + entity data
- Works in web (WASM) build via Clipboard API and native builds via iced clipboard

This fixes the issue where copy command didn't persist to system clipboard in web browser,
allowing proper paste operations and clipboard sharing between application instances.

Co-authored-by: Copilot <[email protected]>
2026-09-09 08:55:34 +02:00
JonathanandCopilot 3700f5abfb Fix: Enable clipboard copy for web/browser via system clipboard API
- Modify COPYCLIP command to write entities as JSON to system clipboard
- Modify CUTCLIP command to write cut entities as JSON to system clipboard
- Modify COPYBASE_AT command to write copied entities as JSON to system clipboard
- Entities are serialized as JSON with base point coordinates for cross-platform support
- Clipboard data format: OCS_CLIPBOARD_JSON header + base point + entity data
- Works in web (WASM) build via Clipboard API and native builds via iced clipboard

This fixes the issue where copy command didn't persist to system clipboard in web browser,
allowing proper paste operations and clipboard sharing between application instances.

Co-authored-by: Copilot <[email protected]>
2026-09-09 08:54:16 +02:00
Sebastian ecb8ca9342 Swap doc_api.rs for commit reversability 2026-09-09 08:11:12 +02:00
Sebastian 6d7c3443d3 Cleaning implementation 2026-09-09 08:03:40 +02:00
Sebastian 55f61a4327 General improvements on API 2026-09-09 08:02:35 +02:00
JonathanandCopilot b3e3555f4f Adjust plus button spacing next to Start tab
- Changed button padding from [5, 10] to [4, 8] to match layout tabs
- Changed container left padding from 6.0 to 2.0 for consistent spacing
- Plus button now has same distance from Start tab as from Layout tabs

Co-authored-by: Copilot <[email protected]>
2026-09-09 07:48:26 +02:00
Hakan Seven 56e09cd3f5 fix(dwg): preserve hatch context loops 2026-09-09 08:23:41 +03:00
Hakan Seven 3fb49c4d3e chore: update DWG database repair stack 2026-09-09 07:23:33 +03:00
Hakan Seven b0c0cbdf4a Merge PR #1086: add collapsible property sections 2026-09-09 06:38:47 +03:00
Hakan Seven 4ddd19f6e8 feat(mcp): describe complete CAD record schemas 2026-09-09 01:01:44 +03:00
Hakan Seven 8f574c8388 feat(mcp): expose complete drawing records 2026-09-08 23:59:13 +03:00
Felix RiestraandClaude Sonnet 5 63a74b19a9 Add persistent sketch-constraint system (ocs_gcs port) and named-parameters handoff docs
Ports FreeCAD's planegcs 2D geometric constraint solver to Rust as a new
crates/ocs_gcs workspace member, and wires it into the document/scene model
as a persistent SketchConstraintSet: Coincident, Horizontal/Vertical,
Parallel/Perpendicular, Equal, Tangent, Distance, Angle and Radius
constraints that re-solve live (including mid-drag, not just on release),
render glyphs and a DOF badge, flag conflicts with a one-click resolver
pill, and round-trip through save/load via an XRecord blob.

Also includes docs/command_reference.md (a statically generated reference
of every registered command and its prompt sequence) and
docs/named_parameters_design.md + docs/backlog.md, which hand off the next
queued feature (a named-parameter/expression table) and consolidate every
deliberate scope-down and open gap found along the way, so a fresh session
has a complete starting point.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-09-08 22:19:23 +02:00
Hakan Seven 89572e5ca9 fix: keep valid small drawing curves on open 2026-09-08 22:42:49 +03:00
Hakan Seven 2d55b90b0e chore: update DWG save dependencies 2026-09-08 22:20:07 +03:00
Marcel d22f4fdbe7 Remove accidental file 2026-09-08 20:53:20 +02:00
MarcelP102 c9bb898b92 Merge branch 'HakanSeven12:main' into codex/collapsible-properties-sections 2026-09-08 20:47:42 +02:00
Marcel 7a87e08a02 Add collapsible Properties-panel sections 2026-09-08 20:33:24 +02:00
Hakan Seven c5503e4758 Merge PR #1083: implement solid shell workflow 2026-09-08 21:02:01 +03:00
ramox81 7913f8e2da Merge remote-tracking branch 'origin/main' into codex/shell-parity
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	crates/ocs_doc_api/Cargo.toml
#	src/modules/model/mod.rs
2026-09-08 19:49:35 +03:00
Hakan Seven cadd506f76 Merge pull request #1079 from mechpanos/pr/first-edit-patches
Carry the loader-built resident wire layout into the installed scene so the first edit can use the incremental patch path. Add a regression test that exercises the full prepare/install/edit handoff.
2026-09-08 19:45:18 +03:00
ramox81 be06a756da Implement solid shell workflow and properties 2026-09-08 19:37:35 +03:00
Hakan Seven f611ceb638 Update CAD dependency revisions 2026-09-08 19:34:39 +03:00
Hakan Seven fd3ddc1608 Finish Ramox edge and slice integration 2026-09-08 19:02:08 +03:00
Hakan Seven d3f0d0ec42 Merge pull request #1081 from ramox81/codex/chamferedge-split 2026-09-08 18:33:50 +03:00
Hakan Seven 39492860d3 Merge pull request #1077 from ramox81/codex/filletedge-split
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	src/app/model_ops.rs
#	src/scene/model/solid_history.rs
2026-09-08 18:33:20 +03:00
Hakan Seven 7ec07f3222 Merge pull request #1070 from ramox81/codex/filletedge-parity
# Conflicts:
#	Cargo.lock
2026-09-08 18:30:34 +03:00
Hakan Seven 001605baa1 Merge pull request #1065 from ramox81/codex/slice-command-parity 2026-09-08 18:28:01 +03:00
Karim Jerbi 08891816be fix(render): highlight untinted analytical curves and guard uniform bind group
- Fall back to WireModel::SELECTED when selected_tint is None (classic mode) so selected circles, arcs, and ellipses are not omitted from the highlight pass.

- Explicitly rebind uniform_bind_group before drawing analytical curves in selection_xray pass.

- Skip invisible wires (display_visible == false) during selection and hover wire extraction.
2026-09-08 16:21:28 +01:00
ramox81 4f22d998e7 Complete independent CHAMFEREDGE workflow 2026-09-08 18:08:52 +03:00
Hakan Seven 9868158e27 Merge pull request #1080 from mf4633/registry-stormsewer-pro
registry: note Storm Sewer free/Pro split in description
2026-09-08 18:00:37 +03:00
Hydro Engineer e6e60c136a registry: note Storm Sewer free/Pro split 2026-09-08 10:56:19 -04:00