* CLI: --ground-face-* / --lay-flat / --center-on-bed orientation primitives
Adds the CLI counterparts to the GUI's lay-flat / face-pick gizmos.
Scripted / CI / AI pipelines can now set orientation without rendering
a wxWidgets frame; today the only way is a GUI round-trip.
New CLI actions (all operate in the mesh-local frame so they compose
with prior --rotate-* / --orient flags):
--ground-largest-face 1 Auto-detect the largest planar-face
or --lay-flat 1 cluster (area-weighted), rotate so its
normal points -Z. Covers "this part has
one obvious flat side" cases.
--ground-face-normal NX,NY,NZ Pick the face whose mesh-local
normal best matches the given
vector; ground it. e.g.
`--ground-face-normal 1,0,0`
stands a part on its +X side.
--ground-face-point X,Y,Z Find the triangle containing the
given mesh-local point; ground its
face. Disambiguates when several
faces share a normal (largest
containing triangle wins).
--center-on-bed 1 Translate so the XY bounding-box
centroid lands at the bed center
(derived from printable_area).
New file `src/slic3r/Utils/MeshOrient.{hpp,cpp}`:
- collect_triangles_object / compute_face_clusters — quantize
per-triangle normals (0.001, ~0.06°) and area-weighted-average
within clusters. Same clustering logic used by lay-flat.
- apply_ground_rotation — same math as Selection::flattening_rotate
in the GUI (Selection.cpp:1432): world-space quaternion from the
transformed normal to -Z, applied as offset * new_rot * old_no_offset
on every instance of every object, then a per-instance Z-lift so the
grounded face lands at exactly 0 (avoids "No layers were detected"
from FP-error z≈-1e-9).
- ground_face_point uses a top-N cluster search + point-in-triangle
test in local space; largest-area triangle wins on ambiguity.
Rationale: without these, any CLI pipeline that needs a specific
face on the bed must either encode custom rotation math per part or
break out of the pipeline into the GUI. Both are bad for
reproducibility. The --ground-face-* triple + the largest-face
auto-mode cover essentially every orientation intent expressible
in a slicing wizard.
Scope:
- `src/slic3r/Utils/MeshOrient.{hpp,cpp}` — new, ~420 lines
- `src/slic3r/CMakeLists.txt` — 2-line registration
- `src/libslic3r/PrintConfig.cpp` — 5 new CLIMiscConfigDef entries
- `src/OrcaSlicer.cpp` — 58-line handler block + 1 include
No behaviour change when the flags are absent.
(cherry picked from commit c45a9795e1)
* CLI grounding: choose among the Lay on Face planes, per object
Addresses review:
- Move the geometry of GLGizmoFlatten::update_planes() into
libslic3r/LayOnFace and use it from the gizmo and the CLI, so the
--ground-* options pick convex-hull faces per object and instance,
with part transformations (--rotate-x/y) applied.
- Drop --center-on-bed, the --lay-flat alias and MeshOrient; make
--ground-largest-face a coBool.
- Parse --ground-face-normal and --ground-face-point strictly. A point
that only some objects contain grounds those and leaves the others.
- Fold in --inspect-mesh from #14603, reporting the same planes.
- Tests in tests/libslic3r/test_lay_on_face.cpp: bounding boxes before
and after, rotate then ground, two objects, and a ribbed part whose
parallel inner faces outsum its base.
* CLI --inspect-mesh, --ground-face-*: reject missing input and empty values
- Without an input file or --load-assemble-list, --inspect-mesh printed
nothing and exited 0. Reject it up front with CLI_INVALID_PARAMS.
- An explicit empty --ground-face-normal or --ground-face-point was
silently ignored. Only options given on the command line reach the
transforms loop, so an empty value now fails the strict parse like any
other malformed value.
* build: clear 2 warnings - cast the NSTextField the class check already proved
mainframe_text_field is NSTextField* and was assigned a bare NSView*, which
Clang reports as -Wincompatible-pointer-types. Both assignments sit inside
if ([viewObject class] == [NSTextField self]), so the runtime type is already
guaranteed, and the line above the second one casts the same variable the same
way to call setTextColor. macOS only, since nothing else compiles this file.
* build: clear 6 warning categories from the clang-cl inventory
-Wmissing-braces (9). Aggregates whose first member is itself an aggregate.
GUID's fourth member is BYTE[8], so the trailing eight bytes take their own
braces. The others were reaching for zero-initialization with {0} and say {}
now. bbs_3mf's backup Task ends in an anonymous union, which needs braces of
its own; those braces initialize the union's first member rather than the one
named at the call site, so the RemoveBackup site says so in a comment.
-Wmacro-redefined (11). SendMultiMachinePage.hpp defines five names that
Preferences.hpp, PresetBundleDialog.hpp, ExportPresetBundleDialog.hpp and
TroubleshootDialog.hpp also define with different values, so the value in
force depended on include order. All nine of this file's DESIGN_ macros take
the SEND_ prefix it already uses for its own macros, values unchanged, so a
DESIGN_ name added elsewhere later cannot collide with it again. They read as
one page-local palette, a 900 to 400 gray ramp plus sizes, so the four with
no current readers stay: dropping them would leave gaps in a named scale. test_marchingsquares.cpp defines NOMINMAX,
which libslic3r already passes as a PUBLIC compile definition, so it takes
the #ifndef guard the other suites use.
-Wbraced-scalar-init (3). Two PushStyleVar calls resolve to the float
overload, so the braces were initializing a scalar. ConfigOptionFloatsNullable
already takes an initializer_list, so the inner braces did the same thing.
-Wmicrosoft-goto (2). Both gotos in copy_file_gui jump forward over the
initialization of size, dwRead and dwWrite, which only MSVC accepts. Those
declarations move up to join the others at the top of the function.
-Wunused-private-field (3). Every use of ColourPicker's m_clrData and
m_picker_widget is behind !defined(__linux__), so on Linux they are written
and never read; the members now carry the same guard. ParamsPanel's
m_size_move is read nowhere. Tab has its own, which is the one Tab.cpp uses.
-Wnonportable-include-path (2). BaseException.h asked for "stackwalker.h"
and the file on disk is StackWalker.h.
build: clear eleven single-site clang-cl warning categories
Each of these is the last site left in its category, and every one is the
compiler saying it cannot tell what the code meant. Nothing here changes
defined behavior.
- OrcaSlicer_app_msvc.cpp printed a DWORD with %d
- StackWalker.cpp ran delete[] through an LPVOID
- ToolOrdering.cpp used a bare ; as a deliberate skip loop's body
- WipeTower.cpp had finish_block_tcr = finish_block_tcr, so the branch that
reached it did nothing. Folding the condition into the enclosing if leaves
the other branch untouched
- GCodeProcessor.cpp had an else binding to the inner if while the outer if
carried no braces
- AmsMappingPopupUpdate.cpp wrote >= 1 || <= 3 where its own comment says &&
- CalibrationWizardPresetPage.cpp left max_decimal_length unset through a
pair of conditions that cover every value but not visibly so
- DevManager.cpp bound map elements to pair<K, V> rather than
pair<const K, V>, copying every one
- SyncAmsInfoDialog.cpp had extraneous parentheses around a comparison
- Http.cpp had if (speed > 0.01) speed = speed;. speed now starts at 0 as
well, because curl_easy_getinfo leaves the target untouched when it fails
and the value reaches Progress either way
- SnapmakerPrinterAgent.cpp truncated npos into an unsigned int, so the
!= npos guard was always true. A colour with no # still yields 0, because
the wrap produced 0 as well
Nine categories go to zero. -Wtautological-overlap-compare and
-Wsometimes-uninitialized reach zero when #15583 merges their second site.
Orca content-addresses every system filament, Bambu's included, but a printer,
its AMS and its vendor's cloud know only that vendor's own catalog ids. The
printer agent now translates between the two: outbound MQTT and FTP traffic, the
AMS mapping sent with a print job, and the ids written into a 3mf bound for the
printer all leave in the printer's own ids, while status messages, loaded
projects and SD-card prints arrive in Orca's. An id with no mapping passes
through unchanged, and an agent whose printers already speak Orca's ids
translates nothing at all.
Bambu's map is generated from BambuStudio's own shipped bundle; a missing or
unreadable file leaves every lookup an identity rather than taking the app down.
The profile check validates the map's shape, and profile CI now runs on the paths
that can change it. docs/HLSD/filament_id.md records the places the map
deliberately does not reach.
* build: enable /Zc:lambda for MSVC
MSVC keeps its legacy lambda processor under /std:c++17, which rejects
reading a constexpr constant inside a lambda that does not capture it
(C3493). No other compiler requires that capture, and clang reports it as
an unused one, so the two cannot both be satisfied without the flag.
/Zc:lambda selects the conforming lambda parser that clang and GCC
already use. It is implied by /std:c++20 and /permissive-, so it is only
needed while we are on C++17. clang-cl is conforming already and does not
take the flag.
It requires VS2019 16.8, so build_release_vs.bat now says 16.8+.
* build: clear 237 unused lambda capture warnings
236 captures across 81 files, 142 of them `this`. Removing an unused
capture changes no behavior; clang does not report a capture whose type
has a non-trivial destructor, so nothing held only to extend an object's
lifetime is in this set.
Nine of them are the second half of the warning, "is not required to be
captured for this use", where the capture is a const or constexpr value
the body does read. Those depend on the /Zc:lambda change in the previous
commit. One of them, in FillRectilinear.cpp, had been worked around with
an #ifndef __APPLE__ guard around the capture list, which is now gone.
GUI_ObjectTableSettings.cpp captured its reset button only to read it
inside #ifdef __WXOSX_MAC__. That branch now takes the button from the
event it is already handling.
* build: fail configure on MSVC older than 19.28 instead of dropping /Zc:lambda
cl.exe answers an unrecognized /Zc: sub-option with warning D9002 and keeps
going, so on VS2019 before 16.8 the flag is silently ignored and the build
instead dies with C3493 in FillRectilinear.cpp, nowhere near the cause.
* fix: delete three locals that are now unused
Their only remaining use was the lambda capture this branch removed. The
Clang builds set -Wno-unused-variable, so the build never flagged them.
---------
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>