Compare commits

..

83 Commits

Author SHA1 Message Date
SoftFever
d8369e5f75 Fix faint toolbar icons on Wayland (#13723)
Use glBlendFuncSeparate in GLTexture::render_sub_texture so destination
  alpha stays at 1.0. The Wayland compositor honors framebuffer alpha for     window compositing; the previous straight-alpha blend reduced dst alpha
  at anti-aliased icon edges, making them semi-transparent against the
  desktop. RGB blending is unchanged, so X11/Windows/macOS are unaffected.
2026-05-19 01:38:37 +08:00
SoftFever
88b4a63228 Fix Linux data-view dropdown popup parenting (#13721)
Delay opening the object-list filament dropdown on wxGTK until the editor
  window is mapped, avoiding popup creation without a valid native toplevel.
  Also set the GTK transient parent for dropdown popups created from data-view
  cell editors.
2026-05-19 01:01:53 +08:00
yw4z
dc12126b78 Fix 2 Linux assertation errors on gtk_window_resize() (#13718)
Update DropDown.cpp
2026-05-18 19:01:42 +03:00
yw4z
054a173af7 Fix possible crash on startup because of low max volumetric speed on profiles (#13716)
* Update fdm_filament_common.json

* update

* Update fdm_filament_common.json
2026-05-18 19:00:48 +03:00
Kappa971
248a55abd0 Update Italian translation (#13674) 2026-05-18 10:29:38 -03:00
yw4z
b4aa070c40 MultiChooseDialog & CheckList class & improvements for Profile Dependencies (#9971)
* init

* fix

* fix

* update

* update

* update

* Update Tab.cpp

* Update CheckList.cpp
2026-05-18 19:46:47 +08:00
Thomas Henauer
b9ff15054f Fix wxGTK submenu popup parenting and sizing on Wayland (#13707) 2026-05-18 18:01:19 +08:00
CSLRDoesntGameDev
ddeaa4ba82 Add patches to the Anycubic Kobra X machine json (#13677)
add patched anycubic kobra x machine json

Co-authored-by: SoftFever <softfeverever@gmail.com>
2026-05-18 16:57:24 +08:00
Ian Chua
b333b04815 log: add logs surrounding logout to potentially catch any unwanted logouts or errors (#13713)
# Description

Currently, there is some suspicious behavior going on with the logout
flow, adding some logs to potentially catch any unwanted logouts or
unintentional behaviors.


[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
2026-05-18 16:39:59 +08:00
Ioannis Giannakas
e5ca01ba9e Fix per-volume "Only one wall" overrides being ignored on assembly parts (#13714) 2026-05-18 09:24:28 +01:00
Ian Chua
6a06b63d6f add logs to http_get/post/put/delete 2026-05-18 16:12:03 +08:00
Ian Chua
d0701b9597 Merge branch 'main' into fix/network-logs 2026-05-18 15:41:50 +08:00
Ian Chua
232fc30db1 log: add logs surrounding logout to potentially catch any unwanted logouts or errors 2026-05-18 15:18:31 +08:00
yw4z
f0392ab226 Show filament edit button or action menu dynamically depends on single / multi materilal usage (#12651)
* init

* fix build error

* add guards

* Update Plater.cpp
2026-05-18 13:59:22 +08:00
Hanno Witzleb
3ca7c4b752 Unify Tool UI Footer (#12850)
* unify footer
adds "Done" Buttons,
standardize "Reset" Buttons,
adds disabled logic to "Reset" Buttons

* adds ImGuiWrapper::COL_WARNING = ColorRGB:Warning,
replaces ColorRGB::Warning

* consistently display warnings,
moves assermbly warning after footer,
make cut warnings warning color

* adds separator above cut warnings

* adds tooltip entry in move, rotate & scale for auto-drop

* use wrapper tooltip in wrapper->button for consistent text color

* restructures brim ears button,
renames "Reset" button in painting tools to "Erase All",
small styling fixes

* small adjustments,
moves "Edge detection" checkbox in painting tool underneath,
moves "Section View" in Brim ears tool after buttons,
moves warnings in Assemble tool under footer

* small brim ear tool structure changes,
adds separator between "Head Diameter" and "Max angle",
adds tooltip to "Auto-generate" button,
rewords shortcut descriptions to match other tools

---------

Co-authored-by: Hanno Witzleb <hannowitzleb@gmail.com>
2026-05-18 12:58:58 +08:00
Hanno Witzleb
15451c6c50 Feature: Multiple dovetail cuts (#12318)
* adds UI and preview plane for multiple dovetail cuts

* adds multiple dovetail cuts to perform_with_groove()

* adds ui text info for spacing, adjusts max_val for gap to respect plate dimensions

* adds spacing before multpile UI

* adjusts wording, adjust gap max by count

---------

Co-authored-by: Hanno Witzleb <hannowitzleb@gmail.com>
Co-authored-by: SoftFever <softfeverever@gmail.com>
2026-05-18 12:57:48 +08:00
r3dbaba
1447602d43 Add ability to assign None/Pan/Rotate to mouse buttons (#10736)
* Add logic to handle the left, middle and right buttons being assigned to do nothing, pan or rotate

* Add entries for setting the drag actions to preferences

* Allow the label text in preferences to wrap

* Show mouse mappings in Help -> Keyboard Shortcuts

* Re-add preferences in updated layout

* Add camera mouse options under camera

* Change mouse action strings to use L() for localization

* Display "None" when it is selected instead of blank in keyboard shortcuts

---------

Co-authored-by: Rob O <robertolabode@gmail.com>
Co-authored-by: Noisyfox <timemanager.rick@gmail.com>
2026-05-18 08:54:21 +08:00
yw4z
6cf7db1ded Match titlebar font on Linux (#12828)
* Update BBLTopbar.cpp

* Update BBLTopbar.cpp

* Update BBLTopbar.cpp

* Update BBLTopbar.cpp
2026-05-18 00:43:22 +03:00
Ioannis Giannakas
d52d0a082d Option to always travel to wipe tower before Tx commands on multi-toolhead setups using type 2 tower (#13703)
* Option to always travel to wipe tower before Tx commands on multi-toolhead setups using type 2 tower
2026-05-17 20:46:08 +01:00
SoftFever
484ce81e38 Fix sidebar filament count for multi-extruder printers (#13706)
load_selections() and update_selections() size the parallel project_config
arrays (filament_colour, filament_colour_type, filament_map) off
filament_presets.size(). When the saved list is shorter than the printer's
nozzle count — never-used printer, hand-trimmed conf, or fewer filament_NN
entries than nozzles — the loaded colors get truncated and the sidebar
starts up one combo short.
2026-05-18 01:18:09 +08:00
Matthew Nickerson
bcbc581417 fix: harden CLI export without OpenGL thumbnails (#13532)
## Summary
- skip CLI thumbnail generation when an OpenGL/GLFW context cannot be
created, allowing export workflows to continue in headless/automation
environments
- guard filament variant remapping against missing config options and
out-of-range variant indexes
- log warnings instead of dereferencing invalid config state during
CLI/profile-driven export

## Context
These guards came out of automating OrcaSlicer CLI exports for printer
workflows. In that flow, slicing/export can still be valid even when
thumbnail rendering is unavailable, but the current path can proceed
into OpenGL thumbnail setup after context creation fails. Separately,
malformed or mismatched filament/profile state can index past option
vectors during multi-filament value remapping.

## Test plan
- `git diff --check`
- `cmake --build build/arm64 --config RelWithDebInfo --target OrcaSlicer
-- -j4`
2026-05-17 20:10:39 +08:00
Noisyfox
c965b2a5b3 Fix macOS object-list filament editor crash/glitch (#13700)
# Description

Fixes a macOS object-list filament editor crash/glitch where the
filament column could enter Cocoa native text editing and expose
`wxCustomRendererObject: 0x...` or crash while committing an invalid
`DataViewBitmapText` value.

The visible `wxCustomRendererObject` glitch was observed on macOS
through Cocoa `wxDataViewCtrl` editing. The underlying unsafe
assignment/variant/editor assumptions are not inherently macOS-only, so
the defensive data-path fixes are cross-platform.

Changes:
- Adds an explicit `DataViewBitmapText` assignment operator that avoids
copying the `wxObject` base, matching the existing copy constructor.
- Rejects unexpected variant types before reading object-list
name/filament values as `DataViewBitmapText`.
- Hardens filament editor value extraction against unexpected editor
controls.
- On macOS, routes filament-column editing through the custom
bitmap-choice renderer instead of `wxDataViewCtrl::EditItem()`, avoiding
native text editing of `wxCustomRendererObject`.



Fixes https://github.com/OrcaSlicer/OrcaSlicer/issues/13682

Previous PR with conversation:
[#13684](https://github.com/OrcaSlicer/OrcaSlicer/pull/13684)

This should fix the crash observed by @Noisyfox as we're addressing the
underlying problem of presenting the `wxCustomRendererObject`.

## Tests

Validated on macOS arm64. Repeated double-click/edit attempts on an
unselected object's filament cell no longer show
`wxCustomRendererObject` and no crash reproduced.

<!--
> A guide for users on how to download the artifacts from this PR.
-->

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
2026-05-17 19:48:12 +08:00
TheLegendTubaGuy
da5a13a032 Fix DataViewBitmapText assignment 2026-05-17 02:29:39 -05:00
Noisyfox
1c0d0b89cc Keep painting after cut (#13472)
[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)


This can be enabled in Preference->Developer->Keep painted feature after
mesh change.

<img width="731" height="633" alt="init"
src="https://github.com/user-attachments/assets/8b195486-538e-4eda-9e77-bfdf1a794306"
/>


TODO:
- [ ] Bug fixes
- [ ] Make it faster
- Keep painting after other mesh operations such as reload from
disk/simplify/boolean operation etc:
  - [x] Planar cut
  - [x] Dovetail cut
  - [x] Cut with part assigned to other side
  - [x] Split to parts
  - [x] Split to objects
  - [x] Mesh boolean gizmo
  - [x] Mesh boolean in right click
- [x] Reload from disk/replace stl (won't work well if mesh changed too
much)
  - [x] Fix model
- [x] Simplify/smooth (this two won't work well due to too much mesh
changes)
- [x] Add options in settings since I think this will be experimental
for a long time until being tested by a lot of ppl
2026-05-17 14:38:37 +08:00
Ian Bassi
873d0ed26e Graphics Preferences: Anti-aliasing + FPS (#13538)
* Expose Antialiasing velues

Expose Antialiasing multipliers.
Default to 4 as current implementation but enables the user to disable it to improve performante or increase sampling to improve quality.

* FXAA

* Improve descriptions

* Require restart when MSAA setting changes

Detect changes to the OpenGL MSAA (multisample anti-aliasing) preference when opening Preferences and prompt the user to restart the application to apply the change. Adds a constant key for the MSAA setting, stores the previous value, checks for changes (similar to the existing FXAA handling), and shows a warning dialog explaining the restart will close the current project without saving. If the user accepts, recreate_GUI is invoked to apply the MSAA change immediately.

* Revert "Require restart when MSAA setting changes"

This reverts commit dde134d346c3849598c91d025d2faed1b51c8a22.

* Menu and FPS options

* Fix FPS limiter and remove VSYNC

* Grouped FPS settings and mode up rigth fps counter

---------

Co-authored-by: Noisyfox <timemanager.rick@gmail.com>
2026-05-17 13:31:51 +08:00
Rodrigo Faselli
b3fe733bf2 Fix Build (#13694) 2026-05-16 12:56:00 -03:00
SoftFever
a0e1aa2507 update agents.md 2026-05-16 22:22:06 +08:00
yw4z
95b23cea0f [Linux] Fix scrollbar appears while 1 filament exist on filament area (#13363)
init
2026-05-16 22:10:17 +08:00
packerlschupfer
f760f4e462 Fix Flow Ratio dialog shrinking after main window minimize (#13545)
FlowRateCalibrationDialog was missing the SetSizeHints call that every
other calibration dialog in calib_dlg.cpp uses (Cornering, Pa, Pa Pattern,
Max Volumetric Speed, Temperature, Retraction, VFA, Input Shaping). Without
it, the dialog has no enforced minimum size: on wxGTK, iconizing the main
window while the dialog is open triggers a layout/refresh that re-runs
Fit() with transient zero-sized children, collapsing the dialog to ~222x249
px with the OK button clipped and unreachable. The window manager then
honors the (incorrect) small geometry hint, so the user cannot resize it
back manually.

Two changes:

* Add v_sizer->SetSizeHints(this) after Fit() in the constructor, matching
  the pattern used by all other dialogs in this file. This locks in the
  correct minimum the first time Fit() runs, before any iconize event.

* Remove the redundant Fit() from on_dpi_changed. With SetSizeHints in
  place the WM enforces the minimum, but the unconditional Fit() on every
  DPI/refresh signal was the trigger for the shrink path; Refresh() alone
  is sufficient here.

Co-authored-by: Packerlschupfer <packerl@schupfer.at>
2026-05-16 21:29:01 +08:00
Ian Bassi
9ec2fe3c45 Add tooltips to Transfer buttons (#13535)
* Add tooltips to Transfer buttons

Set contextual tooltips for the Discard, Transfer and Save buttons when a dependent preset is present. The code computes the previous and new profile names and provides localized explanatory tooltips that clarify that switching will discard changes, transfer "New Value" settings, or save changes into the current profile. This improves UX by making the consequences of each action explicit.

* added some endlines

Co-Authored-By: yw4z <yw4z@outlook.com>

---------

Co-authored-by: yw4z <yw4z@outlook.com>
2026-05-16 21:28:15 +08:00
Andrei
a0717853df Reduce warnings stemming from libslic3r/Config.hpp (#13533)
https://github.com/prusa3d/PrusaSlicer/pull/15106
2026-05-16 21:16:57 +08:00
gaaat98
82cedc0316 Improved SnapmakerPrinterAgent filament sync (#13265)
* Improved SnapmakerPrinterAgent filament sync

* Update src/slic3r/Utils/SnapmakerPrinterAgent.cpp

Fixed missing assignment

* fixed issues

---------
2026-05-16 20:04:10 +08:00
Kevin J. Lynagh
8dd1dd8921 Fix filament syncing by fixing nozzle diameter guards (#13330)
* Remove unused `get_printer_preset` calls.

* `Plater::check_printer_initialized` should skip nozzle flow type checks if nozzle is unknown.

Also remove unnecessary `is_multi_extruders` check.

* Remove unused `CalibUtils::is_same_nozzle_diameters()` fn.

* Simplify `CalibUtils::check_printable_status_before_cali`.

The single-arity can delegate to the vectorized arity.

* Add `DevExtruderSystem::NozzleDiameterMatchesOrUnknown` to simply checks.

* Update `CalibrationPresetPage::update_sync_button_status()` to use `NozzleDiameterMatchesOrUnknown`.

Simplify logic by iterating over each extruder and checking for diameter and volume type match.

The previous code had several mistakes (from what I could tell):

- `curr_obj->is_multi_extruders()` doesn't imply exactly 2 extruders
- the single/multi branch served no purpose
- the single branch failed to check the volume type

* Specify `std::fabs` and add explicit import.

Ref: https://github.com/OrcaSlicer/OrcaSlicer/pull/13330#discussion_r3133613736

Not sure how idiomatic this is in C++ / OrcaSlicer codebase, but CoPilot suggested it and it seems reasonable.

---------

Co-authored-by: SoftFever <softfeverever@gmail.com>
2026-05-16 19:13:40 +08:00
anjis
427d0f7a9f Support file uploads and the device details page for Elegoo Centauri Carbon 2 (#13212)
* Support file uploads and the device details page for CC2 printers.

* Resolved build issues for Linux and macOS.

* 1. Added `ElegooPrinterWebViewHandler` to handle WebUI messages for Elegoo printers. Other printers will keep the current behavior.
2. Added a static `get_print_host_webui` method in `PrintHost` to retrieve the printer WebUI URL.

* Improved timeout handling for CC2 file upload and SN info APIs.

---------

Co-authored-by: SoftFever <softfeverever@gmail.com>
2026-05-16 15:22:31 +08:00
gedanke
5a136a25d1 perf: speed up startup and show progress in splash screen (#13667)
* perf: speed up startup and show progress in splash screen

Cold-start was ~15 s. Profiled in GUI_App::on_init_inner: 5 s in
preset_bundle->load_presets (sequential vendor loading of ~3000 JSON
profile files), 3.7 s in new MainFrame(), and a 1.5 s splash screen
that closed long before init finished — so the user stared at a
frozen blank screen for several seconds with no feedback.

Changes:

- PresetBundle::load_system_presets_from_json: parallelize vendor
  loading with TBB. ORCA_FILAMENT_LIBRARY is loaded first
  synchronously (it is the inheritance base for filaments); the
  remaining vendors are loaded in parallel into separate PresetBundle
  instances, then sequentially merged. On a typical setup this drops
  load_presets from ~5 s to ~3.5 s; the saving scales with vendor
  count and CPU cores.

- SplashScreen: remove the wxSPLASH_TIMEOUT flag so the splash stays
  visible until the main window is shown explicitly, and add status
  updates at each slow init phase ("Loading printer and filament
  profiles", "Creating main window", "Loading current preset",
  "Showing main window"). The splash is destroyed right after
  mainframe->Show(true).

- MainFrame: FileHistory::LoadThumbnails moved to a detached
  background thread. The previous synchronous call opened every recent
  3MF file at startup — on macOS that triggered the TCC permission
  dialog for ~/Downloads mid-launch, freezing the whole app until the
  user clicked. Letting it run in the background means the UI is
  responsive from the start and thumbnails populate when ready.

* revert: keep LoadThumbnails on the main thread (review feedback)

SoftFever pointed out the detached thread introduces race conditions
(e.g. MainFrame::open_recent_project() reading while the thread writes
m_thumbnails) and that thumbnails may not appear if the homepage shows
before it finishes. LoadThumbnails already uses tbb::parallel_for
internally, so the call-site offload gave no real speedup. Reverted to
the original synchronous call. The macOS TCC-dialog concern that
motivated this will be handled properly in the lazy-init refactor.

---------

Co-authored-by: SoftFever <softfeverever@gmail.com>
2026-05-16 14:42:25 +08:00
Francesco Palmarini
83179d5978 Make flushing volumes dialog resizable (#13663) 2026-05-16 07:37:16 +01:00
Allyn Malventano
fb5296aad6 fix: register enable_filament_dynamic_map and has_filament_switcher config options (#13623)
fix(printconfig): register enable_filament_dynamic_map and has_filament_switcher options

PR #13388 (X2D Support) added import/export for these options in
bbs_3mf.cpp but never registered them in PrintConfig.cpp. Loading any
.3mf containing these keys throws UnknownOptionException at
PartPlate.cpp:6153 when config->apply() looks up the missing definition.
2026-05-16 14:24:26 +08:00
RobertKuszmar
74f2becb23 Fix PrinterWebView only clear deferred url on success (#11508)
* Fix only clear deferred url on success

* add comments

---------

Co-authored-by: Ioannis Giannakas <59056762+igiannakas@users.noreply.github.com>
Co-authored-by: yw4z <ywsyildiz@gmail.com>
2026-05-16 14:20:43 +08:00
Justin Levine
1555fc92a5 docs(readme): update logo credit GitHub username (#13680) 2026-05-15 22:40:36 -03:00
Ian Bassi
2f7441317b Updates for printer covers (#13660)
* Remove border for X2D image

* RatRig improvement

* Update Elegoo Centauri_cover.png

* Update Kingroon KLP1_cover.png

* Update FlyingBear Reborn3_cover.png

* Update Folgertech FT-6_cover.png

* Update Snapmaker J1_cover.png

* flashforge c5

* RatRir diagonal

* FlashForge perspective

* Update Orca Arena X1 Carbon_cover.png

* Update Tiertime UP310 Pro_cover.png

* Update Folgertech i3_cover.png

* Update FlyingBear Ghost 6_cover.png

* Update Lulzbot Taz 4 or 5_cover.png

* Update Snapmaker J1_cover.png

* Revert "Update Orca Arena X1 Carbon_cover.png"

This reverts commit a6e0f592a1.

* Update Orca Arena X1 Carbon_cover.png

* Update Elegoo Centauri_cover.png

* Update Tiertime UP310 Pro_cover.png

* Update Snapmaker J1_cover.png

* Update Bambu Lab X2D_cover.png

* flashforge creator

* Update Snapmaker U1_cover.png

* Update Folgertech FT-6_cover.png

* Update Kingroon KLP1_cover.png

* Update Folgertech i3_cover.png

* LH stinger

* Update Lulzbot Taz 4 or 5_cover.png

* flyingbear

* LH Stinger

* deltamaker

* ratrig

* Update Generic Repetier Printer_cover.png

---------

Co-authored-by: yw4z <ywsyildiz@gmail.com>
2026-05-15 20:44:33 -03:00
yw4z
b3bb8604c4 UI fixes / improvements (#12513)
* bbl device selector search box

* align file and more menus with its button

* fix multiline inputbox border color on windows

* fix multiline inputbox border color on windows

* preferences: use content width on combobox dropdowns

* about:  match version text size on macOS

* msg dialog improvements

* fix canvas menu overlapping with sliced plates toolbar

* bbl bind dialog button placement

* bbl color picker

* Update StepMeshDialog.cpp

* drop file dialog

* drop dialog revert fonts

* revert windows multiline border

* Update StepMeshDialog.cpp

* update

* Flushing Volumes: match style of combobox

* fix hyperlink color on canvas notifications

* fix possible issues with shared profiles notification
2026-05-16 01:12:30 +08:00
Francesco Palmarini
d614917d1d Fix H2D LAN print job routing (#13662) 2026-05-16 01:09:31 +08:00
Ocraftyone
4154785025 Speed up encoding check (#10873)
Update encoding check
2026-05-15 23:45:39 +08:00
SoftFever
2167378bbe Enhancement: eliminate UI freeze during cloud preset sync on startup (#13673)
fix: eliminate UI freeze during cloud preset sync on startup
  Move synchronous HTTP calls off the main thread in
  GUI_App::start_sync_user_preset():

  - Call scan_orphaned_info_files() and process_delete_presets() in
    the background sync thread instead of the UI thread, so their
    HTTP DELETE calls don't block startup.
  - Call reload_settings() directly from the background thread
    instead of via CallAfter, so get_user_presets() (HTTP GET) and
    load/save_user_presets (file I/O) run off the main thread.
  - Guard update_side_preset_ui() and app_config->save() with
    is_main_thread_active() / CallAfter so they're safe when called
    from a worker thread.
  - Simplifiy finishFn lambdas: the progress-dialog case only
    destroys the dialog; the no-dialog case is a no-op.
2026-05-15 19:45:24 +08:00
Noisyfox
ecab578052 Merge branch 'main' into dev/cut-keep-paint 2026-05-12 16:18:34 +08:00
Noisyfox
b16a461320 Merge branch 'main' into dev/cut-keep-paint 2026-05-11 17:22:21 +08:00
Noisyfox
5b1766b1d5 Remap paint after smooth 2026-05-11 17:16:36 +08:00
Noisyfox
b4b2982106 Remap paint after simplify 2026-05-11 17:00:54 +08:00
Noisyfox
3cbdb092d6 Always clear existing facets first if not kept 2026-05-11 17:00:31 +08:00
Noisyfox
ea5119ec3f Remap paint after contour cut (cut with part assigned to other side using right mouse click) 2026-05-11 15:33:09 +08:00
Noisyfox
b9c9f42f01 Remap paint after dovetail cut 2026-05-11 14:53:53 +08:00
Noisyfox
66f8d954af Simplify cut repaint code to make it more generic 2026-05-11 14:42:45 +08:00
Noisyfox
4aeb6a31db Revert "Refactor planar cut code so it can be reused by other cut type"
This reverts commit a0d1ccaf28.
2026-05-11 14:19:08 +08:00
Noisyfox
89ab4d27cb Revert "Remap paint after dovetail cut"
This reverts commit f3fe37eab3.
2026-05-11 14:19:03 +08:00
Noisyfox
f3fe37eab3 Remap paint after dovetail cut 2026-05-10 23:35:09 +08:00
Noisyfox
a0d1ccaf28 Refactor planar cut code so it can be reused by other cut type 2026-05-10 22:07:02 +08:00
Noisyfox
1299fcef4a Remap paint after repair model 2026-05-10 18:27:02 +08:00
Noisyfox
d5f964ee4f Merge remote-tracking branch 'upstream/main' into dev/cut-keep-paint 2026-05-10 16:41:59 +08:00
Noisyfox
5c754e360e Spatial paint remapping after replace stl 2026-05-10 16:33:08 +08:00
Noisyfox
51d2c91c9b Remap paint after reload from disk 2026-05-10 16:26:19 +08:00
Noisyfox
73096a1161 Fix artifact during normal paint 2026-05-10 12:35:31 +08:00
Noisyfox
219ef664bd Fix issue that in certain cases the paint is not applied when faces are parallel to an axis, by adding a small tolerance to the bbox 2026-05-10 11:50:47 +08:00
Noisyfox
f8a18e7656 Remap paint after mesh boolean (from context menu) 2026-05-10 00:41:18 +08:00
Noisyfox
3aadd6e080 Remap paint after mesh boolean 2026-05-09 21:48:52 +08:00
Noisyfox
e6b3f6ccef Add option to keep existing painting while mapping new paintings to it 2026-05-09 21:47:40 +08:00
Noisyfox
b3a513eab9 Remove redundent mmu facets assign because that's already done in new_object->add_volume(*volume) 2026-05-09 17:36:17 +08:00
Noisyfox
fb0cf966cf Remap paint after split to parts 2026-05-09 17:06:19 +08:00
Noisyfox
c2d33bea08 Remap paint after split to objects 2026-05-09 17:02:46 +08:00
Noisyfox
bfde91685e Rearrange code a little bit to make it more reusable 2026-05-09 16:16:31 +08:00
Noisyfox
4490dccade Fix issue that support/seam/fuzzy skin painting not kept after split 2026-05-09 10:12:36 +08:00
Noisyfox
2f160ad8bc Rearrange code a little bit to make it more reusable 2026-05-08 22:54:20 +08:00
Noisyfox
fad680fcc1 Simplify mesh transform 2026-05-08 21:23:38 +08:00
Noisyfox
83e9f17aa8 Fix issue that Geometry::deg2rad() do calculation in the same type as the parameter, which means if the parameter is int then you lose all the precision 2026-05-07 22:32:56 +08:00
Noisyfox
8b716d43e5 Merge branch 'main' into dev/cut-keep-paint 2026-05-07 08:49:57 +08:00
Noisyfox
be141d32c1 Speed up calculation by caching barycentric independent variables 2026-05-05 21:53:58 +08:00
Noisyfox
5978e96ff5 Add option to enable/disable paint keep 2026-05-05 18:39:50 +08:00
Noisyfox
368563e14e Fix part offset 2026-05-05 18:11:44 +08:00
Noisyfox
01e0013b16 Don't remap paint unless it's the final cut 2026-05-05 17:08:53 +08:00
Noisyfox
4b489339c6 Check normal before expanding the painting to neighboring faces 2026-05-05 11:59:20 +08:00
Noisyfox
e451df27f7 Fix issue of pojection calculation 2026-05-05 11:05:48 +08:00
Noisyfox
24458ba5a2 Remapping the paintings after cut 2026-05-04 20:41:00 +08:00
Noisyfox
ded2e72dcc Refine code 2026-05-04 20:33:13 +08:00
Noisyfox
07173a8de4 Remove unused facets 2026-05-04 20:33:13 +08:00
191 changed files with 5315 additions and 1641 deletions

View File

@@ -46,3 +46,12 @@ ctest --test-dir ./tests/fff_print
- **Cross-platform** — all changes must work on Windows, macOS, and Linux
- Profile/format changes need version migration handling
- Dependencies built separately in `deps/build/`, then linked to main app
## Code review focus areas
- Changes must not cause regressions in existing functionality, defaults, profiles, or project compatibility.
- Features gated by options must not affect existing behavior when those options are disabled.
- Changes should follow the existing code style and architecture. Architectural changes should be justified in code comments and the PR description.
- Add helper functions or utilities only when existing code cannot reasonably be reused. Avoid duplication.
- Keep code concise and clear. Manually simplify AI generated bloated codes before review.
- Include targeted tests or documented verification for behavior changes, especially in slicing logic, profiles, formats, and GUI defaults.

View File

@@ -218,7 +218,7 @@ Open-source slicing has always been built on a tradition of collaboration and at
OrcaSlicer began in that same spirit, drawing from BambuStudio, PrusaSlicer, and ideas inspired by CuraSlicer and SuperSlicer. But it has since grown far beyond its origins. Through relentless innovation — introducing advanced calibration tools, precise wall and seam control, tree supports, adaptive slicing, and hundreds of other features — OrcaSlicer has become the most widely used and actively developed open-source slicer in the 3D printing community. Many of its innovations have been adopted by other slicers, making it a driving force for the entire industry.
The OrcaSlicer logo was designed by community member Justin Levine (@freejstnalxndr).
The OrcaSlicer logo was designed by community member [Justin Levine](https://github.com/jal-co).
# License
- **OrcaSlicer** is licensed under the GNU Affero General Public License, version 3.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points=".5 .5 5.5 7.5 5.5 13.5 9.5 15.5 9.5 7.5 14.5 .5 .5 .5" style="fill:none; stroke:#949494; stroke-linecap:round; stroke-linejoin:round;"/><line x1="8.64" y1="4.5" x2="10.19" y2="2.34" style="fill:none; stroke:#949494; stroke-linecap:round; stroke-linejoin:round;"/></svg>

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

File diff suppressed because one or more lines are too long

View File

@@ -61,7 +61,7 @@
"nil"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -58,7 +58,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

File diff suppressed because one or more lines are too long

View File

@@ -58,7 +58,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -97,7 +97,7 @@
"nil"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_ramming_volumetric_speed": [
"-1"

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -67,7 +67,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -14,7 +14,7 @@
"15"
],
"filament_max_volumetric_speed": [
"0"
"8"
],
"filament_type": [
"PETG"

View File

@@ -6,7 +6,7 @@
"instantiation": "false",
"fan_cooling_layer_time": "100",
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_type": [
"PLA"

View File

@@ -14,7 +14,7 @@
"30"
],
"filament_max_volumetric_speed": [
"0"
"3.6"
],
"filament_type": [
"TPU"

View File

@@ -40,7 +40,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -58,7 +58,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -58,7 +58,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -38,7 +38,7 @@
"15"
],
"filament_max_volumetric_speed": [
"0"
"8"
],
"filament_type": [
"PETG"

View File

@@ -8,7 +8,7 @@
"100"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_type": [
"PLA"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -70,7 +70,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -61,7 +61,7 @@
"nil"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -58,7 +58,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -58,7 +58,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -58,7 +58,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -61,7 +61,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -67,7 +67,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"0"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -61,7 +61,7 @@
"nil"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -64,7 +64,7 @@
"1.75"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -61,7 +61,7 @@
"nil"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -64,7 +64,7 @@
"2.85"
],
"filament_max_volumetric_speed": [
"0"
"12"
],
"filament_minimal_purge_on_wipe_tower": [
"15"

View File

@@ -0,0 +1,50 @@
#version 110
uniform sampler2D uniform_texture;
uniform vec2 inv_tex_size;
varying vec2 tex_coord;
void main()
{
vec3 rgbNW = texture2D(uniform_texture, tex_coord + vec2(-1.0, -1.0) * inv_tex_size).rgb;
vec3 rgbNE = texture2D(uniform_texture, tex_coord + vec2(1.0, -1.0) * inv_tex_size).rgb;
vec3 rgbSW = texture2D(uniform_texture, tex_coord + vec2(-1.0, 1.0) * inv_tex_size).rgb;
vec3 rgbSE = texture2D(uniform_texture, tex_coord + vec2(1.0, 1.0) * inv_tex_size).rgb;
vec3 rgbM = texture2D(uniform_texture, tex_coord).rgb;
vec3 luma_coeff = vec3(0.299, 0.587, 0.114);
float lumaNW = dot(rgbNW, luma_coeff);
float lumaNE = dot(rgbNE, luma_coeff);
float lumaSW = dot(rgbSW, luma_coeff);
float lumaSE = dot(rgbSE, luma_coeff);
float lumaM = dot(rgbM, luma_coeff);
float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
vec2 dir;
dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
const float FXAA_REDUCE_MIN = 1.0 / 128.0;
const float FXAA_REDUCE_MUL = 1.0 / 8.0;
const float FXAA_SPAN_MAX = 8.0;
float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);
float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
dir = min(vec2(FXAA_SPAN_MAX), max(vec2(-FXAA_SPAN_MAX), dir * rcpDirMin)) * inv_tex_size;
vec3 rgbA = 0.5 * (
texture2D(uniform_texture, tex_coord + dir * (1.0 / 3.0 - 0.5)).rgb +
texture2D(uniform_texture, tex_coord + dir * (2.0 / 3.0 - 0.5)).rgb
);
vec3 rgbB = rgbA * 0.5 + 0.25 * (
texture2D(uniform_texture, tex_coord + dir * -0.5).rgb +
texture2D(uniform_texture, tex_coord + dir * 0.5).rgb
);
float lumaB = dot(rgbB, luma_coeff);
gl_FragColor = (lumaB < lumaMin || lumaB > lumaMax) ? vec4(rgbA, 1.0) : vec4(rgbB, 1.0);
}

View File

@@ -0,0 +1,15 @@
#version 110
uniform mat4 view_model_matrix;
uniform mat4 projection_matrix;
attribute vec3 v_position;
attribute vec2 v_tex_coord;
varying vec2 tex_coord;
void main()
{
tex_coord = v_tex_coord;
gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0);
}

View File

@@ -0,0 +1,52 @@
#version 140
uniform sampler2D uniform_texture;
uniform vec2 inv_tex_size;
in vec2 tex_coord;
out vec4 out_color;
void main()
{
vec3 rgbNW = texture(uniform_texture, tex_coord + vec2(-1.0, -1.0) * inv_tex_size).rgb;
vec3 rgbNE = texture(uniform_texture, tex_coord + vec2(1.0, -1.0) * inv_tex_size).rgb;
vec3 rgbSW = texture(uniform_texture, tex_coord + vec2(-1.0, 1.0) * inv_tex_size).rgb;
vec3 rgbSE = texture(uniform_texture, tex_coord + vec2(1.0, 1.0) * inv_tex_size).rgb;
vec3 rgbM = texture(uniform_texture, tex_coord).rgb;
vec3 luma_coeff = vec3(0.299, 0.587, 0.114);
float lumaNW = dot(rgbNW, luma_coeff);
float lumaNE = dot(rgbNE, luma_coeff);
float lumaSW = dot(rgbSW, luma_coeff);
float lumaSE = dot(rgbSE, luma_coeff);
float lumaM = dot(rgbM, luma_coeff);
float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
vec2 dir;
dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
const float FXAA_REDUCE_MIN = 1.0 / 128.0;
const float FXAA_REDUCE_MUL = 1.0 / 8.0;
const float FXAA_SPAN_MAX = 8.0;
float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);
float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
dir = min(vec2(FXAA_SPAN_MAX), max(vec2(-FXAA_SPAN_MAX), dir * rcpDirMin)) * inv_tex_size;
vec3 rgbA = 0.5 * (
texture(uniform_texture, tex_coord + dir * (1.0 / 3.0 - 0.5)).rgb +
texture(uniform_texture, tex_coord + dir * (2.0 / 3.0 - 0.5)).rgb
);
vec3 rgbB = rgbA * 0.5 + 0.25 * (
texture(uniform_texture, tex_coord + dir * -0.5).rgb +
texture(uniform_texture, tex_coord + dir * 0.5).rgb
);
float lumaB = dot(rgbB, luma_coeff);
out_color = (lumaB < lumaMin || lumaB > lumaMax) ? vec4(rgbA, 1.0) : vec4(rgbB, 1.0);
}

View File

@@ -0,0 +1,15 @@
#version 140
uniform mat4 view_model_matrix;
uniform mat4 projection_matrix;
in vec3 v_position;
in vec2 v_tex_coord;
out vec2 tex_coord;
void main()
{
tex_coord = v_tex_coord;
gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0);
}

View File

@@ -17,11 +17,11 @@ var LangText = {
t15: "Printer",
t16: "Filament type",
t17: "Vendor",
t18: "error",
t18: "Error",
t19: "At least one filament must be selected.",
t20: "Do you want to use default filament ?",
t21: "yes",
t22: "no",
t21: "Yes",
t22: "No",
t23: "Release note",
t24: "Get Started",
t25: "Finish",
@@ -35,7 +35,7 @@ var LangText = {
t33: "Open Project",
t34: "hotspot",
t35: "Recently opened",
t36: "ok",
t36: "OK",
t37: "At least one printer must be selected.",
t38: "Cancel",
t39: "Confirm",
@@ -107,7 +107,7 @@ var LangText = {
t113: "You may change your choice in preference anytime.",
t126: "Loading……",
orca1: "Edit Project Info",
orca2: "no model information",
orca2: "No model information",
orca3: "Stealth Mode",
orca4: "This stops the transmission of data to Bambu's cloud services. Users who don't use BBL machines or use LAN mode only can safely turn on this function.",
orca5: "Enable Stealth Mode.",
@@ -131,7 +131,7 @@ var LangText = {
t15: "Impressora",
t16: "Tipus de filament",
t17: "Proveïdor",
t18: "error",
t18: "Error",
t19: "S'ha de seleccionar almenys un filament.",
t20: "Vols utilitzar el filament per defecte?",
t21: "sí",
@@ -149,7 +149,7 @@ var LangText = {
t33: "Obrir Projecte",
t34: "hotspot",
t35: "Obert recentment",
t36: "d'acord",
t36: "D'acord",
t37: "S'ha de seleccionar almenys una impressora.",
t38: "Cancel·lar",
t39: "Confirmar",
@@ -220,7 +220,7 @@ var LangText = {
t112: "Unir-se al Programa",
t113: "Pots canviar la teva elecció en les preferències en qualsevol moment.",
orca1: "Editar Informació del Projecte",
orca2: "no hi ha informació del model",
orca2: "No hi ha informació del model",
orca6: "Bambu Cloud",
},
es_ES: {
@@ -241,11 +241,11 @@ var LangText = {
t15: "Impresora",
t16: "Tipo de filamento",
t17: "Fabricante",
t18: "error",
t18: "Error",
t19: "Al menos se debe seleccionar un filamento.",
t20: "¿Desea usar el filamento por defecto?",
t21: "sí",
t22: "no",
t21: "Sí",
t22: "No",
t23: "Notas de la versión",
t24: "Comenzar",
t25: "Finalizar",
@@ -259,7 +259,7 @@ var LangText = {
t33: "Abrir proyecto",
t34: "punto de acceso",
t35: "Abiertos recientemente",
t36: "ok",
t36: "OK",
t37: "Al menos se debe seleccionar una impresora.",
t38: "Cancelar",
t39: "Confirmar",
@@ -355,11 +355,11 @@ var LangText = {
t15: "Stampante",
t16: "Tipo di filamento",
t17: "Produttore",
t18: "errore",
t18: "Errore",
t19: "È necessario selezionare almeno un filamento.",
t20: "Vuoi utilizzare il filamento predefinito?",
t21: "sì",
t22: "no",
t21: "Sì",
t22: "No",
t23: "Note di rilascio",
t24: "Inizia",
t25: "Fine",
@@ -373,7 +373,7 @@ var LangText = {
t33: "Apri progetto",
t34: "hotspot",
t35: "Aperti di recente",
t36: "ok",
t36: "OK",
t37: "È necessario selezionare almeno una stampante.",
t38: "Annulla",
t39: "Conferma",
@@ -444,7 +444,7 @@ var LangText = {
t112: "Unisciti al programma",
t113: "Puoi modificare la tua scelta in 'Preferenze' in qualsiasi momento.",
orca1: "Modifica informazioni progetto",
orca2: "nessuna informazione sul modello",
orca2: "Nessuna informazione sul modello",
orca3: "Modalità invisibile",
orca4: "Con questa modalità, la trasmissione dei dati ai servizi cloud di Bambu sarà interrotta. Gli utenti che non utilizzano macchine BBL o che usano solo la modalità LAN possono attivare questa funzione in modo sicuro.",
orca5: "Abilita la modalità invisibile.",
@@ -551,7 +551,7 @@ var LangText = {
t106: "Profilbeschreibung",
t126: "Laden……",
orca1: "Edit Project Info",
orca2: "no model information",
orca2: "No model information",
orca6: "Bambu Cloud",
},
cs_CZ: {
@@ -655,7 +655,7 @@ var LangText = {
t106: "Popis profilu",
t126: "Načtení probíhá……",
orca1: "Edit Project Info",
orca2: "no model information",
orca2: "No model information",
orca6: "Bambu Cloud",
},
fr_FR: {
@@ -676,11 +676,11 @@ var LangText = {
t15: "Imprimante",
t16: "Type de filament",
t17: "Fournisseur",
t18: "erreur",
t18: "Erreur",
t19: "Au moins un filament doit être sélectionné.",
t20: "Voulez-vous utiliser le filament par défaut ?",
t21: "oui",
t22: "non",
t21: "Oui",
t22: "Non",
t23: "Note de version",
t24: "Commencer",
t25: "Terminer",
@@ -694,7 +694,7 @@ var LangText = {
t33: "Ouvrir un Projet",
t34: "hotspot",
t35: "Récemment ouvert",
t36: "ok",
t36: "OK",
t37: "Au moins une imprimante doit être sélectionnée.",
t38: "Annuler",
t39: "Confirmer",
@@ -762,7 +762,7 @@ var LangText = {
t111: "Créer un nouveau filament",
t126: "Chargement en cours……",
orca1: "Modifier les informations du projet",
orca2: "pas d'information sur le modèle",
orca2: "Pas d'information sur le modèle",
wk1: "Démarrage rapide",
wk2: "Cet article présente l'utilisation la plus basique de Orca Slicer. Il guide les utilisateurs pour configurer le logiciel, créer des projets et effectuer la première tâche d'impression étape par étape.",
wk3: "Workflow basé sur des projets",
@@ -1032,11 +1032,11 @@ var LangText = {
t15: "Принтер",
t16: "Тип материала",
t17: "Производитель",
t18: "ошибка",
t18: "Oшибка",
t19: "Должна быть выбрана хотя бы одна пластиковая нить.",
t20: "Выбрать пластиковые нити по умолчанию?",
t21: "да",
t22: "нет",
t21: "Да",
t22: "Нет",
t23: "Информация о версии",
t24: "Начать",
t25: "Закончить",
@@ -1218,7 +1218,7 @@ var LangText = {
t94: "장치를 보려면 프린터 연결을 설정하세요.",
t126: "로딩 중……",
orca1: "Edit Project Info",
orca2: "no model information",
orca2: "No model information",
orca6: "Bambu Cloud",
},
tr_TR: {
@@ -1257,7 +1257,7 @@ var LangText = {
t33: "Projeyi Aç",
t34: "Erişim noktası",
t35: "Yakın zamanda açıldı",
t36: "Ok",
t36: "OK",
t37: "En az bir yazıcı seçilmelidir.",
t38: "İptal Et",
t39: "Onayla",
@@ -1329,7 +1329,7 @@ var LangText = {
t113: "Tercihinizi istediğiniz zaman değiştirebilirsiniz.",
t126: "Yükleme devam ediyor……",
orca1: "Proje Bilgilerini Düzenle",
orca2: "model bilgisi yok",
orca2: "Model bilgisi yok",
orca3: "Gizli Mod",
orca4: "Bu, Bambu'nun bulut hizmetlerine veri iletimini durdurur. BBL makinelerini kullanmayan veya yalnızca LAN modunu kullanan kullanıcılar bu işlevi güvenle açabilir.",
orca5: "Gizli Modu etkinleştirin.",
@@ -1353,11 +1353,11 @@ var LangText = {
t15: "Drukarka",
t16: "Typ filamentu",
t17: "Dostawca",
t18: "błąd",
t18: "Błąd",
t19: "Przynajmniej jeden filament musi być wybrany.",
t20: "Czy chcesz użyć domyślnego filamentu?",
t21: "tak",
t22: "nie",
t21: "Tak",
t22: "Nie",
t23: "Informacje o wydaniu",
t24: "Rozpocznij",
t25: "Zakończ",
@@ -1371,7 +1371,7 @@ var LangText = {
t33: "Otwórz Projekt",
t34: "hotspot",
t35: "Ostatnio otwarte",
t36: "ok",
t36: "OK",
t37: "Przynajmniej jedna drukarka musi być wybrana.",
t38: "Anuluj",
t39: "Potwierdź",
@@ -1443,7 +1443,7 @@ var LangText = {
t113: "Możesz zmienić swój wybór w preferencjach w dowolnym momencie.",
t126: "Ładowanie trwa……",
orca1: "Edytuj informacje o projekcie",
orca2: "brak informacji o modelu",
orca2: "Brak informacji o modelu",
orca3: "Tryb «Niewidzialny»",
orca4: "To wyłączy przesyłanie danych do usług chmurowych Bambu. Użytkownicy, którzy nie korzystają z maszyn BBL lub używają tylko trybu LAN, mogą bez obaw włączyć tę opcję.",
orca5: "Włącz tryb «Niewidzialny»",
@@ -1485,7 +1485,7 @@ var LangText = {
t33: "Abrir Projeto",
t34: "hotspot",
t35: "Aberto Recentemente",
t36: "Ok",
t36: "OK",
t37: "Pelo menos uma impressora deve ser selecionada.",
t38: "Cancelar",
t39: "Confirmar",
@@ -1581,11 +1581,11 @@ var LangText = {
t15: "Spausdintuvas",
t16: "Gijos tipas",
t17: "Gamintojas",
t18: "klaida",
t18: "Klaida",
t19: "Turi būti pasirinkta bent viena gija.",
t20: "Ar norite naudoti numatytąją giją?",
t21: "taip",
t22: "ne",
t21: "Taip",
t22: "Ne",
t23: "Išleidimo pastabos",
t24: "Pradėti",
t25: "Pabaigti",
@@ -1599,7 +1599,7 @@ var LangText = {
t33: "Atverti projektą",
t34: "Prieigos taškas",
t35: "Neseniai atidaryti",
t36: "gerai",
t36: "Gerai",
t37: "Turi būti pasirinktas bent vienas spausdintuvas.",
t38: "Atšaukti",
t39: "Patvirtinti",
@@ -1670,7 +1670,7 @@ var LangText = {
t112: "Prisijungti prie programos",
t113: "Savo pasirinkimą galite bet kada pakeisti.",
orca1: "Redaguoti projekto informaciją",
orca2: "nėra informacijos apie modelį",
orca2: "Nėra informacijos apie modelį",
orca3: "Slaptas režimas",
orca4: "Tai sustabdo duomenų perdavimą į Bambu debesijos paslaugas. Vartotojai, kurie nenaudoja BBL mašinų arba naudoja tik LAN režimą, gali drąsiai įjungti šią funkciją.",
orca5: "Įjungti slaptą režimą.",

View File

@@ -148,29 +148,6 @@
display: inline-block;
}
select {
padding: 6px 9px;
border: 1px solid #dbdbdb;
border-radius: 3px;
font-size: 12px;
cursor: pointer;
appearance: auto;
background-color: white;
color: black;
}
select option {
background-color: white;
color: black;
}
select:hover,
select:focus {
outline: none;
border-color: #26A69A;
background-color: #edfaf2;
}
.button-container {
display: flex;
justify-content: center;
@@ -243,11 +220,6 @@
position: sticky;
z-index: 11;
}
body.dark-mode select {
background-color: #2d2d31;
color: white;
border-color: #4c4c55;
}
body.dark-mode .warning-text {
color: #f44336;
@@ -281,13 +253,16 @@
>
Re-Calculate
</div>
<select
id="extruders"
onchange="handleExtruderSelect(document.getElementById('extruders').value)"
>
<option value="left" id="extruder_label_0">Left Nozzle</option>
<option value="right" id="extruder_label_1">Right Nozzle</option>
</select>
<div class="ComboBox">
<div class="arrow-icon"></div>
<select
id="extruders"
onchange="handleExtruderSelect(document.getElementById('extruders').value)"
>
<option value="left" id="extruder_label_0">Left Nozzle</option>
<option value="right" id="extruder_label_1">Right Nozzle</option>
</select>
</div>
</div>
<div class="scroll-container">

View File

@@ -26,7 +26,7 @@
<div id="EmptyArea">
<div><img src="img/null.png"></div>
<div class="Text_Title Text_Bold trans" tid='orca2'>no model information</div>
<div class="Text_Title Text_Bold trans" tid='orca2'>No model information</div>
<div id="AddModelInfoBtn" class="ButtonStyleConfirm ButtonTypeWindow trans" tid='orca1' onClick="OnClickEditProjectInfo()">Edit Project Info</div>
</div>

View File

@@ -380,4 +380,5 @@ body
#AddModelInfoBtn
{
margin-top: 20px;
margin-right:0;
}

View File

@@ -4456,7 +4456,7 @@ int CLI::run(int argc, char **argv)
size_t num_objects = model.objects.size();
for (size_t i = 0; i < num_objects; ++ i) {
ModelObjectPtrs new_objects;
model.objects.front()->split(&new_objects);
model.objects.front()->split(&new_objects, false); // TODO: add cli option to enable this?
model.delete_object(size_t(0));
}
}
@@ -6435,6 +6435,7 @@ int CLI::run(int argc, char **argv)
glfwGetVersion(&gl_major, &gl_minor, &gl_verbos);
BOOST_LOG_TRIVIAL(info) << boost::format("opengl version %1%.%2%.%3%")%gl_major %gl_minor %gl_verbos;
bool thumbnail_opengl_ready = false;
glfwSetErrorCallback(glfw_callback);
int ret = glfwInit();
if (ret == GLFW_FALSE) {
@@ -6463,13 +6464,22 @@ int CLI::run(int argc, char **argv)
GLFWwindow* window = glfwCreateWindow(640, 480, "base_window", NULL, NULL);
if (window == NULL)
{
BOOST_LOG_TRIVIAL(error) << "Failed to create GLFW window" << std::endl;
BOOST_LOG_TRIVIAL(error) << "Failed to create GLFW window; skipping thumbnail rendering for CLI export" << std::endl;
}
else
else {
glfwMakeContextCurrent(window);
thumbnail_opengl_ready = true;
}
}
//opengl manager related logic
if (!thumbnail_opengl_ready) {
BOOST_LOG_TRIVIAL(error) << "OpenGL context unavailable; skip thumbnail generating" << std::endl;
need_create_thumbnail_group = false;
need_create_no_light_group = false;
need_create_top_group = false;
}
else
{
GUI::OpenGLManager opengl_mgr;
bool opengl_valid = opengl_mgr.init_gl(false);

View File

@@ -31,16 +31,11 @@ function(encoding_check TARGET)
# Define top-level encoding check target for this ${TARGET}
add_custom_target(encoding-check-${TARGET}
DEPENDS encoding-check ${T_SOURCES}
COMMAND $<TARGET_FILE:encoding-check> ${TARGET} ${T_SOURCES}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Checking source files encodings for target ${TARGET}"
)
# Add checking of each source file as a subcommand of encoding-check-${TARGET}
foreach(file ${T_SOURCES})
add_custom_command(TARGET encoding-check-${TARGET} PRE_BUILD
COMMAND $<TARGET_FILE:encoding-check> ${TARGET} ${file}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
endforeach()
# This adds dependency on encoding-check-${TARGET} to ${TARET}
# via the global-encoding-check

View File

@@ -69,28 +69,24 @@ unsigned char *utf8_check(unsigned char *s)
}
int main(int argc, char const *argv[])
static const char* target;
void error_exit(const char* error, const char* filename)
{
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " <program/library> <file>" << std::endl;
return -1;
}
std::cerr << "\n\tError: " << error << ": " << filename << "\n"
<< "\tTarget: " << target << "\n"
<< std::endl;
std::exit(-2);
}
const char* target = argv[1];
const char* filename = argv[2];
const auto error_exit = [=](const char* error) {
std::cerr << "\n\tError: " << error << ": " << filename << "\n"
<< "\tTarget: " << target << "\n"
<< std::endl;
std::exit(-2);
};
void utf8_check_file(const char* filename)
{
std::ifstream file(filename, std::ios::binary | std::ios::ate);
const auto size = file.tellg();
if (size == 0) {
return 0;
return;
}
file.seekg(0, std::ios::beg);
@@ -101,7 +97,7 @@ int main(int argc, char const *argv[])
// Check UTF-8 validity
if (utf8_check(reinterpret_cast<unsigned char*>(buffer.data())) != nullptr) {
error_exit("Source file does not contain (valid) UTF-8");
error_exit("Source file does not contain (valid) UTF-8", filename);
}
// Check against a BOM mark
@@ -109,10 +105,25 @@ int main(int argc, char const *argv[])
&& buffer[0] == '\xef'
&& buffer[1] == '\xbb'
&& buffer[2] == '\xbf') {
error_exit("Source file is valid UTF-8 but contains a BOM mark");
error_exit("Source file is valid UTF-8 but contains a BOM mark", filename);
}
} else {
error_exit("Could not read source file");
error_exit("Could not read source file", filename);
}
}
int main(int argc, char const *argv[])
{
if (argc < 3) {
std::cerr << "Usage: " << argv[0] << " <program/library> <file[s]>" << std::endl;
return -1;
}
target = argv[1];
for (int i = 2; i < argc; i++) {
utf8_check_file(argv[i]);
}
return 0;

View File

@@ -212,8 +212,14 @@ void AppConfig::set_defaults()
if (get("camera_navigation_style").empty())
set("camera_navigation_style", "0");
if (get("swap_mouse_buttons").empty())
set_bool("swap_mouse_buttons", false);
if (get("left_mouse_drag_action").empty())
set("left_mouse_drag_action", "2");
if (get("middle_mouse_drag_action").empty())
set("middle_mouse_drag_action", "1");
if (get("right_mouse_drag_action").empty())
set("right_mouse_drag_action", "1");
if (get("reverse_mouse_wheel_zoom").empty())
set_bool("reverse_mouse_wheel_zoom", false);
@@ -230,6 +236,29 @@ void AppConfig::set_defaults()
if (get("camera_orbit_mult").empty())
set("camera_orbit_mult", "1.0");
if (get(SETTING_OPENGL_AA_SAMPLES).empty())
set(SETTING_OPENGL_AA_SAMPLES, "4");
if (get(SETTING_OPENGL_FXAA_ENABLED).empty())
set_bool(SETTING_OPENGL_FXAA_ENABLED, false);
if (get(SETTING_OPENGL_FPS_CAP).empty())
set(SETTING_OPENGL_FPS_CAP, "0");
else {
int fps_cap = 0;
try {
fps_cap = std::stoi(get(SETTING_OPENGL_FPS_CAP));
}
catch (...) {
fps_cap = 0;
}
fps_cap = std::max(0, std::min(fps_cap, 240));
set(SETTING_OPENGL_FPS_CAP, std::to_string(fps_cap));
}
if (get(SETTING_OPENGL_SHOW_FPS_OVERLAY).empty())
set_bool(SETTING_OPENGL_SHOW_FPS_OVERLAY, false);
if (get("export_sources_full_pathnames").empty())
set_bool("export_sources_full_pathnames", false);
@@ -834,8 +863,10 @@ std::string AppConfig::load()
void AppConfig::save()
{
if (! is_main_thread_active())
if (!is_main_thread_active()) {
BOOST_LOG_TRIVIAL(fatal) << "Calling AppConfig::save() from a worker thread!";
throw CriticalException("Calling AppConfig::save() from a worker thread!");
}
// The config is first written to a file with a PID suffix and then moved
// to avoid race conditions with multiple instances of Slic3r

View File

@@ -30,6 +30,10 @@ using namespace nlohmann;
#define SETTING_NETWORK_PLUGIN_REMIND_LATER "network_plugin_remind_later"
#define SETTING_USE_ENCRYPTED_TOKEN_FILE "use_encrypted_token_file"
#define SETTING_CLOUD_PROVIDERS "cloud_providers"
#define SETTING_OPENGL_AA_SAMPLES "opengl_antialiasing_samples"
#define SETTING_OPENGL_FXAA_ENABLED "opengl_fxaa_enabled"
#define SETTING_OPENGL_FPS_CAP "opengl_fps_cap"
#define SETTING_OPENGL_SHOW_FPS_OVERLAY "opengl_show_fps_overlay"
#if defined(_WIN32) || defined(_WIN64)
#define BAMBU_NETWORK_AGENT_VERSION_LEGACY "01.10.01.09"

View File

@@ -330,6 +330,8 @@ public:
size_t hash() const throw() override { return std::hash<T>{}(this->value); }
// Warning mitigation: Indicate that virtual serialize() is not forgotten
using ConfigOption::serialize;
private:
friend class cereal::access;
template<class Archive> void serialize(Archive & ar) { ar(this->value); }
@@ -752,6 +754,8 @@ public:
return modified;
}
// Warning mitigation: Indicate that virtual serialize() is not forgotten
using ConfigOptionVectorBase::serialize;
private:
friend class cereal::access;
template<class Archive> void serialize(Archive & ar) { ar(this->values); }

View File

@@ -63,7 +63,7 @@ static void add_cut_volume(TriangleMesh& mesh, ModelObject* object, const ModelV
vol->cut_info = src_volume->cut_info;
}
static void process_volume_cut( ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix,
static void process_volume_cut( const ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix,
ModelObjectCutAttributes attributes, TriangleMesh& upper_mesh, TriangleMesh& lower_mesh)
{
const auto volume_matrix = volume->get_matrix();
@@ -178,7 +178,7 @@ static void process_modifier_cut(ModelVolume* volume, const Transform3d& instanc
lower->add_volume(*volume);
}
static void process_solid_part_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix,
static void process_solid_part_cut(const ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix,
ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower)
{
// Perform cut
@@ -279,9 +279,22 @@ void Cut::post_process(ModelObject* upper, ModelObject* lower, ModelObjectPtrs&
}
void Cut::finalize(const ModelObjectPtrs& objects)
void Cut::finalize(const ModelObjectPtrs& objects, const std::vector<std::optional<TriangleSelector::SavedPainting>>& saved_paintings)
{
//clear model from temporarry objects
// Paint volumes
for (const auto& saved_painting : saved_paintings) {
if (saved_painting) {
for (const auto object : objects) {
for (const auto volume : object->volumes) {
if (volume->is_model_part() && !volume->is_cut_connector()) {
volume->restore_painting(saved_painting, true);
}
}
}
}
}
//clear model from temporary objects
m_model.clear_objects();
// add to model result objects
@@ -320,7 +333,17 @@ const ModelObjectPtrs& Cut::perform_with_plane()
const Transformation cut_transformation = Transformation(m_cut_matrix);
const Transform3d inverse_cut_matrix = cut_transformation.get_rotation_matrix().inverse() * translation_transform(-1. * cut_transformation.get_offset());
std::vector<std::optional<TriangleSelector::SavedPainting>> saved_paintings;
for (ModelVolume* volume : mo->volumes) {
// Save painting data before reset_extra_facets() discards it.
if (m_attributes.has(ModelObjectCutAttribute::KeepPaint)) {
saved_paintings.emplace_back(volume->save_painting());
if (saved_paintings.back()) {
// Transform mesh to cut space (same transform as process_volume_cut applies)
saved_paintings.back()->mesh.transform(instance_matrix * volume->get_matrix(), true);
}
}
volume->reset_extra_facets();
if (!volume->is_model_part()) {
@@ -376,9 +399,9 @@ const ModelObjectPtrs& Cut::perform_with_plane()
}
}
BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - end";
finalize(cut_object_ptrs, saved_paintings);
finalize(cut_object_ptrs);
BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - end";
return m_model.objects;
}
@@ -431,7 +454,7 @@ static void merge_solid_parts_inside_object(ModelObjectPtrs& objects)
}
const ModelObjectPtrs& Cut::perform_by_contour(std::vector<Part> parts, int dowels_count)
const ModelObjectPtrs& Cut::perform_by_contour(const ModelObject* src_object, std::vector<Part> parts, int dowels_count)
{
ModelObject* cut_mo = m_model.objects.front();
@@ -446,6 +469,19 @@ const ModelObjectPtrs& Cut::perform_by_contour(std::vector<Part> parts, int dowe
lower->name = lower->name + "_B";
}
// Save painting data so we later can remap it.
std::vector<std::optional<TriangleSelector::SavedPainting>> saved_paintings;
if (m_attributes.has(ModelObjectCutAttribute::KeepPaint)) {
const auto instance_matrix = src_object->instances[m_instance]->get_transformation().get_matrix_no_offset();
for (const auto volume : src_object->volumes) {
saved_paintings.emplace_back(volume->save_painting());
if (saved_paintings.back()) {
// Transform mesh to cut space (same transform as process_volume_cut applies)
saved_paintings.back()->mesh.transform(instance_matrix * volume->get_matrix(), true);
}
}
}
const size_t cut_parts_cnt = parts.size();
bool has_modifiers = false;
@@ -475,7 +511,7 @@ const ModelObjectPtrs& Cut::perform_by_contour(std::vector<Part> parts, int dowe
merge_solid_parts_inside_object(cut_object_ptrs);
// replace initial objects in model with cut object
finalize(cut_object_ptrs);
finalize(cut_object_ptrs, saved_paintings);
}
else if (volumes.size() > cut_parts_cnt) {
// Means that object is cut with connectors
@@ -506,7 +542,7 @@ const ModelObjectPtrs& Cut::perform_by_contour(std::vector<Part> parts, int dowe
merge_solid_parts_inside_object(cut_object_ptrs);
// replace initial objects in model with cut object
finalize(cut_object_ptrs);
finalize(cut_object_ptrs, saved_paintings);
// Add Dowel-connectors as separate objects to model
if (cut_connectors_obj.size() >= 3)
@@ -518,7 +554,12 @@ const ModelObjectPtrs& Cut::perform_by_contour(std::vector<Part> parts, int dowe
}
const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Transform3d& rotation_m, bool keep_as_parts/* = false*/)
const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove,
const Transform3d& rotation_m,
const int groove_count,
const float groove_gap,
const float m_radius,
bool keep_as_parts /* = false*/)
{
ModelObject* cut_mo = m_model.objects.front();
@@ -532,6 +573,20 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran
upper->name = upper->name + "_A";
lower->name = lower->name + "_B";
}
// Save painting data so we later can remap it.
std::vector<std::optional<TriangleSelector::SavedPainting>> saved_paintings;
if (m_attributes.has(ModelObjectCutAttribute::KeepPaint)) {
const auto instance_matrix = cut_mo->instances[m_instance]->get_transformation().get_matrix_no_offset();
for (const auto volume : cut_mo->volumes) {
saved_paintings.emplace_back(volume->save_painting());
if (saved_paintings.back()) {
// Transform mesh to cut space (same transform as process_volume_cut applies)
saved_paintings.back()->mesh.transform(instance_matrix * volume->get_matrix(), true);
}
}
}
const double groove_half_depth = 0.5 * double(groove.depth);
Model tmp_model_for_cut = Model();
@@ -565,61 +620,108 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran
reset_instance_transformation(object, m_instance);
};
// cut by upper plane
const Transform3d cut_matrix_upper = translation_transform(rotation_m * (groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix;
// cut by upper plane (+Z)
{
const Transform3d cut_matrix_upper = translation_transform(rotation_m * (groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix;
cut(tmp_object, cut_matrix_upper, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
}
// cut by lower plane
const Transform3d cut_matrix_lower = translation_transform(rotation_m * (-groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix;
// cut by lower plane (-Z)
{
const Transform3d cut_matrix_lower = translation_transform(rotation_m * (-groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix;
cut(tmp_object, cut_matrix_lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
}
// cut middle part with 2 angles and add parts to related upper/lower objects
// Compute same slot outer width used in preview plane
const float groove_width = calculate_groove_width(groove, m_radius);
const double h_side_shift = 0.5 * double(groove.width + groove.depth / tan(groove.flaps_angle));
ModelObject* groove_object{nullptr};
// cut by angle1 plane
{
const Transform3d cut_matrix_angle1 = translation_transform(rotation_m * (-h_side_shift * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, -groove.flaps_angle, -groove.angle));
// multiple cuts
for (int i = 0; i < groove_count; i++) {
bool is_first_groove = i == 0;
bool is_last_groove = i == groove_count - 1;
cut(tmp_object, cut_matrix_angle1, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
// Calculate the x-axis offset for this dovetail
float groove_offset_factor_start = -.5 * ((groove_count - 1));
float groove_offset_factor = groove_offset_factor_start + i;
float offset_x = groove_offset_factor * (groove_gap + groove_width);
tmp_object->clone_for_cut(&groove_object);
for (ModelVolume* volume : tmp_object->volumes) {
ModelVolume* new_vol = groove_object->add_volume(*volume);
new_vol->reset_from_upper();
}
// isolate area of current groove
if (!is_first_groove) {
float left_cut_position = (-groove_gap / 2.f) - (groove_width / 2.f) + offset_x;
const Transform3d cut_matrix_left = translation_transform(rotation_m * (left_cut_position * Vec3d::UnitX())) *
m_cut_matrix * rotation_transform(Vec3d(0, M_PI / 2.0, 0));
cut(groove_object, cut_matrix_left, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
}
if (!is_last_groove) {
float right_cut_position = (groove_gap / 2.f) + (groove_width / 2.f) + offset_x;
const Transform3d cut_matrix_right = translation_transform(rotation_m * (right_cut_position * Vec3d::UnitX())) *
m_cut_matrix * rotation_transform(Vec3d(0, M_PI / 2.0, 0));
cut(groove_object, cut_matrix_right, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
}
const Transform3d groove_translation = translation_transform(rotation_m * (offset_x * Vec3d::UnitX()));
// cut middle part with 2 angles and add parts to related upper/lower objects
const double h_side_shift = 0.5 * double(groove.width + groove.depth / tan(groove.flaps_angle));
// cut by angle1 plane
{
const Transform3d cut_matrix_angle1 = groove_translation * translation_transform(rotation_m * (-h_side_shift * Vec3d::UnitX())) *
m_cut_matrix * rotation_transform(Vec3d(0, -groove.flaps_angle, -groove.angle));
cut(groove_object, cut_matrix_angle1, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
}
// cut by angle2 plane
{
const Transform3d cut_matrix_angle2 = groove_translation * translation_transform(rotation_m * (h_side_shift * Vec3d::UnitX())) *
m_cut_matrix * rotation_transform(Vec3d(0, groove.flaps_angle, groove.angle));
cut(groove_object, cut_matrix_angle2, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
}
// apply tolerance to the middle part
{
const double h_groove_shift_tolerance = groove_half_depth - (double)groove.depth_tolerance;
const Transform3d cut_matrix_lower_tolerance = groove_translation * translation_transform(rotation_m * (-h_groove_shift_tolerance * Vec3d::UnitZ())) *
m_cut_matrix;
cut(groove_object, cut_matrix_lower_tolerance, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
const double h_side_shift_tolerance = h_side_shift - 0.5 * double(groove.width_tolerance);
const Transform3d cut_matrix_angle1_tolerance = groove_translation * translation_transform(rotation_m * (-h_side_shift_tolerance * Vec3d::UnitX())) *
m_cut_matrix * rotation_transform(Vec3d(0, -groove.flaps_angle, -groove.angle));
cut(groove_object, cut_matrix_angle1_tolerance, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
const Transform3d cut_matrix_angle2_tolerance = groove_translation * translation_transform(rotation_m * (h_side_shift_tolerance * Vec3d::UnitX())) *
m_cut_matrix * rotation_transform(Vec3d(0, groove.flaps_angle, groove.angle));
cut(groove_object, cut_matrix_angle2_tolerance, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
}
add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
groove_object->clear_volumes();
}
// cut by angle2 plane
{
const Transform3d cut_matrix_angle2 = translation_transform(rotation_m * (h_side_shift * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, groove.flaps_angle, groove.angle));
cut(tmp_object, cut_matrix_angle2, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
}
// apply tolerance to the middle part
{
const double h_groove_shift_tolerance = groove_half_depth - (double)groove.depth_tolerance;
const Transform3d cut_matrix_lower_tolerance = translation_transform(rotation_m * (-h_groove_shift_tolerance * Vec3d::UnitZ())) * m_cut_matrix;
cut(tmp_object, cut_matrix_lower_tolerance, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
const double h_side_shift_tolerance = h_side_shift - 0.5 * double(groove.width_tolerance);
const Transform3d cut_matrix_angle1_tolerance = translation_transform(rotation_m * (-h_side_shift_tolerance * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, -groove.flaps_angle, -groove.angle));
cut(tmp_object, cut_matrix_angle1_tolerance, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
const Transform3d cut_matrix_angle2_tolerance = translation_transform(rotation_m * (h_side_shift_tolerance * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, groove.flaps_angle, groove.angle));
cut(tmp_object, cut_matrix_angle2_tolerance, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
}
// this part can be added to the upper object now
add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
ModelObjectPtrs cut_object_ptrs;
if (keep_as_parts) {
@@ -658,10 +760,24 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran
merge_solid_parts_inside_object(cut_object_ptrs);
}
finalize(cut_object_ptrs);
finalize(cut_object_ptrs, saved_paintings);
return m_model.objects;
}
float Cut::calculate_groove_width (const Cut::Groove& groove, const float m_radius)
{
// Compute same slot outer width used in preview plane
const double flap_width = is_approx(groove.flaps_angle, 0.f) ? groove.depth : groove.depth / sin(groove.flaps_angle);
const double total_flap_width = 2.0 * flap_width * cos(groove.flaps_angle);
const double slot_neck_half_width = 0.5f * (groove.width);
const double slot_mouth_half_width = 0.5 * (groove.width + total_flap_width);
const double plane_half_height = 0.5f* (1.5f * (1.5f *m_radius));
const double flap_taper_offset = plane_half_height * tan(groove.angle);
const double slot_outer_x_max = std::max(slot_mouth_half_width + flap_taper_offset, slot_neck_half_width + flap_taper_offset);
return float(2.0 * slot_outer_x_max);
}
} // namespace Slic3r

View File

@@ -11,7 +11,7 @@ namespace Slic3r {
using ModelObjectPtrs = std::vector<ModelObject*>;
enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, KeepAsParts, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels, InvalidateCutInfo };
enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, KeepAsParts, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels, InvalidateCutInfo, KeepPaint };
using ModelObjectCutAttributes = enum_bitmask<ModelObjectCutAttribute>;
ENABLE_ENUM_BITMASK_OPERATORS(ModelObjectCutAttribute);
@@ -25,7 +25,7 @@ class Cut {
void post_process(ModelObject* object, ModelObjectPtrs& objects, bool keep, bool place_on_cut, bool flip);
void post_process(ModelObject* upper_object, ModelObject* lower_object, ModelObjectPtrs& objects);
void finalize(const ModelObjectPtrs& objects);
void finalize(const ModelObjectPtrs& objects, const std::vector<std::optional<TriangleSelector::SavedPainting>>& saved_paintings);
public:
@@ -56,10 +56,16 @@ public:
};
const ModelObjectPtrs& perform_with_plane();
const ModelObjectPtrs& perform_by_contour(std::vector<Part> parts, int dowels_count);
const ModelObjectPtrs& perform_with_groove(const Groove& groove, const Transform3d& rotation_m, bool keep_as_parts = false);
const ModelObjectPtrs& perform_by_contour(const ModelObject* src_object, std::vector<Part> parts, int dowels_count);
const ModelObjectPtrs& perform_with_groove(const Groove& groove,
const Transform3d& rotation_m,
const int groove_count,
const float groove_gap,
const float m_radius,
bool keep_as_parts = false);
}; // namespace Cut
static float calculate_groove_width(const Cut::Groove& groove, const float m_radius);
}; // namespace Cut
} // namespace Slic3r

View File

@@ -1161,10 +1161,15 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
const bool is_ramming = (gcodegen.config().single_extruder_multi_material) ||
(!gcodegen.config().single_extruder_multi_material &&
gcodegen.config().filament_multitool_ramming.get_at(tcr.initial_tool));
// Orca: user-facing override (Printer Settings > Wipe tower > "Tool change on wipe tower").
// Forces the toolhead to travel over the wipe tower before issuing Tx even on multi-toolhead
// printers without ramming, where Orca would otherwise emit Tx in place (potentially over the part).
const bool tool_change_on_wipe_tower = gcodegen.config().tool_change_on_wipe_tower.value;
const bool should_travel_to_tower = !tcr.priming && (tcr.force_travel // wipe tower says so
|| !needs_toolchange // this is just finishing the tower with no toolchange
|| will_go_down // Make sure to move to prime tower before moving down
|| is_ramming);
|| is_ramming
|| tool_change_on_wipe_tower);
if (should_travel_to_tower || gcodegen.m_need_change_layer_lift_z) {
// FIXME: It would be better if the wipe tower set the force_travel flag for all toolchanges,

View File

@@ -298,7 +298,11 @@ bool directions_perpendicular(double angle1, double angle2, double max_diff = 0)
template<class T> bool contains(const std::vector<T> &vector, const Point &point);
template<typename T> T rad2deg(T angle) { return T(180.0) * angle / T(PI); }
double rad2deg_dir(double angle);
template<typename T> constexpr T deg2rad(const T angle) { return T(PI) * angle / T(180.0); }
template<typename T> constexpr T deg2rad(const T angle)
{
static_assert(std::is_floating_point<T>::value, "Why do you want to calculate angle in integer?");
return T(PI) * angle / T(180.0);
}
template<typename T> T angle_to_0_2PI(T angle)
{
static const T TWO_PI = T(2) * T(PI);

View File

@@ -159,6 +159,12 @@ bool Layer::is_perimeter_compatible(const PrintRegion& a, const PrintRegion& b)
&& config.detect_thin_wall == other_config.detect_thin_wall
&& config.infill_wall_overlap == other_config.infill_wall_overlap
&& config.top_bottom_infill_wall_overlap == other_config.top_bottom_infill_wall_overlap
// Orca: these flags directly change the effective wall count produced by the perimeter
// generator. If two regions disagree on any of them, merging their slices into one shared make_perimeters
// call would silently use the first region's flag for both.
&& config.only_one_wall_first_layer == other_config.only_one_wall_first_layer
&& config.only_one_wall_top == other_config.only_one_wall_top
&& config.min_width_top_surface == other_config.min_width_top_surface
&& config.seam_slope_type == other_config.seam_slope_type
&& config.seam_slope_conditional == other_config.seam_slope_conditional
&& config.scarf_angle_threshold == other_config.scarf_angle_threshold

View File

@@ -1980,6 +1980,49 @@ void ModelVolume::reset_extra_facets()
this->fuzzy_skin_facets.reset();
}
std::optional<TriangleSelector::SavedPainting> ModelVolume::save_painting() const
{
if (is_any_painted() && is_model_part() && !mesh().empty()) {
TriangleSelector::SavedPainting sp;
sp.mesh = mesh();
sp.supported = supported_facets.get_data();
sp.seam = seam_facets.get_data();
sp.mmu = mmu_segmentation_facets.get_data();
sp.fuzzy = fuzzy_skin_facets.get_data();
return sp;
}
return {};
}
void ModelVolume::restore_painting(const std::optional<TriangleSelector::SavedPainting>& saved, const bool keep_existing_paint)
{
if (!keep_existing_paint) {
reset_extra_facets();
}
if (!saved) {
return;
}
auto remap_one = [&](const TriangleSelector::TriangleSplittingData& src_data,
FacetsAnnotation& target_facets) {
if (src_data.bitstream.empty())
return;
auto result =
TriangleSelector::remap_painting(saved->mesh.its, src_data, mesh().its, Geometry::translation_transform(mesh().get_init_shift()),
keep_existing_paint ?
std::optional<std::reference_wrapper<const TriangleSelector::TriangleSplittingData>>{std::ref(target_facets.get_data())} :
std::optional<std::reference_wrapper<const TriangleSelector::TriangleSplittingData>>{});
if (!result.bitstream.empty())
target_facets.set_data(std::move(result));
};
remap_one(saved->supported, supported_facets);
remap_one(saved->seam, seam_facets);
remap_one(saved->mmu, mmu_segmentation_facets);
remap_one(saved->fuzzy, fuzzy_skin_facets);
}
static void invalidate_translations(ModelObject* object, const ModelInstance* src_instance)
{
if (!object->origin_translation.isApprox(Vec3d::Zero()) && src_instance->get_offset().isApprox(Vec3d::Zero())) {
@@ -1993,13 +2036,14 @@ static void invalidate_translations(ModelObject* object, const ModelInstance* sr
}
}
void ModelObject::split(ModelObjectPtrs* new_objects)
void ModelObject::split(ModelObjectPtrs* new_objects, const bool remap_paint)
{
std::vector<TriangleMesh> all_meshes;
std::vector<Transform3d> all_transfos;
std::vector<std::pair<int, int>> volume_mesh_counts;
all_meshes.reserve(this->volumes.size() * 5);
bool is_multi_volume_object = (this->volumes.size() > 1);
std::optional<TriangleSelector::SavedPainting> saved_painting;
for (int volume_idx = 0; volume_idx < this->volumes.size(); volume_idx++) {
ModelVolume* volume = this->volumes[volume_idx];
@@ -2011,6 +2055,10 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
volume->text_configuration.reset();
if (!is_multi_volume_object) {
if (remap_paint) {
// Save painting so we could restore them after the mesh split
saved_painting = volume->save_painting();
}
//BBS: not multi volume object, then split mesh.
std::vector<TriangleMesh> volume_meshes = volume->mesh().split();
int mesh_count = 0;
@@ -2078,10 +2126,19 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
ModelVolume* new_vol = new_object->add_volume(*volume, std::move(mesh));
if (is_multi_volume_object) {
// BBS: volume geometry not changed, so we can keep the color paint facets
if (new_vol->mmu_segmentation_facets.timestamp() == volume->mmu_segmentation_facets.timestamp())
new_vol->mmu_segmentation_facets.reset(); // BBS: let next assign take effect
new_vol->mmu_segmentation_facets.assign(volume->mmu_segmentation_facets);
// BBS: volume geometry not changed, so we can keep the paint facets
#define COPY_FACETS(f) \
if (new_vol->f.timestamp() == volume->f.timestamp()) \
new_vol->f.reset(); /* BBS: let next assign take effect */ \
new_vol->f.assign(volume->f)
COPY_FACETS(supported_facets);
COPY_FACETS(seam_facets);
COPY_FACETS(mmu_segmentation_facets);
COPY_FACETS(fuzzy_skin_facets);
} else if (saved_painting) {
// Geometry changed, attempt to remap them to the new mesh
new_vol->restore_painting(saved_painting);
}
// BBS: clear volume's config, as we already set them into object
@@ -2682,7 +2739,7 @@ std::string ModelVolume::type_to_string(const ModelVolumeType t)
// Split this volume, append the result to the object owning this volume.
// Return the number of volumes created from this one.
// This is useful to assign different materials to different volumes of an object.
size_t ModelVolume::split(unsigned int max_extruders)
size_t ModelVolume::split(unsigned int max_extruders, bool remap_paint)
{
std::vector<TriangleMesh> meshes = this->mesh().split();
if (meshes.size() <= 1)
@@ -2692,6 +2749,9 @@ size_t ModelVolume::split(unsigned int max_extruders)
if (text_configuration.has_value())
text_configuration.reset();
std::optional<TriangleSelector::SavedPainting> saved_painting = remap_paint ? save_painting() :
std::optional<TriangleSelector::SavedPainting>{};
size_t idx = 0;
size_t ivolume = std::find(this->object->volumes.begin(), this->object->volumes.end(), this) - this->object->volumes.begin();
const std::string name = this->name;
@@ -2714,11 +2774,7 @@ size_t ModelVolume::split(unsigned int max_extruders)
this->source = ModelVolume::Source();
// BBS: reset facet annotations
this->mmu_segmentation_facets.reset();
this->exterior_facets.reset();
this->supported_facets.reset();
this->seam_facets.reset();
this->fuzzy_skin_facets.reset();
this->reset_extra_facets();
}
else
this->object->volumes.insert(this->object->volumes.begin() + (++ivolume), new ModelVolume(object, *this, std::move(mesh)));
@@ -2731,6 +2787,8 @@ size_t ModelVolume::split(unsigned int max_extruders)
this->object->volumes[ivolume]->config.set("extruder", this->extruder_id());
//this->object->volumes[ivolume]->config.set("extruder", auto_extruder_id(max_extruders, extruder_counter));
this->object->volumes[ivolume]->m_is_splittable = 0;
this->object->volumes[ivolume]->restore_painting(saved_painting);
++ idx;
}

Some files were not shown because too many files have changed in this diff Show More