mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-11 09:51:06 +00:00
88eb219868cd70936fa4a30cf168cc85eeb91eda
23
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8a6377f087 |
Add Missing Includes Across src/libslic3r (#16068)
* Add Missing Includes Across src/libslic3r Every libslic3r source and header now directly includes the headers declaring what it uses, rather than relying on the precompiled header or transitive includes. Generated with clang-tidy misc-include-cleaner, with libslic3r headers spelled libslic3r/... so they resolve outside the library's private include paths. MultiMaterialSegmentation.hpp, Support/SupportParameters.hpp and Format/STEP.hpp are made self-contained by hand. * Make the libslic3r Headers Compile on Their Own Each now includes, or forward-declares, what it uses instead of relying on what its includers happened to include first. Left out: I18N.hpp, which errors on purpose when included from GUI code, and VoxelizeCSGMesh.hpp and SLA/bicubic.h, which nothing includes and which no longer compile at all. * Add the Includes Missing From the Hand-Fixed libslic3r Headers clang-tidy would not edit these headers while they failed to compile on their own, so the first pass skipped them. With the headers now self-contained, a second pass adds the rest. * Keep Windows Setup Ahead of the Added libslic3r Includes Print.cpp and Thread.cpp open with a _WIN32 block that has to come first; without the precompiled header, Print.cpp otherwise reaches windows.h through OCCT with NONLS defined and boost/regex fails. OpenVDBUtils.cpp and SLA/SupportTreeBuilder.cpp had includes inside #ifndef NOMINMAX, which libslic3r defines on Windows, so those were skipped there. .clang-tidy also ignores the MSVC STL and UCRT internals, Boost.Multiprecision's fwd.hpp and CPython's Windows include directory. * Re-Add libslic3r Includes After the Clipper2 2.0.1 Migration Rebasing onto main took main's version of the files the Clipper2 migration rewrote, so their added includes are restored here, along with includes for main's new code. Clipper2's individual headers are now ignored by clang-tidy: they only build the Z variant through clipper2_z.hpp, which defines USINGZ first, so including clipper.core.h and the like directly broke ClipperZUtils.cpp. |
||
|
|
f3a8f711fd |
Catch Standard_Failure before std::exception (OCCT >= 8) (#15826)
Co-authored-by: yw4z <ywsyildiz@gmail.com> |
||
|
|
00bde9265b |
Add missing OCCT (8.x) header includes (#15825)
* Add missing TopTools includes to GeometryEngine.cpp * Add missing TDF_LabelSequence include in STEP.cpp --------- Co-authored-by: yw4z <ywsyildiz@gmail.com> |
||
|
|
31a15cc5e5 | Rename snaporca/SnapOrca to orca_cad so the OrcaSlicer PR carries no Snapmaker naming | ||
|
|
bb6a1810f6 |
A stray click must not break a model that looks perfect on screen
Revolve failed on a sketch whose profile was closed. Decoding the reported 3mf: four
entities forming a proper closed loop (joints open by 4.44e-06 mm, well inside
tolerance) plus one stray 1.82 mm Line at (-24.2, 80.3), inside the shaded region,
touching nothing.
The viewport's region_loops discards open chains ON PURPOSE — it exists to find
EXTRUDABLE regions — so the user saw one clean closed region. entities_to_wires kept
the stray as its own one-edge loop, so it returned two wires, and Revolve goes through
entities_to_wire which demands exactly one. Extrude would have failed one step later in
wires_to_face, because a one-edge open wire bounds no face. Same class as the tolerance
split fixed in
|
||
|
|
8b568b7b9d |
The viewport and the kernel now answer "is this joint closed?" with one number
Tommaso asked the question that names the real defect: if the sketch was open, why was the same sketch shaded closed and offered for extrude? Because the two halves used different tolerances. region_loops shades a region closed at 1e-3 mm; connected_loop chained at 1e-3; the kernel welded at 1e-4 and OCCT matched vertices at 1e-7. The 2.28e-5 mm gap in the reported sketch did not cause that disagreement, it only made it visible — and fixing the gap alone would have left the contradiction in place, ready to reappear anywhere in (1e-4, 1e-3]. kSketchJoinTol now lives in SketchEngine.hpp and is the only place the number exists. region_loops, loop_report, connected_loop and entities_to_wires all read it through sketch_join_tol(). The viewport cannot promise a region the kernel refuses to build. The welding is optional, because a kernel that silently closes loops should let you say no: "Auto-close sketch loops" in Preferences, default ON, no restart. OFF means only exactly coincident endpoints join — and since both halves read the same value, the viewport simply stops shading the region closed, so an open loop is visible rather than welded behind your back. No separate UI needed for that; it falls out of sharing one number. Details that matter. The kernel defaults to auto-close ON independently of the GUI, so headless and MCP callers behave like the viewport instead of inheriting an unset preference. With the tolerance at 0 the comparisons become <=, because OFF must mean exact, not broken. OCCT never receives a zero vertex tolerance — it is clamped to Precision::Confusion. The preference is pushed from EVERY entry that starts a sketch session, not just begin(): a Constrain session enters through begin_constrain / begin_constrain_entities and uses region_loops and connected_loop, so a single push site would have left those sessions running on whatever the previous one set. begin_imported_transform is excluded deliberately — it works on imported regions, not chained entities. Tests: a loop with one joint open by 9e-4 mm, given out of traversal order, builds a closed four-edge wire; with auto-close off the same loop yields no wire; and an exactly closed loop still builds with auto-close off, proving OFF means exact. Kernel 66104 assertions / 606 cases green. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011FbJKJAJxxkhDTs9XdZzKA |
||
|
|
faf4406f89 |
A wire that lost two edges still called itself done
An extrude built a solid the user never drew: three sides of the handle plus the arc
that bulges outside the outline, with the bowl's second arc and the left edge missing.
Two faults met. entities_to_wires added edges in ENTITY-CREATION order, so a partial
wire rejects the next edge even when the sketch closes perfectly; and one joint of the
reported sketch is open by 2.28e-5 mm, wider than OCCT's 1e-7 vertex tolerance and
wider than this function's own EPS of 1e-6, so that edge was refused on geometry too.
Neither showed up, because BRepLib_MakeWire::Add DROPS a disconnected edge
(BRepLib_DisconnectedWire + NotDone) while every successful Add ends with
BRepLib_WireDone + Done() — overwriting the failure. `if (!wm.IsDone()) return {}`
was therefore asking only whether the LAST edge connected. Six edges in, four out,
IsDone() true.
Endpoints now weld into shared nodes at one tolerance (kSketchWeldTol) used by BOTH
the union-find grouping and the wire build — they disagreed before, which is how a
joint gets united into a loop and then refused by the builder. Each node becomes ONE
TopoDS_Vertex, so the builder matches on identity instead of proximity, with the
vertex tolerance widened because BRepLib_MakeEdge::Init projects a vertex onto the
curve within that tolerance and a welded node sits up to the weld gap off its
neighbour's curve. Members are then walked in traversal order. Finally the result is
counted: IsDone() alone is not evidence, edge_count == members.size() is.
Arc geometry is untouched — the midpoint from (start_angle+end_angle)/2 and the
solver's angle reflow both measured correct and were never part of this.
The regression case carries the reported sketch verbatim, open joint included. It
fails 4 == 6 without the fix, which was measured, not assumed. Kernel 66092
assertions / 604 cases green.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011FbJKJAJxxkhDTs9XdZzKA
|
||
|
|
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 |
||
|
|
b5ead4b29f |
Pull a body's edges into a sketch as construction references
Port of snaporca e635627b81. Parity OK: 17 files identical, 8 diverging at their expected counts. The last reference an industrial sketcher offers that this one did not: Onshape's Use, SolidWorks' Convert Entities. Project already turned a body's 3D edges into 2D Lines, Circles and Arcs on a plane, but the result landed in its OWN feature, so while drawing in one sketch you could not borrow an existing body's edge and constrain to it. No new geometry code: Project's per-edge conversion loop is factored into project_edges_to_entities() and called from a second entry point that appends into an EXISTING sketch with construction = true. The loop appears once now, not twice. Construction is what makes it cheap and safe: SketchEngine already skips construction entities when building wires, so the references guide without being built, and being otherwise ordinary entities every constraint from this epic -- Collinear, EqualRadius, the axis-projected distances, PointOnLine, Symmetric -- works against them for free. Part of this refactors working code, so Project's behaviour identity is the invariant; the existing [CadDocument][project] cases guard it and a new case asserts a Project feature still emits construction == false. project_edges_into_sketch returns the number of entities appended, or -1 on a bad reference rather than throwing. VERIFICATION LIMIT, as with the previous four 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 7700 assertions / 270 cases and ALL LADDERS HELD 7/7. |
||
|
|
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. |
||
|
|
45494c6035 |
The origin and the two axes become things you can constrain to
Port of snaporca 5b1294de59. Parity OK: 17 files identical, 8 diverging at their expected counts. Every industrial sketcher gives you the origin and the axes as references. Here the origin was only a SNAP target and the axes did not exist, so Symmetric needed a third picked ENTITY as its mirror axis: symmetry about the sketch's vertical axis first required drawing a construction line. Every constraint reference resolves through four lambdas in the solver (valid/ptOf/primOf/coordOf), so teaching those about three negative sentinel indices makes the origin and both axes available to EVERY constraint type at once. No new SketchEntity type, no serialization change; -1 still means "unset". The references live in G_FIXED and add no degrees of freedom, which a test asserts via the reported DoF. SymmetricAboutY / SymmetricAboutX are two buttons that need no third pick and no construction line. Making the axes clickable in the viewport is deliberately left out: that is canvas hit-testing work with its own risks. Recorded in the tests because it will catch the next person: sys.dragged[] is populated only during a drag, so a plain sketch_solve of an UNDER-constrained system may move any free parameter -- solvespace runs Newton, it does not minimise movement. PointOnLine onto an axis is one equation in two unknowns and the point legitimately slides along it. Those tests pin the free direction instead of asserting the other coordinate is untouched. VERIFICATION LIMIT, as with the previous two commits: this fork's kernel suite still cannot run (find_package(assimp) fails at configure, snaporca-w80c). The shared sources are byte-identical to snaporca's, where kernel is 2624 assertions / 206 cases and ALL LADDERS HELD across all seven rungs. |
||
|
|
a63bba2d55 |
Horizontal and vertical distance dimensions
Port of snaporca 9fa304c77a. Parity OK: 17 files identical, 8 diverging at their expected counts. The everyday dimension in SolidWorks and Onshape, and this kernel had no form of it. Distance constrains the straight-line gap; LockX/LockY pin one point's ABSOLUTE coordinate. Neither relates two points along an axis. DistanceX/DistanceY emit SLVS_C_PROJ_PT_DISTANCE against two unit direction lines built in the solver's G_FIXED group, so they add no degrees of freedom. THE DIRECTION IS SIGNED, and getting it backwards is silent. libslvs defines a LINE_SEGMENT's direction as point[0] - point[1] (entity.cpp) and PROJ_PT_DISTANCE constrains (pB - pA).dot(dir) (constrainteq.cpp:234), so the reference lines are built head-first to mean +X and +Y. The same signedness was a real defect in the GUI: the inline editor was pre-filled with |delta|, so when the closest endpoint pair ran right-to-left, opening the dimension and accepting the number shown would flip the point to the other side of its anchor. Opening a dimension and accepting its own value must be a no-op. The refs are now ordered so the shown value is positive. On the CAD-1000-hours corpus, dimensioning and constraining is 31.9% of all observed CAD time -- the largest single class, 7.6x feature operations. This is the item in the constraint epic that lands most directly on it. VERIFICATION LIMIT, as with the previous commit: this fork's kernel suite still cannot run (find_package(assimp) fails at configure time, snaporca-w80c). The shared sources are byte-identical to snaporca's, where kernel is 2603 assertions / 200 cases and ALL LADDERS HELD across all seven rungs. |
||
|
|
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.
|
||
|
|
8f014de84c |
Load the CAD recipe from projects saved before it was renamed
The recipe's 3MF entry moved from Metadata/SnapOrca_cad.bin to Metadata/orca_cad.bin, so projects saved by earlier builds opened with an empty Design tab. Both 3MF backends now read either name and write only the new one; the recipe version advances to 6 to mark the move. |
||
|
|
5a170520d3 | refactor: rename SnapOrca references to Orca in CAD components to avoid confusion and update recipe versioning | ||
|
|
3fd5c3353a |
A reference is a reference whatever feature holds it
Port of snaporca 1bb9825db0. Four defects from an independent 20-agent audit, each verified in the code first; two further findings from the same report were verified OUT and are not in this commit. remove_feature()/move_feature() remapped Extrude::sketch_ref and a Mate's two connectors and nothing else, leaving seven of the nine index-bearing fields — sweep_path_ref, loft_profile_refs[], pattern_curve_sketch, rib_sketch_ref, and sketch_ref on Revolve, Sweep, Rib and the Surface* family — pointing at whatever slid into the slot. Quiet by construction: the shifted index still names a real feature, recompute() succeeds, the solid is built from the wrong profile. The comment above the loop already required "EVERY field holding a feature index"; the code under it handled two, because a type switch is only correct on the day it is written. for_each_feature_ref() visits the FIELDS instead, so a feature type added later is covered the moment it reuses one. plane_base and axis_plane_a/b are excluded on purpose and documented at the helper — they encode an ordinal into the datum-plane list, not an index into features[], and are filed separately. The delete cascade got the same field-based treatment. The regression test was run against the pre-fix code to prove it bites: all three sections fail there, and move_feature returns TRUE while leaving sketch_ref == 1 where it must be 0 — success with the wrong answer, which is what makes this class expensive. apply_constraint, commit_entity_constraints and delete_constraint mutated the recipe with no checkpoint() and no sync_recipe_to_model(), alone among seventeen mutation sites in that file: Ctrl+Z reached past the constraint edit and discarded unrelated work, and saving persisted the pre-constraint blob. A rejected constraint now calls abandon_checkpoint() rather than leaving an undo step that does nothing. MCP: params["generation"].get<uint64_t>() sat outside the try inside a bare CallAfter lambda, so one malformed string terminated the process through the wx event loop; it is type-checked now and the lambda lets nothing escape. The socket bound with no mode of its own in a world-writable directory — umask around bind() plus chmod, and it refuses to listen rather than listen wide. The reply write is no longer a bare write(), which could SIGPIPE the app when a client hung up. Kernel suite on this fork: 190 cases / 2562 assertions, green. GUI target compiles. The full ladder gate ran on snaporca (ALL LADDERS HELD — gestures 98/98, offer 108/108, corpus and corpus-scale green) and fork-check parity holds at 17 identical / 8 diverging as expected, which is what makes that gate transferable here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MrMzTpAf78U4NG2M8jfvHY |
||
|
|
6e7f6429fa |
A body carries its own name, because a body is not its first feature
User report 2026-08-23, and it is right: "you have renamed the feature extrusion,
not the body. i clicked rename on the body feature tree and the feature extrude
changed name. this means that you consider the extrusion = the body. this is very
far from truth as a body can contain several extrusions."
That is exactly what the previous commit did. It resolved a selected body to
CadBody::source_feature and renamed THAT feature, on the reasoning that a body has
no name of its own. The reasoning described an implementation detail — CadBody::
name is derived and restamped on every recompute — and mistook it for the user's
model. An Extrude, a Cut and a Fillet all land on the same body: the maker is one
operation in its history, and renaming it renames the wrong object.
A body now has a name of its own. CadBody::user_name, set only by a rename, is:
- carried across recompute() by body index, next to the per-body colour override
and under the same index contract the GUI already relies on for visibility and
Move — without which a name would survive exactly until the next feature;
- written into the recipe, because bodies are recomputed and never serialised, so
a name has nowhere else to live and would otherwise vanish on reopen;
- shown on the Bodies row ahead of the derived maker name, as "Body N — name",
with the number still leading because every status line, the interference
report and the mate errors identify a body that way.
The recipe block is APPENDED after the variables block rather than given a version
bump. A build that predates it reads features and variables, returns, and never
looks at the trailing bytes — so yesterday's projects open here and today's
projects still open there. A bump would have cost every project written today its
readability by the previous build, for one optional field.
Renaming a FEATURE is unchanged. The feature tree renames features; the Bodies
list renames bodies; neither reaches into the other.
WHAT THIS COST, and why it is written down. Getting here took two wrong turns
inside one fix, both mine:
1. UnselectAll() -> Unselect(). Both trees are wxTR_SINGLE, where UnselectAll()
— the MULTI-selection call — does nothing. That was the one-word reason the
rename had been vetoed everywhere (BEGIN_LABEL_EDIT refuses while
tree_body_selection() >= 0). Fixing it turned a pair of harmless no-ops into
a real loop: the two lists clear each other so "the target" is unambiguous,
so clicking a body row ran apply_body_row -> m_tree->Unselect() -> the feature
tree's SEL_CHANGED -> m_parts->Unselect(), which cleared the row just clicked.
The handler now clears the other list only when it actually holds a selection.
2. Trusting a screenshot taken after a polluted run. A leftover Rib card had
shifted the whole panel, so a click measured against it landed nowhere near
the row. Relaunch, then measure.
VERIFIED, on the rig and in the kernel:
body renamed ('Extrude', user_name=False) -> ('Bracket', user_name=True)
features untouched ['Sketch', 'Extrude'] before and after
survives a recompute add a Hole to the same body: features become
['Sketch', 'Extrude', 'Hole'], body stays 'Bracket'
survives the recipe serialize -> deserialize -> 'Bracket'
New kernel test "a body carries its own name, through recompute and the recipe"
pins all three properties; the suite is 189 cases / 2547 assertions.
Gate green: ALL LADDERS HELD — offer table matches the atlas, kernel suite,
engine rungs 1-8, 977-sheet corpus + the heaviest sheets, gesture ladder 98/98,
offer ladder 108/108.
|
||
|
|
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 |
||
|
|
942f6c28c7 |
Port: mirror emits a half that continues the chain
Carries snaporca 0231bd5b68. Parity holds: 17 files identical, 8 diverging as expected. A reflection reverses orientation, so mirror_entities now hands the reflected half back reversed in ORDER and flipped per ENTITY — an arc swapping its angles as well as its ends, a spline reversing its control points. Appending it to the source then yields one walkable chain instead of two halves meeting head-to-head, and a mirrored CCW loop stays CCW. This is the producer half of the confusion that cost three defects; the consumers (offset, and the exact loop area) keep their defensive handling, because that is what makes them correct for hand-built and imported sketches rather than only for geometry this function produced. Contract change, carried with the reason: a mirrored line's p0 is the reflection of the SOURCE's p1, and a mirrored CCW arc keeps a POSITIVE sweep — the reflection negates it, walking it the other way negates it again. Both [SketchEdit] cases updated, and a new [SketchProfile] case "a mirrored half continues the original chain" pins the property directly. Kernel here: all tests passed, 2687 assertions in 232 test cases. GUI target builds and links. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
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> |
||
|
|
2b02a8e3dd |
Design tab: move the CAD sources into their own folder
Review request on PR #15238: "Place CAD-related files (e.g. CadDocument/ GeometryEngine) into a separate folder." src/libslic3r/CAD/ the kernel — CadDocument, GeometryEngine, the four Sketch* units, SketchSolver, ThreadStandards src/slic3r/GUI/CAD/ the tab — DesignPanel, DesignCanvas, DesignSketchTool, SketchInlineEditor, McpControl, generated DesignOffer Pure relocation: no line of logic changes. Two include rewrites follow from it — files that moved re-spell their own neighbours against src/ (already on the include path), and files that did not move pick up the new folder. docs and docs/ux/mockups/gen_offer_table.py follow the same paths. Verified: libslic3r, libslic3r_gui and libslic3r_tests all build, CAD suite green at 2518 assertions in 194 test cases, and the sibling fork builds identically — 17 shared sources still byte-identical, 8 diverging by their expected counts. |