diff --git a/.clang-format b/.clang-format
index 6b68254ec0..440c89ec57 100644
--- a/.clang-format
+++ b/.clang-format
@@ -77,7 +77,7 @@ IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
-KeepLineBreaksForNonEmptyLines: false
+#KeepLineBreaksForNonEmptyLines: false
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
diff --git a/.gitignore b/.gitignore
index efeaa91b5f..63004bab25 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,9 @@ MANIFEST.bak
xs/MANIFEST.bak
xs/assertlib*
.init_bundle.ini
+.vs/*
local-lib
/src/TAGS
/.vscode/
+build-linux/*
+deps/build-linux/*
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 268380dc28..d771a730a9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,6 +3,7 @@ project(PrusaSlicer)
include("version.inc")
include(GNUInstallDirs)
+include(CMakeDependentOption)
set(SLIC3R_RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/resources")
file(TO_NATIVE_PATH "${SLIC3R_RESOURCES_DIR}" SLIC3R_RESOURCES_DIR_WIN)
@@ -32,6 +33,8 @@ option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
option(SLIC3R_PERL_XS "Compile XS Perl module and enable Perl unit and integration tests" 0)
option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
+# If SLIC3R_FHS is 1 -> SLIC3R_DESKTOP_INTEGRATION is always 0, othrewise variable.
+CMAKE_DEPENDENT_OPTION(SLIC3R_DESKTOP_INTEGRATION "Allow perfoming desktop integration during runtime" 1 "NOT SLIC3R_FHS" 0)
set(OPENVDB_FIND_MODULE_PATH "" CACHE PATH "Path to OpenVDB installation's find modules.")
@@ -71,6 +74,10 @@ if (SLIC3R_GUI)
add_definitions(-DSLIC3R_GUI)
endif ()
+if(SLIC3R_DESKTOP_INTEGRATION)
+ add_definitions(-DSLIC3R_DESKTOP_INTEGRATION)
+endif ()
+
if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL Clang)
set(IS_CLANG_CL TRUE)
@@ -398,7 +405,7 @@ else()
target_link_libraries(libcurl INTERFACE crypt32)
endif()
-if (SLIC3R_STATIC)
+if (SLIC3R_STATIC AND NOT SLIC3R_STATIC_EXCLUDE_CURL)
if (NOT APPLE)
# libcurl is always linked dynamically to the system libcurl on OSX.
# On other systems, libcurl is linked statically if SLIC3R_STATIC is set.
@@ -449,13 +456,13 @@ set(OpenGL_GL_PREFERENCE "LEGACY")
find_package(OpenGL REQUIRED)
# Find glew or use bundled version
-if (SLIC3R_STATIC)
+if (SLIC3R_STATIC AND NOT SLIC3R_STATIC_EXCLUDE_GLEW)
set(GLEW_USE_STATIC_LIBS ON)
set(GLEW_VERBOSE ON)
endif()
find_package(GLEW)
-if (NOT GLEW_FOUND)
+if (NOT TARGET GLEW::GLEW)
message(STATUS "GLEW not found, using bundled version.")
add_library(glew STATIC ${LIBDIR}/glew/src/glew.c)
set(GLEW_FOUND TRUE)
@@ -474,6 +481,7 @@ add_custom_target(gettext_make_pot
COMMAND xgettext --keyword=L --keyword=_L --keyword=_u8L --keyword=L_CONTEXT:1,2c --keyword=_L_PLURAL:1,2 --add-comments=TRN --from-code=UTF-8 --debug
-f "${L10N_DIR}/list.txt"
-o "${L10N_DIR}/PrusaSlicer.pot"
+ COMMAND hintsToPot ${SLIC3R_RESOURCES_DIR} ${L10N_DIR}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Generate pot file from strings in the source tree"
)
@@ -546,6 +554,8 @@ endfunction()
add_subdirectory(src)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT PrusaSlicer_app_console)
+add_dependencies(gettext_make_pot hintsToPot)
+
# Perl bindings, currently only used for the unit / integration tests of libslic3r.
# Also runs the unit / integration tests.
#FIXME Port the tests into C++ to finally get rid of the Perl!
@@ -569,7 +579,7 @@ elseif (SLIC3R_FHS)
# CMAKE_INSTALL_FULL_DATAROOTDIR: read-only architecture-independent data root (share)
set(SLIC3R_FHS_RESOURCES "${CMAKE_INSTALL_FULL_DATAROOTDIR}/PrusaSlicer")
install(DIRECTORY ${SLIC3R_RESOURCES_DIR}/ DESTINATION ${SLIC3R_FHS_RESOURCES}
- PATTERN "*/data" EXCLUDE PATTERN "*/udev" EXCLUDE
+ PATTERN "*/udev" EXCLUDE
)
install(FILES src/platform/unix/PrusaSlicer.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
install(FILES src/platform/unix/PrusaGcodeviewer.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
diff --git a/cmake/modules/FindDBus.cmake b/cmake/modules/FindDBus.cmake
index 1d0f29dd75..d54d4e516c 100644
--- a/cmake/modules/FindDBus.cmake
+++ b/cmake/modules/FindDBus.cmake
@@ -56,4 +56,4 @@ FIND_PATH(DBUS_ARCH_INCLUDE_DIR
SET(DBUS_INCLUDE_DIRS ${DBUS_INCLUDE_DIR} ${DBUS_ARCH_INCLUDE_DIR})
INCLUDE(FindPackageHandleStandardArgs)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(DBUS REQUIRED_VARS DBUS_INCLUDE_DIRS DBUS_LIBRARIES)
\ No newline at end of file
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(DBus REQUIRED_VARS DBUS_INCLUDE_DIRS DBUS_LIBRARIES)
\ No newline at end of file
diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt
index 3ce6b88a93..bc98e0b836 100644
--- a/deps/CMakeLists.txt
+++ b/deps/CMakeLists.txt
@@ -57,6 +57,11 @@ set(PATCH_CMD ${GIT_EXECUTABLE} apply --verbose --ignore-space-change --whitespa
get_property(_is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if (NOT _is_multi AND NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Release)
+ message(STATUS "Forcing CMAKE_BUILD_TYPE to Release as it was not specified.")
+endif ()
+
function(prusaslicer_add_cmake_project projectname)
cmake_parse_arguments(P_ARGS "" "INSTALL_DIR;BUILD_COMMAND;INSTALL_COMMAND" "CMAKE_ARGS" ${ARGN})
diff --git a/doc/How to build - Linux et al.md b/doc/How to build - Linux et al.md
index b23fef7728..cf47c93921 100644
--- a/doc/How to build - Linux et al.md
+++ b/doc/How to build - Linux et al.md
@@ -2,10 +2,10 @@
# Building PrusaSlicer on UNIX/Linux
PrusaSlicer uses the CMake build system and requires several dependencies.
-The dependencies can be listed in `deps/deps-linux.cmake` and `deps/deps-unix-common.cmake`, although they don't necessarily need to be as recent
-as the versions listed - generally versions available on conservative Linux distros such as Debian stable or CentOS should suffice.
+The dependencies can be listed in the `deps` directory in individual subdirectories, although they don't necessarily need to be as recent
+as the versions listed - generally versions available on conservative Linux distros such as Debian stable, Ubuntu LTS releases or Fedora are likely sufficient.
-Perl is not required any more.
+Perl is not required anymore.
In a typical situation, one would open a command line, go to the PrusaSlicer sources (**the root directory of the repository**), create a directory called `build` or similar,
`cd` into it and call:
diff --git a/resources/data/hints.ini b/resources/data/hints.ini
index 2ebf9091fe..95060f9ec6 100644
--- a/resources/data/hints.ini
+++ b/resources/data/hints.ini
@@ -1,3 +1,100 @@
+# THIS DOCUMENT CONTAINS DATA FOR HINTS NOTIFICATIONS
+#
+# Each notification is divided by
+# [hint:*name of notification*]
+#
+# Each notification MUST have text var in format:
+# text = Headline of hint\nBody of hint.
+# Headline is divided by new line (\n) from body.
+# Headline is automaticaly printed as Bold.
+# Body can contain bold marks: text to be bold (currently rendered as different color, not bold due to font limitations)
+# Body can contain hypertext: hypertext text
+# Hypertext must be max one per notification and must be closed by
+#
+# Notification can have documentation link:
+# documentation_link = https://help.prusa3d.com/en/article/name-of-article
+#
+# If notification contains hypertext, it needs to be specified by hypertext_type var.
+# each type needs to be supported with one or more additional vars.
+# These types are possible:
+#
+# Settings highlight (like search feature)
+# hypertext_type = settings
+# hypertext_settings_opt = name_of_settings (hover over settings value and copy last line of hover text)
+# hypertext_settings_type = 1 (1 - 5 according to settings tab - to be channged to name of tabs instead of numbers)
+# hypertext_settings_category = Infill (name of panel - written on left in settings)
+#
+# Plater top toolbar highlight
+# hypertext_type = plater
+# hypertext_plater_item = nameofbutton (internal name of GLToolbar items)
+#
+# Plater gizmos (left) toolbar highlight
+# hypertext_type = gizmo
+# hypertext_gizmo_item = name (name of svg icon of gizmo in resources without .svg suffix)
+#
+# Open preferences (might add item to highlight)
+# hypertext_type = preferences
+# hypertext_preferences_page = 0 (values 0-2 according to prefernces tab to be opened)
+#
+# Open gallery (no aditional var)
+# hypertext_type = gallery
+#
+#
+# Each notification can have disabled and enabled modes and techs - divided by ; and space
+# enabled_tags = ...
+# disabled_tags = ...
+# supported tags are: simple; advanced; expert; FFF; MMU; SLA; Windows; Linux; OSX;
+# Tags are case sensitive.
+# FFF is affirmative for both one or more extruder printers.
+# Algorithm shows hint only if ALL enabled tags are affirmative. (so never do enabled_tags = FFF; SLA;)
+# Algorithm shows hint only if not in all disabled tags.
+# if there are both disabled and preferred, only preferred that are not in disabled are valid.
+#
+#
+# Notifications shows in random order, already shown notifications are saved at cache/hints.cereal (as binary - human non-readable)
+# You can affect random ordering by seting weigh
+# weight = 5
+# Weight must be larger or equal to 1. Default weight is 1.
+# Weight defines probability as weight : sum_of_all_weights.
+
+[hint:Fuzzy skin]
+text = Fuzzy skin\nDid you know that you can create rough fibre-like texture on the sides of your models using theFuzzy skinfeature? You can also use modifiers to apply fuzzy-skin only to a portion of your model.
+hypertext_type = settings
+hypertext_settings_opt = fuzzy_skin
+hypertext_settings_type = 1
+hypertext_settings_category = Layers and perimeters
+disabled_tags = SLA
+
+[hint:Shapes gallery]
+text = Shapes gallery\nDid you know that PrusaSlicer has a Shapes Gallery? You can use the included models as modifiers, negative volumes or as printable objects. Right-click the platter and selectAdd Shape - Gallery.
+hypertext_type = gallery
+disable_modes = simple
+
+[hint:Auto-arrange settings]
+text = Auto-arrange settings\nDid you know that you can right-click theauto-arrange iconto adjust the size of the gap between objects and to allow automatic rotations?
+hypertext_type = plater
+hypertext_plater_item = arrange
+
+[hint:Negative volume]
+text = Negative volume\nDid you know that you can subtract one mesh from another using the Negative volume modifier? That way you can, for example, create easily resizable holes directly in PrusaSlicer. Read more in the documentation. (Requires Advanced or Expert mode.)
+hypertext_type = link
+documentation_link = https://help.prusa3d.com/en/article/negative-volume_238503
+disabled_tags = SLA; simple
+
+[hint:Simplify mesh]
+text = Simplify mesh\nDid you know that you can reduce the number of triangles in a mesh using the Simplify mesh feature? Right-click the model and select Simplify model. Read more in the documentation.
+hypertext_type = link
+documentation_link = https://help.prusa3d.com/en/article/simplify-mesh_238941
+
+[hint:Reload from disk]
+text = Reload from disk\nDid you know that if you created a newer version of your model, you can simply reload it in PrusaSlicer? Right-click the model in the 3D view and choose Reload from disk. Read more in the documentation.
+hypertext_type = link
+documentation_link = https://help.prusa3d.com/en/article/reload-from-disk_120427
+
+[hint:Hiding sidebar]
+text = Hiding sidebar\nDid you know that you can hide the right sidebar using the shortcut Shift+Tab? You can also enable the icon for this from thePreferences.
+hypertext_type = preferences
+hypertext_preferences_page = 2
[hint:Perspective camera]
text = Perspective camera\nDid you know that you can use the K key to quickly switch between an orthographic and perspective camera?
@@ -19,38 +116,24 @@ hypertext_type = settings
hypertext_settings_opt = infill_every_layers
hypertext_settings_type = 1
hypertext_settings_category = Infill
-disabled_modes = SLA; simple
-
-[hint:Hiding sidebar]
-text = Hiding sidebar\nDid you know that you can hide the right sidebar using the shortcut Shift+Tab? You can also enable the icon for this from thePreferences.
-hypertext_type = preferences
-hypertext_preferences_page = 2
+disabled_tags = SLA; simple
[hint:Variable layer height]
text = Variable layer height\nDid you know that you can print different regions of your model with a different layer height and smooth the transitions between them? Try theVariable layer height tool.(Not available for SLA printers.)
hypertext_type = plater
hypertext_plater_item = layersediting
-disabled_modes = SLA
+disabled_tags = SLA
[hint:Undo/redo history]
text = Undo/redo history\nDid you know that you can right-click theundo/redo arrowsto see the history of changes and to undo or redo several actions at once?
hypertext_type = plater
hypertext_plater_item = undo
-[hint:Auto-arrange settings]
-text = Auto-arrange settings\nDid you know that you can right-click theauto-arrange iconto adjust the size of the gap between objects and to allow automatic rotations?
-hypertext_type = plater
-hypertext_plater_item = arrange
-
-[hint:Reload from disk]
-text = Reload from disk\nDid you know that if you created a newer version of your model, you can simply reload it in PrusaSlicer? Right-click the model in the 3D view and choose Reload from disk. Read more in thedocumentation.
-hypertext_type = link
-hypertext_link = https://help.prusa3d.com/en/article/reload-from-disk_120427
-
[hint:Different layer height for each model]
-text = Different layer height for each model\nDid you know that you can print each model on the plater with a different layer height? Right-click the model in the 3D view, choose Layers and Perimeters and adjust the values in the right panel. Read more in thedocumentation.
+text = Different layer height for each model\nDid you know that you can print each model on the plater with a different layer height? Right-click the model in the 3D view, choose Layers and Perimeters and adjust the values in the right panel. Read more in the documentation.
hypertext_type = link
-hypertext_link = https://help.prusa3d.com/en/article/per-model-settings_1674
+documentation_link= https://help.prusa3d.com/en/article/per-model-settings_1674
+disabled_tags = SLA
[hint:Solid infill threshold area]
text = Solid infill threshold area\nDid you know that you can make parts of your model with a small cross-section be filled with solid infill automatically? Set theSolid infill threshold area.(Expert mode only.)
@@ -58,10 +141,10 @@ hypertext_type = settings
hypertext_settings_opt = solid_infill_below_area
hypertext_settings_type = 1
hypertext_settings_category = Infill
-disabled_modes = SLA; simple; advanced
+enabled_tags = FFF; expert
[hint:Search functionality]
-text = Search functionality\n Did you know that you use theSearchtool to quickly find a specific PrusaSlicer setting? Or use the familiar shortcut Ctrl+F.
+text = Search functionality\nDid you know that you use theSearchtool to quickly find a specific PrusaSlicer setting? Or use the familiar shortcut Ctrl+F.
hypertext_type = plater
hypertext_plater_item = search
@@ -71,11 +154,6 @@ text = Box selection\nDid you know that you can do a box selection with Shift+Mo
[hint:Zoom on selected objects or on all objects if none selected]
text =Zoom on selected objects or on all objects if none selected\nDid you know that you can zoom in on selected objects by pressing the Z key? If none are selected, the camera will zoom on all objects in the scene.
-[hint:Shapes gallery]
-text = Shapes gallery\nDid you know that PrusaSlicer has a Shapes Gallery? You can use the included models as modifiers, negative volumes or as printable objects. Right-click the platter and selectAdd Shape - Gallery.
-hypertext_type = gallery
-disable_modes = simple
-
[hint:Printable toggle]
text = Printable toggle\nDid you know that you can disable the G-code generation for the selected model without having to move or delete it? Toggle the Printable property of a model from the Right-click context menu.
@@ -89,51 +167,39 @@ text = PageUp / PageDown quick rotation by 45 degrees\nDid you know that you can
text = Load config from G-code\nDid you know that you can use File-Import Config to load print, filament and printer profiles from an existing G-code file? Similarly, you can use File-Import SL1 archive, which also lets you reconstruct 3D models from the voxel data.
[hint:Ironing]
-text = Ironing\nDid you know that you can smooth top surfaces of prints using Ironing? The nozzle will run a special second infill phase at the same layer to fill in holes and flatten any lifted plastic. Read more in thedocumentation. (Requires Advanced or Expert mode.)
+text = Ironing\nDid you know that you can smooth top surfaces of prints using Ironing? The nozzle will run a special second infill phase at the same layer to fill in holes and flatten any lifted plastic. Read more in the documentation. (Requires Advanced or Expert mode.)
hypertext_type = link
-hypertext_link = https://help.prusa3d.com/en/article/ironing_177488
-disabled_modes = SLA; simple
-
-[hint:Fuzzy skin]
-text = Fuzzy skin\nDid you know that you can create rough fibre-like texture on the sides of your models using theFuzzy skinfeature? You can also use modifiers to apply fuzzy-skin only to a portion of your model.
-hypertext_type = settings
-hypertext_settings_opt = fuzzy_skin
-hypertext_settings_type = 1
-hypertext_settings_category = Layers and perimeters
-disabled_modes = SLA
-
-[hint:Negative volume]
-text = Negative volume\nDid you know that you can subtract one mesh from another using the Negative volume modifier? That way you can, for example, create easily resizable holes directly in PrusaSlicer. Read more in thedocumentation.(Requires Advanced or Expert mode.)
-hypertext_type = link
-hypertext_link = https://help.prusa3d.com/en/article/negative-volume_238503
-disabled_modes = SLA; simple
+documentation_link = https://help.prusa3d.com/en/article/ironing_177488
+disabled_tags = SLA; simple
[hint:Paint-on supports]
text = Paint-on supports\nDid you know that you can paint directly on the object and select areas, where supports should be enforced or blocked? Try thePaint-on supportsfeature. (Requires Advanced or Expert mode.)
hypertext_type = gizmo
hypertext_gizmo_item = fdm_supports
-disabled_modes = SLA; simple
+disabled_tags = SLA; simple
[hint:Paint-on seam]
text = Paint-on seam\nDid you know that you can paint directly on the object and select where to place the start/endpoint of each perimeter loop? Try theSeam paintingfeature. (Requires Advanced or Expert mode.)
hypertext_type = gizmo
hypertext_gizmo_item = seam
-disabled_modes = SLA; simple
+disabled_tags = SLA; simple
[hint:Insert Pause]
-text = Insert Pause\nDid you know that you can schedule the print to pause at a specific layer? Right-click the layer slider in the Preview and select Add pause print (M601). This can be used to insert magnets, weights or nuts into your prints. Read more in thedocumentation.
+text = Insert Pause\nDid you know that you can schedule the print to pause at a specific layer? Right-click the layer slider in the Preview and select Add pause print (M601). This can be used to insert magnets, weights or nuts into your prints. Read more in the documentation.
hypertext_type = link
-hypertext_link = https://help.prusa3d.com/en/article/insert-pause-or-custom-g-code-at-layer_120490#insert-pause-at-layer
+documentation_link = https://help.prusa3d.com/en/article/insert-pause-or-custom-g-code-at-layer_120490#insert-pause-at-layer
+disabled_tags = SLA
[hint:Insert Custom G-code]
-text = Insert Custom G-code\nDid you know that you can insert a custom G-code at a specific layer? Right-click the layer in the Preview and select Add custom G-code. With this function you can, for example, create a temperature tower. Read more in thedocumentation.
+text = Insert Custom G-code\nDid you know that you can insert a custom G-code at a specific layer? Right-click the layer in the Preview and select Add custom G-code. With this function you can, for example, create a temperature tower. Read more in the documentation.
hypertext_type = link
-hypertext_link = https://help.prusa3d.com/en/article/insert-pause-or-custom-g-code-at-layer_120490#insert-custom-g-code-at-layer
+documentation_link = https://help.prusa3d.com/en/article/insert-pause-or-custom-g-code-at-layer_120490#insert-custom-g-code-at-layer
+disabled_tags = SLA
[hint:Configuration snapshots]
-text = Configuration snapshots\nDid you know that roll back to a complete backup of all system and user profiles? You can view and move back and forth between snapshots using the Configuration - Configuration snapshots menu. Read more in thedocumentation.
+text = Configuration snapshots\nDid you know that roll back to a complete backup of all system and user profiles? You can view and move back and forth between snapshots using the Configuration - Configuration snapshots menu. Read more in the documentation.
hypertext_type = link
-hypertext_link = https://help.prusa3d.com/en/article/configuration-snapshots_1776
+documentation_link = https://help.prusa3d.com/en/article/configuration-snapshots_1776
[hint:Minimum wall thickness]
text = Minimum wall thickness\nDid you know that instead of the number of top and bottom layers, you can define theMinimum shell thicknessin millimeters? This feature is especially useful when using the variable layer height function.
@@ -141,7 +207,7 @@ hypertext_type = settings
hypertext_settings_opt = top_solid_min_thickness
hypertext_settings_type = 1
hypertext_settings_category = Layers and perimeters
-disabled_modes = SLA
+disabled_tags = SLA
[hint:Settings in non-modal window]
text = Settings in non-modal window\nDid you know that you can open the Settings in a new non-modal window? This means you can have settings open on one screen and the G-code Preview on the other. Go to thePreferencesand select Settings in non-modal window.
@@ -149,17 +215,14 @@ hypertext_type = preferences
hypertext_preferences_page = 2
[hint:Adaptive infills]
-text = Adaptive infills\nDid you know that you can use the Adaptive cubic and Support cubic infills to decrease the print time and lower the filament consumption? Read more in thedocumentation.
+text = Adaptive infills\nDid you know that you can use the Adaptive cubic and Support cubic infills to decrease the print time and lower the filament consumption? Read more in the documentation.
hypertext_type = link
-hypertext_link = https://help.prusa3d.com/en/article/infill-patterns_177130
+documentation_link = https://help.prusa3d.com/en/article/infill-patterns_177130
+disabled_tags = SLA
[hint:Fullscreen mode]
text = Fullscreen mode\nDid you know that you can switch PrusaSlicer to fullscreen mode? Use the F11 hotkey.
-
-[hint:Simplify mesh]
-text = Simplify mesh\nDid you know that you can reduce the number of triangles in a mesh using the Simplify mesh feature? Right-click the model and select Simplify model. Read more in thedocumentation.
-hypertext_type = link
-hypertext_link = https://help.prusa3d.com/en/article/simplify-mesh_238941
+enabled_tags = Windows
#[hint:]
#text =
diff --git a/resources/icons/fuzzy_skin.svg b/resources/icons/fuzzy_skin.svg
index b8ba0a6513..f1ddc6b332 100644
--- a/resources/icons/fuzzy_skin.svg
+++ b/resources/icons/fuzzy_skin.svg
@@ -1,8 +1,13 @@
-
+
diff --git a/resources/icons/info.png b/resources/icons/info.png
deleted file mode 100644
index 9eeee9b3cd..0000000000
Binary files a/resources/icons/info.png and /dev/null differ
diff --git a/resources/icons/info.svg b/resources/icons/info.svg
new file mode 100644
index 0000000000..276b260610
--- /dev/null
+++ b/resources/icons/info.svg
@@ -0,0 +1,71 @@
+
+
diff --git a/resources/icons/mmu_segmentation.svg b/resources/icons/mmu_segmentation.svg
new file mode 100644
index 0000000000..715e6ec281
--- /dev/null
+++ b/resources/icons/mmu_segmentation.svg
@@ -0,0 +1,28 @@
+
+
+
diff --git a/resources/icons/notification_clippy.svg b/resources/icons/notification_clippy.svg
new file mode 100644
index 0000000000..406ad2bfa6
--- /dev/null
+++ b/resources/icons/notification_clippy.svg
@@ -0,0 +1,280 @@
+
+
diff --git a/resources/icons/notification_documentation.svg b/resources/icons/notification_documentation.svg
new file mode 100644
index 0000000000..21e7cfcb3c
--- /dev/null
+++ b/resources/icons/notification_documentation.svg
@@ -0,0 +1,86 @@
+
+
diff --git a/resources/icons/notification_documentation_hover.svg b/resources/icons/notification_documentation_hover.svg
new file mode 100644
index 0000000000..0c6b2e2071
--- /dev/null
+++ b/resources/icons/notification_documentation_hover.svg
@@ -0,0 +1,97 @@
+
+
diff --git a/resources/icons/objlist_info.svg b/resources/icons/objlist_info.svg
new file mode 100644
index 0000000000..6e11a9b778
--- /dev/null
+++ b/resources/icons/objlist_info.svg
@@ -0,0 +1,17 @@
+
+
+
diff --git a/resources/icons/toolbar_arrow.png b/resources/icons/toolbar_arrow.png
deleted file mode 100644
index 65905a7270..0000000000
Binary files a/resources/icons/toolbar_arrow.png and /dev/null differ
diff --git a/resources/icons/toolbar_arrow.svg b/resources/icons/toolbar_arrow.svg
index a1476bcd9e..b496451907 100644
--- a/resources/icons/toolbar_arrow.svg
+++ b/resources/icons/toolbar_arrow.svg
@@ -1,79 +1,22 @@
-
-
+
+
+
\ No newline at end of file
diff --git a/resources/icons/white/info.svg b/resources/icons/white/info.svg
new file mode 100644
index 0000000000..db227aa320
--- /dev/null
+++ b/resources/icons/white/info.svg
@@ -0,0 +1,71 @@
+
+
diff --git a/resources/profiles/Anycubic.idx b/resources/profiles/Anycubic.idx
index cc3b55ef4c..a834d2c706 100644
--- a/resources/profiles/Anycubic.idx
+++ b/resources/profiles/Anycubic.idx
@@ -1,3 +1,5 @@
+min_slic3r_version = 2.3.2-alpha0
+0.0.11 Added bed model and texture for i3 Mega, i3 Mega S.
min_slic3r_version = 2.3.1-beta
0.0.10 Various updates for Anycubic Mega. Added filament profiles.
0.0.9 Updated bed textures
diff --git a/resources/profiles/Anycubic.ini b/resources/profiles/Anycubic.ini
index c1b763879c..2cb42f0281 100644
--- a/resources/profiles/Anycubic.ini
+++ b/resources/profiles/Anycubic.ini
@@ -5,7 +5,7 @@
name = Anycubic
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded.
-config_version = 0.0.10
+config_version = 0.0.11
# Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Anycubic/
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@@ -46,12 +46,16 @@ name = Anycubic i3 Mega
variants = 0.4
technology = FFF
family = MEGA
+bed_model = i3megas_bed.stl
+bed_texture = i3megas.svg
[printer_model:I3MEGAS]
name = Anycubic i3 Mega S
variants = 0.4
technology = FFF
family = MEGA
+bed_model = i3megas_bed.stl
+bed_texture = i3megas.svg
[printer_model:PREDATOR]
name = Anycubic Predator
diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx
index d4d05f625b..37d144ff0f 100644
--- a/resources/profiles/PrusaResearch.idx
+++ b/resources/profiles/PrusaResearch.idx
@@ -1,4 +1,6 @@
min_slic3r_version = 2.4.0-alpha0
+1.4.0-alpha7 Updated brim_offset value. Updated Prusa MINI end g-code. Added Filamentworld filament profiles.
+1.4.0-alpha6 Added nozzle priming after M600. Added nozzle diameter checks for 0.8 nozzle printer profiles. Updated FW version. Increased number of top solid infill layers (0.2 layer height).
1.4.0-alpha5 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S).
1.4.0-alpha4 Decreased Area Fill (SL1S).
1.4.0-alpha3 Updated SL1S tilt times.
@@ -10,7 +12,7 @@ min_slic3r_version = 2.4.0-alpha0
1.3.0-alpha0 Disabled thick bridges, updated support settings.
min_slic3r_version = 2.3.2-alpha0
1.3.1 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S).
-1.3.0 Added SL1S profiles.
+1.3.0 Added SL1S SPEED profiles.
min_slic3r_version = 2.3.0-rc1
1.2.8 Added multiple add:north and Extrudr filament profiles.
1.2.7 Updated "Prusament PC Blend Carbon Fiber" profile for Prusa MINI.
@@ -29,6 +31,7 @@ min_slic3r_version = 2.3.0-alpha4
1.2.0-alpha1 Renamed MK3S and MINI printer profiles. Updated end g-code (MINI). Added new SLA materials and filament profiles.
1.2.0-alpha0 Added filament spool weights
min_slic3r_version = 2.2.0-alpha3
+1.1.14 Updated firmware version.
1.1.13 Updated firmware version. Updated end g-code in MMU2 printer profiles.
1.1.12 Added Prusament PVB filament profile. Added 0.8mm nozzle profiles.
1.1.11 Renamed MK3S and MINI printer profiles. Updated end g-code (MINI). Added new SLA materials and filament profiles.
@@ -52,6 +55,7 @@ min_slic3r_version = 2.2.0-alpha0
1.1.1-alpha2 Bumped up config version, so our in house customer will get updated profiles.
1.1.0 Filament aliases, Creality profiles and other goodies for PrusaSlicer 2.2.0-alpha0
min_slic3r_version = 2.1.1-beta0
+1.0.12 Updated firmware version.
1.0.11 Updated firmware version.
1.0.10 Updated firmware version for MK2.5/S and MK3/S.
1.0.9 Updated firmware version for MK2.5/S and MK3/S.
@@ -71,6 +75,7 @@ min_slic3r_version = 2.1.0-alpha0
1.0.0-alpha1 Added Prusament ASA profile
1.0.0-alpha0 Filament specific retract for PET and similar copolymers, and for FLEX
min_slic3r_version = 1.42.0-alpha6
+0.8.11 Updated firmware version.
0.8.10 Updated firmware version.
0.8.9 Updated firmware version for MK2.5/S and MK3/S.
0.8.8 Updated firmware version for MK2.5/S and MK3/S.
diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini
index 0f3fa63648..0ed5b59a6d 100644
--- a/resources/profiles/PrusaResearch.ini
+++ b/resources/profiles/PrusaResearch.ini
@@ -5,7 +5,7 @@
name = Prusa Research
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded.
-config_version = 1.4.0-alpha5
+config_version = 1.4.0-alpha7
# Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/
changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@@ -144,6 +144,7 @@ bridge_angle = 0
bridge_flow_ratio = 1
bridge_speed = 25
brim_width = 0
+brim_offset = 0.1
clip_multipart_objects = 1
compatible_printers =
complete_objects = 0
@@ -488,7 +489,7 @@ perimeter_acceleration = 800
perimeter_speed = 50
solid_infill_speed = 50
top_infill_extrusion_width = 0.4
-top_solid_layers = 5
+top_solid_layers = 6
[print:*0.25mm*]
inherits = *common*
@@ -2464,6 +2465,76 @@ inherits = addnorth Textura
filament_retract_length = nil
compatible_printers_condition = printer_model=="MK2SMM"
+[filament:Filamentworld ABS]
+inherits = *ABSC*
+filament_vendor = Filamentworld
+filament_cost = 24.9
+filament_density = 1.04
+temperature = 230
+bed_temperature = 95
+first_layer_temperature = 240
+first_layer_bed_temperature = 105
+max_fan_speed = 20
+min_fan_speed = 10
+min_print_speed = 20
+disable_fan_first_layers = 3
+fan_below_layer_time = 60
+slowdown_below_layer_time = 15
+bridge_fan_speed = 20
+compatible_printers_condition = nozzle_diameter[0]!=0.8 and printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
+
+[filament:Filamentworld ABS @MINI]
+inherits = Filamentworld ABS
+first_layer_bed_temperature = 100
+min_fan_speed = 15
+fan_below_layer_time = 60
+compatible_printers_condition = printer_model=="MINI"
+
+[filament:Filamentworld PETG]
+inherits = *PET*
+filament_vendor = Filamentworld
+filament_cost = 34.9
+filament_density = 1.27
+bed_temperature = 70
+first_layer_bed_temperature = 85
+first_layer_temperature = 240
+temperature = 235
+fan_always_on = 1
+min_fan_speed = 25
+max_fan_speed = 55
+bridge_fan_speed = 55
+slowdown_below_layer_time = 20
+min_print_speed = 20
+fan_below_layer_time = 35
+disable_fan_first_layers = 2
+full_fan_speed_layer = 0
+filament_retract_length = 1.4
+filament_max_volumetric_speed = 8
+filament_spool_weight = 0
+
+[filament:Filamentworld PETG @MINI]
+inherits = Filamentworld PETG
+filament_retract_length = nil
+filament_retract_lift = nil
+filament_retract_speed = 40
+filament_deretract_speed = 25
+filament_max_volumetric_speed = 7
+compatible_printers_condition = printer_model=="MINI"
+
+[filament:Filamentworld PLA]
+inherits = *PLA*
+filament_vendor = Filamentworld
+filament_cost = 24.9
+filament_density = 1.24
+temperature = 205
+bed_temperature = 55
+first_layer_temperature = 215
+first_layer_bed_temperature = 60
+full_fan_speed_layer = 3
+slowdown_below_layer_time = 10
+filament_spool_weight = 0
+min_print_speed = 20
+
[filament:Filament PM PETG]
inherits = *PET*
renamed_from = "Plasty Mladec PETG"
@@ -3097,6 +3168,7 @@ filament_loading_speed_start = 19
filament_minimal_purge_on_wipe_tower = 15
filament_unloading_speed_start = 100
full_fan_speed_layer = 4
+filament_max_volumetric_speed = 13
[filament:Generic PLA @MMU2]
inherits = *PLA MMU2*
@@ -5832,6 +5904,7 @@ printer_model = MK2S
printer_variant = 0.4
default_print_profile = 0.15mm OPTIMAL
default_filament_profile = Prusament PLA
+color_change_gcode = M600\nG1 E0.4 F1500 ; prime after color change
[printer:*multimaterial*]
inherits = *common*
@@ -5888,6 +5961,7 @@ variable_layer_height = 1
printer_variant = 0.25
retract_lift = 0.15
default_print_profile = 0.10mm DETAIL 0.25 nozzle
+color_change_gcode = M600\nG1 E0.3 F1500 ; prime after color change
[printer:Original Prusa i3 MK2S 0.6 nozzle]
inherits = *common*
@@ -5896,6 +5970,7 @@ min_layer_height = 0.1
nozzle_diameter = 0.6
printer_variant = 0.6
default_print_profile = 0.20mm NORMAL @0.6 nozzle
+color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
# XXXXXXXXXXXXXXXXXXX
# XXX--- MK2MM ---XXX
@@ -5937,21 +6012,21 @@ inherits = Original Prusa i3 MK2S
printer_model = MK2.5
remaining_times = 1
machine_max_jerk_e = 4.5
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
[printer:Original Prusa i3 MK2.5 0.25 nozzle]
inherits = Original Prusa i3 MK2S 0.25 nozzle
printer_model = MK2.5
remaining_times = 1
machine_max_jerk_e = 4.5
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
[printer:Original Prusa i3 MK2.5 0.6 nozzle]
inherits = Original Prusa i3 MK2S 0.6 nozzle
printer_model = MK2.5
remaining_times = 1
machine_max_jerk_e = 4.5
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
[printer:Original Prusa i3 MK2.5 0.8 nozzle]
inherits = Original Prusa i3 MK2S 0.6 nozzle
@@ -5963,9 +6038,10 @@ min_layer_height = 0.2
retract_length = 1
remaining_times = 1
machine_max_jerk_e = 4.5
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle
+color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
[printer:Original Prusa i3 MK2.5 MMU2 Single]
inherits = *25mm2*
@@ -5975,7 +6051,7 @@ max_print_height = 200
default_print_profile = 0.15mm OPTIMAL @MK2.5
default_filament_profile = Prusament PLA
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2.5\n
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\n; select extruder\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; load to nozzle\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.20 F1000\nG1 X5 E4 F1000\nG92 E0\n
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\n; select extruder\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; load to nozzle\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.20 F1000\nG1 X5 E4 F1000\nG92 E0\n
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+10, max_print_height)}{endif} F720 ; Move print head up\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM702 C\nG4 ; wait\nM104 S0 ; turn off temperature\nM900 K0 ; reset LA\nM84 ; disable motors
[printer:Original Prusa i3 MK2.5 MMU2 Single 0.8 nozzle]
@@ -5999,7 +6075,7 @@ printer_notes = Don't remove the following keywords! These keywords are used in
single_extruder_multi_material = 1
nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\nG92 E0\n
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\nG92 E0\n
end_gcode = ; Lift print head a bit\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+30, max_print_height)}{endif} ; Move print head up\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nG1 X0 Y210 F3000 ; home X axis\nM900 K0 ; reset LA\nM84 ; disable motors\n
[printer:Original Prusa i3 MK2.5S]
@@ -6026,7 +6102,7 @@ max_print_height = 200
default_print_profile = 0.15mm OPTIMAL @MK2.5
default_filament_profile = Prusament PLA
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2.5\n
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+10, max_print_height)}{endif} F720 ; Move print head up\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM702 C\nG4 ; wait\nM104 S0 ; turn off temperature\nM900 K0 ; reset LA\nM84 ; disable motors
[printer:Original Prusa i3 MK2.5S MMU2S Single 0.8 nozzle]
@@ -6037,9 +6113,10 @@ min_layer_height = 0.2
nozzle_diameter = 0.8
printer_variant = 0.8
retract_length = 1
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n
default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle
+color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
[printer:Original Prusa i3 MK2.5S MMU2S Single 0.6 nozzle]
inherits = Original Prusa i3 MK2.5S MMU2S Single
@@ -6049,6 +6126,7 @@ min_layer_height = 0.1
nozzle_diameter = 0.6
printer_variant = 0.6
default_print_profile = 0.20mm NORMAL @0.6 nozzle
+color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
[printer:Original Prusa i3 MK2.5S MMU2S Single 0.25 nozzle]
inherits = Original Prusa i3 MK2.5S MMU2S Single
@@ -6059,7 +6137,8 @@ nozzle_diameter = 0.25
printer_variant = 0.25
retract_lift = 0.15
default_print_profile = 0.10mm DETAIL 0.25 nozzle
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F1400\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F1400\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n
+color_change_gcode = M600\nG1 E0.3 F1500 ; prime after color change
[printer:Original Prusa i3 MK2.5S MMU2S]
inherits = *25mm2s*
@@ -6070,7 +6149,7 @@ printer_notes = Don't remove the following keywords! These keywords are used in
single_extruder_multi_material = 1
nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\nG92 E0\n
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\nG92 E0\n
end_gcode = ; Lift print head a bit\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+30, max_print_height)}{endif} ; Move print head up\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nG1 X0 Y210 F3000 ; home X axis\nM900 K0 ; reset LA\nM84 ; disable motors\n
[printer:Original Prusa i3 MK2.5S MMU2S 0.6 nozzle]
@@ -6080,6 +6159,7 @@ max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
default_print_profile = 0.20mm NORMAL @0.6 nozzle
+color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
[printer:Original Prusa i3 MK2.5 MMU2 0.6 nozzle]
inherits = Original Prusa i3 MK2.5 MMU2
@@ -6088,6 +6168,7 @@ max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
default_print_profile = 0.20mm NORMAL @0.6 nozzle
+color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
## 0.8mm nozzle profiles are only available for MMU2 Single mode at the moment.
@@ -6099,7 +6180,7 @@ default_print_profile = 0.20mm NORMAL @0.6 nozzle
## printer_variant = 0.8
## retract_length = 1
## default_print_profile = 0.40mm QUALITY @0.8 nozzle
-## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n
+## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n
## [printer:Original Prusa i3 MK2.5 MMU2 0.8 nozzle]
## inherits = Original Prusa i3 MK2.5 MMU2
@@ -6109,7 +6190,7 @@ default_print_profile = 0.20mm NORMAL @0.6 nozzle
## printer_variant = 0.8
## retract_length = 1
## default_print_profile = 0.40mm QUALITY @0.8 nozzle
-## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n
+## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n
# XXXXXXXXXXXXXXXXX
# XXX--- MK3 ---XXX
@@ -6139,7 +6220,7 @@ remaining_times = 1
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
retract_lift_below = 209
max_print_height = 210
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
printer_model = MK3
default_print_profile = 0.15mm QUALITY @MK3
@@ -6150,8 +6231,9 @@ max_layer_height = 0.15
min_layer_height = 0.05
printer_variant = 0.25
retract_lift = 0.15
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E8 F700 ; intro line\nG1 X100 E12.5 F700 ; intro line\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}\n\n; Don't change E value below. Excessive value can damage the printer.\n{if print_settings_id=~/.*@0.25 nozzle MK3.*/}M907 E430 ; set extruder motor current{endif}
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E8 F700 ; intro line\nG1 X100 E12.5 F700 ; intro line\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}\n\n; Don't change E value below. Excessive value can damage the printer.\n{if print_settings_id=~/.*@0.25 nozzle MK3.*/}M907 E430 ; set extruder motor current{endif}
default_print_profile = 0.10mm DETAIL @0.25 nozzle MK3
+color_change_gcode = M600\nG1 E0.3 F1500 ; prime after color change
[printer:Original Prusa i3 MK3 0.6 nozzle]
inherits = Original Prusa i3 MK3
@@ -6159,8 +6241,9 @@ nozzle_diameter = 0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}
default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
+color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
[printer:Original Prusa i3 MK3 0.8 nozzle]
inherits = Original Prusa i3 MK3
@@ -6169,9 +6252,10 @@ max_layer_height = 0.6
min_layer_height = 0.2
printer_variant = 0.8
retract_length = 1
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0\nM221 S95
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0\nM221 S95
default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle
+color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
[printer:Original Prusa i3 MK3S & MK3S+]
inherits = Original Prusa i3 MK3
@@ -6240,7 +6324,7 @@ default_filament_profile = Prusament PLA @MMU2
inherits = *mm2*
single_extruder_multi_material = 0
default_filament_profile = Prusament PLA
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+10, max_print_height)}{endif} F720 ; Move print head up\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM702 C\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nM84 ; disable motors
[printer:Original Prusa i3 MK3 MMU2 Single 0.6 nozzle]
@@ -6250,8 +6334,9 @@ nozzle_diameter = 0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
+color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
[printer:Original Prusa i3 MK3 MMU2 Single 0.8 nozzle]
inherits = Original Prusa i3 MK3 MMU2 Single 0.6 nozzle
@@ -6261,9 +6346,10 @@ max_layer_height = 0.6
min_layer_height = 0.2
printer_variant = 0.8
retract_length = 1
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle
+color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
[printer:Original Prusa i3 MK3 MMU2 Single 0.25 nozzle]
inherits = Original Prusa i3 MK3 MMU2 Single
@@ -6273,15 +6359,16 @@ max_layer_height = 0.15
min_layer_height = 0.05
printer_variant = 0.25
retract_lift = 0.15
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F1000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F1400\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E value below. Excessive value can damage the printer.\n{if print_settings_id=~/.*@0.25 nozzle MK3.*/}M907 E430 ; set extruder motor current{endif}
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F1000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F1400\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E value below. Excessive value can damage the printer.\n{if print_settings_id=~/.*@0.25 nozzle MK3.*/}M907 E430 ; set extruder motor current{endif}
default_print_profile = 0.10mm DETAIL @0.25 nozzle MK3
+color_change_gcode = M600\nG1 E0.3 F1500 ; prime after color change
[printer:Original Prusa i3 MK3 MMU2]
inherits = *mm2*
machine_max_acceleration_e = 8000,8000
nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
end_gcode = ; Lift print head a bit\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+30, max_print_height)}{endif} ; Move print head up\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nG1 X0 Y210 F3000 ; home X axis\nM84 ; disable motors\n
[printer:Original Prusa i3 MK3S & MK3S+ MMU2S Single]
@@ -6289,7 +6376,7 @@ inherits = *mm2s*
renamed_from = "Original Prusa i3 MK3S MMU2S Single"
single_extruder_multi_material = 0
default_filament_profile = Prusament PLA
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+10, max_print_height)}{endif} F720 ; Move print head up\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM702 C\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nM84 ; disable motors
[printer:Original Prusa i3 MK3S & MK3S+ MMU2S Single 0.6 nozzle]
@@ -6300,8 +6387,9 @@ nozzle_diameter = 0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
+color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
[printer:Original Prusa i3 MK3S & MK3S+ MMU2S Single 0.8 nozzle]
inherits = Original Prusa i3 MK3S & MK3S+ MMU2S Single 0.6 nozzle
@@ -6311,9 +6399,10 @@ max_layer_height = 0.6
min_layer_height = 0.2
printer_variant = 0.8
retract_length = 1
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle
+color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
[printer:Original Prusa i3 MK3S & MK3S+ MMU2S Single 0.25 nozzle]
inherits = Original Prusa i3 MK3S & MK3S+ MMU2S Single
@@ -6324,8 +6413,9 @@ max_layer_height = 0.15
min_layer_height = 0.05
printer_variant = 0.25
retract_lift = 0.15
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F1400\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E value below. Excessive value can damage the printer.\n{if print_settings_id=~/.*@0.25 nozzle MK3.*/}M907 E430 ; set extruder motor current{endif}
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F1400\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E value below. Excessive value can damage the printer.\n{if print_settings_id=~/.*@0.25 nozzle MK3.*/}M907 E430 ; set extruder motor current{endif}
default_print_profile = 0.10mm DETAIL @0.25 nozzle MK3
+color_change_gcode = M600\nG1 E0.3 F1500 ; prime after color change
[printer:Original Prusa i3 MK3S & MK3S+ MMU2S]
inherits = *mm2s*
@@ -6333,7 +6423,7 @@ renamed_from = "Original Prusa i3 MK3S MMU2S"
machine_max_acceleration_e = 8000,8000
nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
end_gcode = ; Lift print head a bit\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+30, max_print_height)}{endif} ; Move print head up\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nG1 X0 Y210 F3000 ; home X axis\nM84 ; disable motors\n
## 0.6mm nozzle MMU2/S printer profiles
@@ -6345,8 +6435,9 @@ nozzle_diameter = 0.6,0.6,0.6,0.6,0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
+color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
[printer:Original Prusa i3 MK3 MMU2 0.6 nozzle]
inherits = Original Prusa i3 MK3 MMU2
@@ -6354,8 +6445,9 @@ nozzle_diameter = 0.6,0.6,0.6,0.6,0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
-start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
+start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
+color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
## 0.8mm nozzle MMU2/S printer profiles
@@ -6367,7 +6459,7 @@ default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
## max_layer_height = 0.6
## min_layer_height = 0.2
## printer_variant = 0.8
-## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0
+## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0
## default_print_profile = 0.40mm QUALITY @0.8 nozzle
## [printer:Original Prusa i3 MK3S & MK3S+ MMU2S 0.8 nozzle]
@@ -6376,7 +6468,7 @@ default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
## max_layer_height = 0.6
## min_layer_height = 0.2
## printer_variant = 0.8
-## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0
+## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0
## default_print_profile = 0.40mm QUALITY @0.8 nozzle
## MINI
@@ -6427,9 +6519,10 @@ retract_layer_change = 1
silent_mode = 0
remaining_times = 1
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S170 ; set extruder temp for bed leveling\nM140 S[first_layer_bed_temperature] ; set bed temp\nM109 R170 ; wait for bed leveling temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM204 T1250 ; set travel acceleration\nG28 ; home all without mesh bed level\nG29 ; mesh bed leveling \nM204 T[machine_max_acceleration_travel] ; restore travel acceleration\nM104 S[first_layer_temperature] ; set extruder temp\nG92 E0\nG1 Y-2 X179 F2400\nG1 Z3 F720\nM109 S[first_layer_temperature] ; wait for extruder temp\n\n; intro line\nG1 X170 F1000\nG1 Z0.2 F720\nG1 X110 E8 F900\nG1 X40 E10 F700\nG92 E0\n\nM221 S95 ; set flow
-end_gcode = G1 E-1 F2100 ; retract\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)}{endif} F720 ; Move print head up\nG1 X178 Y178 F4200 ; park print head\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+30, max_print_height)}{endif} F720 ; Move print head further up\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM221 S100 ; reset flow\nM900 K0 ; reset LA\nM84 ; disable motors
+end_gcode = G1 E-1 F2100 ; retract\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F720 ; Move print head up{endif}\nG1 X178 Y178 F4200 ; park print head\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+30, max_print_height)} F720 ; Move print head further up{endif}\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM221 S100 ; reset flow\nM900 K0 ; reset LA\nM84 ; disable motors
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MINI\n
extruder_colour =
+color_change_gcode = M600\nG1 E0.8 F1500 ; prime after color change
[printer:Original Prusa MINI & MINI+ 0.25 nozzle]
inherits = Original Prusa MINI & MINI+
@@ -6443,6 +6536,7 @@ retract_length = 3
retract_lift = 0.15
retract_before_travel = 1
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S170 ; set extruder temp for bed leveling\nM140 S[first_layer_bed_temperature] ; set bed temp\nM109 R170 ; wait for bed leveling temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM204 T1250 ; set travel acceleration\nG28 ; home all without mesh bed level\nG29 ; mesh bed leveling \nM204 T[machine_max_acceleration_travel] ; restore travel acceleration\nM104 S[first_layer_temperature] ; set extruder temp\nG92 E0\nG1 Y-2 X179 F2400\nG1 Z3 F720\nM109 S[first_layer_temperature] ; wait for extruder temp\n\n; intro line\nG1 X170 F1000\nG1 Z0.2 F720\nG1 X110 E8 F600\nG1 X40 E10 F400\nG92 E0\n\nM221 S95 ; set flow
+color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
[printer:Original Prusa MINI & MINI+ 0.6 nozzle]
inherits = Original Prusa MINI & MINI+
@@ -6454,6 +6548,7 @@ min_layer_height = 0.15
default_print_profile = 0.30mm QUALITY @0.6 nozzle MINI
retract_length = 3.5
retract_before_travel = 1.5
+color_change_gcode = M600\nG1 E1 F1500 ; prime after color change
[printer:Original Prusa MINI & MINI+ 0.8 nozzle]
inherits = Original Prusa MINI & MINI+
@@ -6465,6 +6560,7 @@ default_print_profile = 0.40mm QUALITY @0.8 nozzle MINI
default_filament_profile = Prusament PLA @0.8 nozzle
retract_length = 3.5
retract_before_travel = 1.5
+color_change_gcode = M600\nG1 E1.2 F1500 ; prime after color change
[printer:Original Prusa SL1]
printer_technology = SLA
diff --git a/resources/shaders/mm_contour.fs b/resources/shaders/mm_contour.fs
new file mode 100644
index 0000000000..8ccf5b832c
--- /dev/null
+++ b/resources/shaders/mm_contour.fs
@@ -0,0 +1,11 @@
+#version 110
+
+const float EPSILON = 0.0001;
+
+void main()
+{
+ gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+ // Values inside depth buffer for fragments of the contour of a selected area are offset
+ // by small epsilon to solve z-fighting between painted triangles and contour lines.
+ gl_FragDepth = gl_FragCoord.z - EPSILON;
+}
diff --git a/resources/shaders/mm_contour.vs b/resources/shaders/mm_contour.vs
new file mode 100644
index 0000000000..d0d3ee42a9
--- /dev/null
+++ b/resources/shaders/mm_contour.vs
@@ -0,0 +1,6 @@
+#version 110
+
+void main()
+{
+ gl_Position = ftransform();
+}
diff --git a/resources/shaders/printbed.vs b/resources/shaders/printbed.vs
index ac47637820..7633017f12 100644
--- a/resources/shaders/printbed.vs
+++ b/resources/shaders/printbed.vs
@@ -1,12 +1,14 @@
#version 110
-attribute vec4 v_position;
+attribute vec3 v_position;
attribute vec2 v_tex_coords;
varying vec2 tex_coords;
void main()
{
- gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * v_position;
+ gl_Position = gl_ModelViewProjectionMatrix * vec4(v_position.x, v_position.y, v_position.z, 1.0);
+ // the following line leads to crash on some Intel graphics card
+ //gl_Position = gl_ModelViewProjectionMatrix * vec4(v_position, 1.0);
tex_coords = v_tex_coords;
}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index bbade8a973..9e89e82f67 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -13,6 +13,7 @@ add_subdirectory(qhull)
add_subdirectory(Shiny)
add_subdirectory(semver)
add_subdirectory(libigl)
+add_subdirectory(hints)
# Adding libnest2d project for bin packing...
add_subdirectory(libnest2d)
diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp
index 21b161456f..3490b81836 100644
--- a/src/PrusaSlicer.cpp
+++ b/src/PrusaSlicer.cpp
@@ -258,7 +258,6 @@ int CLI::run(int argc, char **argv)
Points bed = get_bed_shape(m_print_config);
ArrangeParams arrange_cfg;
arrange_cfg.min_obj_distance = scaled(min_object_distance(m_print_config));
- bool user_ensure_on_bed = true;
for (auto const &opt_key : m_transforms) {
if (opt_key == "merge") {
@@ -331,10 +330,8 @@ int CLI::run(int argc, char **argv)
}
} else if (opt_key == "dont_arrange") {
// do nothing - this option alters other transform options
- } else if (opt_key == "dont_ensure_on_bed") {
- // Remember that we saw this so we don't lift objects from the bed
- // after the other transformations are processed.
- user_ensure_on_bed = false;
+ } else if (opt_key == "ensure_on_bed") {
+ // do nothing, the value is used later
} else if (opt_key == "rotate") {
for (auto &model : m_models)
for (auto &o : model.objects)
@@ -439,7 +436,7 @@ int CLI::run(int argc, char **argv)
// All transforms have been dealt with. Now ensure that the objects are on bed.
// (Unless the user said otherwise.)
- if (user_ensure_on_bed)
+ if (m_config.opt_bool("ensure_on_bed"))
for (auto &model : m_models)
for (auto &o : model.objects)
o->ensure_on_bed();
diff --git a/src/Shiny/CMakeLists.txt b/src/Shiny/CMakeLists.txt
index 8be7592ae5..abdb96a72e 100644
--- a/src/Shiny/CMakeLists.txt
+++ b/src/Shiny/CMakeLists.txt
@@ -1,5 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12)
project(Shiny)
-cmake_minimum_required(VERSION 2.6)
add_library(Shiny STATIC
Shiny.h
diff --git a/src/admesh/CMakeLists.txt b/src/admesh/CMakeLists.txt
index 7d0177782f..217976318a 100644
--- a/src/admesh/CMakeLists.txt
+++ b/src/admesh/CMakeLists.txt
@@ -1,5 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12)
project(admesh)
-cmake_minimum_required(VERSION 2.6)
add_library(admesh STATIC
connect.cpp
diff --git a/src/boost/CMakeLists.txt b/src/boost/CMakeLists.txt
index 12fe6b4e52..e8c9e11ce6 100644
--- a/src/boost/CMakeLists.txt
+++ b/src/boost/CMakeLists.txt
@@ -1,5 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12)
project(nowide)
-cmake_minimum_required(VERSION 2.6)
add_library(nowide STATIC
nowide/args.hpp
diff --git a/src/clipper/CMakeLists.txt b/src/clipper/CMakeLists.txt
index 0362a4d849..f625088209 100644
--- a/src/clipper/CMakeLists.txt
+++ b/src/clipper/CMakeLists.txt
@@ -1,5 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12)
project(clipper)
-cmake_minimum_required(VERSION 2.6)
add_library(clipper STATIC
# We are using ClipperLib compiled as part of the libslic3r project using Slic3r::Point as its base type.
diff --git a/src/glu-libtess/CMakeLists.txt b/src/glu-libtess/CMakeLists.txt
index f3f8d024a2..8fca992a3e 100644
--- a/src/glu-libtess/CMakeLists.txt
+++ b/src/glu-libtess/CMakeLists.txt
@@ -1,5 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12)
project(glu-libtess)
-cmake_minimum_required(VERSION 2.6)
add_library(glu-libtess STATIC
src/dict-list.h
diff --git a/src/hints/CMakeLists.txt b/src/hints/CMakeLists.txt
new file mode 100644
index 0000000000..66550c7861
--- /dev/null
+++ b/src/hints/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.13)
+project(HintsToPot)
+
+add_executable(hintsToPot
+ HintsToPot.cpp)
+
+target_link_libraries(hintsToPot PRIVATE boost_libs)
+
+#encoding_check(HintsToPot)
+
+
+
diff --git a/src/hints/HintsToPot.cpp b/src/hints/HintsToPot.cpp
new file mode 100644
index 0000000000..7c8029cdeb
--- /dev/null
+++ b/src/hints/HintsToPot.cpp
@@ -0,0 +1,84 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+bool write_to_pot(boost::filesystem::path path, const std::vector>& data)
+{
+ boost::filesystem::ofstream file(std::move(path), std::ios_base::app);
+ for (const auto& element : data)
+ {
+ //Example of .pot element
+ //#: src/slic3r/GUI/GUI_App.cpp:1647 src/slic3r/GUI/wxExtensions.cpp:687
+ //msgctxt "Mode"
+ //msgid "Advanced"
+ //msgstr ""
+ file << "\n#: resources/data/hints.ini: ["<< element.first << "]\nmsgid \"" << element.second << "\"\nmsgstr \"\"\n";
+ }
+ file.close();
+ return true;
+}
+bool read_hints_ini(boost::filesystem::path path, std::vector>& pot_elements)
+{
+ namespace pt = boost::property_tree;
+ pt::ptree tree;
+ boost::nowide::ifstream ifs(path.string());
+ try {
+ pt::read_ini(ifs, tree);
+ }
+ catch (const boost::property_tree::ini_parser::ini_parser_error& err) {
+ std::cout << err.what() << std::endl;
+ return false;
+ }
+ for (const auto& section : tree) {
+ if (boost::starts_with(section.first, "hint:")) {
+ for (const auto& data : section.second) {
+ if (data.first == "text")
+ {
+ pot_elements.emplace_back(section.first, data.second.data());
+ break;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+int main(int argc, char* argv[])
+{
+ std::vector> data;
+ boost::filesystem::path path_to_ini;
+ boost::filesystem::path path_to_pot;
+ if (argc != 3)
+ {
+ std::cout << "HINTS_TO_POT FAILED: WRONG NUM OF ARGS" << std::endl;
+ return -1;
+ }
+ try {
+ path_to_ini = boost::filesystem::canonical(boost::filesystem::path(argv[1])).parent_path() / "resources" / "data" / "hints.ini";
+ path_to_pot = boost::filesystem::canonical(boost::filesystem::path(argv[2])).parent_path() / "localization" /"PrusaSlicer.pot";
+ } catch (std::exception&) {
+ std::cout << "HINTS_TO_POT FAILED: BOOST CANNONICAL" << std::endl;
+ return -1;
+ }
+
+ if (!boost::filesystem::exists(path_to_ini)){
+ std::cout << "HINTS_TO_POT FAILED: PATH TO INI DOES NOT EXISTS" << std::endl;
+ std::cout << path_to_ini.string() << std::endl;
+ return -1;
+ }
+ if (!read_hints_ini(std::move(path_to_ini), data)) {
+ std::cout << "HINTS_TO_POT FAILED TO READ HINTS INI" << std::endl;
+ return -1;
+ }
+ if (!write_to_pot(std::move(path_to_pot), data)) {
+ std::cout << "HINTS_TO_POT FAILED TO WRITE POT FILE" << std::endl;
+ return -1;
+ }
+ std::cout << "HINTS_TO_POT SUCCESS" << std::endl;
+ return 0;
+}
diff --git a/src/imgui/CMakeLists.txt b/src/imgui/CMakeLists.txt
index 50575308d2..235afe1105 100644
--- a/src/imgui/CMakeLists.txt
+++ b/src/imgui/CMakeLists.txt
@@ -1,5 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12)
project(imgui)
-cmake_minimum_required(VERSION 2.6)
add_library(imgui STATIC
imconfig.h
diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h
index dfb314d3cf..713499a1ba 100644
--- a/src/imgui/imconfig.h
+++ b/src/imgui/imconfig.h
@@ -124,32 +124,34 @@ namespace ImGui
const char ColorMarkerEnd = 0x3; // ETX
// Special ASCII characters are used here as an ikons markers
- const char PrintIconMarker = 0x4;
- const char PrinterIconMarker = 0x5;
- const char PrinterSlaIconMarker = 0x6;
- const char FilamentIconMarker = 0x7;
- const char MaterialIconMarker = 0x8;
- const char CloseNotifButton = 0xB;
- const char CloseNotifHoverButton = 0xC;
- const char MinimalizeButton = 0xE;
- const char MinimalizeHoverButton = 0xF;
- const char WarningMarker = 0x10;
- const char ErrorMarker = 0x11;
- const char EjectButton = 0x12;
- const char EjectHoverButton = 0x13;
- const char CancelButton = 0x14;
- const char CancelHoverButton = 0x15;
- const char VarLayerHeightMarker = 0x16;
+ const wchar_t PrintIconMarker = 0x4;
+ const wchar_t PrinterIconMarker = 0x5;
+ const wchar_t PrinterSlaIconMarker = 0x6;
+ const wchar_t FilamentIconMarker = 0x7;
+ const wchar_t MaterialIconMarker = 0x8;
+ const wchar_t CloseNotifButton = 0xB;
+ const wchar_t CloseNotifHoverButton = 0xC;
+ const wchar_t MinimalizeButton = 0xE;
+ const wchar_t MinimalizeHoverButton = 0xF;
+ const wchar_t WarningMarker = 0x10;
+ const wchar_t ErrorMarker = 0x11;
+ const wchar_t EjectButton = 0x12;
+ const wchar_t EjectHoverButton = 0x13;
+ const wchar_t CancelButton = 0x14;
+ const wchar_t CancelHoverButton = 0x15;
+ const wchar_t VarLayerHeightMarker = 0x16;
- const char RightArrowButton = 0x18;
- const char RightArrowHoverButton = 0x19;
- const char PreferencesButton = 0x1A;
- const char PreferencesHoverButton = 0x1B;
- const char SinkingObjectMarker = 0x1C;
- const char CustomSupportsMarker = 0x1D;
- const char CustomSeamMarker = 0x1E;
- const char MmuSegmentationMarker = 0x1F;
-
+ const wchar_t RightArrowButton = 0x18;
+ const wchar_t RightArrowHoverButton = 0x19;
+ const wchar_t PreferencesButton = 0x1A;
+ const wchar_t PreferencesHoverButton = 0x1B;
+ const wchar_t SinkingObjectMarker = 0x1C;
+ const wchar_t CustomSupportsMarker = 0x1D;
+ const wchar_t CustomSeamMarker = 0x1E;
+ const wchar_t MmuSegmentationMarker = 0x1F;
+ const wchar_t DocumentationButton = 0x2600;
+ const wchar_t DocumentationHoverButton = 0x2601;
+ const wchar_t ClippyMarker = 0x2602;
// void MyFunction(const char* name, const MyMatrix44& v);
diff --git a/src/libigl/CMakeLists.txt b/src/libigl/CMakeLists.txt
index 3daac757b1..f023826a52 100644
--- a/src/libigl/CMakeLists.txt
+++ b/src/libigl/CMakeLists.txt
@@ -1,5 +1,5 @@
-project(libigl)
cmake_minimum_required(VERSION 3.0)
+project(libigl)
add_library(libigl INTERFACE)
diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp
index 4166658f5a..177d8d708b 100644
--- a/src/libslic3r/AppConfig.cpp
+++ b/src/libslic3r/AppConfig.cpp
@@ -167,9 +167,6 @@ void AppConfig::set_defaults()
if (get("show_splash_screen").empty())
set("show_splash_screen", "1");
- if (get("last_hint").empty())
- set("last_hint", "0");
-
if (get("show_hints").empty())
set("show_hints", "1");
diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp
index 853c5e22e9..f4455fdd55 100644
--- a/src/libslic3r/Brim.cpp
+++ b/src/libslic3r/Brim.cpp
@@ -45,14 +45,40 @@ static float max_brim_width(const ConstPrintObjectPtrsAdaptor &objects)
}));
}
-static ConstPrintObjectPtrs get_top_level_objects_with_brim(const Print &print)
+// Returns ExPolygons of the bottom layer of the print object after elephant foot compensation.
+static ExPolygons get_print_object_bottom_layer_expolygons(const PrintObject &print_object)
{
+ ExPolygons ex_polygons;
+ for (LayerRegion *region : print_object.layers().front()->regions())
+ Slic3r::append(ex_polygons, offset_ex(offset_ex(region->slices.surfaces, float(SCALED_EPSILON)), -float(SCALED_EPSILON)));
+ return ex_polygons;
+}
+
+// Returns ExPolygons of bottom layer for every print object in Print after elephant foot compensation.
+static std::vector get_print_bottom_layers_expolygons(const Print &print)
+{
+ std::vector bottom_layers_expolygons;
+ bottom_layers_expolygons.reserve(print.objects().size());
+ for (const PrintObject *object : print.objects())
+ bottom_layers_expolygons.emplace_back(get_print_object_bottom_layer_expolygons(*object));
+
+ return bottom_layers_expolygons;
+}
+
+static ConstPrintObjectPtrs get_top_level_objects_with_brim(const Print &print, const std::vector &bottom_layers_expolygons)
+{
+ assert(print.objects().size() == bottom_layers_expolygons.size());
Polygons islands;
ConstPrintObjectPtrs island_to_object;
- for (const PrintObject *object : print.objects()) {
+ for(size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx) {
+ const PrintObject *object = print.objects()[print_object_idx];
+
+ if (! object->has_brim())
+ continue;
+
Polygons islands_object;
- islands_object.reserve(object->layers().front()->lslices.size());
- for (const ExPolygon &ex_poly : object->layers().front()->lslices)
+ islands_object.reserve(bottom_layers_expolygons[print_object_idx].size());
+ for (const ExPolygon &ex_poly : bottom_layers_expolygons[print_object_idx])
islands_object.emplace_back(ex_poly.contour);
islands.reserve(islands.size() + object->instances().size() * islands_object.size());
@@ -110,7 +136,7 @@ static Polygons top_level_outer_brim_islands(const ConstPrintObjectPtrs &top_lev
//FIXME how about the brim type?
auto brim_offset = float(scale_(object->config().brim_offset.value));
Polygons islands_object;
- for (const ExPolygon &ex_poly : object->layers().front()->lslices) {
+ for (const ExPolygon &ex_poly : get_print_object_bottom_layer_expolygons(*object)) {
Polygons contour_offset = offset(ex_poly.contour, brim_offset);
for (Polygon &poly : contour_offset)
poly.douglas_peucker(SCALED_RESOLUTION);
@@ -124,8 +150,12 @@ static Polygons top_level_outer_brim_islands(const ConstPrintObjectPtrs &top_lev
return islands;
}
-static ExPolygons top_level_outer_brim_area(const Print &print, const ConstPrintObjectPtrs &top_level_objects_with_brim, const float no_brim_offset)
+static ExPolygons top_level_outer_brim_area(const Print &print,
+ const ConstPrintObjectPtrs &top_level_objects_with_brim,
+ const std::vector &bottom_layers_expolygons,
+ const float no_brim_offset)
{
+ assert(print.objects().size() == bottom_layers_expolygons.size());
std::unordered_set top_level_objects_idx;
top_level_objects_idx.reserve(top_level_objects_with_brim.size());
for (const PrintObject *object : top_level_objects_with_brim)
@@ -133,15 +163,16 @@ static ExPolygons top_level_outer_brim_area(const Print &print, const ConstPrint
ExPolygons brim_area;
ExPolygons no_brim_area;
- for (const PrintObject *object : print.objects()) {
- const BrimType brim_type = object->config().brim_type.value;
- const float brim_offset = scale_(object->config().brim_offset.value);
- const float brim_width = scale_(object->config().brim_width.value);
- const bool is_top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end();
+ for(size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx) {
+ const PrintObject *object = print.objects()[print_object_idx];
+ const BrimType brim_type = object->config().brim_type.value;
+ const float brim_offset = scale_(object->config().brim_offset.value);
+ const float brim_width = scale_(object->config().brim_width.value);
+ const bool is_top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end();
ExPolygons brim_area_object;
ExPolygons no_brim_area_object;
- for (const ExPolygon &ex_poly : object->layers().front()->lslices) {
+ for (const ExPolygon &ex_poly : bottom_layers_expolygons[print_object_idx]) {
if ((brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner) && is_top_outer_brim)
append(brim_area_object, diff_ex(offset(ex_poly.contour, brim_width + brim_offset), offset(ex_poly.contour, brim_offset)));
@@ -166,8 +197,12 @@ static ExPolygons top_level_outer_brim_area(const Print &print, const ConstPrint
return diff_ex(brim_area, no_brim_area);
}
-static ExPolygons inner_brim_area(const Print &print, const ConstPrintObjectPtrs &top_level_objects_with_brim, const float no_brim_offset)
+static ExPolygons inner_brim_area(const Print &print,
+ const ConstPrintObjectPtrs &top_level_objects_with_brim,
+ const std::vector &bottom_layers_expolygons,
+ const float no_brim_offset)
{
+ assert(print.objects().size() == bottom_layers_expolygons.size());
std::unordered_set top_level_objects_idx;
top_level_objects_idx.reserve(top_level_objects_with_brim.size());
for (const PrintObject *object : top_level_objects_with_brim)
@@ -176,16 +211,17 @@ static ExPolygons inner_brim_area(const Print &print, const ConstPrintObjectPtrs
ExPolygons brim_area;
ExPolygons no_brim_area;
Polygons holes;
- for (const PrintObject *object : print.objects()) {
- const BrimType brim_type = object->config().brim_type.value;
- const float brim_offset = scale_(object->config().brim_offset.value);
- const float brim_width = scale_(object->config().brim_width.value);
- const bool top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end();
+ for(size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx) {
+ const PrintObject *object = print.objects()[print_object_idx];
+ const BrimType brim_type = object->config().brim_type.value;
+ const float brim_offset = scale_(object->config().brim_offset.value);
+ const float brim_width = scale_(object->config().brim_width.value);
+ const bool top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end();
ExPolygons brim_area_object;
ExPolygons no_brim_area_object;
Polygons holes_object;
- for (const ExPolygon &ex_poly : object->layers().front()->lslices) {
+ for (const ExPolygon &ex_poly : bottom_layers_expolygons[print_object_idx]) {
if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner) {
if (top_outer_brim)
no_brim_area_object.emplace_back(ex_poly);
@@ -204,7 +240,7 @@ static ExPolygons inner_brim_area(const Print &print, const ConstPrintObjectPtrs
append(holes_object, ex_poly.holes);
}
- append(no_brim_area_object, offset_ex(object->layers().front()->lslices, brim_offset));
+ append(no_brim_area_object, offset_ex(bottom_layers_expolygons[print_object_idx], brim_offset));
for (const PrintInstance &instance : object->instances()) {
append_and_translate(brim_area, brim_area_object, instance);
@@ -236,7 +272,7 @@ static void optimize_polylines_by_reversing(Polylines *polylines)
static Polylines connect_brim_lines(Polylines &&polylines, const Polygons &brim_area, float max_connection_length)
{
if (polylines.empty())
- return Polylines();
+ return {};
BoundingBox bbox = get_extents(polylines);
bbox.merge(get_extents(brim_area));
@@ -305,16 +341,20 @@ static Polylines connect_brim_lines(Polylines &&polylines, const Polygons &brim_
}
}
if (end < polylines.size())
- polylines.erase(polylines.begin() + end, polylines.end());
+ polylines.erase(polylines.begin() + int(end), polylines.end());
}
return std::move(polylines);
}
-static void make_inner_brim(const Print &print, const ConstPrintObjectPtrs &top_level_objects_with_brim, ExtrusionEntityCollection &brim)
+static void make_inner_brim(const Print &print,
+ const ConstPrintObjectPtrs &top_level_objects_with_brim,
+ const std::vector &bottom_layers_expolygons,
+ ExtrusionEntityCollection &brim)
{
+ assert(print.objects().size() == bottom_layers_expolygons.size());
Flow flow = print.brim_flow();
- ExPolygons islands_ex = inner_brim_area(print, top_level_objects_with_brim, float(flow.scaled_spacing()));
+ ExPolygons islands_ex = inner_brim_area(print, top_level_objects_with_brim, bottom_layers_expolygons, float(flow.scaled_spacing()));
Polygons loops;
islands_ex = offset_ex(islands_ex, -0.5f * float(flow.scaled_spacing()), jtSquare);
for (size_t i = 0; !islands_ex.empty(); ++i) {
@@ -334,11 +374,12 @@ static void make_inner_brim(const Print &print, const ConstPrintObjectPtrs &top_
// Collect islands_area to be merged into the final 1st layer convex hull.
ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cancel, Polygons &islands_area)
{
- Flow flow = print.brim_flow();
- ConstPrintObjectPtrs top_level_objects_with_brim = get_top_level_objects_with_brim(print);
- Polygons islands = top_level_outer_brim_islands(top_level_objects_with_brim);
- ExPolygons islands_area_ex = top_level_outer_brim_area(print, top_level_objects_with_brim, float(flow.scaled_spacing()));
- islands_area = to_polygons(islands_area_ex);
+ Flow flow = print.brim_flow();
+ std::vector bottom_layers_expolygons = get_print_bottom_layers_expolygons(print);
+ ConstPrintObjectPtrs top_level_objects_with_brim = get_top_level_objects_with_brim(print, bottom_layers_expolygons);
+ Polygons islands = top_level_outer_brim_islands(top_level_objects_with_brim);
+ ExPolygons islands_area_ex = top_level_outer_brim_area(print, top_level_objects_with_brim, bottom_layers_expolygons, float(flow.scaled_spacing()));
+ islands_area = to_polygons(islands_area_ex);
Polygons loops;
size_t num_loops = size_t(floor(max_brim_width(print.objects()) / flow.spacing()));
@@ -536,7 +577,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
extrusion_entities_append_loops_and_paths(brim.entities, std::move(all_loops), erSkirt, float(flow.mm3_per_mm()), float(flow.width()), float(print.skirt_first_layer_height()));
}
- make_inner_brim(print, top_level_objects_with_brim, brim);
+ make_inner_brim(print, top_level_objects_with_brim, bottom_layers_expolygons, brim);
return brim;
}
diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index 28865149f7..f9bef903bc 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -178,6 +178,8 @@ add_library(libslic3r STATIC
PrintRegion.cpp
PNGReadWrite.hpp
PNGReadWrite.cpp
+ QuadricEdgeCollapse.cpp
+ QuadricEdgeCollapse.hpp
Semver.cpp
ShortestPath.cpp
ShortestPath.hpp
diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp
index b9f9b266dc..c8a3835dde 100644
--- a/src/libslic3r/Config.cpp
+++ b/src/libslic3r/Config.cpp
@@ -223,10 +223,13 @@ std::vector ConfigOptionDef::cli_args(const std::string &key) const
{
std::vector args;
if (this->cli != ConfigOptionDef::nocli) {
- std::string cli = this->cli.substr(0, this->cli.find("="));
- boost::trim_right_if(cli, boost::is_any_of("!"));
+ const std::string &cli = this->cli;
+ //FIXME What was that for? Check the "readline" documentation.
+ // Neither '=' nor '!' is used in any of the cli parameters currently defined by PrusaSlicer.
+// std::string cli = this->cli.substr(0, this->cli.find("="));
+// boost::trim_right_if(cli, boost::is_any_of("!"));
if (cli.empty()) {
- // Add the key
+ // Convert an option key to CLI argument by replacing underscores with dashes.
std::string opt = key;
boost::replace_all(opt, "_", "-");
args.emplace_back(std::move(opt));
@@ -245,7 +248,7 @@ ConfigOption* ConfigOptionDef::create_empty_option() const
case coPercents: return new ConfigOptionPercentsNullable();
case coFloatsOrPercents: return new ConfigOptionFloatsOrPercentsNullable();
case coBools: return new ConfigOptionBoolsNullable();
- default: throw Slic3r::RuntimeError(std::string("Unknown option type for nullable option ") + this->label);
+ default: throw ConfigurationError(std::string("Unknown option type for nullable option ") + this->label);
}
} else {
switch (this->type) {
@@ -266,7 +269,7 @@ ConfigOption* ConfigOptionDef::create_empty_option() const
case coBool: return new ConfigOptionBool();
case coBools: return new ConfigOptionBools();
case coEnum: return new ConfigOptionEnumGeneric(this->enum_keys_map);
- default: throw Slic3r::RuntimeError(std::string("Unknown option type for option ") + this->label);
+ default: throw ConfigurationError(std::string("Unknown option type for option ") + this->label);
}
}
}
@@ -423,7 +426,19 @@ void ConfigBase::apply_only(const ConfigBase &other, const t_config_option_keys
}
}
-// this will *ignore* options not present in both configs
+// Are the two configs equal? Ignoring options not present in both configs.
+bool ConfigBase::equals(const ConfigBase &other) const
+{
+ for (const t_config_option_key &opt_key : this->keys()) {
+ const ConfigOption *this_opt = this->option(opt_key);
+ const ConfigOption *other_opt = other.option(opt_key);
+ if (this_opt != nullptr && other_opt != nullptr && *this_opt != *other_opt)
+ return false;
+ }
+ return true;
+}
+
+// Returns options differing in the two configs, ignoring options not present in both configs.
t_config_option_keys ConfigBase::diff(const ConfigBase &other) const
{
t_config_option_keys diff;
@@ -436,6 +451,7 @@ t_config_option_keys ConfigBase::diff(const ConfigBase &other) const
return diff;
}
+// Returns options being equal in the two configs, ignoring options not present in both configs.
t_config_option_keys ConfigBase::equal(const ConfigBase &other) const
{
t_config_option_keys equal;
@@ -494,7 +510,7 @@ bool ConfigBase::set_deserialize_nothrow(const t_config_option_key &opt_key_src,
void ConfigBase::set_deserialize(const t_config_option_key &opt_key_src, const std::string &value_src, ConfigSubstitutionContext& substitutions_ctxt, bool append)
{
if (! this->set_deserialize_nothrow(opt_key_src, value_src, substitutions_ctxt, append))
- throw BadOptionTypeException(format("ConfigBase::set_deserialize() failed for parameter \"%1%\", value \"%2%\"", opt_key_src, value_src));
+ throw BadOptionValueException(format("Invalid value provided for parameter %1%: %2%", opt_key_src, value_src));
}
void ConfigBase::set_deserialize(std::initializer_list items, ConfigSubstitutionContext& substitutions_ctxt)
@@ -539,26 +555,50 @@ bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, con
ConfigOption *opt = this->option(opt_key, true);
assert(opt != nullptr);
- bool success = opt->deserialize(value, append);
- if (! success && substitutions_ctxt.rule != ForwardCompatibilitySubstitutionRule::Disable &&
- // Only allow substitutions of an enum value by another enum value or a boolean value with an enum value.
- // That means, we expect enum values being added in the future and possibly booleans being converted to enums.
- (optdef->type == coEnum || optdef->type == coBool))
- {
- // Deserialize failed, try to substitute with a default value.
- assert(substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable || substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::EnableSilent);
+ bool success = false;
+ bool substituted = false;
+ if (optdef->type == coBools && substitutions_ctxt.rule != ForwardCompatibilitySubstitutionRule::Disable) {
+ //FIXME Special handling of vectors of bools, quick and not so dirty solution before PrusaSlicer 2.3.2 release.
+ bool nullable = opt->nullable();
+ ConfigHelpers::DeserializationSubstitution default_value = ConfigHelpers::DeserializationSubstitution::DefaultsToFalse;
+ if (optdef->default_value) {
+ // Default value for vectors of booleans used in a "per extruder" context, thus the default contains just a single value.
+ assert(dynamic_cast*>(optdef->default_value.get()));
+ auto &values = static_cast*>(optdef->default_value.get())->values;
+ if (values.size() == 1 && values.front() == 1)
+ default_value = ConfigHelpers::DeserializationSubstitution::DefaultsToTrue;
+ }
+ auto result = nullable ?
+ static_cast(opt)->deserialize_with_substitutions(value, append, default_value) :
+ static_cast(opt)->deserialize_with_substitutions(value, append, default_value);
+ success = result != ConfigHelpers::DeserializationResult::Failed;
+ substituted = result == ConfigHelpers::DeserializationResult::Substituted;
+ } else {
+ success = opt->deserialize(value, append);
+ if (! success && substitutions_ctxt.rule != ForwardCompatibilitySubstitutionRule::Disable &&
+ // Only allow substitutions of an enum value by another enum value or a boolean value with an enum value.
+ // That means, we expect enum values being added in the future and possibly booleans being converted to enums.
+ (optdef->type == coEnum || optdef->type == coBool) && ConfigHelpers::looks_like_enum_value(value)) {
+ // Deserialize failed, try to substitute with a default value.
+ assert(substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable || substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::EnableSilent);
+ if (optdef->type == coBool)
+ static_cast(opt)->value = ConfigHelpers::enum_looks_like_true_value(value);
+ else
+ // Just use the default of the option.
+ opt->set(optdef->default_value.get());
+ success = true;
+ substituted = true;
+ }
+ }
- opt->set(optdef->default_value.get());
-
- if (substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable) {
- // Log the substitution.
- ConfigSubstitution config_substitution;
- config_substitution.opt_def = optdef;
- config_substitution.old_value = value;//std::unique_ptr(opt);
- config_substitution.new_value = ConfigOptionUniquePtr(this->option(opt_key, true)->clone());
- substitutions_ctxt.substitutions.emplace_back(std::move(config_substitution));
- }
- return true;
+ if (substituted && (substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable ||
+ substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::EnableSystemSilent)) {
+ // Log the substitution.
+ ConfigSubstitution config_substitution;
+ config_substitution.opt_def = optdef;
+ config_substitution.old_value = value;
+ config_substitution.new_value = ConfigOptionUniquePtr(opt->clone());
+ substitutions_ctxt.substitutions.emplace_back(std::move(config_substitution));
}
return success;
}
@@ -585,7 +625,7 @@ double ConfigBase::get_abs_value(const t_config_option_key &opt_key) const
return opt_def->ratio_over.empty() ? 0. :
static_cast(raw_opt)->get_abs_value(this->get_abs_value(opt_def->ratio_over));
}
- throw Slic3r::RuntimeError("ConfigBase::get_abs_value(): Not a valid option type for get_abs_value()");
+ throw ConfigurationError("ConfigBase::get_abs_value(): Not a valid option type for get_abs_value()");
}
// Return an absolute value of a possibly relative config variable.
@@ -596,7 +636,7 @@ double ConfigBase::get_abs_value(const t_config_option_key &opt_key, double rati
const ConfigOption *raw_opt = this->option(opt_key);
assert(raw_opt != nullptr);
if (raw_opt->type() != coFloatOrPercent)
- throw Slic3r::RuntimeError("ConfigBase::get_abs_value(): opt_key is not of coFloatOrPercent");
+ throw ConfigurationError("ConfigBase::get_abs_value(): opt_key is not of coFloatOrPercent");
// Compute absolute value.
return static_cast(raw_opt)->get_abs_value(ratio_over);
}
@@ -622,18 +662,71 @@ void ConfigBase::setenv_() const
ConfigSubstitutions ConfigBase::load(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
return is_gcode_file(file) ?
- this->load_from_gcode_file(file, true /* check header */, compatibility_rule) :
+ this->load_from_gcode_file(file, compatibility_rule) :
this->load_from_ini(file, compatibility_rule);
}
ConfigSubstitutions ConfigBase::load_from_ini(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule)
+{
+ try {
+ boost::property_tree::ptree tree;
+ boost::nowide::ifstream ifs(file);
+ boost::property_tree::read_ini(ifs, tree);
+ return this->load(tree, compatibility_rule);
+ } catch (const ConfigurationError &e) {
+ throw ConfigurationError(format("Failed loading configuration file \"%1%\": %2%", file, e.what()));
+ }
+}
+
+ConfigSubstitutions ConfigBase::load_from_ini_string(const std::string &data, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
boost::property_tree::ptree tree;
- boost::nowide::ifstream ifs(file);
- boost::property_tree::read_ini(ifs, tree);
+ std::istringstream iss(data);
+ boost::property_tree::read_ini(iss, tree);
return this->load(tree, compatibility_rule);
}
+// Loading a "will be one day a legacy format" of configuration stored into 3MF or AMF.
+// Accepts the same data as load_from_ini_string(), only with each configuration line possibly prefixed with a semicolon (G-code comment).
+ConfigSubstitutions ConfigBase::load_from_ini_string_commented(std::string &&data, ForwardCompatibilitySubstitutionRule compatibility_rule)
+{
+ // Convert the "data" string into INI format by removing the semi-colons at the start of a line.
+ // Also the "; generated by PrusaSlicer ..." comment line will be removed.
+ size_t j = 0;
+ for (size_t i = 0; i < data.size();)
+ if (i == 0 || data[i] == '\n') {
+ // Start of a line.
+ if (i != 0) {
+ // Consume LF.
+ assert(data[i] == '\n');
+ // Don't keep empty lines.
+ if (j > 0 && data[j - 1] != '\n')
+ data[j ++] = data[i];
+ ++ i;
+ }
+ // Skip all leading spaces;
+ for (; i < data.size() && (data[i] == ' ' || data[i] == '\t'); ++ i) ;
+ // Skip the semicolon (comment indicator).
+ if (i < data.size() && data[i] == ';')
+ ++ i;
+ // Skip all leading spaces after semicolon.
+ for (; i < data.size() && (data[i] == ' ' || data[i] == '\t'); ++ i) ;
+ if (strncmp(data.data() + i, "generated by ", 13) == 0) {
+ // Skip the "; generated by ..." line.
+ for (; i < data.size() && data[i] != '\n'; ++ i);
+ }
+ } else if (data[i] == '\r' && i + 1 < data.size() && data[i + 1] == '\n') {
+ // Skip CR.
+ ++ i;
+ } else {
+ // Consume the rest of the data.
+ data[j ++] = data[i ++];
+ }
+ data.erase(data.begin() + j, data.end());
+
+ return this->load_from_ini_string(data, compatibility_rule);
+}
+
ConfigSubstitutions ConfigBase::load(const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
ConfigSubstitutionContext substitutions_ctxt(compatibility_rule);
@@ -648,37 +741,8 @@ ConfigSubstitutions ConfigBase::load(const boost::property_tree::ptree &tree, Fo
return std::move(substitutions_ctxt.substitutions);
}
-// Load the config keys from the tail of a G-code file.
-ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, bool check_header, ForwardCompatibilitySubstitutionRule compatibility_rule)
-{
- // Read a 64k block from the end of the G-code.
- boost::nowide::ifstream ifs(file);
- if (check_header) {
- const char slic3r_gcode_header[] = "; generated by Slic3r ";
- const char prusaslicer_gcode_header[] = "; generated by PrusaSlicer ";
- std::string firstline;
- std::getline(ifs, firstline);
- if (strncmp(slic3r_gcode_header, firstline.c_str(), strlen(slic3r_gcode_header)) != 0 &&
- strncmp(prusaslicer_gcode_header, firstline.c_str(), strlen(prusaslicer_gcode_header)) != 0)
- throw Slic3r::RuntimeError("Not a PrusaSlicer / Slic3r PE generated g-code.");
- }
- ifs.seekg(0, ifs.end);
- auto file_length = ifs.tellg();
- auto data_length = std::min(65535, file_length);
- ifs.seekg(file_length - data_length, ifs.beg);
- std::vector data(size_t(data_length) + 1, 0);
- ifs.read(data.data(), data_length);
- ifs.close();
-
- ConfigSubstitutionContext substitutions_ctxt(compatibility_rule);
- size_t key_value_pairs = load_from_gcode_string(data.data(), substitutions_ctxt);
- if (key_value_pairs < 80)
- throw Slic3r::RuntimeError(format("Suspiciously low number of configuration values extracted from %1%: %2%", file, key_value_pairs));
- return std::move(substitutions_ctxt.substitutions);
-}
-
// Load the config keys from the given string.
-size_t ConfigBase::load_from_gcode_string(const char* str, ConfigSubstitutionContext& substitutions)
+static inline size_t load_from_gcode_string_legacy(ConfigBase &config, const char *str, ConfigSubstitutionContext &substitutions)
{
if (str == nullptr)
return 0;
@@ -701,7 +765,7 @@ size_t ConfigBase::load_from_gcode_string(const char* str, ConfigSubstitutionCon
if (end - (++ start) < 10 || start[0] != ';' || start[1] != ' ')
break;
const char *key = start + 2;
- if (!(*key >= 'a' && *key <= 'z') || (*key >= 'A' && *key <= 'Z'))
+ if (!((*key >= 'a' && *key <= 'z') || (*key >= 'A' && *key <= 'Z')))
// A key must start with a letter.
break;
const char *sep = key;
@@ -723,7 +787,7 @@ size_t ConfigBase::load_from_gcode_string(const char* str, ConfigSubstitutionCon
if (key == nullptr)
break;
try {
- this->set_deserialize(std::string(key, key_end), std::string(value, end), substitutions);
+ config.set_deserialize(std::string(key, key_end), std::string(value, end), substitutions);
++num_key_value_pairs;
}
catch (UnknownOptionException & /* e */) {
@@ -732,7 +796,175 @@ size_t ConfigBase::load_from_gcode_string(const char* str, ConfigSubstitutionCon
end = start;
}
- return num_key_value_pairs;
+ return num_key_value_pairs;
+}
+
+// Reading a config from G-code back to front for performance reasons: We don't want to scan
+// hundreds of MB file for a short config block, which we expect to find at the end of the G-code.
+class ReverseLineReader
+{
+public:
+ using pos_type = boost::nowide::ifstream::pos_type;
+
+ // Stop at file_start
+ ReverseLineReader(boost::nowide::ifstream &ifs, pos_type file_start) : m_ifs(ifs), m_file_start(file_start)
+ {
+ m_ifs.seekg(0, m_ifs.end);
+ m_file_pos = m_ifs.tellg();
+ m_block.assign(m_block_size, 0);
+ }
+
+ bool getline(std::string &out) {
+ out.clear();
+ for (;;) {
+ if (m_block_len == 0) {
+ // Read the next block.
+ m_block_len = size_t(std::min(m_block_size, m_file_pos - m_file_start));
+ if (m_block_len == 0)
+ return false;
+ m_file_pos -= m_block_len;
+ m_ifs.seekg(m_file_pos, m_ifs.beg);
+ if (! m_ifs.read(m_block.data(), m_block_len))
+ return false;
+ }
+
+ assert(m_block_len > 0);
+ // Non-empty buffer. Find another LF.
+ int i = int(m_block_len) - 1;
+ for (; i >= 0; -- i)
+ if (m_block[i] == '\n')
+ break;
+ // i is position of LF or -1 if not found.
+ if (i == -1) {
+ // LF not found. Just make a backup of the buffer and continue.
+ out.insert(out.begin(), m_block.begin(), m_block.begin() + m_block_len);
+ m_block_len = 0;
+ } else {
+ assert(i >= 0);
+ // Copy new line to the output. It may be empty.
+ out.insert(out.begin(), m_block.begin() + i + 1, m_block.begin() + m_block_len);
+ // Block length without the newline.
+ m_block_len = i;
+ // Remove CRLF from the end of the block.
+ if (m_block_len > 0 && m_block[m_block_len - 1] == '\r')
+ -- m_block_len;
+ return true;
+ }
+ }
+ assert(false);
+ return false;
+ }
+
+private:
+ boost::nowide::ifstream &m_ifs;
+ std::vector m_block;
+ size_t m_block_size = 65536;
+ size_t m_block_len = 0;
+ pos_type m_file_start;
+ pos_type m_file_pos = 0;
+};
+
+// Load the config keys from the tail of a G-code file.
+ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule)
+{
+ // Read a 64k block from the end of the G-code.
+ boost::nowide::ifstream ifs(file);
+ // Look for Slic3r or PrusaSlicer header.
+ // Look for the header across the whole file as the G-code may have been extended at the start by a post-processing script or the user.
+ bool has_delimiters = false;
+ {
+ static constexpr const char slic3r_gcode_header[] = "; generated by Slic3r ";
+ static constexpr const char prusaslicer_gcode_header[] = "; generated by PrusaSlicer ";
+ std::string header;
+ bool header_found = false;
+ while (std::getline(ifs, header)) {
+ if (strncmp(slic3r_gcode_header, header.c_str(), strlen(slic3r_gcode_header)) == 0) {
+ header_found = true;
+ break;
+ } else if (strncmp(prusaslicer_gcode_header, header.c_str(), strlen(prusaslicer_gcode_header)) == 0) {
+ // Parse PrusaSlicer version.
+ size_t i = strlen(prusaslicer_gcode_header);
+ for (; i < header.size() && header[i] == ' '; ++ i) ;
+ size_t j = i;
+ for (; j < header.size() && header[j] != ' '; ++ j) ;
+ try {
+ Semver semver(header.substr(i, j - i));
+ has_delimiters = semver >= Semver(2, 4, 0, nullptr, "alpha0");
+ } catch (const RuntimeError &) {
+ }
+ header_found = true;
+ break;
+ }
+ }
+ if (! header_found)
+ throw Slic3r::RuntimeError("Not a PrusaSlicer / Slic3r PE generated g-code.");
+ }
+
+ auto header_end_pos = ifs.tellg();
+ ConfigSubstitutionContext substitutions_ctxt(compatibility_rule);
+ size_t key_value_pairs = 0;
+
+ if (has_delimiters)
+ {
+ // PrusaSlicer starting with 2.4.0-alpha0 delimits the config section stored into G-code with
+ // ; prusaslicer_config = begin
+ // ...
+ // ; prusaslicer_config = end
+ // The begin / end tags look like any other key / value pairs on purpose to be compatible with older G-code viewer.
+ // Read the file in reverse line by line.
+ ReverseLineReader reader(ifs, header_end_pos);
+ // Read the G-code file by 64k blocks back to front.
+ bool begin_found = false;
+ bool end_found = false;
+ std::string line;
+ while (reader.getline(line))
+ if (line == "; prusaslicer_config = end") {
+ end_found = true;
+ break;
+ }
+ if (! end_found)
+ throw Slic3r::RuntimeError(format("Configuration block closing tag \"; prusaslicer_config = end\" not found when reading %1%", file));
+ std::string key, value;
+ while (reader.getline(line)) {
+ if (line == "; prusaslicer_config = begin") {
+ begin_found = true;
+ break;
+ }
+ // line should be a valid key = value pair.
+ auto pos = line.find('=');
+ if (pos != std::string::npos && pos > 1 && line.front() == ';') {
+ key = line.substr(1, pos - 1);
+ value = line.substr(pos + 1);
+ boost::trim(key);
+ boost::trim(value);
+ try {
+ this->set_deserialize(key, value, substitutions_ctxt);
+ ++ key_value_pairs;
+ } catch (UnknownOptionException & /* e */) {
+ // ignore
+ }
+ }
+ }
+ if (! begin_found)
+ throw Slic3r::RuntimeError(format("Configuration block opening tag \"; prusaslicer_config = begin\" not found when reading %1%", file));
+ }
+ else
+ {
+ // Slic3r or PrusaSlicer older than 2.4.0-alpha0 do not emit any delimiter.
+ // Try a heuristics reading the G-code from back.
+ ifs.seekg(0, ifs.end);
+ auto file_length = ifs.tellg();
+ auto data_length = std::min(65535, file_length - header_end_pos);
+ ifs.seekg(file_length - data_length, ifs.beg);
+ std::vector data(size_t(data_length) + 1, 0);
+ ifs.read(data.data(), data_length);
+ ifs.close();
+ key_value_pairs = load_from_gcode_string_legacy(*this, data.data(), substitutions_ctxt);
+ }
+
+ if (key_value_pairs < 80)
+ throw Slic3r::RuntimeError(format("Suspiciously low number of configuration values extracted from %1%: %2%", file, key_value_pairs));
+ return std::move(substitutions_ctxt.substitutions);
}
void ConfigBase::save(const std::string &file) const
@@ -803,7 +1035,7 @@ ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool cre
throw NoDefinitionException(opt_key);
const ConfigOptionDef *optdef = def->get(opt_key);
if (optdef == nullptr)
-// throw Slic3r::RuntimeError(std::string("Invalid option name: ") + opt_key);
+// throw ConfigurationError(std::string("Invalid option name: ") + opt_key);
// Let the parent decide what to do if the opt_key is not defined by this->def().
return nullptr;
ConfigOption *opt = optdef->create_default_option();
@@ -817,22 +1049,12 @@ const ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key) co
return (it == options.end()) ? nullptr : it->second.get();
}
-void DynamicConfig::read_cli(const std::vector &tokens, t_config_option_keys* extra, t_config_option_keys* keys)
-{
- std::vector args;
- // push a bogus executable name (argv[0])
- args.emplace_back("");
- for (size_t i = 0; i < tokens.size(); ++ i)
- args.emplace_back(tokens[i].c_str());
- this->read_cli(int(args.size()), args.data(), extra, keys);
-}
-
bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys)
{
// cache the CLI option => opt_key mapping
std::map opts;
for (const auto &oit : this->def()->options)
- for (auto t : oit.second.cli_args(oit.first))
+ for (const std::string &t : oit.second.cli_args(oit.first))
opts[t] = oit.first;
bool parse_options = true;
@@ -854,14 +1076,8 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option
parse_options = false;
continue;
}
- // Remove leading dashes
- boost::trim_left_if(token, boost::is_any_of("-"));
- // Remove the "no-" prefix used to negate boolean options.
- bool no = false;
- if (boost::starts_with(token, "no-")) {
- no = true;
- boost::replace_first(token, "no-", "");
- }
+ // Remove leading dashes (one or two).
+ token.erase(token.begin(), token.begin() + (boost::starts_with(token, "--") ? 2 : 1));
// Read value when supplied in the --key=value form.
std::string value;
{
@@ -872,22 +1088,45 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option
}
}
// Look for the cli -> option mapping.
- const auto it = opts.find(token);
+ auto it = opts.find(token);
+ bool no = false;
if (it == opts.end()) {
- boost::nowide::cerr << "Unknown option --" << token.c_str() << std::endl;
- return false;
+ // Remove the "no-" prefix used to negate boolean options.
+ std::string yes_token;
+ if (boost::starts_with(token, "no-")) {
+ yes_token = token.substr(3);
+ it = opts.find(yes_token);
+ no = true;
+ }
+ if (it == opts.end()) {
+ boost::nowide::cerr << "Unknown option --" << token.c_str() << std::endl;
+ return false;
+ }
+ if (no)
+ token = yes_token;
}
- const t_config_option_key opt_key = it->second;
- const ConfigOptionDef &optdef = this->def()->options.at(opt_key);
+
+ const t_config_option_key &opt_key = it->second;
+ const ConfigOptionDef &optdef = this->def()->options.at(opt_key);
+
// If the option type expects a value and it was not already provided,
// look for it in the next token.
- if (optdef.type != coBool && optdef.type != coBools && value.empty()) {
- if (i == (argc-1)) {
- boost::nowide::cerr << "No value supplied for --" << token.c_str() << std::endl;
+ if (value.empty() && optdef.type != coBool && optdef.type != coBools) {
+ if (i == argc-1) {
+ boost::nowide::cerr << "No value supplied for --" << token.c_str() << std::endl;
return false;
}
value = argv[++ i];
}
+
+ if (no) {
+ assert(optdef.type == coBool || optdef.type == coBools);
+ if (! value.empty()) {
+ boost::nowide::cerr << "Boolean options negated by the --no- prefix cannot have a value." << std::endl;
+ return false;
+ }
+ }
+
// Store the option value.
const bool existing = this->has(opt_key);
if (keys != nullptr && ! existing) {
@@ -902,7 +1141,7 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option
opt_vector->clear();
// Vector values will be chained. Repeated use of a parameter will append the parameter or parameters
// to the end of the value.
- if (opt_base->type() == coBools)
+ if (opt_base->type() == coBools && value.empty())
static_cast(opt_base)->values.push_back(!no);
else
// Deserialize any other vector value (ConfigOptionInts, Floats, Percents, Points) the same way
@@ -911,7 +1150,10 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option
// unescaped by the calling shell.
opt_vector->deserialize(value, true);
} else if (opt_base->type() == coBool) {
- static_cast(opt_base)->value = !no;
+ if (value.empty())
+ static_cast(opt_base)->value = !no;
+ else
+ opt_base->deserialize(value);
} else if (opt_base->type() == coString) {
// Do not unescape single string values, the unescaping is left to the calling shell.
static_cast(opt_base)->value = value;
@@ -961,6 +1203,65 @@ t_config_option_keys StaticConfig::keys() const
return keys;
}
+// Iterate over the pairs of options with equal keys, call the fn.
+// Returns true on early exit by fn().
+template
+static inline bool dynamic_config_iterate(const DynamicConfig &lhs, const DynamicConfig &rhs, Fn fn)
+{
+ std::map>::const_iterator i = lhs.cbegin();
+ std::map>::const_iterator j = rhs.cbegin();
+ while (i != lhs.cend() && j != rhs.cend())
+ if (i->first < j->first)
+ ++ i;
+ else if (i->first > j->first)
+ ++ j;
+ else {
+ assert(i->first == j->first);
+ if (fn(i->first, i->second.get(), j->second.get()))
+ // Early exit by fn.
+ return true;
+ ++ i;
+ ++ j;
+ }
+ // Finished to the end.
+ return false;
+}
+
+// Are the two configs equal? Ignoring options not present in both configs.
+bool DynamicConfig::equals(const DynamicConfig &other) const
+{
+ return ! dynamic_config_iterate(*this, other,
+ [](const t_config_option_key & /* key */, const ConfigOption *l, const ConfigOption *r) { return *l != *r; });
+}
+
+// Returns options differing in the two configs, ignoring options not present in both configs.
+t_config_option_keys DynamicConfig::diff(const DynamicConfig &other) const
+{
+ t_config_option_keys diff;
+ dynamic_config_iterate(*this, other,
+ [&diff](const t_config_option_key &key, const ConfigOption *l, const ConfigOption *r) {
+ if (*l != *r)
+ diff.emplace_back(key);
+ // Continue iterating.
+ return false;
+ });
+ return diff;
+}
+
+// Returns options being equal in the two configs, ignoring options not present in both configs.
+t_config_option_keys DynamicConfig::equal(const DynamicConfig &other) const
+{
+ t_config_option_keys equal;
+ dynamic_config_iterate(*this, other,
+ [&equal](const t_config_option_key &key, const ConfigOption *l, const ConfigOption *r) {
+ if (*l == *r)
+ equal.emplace_back(key);
+ // Continue iterating.
+ return false;
+ });
+ return equal;
+}
+
}
#include
diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp
index bf356dfe65..6439e4632c 100644
--- a/src/libslic3r/Config.hpp
+++ b/src/libslic3r/Config.hpp
@@ -80,32 +80,77 @@ extern bool unescape_strings_cstyle(const std::string &str, std::vector<
extern std::string escape_ampersand(const std::string& str);
-/// Specialization of std::exception to indicate that an unknown config option has been encountered.
-class UnknownOptionException : public Slic3r::RuntimeError {
-public:
- UnknownOptionException() :
- Slic3r::RuntimeError("Unknown option exception") {}
- UnknownOptionException(const std::string &opt_key) :
- Slic3r::RuntimeError(std::string("Unknown option exception: ") + opt_key) {}
+namespace ConfigHelpers {
+ inline bool looks_like_enum_value(std::string value)
+ {
+ boost::trim(value);
+ if (value.empty() || value.size() > 64 || ! isalpha(value.front()))
+ return false;
+ for (const char c : value)
+ if (! (isalnum(c) || c == '_' || c == '-'))
+ return false;
+ return true;
+ }
+
+ inline bool enum_looks_like_true_value(std::string value) {
+ boost::trim(value);
+ return boost::iequals(value, "enabled") || boost::iequals(value, "on");
+ }
+
+ enum class DeserializationSubstitution {
+ Disabled,
+ DefaultsToFalse,
+ DefaultsToTrue
+ };
+
+ enum class DeserializationResult {
+ Loaded,
+ Substituted,
+ Failed,
+ };
};
-/// Indicate that the ConfigBase derived class does not provide config definition (the method def() returns null).
-class NoDefinitionException : public Slic3r::RuntimeError
+// Base for all exceptions thrown by the configuration layer.
+class ConfigurationError : public Slic3r::RuntimeError {
+public:
+ using RuntimeError::RuntimeError;
+};
+
+// Specialization of std::exception to indicate that an unknown config option has been encountered.
+class UnknownOptionException : public ConfigurationError {
+public:
+ UnknownOptionException() :
+ ConfigurationError("Unknown option exception") {}
+ UnknownOptionException(const std::string &opt_key) :
+ ConfigurationError(std::string("Unknown option exception: ") + opt_key) {}
+};
+
+// Indicate that the ConfigBase derived class does not provide config definition (the method def() returns null).
+class NoDefinitionException : public ConfigurationError
{
public:
NoDefinitionException() :
- Slic3r::RuntimeError("No definition exception") {}
+ ConfigurationError("No definition exception") {}
NoDefinitionException(const std::string &opt_key) :
- Slic3r::RuntimeError(std::string("No definition exception: ") + opt_key) {}
+ ConfigurationError(std::string("No definition exception: ") + opt_key) {}
};
-/// Indicate that an unsupported accessor was called on a config option.
-class BadOptionTypeException : public Slic3r::RuntimeError
+// Indicate that an unsupported accessor was called on a config option.
+class BadOptionTypeException : public ConfigurationError
{
public:
- BadOptionTypeException() : Slic3r::RuntimeError("Bad option type exception") {}
- BadOptionTypeException(const std::string &message) : Slic3r::RuntimeError(message) {}
- BadOptionTypeException(const char* message) : Slic3r::RuntimeError(message) {}
+ BadOptionTypeException() : ConfigurationError("Bad option type exception") {}
+ BadOptionTypeException(const std::string &message) : ConfigurationError(message) {}
+ BadOptionTypeException(const char* message) : ConfigurationError(message) {}
+};
+
+// Indicate that an option has been deserialized from an invalid value.
+class BadOptionValueException : public ConfigurationError
+{
+public:
+ BadOptionValueException() : ConfigurationError("Bad option value exception") {}
+ BadOptionValueException(const std::string &message) : ConfigurationError(message) {}
+ BadOptionValueException(const char* message) : ConfigurationError(message) {}
};
// Type of a configuration value.
@@ -166,9 +211,16 @@ enum PrinterTechnology : unsigned char
enum ForwardCompatibilitySubstitutionRule
{
+ // Disable susbtitution, throw exception if an option value is not recognized.
Disable,
+ // Enable substitution of an unknown option value with default. Log the substitution.
Enable,
+ // Enable substitution of an unknown option value with default. Don't log the substitution.
EnableSilent,
+ // Enable substitution of an unknown option value with default. Log substitutions in user profiles, don't log substitutions in system profiles.
+ EnableSystemSilent,
+ // Enable silent substitution of an unknown option value with default when loading user profiles. Throw on an unknown option value in a system profile.
+ EnableSilentDisableSystem,
};
class ConfigOption;
@@ -252,7 +304,7 @@ public:
void set(const ConfigOption *rhs) override
{
if (rhs->type() != this->type())
- throw Slic3r::RuntimeError("ConfigOptionSingle: Assigning an incompatible type");
+ throw ConfigurationError("ConfigOptionSingle: Assigning an incompatible type");
assert(dynamic_cast*>(rhs));
this->value = static_cast*>(rhs)->value;
}
@@ -260,7 +312,7 @@ public:
bool operator==(const ConfigOption &rhs) const override
{
if (rhs.type() != this->type())
- throw Slic3r::RuntimeError("ConfigOptionSingle: Comparing incompatible types");
+ throw ConfigurationError("ConfigOptionSingle: Comparing incompatible types");
assert(dynamic_cast*>(&rhs));
return this->value == static_cast*>(&rhs)->value;
}
@@ -327,7 +379,7 @@ public:
void set(const ConfigOption *rhs) override
{
if (rhs->type() != this->type())
- throw Slic3r::RuntimeError("ConfigOptionVector: Assigning an incompatible type");
+ throw ConfigurationError("ConfigOptionVector: Assigning an incompatible type");
assert(dynamic_cast*>(rhs));
this->values = static_cast*>(rhs)->values;
}
@@ -344,12 +396,12 @@ public:
if (opt->type() == this->type()) {
auto other = static_cast*>(opt);
if (other->values.empty())
- throw Slic3r::RuntimeError("ConfigOptionVector::set(): Assigning from an empty vector");
+ throw ConfigurationError("ConfigOptionVector::set(): Assigning from an empty vector");
this->values.emplace_back(other->values.front());
} else if (opt->type() == this->scalar_type())
this->values.emplace_back(static_cast*>(opt)->value);
else
- throw Slic3r::RuntimeError("ConfigOptionVector::set():: Assigning an incompatible type");
+ throw ConfigurationError("ConfigOptionVector::set():: Assigning an incompatible type");
}
}
@@ -368,12 +420,12 @@ public:
// Assign the first value of the rhs vector.
auto other = static_cast*>(rhs);
if (other->values.empty())
- throw Slic3r::RuntimeError("ConfigOptionVector::set_at(): Assigning from an empty vector");
+ throw ConfigurationError("ConfigOptionVector::set_at(): Assigning from an empty vector");
this->values[i] = other->get_at(j);
} else if (rhs->type() == this->scalar_type())
this->values[i] = static_cast*>(rhs)->value;
else
- throw Slic3r::RuntimeError("ConfigOptionVector::set_at(): Assigning an incompatible type");
+ throw ConfigurationError("ConfigOptionVector::set_at(): Assigning an incompatible type");
}
const T& get_at(size_t i) const
@@ -398,9 +450,9 @@ public:
else if (n > this->values.size()) {
if (this->values.empty()) {
if (opt_default == nullptr)
- throw Slic3r::RuntimeError("ConfigOptionVector::resize(): No default value provided.");
+ throw ConfigurationError("ConfigOptionVector::resize(): No default value provided.");
if (opt_default->type() != this->type())
- throw Slic3r::RuntimeError("ConfigOptionVector::resize(): Extending with an incompatible type.");
+ throw ConfigurationError("ConfigOptionVector::resize(): Extending with an incompatible type.");
this->values.resize(n, static_cast*>(opt_default)->values.front());
} else {
// Resize by duplicating the last value.
@@ -417,7 +469,7 @@ public:
bool operator==(const ConfigOption &rhs) const override
{
if (rhs.type() != this->type())
- throw Slic3r::RuntimeError("ConfigOptionVector: Comparing incompatible types");
+ throw ConfigurationError("ConfigOptionVector: Comparing incompatible types");
assert(dynamic_cast*>(&rhs));
return this->values == static_cast*>(&rhs)->values;
}
@@ -437,9 +489,9 @@ public:
// An option overrides another option if it is not nil and not equal.
bool overriden_by(const ConfigOption *rhs) const override {
if (this->nullable())
- throw Slic3r::RuntimeError("Cannot override a nullable ConfigOption.");
+ throw ConfigurationError("Cannot override a nullable ConfigOption.");
if (rhs->type() != this->type())
- throw Slic3r::RuntimeError("ConfigOptionVector.overriden_by() applied to different types.");
+ throw ConfigurationError("ConfigOptionVector.overriden_by() applied to different types.");
auto rhs_vec = static_cast*>(rhs);
if (! rhs->nullable())
// Overridding a non-nullable object with another non-nullable object.
@@ -457,9 +509,9 @@ public:
// Apply an override option, possibly a nullable one.
bool apply_override(const ConfigOption *rhs) override {
if (this->nullable())
- throw Slic3r::RuntimeError("Cannot override a nullable ConfigOption.");
+ throw ConfigurationError("Cannot override a nullable ConfigOption.");
if (rhs->type() != this->type())
- throw Slic3r::RuntimeError("ConfigOptionVector.apply_override() applied to different types.");
+ throw ConfigurationError("ConfigOptionVector.apply_override() applied to different types.");
auto rhs_vec = static_cast*>(rhs);
if (! rhs->nullable()) {
// Overridding a non-nullable object with another non-nullable object.
@@ -550,7 +602,7 @@ public:
bool operator< (const ConfigOptionFloatsTempl &rhs) const throw() { return vectors_lower(this->values, rhs.values); }
bool operator==(const ConfigOption &rhs) const override {
if (rhs.type() != this->type())
- throw Slic3r::RuntimeError("ConfigOptionFloatsTempl: Comparing incompatible types");
+ throw ConfigurationError("ConfigOptionFloatsTempl: Comparing incompatible types");
assert(dynamic_cast*>(&rhs));
return vectors_equal(this->values, static_cast*>(&rhs)->values);
}
@@ -597,7 +649,7 @@ public:
if (NULLABLE)
this->values.push_back(nil_value());
else
- throw Slic3r::RuntimeError("Deserializing nil into a non-nullable object");
+ throw ConfigurationError("Deserializing nil into a non-nullable object");
} else {
std::istringstream iss(item_str);
double value;
@@ -622,9 +674,9 @@ protected:
if (NULLABLE)
ss << "nil";
else
- throw Slic3r::RuntimeError("Serializing NaN");
+ throw ConfigurationError("Serializing NaN");
} else
- throw Slic3r::RuntimeError("Serializing invalid number");
+ throw ConfigurationError("Serializing invalid number");
}
static bool vectors_equal(const std::vector &v1, const std::vector &v2) {
if (NULLABLE) {
@@ -756,7 +808,7 @@ public:
if (NULLABLE)
this->values.push_back(nil_value());
else
- throw Slic3r::RuntimeError("Deserializing nil into a non-nullable object");
+ throw ConfigurationError("Deserializing nil into a non-nullable object");
} else {
std::istringstream iss(item_str);
int value;
@@ -773,7 +825,7 @@ private:
if (NULLABLE)
ss << "nil";
else
- throw Slic3r::RuntimeError("Serializing NaN");
+ throw ConfigurationError("Serializing NaN");
} else
ss << v;
}
@@ -963,7 +1015,7 @@ public:
bool operator==(const ConfigOption &rhs) const override
{
if (rhs.type() != this->type())
- throw Slic3r::RuntimeError("ConfigOptionFloatOrPercent: Comparing incompatible types");
+ throw ConfigurationError("ConfigOptionFloatOrPercent: Comparing incompatible types");
assert(dynamic_cast(&rhs));
return *this == *static_cast(&rhs);
}
@@ -979,7 +1031,7 @@ public:
void set(const ConfigOption *rhs) override {
if (rhs->type() != this->type())
- throw Slic3r::RuntimeError("ConfigOptionFloatOrPercent: Assigning an incompatible type");
+ throw ConfigurationError("ConfigOptionFloatOrPercent: Assigning an incompatible type");
assert(dynamic_cast(rhs));
*this = *static_cast(rhs);
}
@@ -1023,7 +1075,7 @@ public:
bool operator==(const ConfigOptionFloatsOrPercentsTempl &rhs) const throw() { return vectors_equal(this->values, rhs.values); }
bool operator==(const ConfigOption &rhs) const override {
if (rhs.type() != this->type())
- throw Slic3r::RuntimeError("ConfigOptionFloatsOrPercentsTempl: Comparing incompatible types");
+ throw ConfigurationError("ConfigOptionFloatsOrPercentsTempl: Comparing incompatible types");
assert(dynamic_cast*>(&rhs));
return vectors_equal(this->values, static_cast*>(&rhs)->values);
}
@@ -1072,7 +1124,7 @@ public:
if (NULLABLE)
this->values.push_back(nil_value());
else
- throw Slic3r::RuntimeError("Deserializing nil into a non-nullable object");
+ throw ConfigurationError("Deserializing nil into a non-nullable object");
} else {
bool percent = item_str.find_first_of("%") != std::string::npos;
std::istringstream iss(item_str);
@@ -1100,9 +1152,9 @@ protected:
if (NULLABLE)
ss << "nil";
else
- throw Slic3r::RuntimeError("Serializing NaN");
+ throw ConfigurationError("Serializing NaN");
} else
- throw Slic3r::RuntimeError("Serializing invalid number");
+ throw ConfigurationError("Serializing invalid number");
}
static bool vectors_equal(const std::vector &v1, const std::vector &v2) {
if (NULLABLE) {
@@ -1308,11 +1360,11 @@ public:
bool deserialize(const std::string &str, bool append = false) override
{
UNUSED(append);
- if (str == "1" || boost::iequals(str, "enabled") || boost::iequals(str, "on")) {
+ if (str == "1") {
this->value = true;
return true;
}
- if (str == "0" || boost::iequals(str, "disabled") || boost::iequals(str, "off")) {
+ if (str == "0") {
this->value = false;
return true;
}
@@ -1378,24 +1430,39 @@ public:
}
return vv;
}
-
- bool deserialize(const std::string &str, bool append = false) override
+
+ ConfigHelpers::DeserializationResult deserialize_with_substitutions(const std::string &str, bool append, ConfigHelpers::DeserializationSubstitution substitution)
{
if (! append)
this->values.clear();
std::istringstream is(str);
std::string item_str;
+ bool substituted = false;
while (std::getline(is, item_str, ',')) {
boost::trim(item_str);
+ unsigned char new_value = 0;
if (item_str == "nil") {
if (NULLABLE)
- this->values.push_back(nil_value());
+ new_value = nil_value();
else
- throw Slic3r::RuntimeError("Deserializing nil into a non-nullable object");
+ throw ConfigurationError("Deserializing nil into a non-nullable object");
+ } else if (item_str == "1") {
+ new_value = true;
+ } else if (item_str == "0") {
+ new_value = false;
+ } else if (substitution != ConfigHelpers::DeserializationSubstitution::Disabled && ConfigHelpers::looks_like_enum_value(item_str)) {
+ new_value = ConfigHelpers::enum_looks_like_true_value(item_str) || substitution == ConfigHelpers::DeserializationSubstitution::DefaultsToTrue;
+ substituted = true;
} else
- this->values.push_back(item_str.compare("1") == 0);
+ return ConfigHelpers::DeserializationResult::Failed;
+ this->values.push_back(new_value);
}
- return true;
+ return substituted ? ConfigHelpers::DeserializationResult::Substituted : ConfigHelpers::DeserializationResult::Loaded;
+ }
+
+ bool deserialize(const std::string &str, bool append = false) override
+ {
+ return this->deserialize_with_substitutions(str, append, ConfigHelpers::DeserializationSubstitution::Disabled) == ConfigHelpers::DeserializationResult::Loaded;
}
protected:
@@ -1404,7 +1471,7 @@ protected:
if (NULLABLE)
ss << "nil";
else
- throw Slic3r::RuntimeError("Serializing NaN");
+ throw ConfigurationError("Serializing NaN");
} else
ss << (v ? "1" : "0");
}
@@ -1442,14 +1509,14 @@ public:
bool operator==(const ConfigOption &rhs) const override
{
if (rhs.type() != this->type())
- throw Slic3r::RuntimeError("ConfigOptionEnum: Comparing incompatible types");
+ throw ConfigurationError("ConfigOptionEnum: Comparing incompatible types");
// rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum
return this->value == (T)rhs.getInt();
}
void set(const ConfigOption *rhs) override {
if (rhs->type() != this->type())
- throw Slic3r::RuntimeError("ConfigOptionEnum: Assigning an incompatible type");
+ throw ConfigurationError("ConfigOptionEnum: Assigning an incompatible type");
// rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum
this->value = (T)rhs->getInt();
}
@@ -1512,14 +1579,14 @@ public:
bool operator==(const ConfigOption &rhs) const override
{
if (rhs.type() != this->type())
- throw Slic3r::RuntimeError("ConfigOptionEnumGeneric: Comparing incompatible types");
+ throw ConfigurationError("ConfigOptionEnumGeneric: Comparing incompatible types");
// rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum
return this->value == rhs.getInt();
}
void set(const ConfigOption *rhs) override {
if (rhs->type() != this->type())
- throw Slic3r::RuntimeError("ConfigOptionEnumGeneric: Assigning an incompatible type");
+ throw ConfigurationError("ConfigOptionEnumGeneric: Assigning an incompatible type");
// rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum
this->value = rhs->getInt();
}
@@ -1592,7 +1659,7 @@ public:
case coInts: { auto opt = new ConfigOptionIntsNullable(); archive(*opt); return opt; }
case coPercents: { auto opt = new ConfigOptionPercentsNullable();archive(*opt); return opt; }
case coBools: { auto opt = new ConfigOptionBoolsNullable(); archive(*opt); return opt; }
- default: throw Slic3r::RuntimeError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown nullable option type for option ") + this->opt_key);
+ default: throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown nullable option type for option ") + this->opt_key);
}
} else {
switch (this->type) {
@@ -1611,7 +1678,7 @@ public:
case coBool: { auto opt = new ConfigOptionBool(); archive(*opt); return opt; }
case coBools: { auto opt = new ConfigOptionBools(); archive(*opt); return opt; }
case coEnum: { auto opt = new ConfigOptionEnumGeneric(this->enum_keys_map); archive(*opt); return opt; }
- default: throw Slic3r::RuntimeError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key);
+ default: throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key);
}
}
}
@@ -1623,7 +1690,7 @@ public:
case coInts: archive(*static_cast(opt)); break;
case coPercents: archive(*static_cast(opt));break;
case coBools: archive(*static_cast(opt)); break;
- default: throw Slic3r::RuntimeError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown nullable option type for option ") + this->opt_key);
+ default: throw ConfigurationError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown nullable option type for option ") + this->opt_key);
}
} else {
switch (this->type) {
@@ -1642,7 +1709,7 @@ public:
case coBool: archive(*static_cast(opt)); break;
case coBools: archive(*static_cast(opt)); break;
case coEnum: archive(*static_cast(opt)); break;
- default: throw Slic3r::RuntimeError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key);
+ default: throw ConfigurationError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key);
}
}
// Make the compiler happy, shut up the warnings.
@@ -1765,7 +1832,7 @@ public:
return out;
}
- /// Iterate through all of the CLI options and write them to a stream.
+ // Iterate through all of the CLI options and write them to a stream.
std::ostream& print_cli_help(
std::ostream& out, bool show_defaults,
std::function filter = [](const ConfigOptionDef &){ return true; }) const;
@@ -1826,8 +1893,8 @@ public:
// The configuration definition is static: It does not carry the actual configuration values,
// but it carries the defaults of the configuration values.
- ConfigBase() {}
- ~ConfigBase() override {}
+ ConfigBase() = default;
+ ~ConfigBase() override = default;
// Virtual overridables:
public:
@@ -1886,8 +1953,11 @@ public:
// An UnknownOptionException is thrown in case some option keys are not defined by this->def(),
// or this ConfigBase is of a StaticConfig type and it does not support some of the keys, and ignore_nonexistent is not set.
void apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false);
- bool equals(const ConfigBase &other) const { return this->diff(other).empty(); }
+ // Are the two configs equal? Ignoring options not present in both configs.
+ bool equals(const ConfigBase &other) const;
+ // Returns options differing in the two configs, ignoring options not present in both configs.
t_config_option_keys diff(const ConfigBase &other) const;
+ // Returns options being equal in the two configs, ignoring options not present in both configs.
t_config_option_keys equal(const ConfigBase &other) const;
std::string opt_serialize(const t_config_option_key &opt_key) const;
@@ -1934,9 +2004,11 @@ public:
void setenv_() const;
ConfigSubstitutions load(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule);
ConfigSubstitutions load_from_ini(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule);
- ConfigSubstitutions load_from_gcode_file(const std::string &file, bool check_header /* = true */, ForwardCompatibilitySubstitutionRule compatibility_rule);
- // Returns number of key/value pairs extracted.
- size_t load_from_gcode_string(const char* str, ConfigSubstitutionContext& substitutions);
+ ConfigSubstitutions load_from_ini_string(const std::string &data, ForwardCompatibilitySubstitutionRule compatibility_rule);
+ // Loading a "will be one day a legacy format" of configuration stored into 3MF or AMF.
+ // Accepts the same data as load_from_ini_string(), only with each configuration line possibly prefixed with a semicolon (G-code comment).
+ ConfigSubstitutions load_from_ini_string_commented(std::string &&data, ForwardCompatibilitySubstitutionRule compatibility_rule);
+ ConfigSubstitutions load_from_gcode_file(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule);
ConfigSubstitutions load(const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule);
void save(const std::string &file) const;
@@ -1953,12 +2025,12 @@ private:
class DynamicConfig : public virtual ConfigBase
{
public:
- DynamicConfig() {}
+ DynamicConfig() = default;
DynamicConfig(const DynamicConfig &rhs) { *this = rhs; }
DynamicConfig(DynamicConfig &&rhs) noexcept : options(std::move(rhs.options)) { rhs.options.clear(); }
explicit DynamicConfig(const ConfigBase &rhs, const t_config_option_keys &keys);
explicit DynamicConfig(const ConfigBase& rhs) : DynamicConfig(rhs, rhs.keys()) {}
- virtual ~DynamicConfig() override { clear(); }
+ virtual ~DynamicConfig() override = default;
// Copy a content of one DynamicConfig to another DynamicConfig.
// If rhs.def() is not null, then it has to be equal to this->def().
@@ -2075,6 +2147,13 @@ public:
}
}
+ // Are the two configs equal? Ignoring options not present in both configs.
+ bool equals(const DynamicConfig &other) const;
+ // Returns options differing in the two configs, ignoring options not present in both configs.
+ t_config_option_keys diff(const DynamicConfig &other) const;
+ // Returns options being equal in the two configs, ignoring options not present in both configs.
+ t_config_option_keys equal(const DynamicConfig &other) const;
+
std::string& opt_string(const t_config_option_key &opt_key, bool create = false) { return this->option(opt_key, create)->value; }
const std::string& opt_string(const t_config_option_key &opt_key) const { return const_cast(this)->opt_string(opt_key); }
std::string& opt_string(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); }
@@ -2099,7 +2178,6 @@ public:
bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option(opt_key)->get_at(idx) != 0; }
// Command line processing
- void read_cli(const std::vector &tokens, t_config_option_keys* extra, t_config_option_keys* keys = nullptr);
bool read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys = nullptr);
std::map>::const_iterator cbegin() const { return options.cbegin(); }
@@ -2113,9 +2191,9 @@ private:
template void serialize(Archive &ar) { ar(options); }
};
-/// Configuration store with a static definition of configuration values.
-/// In Slic3r, the static configuration stores are during the slicing / g-code generation for efficiency reasons,
-/// because the configuration values could be accessed directly.
+// Configuration store with a static definition of configuration values.
+// In Slic3r, the static configuration stores are during the slicing / g-code generation for efficiency reasons,
+// because the configuration values could be accessed directly.
class StaticConfig : public virtual ConfigBase
{
public:
diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index 613b7444af..ed2d5d9c36 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -595,7 +595,7 @@ namespace Slic3r {
mz_zip_archive_file_stat stat;
- m_name = boost::filesystem::path(filename).filename().stem().string();
+ m_name = boost::filesystem::path(filename).stem().string();
// we first loop the entries to read from the archive the .model file only, in order to extract the version from it
for (mz_uint i = 0; i < num_entries; ++i) {
@@ -875,7 +875,9 @@ namespace Slic3r {
add_error("Error while reading config data to buffer");
return;
}
- config.load_from_gcode_string(buffer.data(), config_substitutions);
+ //FIXME Loading a "will be one day a legacy format" of configuration in a form of a G-code comment.
+ // Each config line is prefixed with a semicolon (G-code comment), that is ugly.
+ config_substitutions.substitutions = config.load_from_ini_string_commented(std::move(buffer), config_substitutions.rule);
}
}
@@ -1406,6 +1408,13 @@ namespace Slic3r {
m_model->delete_object(model_object);
}
+ if (m_version == 0) {
+ // if the 3mf was not produced by PrusaSlicer and there is only one object,
+ // set the object name to match the filename
+ if (m_model->objects.size() == 1)
+ m_model->objects.front()->name = m_name;
+ }
+
// applies instances' matrices
for (Instance& instance : m_instances) {
if (instance.instance != nullptr && instance.instance->get_object() != nullptr)
@@ -2860,9 +2869,10 @@ namespace Slic3r {
stream << prefix << SOURCE_OFFSET_Y_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.mesh_offset(1) << "\"/>\n";
stream << prefix << SOURCE_OFFSET_Z_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.mesh_offset(2) << "\"/>\n";
}
+ assert(! volume->source.is_converted_from_inches || ! volume->source.is_converted_from_meters);
if (volume->source.is_converted_from_inches)
stream << prefix << SOURCE_IN_INCHES << "\" " << VALUE_ATTR << "=\"1\"/>\n";
- if (volume->source.is_converted_from_meters)
+ else if (volume->source.is_converted_from_meters)
stream << prefix << SOURCE_IN_METERS << "\" " << VALUE_ATTR << "=\"1\"/>\n";
}
diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index d03cfd4fa0..35b3e0cf43 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -706,7 +706,9 @@ void AMFParserContext::endElement(const char * /* name */)
case NODE_TYPE_METADATA:
if ((m_config != nullptr) && strncmp(m_value[0].c_str(), SLIC3R_CONFIG_TYPE, strlen(SLIC3R_CONFIG_TYPE)) == 0) {
- m_config->load_from_gcode_string(m_value[1].c_str(), *m_config_substitutions);
+ //FIXME Loading a "will be one day a legacy format" of configuration in a form of a G-code comment.
+ // Each config line is prefixed with a semicolon (G-code comment), that is ugly.
+ m_config_substitutions->substitutions = m_config->load_from_ini_string_commented(std::move(m_value[1].c_str()), m_config_substitutions->rule);
}
else if (strncmp(m_value[0].c_str(), "slic3r.", 7) == 0) {
const char *opt_key = m_value[0].c_str() + 7;
@@ -1241,9 +1243,10 @@ bool store_amf(const char* path, Model* model, const DynamicPrintConfig* config,
stream << " " << volume->source.mesh_offset(1) << "\n";
stream << " " << volume->source.mesh_offset(2) << "\n";
}
+ assert(! volume->source.is_converted_from_inches || ! volume->source.is_converted_from_meters);
if (volume->source.is_converted_from_inches)
stream << " 1\n";
- if (volume->source.is_converted_from_meters)
+ else if (volume->source.is_converted_from_meters)
stream << " 1\n";
stream << std::setprecision(std::numeric_limits::max_digits10);
const indexed_triangle_set &its = volume->mesh().its;
diff --git a/src/libslic3r/Format/SL1.cpp b/src/libslic3r/Format/SL1.cpp
index 6d779b94e3..e2ef801f27 100644
--- a/src/libslic3r/Format/SL1.cpp
+++ b/src/libslic3r/Format/SL1.cpp
@@ -203,7 +203,7 @@ RasterParams get_raster_params(const DynamicPrintConfig &cfg)
if (!opt_disp_cols || !opt_disp_rows || !opt_disp_w || !opt_disp_h ||
!opt_mirror_x || !opt_mirror_y || !opt_orient)
- throw Slic3r::FileIOError("Invalid SL1 file");
+ throw Slic3r::FileIOError("Invalid SL1 / SL1S file");
RasterParams rstp;
@@ -229,7 +229,7 @@ SliceParams get_slice_params(const DynamicPrintConfig &cfg)
auto *opt_init_layerh = cfg.option("initial_layer_height");
if (!opt_layerh || !opt_init_layerh)
- throw Slic3r::FileIOError("Invalid SL1 file");
+ throw Slic3r::FileIOError("Invalid SL1 / SL1S file");
return SliceParams{opt_layerh->getFloat(), opt_init_layerh->getFloat()};
}
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index 9e74d217d2..254f1d4fd9 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -1464,13 +1464,15 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
_write_format(file, "; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges);
_write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
- // Append full config.
- _write(file, "\n");
+ // Append full config, delimited by two 'phony' configuration keys prusaslicer_config = begin and prusaslicer_config = end.
+ // The delimiters are structured as configuration key / value pairs to be parsable by older versions of PrusaSlicer G-code viewer.
{
+ _write(file, "\n; prusaslicer_config = begin\n");
std::string full_config;
append_full_config(print, full_config);
if (!full_config.empty())
_write(file, full_config);
+ _write(file, "; prusaslicer_config = end\n");
}
print.throw_if_canceled();
}
@@ -2714,7 +2716,9 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
// calculate extrusion length per distance unit
double e_per_mm = m_writer.extruder()->e_per_mm3() * path.mm3_per_mm;
- if (m_writer.extrusion_axis().empty()) e_per_mm = 0;
+ if (m_writer.extrusion_axis().empty())
+ // gcfNoExtrusion
+ e_per_mm = 0;
// set speed
if (speed == -1) {
diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp
index 1141ca2a73..0d71a19f53 100644
--- a/src/libslic3r/GCode/GCodeProcessor.cpp
+++ b/src/libslic3r/GCode/GCodeProcessor.cpp
@@ -24,6 +24,9 @@
static const float INCHES_TO_MM = 25.4f;
static const float MMMIN_TO_MMSEC = 1.0f / 60.0f;
static const float DEFAULT_ACCELERATION = 1500.0f; // Prusa Firmware 1_75mm_MK2
+#if ENABLE_RETRACT_ACCELERATION
+static const float DEFAULT_RETRACT_ACCELERATION = 1500.0f; // Prusa Firmware 1_75mm_MK2
+#endif // ENABLE_RETRACT_ACCELERATION
static const float DEFAULT_TRAVEL_ACCELERATION = 1250.0f;
static const size_t MIN_EXTRUDERS_COUNT = 5;
@@ -178,6 +181,10 @@ void GCodeProcessor::TimeMachine::reset()
enabled = false;
acceleration = 0.0f;
max_acceleration = 0.0f;
+#if ENABLE_RETRACT_ACCELERATION
+ retract_acceleration = 0.0f;
+ max_retract_acceleration = 0.0f;
+#endif // ENABLE_RETRACT_ACCELERATION
travel_acceleration = 0.0f;
max_travel_acceleration = 0.0f;
extrude_factor_override_percentage = 1.0f;
@@ -834,6 +841,11 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
float max_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_extruding, i);
m_time_processor.machines[i].max_acceleration = max_acceleration;
m_time_processor.machines[i].acceleration = (max_acceleration > 0.0f) ? max_acceleration : DEFAULT_ACCELERATION;
+#if ENABLE_RETRACT_ACCELERATION
+ float max_retract_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i);
+ m_time_processor.machines[i].max_retract_acceleration = max_retract_acceleration;
+ m_time_processor.machines[i].retract_acceleration = (max_retract_acceleration > 0.0f) ? max_retract_acceleration : DEFAULT_RETRACT_ACCELERATION;
+#endif // ENABLE_RETRACT_ACCELERATION
float max_travel_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_travel, i);
m_time_processor.machines[i].max_travel_acceleration = max_travel_acceleration;
m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION;
@@ -1052,6 +1064,11 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
float max_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_extruding, i);
m_time_processor.machines[i].max_acceleration = max_acceleration;
m_time_processor.machines[i].acceleration = (max_acceleration > 0.0f) ? max_acceleration : DEFAULT_ACCELERATION;
+#if ENABLE_RETRACT_ACCELERATION
+ float max_retract_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i);
+ m_time_processor.machines[i].max_retract_acceleration = max_retract_acceleration;
+ m_time_processor.machines[i].retract_acceleration = (max_retract_acceleration > 0.0f) ? max_retract_acceleration : DEFAULT_RETRACT_ACCELERATION;
+#endif // ENABLE_RETRACT_ACCELERATION
float max_travel_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_travel, i);
m_time_processor.machines[i].max_travel_acceleration = max_travel_acceleration;
m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION;
@@ -1172,7 +1189,7 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
// Silently substitute unknown values by new ones for loading configurations from PrusaSlicer's own G-code.
// Showing substitution log or errors may make sense, but we are not really reading many values from the G-code config,
// thus a probability of incorrect substitution is low and the G-code viewer is a consumer-only anyways.
- config.load_from_gcode_file(filename, false, ForwardCompatibilitySubstitutionRule::EnableSilent);
+ config.load_from_gcode_file(filename, ForwardCompatibilitySubstitutionRule::EnableSilent);
apply_config(config);
}
else if (m_producer == EProducer::Simplify3D)
@@ -2713,14 +2730,22 @@ void GCodeProcessor::process_M204(const GCodeReader::GCodeLine& line)
set_acceleration(static_cast(i), value);
set_travel_acceleration(static_cast(i), value);
if (line.has_value('T', value))
+#if ENABLE_RETRACT_ACCELERATION
+ set_retract_acceleration(static_cast(i), value);
+#else
set_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i, value);
+#endif // ENABLE_RETRACT_ACCELERATION
}
else {
// New acceleration format, compatible with the upstream Marlin.
if (line.has_value('P', value))
set_acceleration(static_cast(i), value);
if (line.has_value('R', value))
+#if ENABLE_RETRACT_ACCELERATION
+ set_retract_acceleration(static_cast(i), value);
+#else
set_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i, value);
+#endif // ENABLE_RETRACT_ACCELERATION
if (line.has_value('T', value))
// Interpret the T value as the travel acceleration in the new Marlin format.
set_travel_acceleration(static_cast(i), value);
@@ -2979,10 +3004,30 @@ float GCodeProcessor::get_axis_max_jerk(PrintEstimatedStatistics::ETimeMode mode
}
}
+#if ENABLE_RETRACT_ACCELERATION
+float GCodeProcessor::get_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode) const
+{
+ size_t id = static_cast(mode);
+ return (id < m_time_processor.machines.size()) ? m_time_processor.machines[id].retract_acceleration : DEFAULT_RETRACT_ACCELERATION;
+}
+#else
float GCodeProcessor::get_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode) const
{
return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, static_cast(mode));
}
+#endif // ENABLE_RETRACT_ACCELERATION
+
+#if ENABLE_RETRACT_ACCELERATION
+void GCodeProcessor::set_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode, float value)
+{
+ size_t id = static_cast(mode);
+ if (id < m_time_processor.machines.size()) {
+ m_time_processor.machines[id].retract_acceleration = (m_time_processor.machines[id].max_retract_acceleration == 0.0f) ? value :
+ // Clamp the acceleration with the maximum.
+ std::min(value, m_time_processor.machines[id].max_retract_acceleration);
+ }
+}
+#endif // ENABLE_RETRACT_ACCELERATION
float GCodeProcessor::get_acceleration(PrintEstimatedStatistics::ETimeMode mode) const
{
diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp
index d83c39d09b..4fcdd8df39 100644
--- a/src/libslic3r/GCode/GCodeProcessor.hpp
+++ b/src/libslic3r/GCode/GCodeProcessor.hpp
@@ -242,6 +242,11 @@ namespace Slic3r {
float acceleration; // mm/s^2
// hard limit for the acceleration, to which the firmware will clamp.
float max_acceleration; // mm/s^2
+#if ENABLE_RETRACT_ACCELERATION
+ float retract_acceleration; // mm/s^2
+ // hard limit for the acceleration, to which the firmware will clamp.
+ float max_retract_acceleration; // mm/s^2
+#endif // ENABLE_RETRACT_ACCELERATION
float travel_acceleration; // mm/s^2
// hard limit for the travel acceleration, to which the firmware will clamp.
float max_travel_acceleration; // mm/s^2
@@ -337,9 +342,9 @@ namespace Slic3r {
std::string printer;
void reset() {
- print = "";
- filament = std::vector();
- printer = "";
+ print.clear();
+ filament.clear();
+ printer.clear();
}
};
std::string filename;
@@ -669,6 +674,9 @@ namespace Slic3r {
float get_axis_max_acceleration(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
float get_axis_max_jerk(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
float get_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode) const;
+#if ENABLE_RETRACT_ACCELERATION
+ void set_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode, float value);
+#endif // ENABLE_RETRACT_ACCELERATION
float get_acceleration(PrintEstimatedStatistics::ETimeMode mode) const;
void set_acceleration(PrintEstimatedStatistics::ETimeMode mode, float value);
float get_travel_acceleration(PrintEstimatedStatistics::ETimeMode mode) const;
diff --git a/src/libslic3r/GCode/PostProcessor.cpp b/src/libslic3r/GCode/PostProcessor.cpp
index 9a66e743bc..27b2254e9e 100644
--- a/src/libslic3r/GCode/PostProcessor.cpp
+++ b/src/libslic3r/GCode/PostProcessor.cpp
@@ -1,10 +1,15 @@
#include "PostProcessor.hpp"
+#include "libslic3r/Utils.hpp"
+#include "libslic3r/format.hpp"
+
#include
#include
#include
#include
#include
+#include
+#include
#ifdef WIN32
@@ -179,41 +184,146 @@ static int run_script(const std::string &script, const std::string &gcode, std::
namespace Slic3r {
-void run_post_process_scripts(const std::string &path, const DynamicPrintConfig &config)
+// Run post processing script / scripts if defined.
+// Returns true if a post-processing script was executed.
+// Returns false if no post-processing script was defined.
+// Throws an exception on error.
+// host is one of "File", "PrusaLink", "Repetier", "SL1Host", "OctoPrint", "FlashAir", "Duet", "AstroBox" ...
+// For a "File" target, a temp file will be created for src_path by adding a ".pp" suffix and src_path will be updated.
+// In that case the caller is responsible to delete the temp file created.
+// output_name is the final name of the G-code on SD card or when uploaded to PrusaLink or OctoPrint.
+// If uploading to PrusaLink or OctoPrint, then the file will be renamed to output_name first on the target host.
+// The post-processing script may change the output_name.
+bool run_post_process_scripts(std::string &src_path, bool make_copy, const std::string &host, std::string &output_name, const DynamicPrintConfig &config)
{
- const auto* post_process = config.opt("post_process");
+ const auto *post_process = config.opt("post_process");
if (// likely running in SLA mode
post_process == nullptr ||
// no post-processing script
post_process->values.empty())
- return;
+ return false;
+
+ std::string path;
+ if (make_copy) {
+ // Don't run the post-processing script on the input file, it will be memory mapped by the G-code viewer.
+ // Make a copy.
+ path = src_path + ".pp";
+ // First delete an old file if it exists.
+ try {
+ if (boost::filesystem::exists(path))
+ boost::filesystem::remove(path);
+ } catch (const std::exception &err) {
+ BOOST_LOG_TRIVIAL(error) << Slic3r::format("Failed deleting an old temporary file %1% before running a post-processing script: %2%", path, err.what());
+ }
+ // Second make a copy.
+ std::string error_message;
+ if (copy_file(src_path, path, error_message, false) != SUCCESS)
+ throw Slic3r::RuntimeError(Slic3r::format("Failed making a temporary copy of G-code file %1% before running a post-processing script: %2%", src_path, error_message));
+ } else {
+ // Don't make a copy of the G-code before running the post-processing script.
+ path = src_path;
+ }
+
+ auto delete_copy = [&path, &src_path, make_copy]() {
+ if (make_copy)
+ try {
+ if (boost::filesystem::exists(path))
+ boost::filesystem::remove(path);
+ } catch (const std::exception &err) {
+ BOOST_LOG_TRIVIAL(error) << Slic3r::format("Failed deleting a temporary copy %1% of a G-code file %2% : %3%", path, src_path, err.what());
+ }
+ };
- // Store print configuration into environment variables.
- config.setenv_();
auto gcode_file = boost::filesystem::path(path);
if (! boost::filesystem::exists(gcode_file))
throw Slic3r::RuntimeError(std::string("Post-processor can't find exported gcode file"));
- for (const std::string &scripts : post_process->values) {
- std::vector lines;
- boost::split(lines, scripts, boost::is_any_of("\r\n"));
- for (std::string script : lines) {
- // Ignore empty post processing script lines.
- boost::trim(script);
- if (script.empty())
- continue;
- BOOST_LOG_TRIVIAL(info) << "Executing script " << script << " on file " << path;
+ // Store print configuration into environment variables.
+ config.setenv_();
+ // Let the post-processing script know the target host ("File", "PrusaLink", "Repetier", "SL1Host", "OctoPrint", "FlashAir", "Duet", "AstroBox" ...)
+ boost::nowide::setenv("SLIC3R_PP_HOST", host.c_str(), 1);
+ // Let the post-processing script know the final file name. For "File" host, it is a full path of the target file name and its location, for example pointing to an SD card.
+ // For "PrusaLink" or "OctoPrint", it is a file name optionally with a directory on the target host.
+ boost::nowide::setenv("SLIC3R_PP_OUTPUT_NAME", output_name.c_str(), 1);
- std::string std_err;
- const int result = run_script(script, gcode_file.string(), std_err);
- if (result != 0) {
- const std::string msg = std_err.empty() ? (boost::format("Post-processing script %1% on file %2% failed.\nError code: %3%") % script % path % result).str()
- : (boost::format("Post-processing script %1% on file %2% failed.\nError code: %3%\nOutput:\n%4%") % script % path % result % std_err).str();
- BOOST_LOG_TRIVIAL(error) << msg;
- throw Slic3r::RuntimeError(msg);
+ // Path to an optional file that the post-processing script may create and populate it with a single line containing the output_name replacement.
+ std::string path_output_name = path + ".output_name";
+ auto remove_output_name_file = [&path_output_name, &src_path]() {
+ try {
+ if (boost::filesystem::exists(path_output_name))
+ boost::filesystem::remove(path_output_name);
+ } catch (const std::exception &err) {
+ BOOST_LOG_TRIVIAL(error) << Slic3r::format("Failed deleting a file %1% carrying the final name / path of a G-code file %2%: %3%", path_output_name, src_path, err.what());
+ }
+ };
+ // Remove possible stalled path_output_name of the previous run.
+ remove_output_name_file();
+
+ try {
+ for (const std::string &scripts : post_process->values) {
+ std::vector lines;
+ boost::split(lines, scripts, boost::is_any_of("\r\n"));
+ for (std::string script : lines) {
+ // Ignore empty post processing script lines.
+ boost::trim(script);
+ if (script.empty())
+ continue;
+ BOOST_LOG_TRIVIAL(info) << "Executing script " << script << " on file " << path;
+ std::string std_err;
+ const int result = run_script(script, gcode_file.string(), std_err);
+ if (result != 0) {
+ const std::string msg = std_err.empty() ? (boost::format("Post-processing script %1% on file %2% failed.\nError code: %3%") % script % path % result).str()
+ : (boost::format("Post-processing script %1% on file %2% failed.\nError code: %3%\nOutput:\n%4%") % script % path % result % std_err).str();
+ BOOST_LOG_TRIVIAL(error) << msg;
+ delete_copy();
+ throw Slic3r::RuntimeError(msg);
+ }
}
}
+ if (boost::filesystem::exists(path_output_name)) {
+ try {
+ // Read a single line from path_output_name, which should contain the new output name of the post-processed G-code.
+ boost::nowide::fstream f;
+ f.open(path_output_name, std::ios::in);
+ std::string new_output_name;
+ std::getline(f, new_output_name);
+ f.close();
+
+ if (host == "File") {
+ namespace fs = boost::filesystem;
+ fs::path op(new_output_name);
+ if (op.is_relative() && op.has_filename() && op.parent_path().empty()) {
+ // Is this just a filename? Make it an absolute path.
+ auto outpath = fs::path(output_name).parent_path();
+ outpath /= op.string();
+ new_output_name = outpath.string();
+ }
+ else {
+ if (! op.is_absolute() || ! op.has_filename())
+ throw Slic3r::RuntimeError("Unable to parse desired new path from output name file");
+ }
+ if (! fs::exists(fs::path(new_output_name).parent_path()))
+ throw Slic3r::RuntimeError(Slic3r::format("Output directory does not exist: %1%",
+ fs::path(new_output_name).parent_path().string()));
+ }
+
+ BOOST_LOG_TRIVIAL(trace) << "Post-processing script changed the file name from " << output_name << " to " << new_output_name;
+ output_name = new_output_name;
+ } catch (const std::exception &err) {
+ throw Slic3r::RuntimeError(Slic3r::format("run_post_process_scripts: Failed reading a file %1% "
+ "carrying the final name / path of a G-code file: %2%",
+ path_output_name, err.what()));
+ }
+ remove_output_name_file();
+ }
+ } catch (...) {
+ remove_output_name_file();
+ delete_copy();
+ throw;
}
+
+ src_path = std::move(path);
+ return true;
}
} // namespace Slic3r
diff --git a/src/libslic3r/GCode/PostProcessor.hpp b/src/libslic3r/GCode/PostProcessor.hpp
index a9196aef7c..3ea4e0bc1e 100644
--- a/src/libslic3r/GCode/PostProcessor.hpp
+++ b/src/libslic3r/GCode/PostProcessor.hpp
@@ -8,7 +8,23 @@
namespace Slic3r {
-extern void run_post_process_scripts(const std::string &path, const DynamicPrintConfig &config);
+// Run post processing script / scripts if defined.
+// Returns true if a post-processing script was executed.
+// Returns false if no post-processing script was defined.
+// Throws an exception on error.
+// host is one of "File", "PrusaLink", "Repetier", "SL1Host", "OctoPrint", "FlashAir", "Duet", "AstroBox" ...
+// If make_copy, then a temp file will be created for src_path by adding a ".pp" suffix and src_path will be updated.
+// In that case the caller is responsible to delete the temp file created.
+// output_name is the final name of the G-code on SD card or when uploaded to PrusaLink or OctoPrint.
+// If uploading to PrusaLink or OctoPrint, then the file will be renamed to output_name first on the target host.
+// The post-processing script may change the output_name.
+extern bool run_post_process_scripts(std::string &src_path, bool make_copy, const std::string &host, std::string &output_name, const DynamicPrintConfig &config);
+
+inline bool run_post_process_scripts(std::string &src_path, const DynamicPrintConfig &config)
+{
+ std::string src_path_name = src_path;
+ return run_post_process_scripts(src_path, false, "File", src_path_name, config);
+}
} // namespace Slic3r
diff --git a/src/libslic3r/GCodeReader.cpp b/src/libslic3r/GCodeReader.cpp
index 3c76e05c78..7dc3c9a8ac 100644
--- a/src/libslic3r/GCodeReader.cpp
+++ b/src/libslic3r/GCodeReader.cpp
@@ -12,16 +12,24 @@
namespace Slic3r {
+static inline char get_extrusion_axis_char(const GCodeConfig &config)
+{
+ std::string axis = get_extrusion_axis(config);
+ assert(axis.size() <= 1);
+ // Return 0 for gcfNoExtrusion
+ return axis.empty() ? 0 : axis[0];
+}
+
void GCodeReader::apply_config(const GCodeConfig &config)
{
m_config = config;
- m_extrusion_axis = get_extrusion_axis(m_config)[0];
+ m_extrusion_axis = get_extrusion_axis_char(m_config);
}
void GCodeReader::apply_config(const DynamicPrintConfig &config)
{
m_config.apply(config, true);
- m_extrusion_axis = get_extrusion_axis(m_config)[0];
+ m_extrusion_axis = get_extrusion_axis_char(m_config);
}
const char* GCodeReader::parse_line_internal(const char *ptr, GCodeLine &gline, std::pair &command)
@@ -52,9 +60,10 @@ const char* GCodeReader::parse_line_internal(const char *ptr, GCodeLine &gline,
case 'Z': axis = Z; break;
case 'F': axis = F; break;
default:
- if (*c == m_extrusion_axis)
- axis = E;
- else if (*c >= 'A' && *c <= 'Z')
+ if (*c == m_extrusion_axis) {
+ if (m_extrusion_axis != 0)
+ axis = E;
+ } else if (*c >= 'A' && *c <= 'Z')
// Unknown axis, but we still want to remember that such a axis was seen.
axis = UNKNOWN_AXIS;
break;
@@ -190,6 +199,8 @@ void GCodeReader::GCodeLine::set(const GCodeReader &reader, const Axis axis, con
match[1] = 'F';
else {
assert(axis == E);
+ // Extruder axis is set.
+ assert(reader.extrusion_axis() != 0);
match[1] = reader.extrusion_axis();
}
diff --git a/src/libslic3r/GCodeReader.hpp b/src/libslic3r/GCodeReader.hpp
index ad9b7195a8..6b58608e61 100644
--- a/src/libslic3r/GCodeReader.hpp
+++ b/src/libslic3r/GCodeReader.hpp
@@ -122,8 +122,9 @@ public:
float& f() { return m_position[F]; }
float f() const { return m_position[F]; }
+ // Returns 0 for gcfNoExtrusion.
char extrusion_axis() const { return m_extrusion_axis; }
- void set_extrusion_axis(char axis) { m_extrusion_axis = axis; }
+// void set_extrusion_axis(char axis) { m_extrusion_axis = axis; }
private:
const char* parse_line_internal(const char *ptr, GCodeLine &gline, std::pair &command);
diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp
index bbb45c96d0..24549fd895 100644
--- a/src/libslic3r/GCodeWriter.cpp
+++ b/src/libslic3r/GCodeWriter.cpp
@@ -405,8 +405,10 @@ std::string GCodeWriter::extrude_to_xy(const Vec2d &point, double dE, const std:
std::ostringstream gcode;
gcode << "G1 X" << XYZF_NUM(point(0))
- << " Y" << XYZF_NUM(point(1))
- << " " << m_extrusion_axis << E_NUM(m_extruder->E());
+ << " Y" << XYZF_NUM(point(1));
+ if (! m_extrusion_axis.empty())
+ // not gcfNoExtrusion
+ gcode << " " << m_extrusion_axis << E_NUM(m_extruder->E());
COMMENT(comment);
gcode << "\n";
return gcode.str();
@@ -421,8 +423,10 @@ std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std
std::ostringstream gcode;
gcode << "G1 X" << XYZF_NUM(point(0))
<< " Y" << XYZF_NUM(point(1))
- << " Z" << XYZF_NUM(point(2))
- << " " << m_extrusion_axis << E_NUM(m_extruder->E());
+ << " Z" << XYZF_NUM(point(2));
+ if (! m_extrusion_axis.empty())
+ // not gcfNoExtrusion
+ gcode << " " << m_extrusion_axis << E_NUM(m_extruder->E());
COMMENT(comment);
gcode << "\n";
return gcode.str();
@@ -474,7 +478,7 @@ std::string GCodeWriter::_retract(double length, double restart_extra, const std
gcode << "G22 ; retract\n";
else
gcode << "G10 ; retract\n";
- } else {
+ } else if (! m_extrusion_axis.empty()) {
gcode << "G1 " << m_extrusion_axis << E_NUM(m_extruder->E())
<< " F" << XYZF_NUM(m_extruder->retract_speed() * 60.);
COMMENT(comment);
@@ -503,7 +507,7 @@ std::string GCodeWriter::unretract()
else
gcode << "G11 ; unretract\n";
gcode << this->reset_e();
- } else {
+ } else if (! m_extrusion_axis.empty()) {
// use G1 instead of G0 because G0 will blend the restart with the previous travel move
gcode << "G1 " << m_extrusion_axis << E_NUM(m_extruder->E())
<< " F" << XYZF_NUM(m_extruder->deretract_speed() * 60.);
diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp
index 3a57c8bd29..2de95ecc5b 100644
--- a/src/libslic3r/GCodeWriter.hpp
+++ b/src/libslic3r/GCodeWriter.hpp
@@ -25,6 +25,7 @@ public:
Extruder* extruder() { return m_extruder; }
const Extruder* extruder() const { return m_extruder; }
+ // Returns empty string for gcfNoExtrusion.
std::string extrusion_axis() const { return m_extrusion_axis; }
void apply_print_config(const PrintConfig &print_config);
// Extruders are expected to be sorted in an increasing order.
diff --git a/src/libslic3r/MeshBoolean.cpp b/src/libslic3r/MeshBoolean.cpp
index 3dd5da307f..a59165946a 100644
--- a/src/libslic3r/MeshBoolean.cpp
+++ b/src/libslic3r/MeshBoolean.cpp
@@ -118,6 +118,11 @@ void triangle_mesh_to_cgal(const std::vector & V,
{
if (F.empty()) return;
+ size_t vertices_count = V.size();
+ size_t edges_count = (F.size()* 3) / 2;
+ size_t faces_count = F.size();
+ out.reserve(vertices_count, edges_count, faces_count);
+
for (auto &v : V)
out.add_vertex(typename _Mesh::Point{v.x(), v.y(), v.z()});
diff --git a/src/libslic3r/MeshSplitImpl.hpp b/src/libslic3r/MeshSplitImpl.hpp
index 7946411aa9..7233ac40d6 100644
--- a/src/libslic3r/MeshSplitImpl.hpp
+++ b/src/libslic3r/MeshSplitImpl.hpp
@@ -157,6 +157,7 @@ template bool its_is_splittable(const Its &m)
const auto& neighbor_index = ItsWithNeighborsIndex_::get_index(m);
std::vector visited(its.indices.size(), false);
+ its_find_unvisited_neighbors(its, neighbor_index, visited);
auto faces = its_find_unvisited_neighbors(its, neighbor_index, visited);
return !faces.empty();
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index ba743f49ca..6654d3a130 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -424,7 +424,7 @@ void Model::convert_multipart_object(unsigned int max_extruders)
ModelObject* object = new ModelObject(this);
object->input_file = this->objects.front()->input_file;
- object->name = this->objects.front()->name;
+ object->name = boost::filesystem::path(this->objects.front()->input_file).stem().string();
//FIXME copy the config etc?
unsigned int extruder_counter = 0;
@@ -439,7 +439,7 @@ void Model::convert_multipart_object(unsigned int max_extruders)
int counter = 1;
auto copy_volume = [o, max_extruders, &counter, &extruder_counter](ModelVolume *new_v) {
assert(new_v != nullptr);
- new_v->name = o->name + "_" + std::to_string(counter++);
+ new_v->name = (counter > 1) ? o->name + "_" + std::to_string(counter++) : o->name;
new_v->config.set("extruder", auto_extruder_id(max_extruders, extruder_counter));
return new_v;
};
@@ -460,13 +460,15 @@ void Model::convert_multipart_object(unsigned int max_extruders)
this->objects.push_back(object);
}
+static constexpr const double volume_threshold_inches = 9.0; // 9 = 3*3*3;
+
bool Model::looks_like_imperial_units() const
{
if (this->objects.size() == 0)
return false;
for (ModelObject* obj : this->objects)
- if (obj->get_object_stl_stats().volume < 9.0) // 9 = 3*3*3;
+ if (obj->get_object_stl_stats().volume < volume_threshold_inches)
return true;
return false;
@@ -474,22 +476,26 @@ bool Model::looks_like_imperial_units() const
void Model::convert_from_imperial_units(bool only_small_volumes)
{
- double in_to_mm = 25.4;
+ static constexpr const double in_to_mm = 25.4;
for (ModelObject* obj : this->objects)
- if (! only_small_volumes || obj->get_object_stl_stats().volume < 9.0) { // 9 = 3*3*3;
+ if (! only_small_volumes || obj->get_object_stl_stats().volume < volume_threshold_inches) {
obj->scale_mesh_after_creation(Vec3d(in_to_mm, in_to_mm, in_to_mm));
- for (ModelVolume* v : obj->volumes)
+ for (ModelVolume* v : obj->volumes) {
+ assert(! v->source.is_converted_from_meters);
v->source.is_converted_from_inches = true;
+ }
}
}
+static constexpr const double volume_threshold_meters = 0.001; // 0.001 = 0.1*0.1*0.1
+
bool Model::looks_like_saved_in_meters() const
{
if (this->objects.size() == 0)
return false;
for (ModelObject* obj : this->objects)
- if (obj->get_object_stl_stats().volume < 0.001) // 0.001 = 0.1*0.1*0.1;
+ if (obj->get_object_stl_stats().volume < volume_threshold_meters)
return true;
return false;
@@ -497,12 +503,14 @@ bool Model::looks_like_saved_in_meters() const
void Model::convert_from_meters(bool only_small_volumes)
{
- double m_to_mm = 1000;
+ static constexpr const double m_to_mm = 1000;
for (ModelObject* obj : this->objects)
- if (! only_small_volumes || obj->get_object_stl_stats().volume < 0.001) { // 0.001 = 0.1*0.1*0.1;
+ if (! only_small_volumes || obj->get_object_stl_stats().volume < volume_threshold_meters) {
obj->scale_mesh_after_creation(Vec3d(m_to_mm, m_to_mm, m_to_mm));
- for (ModelVolume* v : obj->volumes)
+ for (ModelVolume* v : obj->volumes) {
+ assert(! v->source.is_converted_from_inches);
v->source.is_converted_from_meters = true;
+ }
}
}
@@ -948,9 +956,26 @@ void ModelObject::center_around_origin(bool include_modifiers)
void ModelObject::ensure_on_bed(bool allow_negative_z)
{
- const double min_z = get_min_z();
- if (!allow_negative_z || min_z > SINKING_Z_THRESHOLD)
- translate_instances({ 0.0, 0.0, -min_z });
+ double z_offset = 0.0;
+
+ if (allow_negative_z) {
+ if (parts_count() == 1) {
+ const double min_z = get_min_z();
+ const double max_z = get_max_z();
+ if (min_z >= SINKING_Z_THRESHOLD || max_z < 0.0)
+ z_offset = -min_z;
+ }
+ else {
+ const double max_z = get_max_z();
+ if (max_z < SINKING_MIN_Z_THRESHOLD)
+ z_offset = SINKING_MIN_Z_THRESHOLD - max_z;
+ }
+ }
+ else
+ z_offset = -get_min_z();
+
+ if (z_offset != 0.0)
+ translate_instances(z_offset * Vec3d::UnitZ());
}
void ModelObject::translate_instances(const Vec3d& vector)
@@ -1075,6 +1100,7 @@ void ModelObject::convert_units(ModelObjectPtrs& new_objects, ConversionType con
vol->source.is_converted_from_inches = conv_type == ConversionType::CONV_FROM_INCH;
if (conv_type == ConversionType::CONV_FROM_METER || conv_type == ConversionType::CONV_TO_METER)
vol->source.is_converted_from_meters = conv_type == ConversionType::CONV_FROM_METER;
+ assert(! vol->source.is_converted_from_inches || ! vol->source.is_converted_from_meters);
}
else
vol->set_offset(volume->get_offset());
@@ -1105,6 +1131,15 @@ size_t ModelObject::facets_count() const
return num;
}
+size_t ModelObject::parts_count() const
+{
+ size_t num = 0;
+ for (const ModelVolume* v : this->volumes)
+ if (v->is_model_part())
+ ++num;
+ return num;
+}
+
bool ModelObject::needed_repair() const
{
for (const ModelVolume *v : this->volumes)
@@ -1420,6 +1455,19 @@ double ModelObject::get_min_z() const
}
}
+double ModelObject::get_max_z() const
+{
+ if (instances.empty())
+ return 0.0;
+ else {
+ double max_z = -DBL_MAX;
+ for (size_t i = 0; i < instances.size(); ++i) {
+ max_z = std::max(max_z, get_instance_max_z(i));
+ }
+ return max_z;
+ }
+}
+
double ModelObject::get_instance_min_z(size_t instance_idx) const
{
double min_z = DBL_MAX;
@@ -1441,6 +1489,27 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const
return min_z + inst->get_offset(Z);
}
+double ModelObject::get_instance_max_z(size_t instance_idx) const
+{
+ double max_z = -DBL_MAX;
+
+ const ModelInstance* inst = instances[instance_idx];
+ const Transform3d& mi = inst->get_matrix(true);
+
+ for (const ModelVolume* v : volumes) {
+ if (!v->is_model_part())
+ continue;
+
+ const Transform3d mv = mi * v->get_matrix();
+ const TriangleMesh& hull = v->get_convex_hull();
+ for (const stl_facet& facet : hull.stl.facet_start)
+ for (int i = 0; i < 3; ++i)
+ max_z = std::max(max_z, (mv * facet.vertex[i].cast()).z());
+ }
+
+ return max_z + inst->get_offset(Z);
+}
+
unsigned int ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume)
{
unsigned int num_printable = 0;
@@ -1827,6 +1896,7 @@ void ModelVolume::transform_this_mesh(const Matrix3d &matrix, bool fix_left_hand
void ModelVolume::convert_from_imperial_units()
{
+ assert(! this->source.is_converted_from_meters);
double in_to_mm = 25.4;
this->scale_geometry_after_creation(Vec3d(in_to_mm, in_to_mm, in_to_mm));
this->set_offset(Vec3d(0, 0, 0));
@@ -1835,6 +1905,7 @@ void ModelVolume::convert_from_imperial_units()
void ModelVolume::convert_from_meters()
{
+ assert(! this->source.is_converted_from_inches);
double m_to_mm = 1000;
this->scale_geometry_after_creation(Vec3d(m_to_mm, m_to_mm, m_to_mm));
this->set_offset(Vec3d(0, 0, 0));
diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp
index 11dcfa7757..b89dd5aa1e 100644
--- a/src/libslic3r/Model.hpp
+++ b/src/libslic3r/Model.hpp
@@ -347,6 +347,7 @@ public:
size_t materials_count() const;
size_t facets_count() const;
+ size_t parts_count() const;
bool needed_repair() const;
ModelObjectPtrs cut(size_t instance, coordf_t z, ModelObjectCutAttributes attributes);
void split(ModelObjectPtrs* new_objects);
@@ -358,7 +359,9 @@ public:
void bake_xy_rotation_into_meshes(size_t instance_idx);
double get_min_z() const;
+ double get_max_z() const;
double get_instance_min_z(size_t instance_idx) const;
+ double get_instance_max_z(size_t instance_idx) const;
// Called by Print::validate() from the UI thread.
unsigned int check_instances_print_volume_state(const BoundingBoxf3& print_volume);
@@ -1177,6 +1180,7 @@ void check_model_ids_equal(const Model &model1, const Model &model2);
#endif /* NDEBUG */
static const float SINKING_Z_THRESHOLD = -0.001f;
+static const double SINKING_MIN_Z_THRESHOLD = 0.05;
} // namespace Slic3r
diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp
index 95475b0d7c..9456f50775 100644
--- a/src/libslic3r/MultiMaterialSegmentation.cpp
+++ b/src/libslic3r/MultiMaterialSegmentation.cpp
@@ -1240,221 +1240,6 @@ static inline std::vector> mmu_segmentation_top_and_bott
const size_t num_layers = input_expolygons.size();
const ConstLayerPtrsAdaptor layers = print_object.layers();
-#if 0
- auto get_extrusion_width = [&layers = std::as_const(layers)](const size_t layer_idx) -> float {
- auto extrusion_width_it = std::max_element(layers[layer_idx]->regions().begin(), layers[layer_idx]->regions().end(),
- [](const LayerRegion *l1, const LayerRegion *l2) {
- return l1->region().config().perimeter_extrusion_width <
- l2->region().config().perimeter_extrusion_width;
- });
- assert(extrusion_width_it != layers[layer_idx]->regions().end());
- return float((*extrusion_width_it)->region().config().perimeter_extrusion_width);
- };
-
- auto get_top_solid_layers = [&layers = std::as_const(layers)](const size_t layer_idx) -> int {
- auto top_solid_layer_it = std::max_element(layers[layer_idx]->regions().begin(), layers[layer_idx]->regions().end(),
- [](const LayerRegion *l1, const LayerRegion *l2) {
- return l1->region().config().top_solid_layers < l2->region().config().top_solid_layers;
- });
- assert(top_solid_layer_it != layers[layer_idx]->regions().end());
- return (*top_solid_layer_it)->region().config().top_solid_layers;
- };
-
- auto get_bottom_solid_layers = [&layers = std::as_const(layers)](const size_t layer_idx) -> int {
- auto top_bottom_layer_it = std::max_element(layers[layer_idx]->regions().begin(), layers[layer_idx]->regions().end(),
- [](const LayerRegion *l1, const LayerRegion *l2) {
- return l1->region().config().bottom_solid_layers < l2->region().config().bottom_solid_layers;
- });
- assert(top_bottom_layer_it != layers[layer_idx]->regions().end());
- return (*top_bottom_layer_it)->region().config().bottom_solid_layers;
- };
-
- std::vector top_layers(num_layers);
- top_layers.back() = input_expolygons.back();
- tbb::parallel_for(tbb::blocked_range(1, num_layers), [&](const tbb::blocked_range &range) {
- for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
- throw_on_cancel_callback();
- float extrusion_width = 0.1f * float(scale_(get_extrusion_width(layer_idx)));
- top_layers[layer_idx - 1] = diff_ex(input_expolygons[layer_idx - 1], offset_ex(input_expolygons[layer_idx], extrusion_width));
- }
- }); // end of parallel_for
-
- std::vector bottom_layers(num_layers);
- bottom_layers.front() = input_expolygons.front();
- tbb::parallel_for(tbb::blocked_range(0, num_layers - 1), [&](const tbb::blocked_range &range) {
- for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
- throw_on_cancel_callback();
- float extrusion_width = 0.1f * float(scale_(get_extrusion_width(layer_idx)));
- bottom_layers[layer_idx + 1] = diff_ex(input_expolygons[layer_idx + 1], offset_ex(input_expolygons[layer_idx], extrusion_width));
- }
- }); // end of parallel_for
-
- std::vector> triangles_by_color_raw(num_extruders, std::vector(layers.size()));
- BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - top and bottom layers - projection of painted triangles - begin";
- {
- auto delta = float(10 * SCALED_EPSILON);
- std::vector deltas { delta, delta, delta };
- Points projected_facet;
- for (const ModelVolume *mv : print_object.model_object()->volumes)
- if (mv->is_model_part()) {
- const Transform3f tr = print_object.trafo().cast() * mv->get_matrix().cast();
-
- for (size_t extruder_idx = 0; extruder_idx < num_extruders; ++extruder_idx) {
- const indexed_triangle_set custom_facets = mv->mmu_segmentation_facets.get_facets(*mv, EnforcerBlockerType(extruder_idx));
- if (custom_facets.indices.empty())
- continue;
-
- throw_on_cancel_callback();
- for (size_t facet_idx = 0; facet_idx < custom_facets.indices.size(); ++facet_idx) {
- float min_z = std::numeric_limits::max();
- float max_z = std::numeric_limits::lowest();
-
- std::array facet;
- for (int p_idx = 0; p_idx < 3; ++p_idx) {
- facet[p_idx] = tr * custom_facets.vertices[custom_facets.indices[facet_idx](p_idx)];
- max_z = std::max(max_z, facet[p_idx].z());
- min_z = std::min(min_z, facet[p_idx].z());
- }
-
- // Sort the vertices by z-axis for simplification of projected_facet on slices
- std::sort(facet.begin(), facet.end(), [](const Vec3f &p1, const Vec3f &p2) { return p1.z() < p2.z(); });
- projected_facet.clear();
- projected_facet.reserve(3);
- for (int p_idx = 0; p_idx < 3; ++p_idx)
- projected_facet.emplace_back(Point(scale_(facet[p_idx].x()), scale_(facet[p_idx].y())) - print_object.center_offset());
- if (cross2((projected_facet[1] - projected_facet[0]).cast(), (projected_facet[2] - projected_facet[1]).cast()) < 0)
- // Make CCW.
- std::swap(projected_facet[1], projected_facet[2]);
- ClipperLib::Path offsetted = mittered_offset_path_scaled(projected_facet, deltas, 3.);
-
- // Find lowest slice not below the triangle.
- auto first_layer = std::upper_bound(layers.begin(), layers.end(), float(min_z - EPSILON),
- [](float z, const Layer *l1) { return z < l1->slice_z + l1->height * 0.5; });
- auto last_layer = std::upper_bound(layers.begin(), layers.end(), float(max_z - EPSILON),
- [](float z, const Layer *l1) { return z < l1->slice_z + l1->height * 0.5; });
-
- if (last_layer == layers.end())
- --last_layer;
-
- if (first_layer == layers.end() || (first_layer != layers.begin() && facet[0].z() < (*first_layer)->print_z - EPSILON))
- --first_layer;
-
- for (auto layer_it = first_layer; (layer_it != (last_layer + 1) && layer_it != layers.end()); ++layer_it)
- if (size_t layer_idx = layer_it - layers.begin(); ! top_layers[layer_idx].empty() || ! bottom_layers[layer_idx].empty())
- triangles_by_color_raw[extruder_idx][layer_idx].emplace_back(offsetted);
- }
- }
- }
- }
- BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - top and bottom layers - projection of painted triangles - end";
-
- std::vector> triangles_by_color(num_extruders, std::vector(layers.size()));
- tbb::parallel_for(tbb::blocked_range(0, num_layers), [&](const tbb::blocked_range &range) {
- for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
- throw_on_cancel_callback();
- float offset_factor = 0.1f * float(scale_(get_extrusion_width(layer_idx)));
- for (size_t extruder_id = 0; extruder_id < num_extruders; ++ extruder_id)
- if (ClipperLib::Paths &src_paths = triangles_by_color_raw[extruder_id][layer_idx]; !src_paths.empty())
- triangles_by_color[extruder_id][layer_idx] = offset_ex(offset_ex(ClipperPaths_to_Slic3rExPolygons(src_paths), -offset_factor), offset_factor);
- }
- }); // end of parallel_for
- triangles_by_color_raw.clear();
-
- std::vector> triangles_by_color_bottom(num_extruders);
- std::vector> triangles_by_color_top(num_extruders);
- triangles_by_color_bottom.assign(num_extruders, std::vector(num_layers));
- triangles_by_color_top.assign(num_extruders, std::vector(num_layers));
-
- BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of top layer - begin";
- for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
- float extrusion_width = scale_(get_extrusion_width(layer_idx));
- int top_solid_layers = get_top_solid_layers(layer_idx);
- ExPolygons top_expolygon = top_layers[layer_idx];
- if (top_expolygon.empty())
- continue;
-
- for (size_t color_idx = 0; color_idx < triangles_by_color.size(); ++color_idx) {
- throw_on_cancel_callback();
- if (triangles_by_color[color_idx][layer_idx].empty())
- continue;
- ExPolygons intersection_poly = intersection_ex(triangles_by_color[color_idx][layer_idx], top_expolygon);
- if (!intersection_poly.empty()) {
- triangles_by_color_top[color_idx][layer_idx].insert(triangles_by_color_top[color_idx][layer_idx].end(), intersection_poly.begin(),
- intersection_poly.end());
- for (int last_idx = int(layer_idx) - 1; last_idx >= std::max(int(layer_idx - top_solid_layers), int(0)); --last_idx) {
- float offset_value = float(layer_idx - last_idx) * (-1.0f) * extrusion_width;
- if (offset_ex(top_expolygon, offset_value).empty())
- continue;
- ExPolygons layer_slices_trimmed = input_expolygons[last_idx];
-
- for (int last_idx_1 = last_idx; last_idx_1 < int(layer_idx); ++last_idx_1) {
- layer_slices_trimmed = intersection_ex(layer_slices_trimmed, input_expolygons[last_idx_1 + 1]);
- }
-
- ExPolygons offset_e = offset_ex(layer_slices_trimmed, offset_value);
- ExPolygons intersection_poly_2 = intersection_ex(triangles_by_color_top[color_idx][layer_idx], offset_e);
- triangles_by_color_top[color_idx][last_idx].insert(triangles_by_color_top[color_idx][last_idx].end(), intersection_poly_2.begin(),
- intersection_poly_2.end());
- }
- }
- }
- }
- BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of top layer - end";
-
- BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of bottom layer - begin";
- for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
- float extrusion_width = scale_(get_extrusion_width(layer_idx));
- int bottom_solid_layers = get_bottom_solid_layers(layer_idx);
- const ExPolygons &bottom_expolygon = bottom_layers[layer_idx];
- if (bottom_expolygon.empty())
- continue;
-
- for (size_t color_idx = 0; color_idx < triangles_by_color.size(); ++color_idx) {
- throw_on_cancel_callback();
- if (triangles_by_color[color_idx][layer_idx].empty())
- continue;
-
- ExPolygons intersection_poly = intersection_ex(triangles_by_color[color_idx][layer_idx], bottom_expolygon);
- if (!intersection_poly.empty()) {
- triangles_by_color_bottom[color_idx][layer_idx].insert(triangles_by_color_bottom[color_idx][layer_idx].end(), intersection_poly.begin(),
- intersection_poly.end());
- for (size_t last_idx = layer_idx + 1; last_idx < std::min(layer_idx + bottom_solid_layers, num_layers); ++last_idx) {
- float offset_value = float(last_idx - layer_idx) * (-1.0f) * extrusion_width;
- if (offset_ex(bottom_expolygon, offset_value).empty())
- continue;
- ExPolygons layer_slices_trimmed = input_expolygons[last_idx];
- for (int last_idx_1 = int(last_idx); last_idx_1 > int(layer_idx); --last_idx_1) {
- layer_slices_trimmed = intersection_ex(layer_slices_trimmed, offset_ex(input_expolygons[last_idx_1 - 1], offset_value));
- }
-
- ExPolygons offset_e = offset_ex(layer_slices_trimmed, offset_value);
- ExPolygons intersection_poly_2 = intersection_ex(triangles_by_color_bottom[color_idx][layer_idx], offset_e);
- append(triangles_by_color_bottom[color_idx][last_idx], std::move(intersection_poly_2));
- }
- }
- }
- }
- BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of bottom layer - end";
-
- std::vector> triangles_by_color_merged(num_extruders);
- triangles_by_color_merged.assign(num_extruders, std::vector(num_layers));
- for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
- throw_on_cancel_callback();
- for (size_t color_idx = 0; color_idx < triangles_by_color_merged.size(); ++color_idx) {
- auto &self = triangles_by_color_merged[color_idx][layer_idx];
- append(self, std::move(triangles_by_color_bottom[color_idx][layer_idx]));
- append(self, std::move(triangles_by_color_top[color_idx][layer_idx]));
- self = union_ex(self);
- }
-
- // Cut all colors for cases when two colors are overlapping
- for (size_t color_idx = 1; color_idx < triangles_by_color_merged.size(); ++color_idx) {
- triangles_by_color_merged[color_idx][layer_idx] = diff_ex(triangles_by_color_merged[color_idx][layer_idx],
- triangles_by_color_merged[color_idx - 1][layer_idx]);
- }
- }
-#else
-
// Maximum number of top / bottom layers accounts for maximum overlap of one thread group into a neighbor thread group.
int max_top_layers = 0;
int max_bottom_layers = 0;
@@ -1470,8 +1255,7 @@ static inline std::vector> mmu_segmentation_top_and_bott
// project downards pointing painted triangles over bottom surfaces.
std::vector> top_raw(num_extruders), bottom_raw(num_extruders);
std::vector zs = zs_from_layers(print_object.layers());
- Transform3d object_trafo = print_object.trafo();
- object_trafo.pretranslate(Vec3d(- unscale(print_object.center_offset().x()), - unscale(print_object.center_offset().y()), 0));
+ Transform3d object_trafo = print_object.trafo_centered();
#ifdef MMU_SEGMENTATION_DEBUG_TOP_BOTTOM
static int iRun = 0;
@@ -1650,7 +1434,6 @@ static inline std::vector> mmu_segmentation_top_and_bott
triangles_by_color_merged[color_idx - 1][layer_idx]);
}
});
-#endif
return triangles_by_color_merged;
}
diff --git a/src/libslic3r/MutablePriorityQueue.hpp b/src/libslic3r/MutablePriorityQueue.hpp
index 68cd01859c..cc1cae68c9 100644
--- a/src/libslic3r/MutablePriorityQueue.hpp
+++ b/src/libslic3r/MutablePriorityQueue.hpp
@@ -354,7 +354,7 @@ inline void MutableSkipHeapPriorityQueue::max());
+ m_index_setter(m_heap[1], std::numeric_limits::max());
}
// Zero'th element is padding, thus non-empty queue must have at least two elements.
if (m_heap.size() > 2) {
diff --git a/src/libslic3r/PlaceholderParser.hpp b/src/libslic3r/PlaceholderParser.hpp
index ae6ef8f02c..6157ffe3c8 100644
--- a/src/libslic3r/PlaceholderParser.hpp
+++ b/src/libslic3r/PlaceholderParser.hpp
@@ -24,6 +24,7 @@ public:
PlaceholderParser(const DynamicConfig *external_config = nullptr);
+ void clear_config() { m_config.clear(); }
// Return a list of keys, which should be changed in m_config from rhs.
// This contains keys, which are found in rhs, but not in m_config.
std::vector config_diff(const DynamicPrintConfig &rhs);
diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp
index 1283d0ac1a..3883c4980b 100644
--- a/src/libslic3r/Preset.cpp
+++ b/src/libslic3r/Preset.cpp
@@ -413,212 +413,181 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config)
}
}
-const std::vector& Preset::print_options()
-{
- static std::vector s_opts {
- "layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius", "slicing_mode",
- "top_solid_layers", "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness",
- "extra_perimeters", "ensure_vertical_shell_thickness", "avoid_crossing_perimeters", "thin_walls", "overhangs",
- "seam_position", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
- "infill_every_layers", "infill_only_where_needed", "solid_infill_every_layers", "fill_angle", "bridge_angle",
- "solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first",
- "ironing", "ironing_type", "ironing_flowrate", "ironing_speed", "ironing_spacing",
- "max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour",
- "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_dist",
+static std::vector s_Preset_print_options {
+ "layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius", "slicing_mode",
+ "top_solid_layers", "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness",
+ "extra_perimeters", "ensure_vertical_shell_thickness", "avoid_crossing_perimeters", "thin_walls", "overhangs",
+ "seam_position", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
+ "infill_every_layers", "infill_only_where_needed", "solid_infill_every_layers", "fill_angle", "bridge_angle",
+ "solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first",
+ "ironing", "ironing_type", "ironing_flowrate", "ironing_speed", "ironing_spacing",
+ "max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour",
+ "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_dist",
#ifdef HAS_PRESSURE_EQUALIZER
- "max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative",
+ "max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative",
#endif /* HAS_PRESSURE_EQUALIZER */
- "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "infill_speed", "solid_infill_speed",
- "top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed",
- "bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "perimeter_acceleration", "infill_acceleration",
- "bridge_acceleration", "first_layer_acceleration", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield",
- "min_skirt_length", "brim_width", "brim_offset", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers",
- "raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion",
- "support_material_pattern", "support_material_with_sheath", "support_material_spacing", "support_material_closing_radius", "support_material_style",
- "support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_bottom_interface_layers",
- "support_material_interface_pattern", "support_material_interface_spacing", "support_material_interface_contact_loops",
- "support_material_contact_distance", "support_material_bottom_contact_distance",
- "support_material_buildplate_only", "dont_support_bridges", "thick_bridges", "notes", "complete_objects", "extruder_clearance_radius",
- "extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "perimeter_extruder",
- "infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder",
- "ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width",
- "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
- "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "infill_anchor", "infill_anchor_max", "bridge_flow_ratio", "clip_multipart_objects",
- "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y",
- "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width",
- "wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits"
- };
- return s_opts;
-}
+ "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "infill_speed", "solid_infill_speed",
+ "top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed",
+ "bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "perimeter_acceleration", "infill_acceleration",
+ "bridge_acceleration", "first_layer_acceleration", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield",
+ "min_skirt_length", "brim_width", "brim_offset", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers",
+ "raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion",
+ "support_material_pattern", "support_material_with_sheath", "support_material_spacing", "support_material_closing_radius", "support_material_style",
+ "support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_bottom_interface_layers",
+ "support_material_interface_pattern", "support_material_interface_spacing", "support_material_interface_contact_loops",
+ "support_material_contact_distance", "support_material_bottom_contact_distance",
+ "support_material_buildplate_only", "dont_support_bridges", "thick_bridges", "notes", "complete_objects", "extruder_clearance_radius",
+ "extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "perimeter_extruder",
+ "infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder",
+ "ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width",
+ "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
+ "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "infill_anchor", "infill_anchor_max", "bridge_flow_ratio", "clip_multipart_objects",
+ "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y",
+ "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width",
+ "wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits"
+};
-const std::vector& Preset::filament_options()
-{
- static std::vector s_opts {
- "filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed",
- "extrusion_multiplier", "filament_density", "filament_cost", "filament_spool_weight", "filament_loading_speed", "filament_loading_speed_start", "filament_load_time",
- "filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves",
- "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_minimal_purge_on_wipe_tower",
- "temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed",
- "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "full_fan_speed_layer", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed",
- "start_filament_gcode", "end_filament_gcode",
- // Retract overrides
- "filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel",
- "filament_retract_layer_change", "filament_wipe", "filament_retract_before_wipe",
- // Profile compatibility
- "filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits"
- };
- return s_opts;
-}
+static std::vector s_Preset_filament_options {
+ "filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed",
+ "extrusion_multiplier", "filament_density", "filament_cost", "filament_spool_weight", "filament_loading_speed", "filament_loading_speed_start", "filament_load_time",
+ "filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves",
+ "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_minimal_purge_on_wipe_tower",
+ "temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed",
+ "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "full_fan_speed_layer", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed",
+ "start_filament_gcode", "end_filament_gcode",
+ // Retract overrides
+ "filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel",
+ "filament_retract_layer_change", "filament_wipe", "filament_retract_before_wipe",
+ // Profile compatibility
+ "filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits"
+};
-const std::vector& Preset::machine_limits_options()
-{
- static std::vector s_opts;
- if (s_opts.empty()) {
- s_opts = {
- "machine_max_acceleration_extruding", "machine_max_acceleration_retracting", "machine_max_acceleration_travel",
- "machine_max_acceleration_x", "machine_max_acceleration_y", "machine_max_acceleration_z", "machine_max_acceleration_e",
- "machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e",
- "machine_min_extruding_rate", "machine_min_travel_rate",
- "machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e",
- };
- }
- return s_opts;
-}
+static std::vector s_Preset_machine_limits_options {
+ "machine_max_acceleration_extruding", "machine_max_acceleration_retracting", "machine_max_acceleration_travel",
+ "machine_max_acceleration_x", "machine_max_acceleration_y", "machine_max_acceleration_z", "machine_max_acceleration_e",
+ "machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e",
+ "machine_min_extruding_rate", "machine_min_travel_rate",
+ "machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e",
+};
+
+static std::vector s_Preset_printer_options {
+ "printer_technology",
+ "bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset", "gcode_flavor", "use_relative_e_distances",
+ "use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
+ //FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset.
+ "host_type", "print_host", "printhost_apikey", "printhost_cafile",
+ "single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
+ "color_change_gcode", "pause_print_gcode", "template_custom_gcode",
+ "between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction",
+ "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "max_print_height",
+ "default_print_profile", "inherits",
+ "remaining_times", "silent_mode",
+ "machine_limits_usage", "thumbnails"
+};
+
+static std::vector s_Preset_sla_print_options {
+ "layer_height",
+ "faded_layers",
+ "supports_enable",
+ "support_head_front_diameter",
+ "support_head_penetration",
+ "support_head_width",
+ "support_pillar_diameter",
+ "support_small_pillar_diameter_percent",
+ "support_max_bridges_on_pillar",
+ "support_pillar_connection_mode",
+ "support_buildplate_only",
+ "support_pillar_widening_factor",
+ "support_base_diameter",
+ "support_base_height",
+ "support_base_safety_distance",
+ "support_critical_angle",
+ "support_max_bridge_length",
+ "support_max_pillar_link_distance",
+ "support_object_elevation",
+ "support_points_density_relative",
+ "support_points_minimal_distance",
+ "slice_closing_radius",
+ "slicing_mode",
+ "pad_enable",
+ "pad_wall_thickness",
+ "pad_wall_height",
+ "pad_brim_size",
+ "pad_max_merge_distance",
+ // "pad_edge_radius",
+ "pad_wall_slope",
+ "pad_object_gap",
+ "pad_around_object",
+ "pad_around_object_everywhere",
+ "pad_object_connector_stride",
+ "pad_object_connector_width",
+ "pad_object_connector_penetration",
+ "hollowing_enable",
+ "hollowing_min_thickness",
+ "hollowing_quality",
+ "hollowing_closing_distance",
+ "output_filename_format",
+ "default_sla_print_profile",
+ "compatible_printers",
+ "compatible_printers_condition",
+ "inherits"
+};
+
+static std::vector s_Preset_sla_material_options {
+ "material_type",
+ "initial_layer_height",
+ "bottle_cost",
+ "bottle_volume",
+ "bottle_weight",
+ "material_density",
+ "exposure_time",
+ "initial_exposure_time",
+ "material_correction",
+ "material_notes",
+ "material_vendor",
+ "default_sla_material_profile",
+ "compatible_prints", "compatible_prints_condition",
+ "compatible_printers", "compatible_printers_condition", "inherits"
+};
+
+static std::vector s_Preset_sla_printer_options {
+ "printer_technology",
+ "bed_shape", "bed_custom_texture", "bed_custom_model", "max_print_height",
+ "display_width", "display_height", "display_pixels_x", "display_pixels_y",
+ "display_mirror_x", "display_mirror_y",
+ "display_orientation",
+ "fast_tilt_time", "slow_tilt_time", "area_fill",
+ "relative_correction",
+ "absolute_correction",
+ "elefant_foot_compensation",
+ "elefant_foot_min_width",
+ "gamma_correction",
+ "min_exposure_time", "max_exposure_time",
+ "min_initial_exposure_time", "max_initial_exposure_time",
+ //FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset.
+ "print_host", "printhost_apikey", "printhost_cafile",
+ "printer_notes",
+ "inherits"
+};
+
+const std::vector& Preset::print_options() { return s_Preset_print_options; }
+const std::vector& Preset::filament_options() { return s_Preset_filament_options; }
+const std::vector& Preset::machine_limits_options() { return s_Preset_machine_limits_options; }
+// The following nozzle options of a printer profile will be adjusted to match the size
+// of the nozzle_diameter vector.
+const std::vector& Preset::nozzle_options() { return print_config_def.extruder_option_keys(); }
+const std::vector& Preset::sla_print_options() { return s_Preset_sla_print_options; }
+const std::vector& Preset::sla_material_options() { return s_Preset_sla_material_options; }
+const std::vector& Preset::sla_printer_options() { return s_Preset_sla_printer_options; }
const std::vector& Preset::printer_options()
{
- static std::vector s_opts;
- if (s_opts.empty()) {
- s_opts = {
- "printer_technology",
- "bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset", "gcode_flavor", "use_relative_e_distances",
- "use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
- //FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset.
- "host_type", "print_host", "printhost_apikey", "printhost_cafile",
- "single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
- "color_change_gcode", "pause_print_gcode", "template_custom_gcode",
- "between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction",
- "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "max_print_height",
- "default_print_profile", "inherits",
- "remaining_times", "silent_mode",
- "machine_limits_usage", "thumbnails"
- };
- s_opts.insert(s_opts.end(), Preset::machine_limits_options().begin(), Preset::machine_limits_options().end());
- s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end());
- }
- return s_opts;
-}
-
-// The following nozzle options of a printer profile will be adjusted to match the size
-// of the nozzle_diameter vector.
-const std::vector& Preset::nozzle_options()
-{
- return print_config_def.extruder_option_keys();
-}
-
-const std::vector& Preset::sla_print_options()
-{
- static std::vector s_opts;
- if (s_opts.empty()) {
- s_opts = {
- "layer_height",
- "faded_layers",
- "supports_enable",
- "support_head_front_diameter",
- "support_head_penetration",
- "support_head_width",
- "support_pillar_diameter",
- "support_small_pillar_diameter_percent",
- "support_max_bridges_on_pillar",
- "support_pillar_connection_mode",
- "support_buildplate_only",
- "support_pillar_widening_factor",
- "support_base_diameter",
- "support_base_height",
- "support_base_safety_distance",
- "support_critical_angle",
- "support_max_bridge_length",
- "support_max_pillar_link_distance",
- "support_object_elevation",
- "support_points_density_relative",
- "support_points_minimal_distance",
- "slice_closing_radius",
- "slicing_mode",
- "pad_enable",
- "pad_wall_thickness",
- "pad_wall_height",
- "pad_brim_size",
- "pad_max_merge_distance",
- // "pad_edge_radius",
- "pad_wall_slope",
- "pad_object_gap",
- "pad_around_object",
- "pad_around_object_everywhere",
- "pad_object_connector_stride",
- "pad_object_connector_width",
- "pad_object_connector_penetration",
- "hollowing_enable",
- "hollowing_min_thickness",
- "hollowing_quality",
- "hollowing_closing_distance",
- "output_filename_format",
- "default_sla_print_profile",
- "compatible_printers",
- "compatible_printers_condition",
- "inherits"
- };
- }
- return s_opts;
-}
-
-const std::vector& Preset::sla_material_options()
-{
- static std::vector s_opts;
- if (s_opts.empty()) {
- s_opts = {
- "material_type",
- "initial_layer_height",
- "bottle_cost",
- "bottle_volume",
- "bottle_weight",
- "material_density",
- "exposure_time",
- "initial_exposure_time",
- "material_correction",
- "material_notes",
- "material_vendor",
- "default_sla_material_profile",
- "compatible_prints", "compatible_prints_condition",
- "compatible_printers", "compatible_printers_condition", "inherits"
- };
- }
- return s_opts;
-}
-
-const std::vector& Preset::sla_printer_options()
-{
- static std::vector s_opts;
- if (s_opts.empty()) {
- s_opts = {
- "printer_technology",
- "bed_shape", "bed_custom_texture", "bed_custom_model", "max_print_height",
- "display_width", "display_height", "display_pixels_x", "display_pixels_y",
- "display_mirror_x", "display_mirror_y",
- "display_orientation",
- "fast_tilt_time", "slow_tilt_time", "area_fill",
- "relative_correction",
- "absolute_correction",
- "elefant_foot_compensation",
- "elefant_foot_min_width",
- "gamma_correction",
- "min_exposure_time", "max_exposure_time",
- "min_initial_exposure_time", "max_initial_exposure_time",
- //FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset.
- "print_host", "printhost_apikey", "printhost_cafile",
- "printer_notes",
- "inherits"
- };
- }
+ static std::vector s_opts = [](){
+ std::vector opts = s_Preset_printer_options;
+ append(opts, s_Preset_machine_limits_options);
+ append(opts, Preset::nozzle_options());
+ return opts;
+ }();
return s_opts;
}
@@ -1194,21 +1163,38 @@ inline t_config_option_keys deep_diff(const ConfigBase &config_this, const Confi
return diff;
}
+static constexpr const std::initializer_list optional_keys { "compatible_prints", "compatible_printers" };
+
+bool PresetCollection::is_dirty(const Preset *edited, const Preset *reference)
+{
+ if (edited != nullptr && reference != nullptr) {
+ // Only compares options existing in both configs.
+ if (! reference->config.equals(edited->config))
+ return true;
+ // The "compatible_printers" option key is handled differently from the others:
+ // It is not mandatory. If the key is missing, it means it is compatible with any printer.
+ // If the key exists and it is empty, it means it is compatible with no printer.
+ for (auto &opt_key : optional_keys)
+ if (reference->config.has(opt_key) != edited->config.has(opt_key))
+ return true;
+ }
+ return false;
+}
+
std::vector PresetCollection::dirty_options(const Preset *edited, const Preset *reference, const bool deep_compare /*= false*/)
{
std::vector changed;
if (edited != nullptr && reference != nullptr) {
+ // Only compares options existing in both configs.
changed = deep_compare ?
deep_diff(edited->config, reference->config) :
reference->config.diff(edited->config);
// The "compatible_printers" option key is handled differently from the others:
// It is not mandatory. If the key is missing, it means it is compatible with any printer.
// If the key exists and it is empty, it means it is compatible with no printer.
- std::initializer_list optional_keys { "compatible_prints", "compatible_printers" };
- for (auto &opt_key : optional_keys) {
+ for (auto &opt_key : optional_keys)
if (reference->config.has(opt_key) != edited->config.has(opt_key))
changed.emplace_back(opt_key);
- }
}
return changed;
}
@@ -1385,12 +1371,16 @@ const Preset& PrinterPresetCollection::default_preset_for(const DynamicPrintConf
return this->default_preset((opt_printer_technology == nullptr || opt_printer_technology->value == ptFFF) ? 0 : 1);
}
-const Preset* PrinterPresetCollection::find_by_model_id(const std::string &model_id) const
+const Preset* PrinterPresetCollection::find_system_preset_by_model_and_variant(const std::string &model_id, const std::string& variant) const
{
if (model_id.empty()) { return nullptr; }
const auto it = std::find_if(cbegin(), cend(), [&](const Preset &preset) {
- return preset.config.opt_string("printer_model") == model_id;
+ if (!preset.is_system || preset.config.opt_string("printer_model") != model_id)
+ return false;
+ if (variant.empty())
+ return true;
+ return preset.config.opt_string("printer_variant") == variant;
});
return it != cend() ? &*it : nullptr;
@@ -1405,26 +1395,25 @@ std::string PhysicalPrinter::separator()
return " * ";
}
+static std::vector s_PhysicalPrinter_opts {
+ "preset_name", // temporary option to compatibility with older Slicer
+ "preset_names",
+ "printer_technology",
+ "host_type",
+ "print_host",
+ "printhost_apikey",
+ "printhost_cafile",
+ "printhost_port",
+ "printhost_authorization_type",
+ // HTTP digest authentization (RFC 2617)
+ "printhost_user",
+ "printhost_password",
+ "printhost_ssl_ignore_revoke"
+};
+
const std::vector& PhysicalPrinter::printer_options()
{
- static std::vector s_opts;
- if (s_opts.empty()) {
- s_opts = {
- "preset_name", // temporary option to compatibility with older Slicer
- "preset_names",
- "printer_technology",
- "host_type",
- "print_host",
- "printhost_apikey",
- "printhost_cafile",
- "printhost_port",
- "printhost_authorization_type",
- // HTTP digest authentization (RFC 2617)
- "printhost_user",
- "printhost_password"
- };
- }
- return s_opts;
+ return s_PhysicalPrinter_opts;
}
static constexpr auto legacy_print_host_options = {
diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp
index 9d5597cac1..849dd7b809 100644
--- a/src/libslic3r/Preset.hpp
+++ b/src/libslic3r/Preset.hpp
@@ -371,7 +371,7 @@ public:
const Preset& get_edited_preset() const { return m_edited_preset; }
// Return the last saved preset.
- const Preset& get_saved_preset() const { return m_saved_preset; }
+// const Preset& get_saved_preset() const { return m_saved_preset; }
// Return vendor of the first parent profile, for which the vendor is defined, or null if such profile does not exist.
PresetWithVendorProfile get_preset_with_vendor_profile(const Preset &preset) const;
@@ -395,7 +395,7 @@ public:
void discard_current_changes() {
m_presets[m_idx_selected].reset_dirty();
m_edited_preset = m_presets[m_idx_selected];
- update_saved_preset_from_current_preset();
+// update_saved_preset_from_current_preset();
}
// Return a preset by its name. If the preset is active, a temporary copy is returned.
@@ -463,7 +463,8 @@ public:
size_t num_visible() const { return std::count_if(m_presets.begin(), m_presets.end(), [](const Preset &preset){return preset.is_visible;}); }
// Compare the content of get_selected_preset() with get_edited_preset() configs, return true if they differ.
- bool current_is_dirty() const { return ! this->current_dirty_options().empty(); }
+ bool current_is_dirty() const
+ { return is_dirty(&this->get_edited_preset(), &this->get_selected_preset()); }
// Compare the content of get_selected_preset() with get_edited_preset() configs, return the list of keys where they differ.
std::vector current_dirty_options(const bool deep_compare = false) const
{ return dirty_options(&this->get_edited_preset(), &this->get_selected_preset(), deep_compare); }
@@ -472,10 +473,11 @@ public:
{ return dirty_options(&this->get_edited_preset(), this->get_selected_preset_parent(), deep_compare); }
// Compare the content of get_saved_preset() with get_edited_preset() configs, return true if they differ.
- bool saved_is_dirty() const { return !this->saved_dirty_options().empty(); }
+ bool saved_is_dirty() const
+ { return is_dirty(&this->get_edited_preset(), &m_saved_preset); }
// Compare the content of get_saved_preset() with get_edited_preset() configs, return the list of keys where they differ.
- std::vector saved_dirty_options(const bool deep_compare = false) const
- { return dirty_options(&this->get_edited_preset(), &this->get_saved_preset(), deep_compare); }
+// std::vector saved_dirty_options() const
+// { return dirty_options(&this->get_edited_preset(), &this->get_saved_preset(), /* deep_compare */ false); }
// Copy edited preset into saved preset.
void update_saved_preset_from_current_preset() { m_saved_preset = m_edited_preset; }
@@ -552,7 +554,8 @@ private:
size_t update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType unselect_if_incompatible);
public:
- static std::vector dirty_options(const Preset *edited, const Preset *reference, const bool is_printer_type = false);
+ static bool is_dirty(const Preset *edited, const Preset *reference);
+ static std::vector dirty_options(const Preset *edited, const Preset *reference, const bool deep_compare = false);
private:
// Type of this PresetCollection: TYPE_PRINT, TYPE_FILAMENT or TYPE_PRINTER.
Preset::Type m_type;
@@ -592,7 +595,7 @@ public:
const Preset& default_preset_for(const DynamicPrintConfig &config) const override;
- const Preset* find_by_model_id(const std::string &model_id) const;
+ const Preset* find_system_preset_by_model_and_variant(const std::string &model_id, const std::string &variant) const;
private:
PrinterPresetCollection() = default;
diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp
index b2e35fa2ed..9ac8864f91 100644
--- a/src/libslic3r/PresetBundle.cpp
+++ b/src/libslic3r/PresetBundle.cpp
@@ -188,10 +188,13 @@ void PresetBundle::setup_directories()
}
}
-PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule substitution_rule, const std::string &preferred_model_id)
+PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule substitution_rule,
+ const PresetPreferences& preferred_selection/* = PresetPreferences()*/)
{
// First load the vendor specific system presets.
- std::string errors_cummulative = this->load_system_presets();
+ PresetsConfigSubstitutions substitutions;
+ std::string errors_cummulative;
+ std::tie(substitutions, errors_cummulative) = this->load_system_presets(substitution_rule);
const std::string dir_user_presets = data_dir()
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
@@ -202,7 +205,6 @@ PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, Forward
#endif
;
- PresetsConfigSubstitutions substitutions;
try {
this->prints.load_presets(dir_user_presets, "print", substitutions, substitution_rule);
} catch (const std::runtime_error &err) {
@@ -238,19 +240,28 @@ PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, Forward
if (! errors_cummulative.empty())
throw Slic3r::RuntimeError(errors_cummulative);
- this->load_selections(config, preferred_model_id);
+ // ysToDo : set prefered filament or sla_material (relates to print technology) and force o use of preffered printer model if it was added
+ this->load_selections(config, preferred_selection);
return substitutions;
}
// Load system presets into this PresetBundle.
// For each vendor, there will be a single PresetBundle loaded.
-std::string PresetBundle::load_system_presets()
+std::pair PresetBundle::load_system_presets(ForwardCompatibilitySubstitutionRule compatibility_rule)
{
+ if (compatibility_rule == ForwardCompatibilitySubstitutionRule::EnableSystemSilent)
+ // Loading system presets, don't log substitutions.
+ compatibility_rule = ForwardCompatibilitySubstitutionRule::EnableSilent;
+ else if (compatibility_rule == ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem)
+ // Loading system presets, throw on unknown option value.
+ compatibility_rule = ForwardCompatibilitySubstitutionRule::Disable;
+
// Here the vendor specific read only Config Bundles are stored.
- boost::filesystem::path dir = (boost::filesystem::path(data_dir()) / "vendor").make_preferred();
- std::string errors_cummulative;
- bool first = true;
+ boost::filesystem::path dir = (boost::filesystem::path(data_dir()) / "vendor").make_preferred();
+ PresetsConfigSubstitutions substitutions;
+ std::string errors_cummulative;
+ bool first = true;
for (auto &dir_entry : boost::filesystem::directory_iterator(dir))
if (Slic3r::is_ini_file(dir_entry)) {
std::string name = dir_entry.path().filename().string();
@@ -260,13 +271,13 @@ std::string PresetBundle::load_system_presets()
// Load the config bundle, flatten it.
if (first) {
// Reset this PresetBundle and load the first vendor config.
- this->load_configbundle(dir_entry.path().string(), PresetBundle::LoadSystem);
+ append(substitutions, this->load_configbundle(dir_entry.path().string(), PresetBundle::LoadSystem, compatibility_rule).first);
first = false;
} else {
// Load the other vendor configs, merge them with this PresetBundle.
// Report duplicate profiles.
PresetBundle other;
- other.load_configbundle(dir_entry.path().string(), PresetBundle::LoadSystem);
+ append(substitutions, other.load_configbundle(dir_entry.path().string(), PresetBundle::LoadSystem, compatibility_rule).first);
std::vector duplicates = this->merge_presets(std::move(other));
if (! duplicates.empty()) {
errors_cummulative += "Vendor configuration file " + name + " contains the following presets with names used by other vendors: ";
@@ -288,7 +299,7 @@ std::string PresetBundle::load_system_presets()
}
this->update_system_maps();
- return errors_cummulative;
+ return std::make_pair(std::move(substitutions), errors_cummulative);
}
// Merge one vendor's presets with the other vendor's presets, report duplicates.
@@ -432,7 +443,7 @@ void PresetBundle::load_installed_sla_materials(AppConfig &config)
// Load selections (current print, current filaments, current printer) from config.ini
// This is done on application start up or after updates are applied.
-void PresetBundle::load_selections(AppConfig &config, const std::string &preferred_model_id)
+void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& preferred_selection/* = PresetPreferences()*/)
{
// Update visibility of presets based on application vendor / model / variant configuration.
this->load_installed_printers(config);
@@ -455,13 +466,21 @@ void PresetBundle::load_selections(AppConfig &config, const std::string &preferr
// will be selected by the following call of this->update_compatible(PresetSelectCompatibleType::Always).
const Preset *initial_printer = printers.find_preset(initial_printer_profile_name);
- const Preset *preferred_printer = printers.find_by_model_id(preferred_model_id);
+ const Preset *preferred_printer = printers.find_system_preset_by_model_and_variant(preferred_selection.printer_model_id, preferred_selection.printer_variant);
printers.select_preset_by_name(
- (preferred_printer != nullptr && (initial_printer == nullptr || !initial_printer->is_visible)) ?
+ (preferred_printer != nullptr /*&& (initial_printer == nullptr || !initial_printer->is_visible)*/) ?
preferred_printer->name :
initial_printer_profile_name,
true);
+ // select preferred filament/sla_material profile if any exists and is visible
+ if (!preferred_selection.filament.empty())
+ if (auto it = filaments.find_preset_internal(preferred_selection.filament); it != filaments.end() && it->is_visible)
+ initial_filament_profile_name = it->name;
+ if (!preferred_selection.sla_material.empty())
+ if (auto it = sla_materials.find_preset_internal(preferred_selection.sla_material); it != sla_materials.end() && it->is_visible)
+ initial_sla_material_profile_name = it->name;
+
// Selects the profile, leaves it to -1 if the initial profile name is empty or if it was not found.
prints.select_preset_by_name_strict(initial_print_profile_name);
filaments.select_preset_by_name_strict(initial_filament_profile_name);
@@ -700,7 +719,7 @@ ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, Forw
if (is_gcode_file(path)) {
DynamicPrintConfig config;
config.apply(FullPrintConfig::defaults());
- ConfigSubstitutions config_substitutions = config.load_from_gcode_file(path, true /* check_header */, compatibility_rule);
+ ConfigSubstitutions config_substitutions = config.load_from_gcode_file(path, compatibility_rule);
Preset::normalize(config);
load_config_file_config(path, true, std::move(config));
return config_substitutions;
@@ -714,8 +733,8 @@ ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, Forw
} catch (const std::ifstream::failure &err) {
throw Slic3r::RuntimeError(std::string("The Config Bundle cannot be loaded: ") + path + "\n\tReason: " + err.what());
} catch (const boost::property_tree::file_parser_error &err) {
- throw Slic3r::RuntimeError((boost::format("Failed loading the Config Bundle \"%1%\": %2% at line %3%")
- % err.filename() % err.message() % err.line()).str());
+ throw Slic3r::RuntimeError(format("Failed loading the Config Bundle \"%1%\": %2% at line %3%",
+ err.filename(), err.message(), err.line()));
} catch (const std::runtime_error &err) {
throw Slic3r::RuntimeError(std::string("Failed loading the preset file: ") + path + "\n\tReason: " + err.what());
}
@@ -723,23 +742,27 @@ ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, Forw
// 2) Continue based on the type of the configuration file.
ConfigFileType config_file_type = guess_config_file_type(tree);
ConfigSubstitutions config_substitutions;
- switch (config_file_type) {
- case CONFIG_FILE_TYPE_UNKNOWN:
- throw Slic3r::RuntimeError(std::string("Unknown configuration file type: ") + path);
- case CONFIG_FILE_TYPE_APP_CONFIG:
- throw Slic3r::RuntimeError(std::string("Invalid configuration file: ") + path + ". This is an application config file.");
- case CONFIG_FILE_TYPE_CONFIG:
- {
- // Initialize a config from full defaults.
- DynamicPrintConfig config;
- config.apply(FullPrintConfig::defaults());
- config_substitutions = config.load(tree, compatibility_rule);
- Preset::normalize(config);
- load_config_file_config(path, true, std::move(config));
- return config_substitutions;
- }
- case CONFIG_FILE_TYPE_CONFIG_BUNDLE:
- return load_config_file_config_bundle(path, tree);
+ try {
+ switch (config_file_type) {
+ case CONFIG_FILE_TYPE_UNKNOWN:
+ throw Slic3r::RuntimeError(std::string("Unknown configuration file type: ") + path);
+ case CONFIG_FILE_TYPE_APP_CONFIG:
+ throw Slic3r::RuntimeError(std::string("Invalid configuration file: ") + path + ". This is an application config file.");
+ case CONFIG_FILE_TYPE_CONFIG:
+ {
+ // Initialize a config from full defaults.
+ DynamicPrintConfig config;
+ config.apply(FullPrintConfig::defaults());
+ config_substitutions = config.load(tree, compatibility_rule);
+ Preset::normalize(config);
+ load_config_file_config(path, true, std::move(config));
+ return config_substitutions;
+ }
+ case CONFIG_FILE_TYPE_CONFIG_BUNDLE:
+ return load_config_file_config_bundle(path, tree, compatibility_rule);
+ }
+ } catch (const ConfigurationError &e) {
+ throw Slic3r::RuntimeError(format("Invalid configuration file %1%: %2%", path, e.what()));
}
// This shall never happen. Suppres compiler warnings.
@@ -916,13 +939,14 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
}
// Load the active configuration of a config bundle from a boost property_tree. This is a private method called from load_config_file.
-ConfigSubstitutions PresetBundle::load_config_file_config_bundle(const std::string &path, const boost::property_tree::ptree &tree)
+ConfigSubstitutions PresetBundle::load_config_file_config_bundle(
+ const std::string &path, const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
// 1) Load the config bundle into a temp data.
PresetBundle tmp_bundle;
// Load the config bundle, but don't save the loaded presets to user profile directory, as only the presets marked as active in the loaded preset bundle
// will be loaded into the master PresetBundle and activated.
- auto [presets_substitutions, presets_imported] = tmp_bundle.load_configbundle(path, {});
+ auto [presets_substitutions, presets_imported] = tmp_bundle.load_configbundle(path, {}, compatibility_rule);
UNUSED(presets_imported);
std::string bundle_name = std::string(" - ") + boost::filesystem::path(path).filename().string();
@@ -1135,15 +1159,11 @@ static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree, co
// Load a config bundle file, into presets and store the loaded presets into separate files
// of the local configuration directory.
-std::pair PresetBundle::load_configbundle(const std::string &path, LoadConfigBundleAttributes flags)
+std::pair PresetBundle::load_configbundle(
+ const std::string &path, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
// Enable substitutions for user config bundle, throw an exception when loading a system profile.
- ConfigSubstitutionContext substitution_context {
- flags.has(LoadConfigBundleAttribute::LoadSystem) ?
- ForwardCompatibilitySubstitutionRule::Disable :
- ForwardCompatibilitySubstitutionRule::Enable
- };
-
+ ConfigSubstitutionContext substitution_context { compatibility_rule };
PresetsConfigSubstitutions substitutions;
if (flags.has(LoadConfigBundleAttribute::ResetUserProfile) || flags.has(LoadConfigBundleAttribute::LoadSystem))
@@ -1238,7 +1258,7 @@ std::pair PresetBundle::load_configbundle(co
active_sla_material = kvp.second.data();
} else if (kvp.first == "printer") {
active_printer = kvp.second.data();
- }else if (kvp.first == "physical_printer") {
+ } else if (kvp.first == "physical_printer") {
active_physical_printer = kvp.second.data();
}
}
@@ -1275,32 +1295,36 @@ std::pair PresetBundle::load_configbundle(co
DynamicPrintConfig config;
std::string alias_name;
std::vector renamed_from;
- auto parse_config_section = [§ion, &alias_name, &renamed_from, &substitution_context, &path](DynamicPrintConfig &config) {
- substitution_context.substitutions.clear();
- for (auto &kvp : section.second) {
- if (kvp.first == "alias")
- alias_name = kvp.second.data();
- else if (kvp.first == "renamed_from") {
- if (! unescape_strings_cstyle(kvp.second.data(), renamed_from)) {
- BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The preset \"" <<
- section.first << "\" contains invalid \"renamed_from\" key, which is being ignored.";
- }
- }
- // Throws on parsing error. For system presets, no substituion is being done, but an exception is thrown.
- config.set_deserialize(kvp.first, kvp.second.data(), substitution_context);
+ try {
+ auto parse_config_section = [§ion, &alias_name, &renamed_from, &substitution_context, &path](DynamicPrintConfig &config) {
+ substitution_context.substitutions.clear();
+ for (auto &kvp : section.second) {
+ if (kvp.first == "alias")
+ alias_name = kvp.second.data();
+ else if (kvp.first == "renamed_from") {
+ if (! unescape_strings_cstyle(kvp.second.data(), renamed_from)) {
+ BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The preset \"" <<
+ section.first << "\" contains invalid \"renamed_from\" key, which is being ignored.";
+ }
+ }
+ // Throws on parsing error. For system presets, no substituion is being done, but an exception is thrown.
+ config.set_deserialize(kvp.first, kvp.second.data(), substitution_context);
+ }
+ };
+ if (presets == &this->printers) {
+ // Select the default config based on the printer_technology field extracted from kvp.
+ DynamicPrintConfig config_src;
+ parse_config_section(config_src);
+ default_config = &presets->default_preset_for(config_src).config;
+ config = *default_config;
+ config.apply(config_src);
+ } else {
+ default_config = &presets->default_preset().config;
+ config = *default_config;
+ parse_config_section(config);
}
- };
- if (presets == &this->printers) {
- // Select the default config based on the printer_technology field extracted from kvp.
- DynamicPrintConfig config_src;
- parse_config_section(config_src);
- default_config = &presets->default_preset_for(config_src).config;
- config = *default_config;
- config.apply(config_src);
- } else {
- default_config = &presets->default_preset().config;
- config = *default_config;
- parse_config_section(config);
+ } catch (const ConfigurationError &e) {
+ throw ConfigurationError(format("Invalid configuration bundle \"%1%\", section [%2%]: ", path, section.first) + e.what());
}
Preset::normalize(config);
// Report configuration fields, which are misplaced into a wrong group.
@@ -1408,8 +1432,12 @@ std::pair PresetBundle::load_configbundle(co
DynamicPrintConfig config = default_config;
substitution_context.substitutions.clear();
- for (auto& kvp : section.second)
- config.set_deserialize(kvp.first, kvp.second.data(), substitution_context);
+ try {
+ for (auto& kvp : section.second)
+ config.set_deserialize(kvp.first, kvp.second.data(), substitution_context);
+ } catch (const ConfigurationError &e) {
+ throw ConfigurationError(format("Invalid configuration bundle \"%1%\", section [%2%]: ", path, section.first) + e.what());
+ }
// Report configuration fields, which are misplaced into a wrong group.
std::string incorrect_keys = Preset::remove_invalid_keys(config, default_config);
@@ -1449,7 +1477,7 @@ std::pair PresetBundle::load_configbundle(co
if (! active_print.empty())
prints.select_preset_by_name(active_print, true);
if (! active_sla_print.empty())
- sla_materials.select_preset_by_name(active_sla_print, true);
+ sla_prints.select_preset_by_name(active_sla_print, true);
if (! active_sla_material.empty())
sla_materials.select_preset_by_name(active_sla_material, true);
if (! active_printer.empty())
diff --git a/src/libslic3r/PresetBundle.hpp b/src/libslic3r/PresetBundle.hpp
index 9f75ba6c24..c22599e388 100644
--- a/src/libslic3r/PresetBundle.hpp
+++ b/src/libslic3r/PresetBundle.hpp
@@ -25,9 +25,18 @@ public:
void setup_directories();
+ struct PresetPreferences {
+ std::string printer_model_id;// name of a preferred printer model
+ std::string printer_variant; // name of a preferred printer variant
+ std::string filament; // name of a preferred filament preset
+ std::string sla_material; // name of a preferred sla_material preset
+ };
+
// Load ini files of all types (print, filament, printer) from Slic3r::data_dir() / presets.
// Load selections (current print, current filaments, current printer) from config.ini
- PresetsConfigSubstitutions load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule rule, const std::string &preferred_model_id = std::string());
+ // select preferred presets, if any exist
+ PresetsConfigSubstitutions load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule rule,
+ const PresetPreferences& preferred_selection = PresetPreferences());
// Export selections (current print, current filaments, current printer) into config.ini
void export_selections(AppConfig &config);
@@ -102,7 +111,8 @@ public:
using LoadConfigBundleAttributes = enum_bitmask;
// Load the config bundle based on the flags.
// Don't do any config substitutions when loading a system profile, perform and report substitutions otherwise.
- std::pair load_configbundle(const std::string &path, LoadConfigBundleAttributes flags);
+ std::pair load_configbundle(
+ const std::string &path, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule);
// Export a config bundle file containing all the presets and the names of the active presets.
void export_configbundle(const std::string &path, bool export_system_settings = false, bool export_physical_printers = false);
@@ -139,7 +149,7 @@ public:
static const char *PRUSA_BUNDLE;
private:
- std::string load_system_presets();
+ std::pair load_system_presets(ForwardCompatibilitySubstitutionRule compatibility_rule);
// Merge one vendor's presets with the other vendor's presets, report duplicates.
std::vector merge_presets(PresetBundle &&other);
// Update renamed_from and alias maps of system profiles.
@@ -152,13 +162,14 @@ private:
// Load selections (current print, current filaments, current printer) from config.ini
// This is done just once on application start up.
- void load_selections(AppConfig &config, const std::string &preferred_model_id = "");
+ void load_selections(AppConfig &config, const PresetPreferences& preferred_selection = PresetPreferences());
// Load print, filament & printer presets from a config. If it is an external config, then the name is extracted from the external path.
// and the external config is just referenced, not stored into user profile directory.
// If it is not an external config, then the config will be stored into the user profile directory.
void load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config);
- ConfigSubstitutions load_config_file_config_bundle(const std::string &path, const boost::property_tree::ptree &tree);
+ ConfigSubstitutions load_config_file_config_bundle(
+ const std::string &path, const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule);
DynamicPrintConfig full_fff_config() const;
DynamicPrintConfig full_sla_config() const;
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index b3a1bc9939..48737f8302 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -159,7 +159,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|| opt_key == "wipe_tower_rotation_angle") {
steps.emplace_back(psSkirtBrim);
} else if (
- opt_key == "nozzle_diameter"
+ opt_key == "first_layer_height"
+ || opt_key == "nozzle_diameter"
|| opt_key == "resolution"
// Spiral Vase forces different kind of slicing than the normal model:
// In Spiral Vase mode, holes are closed and only the largest area contour is kept at each layer.
diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp
index 1854800cc7..0056aee333 100644
--- a/src/libslic3r/Print.hpp
+++ b/src/libslic3r/Print.hpp
@@ -253,6 +253,9 @@ public:
ConstLayerPtrsAdaptor layers() const { return ConstLayerPtrsAdaptor(&m_layers); }
ConstSupportLayerPtrsAdaptor support_layers() const { return ConstSupportLayerPtrsAdaptor(&m_support_layers); }
const Transform3d& trafo() const { return m_trafo; }
+ // Trafo with the center_offset() applied after the transformation, to center the object in XY before slicing.
+ Transform3d trafo_centered() const
+ { Transform3d t = this->trafo(); t.pretranslate(Vec3d(- unscale(m_center_offset.x()), - unscale(m_center_offset.y()), 0)); return t; }
const PrintInstances& instances() const { return m_instances; }
// Whoever will get a non-const pointer to PrintObject will be able to modify its layers.
@@ -268,7 +271,11 @@ public:
// Centering offset of the sliced mesh from the scaled and rotated mesh of the model.
const Point& center_offset() const { return m_center_offset; }
- bool has_brim() const { return this->config().brim_type != btNoBrim && this->config().brim_width.value > 0.; }
+ bool has_brim() const {
+ return this->config().brim_type != btNoBrim
+ && this->config().brim_width.value > 0.
+ && ! this->has_raft();
+ }
// This is the *total* layer count (including support layers)
// this value is not supposed to be compared with Layer::id
@@ -318,7 +325,7 @@ public:
bool has_raft() const { return m_config.raft_layers > 0; }
bool has_support_material() const { return this->has_support() || this->has_raft(); }
// Checks if the model object is painted using the multi-material painting gizmo.
- bool is_mm_painted() const { return this->model_object()->is_mm_painted(); };
+ bool is_mm_painted() const { return this->model_object()->is_mm_painted(); }
// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
std::vector object_extruders() const;
diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp
index 0e252ac6f4..10960c5356 100644
--- a/src/libslic3r/PrintApply.cpp
+++ b/src/libslic3r/PrintApply.cpp
@@ -216,22 +216,25 @@ static t_config_option_keys print_config_diffs(
const ConfigOption *opt_new_filament = std::binary_search(extruder_retract_keys.begin(), extruder_retract_keys.end(), opt_key) ? new_full_config.option(filament_prefix + opt_key) : nullptr;
if (opt_new_filament != nullptr && ! opt_new_filament->is_nil()) {
// An extruder retract override is available at some of the filament presets.
- if (*opt_old != *opt_new || opt_new->overriden_by(opt_new_filament)) {
+ bool overriden = opt_new->overriden_by(opt_new_filament);
+ if (overriden || *opt_old != *opt_new) {
auto opt_copy = opt_new->clone();
opt_copy->apply_override(opt_new_filament);
- if (*opt_old == *opt_copy)
- delete opt_copy;
- else {
- filament_overrides.set_key_value(opt_key, opt_copy);
+ bool changed = *opt_old != *opt_copy;
+ if (changed)
print_diff.emplace_back(opt_key);
- }
+ if (changed || overriden) {
+ // filament_overrides will be applied to the placeholder parser, which layers these parameters over full_print_config.
+ filament_overrides.set_key_value(opt_key, opt_copy);
+ } else
+ delete opt_copy;
}
} else if (*opt_new != *opt_old)
print_diff.emplace_back(opt_key);
}
return print_diff;
- }
+}
// Prepare for storing of the full print config into new_full_config to be exported into the G-code and to be used by the PlaceholderParser.
static t_config_option_keys full_print_config_diffs(const DynamicPrintConfig ¤t_full_config, const DynamicPrintConfig &new_full_config)
@@ -812,7 +815,7 @@ static PrintObjectRegions* generate_print_object_regions(
layer_ranges_regions.push_back({ range.layer_height_range, range.config });
}
- const bool is_mm_painted = std::any_of(model_volumes.cbegin(), model_volumes.cend(), [](const ModelVolume *mv) { return mv->is_mm_painted(); });
+ const bool is_mm_painted = num_extruders > 1 && std::any_of(model_volumes.cbegin(), model_volumes.cend(), [](const ModelVolume *mv) { return mv->is_mm_painted(); });
update_volume_bboxes(layer_ranges_regions, out->cached_volume_ids, model_volumes, out->trafo_bboxes, is_mm_painted ? 0.f : std::max(0.f, xy_size_compensation));
std::vector region_set;
@@ -928,6 +931,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
bool num_extruders_changed = false;
if (! full_config_diff.empty()) {
update_apply_status(this->invalidate_step(psGCodeExport));
+ m_placeholder_parser.clear_config();
// Set the profile aliases for the PrintBase::output_filename()
m_placeholder_parser.set("print_preset", new_full_config.option("print_settings_id")->clone());
m_placeholder_parser.set("filament_preset", new_full_config.option("filament_settings_id")->clone());
@@ -939,6 +943,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
// It is also safe to change m_config now after this->invalidate_state_by_config_options() call.
m_config.apply_only(new_full_config, print_diff, true);
//FIXME use move semantics once ConfigBase supports it.
+ // Some filament_overrides may contain values different from new_full_config, but equal to m_config.
+ // As long as these config options don't reallocate memory when copying, we are safe overriding a value, which is in use by a worker thread.
m_config.apply(filament_overrides);
// Handle changes to object config defaults
m_default_object_config.apply_only(new_full_config, object_diff, true);
@@ -946,8 +952,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
m_default_region_config.apply_only(new_full_config, region_diff, true);
m_full_print_config = std::move(new_full_config);
if (num_extruders != m_config.nozzle_diameter.size()) {
- num_extruders = m_config.nozzle_diameter.size();
- num_extruders_changed = true;
+ num_extruders = m_config.nozzle_diameter.size();
+ num_extruders_changed = true;
}
}
@@ -1065,7 +1071,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
// Check whether a model part volume was added or removed, their transformations or order changed.
// Only volume IDs, volume types, transformation matrices and their order are checked, configuration and other parameters are NOT checked.
bool solid_or_modifier_differ = model_volume_list_changed(model_object, model_object_new, solid_or_modifier_types) ||
- model_mmu_segmentation_data_changed(model_object, model_object_new);
+ model_mmu_segmentation_data_changed(model_object, model_object_new) ||
+ (model_object_new.is_mm_painted() && num_extruders_changed);
bool supports_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_BLOCKER) ||
model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER);
bool layer_height_ranges_differ = ! layer_height_ranges_equal(model_object.layer_config_ranges, model_object_new.layer_config_ranges, model_object_new.layer_height_profile.empty());
@@ -1267,7 +1274,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
print_object_regions->ref_cnt_inc();
}
std::vector painting_extruders;
- if (const auto &volumes = print_object.model_object()->volumes;
+ if (const auto &volumes = print_object.model_object()->volumes;
+ num_extruders > 1 &&
std::find_if(volumes.begin(), volumes.end(), [](const ModelVolume *v) { return ! v->mmu_segmentation_facets.empty(); }) != volumes.end()) {
//FIXME be more specific! Don't enumerate extruders that are not used for painting!
painting_extruders.assign(num_extruders, 0);
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index 16c16f038e..f010bad399 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -232,9 +232,19 @@ void PrintConfigDef::init_common_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString(""));
+ def = this->add("elefant_foot_compensation", coFloat);
+ def->label = L("Elephant foot compensation");
+ def->category = L("Advanced");
+ def->tooltip = L("The first layer will be shrunk in the XY plane by the configured value "
+ "to compensate for the 1st layer squish aka an Elephant Foot effect.");
+ def->sidetext = L("mm");
+ def->min = 0;
+ def->mode = comAdvanced;
+ def->set_default_value(new ConfigOptionFloat(0.));
+
def = this->add("thumbnails", coPoints);
def->label = L("G-code thumbnails");
- def->tooltip = L("Picture sizes to be stored into a .gcode and .sl1 files, in the following format: \"XxY, XxY, ...\"");
+ def->tooltip = L("Picture sizes to be stored into a .gcode and .sl1 / .sl1s files, in the following format: \"XxY, XxY, ...\"");
def->mode = comExpert;
def->gui_type = ConfigOptionDef::GUIType::one_string;
def->set_default_value(new ConfigOptionPoints());
@@ -264,6 +274,7 @@ void PrintConfigDef::init_common_params()
"Print host behind HAProxy with basic auth enabled can be accessed by putting the user name and password into the URL "
"in the following format: https://username:password@your-octopi-address/");
def->mode = comAdvanced;
+ def->cli = ConfigOptionDef::nocli;
def->set_default_value(new ConfigOptionString(""));
def = this->add("printhost_apikey", coString);
@@ -271,6 +282,7 @@ void PrintConfigDef::init_common_params()
def->tooltip = L("Slic3r can upload G-code files to a printer host. This field should contain "
"the API Key or the password required for authentication.");
def->mode = comAdvanced;
+ def->cli = ConfigOptionDef::nocli;
def->set_default_value(new ConfigOptionString(""));
def = this->add("printhost_port", coString);
@@ -278,6 +290,7 @@ void PrintConfigDef::init_common_params()
def->tooltip = L("Name of the printer");
def->gui_type = ConfigOptionDef::GUIType::select_open;
def->mode = comAdvanced;
+ def->cli = ConfigOptionDef::nocli;
def->set_default_value(new ConfigOptionString(""));
def = this->add("printhost_cafile", coString);
@@ -285,31 +298,33 @@ void PrintConfigDef::init_common_params()
def->tooltip = L("Custom CA certificate file can be specified for HTTPS OctoPrint connections, in crt/pem format. "
"If left blank, the default OS CA certificate repository is used.");
def->mode = comAdvanced;
+ def->cli = ConfigOptionDef::nocli;
def->set_default_value(new ConfigOptionString(""));
- def = this->add("elefant_foot_compensation", coFloat);
- def->label = L("Elephant foot compensation");
- def->category = L("Advanced");
- def->tooltip = L("The first layer will be shrunk in the XY plane by the configured value "
- "to compensate for the 1st layer squish aka an Elephant Foot effect.");
- def->sidetext = L("mm");
- def->min = 0;
- def->mode = comAdvanced;
- def->set_default_value(new ConfigOptionFloat(0.2));
-
// Options used by physical printers
def = this->add("printhost_user", coString);
def->label = L("User");
// def->tooltip = L("");
def->mode = comAdvanced;
+ def->cli = ConfigOptionDef::nocli;
def->set_default_value(new ConfigOptionString(""));
def = this->add("printhost_password", coString);
def->label = L("Password");
// def->tooltip = L("");
def->mode = comAdvanced;
+ def->cli = ConfigOptionDef::nocli;
def->set_default_value(new ConfigOptionString(""));
+
+ // Only available on Windows.
+ def = this->add("printhost_ssl_ignore_revoke", coBool);
+ def->label = L("Ignore HTTPS certificate revocation checks");
+ def->tooltip = L("Ignore HTTPS certificate revocation checks in case of missing or offline distribution points. "
+ "One may want to enable this option for self signed certificates if connection fails.");
+ def->mode = comAdvanced;
+ def->cli = ConfigOptionDef::nocli;
+ def->set_default_value(new ConfigOptionBool(false));
def = this->add("preset_names", coStrings);
def->label = L("Printer preset names");
@@ -317,12 +332,6 @@ void PrintConfigDef::init_common_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionStrings());
- // temporary workaround for compatibility with older Slicer
- {
- def = this->add("preset_name", coString);
- def->set_default_value(new ConfigOptionString());
- }
-
def = this->add("printhost_authorization_type", coEnum);
def->label = L("Authorization Type");
// def->tooltip = L("");
@@ -332,7 +341,14 @@ void PrintConfigDef::init_common_params()
def->enum_labels.push_back(L("API key"));
def->enum_labels.push_back(L("HTTP digest"));
def->mode = comAdvanced;
+ def->cli = ConfigOptionDef::nocli;
def->set_default_value(new ConfigOptionEnum(atKeyPassword));
+
+ // temporary workaround for compatibility with older Slicer
+ {
+ def = this->add("preset_name", coString);
+ def->set_default_value(new ConfigOptionString());
+ }
}
void PrintConfigDef::init_fff_params()
@@ -465,7 +481,8 @@ void PrintConfigDef::init_fff_params()
def = this->add("brim_width", coFloat);
def->label = L("Brim width");
def->category = L("Skirt and brim");
- def->tooltip = L("Horizontal width of the brim that will be printed around each object on the first layer.");
+ def->tooltip = L("Horizontal width of the brim that will be printed around each object on the first layer."
+ "When raft is used, no brim is generated (use raft_first_layer_expansion).");
def->sidetext = L("mm");
def->min = 0;
def->max = 200;
@@ -491,10 +508,11 @@ void PrintConfigDef::init_fff_params()
def = this->add("brim_offset", coFloat);
def->label = L("Brim offset");
def->category = L("Skirt and brim");
- def->tooltip = L("The offset of the brim from the printed object.");
+ def->tooltip = L("The offset of the brim from the printed object. The offset is applied after the elephant foot compensation.");
def->sidetext = L("mm");
- def->mode = comSimple;
- def->set_default_value(new ConfigOptionFloat(0));
+ def->min = 0;
+ def->mode = comAdvanced;
+ def->set_default_value(new ConfigOptionFloat(0.f));
def = this->add("clip_multipart_objects", coBool);
def->label = L("Clip multi-part objects");
@@ -1808,6 +1826,7 @@ void PrintConfigDef::init_fff_params()
def->enum_labels.push_back("AstroBox");
def->enum_labels.push_back("Repetier");
def->mode = comAdvanced;
+ def->cli = ConfigOptionDef::nocli;
def->set_default_value(new ConfigOptionEnum(htOctoPrint));
def = this->add("only_retract_when_crossing_perimeters", coBool);
@@ -4154,9 +4173,10 @@ CLITransformConfigDef::CLITransformConfigDef()
def->label = L("Don't arrange");
def->tooltip = L("Do not rearrange the given models before merging and keep their original XY coordinates.");
- def = this->add("dont_ensure_on_bed", coBool);
- def->label = L("Don't ensure on bed");
- def->tooltip = L("Do not lift the object above the bed when it is partially below.");
+ def = this->add("ensure_on_bed", coBool);
+ def->label = L("Ensure on bed");
+ def->tooltip = L("Lift the object above the bed when it is partially below. Enabled by default, use --no-ensure-on-bed to disable.");
+ def->set_default_value(new ConfigOptionBool(true));
def = this->add("duplicate", coInt);
def->label = L("Duplicate");
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index 8ebe1eb101..ee09e0f5b7 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -428,10 +428,8 @@ std::pair PrintObject::prepare
indexed_triangle_set mesh = this->model_object()->raw_indexed_triangle_set();
// Rotate mesh and build octree on it with axis-aligned (standart base) cubes.
- Transform3d m = m_trafo;
- m.pretranslate(Vec3d(- unscale(m_center_offset.x()), - unscale(m_center_offset.y()), 0));
auto to_octree = transform_to_octree().toRotationMatrix();
- its_transform(mesh, to_octree * m, true);
+ its_transform(mesh, to_octree * this->trafo_centered(), true);
// Triangulate internal bridging surfaces.
std::vector> overhangs(this->layers().size());
@@ -537,7 +535,6 @@ bool PrintObject::invalidate_state_by_config_options(
steps.emplace_back(posPerimeters);
} else if (
opt_key == "layer_height"
- || opt_key == "first_layer_height"
|| opt_key == "mmu_segmented_region_max_width"
|| opt_key == "raft_layers"
|| opt_key == "raft_contact_distance"
@@ -2298,7 +2295,7 @@ void PrintObject::project_and_append_custom_facets(
: mv->supported_facets.get_facets_strict(*mv, type);
if (! custom_facets.indices.empty())
project_triangles_to_slabs(this->layers(), custom_facets,
- (Eigen::Translation3d(to_3d(unscaled(this->center_offset()), 0.)) * this->trafo() * mv->get_matrix()).cast(),
+ (this->trafo_centered() * mv->get_matrix()).cast(),
seam, out);
}
}
diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp
index 818519be49..1d61be85bc 100644
--- a/src/libslic3r/PrintObjectSlice.cpp
+++ b/src/libslic3r/PrintObjectSlice.cpp
@@ -167,8 +167,9 @@ static std::vector slice_volumes_inner(
params_base.mode_below = params_base.mode;
- const bool is_mm_painted = std::any_of(model_volumes.cbegin(), model_volumes.cend(), [](const ModelVolume *mv) { return mv->is_mm_painted(); });
- const auto extra_offset = is_mm_painted ? 0.f : std::max(0.f, float(print_object_config.xy_size_compensation.value));
+ const size_t num_extruders = print_config.nozzle_diameter.size();
+ const bool is_mm_painted = num_extruders > 1 && std::any_of(model_volumes.cbegin(), model_volumes.cend(), [](const ModelVolume *mv) { return mv->is_mm_painted(); });
+ const auto extra_offset = is_mm_painted ? 0.f : std::max(0.f, float(print_object_config.xy_size_compensation.value));
for (const ModelVolume *model_volume : model_volumes)
if (model_volume_needs_slicing(*model_volume)) {
@@ -695,11 +696,9 @@ void PrintObject::slice_volumes()
}
std::vector slice_zs = zs_from_layers(m_layers);
- Transform3d trafo = this->trafo();
- trafo.pretranslate(Vec3d(- unscale(m_center_offset.x()), - unscale(m_center_offset.y()), 0));
std::vector> region_slices = slices_to_regions(this->model_object()->volumes, *m_shared_regions, slice_zs,
slice_volumes_inner(
- print->config(), this->config(), trafo,
+ print->config(), this->config(), this->trafo_centered(),
this->model_object()->volumes, m_shared_regions->layer_ranges, slice_zs, throw_on_cancel_callback),
m_config.clip_multipart_objects,
throw_on_cancel_callback);
@@ -725,6 +724,7 @@ void PrintObject::slice_volumes()
// Is any ModelVolume MMU painted?
if (const auto& volumes = this->model_object()->volumes;
+ m_print->config().nozzle_diameter.size() > 1 &&
std::find_if(volumes.begin(), volumes.end(), [](const ModelVolume* v) { return !v->mmu_segmentation_facets.empty(); }) != volumes.end()) {
// If XY Size compensation is also enabled, notify the user that XY Size compensation
@@ -745,8 +745,9 @@ void PrintObject::slice_volumes()
BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - make_slices in parallel - begin";
{
// Compensation value, scaled. Only applying the negative scaling here, as the positive scaling has already been applied during slicing.
- const auto xy_compensation_scaled = this->is_mm_painted() ? scaled(0.f) : scaled(std::min(m_config.xy_size_compensation.value, 0.));
- const float elephant_foot_compensation_scaled = (m_config.raft_layers == 0) ?
+ const size_t num_extruders = print->config().nozzle_diameter.size();
+ const auto xy_compensation_scaled = (num_extruders > 1 && this->is_mm_painted()) ? scaled(0.f) : scaled(std::min(m_config.xy_size_compensation.value, 0.));
+ const float elephant_foot_compensation_scaled = (m_config.raft_layers == 0) ?
// Only enable Elephant foot compensation if printing directly on the print bed.
float(scale_(m_config.elefant_foot_compensation.value)) :
0.f;
@@ -832,8 +833,7 @@ std::vector PrintObject::slice_support_volumes(const ModelVolumeType m
const Print *print = this->print();
auto throw_on_cancel_callback = std::function([print](){ print->throw_if_canceled(); });
MeshSlicingParamsEx params;
- params.trafo = this->trafo();
- params.trafo.pretranslate(Vec3d(-unscale(m_center_offset.x()), -unscale(m_center_offset.y()), 0));
+ params.trafo = this->trafo_centered();
for (; it_volume != it_volume_end; ++ it_volume)
if ((*it_volume)->type() == model_volume_type) {
std::vector slices2 = slice_volume(*(*it_volume), zs, params, throw_on_cancel_callback);
diff --git a/src/libslic3r/QuadricEdgeCollapse.cpp b/src/libslic3r/QuadricEdgeCollapse.cpp
new file mode 100644
index 0000000000..6efc5f4a9d
--- /dev/null
+++ b/src/libslic3r/QuadricEdgeCollapse.cpp
@@ -0,0 +1,845 @@
+#include "QuadricEdgeCollapse.hpp"
+#include
+#include
+#include "MutablePriorityQueue.hpp"
+#include "SimplifyMeshImpl.hpp"
+#include
+
+using namespace Slic3r;
+
+// only private namespace not neccessary be in .hpp
+namespace QuadricEdgeCollapse {
+ using Vertices = std::vector;
+ using Triangle = stl_triangle_vertex_indices;
+ using Indices = std::vector;
+ using SymMat = SimplifyMesh::implementation::SymetricMatrix;
+ using ThrowOnCancel = std::function