- Add BeltBackTransform class that inverts the shear/scale matrix and
applies it in GCodeWriter::to_machine_coords() so G-code outputs in
the machine's physical coordinate space, gated by new
belt_gcode_back_transform config option
- Extend belt floor clipping to all three tree support pipelines
(Prusa-style, Orca organic, TreeModelVolumes) with per-layer polygon
clipping, anti-overhang integration, and belt raft extension layers
- Fix tree drop_nodes() belt termination, organic support global Z
offset, collision calculation index bug, and first-layer brim/empty
layer checks for belt printers
two-shot - first build built but didn't plumb to UI. Woah.
add pre-slice axis remap, because Y needs to be Z
going to change tactic and move based on bbox min
switch to per axis snapping
per axis swap snap now per object
build plate tilt wasn't invalidating slicer settings
support upper bound now correct, need to get lower bound corrected
axis swapped support termination corrected
Z Shear works with and without pre-slice remap now
- Fix support clipping z-shift calculation by removing coordinate-space
mismatch and sync belt_floor_z_shift with global_z_offset; fix
invalidation so posSupportMaterial no longer resets slicing params
- Add belt floor polygon clipping to non-organic tree support
(slim/strong/hybrid) with collision surface integration in
TreeSupportData, belt extension layers, and first-layer brim
suppression
- Add belt floor clipping to organic tree support pipeline with virtual
belt raft layers, per-layer polygons in TreeModelVolumes, and
post-generation layer trimming; fix pre-existing processing_last_mesh
bug in calculateCollision()
Fix belt floor support clipping: z-shift, invalidation, and global offset
- Fix support clipping z-shift calculation by removing coordinate-space
mismatch (raw_bounding_box min.z vs trafo_centered m_belt_min_z) and
sync belt_floor_z_shift with global_z_offset in global shear mode
- Fix invalidation so posSupportMaterial no longer resets slicing params,
preventing the exact posSlice z-shift from being overwritten by the
bounding-box approximation on support-only setting changes
- Remove double-counting of global z_offset on support layers — support
already inherits the offset from object layers during generation
This Work Was Co-Authored-By Claude Opus 4.6 (1M context) <noreply@anthropic.com>
UI: gray out inactive belt sub-options, rename to mesh transforms, move to Advanced
Fix mesh clipping through build plate after belt shear/scale transform
Generalize G-code viewer designed-view toggle for full belt transform
Clip support layers to transformed belt floor plane
Supports below the tilted build plate (Z = shear_factor * from_axis - min_z)
are now clipped via half-plane intersection after generation. Belt floor
parameters stored in SlicingParameters and populated in both update_slicing_parameters()
and the static slicing_parameters() overload.
Make belt G-code viewer toggle more prominent, add B keyboard shortcut
- Add separator + teal "Belt Printer" header in legend panel
- Append [B] hint to checkbox label
- Add B key shortcut in GLCanvas3D to toggle designed/machine view
- Read belt_printer_angle from loaded G-code headers to enable belt view
Add per-axis global transform option for belt printer shear
New belt_shear_{x,y,z}_global bool configs. When enabled, shear incorporates
instance shift so objects at different bed positions get position-aware
transform (Z += factor * instance_shift_on_from_axis).
Fix global shear: use layer Z offset instead of mesh transform, add config invalidation
- Global shear offset applied as post-slicing layer print_z adjustment
instead of mesh transform (which was absorbed by min_z normalization
or shifted mesh out of slice range)
- Register all belt transform options in Print::invalidate_state_by_config_options
to trigger posSlice re-slicing (the fallback only invalidated Print steps,
not PrintObject steps — belt changes had no effect without manual re-slice)
- Belt gcode remap options added to steps_gcode (gcode-export only)
- Skip empty-first-layer check for belt objects with global Z offset
WIP: split instances for global shear, relative Z offsets, debug logging
- PrintApply: when belt global mode active, prevent instance grouping by
adding unique Z perturbation to trafo — each copy becomes its own
PrintObject with independent layers
- PrintObjectSlice: compute global Z offset relative to minimum Y shift
across all PrintObjects (lowest-Y object stays at Z=0)
- Debug logging (warning level) for belt global shift values and offsets
Known issues:
- Cached posSlice results cause stale offsets when mixing copies with
individually-added objects — need to compute min baseline outside slice()
- Supports still generate to Z=0 instead of object's global Z offset
Fix global shear for copied objects: disable shared-object layer optimization
When belt global Z shear is active, each object needs unique layer Z
values based on its bed position. The shared-object optimization was
causing copies to reuse the source object's layers (and its Z offset)
instead of computing their own position-based offset.
started work on getting supports to work properly
one step forward, one step back
this version didn't quite work. Getting somewhere though
about to add UI controllable tests
added configuration options for supports
tweak CLAUDE.md to be more aggressive for my machine. This commit should probably be pulled out before contributing upstream
still chasing down some bugs
moving objects between slices no longer results in improper Z-height because of caching
added more data to the debug logs
Z offset is getting more global again
still not quite there, I think there's a fundamental logic flaw?
hunting for bugs
finally have a functional fix
Add belt floor clipping to tree supports (organic and non-organic)
- Add belt floor polygon clipping to non-organic tree support
(slim/strong/hybrid) in draw_circles() and terminate nodes at the
belt surface instead of the horizontal build plate
- Add belt floor clipping to organic tree support pipeline with virtual
belt raft layers for sub-floor branch generation, per-layer belt
floor polygons in TreeModelVolumes, and post-generation layer trimming
- Fix pre-existing processing_last_mesh bug in TreeModelVolumes that
prevented m_anti_overhang (support blockers) from ever being applied;
skip empty first layer check for belt printers
Commits:
current approach: make a face surface to build supports to
closer!
supports now terminate on shear plane, now need to get shear plane to correct Z height
nearly there
chasing down logic issues still
committing for checkpoint, this still does not work
still got logic problems...
cull support clipping
stashing changes for now. Going to focus on getting the global shear OFF support generation dialed first.
beginning per object shear calcs
Local shear transform is on correct Z offset now
local shear finally works now and needs more testing
global shear works now, needs thorough testing
debugging non-45 degree angles
debugging part 2
supports at all angles work now
remove debug logging
Add belt floor collision to non-organic tree support pipeline
- Integrate belt floor as a collision surface in TreeSupportData so
branches route around the belt naturally, replacing the explicit
termination checks in drop_nodes()
- Add belt extension layers below the object after draw_circles() to
allow support geometry to extend to the diagonal belt surface instead
of terminating at a horizontal first layer
- Fix coordinate overflow in belt floor polygons (scale_(1e4) exceeds
int32), skip first-layer brim expansion for belt printers, and
extend empty first layer check bypass to all belt modes
add debug logging, Z translate for tree supports
still not seeing any cutoff surface yet
adding debug options
attempt #2 at trees
if hit Z buildplate stop but don't set to_buildplate true
getting closer
tree support almost there, just need to get rid of the circles at the beginning
getting closer
belt / shear plane clip works, need to figure out the buidlplate plane issues
more logic, added debugging logs
supports now extend somewhat below Z=0 in global shear mode
fix bad alloc, add 10mm below build plate
fully works now
shear transform + prusa tree support generation works now.
pull out debug logging
- Implement per-object global shear transform in PrintObject with
layer Z-offset calculation, config invalidation, and fix for
shared-object layer optimization breaking copied objects
- Clip support layers to the transformed belt floor plane and begin
work on tree support adaptation for sheared coordinate space
- Improve belt UI: gray out inactive sub-options, add B keyboard
shortcut for G-code viewer design-view toggle, fix mesh clipping
through build plate after shear/scale transform
y' = y + z·cot(α),
while x' = x and z' = z
getting closer to customizable variant
getting closer
X/Y/Z shear initial
clean up UI
add 1/sin(a) transform, idea taken from blackbelt cura plugin
Things work now (turns out I've been using the wrong set of transforms)
- Replace monolithic belt rotation transform with independent per-axis
shear controls (mode/angle/source-axis for X, Y, Z) and G-code axis
remapping, giving full flexibility to match any belt printer's
coordinate system
- Remove all rotation mode logic and intermediate type+axes dropdowns,
simplifying the pipeline to pure shear matrices while preserving the
default behavior (Y += Z*cot(45deg) with identity remap)
- Clean up GCodeWriter, GCodeProcessor, and GCodeViewer for the new
shear-only model; expose 12 new settings in printer UI via
Tab.cpp/Preset.cpp
Implement belt printer tilted slicing
Implement the core belt slicing pipeline that makes the slicer
tilt-aware:
Step 1: GCodeWriter::to_machine_coords() - R(+alpha, X) rotation
from slicing frame to machine frame
Step 2: PrintObject - belt-rotated object height calculation
(y*sin(a) + z*cos(a)) for correct layer count
Step 3: PrintObjectSlice - apply R(-alpha, X) rotation trafo so
horizontal slice planes correspond to belt-parallel planes,
with Z-shift computed from model volumes
Step 4: GCodeProcessor - machine-frame preview (no transform needed)
Step 5: 3DBed - rotate bed visualization about X by belt angle
Fix: belt surface IS the build plate, no mesh rotation
Currently still slicing perpendicular to the belt normal. Need to figure out why.
Fix G-code Z sign: use R(-alpha, X) so Z+ is away from belt
The previous R(+alpha, X) transform produced negative Z values
(-y*sin(a) term dominated). Changed to R(-alpha, X) which gives
machine_z = y*sin(a) + z*cos(a), always positive for points
above the belt surface. Z increases with each layer as expected.
reverting and changing slice methodology
Add pink slicing direction arrow from origin
Shows the effective slicing direction (gantry normal) as a pink
arrow from the origin. Shorter and wider than the gravity arrow.
Direction: R(+alpha, X) * Z = (0, -sin(a), cos(a)), which is
the layer stacking direction in the original mesh frame.
Fix slicing arrow visibility and add raw G-code toggle
- Disable depth test for pink slicing arrow so it renders on top of
the tilted bed geometry (was being occluded)
- Remove unnecessary 5mm Z-offset from arrow position
- Add m_belt_show_raw toggle to GCodeViewer
- Add "Show raw G-code (slicing frame)" checkbox in legend when
belt mode is active
Implement to_machine_coords inverse rotation for belt printer G-code
The slicing pipeline rotates the mesh by R(-alpha, X) and shifts Z to
start at 0. The G-code output now undoes this transform via
to_machine_coords: R(+alpha, X) * T(0,0,+z_shift), recovering the
original machine-frame coordinates where Y is horizontal and Z is
vertical.
Changes:
- GCodeWriter: implement to_machine_coords with inverse rotation + Z-shift
- GCodeWriter: add belt_z_shift member and setter/getter
- GCode.cpp: compute Z-shift from print objects (same logic as
PrintObjectSlice) and pass to writer; write z_shift to G-code header
- GCodeProcessor: parse belt_z_shift from G-code header
- GCodeViewer: store belt_z_shift from processor result
Wire raw G-code toggle to apply slicing-frame view transform
When "Show raw G-code (slicing frame)" is checked in the preview
legend, the view matrix is modified to apply R(-alpha, X) * T(0,0,-z_shift)
to the toolpath rendering. This shows the G-code as it was during
slicing: rotated part with horizontal layers.
Default (unchecked): machine-frame view — upright part with tilted layers.
Remove belt printer placeholder comment from GCodeProcessor
The preview now correctly displays machine-frame G-code with the
optional raw view toggle. No transform is needed in the processor.
- Implement core belt slicing pipeline: R(-alpha, X) mesh rotation in PrintObjectSlice with corrected object height calculation for proper layer count
Add to_machine_coords() in GCodeWriter to convert slicing-frame coordinates back to machine-frame, propagated through GCode,
GCodeProcessor, and GCodeViewer
Add belt-mode UI: tilted bed visualization, slicing-direction arrow, and raw G-code toggle to switch between machine-frame and slicing-frame views
This is a combination of 6 commits.
checkpoint 1: initial MVP. Slicing functions, but rotates instead of skews are happening and a lot of other stuff too
getting somewhere, getting to the point where I need to figure out how to verify this stuff
this appears to be a dead end.
getting somewhere I think maybe
I'm pretty sure we've completely lost the plot at this point and need to restart this process...
remove slice logic in preparation for new, more invasive plan
* Fix crash-inconsistent draft shield
* Skip empty skirt G-code and fix skirt_done handling
Track whether a skirt was actually generated for the current print Z and avoid appending empty skirt G-code. Only pop m_skirt_done when a skirt was emitted to prevent corrupting skirt state across multiple instances per layer. Also use a temporary string (moved into the main gcode) to detect emptiness before updating state. Preserves existing first-layer clearing behavior.
* Union ex brims
Revert "Union ex brims"
This reverts commit bbc9a39faf318dc2df093eb2bdcebf19a4162fe9.
Update Brim.cpp
* dont repeat paths
* Update Brim.cpp
* multimaterial brim independiente
* Normal brim if is by object
* fix print order
* cleaning 1
* cleaning 2
* Normal brim if multimaterial on first layer
* fix artifact
* combine_brim optional
refactoring
* refactoring gcode.cpp
* refactoring brim.cpp
Update Brim.cpp
* Remove multimaterial first-layer check for brims
Stop detecting extruders used on the first layer and remove the is_multimaterial_first_layer guard. Simplify can_combine_brims to only consider combine_brims and whether printing is ByObject, allowing brims to be combined across extruders unless printing by object or combine_brims is disabled. Cleans up unused code and simplifies brim-generation conditions.
* Remove material specification from unified brim comment
* Update PrintConfig.cpp
* Fix return from assembly linux
* Tie deferred callback to canvas lifetime and add shutdown guards
Use m_canvas->CallAfter instead of wxGetApp().CallAfter to ensure the callback is only executed if the canvas is still alive.
Add early returns if wxGetApp().is_closing() is true before accessing plater or the 3D canvas, reducing the risk of use-after-free during application shutdown.
Addresses feedback regarding potential UI teardown race conditions.
* copilot suggestion
* Use local reference to wxGetApp() in Return button callback
Replace multiple calls to wxGetApp() with a single local reference
to improve readability and avoid redundant function calls.
* Don't assume 0.4mm nozzle; format as "unknown" if not defined.
* Skip nozzle diameter and hardness checks if nozzle info unknown.
---------
Co-authored-by: SoftFever <softfeverever@gmail.com>
# Description
The Qidi Max 4 and Q2 don't report what they are via /server/info like
the other Qidi printers apparently do. This means that filament matching
is a fool's erand because you'll never actually match anything. this
adds a fallback where we just use the configured machine type. I'm not
sure why we wouldn't just do that all the time, but I wanted to change
as little as possible.
Here's the entirety of the `/server/info` output from a Qidi Max 4:
```
{
"result": {
"klippy_connected": true,
"klippy_state": "ready",
"components": [
"secrets",
"template",
"klippy_connection",
"jsonrpc",
"internal_transport",
"application",
"websockets",
"database",
"dbus_manager",
"file_manager",
"authorization",
"klippy_apis",
"shell_command",
"machine",
"data_store",
"proc_stats",
"job_state",
"job_queue",
"history",
"http_client",
"announcements",
"webcam",
"extensions",
"octoprint_compat",
"timelapse",
"frp_manager",
"mqtt"
],
"failed_components": [],
"registered_directories": [
"config",
"logs",
"gcodes",
"timelapse",
"timelapse_frames",
"config_examples",
"docs"
],
"warnings": [],
"websocket_count": 3,
"moonraker_version": "?",
"missing_klippy_requirements": [],
"api_version": [
1,
4,
0
],
"api_version_string": "1.4.0"
}
}
```
There's no machine name or hostname. This is also what the response
looks like from a Q2, including the exact same API version numbers, so
we cannot match on that either.
In GLCanvas3D::on_mouse, avoid calling SetFocus when the currently focused window is a text input control (wxTextCtrl, wxComboBox or wxSpinCtrl). This prevents deselection bugs when the mouse leaves the window while a text control is focused. Also commented out explicit wx text-control includes near the top of the file.
Only TextCtrl needed
cleaning
Removed unused wxWidgets header includes.
Update GLCanvas3D.cpp
Co-authored-by: yw4z <yw4z@outlook.com>
Co-authored-by: yw4z <ywsyildiz@gmail.com>
The Qidi Max 4 doesn't report that it's a Qidi Max 4 via /server/info
like the other Qidi printers apparently do. This means that filament
matching is a fool's erand because you'll never actually match anything.
this adds a fallback where we just use the configured machine type. I'm
not sure why we wouldn't just do that all the time, but I wanted to
change as little as possible.
Fix: generic locale fallback on all platforms when language is unavailable
Move the locale fallback chain out of the #ifdef __linux__ block so it
applies on macOS and Windows too. Add a base-language fallback step that
strips the region code (e.g. en_IL -> en) before trying the full
fallback chain (current locale, system, best, en_US, en_UK).
Previously, if wxLocale::IsAvailable() failed on non-Linux, the app
would show an error and exit. Now it gracefully falls back to a working
locale.
Co-authored-by: SoftFever <softfeverever@gmail.com>
Commit ed88cbe removed `new WebViewWebKit` on macOS because wx 3.3
dropped the no-arg wxWebViewWebKit constructor, falling through to
wxWebView::New(). That bypassed the WebViewWebKit destructor that calls
RemoveScriptMessageHandler("wx"), reintroducing the WebKit teardown bug
the subclass was added to fix.
Restore the macOS-specific subclass path by adding a constructor that
forwards to the wx 3.3 wxWebViewConfiguration-based ctor.
wxWidgets 3.3.2 changed MSWGetStyle to add WS_CAPTION when
wxMINIMIZE_BOX/wxMAXIMIZE_BOX/wxCLOSE_BOX is set. This caused
DefWindowProc to subtract the caption height in WM_NCCALCSIZE for
maximized windows, shrinking the client area and creating a gap
above the taskbar.
Fix by handling WM_NCCALCSIZE for the maximized case explicitly
(strip only border overshoot, not caption) and removing the now
unnecessary wxEVT_MAXIMIZE workaround.