mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-18 22:42:37 +00:00
ea32f8dc2fc0158c8bb6b1e37cec9cc95088e7df
147
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8b9ff36685 |
The eleven constraint buttons no rung had ever pressed
Twenty buttons on the CONSTRAIN bar, nine of them exercised. The other eleven were "implemented" in the sense that the kernel builds the right def for them -- which is exactly what was true of Parallel yesterday morning, right up until a user pressed it and got nothing. What a kernel test cannot see is whether the BUTTON is wired to the index its name claims. CON_BTN is 449 + 42*i over a hand-written name list, and it has drifted once already: six buttons were inserted, everything from index 6 on pointed at the wrong control, and nothing caught it for months because no rung pressed past index 5. D13 presses index 6; D14 through D22 press 8 to 19. The map turned out to be intact, which is worth knowing rather than assuming. D12 vertical, D13 equal_radius (its own button, not Equal's promotion), D14 concentric, D15 tangent, D16 midpoint, D17 symmetric (the three-pick form), D18 sym_h, D19 radius, D20 diameter, D21 fix, D22 dist_y. Three are shaped around a specific way the code could be wrong rather than around "does something happen": D20 exists for a factor of two. Diameter wired to the Radius handler gives r = 30 for a typed 30, and nothing on screen looks wrong. D21 -- Fix alone is unfalsifiable: nothing moved, so nothing proves the constraint exists. It only becomes observable when a SECOND constraint would otherwise move the fixed point, so the rung drives the pair to a 70 mm gap and checks which end travels. D14 asserts the radii did NOT change. Concentric is about centres; a solve that also equalised the radii would pass a naive check. D17 failed on its first run and the rung was wrong, not the app: all three entities are free, so the solver is entitled to satisfy the mirror by moving the AXIS instead of the points -- and it did, landing the pair symmetric about x = -8.18. It now measures signed perpendicular distance to the axis where the axis actually is, which is the stronger property anyway. Coverage: 20/20 buttons pressed, up from 9. Ladder 135 -> 177 properties across 43 rungs, all holding. snaporca-l2vm |
||
|
|
8f3f835636 |
Constrain while you sketch, and stop losing work to Esc and to invisible points
Five defects from ten minutes of real use, and the mode split behind the worst of them. One commit because the changes overlap in the same functions; the pieces are separable in the diff, not in the file. CONSTRAINING NO LONGER NEEDS A COMMITTED SKETCH. A constraint could only be applied by committing the sketch, selecting it in the feature tree, pressing the padlock, and only then picking. While drawing, the CONSTRAIN toolbar was not even on screen (set_ui_mode showed it in UiMode::Constrain alone) and apply_constraint answered "Press Constrain on a sketch first" -- in a status line nobody looks at. Draw two lines, press Parallel, get nothing: that is what a user reported as "the UX is a mess", and they were right. apply_constraint now takes the live session first, reading the picks from the selection model the sketch tool already had (click, ctrl-click to extend, double-click for the loop) and applying through try_add_constraints, which already did append -> solve -> keep-or-rollback. The committed Constrain path stays for editing an old sketch; it is no longer the only way in. The twenty constraint buttons now show in Sketch mode as well. The discriminator is is_sketching() && !is_constraining() && !is_constraining_entities(). Both begin_constrain and begin_constrain_entities set m_active, so is_sketching() alone is true DURING a constrain session and the new path would hijack the old one -- compiling perfectly and failing in behaviour. ONE PLANNER, NOT TWO. A second caller meant duplicating the logic that decides whether a constraint is legal, which roles it binds and whether it needs a typed value. That duplication is how today's Coincident bug survived: fixed in one branch, alive in the next one down. plan_entity_constraint() now lives in the kernel -- pure, no wx, no translation -- and both UI paths call it. DesignPanel loses 304 lines and gains 155. Being in the kernel makes it TESTABLE. The Parallel defect existed because a constraint type met an entity type nobody had tried, and the only instrument was a 13-minute GUI ladder. 19 new kernel cases cover the matrix: 264 -> 283 cases, 7648 -> 7867 assertions. Parallel, Perpendicular and EqualLength gain the two-line guard they never had. On non-lines they used to emit a def the solver silently dropped -- the sketch reported itself constrained when it was not, the same class as Horizontal on a Point. EqualLength on two rounds still promotes to EqualRadius first. Symmetric is planned completely, including its axis pick: the plan carries a VECTOR of defs because Symmetric on two lines is two constraints (P0/P0 and P1/P1). A single def would have half-applied it -- one end pinned, one free, looking correct until something moves. A PLACED POINT SURVIVES THE COMMIT. Type::Point was created correctly and never drawn once committed: both renderers skip it, correctly, since entity_polyline gives a point nothing. What was missing is the vertex-marker path the live session already used. rung_point passed throughout because it asserts the document, and the point was always in the document -- the pixels lied. ESC STOPS EATING AN UNSAVED SKETCH. The third press reached cancel_sketch(), clearing m_entities with no warning and nothing to undo. live_sketch_has_work() existed and was never consulted. The exit layer refuses once when there is work and lets a second consecutive Esc through; the refusal re-arms on a button press, never on mouse motion, or Esc could never exit while the hand moves. TWO NEW RUNGS. D10 drives Parallel through the committed path -- it passes on the PRE-fix binary, which is how we know the user's failure was the mode and not the constraint. D11 is the acceptance for the collapse: draw, pick both, press Parallel, no commit and no padlock. Ladder 126 -> 135 properties, all holding. CON_BTN_SKETCH is measured, not derived: in Sketch mode the group renders after the sketch toolbar, so the first button is at 677, not 449. Pitch 42, twenty buttons, read off a screenshot. Deriving it by offset is how that table drifted the last time. Known limit, commented at the call site: a constraint added to a LIVE sketch is not on the document undo stack, so Ctrl+Z will not take it back until the sketch is committed. snaporca-itp4, snaporca-oyhx, snaporca-l2vm |
||
|
|
cd30fb891e |
the same phantom-endpoint bug in Coincident, and the two unguarded branches next to it
Port of snaporca da8d011b87; parity holds (DesignPanel.cpp still exactly 32 divergent
lines). Verified independently on this fork's own rig: full ladder 126/126 against
BuildID 96c697a3, built from this tree.
Reviewing the DistanceX/Y fix for OTHER members of its class found three more live defects
on the constrain toolbar. All four share one root: a branch assumes every picked entity has
two endpoints, and the solver's refusal to resolve a role it cannot find is silent.
COINCIDENT had the identical closest-pair walk over {P0,p0},{P1,p1}. For two Points the
phantom (0,0) pair sits at distance 0, which is the smallest distance there is, so it
ALWAYS won: ptOf(Point,P1) -> 0, ref_ok fails (SketchSolver.cpp:185), constraint dropped.
Not sometimes -- every press.
HORIZONTAL/VERTICAL hardcoded ra=P0, rb=P1 with no type check. With a Point picked the
constraint is dropped by the same mechanism but still STORED: constraints goes 0 -> 1 after
the commit and nothing moves, so the Constraints list shows a dimension that can never do
anything. Worse than refusing -- the panel claims the sketch is constrained when it is not.
ANGLE computed p1-p0 on whatever was picked. On a circle that is (0,0)-centre, so two
circles pre-filled the field with the angle between their centre POSITION VECTORS (178.83
deg for two on the x axis), and accepting it emits SLVS_C_ANGLE on two circle prims.
Both branches now refuse with a message. entity_ends()/closest_ends() are file-scope and
shared by Coincident and DistanceX/Y, so there is one implementation instead of two that
drift.
Two smaller findings from the same review: infer_auto_constraints' roles_of omitted
EllipseArc while heal_coincidences' identical copy has it; and set_point(Circle, Center)
wrote e.center and not e.p0, breaking the "p0 mirrors centre" invariant for the duration of
a live drag.
New rungs D8 and D9, both RED against the shipped binary and green here.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MrMzTpAf78U4NG2M8jfvHY
|
||
|
|
afb17e8889 |
D3 was testing luck: the pair started 3 degrees from square, inside inference's snap
Port of snaporca b3221f8a12; this is the fork the fault surfaced on. The perpendicular rung drew its two lines 93.5 degrees apart and then asserted they did NOT start perpendicular. On this rig, whose camera maps the same click a pixel differently, they arrived at exactly 90.000000 -- inference had already done the job the rung exists to test, so the precondition failed while every later check passed. Held on the other fork and failed here from identical source: the rung depended on where a click happened to land, not on the app. The second point now starts the pair 56 degrees off, well outside any snap tolerance, so the button has real work to do. That immediately exposed a second, milder fault in the same rung. From a 51 degree start the LIVE solve converges to its own tolerance and lands at 89.999999991; the old 1e-9 assertion held only because the correction used to be tiny -- it was measuring how little work the solver had to do, not whether the lines came out perpendicular. It is 1e-6 degrees now, which is 1.7e-8 radians. The round-trip check still demands exactly 90 and gets it, because the committed feature re-solves from scratch. Full ladder 118/118 on BOTH rigs after this, each driving its own fork's binary. This fork had never had a green gesture ladder before today (snaporca-eoj1). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MrMzTpAf78U4NG2M8jfvHY |
||
|
|
d35d33971a |
the feature-tree row needs CHROME_DY too — the last chrome constant that did not carry it
Four of this fork's five absolute chrome coordinates were shifted by CHROME_DY when the
ladder was first brought up here (DESIGN_TAB, CONSTRUCTION_CHECKBOX, CON_BTN_Y,
CONFIRM_BTN). TREE_ROW0 was not, because it is declared above the CHROME_DY block and was
simply never in view.
The unshifted click lands 26 px below the first tree row, just past its 23 px height, so
the row is never selected and Delete does nothing. reset_document then spends 40 rounds on
it and dies with "could not empty the feature tree" — a message that names the feature
tree, which is not the fault. The same 26 px is why confirm_and_reopen's double-click did
not reopen the sketch, which surfaced as "sketch_describe: no sketch is open" three frames
away from the cause.
Measured, not inferred: the Sketch1 row centre reads y=241 on the rig at 1920x1080 with
the window at (0,0), against the constant's 215. CONFIRM_BTN was checked in the same pass
from a screenshot taken in CONSTRAIN mode and is correct at (1751, 101).
With this, the four new constraint rungs hold 20/20 on this fork's rig, driving the binary
built from
|
||
|
|
648b930e75 |
gesture rungs for the six new constraint buttons, and the DistanceX/Y bug they found
Port of snaporca 2951e3c60b; parity holds (17 identical, DesignPanel.cpp still exactly 32
divergent lines, so the hunk landed on the right side of the DropDown divergence).
The sketch-constraint epic added six toolbar buttons and covered all six with kernel
tests. Not one of them was ever clicked. The gesture ladder only pressed 'perpendicular'
and 'equal' -- and CON_BTN, which locates buttons by index, was silently wrong for every
entry past index 5 for the whole epic. The untested half of the toolbar was exactly the
broken half (snaporca-rqsy).
Four rungs now drive them: D4 Equal on two circles (must mean equal RADIUS, not the
equal-length no-op the epic fixed), D5 Collinear on two oblique lines, D6 a horizontal
distance, D7 symmetric about the implicit vertical axis. Full ladder 118/118 on snaporca;
this fork's rig has not been rebuilt against the change yet, so here it is reviewed,
parity-checked and NOT exercised.
D6 found a shipped defect. apply_entity_constraint enumerated {P0,p0},{P1,p1} for BOTH
entities regardless of type, but a Point's p1 is unused and reads (0,0), as does a
Circle's. The closest-pair search then picked those two phantom origins, distance 0: the
field opened pre-filled 0.00 and the solver dropped the constraint, because ptOf(Point,P1)
resolves to no handle. Nothing errored -- the dimension simply did nothing. ends_of() now
enumerates only the roles an entity actually exposes, and the pair with no point at all is
refused with a message instead of a silent no-op.
Five kernel tests, a 7/7 ladder, a review and a fork port all passed over this, because
every one of them exercises the kernel, where the geometry was always right.
Two rig faults fixed in the same pass, both of which produce a green-looking session that
tests nothing: start-headless-gui.sh never exported SNAPORCA_MCP or SNAPORCA_KEYTRACE, so
a freshly launched rig comes up healthy and every ladder dies on "Connection refused"; and
it never dismissed the "Restore" dialog a killed session leaves behind, which grabs every
synthetic click afterwards.
The value field also takes no keyboard focus from the WM -- typed digits go to the canvas
and Return commits the pre-filled number (typed 40, got 54.94). focus_field() finds it as
its own top-level window and clicks it first. The no-op tolerance is now 5e-3, the field's
own two-decimal display resolution, not 1e-6.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MrMzTpAf78U4NG2M8jfvHY
|
||
|
|
d0791c3b8a |
Make the ladder runnable on this fork's rig — 6 of 7 rungs now hold
This fork had never been gated end to end. Five separate things stopped it, none
of them a defect in the CAD code itself, and each failure named the wrong
subsystem — which is why they survived.
1. run-all-checks.sh invoked docs/ux/mockups/gen_offer_table.py. The design docs
moved to docs/CAD/ (
|
||
|
|
ca8f813994 |
Add assimp to the deps image, so this fork can run its own tests
This fork's kernel suite has never run. scripts/CAD/run-kernel-tests.sh died at CMake CONFIGURE time on find_package(assimp REQUIRED), before a single source file compiled, so every kernel change ported here was parity-checked against snaporca and never independently tested (snaporca-w80c). WHY IT WAS MISSING. OrcaSlicer mainline gained assimp (glTF/GLB/FBX import for texture-to-colour) after the orcacad-deps image was baked: the image's deps/ tree has no Assimp directory at all and nothing named assimp anywhere in it. On the host, deps/build/dep_Assimp-prefix carries only `patch` and `update` stamps -- no build, no install -- so the dependency was fetched and then never built, inside the image or out of it. The Snapmaker fork never hit this because its base requires neither assimp nor OpenCV. WHY A LAYER. A full deps rebuild is hours and would rewrite artifacts that currently work; this adds the one missing package on top. It is a Dockerfile rather than a `docker commit` so that what was done stays reviewable and repeatable instead of being an undocumented image mutation. The flags are the project's own recipe (deps/Assimp/Assimp.cmake) plus the standard superbuild arguments from orcaslicer_add_cmake_project (deps/CMakeLists.txt:158) and DEP_CMAKE_OPTS (deps/deps-linux.cmake). The file says to keep them in step with that recipe: it stands in for the superbuild, it is not a separate opinion about how to build assimp. The tarball's SHA256 was checked against the recipe's URL_HASH before this was written and is re-checked inside the build, and the build asserts the installed cmake config exists rather than trusting an exit code. OpenCV was confirmed already present, so it is not a second wall behind this one. RESULT, and it is the point: orca_cad kernel now runs and is GREEN at 7701 assertions / 270 cases. snaporca is 7700 / 270 -- same cases, one more assertion here, which is the tolerated test_caddocument.cpp divergence. The "this fork's kernel suite cannot run" caveat carried by the five commits of the sketch constraint epic no longer applies. |
||
|
|
fac3cf44df |
Infer parallel, perpendicular, equal radius and tangent while drawing
Port of snaporca 2d36d28770. Parity OK: 17 files identical, 8 diverging at their expected counts. infer_axis_constraint returned only Horizontal or Vertical. On the CAD-1000-hours corpus the top two transitions are sketch_dim -> sketch_draw (5896) and back (5756): the signature of geometry that does not self-constrain as it is drawn. Every rule requires the relation to be ALREADY TRUE within tolerance, so nothing the user drew is moved; parallel/perpendicular and tangent additionally require a shared endpoint. TWO LIMITS THE CORPUS RUNG FORCED, neither visible to the unit tests: 1. At most ONE constraint per rule per new entity, not one per PAIR, and no one-at-a-time fallback for the relations batch. EqualRadius has no locality restriction, so 200 equal holes produced ~20000 candidates; the rejected batch then cost a solve per constraint and pinned the app at 95% of a core with the MCP socket unresponsive. 2. Relations only for gesture-sized batches. "A scripted add is not a drawn gesture" is already this file's rule at its bulk call site (snaporca-8xg1), and EqualRadius also couples geometrically distant entities, merging independent connected components and defeating the partitioning that makes large sketches solvable (snaporca-yww4). With the cap alone geometry stayed correct (32/32 sheets clean) but seven of the largest timed out, including MPD681 -- the sheet that call site's own comment names. Also fixes the tolerance leak behind 2: the bulk path asks for exact inference with ang_tol_rad = 0 but len_tol_frac kept its 0.01 default. ALSO independent of this feature: run-kernel-tests.sh defaulted to TAGS=[CadDocument] while four CAD test files carry their own tags and nothing selected them (2624 assertions / 206 cases reported, 7648 / 264 actual). All 58 dark cases were passing; the coverage was never exercised. VERIFICATION LIMIT, as with the previous three commits: this fork's kernel suite still cannot run (find_package(assimp) at configure time, snaporca-w80c). Shared sources are byte-identical to snaporca's, where kernel is 7651 assertions / 265 cases and ALL LADDERS HELD 7/7. |
||
|
|
a1f2a2687a |
Equal radius and Collinear, and one Equal button that knows what it picked
Port of snaporca 9ec6405e2d. Parity OK: 17 files identical, 8 diverging at their
expected counts (DesignPanel.cpp 32, test_slvs_constraints.cpp 3).
Measured on the CAD-1000-hours corpus: 51.5% of observed CAD time is 2D sketch
work, and dimensioning/constraining alone is 31.9% -- the largest single class.
Two constraints every industrial sketcher has were missing here.
EqualRadius fixes a dead end rather than adding a feature. Picking two circles
and pressing Equal emitted EqualLength, which maps to SLVS_C_EQUAL_LENGTH_LINES
and constrains nothing on a curve: a silent no-op with no error. Equal is now
one button with two meanings, as in Onshape and SolidWorks.
Collinear emits PARALLEL plus PT_LINE_DISTANCE=0 rather than PT_ON_LINE, whose
internal valP param this libslvs port leaves at 0, drifting an already-collinear
pair.
Both types are appended at the END of SketchConstraintType: cereal serializes it
positionally, so inserting elsewhere reinterprets every saved recipe.
VERIFICATION LIMIT, stated rather than implied: this fork's kernel suite could
NOT be run. scripts/CAD/run-kernel-tests.sh fails at CMake configure time on
find_package(assimp), before any source compiles -- a pre-existing deps gap
(snaporca-w80c), not this change. The shared sources are byte-identical to
snaporca's, where the full gate passed: kernel 2588/195 and ALL LADDERS HELD
across all seven rungs.
Also fixes two defects in this fork's scripts/CAD/run-all-checks.sh:
- `cd $(dirname $0)/..` landed in scripts/ instead of the repo root, so every
rung looked for itself under scripts/scripts/. Broken since the script moved
into scripts/CAD/; the three sibling scripts were fixed then and this was
missed, so the gate has not run since.
- C defaulted to snaporca-gui, the OTHER fork's rig container, so this fork's
gate would drive snaporca's app and report green about the wrong binary.
run-kernel-tests.sh:31 documents the identical defect being fixed once
already for the build volume; this is the third instance.
|
||
|
|
13d5eac891 |
Move the Design-tab scripts into scripts/CAD/ and name them by role
Requested by SoftFever on PR #15238: ten of these had accumulated loose in scripts/ next to ~20 unrelated upstream ones, with names that only meant something to whoever wrote them. They now sit in scripts/CAD/, mirroring the src/libslic3r/CAD/ and src/slic3r/GUI/CAD/ split, and the verb in the name is the role: build- produces a binary, start- brings something up, run- runs a suite, check- asserts one thing against a live app. kernel-test.sh -> CAD/run-kernel-tests.sh ladder-all.sh -> CAD/run-all-checks.sh sketch-ladder.py -> CAD/check-sketch-engine.py ladder-corpus.py -> CAD/check-sketch-engine-corpus.py gui-ladder.py -> CAD/check-gui-sketching.py offer-ladder.py -> CAD/check-gui-context-menu.py mcp-sketch-smoke.py -> CAD/check-mcp-sketch.py rig-build.sh -> CAD/build-gui.sh docker-iter-build.sh -> CAD/build-gui-incremental.sh gui-session.sh -> CAD/start-headless-gui.sh "Ladder" was the worst of them: it named the shape of the test (rungs of increasing difficulty) rather than what the test proves, so nothing in the directory listing told you which one needed a GPU and which was pure kernel. Every reference rewritten -- the docs, the cross-calls between the scripts, Dockerfile.deps, and the container-side /OrcaSlicer/scripts paths. The three shell scripts resolve REPO relative to themselves and now sit one level deeper, so that walk went from /.. to /../.. . The copies these push into a container's /tmp were renamed to match, or the container would have kept the old names alive. Two runtime paths deliberately NOT renamed. /tmp/orca-rig-build.lock is a cross-fork contract -- both forks take the same lock so two concurrent builds serialise instead of OOMing the box, and renaming it on one side silently removes that guard. /tmp/gui-session.log is a runtime artefact, not a script. Added scripts/CAD/README.md: what each script proves, what it needs, and the two constraints that have each cost a session (never build inside the GUI container; a window manager is required or synthetic keys are ignored). On CI, which was the other half of the request: the kernel suite is already there and always has been. The cases are registered in tests/libslic3r/CMakeLists.txt under if (SLIC3R_CAD), which defaults ON and no workflow turns off, so they build into libslic3r_tests and run under ctest on every platform via unit_tests.yml -- like any other unit test, needing no new job. They have simply never been seen to run, because the workflows on this PR are still awaiting maintainer approval. run-kernel-tests.sh is the local loop over the same cases, and it is the only script here CI could run: the other six need an OpenGL canvas and synthetic input. Verified: scripts/CAD/run-kernel-tests.sh from its new location, all tests passed, 2562 assertions in 190 test cases. |
||
|
|
f130b713c8 | fix shellcheck errors | ||
|
|
a24ec03e87 | fix flatpak build error | ||
|
|
0aeb6df122 | Merge branch 'main' into cad-mainline | ||
|
|
1631d3cf01 | fix flatpak build | ||
|
|
1e51b54239 |
Mirror stops destroying arcs, and the Construction box converts what you picked
Two user reports from the same session on the deployed build, 2026-08-23.
FIRST: "if I select a shape (es a circle draw in construction lines) and then I
try to toggle contruction to obtain a full line, does not work". Reproduced: Q
converts the selection and so does the offer's Reference > Construction row —
both run m_keys_sketch['Q'] — but the CHECKBOX, the one control actually
labelled Construction, only ever called set_sketch_construction(), which arms
the mode for the NEXT entity. So the obvious control was the one route that
could not convert existing geometry, and it failed silently while also flipping
the draw mode behind the user's back. It now carries Q's meaning.
Scoped to Select mode, and that scoping is not cosmetic: drawing AUTO-SELECTS
what was just drawn (draw-then-edit), so with a draw tool armed "there is a
selection" does not mean the user picked anything — it means they finished a
line. The first version converted there and turned the box into a trap: arm
construction, draw the axis, click the box to go back to real geometry, and
instead of disarming the mode it converted the axis just drawn. The gesture
ladder's C4 rung does exactly that and reported three construction entities
where it wanted one. In Select mode the intent is unambiguous.
SECOND, and this one destroyed work: "after creation of a circle, a round angled
rectangle and a slot, and mirror of those shapes on a vertical line inside a
outer rectangle, preview is ok but application creates errors: the circle is
mirrored, but rectangle and slot are redrawn as pieces of circles screwing both
the original shapes and the copies." A screenshot came with it, and it showed
more than the words did: the ORIGINALS were wrecked too — the rounded rectangle
was drawn as a four-lobed cloud, each corner fillet having gone the long way
round, and the slot had ballooned into two near-full circles.
Measured on the rig, a slot mirrored about a vertical line:
rails 62.873 / 62.873 -> 2.082 / 62.913
caps r=21.554 sweep=-180.00 -> r=32.214 sweep=-237.66
and all four sources moved, the axis line with them
Cause: confirm_op's Mirror branch bound an Arc copy to its source with a
Symmetric constraint on the CENTRE ALONE. An arc has five degrees of freedom;
pinning two of them leaves the endpoints and the sweep free while the shape's
own coincidences still pull on them, and the solver answers with a different,
internally consistent sketch — which is what a reflex cap and a 2 mm rail are.
A circle came through the same code untouched because a circle HAS no endpoints
to leave free, which is exactly why the failure reads as "circles fine, rounded
rectangles and slots destroyed".
Three parts, and each one is here because the measurement caught the previous
one being half a fix:
1. Arcs are bound by BOTH ENDPOINTS. Endpoints before centre in the ladder:
{p0, p1} is four equations against five DoF and pins the sweep, while
{centre, p0, p1} is six and is refused — the refusal is what silently
degraded the batch to a set that left the sweep free.
2. Every copy is reflected from the PRE-BATCH source, so a batch that disturbs
the sketch cannot hand the next copy already-moved geometry.
3. THE APPLIED RESULT IS THE PREVIEW — checked on the sources AND the copies,
and on violation the whole constraint web is dropped and both halves are
restored to the reflection the preview drew. try_add_constraints rolls back
only when a solve FAILS, and every failure here came from a solve that
succeeded at something else. Guarding only the sources fixed the slot and
left the rounded rectangle's copies at a 13.8 mm rail and a 308 degree cap:
the original was safe and the copy was still wrong, which is half a fix.
The parametric link is kept whenever it provably holds the geometry, and dropped
when it does not. A wrong shape is worse than an unlinked one.
WHY NOTHING CAUGHT THIS: the gesture ladder's mirror rung reflects three
straight LINES. It sat green through the whole defect. C4b now mirrors a slot,
so the reflection has arcs in it, and grades the property the user actually
stated: the copy is the source reflected, the source does not move, and no cap
comes back reflex.
VERIFIED against the user's own scene, rebuilt gesture by gesture on the rig —
outer rectangle, circle, rounded rectangle and slot, a vertical CONSTRUCTION
line as the axis, all 17 entities mirrored in one gesture:
ok the mirror axis is a construction line
ok picked the axis and all 17 entities
ok originals unchanged (moved: [])
ok every copy is the exact reflection (worst 0.000000000)
ok no source arc turned reflex — the 'cloud' failure
ok no copied arc turned reflex (6 arcs checked)
One grader correction worth recording, because it cost a round and would cost
the next one too: a reflection REVERSES ORIENTATION, so a copy legitimately
stores p0/p1 the other way round. Comparing p0 to p0 grades the storage order,
not the geometry, and reported a perfect mirror as an 8.98 mm error. Endpoints
are compared as an unordered pair.
|
||
|
|
3c7105202a |
The offer ladder stops depending on what ran before it
It passed alone and failed inside scripts/ladder-all.sh, twice, on the same property: "right-click with two picked -> None". The diagnostic it now prints said what a screenshot could not — editing=True with an empty selection after two clicks that should have picked two entities. Three rig facts, all about the DRIVER, none of them a product defect: A LEFT-CLICK ON A LINE'S MIDDLE OPENS ITS LENGTH FIELD. The Select branch tests m_live_quotes before it picks, with a ~24 px label tolerance, and a line's Length quote sits at its midpoint — so the click that was meant to select it promoted a dimension and froze the canvas instead. Everything after it landed on nothing. It bit only when the previous step had left that line selected, because live quotes are drawn for the SELECTION: hence passing alone and failing in the gate. Lines are now picked at 0.3 along, clear of the label. A FIELD THAT HAS NOT OPENED YET READS LIKE ONE THAT NEVER WILL. The queue opens each field from a CallAfter, so a driver that looks once, sees nothing and moves on gets frozen by the field that arrives a moment later. keep_as_drawn() now waits for QUIET — two consecutive clear readings — and draw_line_at drains stragglers before handing back. A KEY CANNOT CANCEL A SESSION WHOSE CANVAS IS FROZEN. gui-ladder's enter_sketch dismisses the old sketch with Escapes, which an open field swallows, so the session survived and the four calibration probes landed in it on top of what was already there: "calibration expected 4 points, got 7". Every rung now enters through fresh_sketch(), which cancels through the socket first — that cannot be swallowed. Measured after the fix, in the sequence that failed: gesture ladder 93/93 then offer ladder 108/108, back to back on the same app. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MrMzTpAf78U4NG2M8jfvHY |
||
|
|
96f9261425 |
The offer table is generated again, and its last verb was unreachable
snaporca-ziam said gen_offer_table.py would silently delete the model-mode "Constrain sketch" row, because that row lived in the generated header and not in tool_atlas.json. Running it found more than that: FOUR rows existed only in the header — constrain, rename, and the three typed- value rows sk_length / sk_radius / sk_angdist — and sk_delete's action had drifted, pointing the sketch row at btn:delete, the FEATURE delete. All five are now in the atlas, so the header regenerates byte-identically from it. Verbs may carry a `note`, emitted as a C++ comment above the row: a rationale written into a generated file is deleted by the next regeneration, which is how this started. snaporca-z8rs (P1), found by making that true: after the atlas held all 92 verbs, the regenerated header differed from the checked-in one by EXACTLY ONE LINE — kOfferVerbCount, 91 against 92. Every consumer loops i < kOfferVerbCount, so the last row of the table was invisible: never listed by show_offer_menu, never findable by mcp_run_verb. The verb that fell off the end is sk_angdist, "Angle / distance…" — the typed-value row for a two-entity selection. On the one selection where you would ask for the angle between two lines, the row that types it was not in the menu. It survived because nothing compared the Sk2Ent menu against the table: sk_angdist accepts Sk2Ent and nothing else, so an off-by-one that dropped the LAST verb was invisible from every other selection. The vocabulary rung now covers Sk2Ent too, and picking the pair taught it one more rig fact — shift-clicking a circle at its +X point grabs the RADIUS GRIP, which replaces the selection with that one entity, so the pair silently collapsed to one and the offer answered SkLine. Correctly, for the selection that actually existed. gen_offer_table.py --check proves header == atlas and changes nothing; it is now the first step of scripts/ladder-all.sh, and the only one that needs no rig. Offer ladder 107/107, gesture ladder 93/93, both on the rig. snaporca-ziam snaporca-z8rs Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MrMzTpAf78U4NG2M8jfvHY |
||
|
|
1bde448f51 |
Every 2D verb without a shortcut, driven from the offer — and three more defects
The 2D vocabulary is 46 verbs: 22 have a shortcut and the gesture ladder drives them, 24 have none and nothing had ever exercised those. They are reachable only from the right-click offer, so a key-driven ladder could not have touched them whatever it did. Four new rungs drive all 24, and the coverage claim itself is now arithmetic against DesignOffer.hpp (rung O8) rather than a sentence in a comment that rots when a verb is added. The assertions are CONSTRUCTION invariants wherever a click cannot be exact — a regular polygon's sides are equal to 1e-9 and its vertices lie on one circle; a tangent arc's radius at the shared endpoint is perpendicular to the line to 1e-9 (measured cos 5.97e-17); the three clicks of a 3-point circle all lie on it; a circumscribed pentagon's circumradius is the inscribed one's over cos(pi/5), 1.236067977 against 1.236067977. Where a value field opens, the typed value is graded exactly: a moved line travels +25.000000000 in X and 0 in Y, a rotation turns 30.000000000 deg and leaves the length alone, a scale multiplies it by exactly 3, a linear array's pitch is [20.0, 20.0, 20.0] and a polar one's spokes are 60 deg apart all the way round. Three defects found doing it, all fixed here: snaporca-ua9g (P1) — delete_selected left three things behind. The AUTO-EDIT QUEUE, so a queued field opened on a deleted entity and its commit went nowhere: draw a rounded rectangle, delete everything, draw a 2-point circle, type 30 — the field opens, the digits are accepted, and the radius stays 32.992020763. reset_autoedit() exists for exactly this and its own comment says so; it was simply never called from here. The FEATURE GROUPS, whose [begin,end) ranges all shift on a delete, so feature_of() answered with a group the user never drew — survivors are now remapped and any group that lost a member is dropped, the rule the placed quotes already followed. And the SOLVER STATE: no re-solve, so sketch_describe reported dof=16 for a document holding one circle. snaporca-ekt9 (P2) — the read-back could not see three of its seven entity types. Ellipse, EllipseArc and BSpline serialised as a bare type name: no centre, no semi-axes, no rotation, no sweep, no poles. gui-ladder's ellipse rung had to grade the faceted area of the loop at 2e-2 — that tolerance IS the faceting error — and its spline rung could only count entities. Now they carry their parameters, and the ellipse arc's ends are asserted to satisfy (x/a)^2+(y/b)^2 = 1 to 1e-9. Also read-only, and the reason the other two were found at all: sketch_describe now reports the armed TOOL, the count of PENDING anchors, and whether a value field is EDITING. A menu walk that lands one row off arms a neighbouring tool and then draws something plausible — the first run of the authoring rung drew a circle of area 45238.93 and graded it as a rectangle. Every menu pick now asserts which tool it armed, and the polyline rung (a per-segment Length field freezes the canvas after every click) could only be written once the driver could ask whether a field was open. Offer ladder 102/102 -> 105/105 with coverage. Gesture ladder 93/93 and the kernel suite 188 cases / 2532 assertions, both unchanged. snaporca-ua9g snaporca-ekt9 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MrMzTpAf78U4NG2M8jfvHY |
||
|
|
8c4b05ae9d |
The offer ladder: drive right-click, and fix the two things it found
The gesture ladder proved the TARGET — a complex closed profile, exact in vertices, lengths, arcs
and symmetry, voids correctly attributed. It proved it by arming every tool with a letter key,
which leaves the goal's own MECHANISM untested: the design logic pivots on right-click, and the
verbs offered are supposed to adapt to the element under the cursor. 47 of 86 Design-tab verbs
have a GUI action and no shortcut, so a key-driven ladder cannot reach more than half of them.
scripts/offer-ladder.py drives the menu. It asserts nothing from pixels: show_offer_menu emits an
[OFFER] trace from the same loop that builds the rows (behind the existing SNAPORCA_KEYTRACE), so
what the ladder reads cannot drift from what the user is shown, and the expected row set is
predicted by parsing DesignOffer.hpp rather than transcribed by hand. 25 properties, four rungs:
what each element type offers, that the menu equals the table for four selections AND that the
four differ, a 120 x 80 profile authored entirely through the menu, and a tool with no keyboard
route at all driven from the only door it has.
Two real defects, both found by it, both fixed here:
snaporca-ghcz (P1) — right-click was a black hole while any draw tool was armed. Every draw case
ended with `if (evt.RightDown()) { m_points.clear(); return true; }` and returned true even with
nothing to abandon; on_mouse records that in m_right_consumed and DesignCanvas suppresses the
offer whenever it is set. Measured: with Line armed, two right-clicks in a row produced no menu
and no tool change; only Escape freed it. Same rule snaporca-xmh6 wrote for the selection —
clearing nothing is not a gesture terminator. One shared right_abandon() now consumes the click
only when an anchor was really down; 16 sites, plus Polyline/BSpline (which end a chain, correct
only when there IS one) and Point (which has no anchor at all).
snaporca-lnri (P2) — right-clicking a sketch point offered the empty vocabulary. select_at_screen
tests hit_test_point first and records the hit in m_point_sel, but the offer counts m_selection
only, so a Point entity could never reach the entity branch and SkPoint was unreachable by
construction. A Point IS its own handle, so it is selected as an entity; other entities keep the
handle pick, since a line's endpoint is a drag target, not a vocabulary.
Offer ladder 25/25, gesture ladder 93/93 (no regression), both on the rig. The offer ladder joins
scripts/ladder-all.sh as the fifth rung.
snaporca-ghcz snaporca-lnri
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MrMzTpAf78U4NG2M8jfvHY
|
||
|
|
12047e4085 |
A bulk sketch_add no longer freezes the next gesture
Draw-then-edit is armed from a jump in the entity count: render() sees n > m_autoedit_seen, selects the last entity and schedules open_primary_autoedit. A scripted add made while a creation tool was armed looked exactly like a drawn gesture, so it opened that tool's value field — and an open field freezes the canvas (on_mouse_impl returns early on m_awaiting_length) and swallows every letter (in_text includes inline_busy()). Measured on the rig: after sketch_add, 'p' + click added nothing (4 entities before, 4 after); one Escape and the identical sequence gave 5. It also explains the selection = [last index] that sketch_describe reported although action_sketch_add never selects anything — the render pass wrote it. Escape worked because it sequences two set_tool calls: the pending CallAfter fires between them, so the second one commits the field it finds open. Arming a tool directly is one call, and the CallAfter fires after it. Fix: resync m_autoedit_seen at the end of add_entities_scripted, so a scripted add is not read as something the user just drew. An already-open field is left alone. Covers sketch_add, sketch_mirror and sketch_offset — the three callers. The scale rung's Escape workaround is deleted, which is the issue's acceptance criterion; it is now the regression test. Gesture ladder 93/93 on the rig. snaporca-j7gc Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MrMzTpAf78U4NG2M8jfvHY |
||
|
|
bc1606a4d0 |
Port from snaporca ab22482e40: say why a sheet was skipped, and stop calling an encrypted PDF an engine failure
Over the whole 977-sheet corpus: 767 graded, 767 fully clean, 0 failures. The 210 skips are sheets whose part outline is not a closed stroked path at all (largest loop 5 to 132 mm2, measured), and one of them — MPD133 — is password-protected, which was being reported as an engine ERROR. Both now say what they are. snaporca-j6sr |
||
|
|
4693542d0d |
Port from snaporca: the solver's 1024-unknown cliff, and the scale rungs
Two commits carried across (snaporca 579a9a9162, f68613cfc5). Past about 480 entities a sketch had NO constraints at all and said nothing: libslvs declares MAX_UNKNOWNS = 1024 and is handed every entity in the sketch at two params per point, so the whole system came back TOO_MANY_UNKNOWNS and try_add_constraints rolled the entire inferred batch back. From there no dimension could ever be applied. Constraints only couple entities that share a point, so the solver now falls back — only on TOO_MANY_UNKNOWNS — to solving connected components separately and committing all-or-nothing. The auto-constraint pass batches its Horizontal/Vertical constraints instead of one solve each, which is what kept the bulk path fast once solves started succeeding: a 1204-entity load went 1585 ms -> 562 ms. Plus the scale rungs (a thousand-entity plate drawn on by hand; the heaviest real drawings graded and timed), the --step 1 fix that used to select nothing while reporting a clean run, and scripts/ladder-all.sh as the one-command gate. Parity 17 identical / 8 diverging as expected. Kernel suite here: 188 cases / 2532 assertions, including "a sketch past the solver's unknown limit still solves". snaporca-yww4, snaporca-x6v7, snaporca-j6sr |
||
|
|
82db99f337 |
Port from snaporca: sketch-only projects save, scripted geometry arrives exact,
and a ladder that draws with the mouse Three commits carried across (snaporca 4ffd60eacb, 421055c2ec, b71216ce0b): 1. A design made only of sketches must survive being saved. CadDocument::recompute returned false with "no solid-producing features" for a document that has no solid, and two callers read that as "unusable": the GUI syncs the 3MF recipe only after a successful recompute, so a sketch-only design was saved with no recipe at all, and deserialize_recipe ends with `return recompute()`, so even a project that carried one was refused on load. Having nothing to build is now a success; a feature that MEANT to build a solid and produced none still fails. DesignPanel::refresh_tree syncs the recipe too, for the paths that call m_doc.recompute() directly. 2. Scripted geometry arrives exact. The Horizontal/Vertical inference window and the endpoint weld window both close to zero for add_entities_scripted; void attribution probes from a point strictly inside each loop instead of from its first vertex. Corpus rung 39 graded / 39 fully clean, was 35 with 6 failures. 3. scripts/gui-ladder.py — 17 rungs, 84 properties, all driven by synthetic clicks and typed values rather than through the socket. Parity 17 identical / 8 diverging as expected. Kernel suite here: 188 cases / 2532 assertions. snaporca-mtav, snaporca-8xg1, snaporca-5hvl, snaporca-730j |
||
|
|
05ce2607a8 |
Ladder rung 9: grade the engine against 50 real drawings, not against my taste
Ported from snaporca 5b82c846f3. |
||
|
|
cbbd24dcb4 |
Port the exact loop area, the offset traversal fix, and the 2D sketch ladder
Carries snaporca 572f794c84, d0f9a0052a, 9f7e4e3627 and 3974f8a170. Parity holds: 17 files identical, 8 diverging by their expected counts. EXACT AREA. A loop's area is now integrated entity by entity in traversal order — Green's theorem — instead of being shoelaced over the render polyline, which faceted every arc into 24 chords and lost 2.02 mm2 on a 3706.86 mm2 stadium. 0.054%, invisible on screen, and wrong in a number reported as "the area". OFFSET FOLLOWS THE TRAVERSAL. Offsetting a mirrored profile put one half on the wrong side and split the loop in two, because the chainer only followed p1->p0 links and each entity's offset side was taken from its stored direction. Chains are now orientation-aware, seeded at a free end, offset by `reversed ? -d : d`, and normalised head-to-tail on the way out — so offset is correct for any input ordering and its own output cannot reintroduce the problem. Both are the same underlying lesson, which has now cost three separate defects: an entity's STORED direction is not its direction of TRAVEL around the loop. THE LADDER. scripts/sketch-ladder.py is a graded suite of 2D sketches judged the way a person judges them — VERTEX, LENGTH, ARC, TANGENT, SYMMETRY, CLOSED — with area only as a cross-check, because area is derived and nobody can confirm it by eye. Eight rungs from a rectangle up to MPD5 from the StudyCadCam corpus, a dia 27 x 95 pin reproduced as its revolve half-profile with the R5 fillet tangency solved exactly. Entirely 2D: no extrude or any solid feature. Kernel here: all tests passed, 2681 assertions in 231 test cases, including the new "profile: a mirrored half offsets as one loop, not two". GUI target builds and links. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
fbf858ba47 |
Port the MCP verb surface: run_verb / list_verbs / sketch_set_value
Carries snaporca 39fac9b725. Parity re-verified: 17 files identical, 8 diverging by their expected counts, DesignPanel.cpp still at 32 — the mirrored files were copied and the two divergent ones patched hunk by hunk, so the counts returning to their expected values is the proof each landed on the right side. All 90 offer verbs are now firable by name over the socket, which matters because a deck key can only send a keystroke and 49 of them have no shortcut at all. sketch_set_value calls the same apply_dimension the in-canvas value field calls, so a typed dimension can be asserted with no window manager in the way. Three guards came with it, each confirmed against the source: on_mass_properties bounds-checks m_sel_solid_body (it defaults to -1, and run_verb bypasses the menu grey-out that used to hide that); sketch_set_value validates its value at the boundary because apply_dimension records a driving constraint even for values it refused to apply; and run_verb refuses btn:/fly: verbs that do not apply to the selection while leaving key: verbs alone, so the socket offers exactly what the GUI offers. Dispatch is deferred through CallAfter so no modal verb can wedge the socket thread. GUI target builds and links against the rebuilt deps image. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
5d7fc8c545 |
Port the sketch layer work from snaporca: offset chains, right-click, MCP verbs
Carries snaporca 971320e129, 6b049f0dc6, 4aae782029, 444d59f212, 74cf3d7e54 and the build guards from 597557a6e4. Parity re-verified after every hunk: 17 files identical, 8 diverging by their expected counts — DesignPanel.cpp still 32, DesignCanvas.cpp still 16, which is the proof each hunk landed on the right side rather than being copied over a real divergence. OFFSET OFFSETS THE CHAIN. Per-entity offsetting returned a closed rectangle as four parallel segments that no longer touch, so entities_to_wires gave four OPEN wires and nothing could be extruded. offset_entities now chains by shared endpoints and repairs each seam by mitering the neighbours to their intersection. Second bug, invisible to any single-entity test: +d meant "left of travel" for a line but "radius + d" for an arc regardless of sweep, so a slot outline offset with its straights going one way and its caps the other. The convention is now written on the declaration and pinned by a test. tests/libslic3r/test_sketchprofile.cpp is new and asserts the LOOP rather than coordinates — the property that decides whether a profile can be built, and the one the existing single-entity [SketchEdit] cases cannot see. Its include is catch2/catch_all.hpp here: this fork ships Catch2 v3 while snaporca is on v2, which is why the test files are a tolerated divergence. RIGHT-CLICK PICKS WHAT YOU POINTED AT, so a line's own verbs are offered instead of the empty-selection vocabulary; sk_delete stops sharing btn:delete with the feature tree; and an element's defining number (length / radius / diameter / angle / distance) can be typed, from the menu or from V. TWELVE MCP SKETCH VERBS. The socket had ~40 verbs and none touched a sketch, so the 2D layer could only be exercised by driving a GUI with synthetic clicks. sketch_describe reports each closed loop, the loops it encloses as voids, exact areas, and where a chain is still open; sketch_validate/sketch_heal are FreeCAD's ValidateSketch — find vertices that overlap within a tolerance but carry no coincidence, then weld them AND record the constraint, so a loop closed by floating-point luck becomes one closed by construction. scripts/mcp-sketch-smoke.py is the loop that asserts all of it. Kernel suite on this fork: all tests passed, 2677 assertions in 230 test cases. The GUI target links against the rebuilt deps image (the wxInspector blockage is gone) and the binary carries the new verbs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
df45edb13d |
deps image: carry the rig's X runtime itself
Building orcacad-deps from this Dockerfile removes the snaporca-deps base, which is the point (Trap 1: the old image's baked tree was project(Snapmaker_Orca)) — but that base was also where Xvfb, openbox, xdotool and scrot came from. Without them gui-session.sh reports display DOWN and orca-slicer dies with a trace trap on no display. Verified: the session now comes up with display up, wm up, and the Untitled - OrcaSlicer window present. |
||
|
|
9764815cc3 |
rig-build: -j12, and a deps image that has wxInspector
Raises the bound from -j8 to -j12: the incident dump measured 1.17 GB average per cc1plus, so 12 in flight is ~14 GB typical, well inside the 40 GB cgroup ceiling that is the real guarantee. Keeps the file byte-identical to snaporca's copy, which the header requires. Dockerfile.deps builds the deps with -j 12 for the same reason, and symlinks deps/build/destdir -> deps/build/OrcaSlicer_dep: this tree installs under the latter name while the orcacad_buildcache volume has the former baked as absolute paths in its CMakeCache. Same tree, two names — without the link, one directory rename costs a full cold rebuild. |
||
|
|
8906bfa72b |
rig-build: bound the memory a build can take
Both forks ran this script at once on 2026-08-21, each with ninja -j$(nproc)=16. 36 cc1plus held 42 GB of a 62 GB box, the kernel OOM-killed for 2h28m, ssh went unreachable, lightdm was destroyed (2946 session kill events), and neither build produced a single object file. Three bounds, weakest to strongest: a flock on a path SHARED by both forks so they serialise instead of summing; -j8 so the box stays usable while it compiles; and --memory on the container, which is the actual guarantee — a runaway build now dies inside its own cgroup instead of taking the host with it. --memory-swap is pinned equal to --memory because swap thrash is what made ssh hang rather than fail. Kept byte-identical to the copy in the snaporca fork, as the header requires. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
5ed56eb876 |
Cache system presets to eliminate startup and wizard load times (#14217)
* Add caching system for presets * Removing user\bundle serialization and keeping it only for system presets * Integrate caching into WebGuideDialog which speeds up time of SetupWizzard and PrinterSelection dialog * Add CI\CD step to prepare cache file in ahead of time so user does not need to wait * Add partial cache generation when only one of the vendros is changed to speed up recalculation time * Handle corrupted files * Add cache to GuideDialog as previos version didn't work as expected * Add inspecting tool and fix CI cache generation * Generate cache per vendor * Simplify code by mergin it in PresetBundle * Simplify code a bit more * Add cereal serialize() to VendorProfile, PrinterModel, Preset, and Semver * Remove CachedPrinterModel/VendorProfile/Preset mirror structs from VendorCache * Fix use-after-free in CallAfter lambda; replace raw thread pointer with unique_ptr * Use get_vendor_cache_key() to match cache keys written by the app * Remove BOM added by VSC * Skip invalid vendors * Remove leftover cache file * Fix build for windows arm64 * Revert json cache back * Update check for stale cache * Serealize all value fields for Preset class to minimize regression later * Minimize field duplication by moving Cache thing into PresetBundle * Add tests for Cache system * Add a bit more tests * Merge branch 'main' into feature/cache_profiles_and_optimize_loading_speed * Rvert from per-verndor to single cache file Replace N per-vendor .cache files with a single system_presets.cache that holds all vendors and presets in one serialized blob. Cache load is now all-or-nothing: on hit all vendors are applied from the bundle (sub-second); on miss all vendors are parsed from JSON and a fresh bundle is written to the user cache dir. Invalidation is driven by bundle_key - a sorted concatenation of all vendor JSON version strings. Any vendor update invalidates the whole cache and triggers re-parse on next launch. Guide wizard (WebGuideDialog) loads the bundled cache into a plain PresetBundle instead of a separate VendorGuideData struct, removing the duplicate data model. generate_system_cache simplified from a per-vendor loop to a single save_system_presets_cache() call producing one output file. * Transfer all Preset fields from cache via move assignmet apply_vendor_preset_group was copying fields manually and missed bundle_id, user_id, base_id, sync_info, updated_time, key_values, ini_str. Replace field-by-field copy with move assignment of the fully-deserialized Preset, then restore the vendor pointer which is excluded from serialization. * Ignore cache for future * Remove not used files * Ship one preset cache per vendor in place of the profile JSONs Each vendor's system presets serialize into a single <vendor>.opc built at package time, and a shipped build carries that file alone — the profile JSON and its sub-file tree are pruned. The vendor loader, the setup wizard's profile list and the resource installer all read a vendor through its cache, falling back to parsing whenever one is absent, stale or unreadable, so the cache stays an optimization and never a source of truth. Caches hold presets in source form and resolve inheritance at load, through the same code the JSON path uses. * Make the preset cache self-describing and load each vendor from the system folder alone The cached DynamicPrintConfig is keyed by name, through a per-file dictionary of the distinct opt_keys, the type each was written as, and the distinct enum value names, instead of by serialization_key_ordinal — a position assigned by declaration order at static init, where inserting one option shifts every later ordinal and the lookup then succeeds on the wrong option. Because a name-keyed payload drops the options this build cannot place rather than being rejected wholesale, the schema fingerprint goes, and with it the two fallbacks that existed only because an installed cache died on every app upgrade: the second lookup tier into resources/profiles and the parse fallback to the same place. A vendor is loaded from <data_dir>/system/ and nowhere else, as on main — which is what makes the app write its .opc files there again. * Simplify the preset cache internals after review * Use the shared temp-dir helper in the preset bundle loading test * Bound stamp string reads in the preset cache * Speed up the setup wizard with a profile-data cache The wizard's per-vendor fast path threw on vendors present only in resources, falling back to a ~29 s raw JSON scan on every open. Each vendor now loads from the directory it was found in, and the derived model/machine/filament/process catalog is cached whole in <data_dir>/cache/wizard_profile_data.json, stamped by each vendor's name and version - a fresh cache makes an open one file read, with no bundle built and no presets installed (~0.2 s vs ~2 s). * Remove debug SVG dump from a geometry test * Move the per-vendor cache file format into PresetCacheFormat * Move the vendor install helpers from PresetBundle into Utils * rename * fix flatpak * change cache version to 1 --------- Co-authored-by: SoftFever <softfeverever@gmail.com> |
||
|
|
2179f5f670 | fix build errors on Windows | ||
|
|
56eebe3398 |
kernel-test: stop configuring the GUI, which the kernel suite never needed
This script builds only libslic3r_tests, which links libslic3r and no GUI code — but cmake still processed the whole if(SLIC3R_GUI) block and every find_package inside it, so the kernel suite silently depended on the GUI's dependency set. That came due the moment upstream added wxInspector as a REQUIRED find_package: the orcacad-deps image predates it, so configure died pointing at src/CMakeLists.txt:92 with nothing about the kernel having changed. Turning the block off is not a workaround for that one dependency — it is the suite finally declaring what it actually needs, so the next GUI-side dependency added upstream cannot break it either. Surfaced by taking SoftFever's merge of main into the PR branch. |
||
|
|
030e5f469e | Merge branch 'main' into cad-mainline | ||
|
|
74c4a7e450 |
Support printer specific filament profiles in the OrcaFilamentLibrary (#15101)
* Support printer specific filament profiles in the Orca Filament Library |
||
|
|
cfc2555c3a |
Design: a verb's address is data, so the toolbar widget can stop existing
snaporca-7ih's remaining half. Both flyout factories registered their verbs INSIDE the widget-building loop, so the ~40 retired tool buttons had to be constructed and then Hide()n: skipping construction would have deleted 42 offer verbs (26 fly:<family>#<row> + 16 Shift+keys) while their rows still rendered and did nothing when picked. Register first, build second. The addresses are pure data; the widget is one door onto them, not their owner. A family absent from kBarKeep now returns before any wxWindow is made. The keep-list stays a one-line data decision, not a structural one. And close the class of bug for good: the constructor now verifies, once, that every verb the atlas marks wired resolves to a real registration, logging each break and asserting in debug. Rows that render and do nothing have shipped three times (edit_feature and sk_move with action:null, then this) and are invisible from either side alone. Verified on the snaporca rig by walking the offer, not by reading the code — all four at-risk address kinds run with no widget behind them: fly:design_rect#2 drew an OBLIQUE rectangle (the third variant, not the family's first), key:S+E opened Extrude with its 10 mm gizmo, fly:material#4 opened Thicken. Hover hints, icons and nesting intact. This fork is code-identical here bar the two permitted DropDown divergences; it still owes a build of its own (snaporca-5pl). Two hints were wrong and are fixed: Cut said "Split the body with a plane", colliding with the Split verb one row away and pointing at a card for a value the canvas already offers as a draggable arrow; Split never said its plane comes from a picked face. Also, because it blocked the verification and will block the next one: gui-session.sh killed by full path while its own app_pid() matched by basename, so a differently-pathed instance survived, held the single-instance lock, and got reported as a healthy session — a Jul-30 binary nearly passed as this build. It now kills by basename and prints which binary is actually on screen. Traps 6 and 7 documented. |
||
|
|
fd1bc092d8 |
Design: slot Radius caption, keyboard offer, plane combo removal, mass props, docs
Mirror of snaporca ac85277bac..0e7cb3ec78 (six changes, applied as a patch to DesignPanel.cpp rather than copied, so this fork's 30 permitted divergent lines survive — parity re-checked afterwards: the five shared files are byte-identical, DesignCanvas.cpp and DesignPanel.cpp differ by exactly 16 and 30 lines). - The straight slot's inline field says Radius, which is what it sets. It stores the half-width and passed the typed number through unchanged, so 30 produced a 60 mm slot. - The offer opens from the keyboard (Menu, Shift+F10), anchored on the viewport rather than wherever the pointer happens to be. The card hint names the new route. - The sketch card's Plane combo is gone; the plane comes from the viewport. Also stops build_candidate collapsing a face plane to a base plane while editing. - Mass properties and the dead Edit row are wired into the offer; DesignOffer.hpp is regenerated from tool_atlas.json, verified by re-running the generator and diffing. - docs/rig_build_traps.md + scripts/rig-build.sh, which derives its fork identity from project() so it cannot be pointed at the other fork's image or volume. - docs/design_tab.md refreshed (44 commits stale) + a PR description, with this fork's own merge-base and diff shape rather than snaporca's. Built green in the deps container with the new script and verified on the rig: Menu and Shift+F10 both open the offer at the viewport centre with the pointer parked off-canvas, and the sketch card shows no Plane row. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LyRwbuq6fjn3VV9U9UvhBM |
||
|
|
303be94262 | feat(msix): add execution alias and web link associations to the Store package (#14799) | ||
|
|
f14d31d956 |
scripts/gui-session.sh: bring the headless GUI up without clicking blind
The relaunch sequence was an ad-hoc pile of docker exec one-liners, and it had a real bug: it dismissed the first-run dialogs by computing the titlebar close box from `xdotool getwindowgeometry --shell` and clicking it. When the dialog had already closed, that eval left the geometry variables stale or empty, the click landed at a garbage coordinate, and it kept hitting the Sketch button in the toolbar underneath — so the app came up in sketch mode with a stray Sketch feature that then had to be cancelled by hand. Three times in one session. The fix is not a different mechanism. `xdotool windowclose` looks cleaner and KILLS THE APP: it destroys the GdkWindow out from under the dialog and the process dies with "GdkWindow unexpectedly destroyed", three GLib-GObject criticals and a segfault. Measured, not guessed — that is what the first version of this script did. Escape does not close the Setup Wizard either, which is why it needs handling at all. So the titlebar click stays, and what changes is that it refuses to click geometry it has not validated: the window id is re-resolved immediately before, all four geometry variables are unset first and must come back numeric, and the computed point must be inside the screen. Any of those failing logs why and clicks nothing. Two further honesty fixes in the status output, both caught by reading it rather than by it failing: app_pid skipped nothing, so with a container full of <defunct> instances it printed a dead pid as though the session were healthy — it now walks /proc/<pid>/stat and ignores zombies. And a container without x11vnc reported "vnc: DOWN" as if something had broken, when nothing was ever installed; it now says so, and does not try to start what is not there. Also replaces the fixed post-launch sleep with a wait for the main window, because cold starts under software GL vary by a lot, and adds --status for diagnosis: "no windows but the desktop is up" means the app died, "cannot connect at all" means the desktop did. That distinction cost real time to work out by hand. Verified on both containers: one run each, wizard closed on validated geometry, no stray sketch mode, live pid reported, and the app still up. snaporca-e1p adjacent (tooling, not the tab itself). |
||
|
|
63044b7661 |
feat: Add layout debugging/inspecting tool (#14919)
* Add wxInspector dep * Initial intergration of wxInspector * docs: add wxInspector plugins design spec Design spec for two wxInspector plugins (DPIAware + CustomWidgets) that expose OrcaSlicer's custom control properties in the inspector property grid. Covers: DPIAware scale-factor properties, Button, CheckBox, TextInput, SwitchButton, ProgressBar, Label, and LabeledStaticBox. * docs: add wxInspector plugins implementation plan 6-task plan covering: source changes to existing widget headers, DPIAwarePlugin, CustomWidgetsPlugin, registration helper, MainFrame/CMake wiring, and build verification. * feat: add getters/setters for wxInspector plugin access Add minimal public accessors to DPIAware (set_scale_factor, set_prev_scale_factor, set_em_unit, force_rescale), Button (GetStyle, GetType, IsSelected), CheckBox (IsHalfChecked), TextInput (GetCornerRadius), and LabeledStaticBox (GetCornerRadius, GetBorderWidth, GetBorderColor, GetScale). * feat: add wxInspector plugin registration helper Add RegisterOrcaInspectorPlugins() inline function that creates and registers the DPIAwarePlugin and CustomWidgetsPlugin as static instances (matching wxInspector's built-in pattern). * feat: add DPIAware wxInspector plugin Exposes DPI scaling properties (scale_factor, prev_scale_factor, em_unit, normal_font, force_rescale) on DPIFrame and DPIDialog widgets. Uses dynamic_cast for detection and a template helper to capture the correct static type for lambda accessors. * feat: add OrcaCustomWidgets wxInspector plugin Exposes Orca-specific properties on 7 widget types: - Button: Style, Type, Selected - CheckBox: Half Checked - TextInput: Label, Text Value, Corner Radius - SwitchButton: Value - ProgressBar: Proportion, Show Number - Label: Is Hyperlink, Font Point Size - LabeledStaticBox: Corner Radius, Border Width, Border Color, Scale Each widget type uses dynamic_cast for safe detection. * feat: wire wxInspector plugins into MainFrame and build Call RegisterOrcaInspectorPlugins() in MainFrame constructor after SetupInspectorAccelerator(). Add all 5 plugin source files to SLIC3R_GUI_SOURCES in CMakeLists.txt. * fix: move plugin registration to GUI_App::on_init_inner Register plugins once in app init rather than in MainFrame constructor, which may be recreated during the application lifetime. * fix: include plugin headers in Registration.hpp for complete types Static locals require complete type. Include DPIAwarePlugin.hpp and CustomWidgetsPlugin.hpp instead of forward-declaring. Also remove unused include from MainFrame.cpp (registration moved to GUI_App). * fix: qualify DPIFrame/DPIDialog with Slic3r::GUI namespace * Make DPIDialog inspectable. For other dialogs, we will add them if necessary later. * docs: add spec for moving wxInspectable into DPIAware template Move wxInspector::wxInspectable base class from DPIDialog and MainFrame into the common DPIAware<P> template, making all DPIAware widgets automatically visible in the inspector tree. Co-Authored-By: Claude <noreply@anthropic.com> * docs: add implementation plan for moving wxInspectable into DPIAware Co-Authored-By: Claude <noreply@anthropic.com> * docs: update spec/plan — move SetupInspectorAccelerator into DPIAware too Co-Authored-By: Claude <noreply@anthropic.com> * refactor: move wxInspectable and SetupInspectorAccelerator into DPIAware DPIAware<P> now inherits wxInspector::wxInspectable and calls SetupInspectorAccelerator in its constructor, making all DPIAware widgets automatically appear in the inspector tree with the Ctrl+Shift+I shortcut. DPIDialog now uses 'using' to inherit the constructor. Remove redundant wxInspectable inheritance and SetupInspectorAccelerator calls from DPIDialog and MainFrame. Co-Authored-By: Claude <noreply@anthropic.com> * fix: use LB_HYPERLINK constant instead of magic number 0x0020 Co-Authored-By: Claude <noreply@anthropic.com> * Clean up * Fix Linux build * Don't build wxInspector sample * Use shallow clone * Try fix flatpak build * Attempt to fix build again * Fix build failure caused by https://github.com/wxWidgets/wxWidgets/commit/436c16135ec7ddf580f44624bf74c592aae43b66 * wxWidgets build only download required submodules * This should fix build on Windows on ARM * Enable PIC * Disable layout inspector by default for public release * Use wxInspector 1.0.0 release --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
5026dd11a6 |
Fix the solver abort on circle-line tangency; the CAD suite now runs complete
snaporca-tkz, the last quarantined test. Root cause read out of the vendored
source rather than guessed: slvs/constrainteq.cpp, Type::ARC_LINE_TANGENT does
ExprVector ap = SK.GetEntity(arc->point[other ? 2 : 1])->PointGetExprs();
so it dereferences the ARC'S ENDPOINTS. A full circle entity carries only
point[0], its centre. point[1] and point[2] are zero handles, FindById throws
"Cannot find handle", and the process ABORTS rather than failing the solve —
taking every later test in the binary with it. That is also the wrong equation
for a circle regardless: it only makes the line perpendicular to the radius at
an endpoint that does not exist.
CT::Tangent no longer hands a full circle to that constraint. For a circle it
emits PT_LINE_DISTANCE(centre, line) = radius, which is precisely what tangency
to a circle means. Arcs keep the ARC_LINE_TANGENT path they are built for.
One limitation, stated rather than buried: the slvs C API takes a constant
distance and offers no way to reference the circle's radius parameter, so the
radius is captured when the constraint is emitted. That is exact whenever the
radius is fixed or is simply not driven by another constraint in the same
solve, and re-solving restores tangency if something else moves it. Tying them
would need an auxiliary point constrained onto both the circle and the line.
With this and eeca6794e7, both quarantined tests are gone and the exclusion in
kernel-test.sh goes with them. A green run now means the whole CAD suite
passed, not "everything except the two we gave up on":
149 cases / 2043 assertions, no filters.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
f599ff0ff7 |
kernel-test.sh: one quarantined case now, not two
Follow-through from eeca6794e7. The header claimed two pre-existing failures are excluded and named both; the internal-thread case now runs like any other, so only the solver SIGABRT is left. A comment that lists a test which is no longer excluded sends the next reader looking for something that is not there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
9c199e4a38 |
Fix the Shellcheck CI job, red since the CAD kernel-test loop landed
The Shellcheck workflow has failed on every push and every scheduled run since 2026-07-24, on exactly one finding: SC2029 in scripts/kernel-test.sh, the file the CAD branch added. So the CAD work is what turned that job red, and a PR arriving with a red job is a bad way to open a conversation with a maintainer. Client-side expansion of $REMOTE is the intended behaviour — it is derived from $VOL locally and the remote has no such variable, exactly as the rsync destination two lines down relies on. So this is a disable with a reason, not a silencing: the note says why the warning does not apply. Verified by running the workflow's own command over all 24 matched scripts: exit 0, no findings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
f13f2876f6 |
Tag the two known-broken tests [NotWorking] so CI stops being red on every commit
This fork's Unit Tests job failed on every single commit, because CI runs the whole ctest suite including the two cases tagged [known-broken] that scripts/kernel-test.sh has always excluded locally. A job that is red unconditionally is worse than no job: it trains everyone to ignore it, so the next genuine regression arrives invisible. No workflow change was needed. scripts/run_unit_tests.sh already passes -LE NotWorking, and tests/CMakeLists.txt registers Catch2 tags as ctest labels via catch_discover_tests(ADD_TAGS_AS_LABELS) — so the exclusion upstream already ships works as soon as the cases carry the tag. Verified against the built test tree: 337 tests unfiltered, 335 with -LE NotWorking, i.e. exactly these two dropped and nothing else. The second cause recorded in the issue, the test-reporter step failing with "Resource not accessible by integration: 403" on a fork, is already fixed upstream: the Publish Test Results step now carries continue-on-error: true. The comment these cases carried claimed CI kept the bugs visible by reporting them forever. That is now false and was never a good mechanism anyway, so visibility moves to the tracker: snaporca-tkz for the solver SIGABRT, and snaporca-kzy, filed now, for the thread groove volume. Neither is fixed; neither is forgotten. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
afe6d11375 |
Make this fork's GUI link: OpenCV was reusing snaporca's JPEG-enabled build
First successful link of orca-slicer in this fork's history (158 MB, 738/738
objects, plus OrcaSlicer_profile_validator).
|
||
|
|
ed9d02093e |
Default both build scripts to orcacad-deps, not the other fork's image
Both scripts defaulted IMAGE to snaporca-deps. That image is Snapmaker-based
and lacks Eigen 5.0.1, CGAL 5.6.3, wx 3.3.2 and Python 3.12 Development.Embed,
so running either script here without an explicit IMAGE= dies at CMake
configure — which is a large part of why this fork reached M8 having never once
compiled (
|
||
|
|
1633005bba |
Make this fork actually compile: first green Catch2 run in its history
206/206 targets built, 139 [CadDocument] cases / 1960 assertions passing —
identical to snaporca's suite. Until now this fork had never compiled at all:
CMake died at configure, so the M1-M8 "suite green" figures were snaporca's
alone and the ports rested on patch-apply plus byte-identical sources.
Three fixes here; the deps work is in the orcacad-deps image (see below).
1. kernel-test.sh mounts deps_src. pybind11 is vendored in-tree and CMakeLists
requires its headers; without the mount the container fell back to the
image's baked tree, which predates it.
2. tests/libslic3r/test_3mf.cpp: repair the upstream-merge conflict resolution.
Resolving it as a union dropped the three closing braces of our SCENARIO, so
upstream's SCENARIO opened inside ours ("a function-definition is not allowed
here", plus 12 cascading catch2 registry errors). Restored from the pre-merge
file; whole-file brace balance is now 0 and the case count reconciles as
5 (ours) + 8 (upstream) - 3 (shared) = 10, with both CAD recipe tests intact.
3. tests/libslic3r/test_caddocument.cpp: REQUIRE_CONTAINS / CHECK_CONTAINS.
Catch2 v2 (snaporca) spells substring-match Matchers::Contains; v3 (here)
spells it ContainsSubstring and gives Contains an incompatible meaning,
range-contains-ELEMENT, which fails to COMPILE against std::string. Four
sites had been hand-adapted long ago, but M2-M8 kept porting in un-adapted
Contains calls — 16 of them — and nothing objected because nothing compiled.
Both forks now use the same find()-based macros, so the assertion lines are
byte-identical again and future format-patch ports carry across unchanged.
Five orphaned `using Catch::Matchers::Contains;` lines removed with them.
The deps gap that blocked configure needed five additions on top of
snaporca-deps, built into image orcacad-deps: Eigen 5.0.1, Python 3.12.13
(exact, with Development.Embed), wxWidgets 3.3.2 (was 3.1.5), CGAL 5.6.3
(was 5.4 — mainline's own MeshBoolean.cpp calls CGAL::parameters::default_values,
added in 5.5), plus the pybind11 mount above. OCCT V7_6_0, Boost 1.84.0 and
OpenCV 4.6.0 are pinned identically in both forks and were reused as-is.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
113e75e7b3 |
kernel-test.sh: stop defaulting to the other fork's build volume
BUILD_VOL defaulted to snaporca_buildcache — snaporca's volume — so running
this fork's kernel test wrote into the other fork's build cache. Defaults to
orcacad_kerneltest now.
docker-iter-build.sh had the identical defect and was fixed to
orcacad_buildcache; this script was missed at the time.
Observed rather than theorised: an orca_cad run under a different deps image
overwrote snaporca_buildcache's CMakeCache.txt, after which snaporca's own
kernel test failed to configure ("Cannot find NLopt library 'nlopt_cxx' in
.../lib/cmake/nlopt/lib") because it inherited the foreign cached paths. No
foreign object files were written — the run died at configure — but the cache
was poisoned, and the volume had to be wiped and rebuilt clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
8c6df84acc |
Merge upstream/main into cad-mainline (530 commits)
Catches the fork up from |