Merge branch 'master' into fs_CenterSupportForIsland

This commit is contained in:
Filip Sykala 2021-02-24 13:23:02 +01:00
commit 068ab2cf1b
271 changed files with 33271 additions and 14501 deletions

View File

@ -35,15 +35,27 @@ option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
set(SLIC3R_GTK "2" CACHE STRING "GTK version to use with wxWidgets on Linux")
set(IS_CROSS_COMPILE FALSE)
if (APPLE)
set(CMAKE_FIND_FRAMEWORK LAST)
set(CMAKE_FIND_APPBUNDLE LAST)
list(FIND CMAKE_OSX_ARCHITECTURES ${CMAKE_SYSTEM_PROCESSOR} _arch_idx)
if (CMAKE_OSX_ARCHITECTURES AND _arch_idx LESS 0)
set(IS_CROSS_COMPILE TRUE)
endif ()
endif ()
# Proposal for C++ unit tests and sandboxes
option(SLIC3R_BUILD_SANDBOXES "Build development sandboxes" OFF)
option(SLIC3R_BUILD_TESTS "Build unit tests" ON)
if (IS_CROSS_COMPILE)
message("Detected cross compilation setup. Tests and encoding checks will be forcedly disabled!")
set(SLIC3R_PERL_XS OFF CACHE BOOL "" FORCE)
set(SLIC3R_BUILD_TESTS OFF CACHE BOOL "" FORCE)
endif ()
# Print out the SLIC3R_* cache options
get_cmake_property(_cache_vars CACHE_VARIABLES)
list (SORT _cache_vars)
@ -80,12 +92,21 @@ if (MSVC)
# Disable STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17.
#FIXME Remove this line after eigen library adapts to the new C++17 adaptor rules.
add_compile_options(-D_SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING)
# Disable warnings on conversion from unsigned to signed (possible loss of data)
# C4244: 'conversion' conversion from 'type1' to 'type2', possible loss of data. An integer type is converted to a smaller integer type.
# C4267: The compiler detected a conversion from size_t to a smaller type.
add_compile_options(/wd4244 /wd4267)
endif ()
if (MINGW)
add_compile_options(-Wa,-mbig-obj)
endif ()
if (NOT MSVC)
# ARMs (Raspberry PI) use an unsigned char by default. Let's make it consistent for PrusaSlicer on all platforms.
add_compile_options(-fsigned-char)
endif ()
# Display and check CMAKE_PREFIX_PATH
message(STATUS "SLIC3R_STATIC: ${SLIC3R_STATIC}")
if (NOT "${CMAKE_PREFIX_PATH}" STREQUAL "")
@ -190,6 +211,13 @@ if (NOT MSVC AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMP
add_compile_options(-Wno-ignored-attributes) # Tamas: Eigen include dirs are marked as SYSTEM
endif()
# Clang reports legacy OpenGL calls as deprecated. Turn off the warning for now
# to reduce the clutter, we know about this one. It should be reenabled after
# we finally get rid of the deprecated code.
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
add_compile_options(-Wno-deprecated-declarations)
endif()
#GCC generates loads of -Wunknown-pragmas when compiling igl. The fix is not easy due to a bug in gcc, see
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66943 or
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431
@ -223,13 +251,16 @@ include_directories(${LIBDIR})
# For generated header files
include_directories(${LIBDIR_BIN}/platform)
# For libslic3r.h
include_directories(${LIBDIR}/clipper ${LIBDIR}/polypartition)
include_directories(${LIBDIR}/clipper)
if(WIN32)
add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS)
if(MSVC)
# BOOST_ALL_NO_LIB: Avoid the automatic linking of Boost libraries on Windows. Rather rely on explicit linking.
add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_USE_WINAPI_VERSION=0x601 -DBOOST_SYSTEM_USE_UTF8 )
# Force the source code encoding to UTF-8. See PrusaSlicer GH pull request #5583
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
endif(MSVC)
endif(WIN32)
@ -266,10 +297,9 @@ if(SLIC3R_STATIC)
endif()
#set(Boost_DEBUG ON)
# set(Boost_COMPILER "-mgw81")
if(NOT WIN32)
# boost::process was introduced first in version 1.64.0
set(MINIMUM_BOOST_VERSION "1.64.0")
endif()
# boost::process was introduced first in version 1.64.0,
# boost::beast::detail::base64 was introduced first in version 1.66.0
set(MINIMUM_BOOST_VERSION "1.66.0")
set(_boost_components "system;filesystem;thread;log;locale;regex;chrono;atomic;date_time")
find_package(Boost ${MINIMUM_BOOST_VERSION} REQUIRED COMPONENTS ${_boost_components})

View File

@ -302,7 +302,7 @@ if(NOT TBB_FOUND)
IMPORTED_LOCATION ${TBB_LIBRARIES})
if(TBB_LIBRARIES_RELEASE AND TBB_LIBRARIES_DEBUG)
set_target_properties(TBB::tbb PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "${TBB_DEFINITIONS};$<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:${TBB_DEFINITIONS_DEBUG}>;$<$<CONFIG:Release>:${TBB_DEFINITIONS_RELEASE}>"
INTERFACE_COMPILE_DEFINITIONS "${TBB_DEFINITIONS};$<$<OR:$<CONFIG:Release>,$<CONFIG:RelWithDebInfo>>:${TBB_DEFINITIONS_RELEASE}>;$<$<CONFIG:Debug>:${TBB_DEFINITIONS_DEBUG}>"
IMPORTED_LOCATION_DEBUG ${TBB_LIBRARIES_DEBUG}
IMPORTED_LOCATION_RELWITHDEBINFO ${TBB_LIBRARIES_RELEASE}
IMPORTED_LOCATION_RELEASE ${TBB_LIBRARIES_RELEASE}

View File

@ -157,7 +157,9 @@ function(OPENVDB_ABI_VERSION_FROM_PRINT OPENVDB_PRINT)
endif()
set(_OpenVDB_ABI)
string(REGEX REPLACE ".*abi([0-9]*).*" "\\1" _OpenVDB_ABI ${_VDB_PRINT_VERSION_STRING})
if (_VDB_PRINT_VERSION_STRING)
string(REGEX REPLACE ".*abi([0-9]*).*" "\\1" _OpenVDB_ABI ${_VDB_PRINT_VERSION_STRING})
endif ()
if(${_OpenVDB_ABI} STREQUAL ${_VDB_PRINT_VERSION_STRING})
set(_OpenVDB_ABI "")
endif()

View File

@ -26,6 +26,7 @@ ExternalProject_Add(dep_boost
variant=release
threading=multi
boost.locale.icu=off
--disable-icu
cflags=-fPIC
cxxflags=-fPIC
install

View File

@ -33,6 +33,7 @@ ExternalProject_Add(dep_boost
variant=release
threading=multi
boost.locale.icu=off
--disable-icu
"cflags=-fPIC -mmacosx-version-min=${DEP_OSX_TARGET}"
"cxxflags=-fPIC -mmacosx-version-min=${DEP_OSX_TARGET}"
"mflags=-fPIC -mmacosx-version-min=${DEP_OSX_TARGET}"

View File

@ -76,6 +76,7 @@ ExternalProject_Add(dep_boost
variant=release
threading=multi
boost.locale.icu=off
--disable-icu
"${DEP_BOOST_DEBUG}" release install
INSTALL_COMMAND "" # b2 does that already
)

View File

@ -22,8 +22,6 @@
* qhull: libqhull-dev does not contain libqhullcpp => link errors. Until it is fixed, we will use the builtin version. https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=925540
* semver: One module C library, author expects to use clib for installation. No packages.
* Shiny: no packages
* poly2tree: Obsolete, candidate for removal
* polypartition: Obsolete, candidate for removal
## Header only
* igl

View File

@ -7,7 +7,7 @@ as the versions listed - generally versions available on conservative Linux dist
Perl is not required any more.
In a typical situation, one would open a command line, go to the PrusaSlicer sources, create a directory called `build` or similar,
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:
cmake ..
@ -37,7 +37,7 @@ To do this, go to the `deps` directory, create a `build` subdirectory (or the li
where the target destdir is a directory of your choosing where the dependencies will be installed.
You can also omit the `DESTDIR` option to use the default, in that case the `destdir` will be created inside the `build` directory where `cmake` is run.
To pass the destdir path to the top-level PrusaSlicer CMake script, use the `CMAKE_PREFIX_PATH` option along with turning on `SLIC3R_STATIC`:
Once the dependencies have been built, in order to pass the destdir path to the **top-level** PrusaSlicer `CMakeLists.txt` script, use the `CMAKE_PREFIX_PATH` option along with turning on `SLIC3R_STATIC`:
cmake .. -DSLIC3R_STATIC=1 -DCMAKE_PREFIX_PATH=<path to destdir>/usr/local

View File

@ -90,8 +90,9 @@ Works on a fresh installation of MacOS Catalina 10.15.6
- Enter:
```brew install cmake git gettext
```
brew update
brew install cmake git gettext
brew upgrade
git clone https://github.com/prusa3d/PrusaSlicer/
cd PrusaSlicer/deps
@ -105,3 +106,4 @@ cd build
cmake .. -DCMAKE_PREFIX_PATH="$PWD/../deps/build/destdir/usr/local"
make
src/prusa-slicer
```

View File

@ -38,6 +38,8 @@ cd build
cmake .. -G "Visual Studio 16 2019" -DCMAKE_PREFIX_PATH="c:\src\PrusaSlicer-deps\usr\local"
```
Note that `CMAKE_PREFIX_PATH` must be absolute path. A relative path like "..\..\PrusaSlicer-deps\usr\local" does not work.
### Compile PrusaSlicer.
Double-click c:\src\PrusaSlicer\build\PrusaSlicer.sln to open in Visual Studio 2019.

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="compare_1_">
<g id="compare">
<path fill="#ED6B21" d="M7.87,2.23c-1.54-1.54-4.04-1.54-5.59,0s-1.54,4.04,0,5.59c1.43,1.43,3.69,1.53,5.24,0.31l1.33,1.33
c0,0-0.33,0.33,0,0.66c0.33,0.33,3.29,3.29,3.29,3.29s0.33,0.33,0.66,0c0.33-0.33,0.66-0.66,0.66-0.66s0.33-0.33,0-0.66
c-0.33-0.33-3.29-3.29-3.29-3.29c-0.33-0.33-0.66,0-0.66,0L8.18,7.47C9.41,5.92,9.3,3.67,7.87,2.23z M7.52,7.47
c-1.35,1.35-3.54,1.35-4.89,0s-1.35-3.54,0-4.89s3.54-1.35,4.89,0S8.87,6.12,7.52,7.47z"/>
</g>
<path fill="#808080" d="M7.49,4.35C7.43,4.16,7.36,3.97,7.26,3.8l0.18-0.54L6.85,2.67L6.31,2.85c-0.17-0.1-0.36-0.17-0.56-0.23
L5.5,2.11H4.66L4.41,2.62c-0.2,0.05-0.38,0.13-0.56,0.23L3.31,2.67L2.72,3.26L2.9,3.8C2.8,3.97,2.72,4.16,2.67,4.35L2.16,4.61v0.83
L2.67,5.7C2.72,5.9,2.8,6.08,2.9,6.26L2.72,6.8l0.59,0.59l0.54-0.18c0.17,0.1,0.36,0.17,0.56,0.23l0.26,0.51H5.5l0.26-0.51
c0.2-0.05,0.38-0.13,0.56-0.23l0.54,0.18L7.44,6.8L7.26,6.26C7.36,6.08,7.43,5.9,7.49,5.7L8,5.45V4.61L7.49,4.35z M5.08,6.33
c-0.72,0-1.3-0.58-1.3-1.3c0-0.72,0.58-1.3,1.3-1.3s1.3,0.58,1.3,1.3C6.38,5.75,5.8,6.33,5.08,6.33z"/>
<path fill="#808080" d="M14.56,4.45c-0.05-0.17-0.11-0.33-0.2-0.48l0.15-0.46l-0.51-0.51l-0.46,0.15c-0.15-0.08-0.31-0.15-0.48-0.2
l-0.22-0.44h-0.71l-0.22,0.44c-0.17,0.05-0.33,0.11-0.48,0.2l-0.46-0.15l-0.51,0.51l0.15,0.46c-0.08,0.15-0.15,0.31-0.2,0.48
L10,4.67v0.71l0.44,0.22c0.05,0.17,0.11,0.33,0.2,0.48l-0.15,0.46l0.51,0.51l0.46-0.15c0.15,0.08,0.31,0.15,0.48,0.2l0.22,0.44
h0.71l0.22-0.44c0.17-0.05,0.33-0.11,0.48-0.2l0.46,0.15l0.51-0.51l-0.15-0.46c0.08-0.15,0.15-0.31,0.2-0.48L15,5.39V4.67
L14.56,4.45z M12.5,6.14c-0.62,0-1.11-0.5-1.11-1.11c0-0.62,0.5-1.11,1.11-1.11s1.11,0.5,1.11,1.11
C13.61,5.64,13.11,6.14,12.5,6.14z"/>
<path fill="#808080" d="M7.14,11.91c-0.05-0.17-0.11-0.33-0.2-0.48l0.15-0.46l-0.51-0.51l-0.46,0.15c-0.15-0.08-0.31-0.15-0.48-0.2
L5.44,9.99H4.72L4.5,10.43c-0.17,0.05-0.33,0.11-0.48,0.2l-0.46-0.15l-0.51,0.51l0.15,0.46c-0.08,0.15-0.15,0.31-0.2,0.48
l-0.44,0.22v0.71l0.44,0.22c0.05,0.17,0.11,0.33,0.2,0.48L3.06,14l0.51,0.51l0.46-0.15c0.15,0.08,0.31,0.15,0.48,0.2l0.22,0.44
h0.71l0.22-0.44c0.17-0.05,0.33-0.11,0.48-0.2l0.46,0.15L7.1,14l-0.15-0.46c0.08-0.15,0.15-0.31,0.2-0.48l0.44-0.22v-0.71
L7.14,11.91z M5.08,13.6c-0.62,0-1.11-0.5-1.11-1.11c0-0.62,0.5-1.11,1.11-1.11s1.11,0.5,1.11,1.11C6.19,13.11,5.69,13.6,5.08,13.6
z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

15
resources/icons/equal.svg Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="121.805px" height="121.805px" viewBox="0 0 121.805 121.805" style="enable-background:new 0 0 121.805 121.805;"
xml:space="preserve">
<g>
<g>
<path fill="#808080" d="M7.308,85.264h107.188c4.037,0,7.309-3.271,7.309-7.31s-3.271-7.309-7.309-7.309H7.308C3.271,70.646,0,73.916,0,77.954
S3.271,85.264,7.308,85.264z"/>
<path fill="#808080" d="M7.308,51.158h107.188c4.037,0,7.309-3.272,7.309-7.309c0-4.037-3.271-7.308-7.309-7.308H7.308
C3.271,36.541,0,39.812,0,43.849C0,47.886,3.271,51.158,7.308,51.158z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 901 B

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="121.807px" height="121.807px" viewBox="0 0 121.807 121.807" style="enable-background:new 0 0 121.807 121.807;"
xml:space="preserve">
<g>
<g>
<path fill="#ED6B21" d="M7.308,75.519C3.271,75.519,0,78.789,0,82.827c0,4.036,3.271,7.31,7.308,7.31h18.897l-3.496,3.495
c-2.855,2.854-2.855,7.48,0,10.337c1.428,1.427,3.299,2.141,5.167,2.141c1.869,0,3.74-0.714,5.167-2.139l13.833-13.834h67.621
c4.037,0,7.31-3.272,7.31-7.31s-3.271-7.309-7.31-7.309H61.495L80.982,56.03h33.515c4.037,0,7.31-3.272,7.31-7.308
c0-4.037-3.271-7.309-7.31-7.309H95.602l13.24-13.24c2.854-2.855,2.854-7.481,0-10.336c-2.855-2.855-7.479-2.853-10.334,0
L74.932,41.414H7.308C3.271,41.414,0,44.685,0,48.723c0,4.036,3.271,7.308,7.308,7.308H60.31L40.821,75.519H7.308z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because it is too large Load Diff

View File

@ -8,15 +8,15 @@ msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-01-09 15:30+0700\n"
"PO-Revision-Date: 2021-01-10 02:38+0700\n"
"PO-Revision-Date: 2021-02-03 14:06+0100\n"
"Language-Team: Andylg <andylg@yandex.ru>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && "
"(n%100<10 || n%100>=20) ? 1 : 2);\n"
"X-Generator: Poedit 1.8.7\n"
"Last-Translator: \n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n"
"%100>=20) ? 1 : 2);\n"
"X-Generator: Poedit 2.4.2\n"
"Last-Translator: Oleksandra Iushchenko <yusanka@gmail.com>\n"
"Language: ru_RU\n"
#: src/slic3r/GUI/AboutDialog.cpp:45 src/slic3r/GUI/AboutDialog.cpp:299
@ -394,7 +394,6 @@ msgid "First layer height"
msgstr "Высота первого слоя"
#: src/slic3r/GUI/ConfigManipulation.cpp:81
#, c-format
msgid ""
"The Spiral Vase mode requires:\n"
"- one perimeter\n"
@ -410,7 +409,7 @@ msgstr ""
"- отсутствие верхних сплошных слоёв\n"
"- плотность заполнения 0%\n"
"- отсутствие поддержки\n"
"- отключено \"Обеспечивать вертикальную толщину оболочки\"\n"
"- включено \"Обеспечивать вертикальную толщину оболочки\"\n"
"- отключено \"Обнаружение тонких стенок\""
#: src/slic3r/GUI/ConfigManipulation.cpp:89
@ -432,7 +431,7 @@ msgstr ""
"только в том случае, если она печатается текущим экструдером, без запуска\n"
"смены инструмента. (Значения \"Экструдер, печатающий поддержки/подложки/юбки\"\n"
"и \"Экструдер, печатающий связующий слой поддержки/подложки\" должны быть\n"
"установлены в 0).\""
"установлены в 0)."
#: src/slic3r/GUI/ConfigManipulation.cpp:119
msgid "Shall I adjust those settings in order to enable the Wipe Tower?"
@ -546,7 +545,7 @@ msgstr "пруток"
#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:59 src/libslic3r/Preset.cpp:1300
msgid "SLA print"
msgstr "Профиль SLA печати:"
msgstr "Профиль SLA печати"
#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:60 src/slic3r/GUI/Plater.cpp:696
#: src/libslic3r/Preset.cpp:1301
@ -1070,7 +1069,7 @@ msgstr ""
#: src/slic3r/GUI/DoubleSlider.cpp:1241
msgid "Edit current color - Right click the colored slider segment"
msgstr "Изменить текущий цвет - Правая кнопка мыши по цветному сегменту ползунка ???"
msgstr "Изменить текущий цвет - Правая кнопка мыши по цветному сегменту ползунка"
#: src/slic3r/GUI/DoubleSlider.cpp:1251
msgid "Print mode"
@ -2238,7 +2237,7 @@ msgstr "Ctrl + Колесо мыши"
#: src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp:233
msgid "Autoset custom supports"
msgstr "Автоустановка пользовательских поддержек ???"
msgstr "Автоустановка пользовательских поддержек"
#: src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp:235
msgid "Threshold:"
@ -2344,7 +2343,7 @@ msgstr "Поворот"
#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:547
#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:563 src/libslic3r/PrintConfig.cpp:3754
msgid "Scale"
msgstr "Масштаб "
msgstr "Масштаб"
#: src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp:30
#: src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp:381
@ -2712,7 +2711,7 @@ msgid ""
"Note: This name can be changed later from the physical printers settings"
msgstr ""
"При создании новых принтеров они будут именоваться как \"Принтер N\".\n"
"Примечание: это имя можно изменить позже в настройках физических принтеров."
"Примечание: это имя можно изменить позже в настройках физических принтеров"
#: src/slic3r/GUI/GUI_App.cpp:1124 src/slic3r/GUI/PhysicalPrinterDialog.cpp:626
msgid "Information"
@ -2875,7 +2874,7 @@ msgstr "&Настройки"
#: src/slic3r/GUI/GUI_App.cpp:1781
msgid "The preset(s) modifications are successfully saved"
msgstr "Изменения в профиле(-ях) успешно сохранены."
msgstr "Изменения в профиле(-ях) успешно сохранены"
#: src/slic3r/GUI/GUI_App.cpp:1802
msgid "The uploads are still ongoing"
@ -3459,7 +3458,7 @@ msgstr "Неподдерживаемый выбор"
#: src/slic3r/GUI/GUI_ObjectList.cpp:4012
#, c-format
msgid "You started your selection with %s Item."
msgstr "Вы начали свой выбор с сущности %s"
msgstr "Вы начали свой выбор с сущности %s."
#: src/slic3r/GUI/GUI_ObjectList.cpp:4013
#, c-format
@ -3477,7 +3476,7 @@ msgstr "Информация"
#: src/slic3r/GUI/GUI_ObjectList.cpp:4137
msgid "You can't change a type of the last solid part of the object."
msgstr "Вы не можете изменить тип последнего твердотельного элемента модели"
msgstr "Вы не можете изменить тип последнего твердотельного элемента модели."
#: src/slic3r/GUI/GUI_ObjectList.cpp:4142
msgid "Modifier"
@ -3794,7 +3793,7 @@ msgstr "ОШИБКА: недостаточно ресурсов для выпо
#: src/slic3r/GUI/Jobs/RotoptimizeJob.cpp:41
msgid "Searching for optimal orientation"
msgstr "Поиск оптимального положения."
msgstr "Поиск оптимального положения"
#: src/slic3r/GUI/Jobs/RotoptimizeJob.cpp:73
msgid "Orientation search canceled."
@ -3850,7 +3849,7 @@ msgstr "Импорт завершён."
#: src/slic3r/GUI/Jobs/SLAImportJob.cpp:208 src/slic3r/GUI/Plater.cpp:2357
msgid "You cannot load SLA project with a multi-part object on the bed"
msgstr "Вы не можете загрузить SLA проект с составной моделью на столе."
msgstr "Вы не можете загрузить SLA проект с составной моделью на столе"
#: src/slic3r/GUI/Jobs/SLAImportJob.cpp:209 src/slic3r/GUI/Plater.cpp:2358
#: src/slic3r/GUI/Tab.cpp:3243
@ -5114,7 +5113,7 @@ msgstr ""
#: src/slic3r/GUI/NotificationManager.cpp:490
#: src/slic3r/GUI/NotificationManager.cpp:500
msgid "More"
msgstr "Подробнее."
msgstr "Подробнее"
#: src/slic3r/GUI/NotificationManager.cpp:864
#: src/slic3r/GUI/NotificationManager.cpp:1141
@ -9314,7 +9313,6 @@ msgid "Extra perimeters if needed"
msgstr "Дополнительные периметры при необходимости"
#: src/libslic3r/PrintConfig.cpp:539
#, c-format
msgid ""
"Add more perimeters when needed for avoiding gaps in sloping walls. Slic3r keeps "
"adding perimeters, until more than 70% of the loop immediately above is supported."
@ -10365,7 +10363,6 @@ msgid "This setting represents the maximum speed of your fan."
msgstr "Этот параметр регулирует максимальную скорость вращения вентилятора."
#: src/libslic3r/PrintConfig.cpp:1435
#, c-format
msgid ""
"This is the highest printable layer height for this extruder, used to cap the "
"variable layer height and support layer height. Maximum recommended layer height is "

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,10 @@
min_slic3r_version = 2.3.0-beta2
0.0.8 Updated start and end g-code for Anycubic Mega.
0.0.7 Updated start g-code for Anycubic Mega.
0.0.6 Reduced max print height for Predator. Updated end g-code, before layer change g-code and output filename format for Kossel.
0.0.5 Updated end g-code.
min_slic3r_version = 2.3.0-alpha2
0.0.4 Fixed predator output filaname format, infill overlap.
0.0.4 Fixed predator output filename format, infill overlap, start gcode adjustments.
0.0.3 Fixed infill_overlap, start_gcode, end_gcode for Anycubic Predator
0.0.2 Added Anycubic Predator
min_slic3r_version = 2.3.0-alpha0

View File

@ -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.6
config_version = 0.0.8
# 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%
@ -1051,7 +1051,7 @@ before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;[layer_z]
default_filament_profile = Generic PLA @MEGA
default_print_profile = 0.15mm QUALITY @MEGA
deretract_speed = 50
end_gcode = G4 ; wait\nG92 E0\nG1{if max_layer_z < max_print_height} Z{z_offset+min(max_layer_z+30, max_print_height)}{endif} E-35 F1000 ; move print head up & retract filament\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors
end_gcode = G4 ; wait\nG92 E0\nG1{if max_layer_z < max_print_height} Z{z_offset+min(max_layer_z+30, max_print_height)}{endif} ; move print head up\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors
extruder_colour = #808080
gcode_flavor = marlin
layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z]
@ -1063,7 +1063,7 @@ retract_length = 6
retract_lift = 0.075
retract_lift_below = 204
silent_mode = 0
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting]\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nG28 ; home all\nG1 Y0 Z1 F100 ; move print head up\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG92 E0\nG1 E38 F1000; deretract filament\nG92 E0\nG1 X60 Z0 E9 ; intro line\nG1 X100 E12.5 ; intro line\nG92 E0
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting]\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nG28 ; home all\nG1 Y0 Z1 F100 ; move print head up\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG92 E0\nG1 Z0.2 F360\nG1 X60 E9 F700 ; intro line\nG1 X100 E12.5 F700 ; intro line\nG92 E0
use_relative_e_distances = 1
wipe = 1
machine_max_acceleration_e = 5000

View File

@ -0,0 +1,2 @@
min_slic3r_version = 2.3.0
0.0.1 Initial Artillery bundle

View File

@ -0,0 +1,477 @@
###############
# AUTHOR: Szabolcs Hornyak / design85@gmail.com
# https://szabolcs.eu/2020/12/29/prusaslicer-sw-x1-genius/
# Tested with PrusaSlicer 2.2, 2.3
###############
# Print profiles for the Artillery printers.
[vendor]
# Vendor name will be shown by the Config Wizard.
name = Artillery
# 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.1
# Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Artillery/
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
# The printer models will be shown by the Configuration Wizard in this order,
# also the first model installed & the first nozzle installed will be activated after install.
# Printer model name will be shown by the installation wizard.
#############
## PRINTER ##
#############
[printer_model:X1]
name = Sidewinder X1
variants = 0.4
technology = FFF
bed_model = bed-x1.stl
bed_texture = bed-x1.png
default_materials = Generic PLA @Artillery; Generic ABS @Artillery; Generic PETG @Artillery; Generic TPU @Artillery
[printer_model:Genius]
name = Genius
variants = 0.4
technology = FFF
bed_model = bed-genius.stl
bed_texture = bed-genius.png
default_materials = Generic PLA @Artillery; Generic ABS @Artillery; Generic PETG @Artillery; Generic TPU @Artillery
# Common printer preset
[printer:*common*]
before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0
between_objects_gcode =
cooling_tube_length = 5
cooling_tube_retraction = 91.5
default_filament_profile = Generic PLA @Artillery
default_print_profile = 0.20mm NORMAL @Artillery
deretract_speed = 0
extruder_colour = #FFFF00
extruder_offset = 0x0
gcode_flavor = marlin
layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z]
machine_max_acceleration_e = 5000,5000
machine_max_acceleration_extruding = 1250,1250
machine_max_acceleration_retracting = 1250,1250
machine_max_acceleration_x = 1000,960
machine_max_acceleration_y = 1000,960
machine_max_acceleration_z = 1000,1000
machine_max_feedrate_e = 120,120
machine_max_feedrate_x = 200,100
machine_max_feedrate_y = 200,100
machine_max_feedrate_z = 12,12
machine_max_jerk_e = 1.5,1.5
machine_max_jerk_x = 8,8
machine_max_jerk_y = 8,8
machine_max_jerk_z = 0.4,0.4
machine_min_extruding_rate = 0,0
machine_min_travel_rate = 0,0
max_layer_height = 0.25
max_print_height = 250
min_layer_height = 0.07
nozzle_diameter = 0.4
pause_print_gcode =
printer_technology = FFF
remaining_times = 0
retract_before_travel = 1
retract_before_wipe = 0%
retract_layer_change = 1
retract_length = 1.9
retract_length_toolchange = 4
retract_lift = 0.6
retract_lift_above = 0
retract_lift_below = 380
retract_restart_extra = 0
retract_restart_extra_toolchange = 0
retract_speed = 35
silent_mode = 0
single_extruder_multi_material = 0
toolchange_gcode =
use_firmware_retraction = 0
use_relative_e_distances = 1
use_volumetric_e = 0
variable_layer_height = 1
wipe = 1
z_offset = 0
end_gcode = G4 ; wait\nG92 E0 ; prepare to retract\nG1 E-0.5 F3000; retract to avoid stringing\n\n; Anti-stringing end wiggle\nG91 ; use relative coordinates\nG1 X1 Y1 F1200\n\n; Raise nozzle and present bed\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+120, max_print_height)}{endif} ; Move print head up\nG90 ; use absolute coordinates\n\n; Reset print setting overrides\nM200 D0 ; disable volumetric e\nM220 S100 ; reset speed factor to 100%\nM221 S100 ; reset extrusion rate to 100%\n\n; Shut down printer\nM106 S0 ; turn-off fan\nM104 S0 ; turn-off hotend\nM140 S0 ; turn-off bed\nM150 P0 ; turn off led\nM85 S0 ; deactivate idle timeout\nM84 ; disable motors\n
[printer:*common_STOCK_FW*]
inherits = *common*
start_gcode = ; Initial setups\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM900 W[extrusion_width] H[layer_height] D[filament_diameter]\nM200 D0 ; disable volumetric e\nM220 S100 ; reset speed factor to 100%\nM221 S100 ; reset extrusion rate to 100%\n\n; Set the heating\nM190 S[first_layer_bed_temperature]; wait for bed to heat up\nM104 S[first_layer_temperature]; start nozzle heating but don't wait\n\n; Home\nG1 Z3 F3000 ; move z up little to prevent scratching of surface\nG28 ; home all axes\nG1 X3 Y3 F5000 ; move to corner of the bed to avoid ooze over centre\n\n; Wait for final heating\nM109 S[first_layer_temperature] ; wait for the nozzle to heat up\nM190 S[first_layer_bed_temperature] ; wait for the bed to heat up\n\n; Return to prime position, Prime line routine\nG92 E0 ; Reset Extruder\nG1 Z3 F3000 ; move z up little to prevent scratching of surface\nG1 X10 Y.5 Z0.25 F5000.0 ; Move to start position\nG1 X100 Y.5 Z0.25 F1500.0 E15 ; Draw the first line\nG1 X100 Y.2 Z0.25 F5000.0 ; Move to side a little\nG1 X10 Y.2 Z0.25 F1500.0 E30 ; Draw the second line\nG92 E0 ; Reset Extruder\nM221 S{if layer_height<0.075}100{else}95{endif}
[printer:*common_UPD_FW*]
inherits = *common*
start_gcode = ; Initial setups\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM900 K0.12; K factor\nM900 W[extrusion_width] H[layer_height] D[filament_diameter]\nM200 D0 ; disable volumetric e\nM220 S100 ; reset speed factor to 100%\nM221 S100 ; reset extrusion rate to 100%\n\n; Set the heating\nM190 S[first_layer_bed_temperature]; wait for bed to heat up\nM104 S[first_layer_temperature]; start nozzle heating but don't wait\n\n; Home\nG1 Z3 F3000 ; move z up little to prevent scratching of surface\nG28 ; home all axes\nG1 X3 Y3 F5000 ; move to corner of the bed to avoid ooze over centre\n\n; Wait for final heating\nM109 S[first_layer_temperature] ; wait for the nozzle to heat up\nM190 S[first_layer_bed_temperature] ; wait for the bed to heat up\n\n;Auto bed Leveling\n@BEDLEVELVISUALIZER\nG29 ; ABL T\nM420 S1 Z3 ; reload and fade mesh bed leveling until it reach 3mm Z\n\n; Return to prime position, Prime line routine\nG92 E0 ; Reset Extruder\nG1 Z3 F3000 ; move z up little to prevent scratching of surface\nG1 X10 Y.5 Z0.25 F5000.0 ; Move to start position\nG1 X100 Y.5 Z0.25 F1500.0 E15 ; Draw the first line\nG1 X100 Y.2 Z0.25 F5000.0 ; Move to side a little\nG1 X10 Y.2 Z0.25 F1500.0 E30 ; Draw the second line\nG92 E0 ; Reset Extruder\nM221 S{if layer_height<0.075}100{else}95{endif}
[printer:Sidewinder X1]
inherits = *common_STOCK_FW*
printer_model = X1
printer_variant = 0.4
bed_shape = 0x0,300x0,300x300,0x300
max_print_height = 400
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_Artillery\nPRINTER_MODEL_X1
[printer:Sidewinder X1 BL-TOUCH]
inherits = *common_UPD_FW*
printer_model = X1
printer_variant = 0.4
bed_shape = 0x0,300x0,300x300,0x300
max_print_height = 400
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_Artillery\nPRINTER_MODEL_X1
[printer:Genius]
inherits = *common_STOCK_FW*
printer_model = Genius
printer_variant = 0.4
bed_shape = 0x0,230x0,230x230,0x230
max_print_height = 250
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_Artillery\nPRINTER_MODEL_Genius
[printer:Genius BL-TOUCH]
inherits = *common_UPD_FW*
printer_model = Genius
printer_variant = 0.4
bed_shape = 0x0,230x0,230x230,0x230
max_print_height = 250
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_Artillery\nPRINTER_MODEL_Genius
###########
## PRINT ##
###########
# Common print preset
[print:*common*]
# V2.2 #
#bottom_fill_pattern = rectilinear
#top_fill_pattern = rectilinear
#fill_pattern = cubic
# V2.3 #
top_fill_pattern = monotonic
bottom_fill_pattern = monotonic
fill_pattern = adaptivecubic
avoid_crossing_perimeters = 0
bridge_acceleration = 1000
bridge_angle = 0
bridge_flow_ratio = 0.78
bridge_speed = 20
# brim_width = 5
bottom_solid_min_thickness = 1.2
clip_multipart_objects = 1
compatible_printers =
complete_objects = 0
default_acceleration = 1000
dont_support_bridges = 1
elefant_foot_compensation = 0
ensure_vertical_shell_thickness = 1
external_perimeter_extrusion_width = 0.45
external_perimeter_speed = 25
external_perimeters_first = 0
extra_perimeters = 0
extruder_clearance_height = 25
extruder_clearance_radius = 45
extrusion_width = 0.45
fill_angle = 45
fill_density = 15%
first_layer_acceleration = 500
first_layer_extrusion_width = 0.42
first_layer_height = 150%
first_layer_speed = 20
gap_fill_speed = 30
gcode_comments = 1
gcode_label_objects = 1
infill_acceleration = 1000
infill_every_layers = 1
infill_extruder = 1
infill_extrusion_width = 0.45
infill_first = 0
infill_only_where_needed = 0
infill_overlap = 25%
infill_speed = 50
interface_shells = 0
max_print_speed = 150
max_volumetric_extrusion_rate_slope_negative = 0
max_volumetric_extrusion_rate_slope_positive = 0
max_volumetric_speed = 0
min_skirt_length = 4
notes =
overhangs = 1
only_retract_when_crossing_perimeters = 0
ooze_prevention = 0
output_filename_format = {input_filename_base}_{layer_height}mm_{filament_type[0]}_{printer_model}_{print_time}.gcode
perimeters = 3
perimeter_acceleration = 800
perimeter_extruder = 1
perimeter_extrusion_width = 0
perimeter_speed = 45
post_process =
print_settings_id =
raft_layers = 0
resolution = 0
seam_position = nearest
single_extruder_multi_material_priming = 0
skirts = 1
skirt_distance = 6
skirt_height = 1
small_perimeter_speed = 25
solid_infill_below_area = 0
solid_infill_every_layers = 0
solid_infill_extruder = 1
solid_infill_extrusion_width = 0.45
solid_infill_speed = 50
spiral_vase = 0
standby_temperature_delta = -5
support_material = 0
support_material_extruder = 0
support_material_extrusion_width = 0.35
support_material_interface_extruder = 0
support_material_angle = 0
support_material_buildplate_only = 0
support_material_enforce_layers = 0
support_material_contact_distance = 0.15
support_material_interface_contact_loops = 0
support_material_interface_layers = 2
support_material_interface_spacing = 0.2
support_material_interface_speed = 100%
support_material_pattern = rectilinear
support_material_spacing = 2
support_material_speed = 50
support_material_synchronize_layers = 0
support_material_threshold = 55
support_material_with_sheath = 0
support_material_xy_spacing = 50%
thin_walls = 1
travel_speed = 130
top_infill_extrusion_width = 0.4
top_solid_infill_speed = 30
wipe_tower = 0
wipe_tower_bridging = 10
wipe_tower_rotation_angle = 0
wipe_tower_width = 60
wipe_tower_x = 170
wipe_tower_y = 125
xy_size_compensation = 0
[print:*0.08mm*]
inherits = *common*
default_acceleration = 500
layer_height = 0.08
perimeters = 3
bottom_solid_layers = 9
top_solid_layers = 11
[print:*0.10mm*]
inherits = *common*
default_acceleration = 500
layer_height = 0.1
perimeters = 3
bottom_solid_layers = 7
top_solid_layers = 9
[print:*0.12mm*]
inherits = *common*
default_acceleration = 500
layer_height = 0.12
perimeters = 3
bottom_solid_layers = 6
top_solid_layers = 7
[print:*0.16mm*]
inherits = *common*
layer_height = 0.16
bottom_solid_layers = 5
top_solid_layers = 7
[print:*0.20mm*]
inherits = *common*
layer_height = 0.20
bottom_solid_layers = 4
top_solid_layers = 5
[print:*0.24mm*]
inherits = *common*
layer_height = 0.24
top_infill_extrusion_width = 0.45
bottom_solid_layers = 3
top_solid_layers = 4
[print:*0.28mm*]
inherits = *common*
layer_height = 0.28
top_infill_extrusion_width = 0.45
first_layer_extrusion_width = 0.75
bottom_solid_layers = 3
top_solid_layers = 4
[print:0.08mm SUPERDETAIL @Artillery]
inherits = *0.08mm*
compatible_printers_condition = printer_model=~/(X1|Genius).*/ and nozzle_diameter[0]==0.4
[print:0.10mm HIGHDETAIL @Artillery]
inherits = *0.10mm*
compatible_printers_condition = printer_model=~/(X1|Genius).*/ and nozzle_diameter[0]==0.4
[print:0.12mm DETAIL @Artillery]
inherits = *0.12mm*
compatible_printers_condition = printer_model=~/(X1|Genius).*/ and nozzle_diameter[0]==0.4
[print:0.16mm OPTIMAL @Artillery]
inherits = *0.16mm*
compatible_printers_condition = printer_model=~/(X1|Genius).*/ and nozzle_diameter[0]==0.4
[print:0.20mm SLOW @Artillery]
inherits = *0.20mm*
external_perimeter_speed = 15
fill_density = 20%
gap_fill_speed = 25
infill_speed = 50
perimeter_speed = 30
perimeters = 3
solid_infill_speed = 50
top_solid_infill_speed = 25
first_layer_speed = 15
travel_speed = 100
compatible_printers_condition = printer_model=~/(X1|Genius).*/ and nozzle_diameter[0]==0.4
[print:0.20mm NORMAL @Artillery]
inherits = *0.20mm*
compatible_printers_condition = printer_model=~/(X1|Genius).*/ and nozzle_diameter[0]==0.4
[print:0.20mm SPEED @Artillery]
inherits = *0.20mm*
external_perimeter_speed = 35
fill_density = 15%
fill_pattern = grid
gap_fill_speed = 45
infill_speed = 150
infill_only_where_needed = 1
perimeter_speed = 60
perimeters = 2
solid_infill_speed = 150
top_solid_infill_speed = 50
travel_speed = 170
compatible_printers_condition = printer_model=~/(X1|Genius).*/ and nozzle_diameter[0]==0.4
[print:0.24mm DRAFT @Artillery]
inherits = *0.24mm*
compatible_printers_condition = printer_model=~/(X1|Genius).*/ and nozzle_diameter[0]==0.4
[print:0.28mm SUPERDRAFT @Artillery]
inherits = *0.28mm*
compatible_printers_condition = printer_model=~/(X1|Genius).*/ and nozzle_diameter[0]==0.4
###############
## FILAMENTS ##
###############
# Common filament preset
[filament:*common*]
cooling = 1
compatible_printers =
extrusion_multiplier = 1
filament_cost = 0
filament_density = 0
filament_diameter = 1.75
filament_notes = ""
filament_settings_id = ""
filament_soluble = 0
min_print_speed = 15
slowdown_below_layer_time = 15
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_Artillery.*/
[filament:*PLA*]
inherits = *common*
bed_temperature = 60
bridge_fan_speed = 100
cooling = 1
disable_fan_first_layers = 1
fan_always_on = 1
fan_below_layer_time = 100
filament_colour = #428AF5
filament_cost = 20
filament_density = 1.24
filament_max_volumetric_speed = 15
filament_type = PLA
first_layer_bed_temperature = 65
first_layer_temperature = 210
full_fan_speed_layer = 3
max_fan_speed = 100
min_fan_speed = 100
temperature = 205
[filament:*PET*]
inherits = *common*
bed_temperature = 70
bridge_fan_speed = 100
cooling = 1
disable_fan_first_layers = 3
fan_always_on = 1
fan_below_layer_time = 20
filament_colour = #42E9F5
filament_cost = 30
filament_density = 1.27
filament_max_volumetric_speed = 8
filament_type = PETG
first_layer_bed_temperature = 70
first_layer_temperature = 235
max_fan_speed = 50
min_fan_speed = 20
temperature = 230
[filament:*ABS*]
inherits = *common*
bed_temperature = 90
bridge_fan_speed = 30
cooling = 0
disable_fan_first_layers = 3
fan_always_on = 0
fan_below_layer_time = 20
filament_colour = #6603FC
filament_cost = 20
filament_density = 1.04
filament_max_volumetric_speed = 11
filament_type = ABS
first_layer_bed_temperature = 90
first_layer_temperature = 240
max_fan_speed = 0
min_fan_speed = 0
temperature = 240
top_fan_speed = 0
[filament:*TPU*]
inherits = *common*
bed_temperature = 55
cooling = 0
disable_fan_first_layers = 3
fan_always_on = 0
fan_below_layer_time = 20
filament_colour = #CFFFFB
filament_cost = 30
filament_density = 1.2
filament_max_volumetric_speed = 11
filament_retract_before_travel = 4
filament_retract_length = 2.5
filament_retract_speed = 30
filament_type = TPU
first_layer_bed_temperature = 55
first_layer_temperature = 210
max_fan_speed = 70
min_fan_speed = 0
[filament:Generic PLA @Artillery]
inherits = *PLA*
filament_vendor = Generic
[filament:Generic PETG @Artillery]
inherits = *PET*
filament_vendor = Generic
[filament:Generic ABS @Artillery]
inherits = *ABS*
filament_vendor = Generic
[filament:Generic TPU @Artillery]
inherits = *TPU*
filament_vendor = Generic

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 MiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -1,4 +1,5 @@
min_slic3r_version = 2.3.0-rc2
0.0.14 Optimized start g-code. Added filament profile. Various improvements.
0.0.13 Optimized start and end g-code. General improvements.
0.0.12 Added Ender-3V2 and filament profiles.
min_slic3r_version = 2.3.0-beta2

View File

@ -5,7 +5,7 @@
name = Creality
# 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.13
config_version = 0.0.14
# Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Creality/
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -23,15 +23,6 @@ bed_model = ender3_bed.stl
bed_texture = ender3.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
[printer_model:ENDER3V2]
name = Creality Ender-3 V2
variants = 0.4
technology = FFF
family = ENDER
bed_model = ender3_bed.stl
bed_texture = ender3.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
[printer_model:ENDER3BLTOUCH]
name = Creality Ender-3 BLTouch
variants = 0.4
@ -41,6 +32,33 @@ bed_model = ender3_bed.stl
bed_texture = ender3.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
[printer_model:ENDER3V2]
name = Creality Ender-3 V2
variants = 0.4
technology = FFF
family = ENDER
bed_model = ender3v2_bed.stl
bed_texture = ender3v2.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
#[printer_model:ENDER3MAX]
#name = Creality Ender-3 Max
#variants = 0.4
#technology = FFF
#family = ENDER
#bed_model = cr10v2_bed.stl
#bed_texture = cr10spro.svg
#default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
#[printer_model:ENDER4]
#name = Creality Ender-4
#variants = 0.4
#technology = FFF
#family = ENDER
#bed_model = ender3v2_bed.stl
#bed_texture = ender3v2.svg
#default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
[printer_model:ENDER5]
name = Creality Ender-5
variants = 0.4
@ -59,6 +77,15 @@ bed_model = ender5plus_bed.stl
bed_texture = ender5plus.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
#[printer_model:ENDER6]
#name = Creality Ender-6
#variants = 0.4
#technology = FFF
#family = ENDER
#bed_model = ender6_bed.stl
#bed_texture = ender6.svg
#default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
[printer_model:ENDER2]
name = Creality Ender-2
variants = 0.4
@ -73,8 +100,17 @@ default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @
#variants = 0.4
#technology = FFF
#family = CR
#bed_model = ender3_bed.stl
#bed_texture = cr20.svg
#bed_model = cr6se_bed.stl
#bed_texture = cr6se.svg
#default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
#[printer_model:CR6MAX]
#name = Creality CR-6 Max
#variants = 0.4
#technology = FFF
#family = CR
#bed_model = cr10s4_bed.stl
#bed_texture = cr10s4.svg
#default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
[printer_model:CR10MINI]
@ -86,6 +122,15 @@ bed_model = cr10mini_bed.stl
bed_texture = cr10mini.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
#[printer_model:CR10MAX]
#name = Creality CR-10 Max
#variants = 0.4
#technology = FFF
#family = CR
#bed_model = cr10max_bed.stl
#bed_texture = cr10max.svg
#default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
[printer_model:CR10]
name = Creality CR-10
variants = 0.4
@ -128,7 +173,7 @@ variants = 0.4
technology = FFF
family = CR
bed_model = cr10v2_bed.stl
bed_texture = cr10.svg
bed_texture = cr10spro.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
[printer_model:CR10SPROV2]
@ -176,6 +221,33 @@ bed_model = ender3_bed.stl
bed_texture = cr20.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
#[printer_model:CR8]
#name = Creality CR-8
#variants = 0.4
#technology = FFF
#family = CR
#bed_model = cr8_bed.stl
#bed_texture = cr8.svg
#default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
#[printer_model:CRX]
#name = Creality CR-X
#variants = 0.4
#technology = FFF
#family = CR-X
#bed_model = cr10v2_bed.stl
#bed_texture = cr10spro.svg
#default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
#[printer_model:CRXPRO]
#name = Creality CR-X Pro
#variants = 0.4
#technology = FFF
#family = CR-X
#bed_model = cr10v2_bed.stl
#bed_texture = cr10spro.svg
#default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA (Galaxy) @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 123-3D Jupiter PLA @CREALITY
# All presets starting with asterisk, for example *common*, are intermediate and they will
# not make it into the user interface.
@ -556,6 +628,17 @@ filament_density = 1.3
filament_colour = #3C4547
filament_spool_weight = 256
[filament:Extrudr GreenTEC Pro @CREALITY]
inherits = *PLA*
filament_vendor = Extrudr
temperature = 210
bed_temperature = 60
first_layer_temperature = 215
first_layer_bed_temperature = 60
filament_cost = 56.24
filament_density = 1.35
filament_colour = #3C4547
[filament:Real Filament PLA @CREALITY]
inherits = *PLA*
filament_vendor = Real Filament
@ -610,6 +693,7 @@ first_layer_temperature = 215
first_layer_bed_temperature = 60
filament_cost = 20.56
filament_density = 1.24
filament_colour = #C7F935
[filament:Das Filament PETG @CREALITY]
inherits = *PET*
@ -620,6 +704,7 @@ first_layer_temperature = 240
first_layer_bed_temperature = 70
filament_cost = 27.44
filament_density = 1.29
filament_colour = #C7F935
# Common printer preset
[printer:*common*]
@ -628,7 +713,7 @@ before_layer_gcode = ;BEFORE_LAYER_CHANGE\nG92 E0\n;[layer_z]\n\n
between_objects_gcode =
pause_print_gcode =
deretract_speed = 0
extruder_colour = #FFFF00
extruder_colour = #FCE94F
extruder_offset = 0x0
gcode_flavor = marlin
silent_mode = 0
@ -711,138 +796,208 @@ retract_length = 5
retract_speed = 60
deretract_speed = 40
retract_before_wipe = 70%
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S120 ; set extruder temp for auto bed leveling\nM140 S[first_layer_bed_temperature] ; set bed temp\nG4 S10 ; wait for partial warmup\nG28 ; home all\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S[first_layer_temperature] ; set extruder temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; intro line\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; intro line\nG92 E0
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S120 ; set temporary nozzle temp to prevent oozing during homing and auto bed leveling\nM140 S[first_layer_bed_temperature] ; set final bed temp\nG4 S10 ; allow partial nozzle warmup\nG28 ; home all axis\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S[first_layer_temperature] ; set final nozzle temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp to stabilize\nM109 S[first_layer_temperature] ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F600 ; Move print head up{endif}\nG1 X5 Y{print_bed_max[1]*0.8} F{travel_speed*60} ; present print\n{if max_layer_z < max_print_height-10}G1 Z{z_offset+min(max_layer_z+70, max_print_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{max_print_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors
[printer:Creality Ender-3 V2]
inherits = Creality Ender-3
renamed_from = "Creality Ender-3V2"
printer_model = ENDER3V2
bed_shape = 0x0,220x0,220x220,0x220
# Intended for printers with a smaller bed, like the Ender-3 series
[printer:*fastabl*]
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S120 ; set extruder temp for auto bed leveling\nM140 S[first_layer_bed_temperature] ; set bed temp\nG4 S10 ; wait for partial warmup\nG28 ; home all\nG29 ; auto bed levelling\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S[first_layer_temperature] ; set extruder temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; intro line\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; intro line\nG92 E0
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S120 ; set temporary nozzle temp to prevent oozing during homing and auto bed leveling\nM140 S[first_layer_bed_temperature] ; set final bed temp\nG4 S10 ; allow partial nozzle warmup\nG28 ; home all axis\nG29 ; auto bed levelling\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S[first_layer_temperature] ; set final nozzle temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp to stabilize\nM109 S[first_layer_temperature] ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0
# Intended for printers with a larger bed, like the CR-10 series
[printer:*slowabl*]
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S120 ; set extruder temp for auto bed leveling\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG28 ; home all\nG29 ; auto bed levelling\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S[first_layer_temperature] ; set extruder temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; intro line\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; intro line\nG92 E0
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S120 ; set temporary nozzle temp to prevent oozing during homing and auto bed leveling\nM140 S[first_layer_bed_temperature] ; set final bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp to stabilize\nG28 ; home all axis\nG29 ; auto bed levelling\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S[first_layer_temperature] ; set final nozzle temp\nM109 S[first_layer_temperature] ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0
# Intended for printers with vendor official firmware verified to support M25
[printer:*pauseprint*]
pause_print_gcode = M25 ; pause print
# Intended for printers where the Z-axis lowers the print bed during printing, like the Ender-5 series
[printer:*invertedz*]
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F600{endif} ; Move print bed down\nG1 X50 Y50 F{travel_speed*60} ; present print\n{if max_layer_z < max_print_height-10}G1 Z{z_offset+max_print_height-10} F600{endif} ; Move print bed down further down\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors
[printer:*descendingz*]
renamed_from = "*invertedz*"
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F600{endif} ; Move print bed down\nG1 X50 Y50 F{travel_speed*60} ; move print head out of the way\n{if max_layer_z < max_print_height-10}G1 Z{z_offset+max_print_height-10} F600{endif} ; Move print bed close to the bottom\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors
# Intended for printers with dual extruders and a single hotend/nozzle, like the CR-X series
[printer:*dualextruder*]
single_extruder_multi_material = 1
cooling_tube_length = 5
cooling_tube_retraction = 91.5
extra_loading_move = -2
parking_pos_retraction = 92
deretract_speed = 40,40
extruder_colour = #FCE94F;#729FCF
extruder_offset = 0x0,0x0
max_layer_height = 0.28,0.28
min_layer_height = 0.08,0.08
nozzle_diameter = 0.4,0.4
retract_before_travel = 2,2
retract_before_wipe = 70%,70%
retract_layer_change = 1,1
retract_length = 5,5
retract_length_toolchange = 1,1
retract_lift = 0,0
retract_lift_above = 0,0
retract_lift_below = 0,0
retract_restart_extra = 0,0
retract_restart_extra_toolchange = 0,0
retract_speed = 60,60
wipe = 1,1
[printer:Creality Ender-3 BLTouch]
inherits = Creality Ender-3; *fastabl*
renamed_from = "Creality ENDER-3 BLTouch"
printer_model = ENDER3BLTOUCH
[printer:Creality Ender-3 V2]
inherits = Creality Ender-3
renamed_from = "Creality Ender-3V2"
printer_model = ENDER3V2
bed_shape = 5x0,215x0,215x220,5x220
#[printer:Creality Ender-3 Max]
#inherits = Creality Ender-3
#retract_length = 6
#bed_shape = 5x5,295x5,295x295,5x295
#max_print_height = 340
#printer_model = ENDER3MAX
#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_CREALITY\nPRINTER_MODEL_ENDER3MAX\nPRINTER_HAS_BOWDEN
#[printer:Creality Ender-4]
#inherits = Creality Ender-3; *descendingz*
#bed_shape = 5x0,215x0,215x220,5x220
#max_print_height = 300
#printer_model = ENDER4
#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_CREALITY\nPRINTER_MODEL_ENDER4\nPRINTER_HAS_BOWDEN
[printer:Creality Ender-5]
inherits = Creality Ender-3; *invertedz*
inherits = Creality Ender-3; *descendingz*
retract_length = 6
bed_shape = 5x2.5,225x2.5,225x222.5,5x222.5
max_print_height = 300
printer_model = ENDER5
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_CREALITY\nPRINTER_MODEL_ENDER5\nPRINTER_HAS_BOWDEN
max_print_height = 300
machine_max_acceleration_e = 1000
machine_max_feedrate_z = 5
[printer:Creality Ender-5 Plus]
inherits = Creality Ender-3; *slowabl*; *invertedz*
inherits = Creality Ender-3; *slowabl*; *descendingz*
retract_length = 6
bed_shape = 5x5,355x5,355x355,5x355
max_print_height = 400
printer_model = ENDER5PLUS
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_CREALITY\nPRINTER_MODEL_ENDER5PLUS\nPRINTER_HAS_BOWDEN
max_print_height = 400
machine_max_acceleration_e = 1000
machine_max_feedrate_z = 5
machine_max_feedrate_x = 300
machine_max_feedrate_y = 300
#[printer:Creality Ender-6]
#inherits = Creality Ender-3; *descendingz*
#bed_shape = 5x5,255x5,255x255,5x255
#max_print_height = 400
#printer_model = ENDER6
#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_CREALITY\nPRINTER_MODEL_ENDER6\nPRINTER_HAS_BOWDEN
[printer:Creality Ender-2]
inherits = Creality Ender-3
renamed_from = "Creality ENDER-2"
bed_shape = 0x0,150x0,150x150,0x150
max_print_height = 200
printer_model = ENDER2
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_CREALITY\nPRINTER_MODEL_ENDER2\nPRINTER_HAS_BOWDEN
max_print_height = 200
#[printer:Creality CR-6 SE]
#inherits = Creality Ender-3; *fastabl*
#inherits = Creality Ender-3; *fastabl*; *pauseprint*
#bed_shape = 5x0,230x0,230x235,5x235
#printer_model = CR6SE
#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_CREALITY\nPRINTER_MODEL_CR6SE\nPRINTER_HAS_BOWDEN
#[printer:Creality CR-6 Max]
#inherits = Creality Ender-3; *slowabl*
#retract_length = 6
#bed_shape = 5x5,395x5,395x395,5x395
#max_print_height = 400
#printer_model = CR6MAX
#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_CREALITY\nPRINTER_MODEL_CR6MAX\nPRINTER_HAS_BOWDEN
[printer:Creality CR-10 Mini]
inherits = Creality Ender-3
retract_length = 6
bed_shape = 2.5x5,2.5x225,302.5x225,302.5x5
max_print_height = 300
printer_model = CR10MINI
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_CREALITY\nPRINTER_MODEL_CR10MINI\nPRINTER_HAS_BOWDEN
max_print_height = 300
#[printer:Creality CR-10 Max]
#inherits = Creality Ender-3; *slowabl*
#retract_length = 6
#bed_shape = 5x5,445x5,445x445,5x445
#max_print_height = 470
#printer_model = CR10MAX
#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_CREALITY\nPRINTER_MODEL_CR10MAX\nPRINTER_HAS_BOWDEN
[printer:Creality CR-10]
inherits = Creality Ender-3
retract_length = 6
bed_shape = 5x5,305x5,305x305,5x305
max_print_height = 400
printer_model = CR10
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_CREALITY\nPRINTER_MODEL_CR10\nPRINTER_HAS_BOWDEN
max_print_height = 400
[printer:Creality CR-10 V2]
inherits = Creality Ender-3
retract_length = 6
bed_shape = 5x5,305x5,305x305,5x305
max_print_height = 400
printer_model = CR10V2
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_CREALITY\nPRINTER_MODEL_CR10V2\nPRINTER_HAS_BOWDEN
max_print_height = 400
[printer:Creality CR-10 V3]
inherits = Creality Ender-3
retract_length = 1
bed_shape = 5x5,305x5,305x305,5x305
max_print_height = 400
printer_model = CR10V3
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_CREALITY\nPRINTER_MODEL_CR10V3
max_print_height = 400
[printer:Creality CR-10 S]
inherits = Creality Ender-3
retract_length = 6
bed_shape = 5x5,305x5,305x305,5x305
max_print_height = 400
printer_model = CR10S
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_CREALITY\nPRINTER_MODEL_CR10S\nPRINTER_HAS_BOWDEN
max_print_height = 400
[printer:Creality CR-10 S Pro]
inherits = Creality Ender-3; *slowabl*
retract_length = 6
bed_shape = 0x0,300x0,300x300,0x300
bed_shape = 5x5,295x5,295x295,5x295
max_print_height = 400
printer_model = CR10SPRO
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_CREALITY\nPRINTER_MODEL_CR10SPRO\nPRINTER_HAS_BOWDEN
max_print_height = 400
[printer:Creality CR-10 S Pro V2]
inherits = Creality Ender-3; *slowabl*
retract_length = 6
bed_shape = 5x5,305x5,305x305,5x305
max_print_height = 400
printer_model = CR10SPROV2
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_CREALITY\nPRINTER_MODEL_CR10SPROV2\nPRINTER_HAS_BOWDEN
max_print_height = 400
[printer:Creality CR-10 S4]
inherits = Creality Ender-3
retract_length = 6
bed_shape = 5x5,405x5,405x405,5x405
bed_shape = 5x5,395x5,395x395,5x395
max_print_height = 400
printer_model = CR10S4
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_CREALITY\nPRINTER_MODEL_CR10S4\nPRINTER_HAS_BOWDEN
max_print_height = 400
[printer:Creality CR-10 S5]
inherits = Creality Ender-3
retract_length = 6
bed_shape = 5x5,505x5,505x505,5x505
max_print_height = 500
printer_model = CR10S5
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_CREALITY\nPRINTER_MODEL_CR10S5\nPRINTER_HAS_BOWDEN
max_print_height = 500
[printer:Creality CR-20]
inherits = Creality Ender-3
@ -854,3 +1009,26 @@ inherits = Creality Ender-3; *fastabl*
retract_length = 4
printer_model = CR20PRO
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_CREALITY\nPRINTER_MODEL_CR20PRO\nPRINTER_HAS_BOWDEN
#[printer:Creality CR-8]
#inherits = Creality Ender-3
#bed_shape = 5x5,215x5,215x215,5x215
#max_print_height = 210
#printer_model = CR8
#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_CREALITY\nPRINTER_MODEL_CR8\nPRINTER_HAS_BOWDEN
#[printer:Creality CR-X]
#inherits = Creality Ender-3; *dualextruder*
#retract_length = 6,6
#bed_shape = 5x5,295x5,295x295,5x295
#max_print_height = 400
#printer_model = CRX
#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_CREALITY\nPRINTER_MODEL_CRX\nPRINTER_HAS_BOWDEN
#[printer:Creality CR-X Pro]
#inherits = Creality Ender-3; *dualextruder*; *slowabl*
#retract_length = 6,6
#bed_shape = 5x5,295x5,295x295,5x295
#max_print_height = 400
#printer_model = CRXPRO
#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_CREALITY\nPRINTER_MODEL_CRXPRO\nPRINTER_HAS_BOWDEN

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="440mm" height="440mm" version="1.1" viewBox="0 0 440 440" xmlns="http://www.w3.org/2000/svg">
<rect x=".25" y=".25" width="439.5" height="439.5" fill="none" stroke="#fff" stroke-width=".5"/>
</svg>

After

Width:  |  Height:  |  Size: 251 B

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="400mm" height="400mm" version="1.1" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg">
<rect x=".25" y=".25" width="399.5" height="399.5" fill="none" stroke="#fff" stroke-width=".5"/>
<svg width="390mm" height="390mm" version="1.1" viewBox="0 0 390 390" xmlns="http://www.w3.org/2000/svg">
<rect x=".25" y=".25" width="389.5" height="389.5" fill="none" stroke="#fff" stroke-width=".5"/>
</svg>

Before

Width:  |  Height:  |  Size: 251 B

After

Width:  |  Height:  |  Size: 251 B

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="290mm" height="290mm" version="1.1" viewBox="0 0 290 290" xmlns="http://www.w3.org/2000/svg">
<rect x=".25" y=".25" width="289.5" height="289.5" fill="none" stroke="#fff" stroke-width=".5"/>
</svg>

After

Width:  |  Height:  |  Size: 251 B

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="225mm" height="235mm" version="1.1" viewBox="0 0 225 235" xmlns="http://www.w3.org/2000/svg">
<rect x=".25" y=".25" width="224.5" height="234.5" fill="none" stroke="#fff" stroke-width=".5"/>
</svg>

After

Width:  |  Height:  |  Size: 251 B

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="210mm" height="210mm" version="1.1" viewBox="0 0 210 210" xmlns="http://www.w3.org/2000/svg">
<rect x=".25" y=".25" width="209.5" height="209.5" fill="none" stroke="#fff" stroke-width=".5"/>
</svg>

After

Width:  |  Height:  |  Size: 251 B

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="210mm" height="220mm" version="1.1" viewBox="0 0 210 220" xmlns="http://www.w3.org/2000/svg">
<rect x=".25" y=".25" width="209.5" height="219.5" fill="none" stroke="#fff" stroke-width=".5"/>
</svg>

After

Width:  |  Height:  |  Size: 251 B

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="250mm" height="250mm" version="1.1" viewBox="0 0 250 250" xmlns="http://www.w3.org/2000/svg">
<rect x=".25" y=".25" width="249.5" height="249.5" fill="none" stroke="#fff" stroke-width=".5"/>
</svg>

After

Width:  |  Height:  |  Size: 251 B

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
min_slic3r_version = 2.3.0
0.0.1 Initial version

467
resources/profiles/INAT.ini Normal file
View File

@ -0,0 +1,467 @@
# generated by PrusaSlicer 2.1.1+win64 on 2020-02-25 at 01:51:21 UTC
[vendor]
# Vendor name will be shown by the Config Wizard.
name = INAT s.r.o.
config_version = 0.0.1
config_update_url = http://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/INAT/
###
### PRINTER LIST
###
[printer_model:PROTON_X_RAIL]
name = INAT Proton X Rail
variants = 0.4
technology = FFF
family = Proton
[printer_model:PROTON_X_ROD]
name = INAT Proton X Rod
variants = 0.4
technology = FFF
family = Proton
###
### QUALITY DEFINITIONS
###
[print:*common*]
#layers
layer_height = 0.2
first_layer_height = 0.2
perimeters = 3
spiral_vase = 0
top_solid_layers = 4
bottom_solid_layers = 3
top_solid_min_thickness = 0.8
bottom_solid_min_thickness = 0.6
extra_perimeters = 1
ensure_vertical_shell_thickness = 1
avoid_crossing_perimeters = 0
thin_walls = 0
overhangs = 1
seam_position = aligned
external_perimeters_first = 0
#infill
fill_density = 30%
fill_pattern = cubic
infill_anchor = 600%
infill_anchor_max = 30
top_fill_pattern = monotonic
bottom_fill_patter = monotonic
ironing = 0
ironing_type = top
infill_every_layers = 1
infill_only_where_needed = 0
solid_infill_every_layers = 0
fill_angle = 45
solid_infill_below_area = 20
bridge_angle = 0
only_retract_when_crossing_perimeters = 0
infill_first = 0
#skirt brim
skirts = 5
skirt_distance = 15
skirt_height = 1
draft_shield = 0
min_skirt_length = 5
brim_width = 0
#support
support_material = 0
support_material_auto = 1
support_material_threshold = 0
support_material_enforce_layers = 0
raft_layers = 0
support_material_contact_distance = 0.2
support_material_pattern = rectilinear
support_material_with_sheath = 0
support_material_spacing = 5
support_material_angle = 45
support_material_interface_layers = 3
support_material_interface_spacing = 0
support_material_interface_contact_loops = 0
support_material_buildplate_only = 0
support_material_xy_spacing = 1
dont_support_bridges = 1
#speed
perimeter_speed = 60
small_perimeter_speed = 75%
external_perimeter_speed = 50%
infill_speed = 80
solid_infill_speed = 100%
top_solid_infill_speed = 30
support_material_speed = 80
support_material_interface_speed = 100%
bridge_speed = 60
gap_fill_speed = 40
ironing_speed = 30
travel_speed = 150
first_layer_speed = 30
default_acceleration = 0
max_print_speed = 80
max_volumetric_speed = 12
#multiple extruders
perimeter_extruder = 1
infill_extruder = 1
solid_infill_extruder = 1
support_material_extruder = 1
support_material_interface_extruder = 1
ooze_prevention = 0
wipe_tower = 0
interface_shells = 0
#advanced
extrusion_width = 0
first_layer_extrusion_width = 0
perimeter_extrusion_width = 0
external_perimeter_extrusion_width = 0
infill_extrusion_width = 0
solid_infill_extrusion_width = 0
top_infill_extrusion_width = 0
support_material_extrusion_width = 0
infill_overlap = 25%
bridge_flow_ratio = 1
slice_closing_radius = 0.049
resolution = 0
xy_size_compensation = 0
elefant_foot_compensation = 0.3
clip_multipart_objects = 0
#output
complete_objects = 0
extruder_clearance_radius = 85
extruder_clearance_height = 34
gcode_comments = 0
gcode_label_objects = 0
output_filename_format = {input_filename_base}_{filament_type[0]}_{print_time}.gcode
[print:0.2mm Standard @PROTON_X]
inherits = *common*
[print:0.2mm Strong @PROTON_X]
inherits = *common*
fill_density = 50%
perimeters = 6
[print:0.2mm Advanced Material @PROTON_X]
inherits = *common*
bottom_solid_layers = 5
top_solid_layers = 6
skirts = 0
brim_width = 30
infill_speed = 60
support_material_speed = 60
travel_speed = 100
first_layer_speed = 20
elefant_foot_compensation = 0
[print:0.12mm Fine @PROTON_X]
inherits = *common*
bottom_solid_layers = 7
top_solid_layers = 7
infill_every_layers = 2
perimeter_speed = 50
infill_speed = 50
[print:0.32mm Draft @PROTON_X]
inherits = *common*
perimeter_speed = 80
external_perimeter_speed = 75%
infill_speed = 100
top_solid_infill_speed = 60
fill_density = 15%
###
### PRINTER DEFINITIONS
###
[printer:*common*]
printer_vendor = INAT s.r.o.
default_filament_profile = "PLA @PROTON_X"
#general
printer_technology = FFF
bed_shape = 0x0,304x0,304x304,0x304
max_print_height = 650
z_offset = 0
extruders_count = 1
gcode_flavor = marlin
silent_mode = 0
remaining_times = 1
use_relative_e_distances = 0
use_firmware_retraction = 0
use_volumetric_e = 0
variable_layer_height = 1
#gcodes
start_gcode = G28 ;Home\nG0 Z0.3 F200 ;Move nozzle down\nM192 S50 ; Wait for probe temperature to settle\nG29\nG0 X0 Y0 Z30 F6000\nM84 E\nM0\nG1 Z15.0 F6000 ;Move the platform down 15mm\n;Prime the extruder\nG92 E0\nG1 F200 E3\nG92 E0\n
end_gcode = M400\nM104 S0\nM140 S0\nM107\n;Retract the filament\nG92 E1\nG1 E-1 F300\nG28 X R5\nG0 Y300 F2000\nM84\n
color_change_gcode = M600
#limits
machine_limits_usage = emit_to_gcode
machine_max_feedrate_x = 200,200
machine_max_feedrate_y = 200,200
machine_max_feedrate_z = 10,10
machine_max_feedrate_e = 100,100
machine_max_acceleration_x = 500,500
machine_max_acceleration_y = 500,500
machine_max_acceleration_z = 100,100
machine_max_acceleration_e = 2000,2000
machine_max_acceleration_extruding = 1000,1000
machine_max_acceleration_retracting = 1500,1500
machine_max_jerk_x = 8,8
machine_max_jerk_y = 8,8
machine_max_jerk_z = 1,1
machine_max_jerk_e = 2.5,2.5
machine_min_extruding_rate = 5
#extruder 1
nozzle_diameter = 0.4
min_layer_height = 0.05
max_layer_height = 0.33
extruder_offset = 0x0
retract_length = 1.5
retract_lift = 0.6
retract_lift_above = 0
retract_lift_below = 0
retract_speed = 45
deretract_speed = 0
retract_restart_extra = 0
retract_before_travel = 2
retract_layer_change = 0
wipe = 1
retract_before_wipe = 100%
[printer:Proton X Rail]
inherits = *common*
printer_model = PROTON_X_RAIL
printer_variant = 0.4
default_print_profile = 0.2mm Standard @PROTON_X
gcode_flavor = marlin
machine_max_acceleration_y = 800,800
[printer:Proton X Rod]
inherits = *common*
printer_model = PROTON_X_ROD
printer_variant = 0.4
default_print_profile = 0.2mm Standard @PROTON_X
gcode_flavor = marlin
###
### MATERIAL DEFINITIONS
###
[filament:*common*]
#filament
filament_colour = #29B2B2
filament_diameter = 1.75
extrusion_multiplier = 1
filament_vendor = Generic
#cooling
fan_always_on = 0
cooling = 1
bridge_fan_speed = 100
disable_fan_first_layers = 3
full_fan_speed_layer = 0
fan_below_layer_time = 10
slowdown_below_layer_time = 5
min_print_speed = 10
#advanced
filament_soluble = 0
[filament:PLA @PROTON_X]
inherits = *common*
temperature = 210
bed_temperature = 60
first_layer_temperature = 210
first_layer_bed_temperature = 60
filament_type = PLA
filament_cost = 20
filament_density = 1.25
min_fan_speed = 50
max_fan_speed = 100
[filament:PETG @PROTON_X]
inherits = *common*
temperature = 240
bed_temperature = 80
first_layer_temperature = 240
first_layer_bed_temperature = 80
filament_type = PETG
filament_cost = 25
filament_density = 1.27
min_fan_speed = 0
max_fan_speed = 50
[filament:ABS @PROTON_X]
inherits = *common*
temperature = 235
bed_temperature = 100
first_layer_temperature = 235
first_layer_bed_temperature = 100
filament_type = ABS
filament_cost = 20
filament_density = 1.01
cooling = 0
bridge_fan_speed = 0
[filament:ASA @PROTON_X]
inherits = *common*
temperature = 240
bed_temperature = 110
first_layer_temperature = 240
first_layer_bed_temperature = 110
filament_type = ASA
filament_cost = 22
filament_density = 1.07
cooling = 0
[filament:TPE @PROTON_X]
inherits = *common*
temperature = 220
bed_temperature = 40
first_layer_temperature = 220
first_layer_bed_temperature = 40
filament_type = TPE
filament_cost = 32
filament_density = 0.9
min_fan_speed = 0
max_fan_speed = 50
filament_retract_length = 0.8
filament_retract_speed = 25
[filament:HIPS @PROTON_X]
inherits = *common*
temperature = 245
bed_temperature = 100
first_layer_temperature = 245
first_layer_bed_temperature = 100
filament_type = HIPS
filament_cost = 15
filament_density = 1.04
min_fan_speed = 0
max_fan_speed = 50
filament_soluble = 1
[filament:Nylon @PROTON_X]
inherits = *common*
temperature = 235
bed_temperature = 130
first_layer_temperature = 235
first_layer_bed_temperature = 130
filament_type = Nylon
filament_cost = 70
filament_density = 1.01
cooling = 0
bridge_fan_speed = 0
[filament:PC @PROTON_X]
inherits = *common*
temperature = 270
bed_temperature = 130
first_layer_temperature = 270
first_layer_bed_temperature = 130
filament_type = PC
filament_cost = 65
filament_density = 1.19
cooling = 0
bridge_fan_speed = 0
[filament:CPE @PROTON_X]
inherits = *common*
temperature = 280
bed_temperature = 90
first_layer_temperature = 280
first_layer_bed_temperature = 90
filament_type = PEI
filament_cost = 380
filament_density = 1.27
cooling = 0
bridge_fan_speed = 0
[filament:PEEK @PROTON_X]
inherits = *common*
temperature = 440
bed_temperature = 150
first_layer_temperature = 440
first_layer_bed_temperature = 150
filament_type = PEEK
filament_cost = 500
filament_density = 1.3
cooling = 0
bridge_fan_speed = 0
[filament:PEI @PROTON_X]
inherits = *common*
temperature = 400
bed_temperature = 150
first_layer_temperature = 400
first_layer_bed_temperature = 150
filament_type = PEI
filament_cost = 380
filament_density = 1.27
cooling = 0
bridge_fan_speed = 0
[filament:Polymaker PolyMide CoPA @PROTON_X]
inherits = *common*
filament_vendor = Polymaker
temperature = 265
bed_temperature = 50
first_layer_temperature = 265
first_layer_bed_temperature = 50
filament_type = Nylon
filament_cost = 93
filament_density = 1.12
cooling = 0
[filament:Polymaker PolyMide PA6-CF @PROTON_X]
inherits = *common*
filament_vendor = Polymaker
temperature = 300
bed_temperature = 40
first_layer_temperature = 300
first_layer_bed_temperature = 40
filament_type = Nylon
filament_cost = 95
filament_density = 1.17
cooling = 0
[filament:Polymaker PolyMide PA6-GF @PROTON_X]
inherits = *common*
filament_vendor = Polymaker
temperature = 300
bed_temperature = 40
first_layer_temperature = 300
first_layer_bed_temperature = 40
filament_type = Nylon
filament_cost = 95
filament_density = 1.2
cooling = 0
[filament:Devil Design PETG @PROTON_X]
inherits = *common*
filament_vendor = Devil Design
temperature = 250
bed_temperature = 80
first_layer_temperature = 250
first_layer_bed_temperature = 80
filament_type = PETG
filament_cost = 22
filament_density = 1.23
min_fan_speed = 0
max_fan_speed = 50
[filament:Filament PM PETG FRJet @PROTON_X]
inherits = *common*
filament_vendor = Filament PM
temperature = 250
bed_temperature = 90
first_layer_temperature = 250
first_layer_bed_temperature = 90
filament_type = PETG
filament_cost = 45.5
filament_density = 1.27
cooling = 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -1,4 +1,6 @@
min_slic3r_version = 2.3.0-rc1
1.2.4 Updated cost/density values in filament settings. Various changes in print settings.
1.2.3 Updated firmware version. Updated end g-code in MMU2 printer profiles.
1.2.2 Added Prusament PVB filament profile. Added 0.8mm nozzle profiles.
1.2.1 Updated FW version for MK2.5 family printers.
1.2.0 Added full_fan_speed_layer value for PETG. Increased support interface spacing for 0.6mm nozzle profiles. Updated firmware version.
@ -10,6 +12,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.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.
1.1.10 Updated firmware version.
@ -32,6 +35,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.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.
1.0.8 Various changes in FFF profiles, new filaments/materials added. See changelog.
@ -50,6 +54,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.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.
0.8.7 Updated firmware version

File diff suppressed because it is too large Load Diff

View File

@ -32,22 +32,22 @@ varying vec3 delta_box_max;
varying float world_normal_z;
varying vec3 eye_normal;
vec3 slope_color()
{
return (world_normal_z > slope.normal_z - EPSILON) ? GREEN : RED;
}
void main()
{
if (any(lessThan(clipping_planes_dots, ZERO)))
discard;
vec3 color = slope.actived ? slope_color() : uniform_color.rgb;
vec3 color = uniform_color.rgb;
float alpha = uniform_color.a;
if (slope.actived && world_normal_z < slope.normal_z - EPSILON) {
color = vec3(0.7, 0.7, 1.0);
alpha = 1.0;
}
// if the fragment is outside the print volume -> use darker color
color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? mix(color, ZERO, 0.3333) : color;
#ifdef ENABLE_ENVIRONMENT_MAP
if (use_environment_tex)
gl_FragColor = vec4(0.45 * texture2D(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, uniform_color.a);
gl_FragColor = vec4(0.45 * texture2D(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, alpha);
else
#endif
gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, uniform_color.a);
gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha);
}

View File

@ -9,8 +9,6 @@ add_subdirectory(boost)
add_subdirectory(clipper)
add_subdirectory(miniz)
add_subdirectory(glu-libtess)
add_subdirectory(polypartition)
add_subdirectory(poly2tri)
add_subdirectory(qhull)
add_subdirectory(Shiny)
add_subdirectory(semver)

View File

@ -402,7 +402,8 @@ int CLI::run(int argc, char **argv)
for (Model &model : m_models) {
size_t num_objects = model.objects.size();
for (size_t i = 0; i < num_objects; ++ i) {
model.objects.front()->split(nullptr);
ModelObjectPtrs new_objects;
model.objects.front()->split(&new_objects);
model.delete_object(size_t(0));
}
}

View File

@ -532,7 +532,7 @@ void stl_remove_unconnected_facets(stl_file *stl)
assert(false);
}
if (facet_number < -- stl->stats.number_of_facets) {
if (facet_number < int(-- stl->stats.number_of_facets)) {
// Removing a face, which was not the last one.
// Copy the face and neighborship from the last face to facet_number.
stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets];

View File

@ -133,16 +133,16 @@ void stl_fix_normal_directions(stl_file *stl)
// Initialize list that keeps track of already fixed facets.
std::vector<char> norm_sw(stl->stats.number_of_facets, 0);
// Initialize list that keeps track of reversed facets.
std::vector<int> reversed_ids(stl->stats.number_of_facets, 0);
std::vector<int> reversed_ids;
reversed_ids.reserve(stl->stats.number_of_facets);
int facet_num = 0;
int reversed_count = 0;
// If normal vector is not within tolerance and backwards:
// Arbitrarily starts at face 0. If this one is wrong, we're screwed. Thankfully, the chances
// of it being wrong randomly are low if most of the triangles are right:
if (check_normal_vector(stl, 0, 0)) {
reverse_facet(stl, 0);
reversed_ids[reversed_count ++] = 0;
reversed_ids.emplace_back(0);
}
// Say that we've fixed this facet:
@ -159,13 +159,13 @@ void stl_fix_normal_directions(stl_file *stl)
if (stl->neighbors_start[facet_num].neighbor[j] != -1) {
if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] == 1) {
// trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206)
for (int id = reversed_count - 1; id >= 0; -- id)
for (int id = int(reversed_ids.size()) - 1; id >= 0; -- id)
reverse_facet(stl, reversed_ids[id]);
force_exit = true;
break;
}
reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]);
reversed_ids[reversed_count ++] = stl->neighbors_start[facet_num].neighbor[j];
reversed_ids.emplace_back(stl->neighbors_start[facet_num].neighbor[j]);
}
}
// If this edge of the facet is connected:
@ -188,6 +188,7 @@ void stl_fix_normal_directions(stl_file *stl)
// Get next facet to fix from top of list.
if (head->next != tail) {
facet_num = head->next->facet_num;
assert(facet_num < stl->stats.number_of_facets);
if (norm_sw[facet_num] != 1) { // If facet is in list mutiple times
norm_sw[facet_num] = 1; // Record this one as being fixed.
++ checked;
@ -197,7 +198,7 @@ void stl_fix_normal_directions(stl_file *stl)
// pool.destroy(temp);
} else { // If we ran out of facets to fix: All of the facets in this part have been fixed.
++ stl->stats.number_of_parts;
if (checked >= stl->stats.number_of_facets)
if (checked >= int(stl->stats.number_of_facets))
// All of the facets have been checked. Bail out.
break;
// There is another part here. Find it and continue.
@ -207,7 +208,7 @@ void stl_fix_normal_directions(stl_file *stl)
facet_num = i;
if (check_normal_vector(stl, i, 0)) {
reverse_facet(stl, i);
reversed_ids[reversed_count++] = i;
reversed_ids.emplace_back(i);
}
norm_sw[facet_num] = 1;
++ checked;

View File

@ -70,7 +70,7 @@ void stl_translate(stl_file *stl, float x, float y, float z)
{
stl_vertex new_min(x, y, z);
stl_vertex shift = new_min - stl->stats.min;
for (int i = 0; i < stl->stats.number_of_facets; ++ i)
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
for (int j = 0; j < 3; ++ j)
stl->facet_start[i].vertex[j] += shift;
stl->stats.min = new_min;
@ -81,7 +81,7 @@ void stl_translate(stl_file *stl, float x, float y, float z)
void stl_translate_relative(stl_file *stl, float x, float y, float z)
{
stl_vertex shift(x, y, z);
for (int i = 0; i < stl->stats.number_of_facets; ++ i)
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
for (int j = 0; j < 3; ++ j)
stl->facet_start[i].vertex[j] += shift;
stl->stats.min += shift;
@ -100,7 +100,7 @@ void stl_scale_versor(stl_file *stl, const stl_vertex &versor)
if (stl->stats.volume > 0.0)
stl->stats.volume *= versor(0) * versor(1) * versor(2);
// Scale the mesh.
for (int i = 0; i < stl->stats.number_of_facets; ++ i)
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
for (int j = 0; j < 3; ++ j)
stl->facet_start[i].vertex[j].array() *= s;
}
@ -330,10 +330,10 @@ void stl_repair(
increment = stl->stats.bounding_diameter / 10000.0;
}
if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
if (stl->stats.connected_facets_3_edge < int(stl->stats.number_of_facets)) {
int last_edges_fixed = 0;
for (int i = 0; i < iterations; ++ i) {
if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
if (stl->stats.connected_facets_3_edge < int(stl->stats.number_of_facets)) {
if (verbose_flag)
printf("Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance, i + 1, iterations);
stl_check_facets_nearby(stl, tolerance);
@ -351,7 +351,7 @@ void stl_repair(
printf("All facets connected. No nearby check necessary.\n");
if (remove_unconnected_flag || fixall_flag || fill_holes_flag) {
if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
if (stl->stats.connected_facets_3_edge < int(stl->stats.number_of_facets)) {
if (verbose_flag)
printf("Removing unconnected facets...\n");
stl_remove_unconnected_facets(stl);
@ -360,7 +360,7 @@ void stl_repair(
}
if (fill_holes_flag || fixall_flag) {
if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
if (stl->stats.connected_facets_3_edge < int(stl->stats.number_of_facets)) {
if (verbose_flag)
printf("Filling holes...\n");
stl_fill_holes(stl);

View File

@ -1,6 +1,11 @@
option(SLIC3R_ENC_CHECK "Verify encoding of source files" 1)
if (IS_CROSS_COMPILE)
# Force disable due to cross compilation. This fact is already printed on cli for users
set(SLIC3R_ENC_CHECK OFF CACHE BOOL "" FORCE)
endif ()
if (SLIC3R_ENC_CHECK)
add_executable(encoding-check encoding-check.cpp)

View File

@ -3895,10 +3895,10 @@ double DistanceFromLineSqrd(
const IntPoint& pt, const IntPoint& ln1, const IntPoint& ln2)
{
//The equation of a line in general form (Ax + By + C = 0)
//given 2 points (x¹,y¹) & (x²,y²) is ...
//(y¹ - y²)x + (x² - x¹)y + (y² - y¹)x¹ - (x² - x¹)y¹ = 0
//A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹
//perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²)
//given 2 points (x¹,y¹) & (x²,y²) is ...
//(y¹ - y²)x + (x² - x¹)y + (y² - y¹)x¹ - (x² - x¹)y¹ = 0
//A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹
//perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²)
//see http://en.wikipedia.org/wiki/Perpendicular_distance
double A = double(ln1.Y - ln2.Y);
double B = double(ln2.X - ln1.X);

View File

@ -836,7 +836,7 @@ public:
inline ItemIteratorOnly<It, size_t> execute(It from, It to)
{
auto infl = static_cast<Coord>(std::ceil(min_obj_distance_/2.0));
if(infl > 0) std::for_each(from, to, [this, infl](Item& item) {
if(infl > 0) std::for_each(from, to, [infl](Item& item) {
item.inflate(infl);
});

View File

@ -653,8 +653,8 @@ inline bool intersect_ray_all_hits(
std::vector<igl::Hit> &hits)
{
auto ray_intersector = detail::RayIntersectorHits<VertexType, IndexedFaceType, TreeType, VectorType> {
vertices, faces, tree,
origin, dir, VectorType(dir.cwiseInverse())
{ vertices, faces, {tree},
origin, dir, VectorType(dir.cwiseInverse()) }
};
if (! tree.empty()) {
ray_intersector.hits.reserve(8);

View File

@ -123,6 +123,9 @@ void AppConfig::set_defaults()
if (get("default_action_on_select_preset").empty())
set("default_action_on_select_preset", "none"); // , "transfer", "discard" or "save"
if (get("color_mapinulation_panel").empty())
set("color_mapinulation_panel", "0");
}
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
else {
@ -136,6 +139,11 @@ void AppConfig::set_defaults()
if (get("seq_top_layer_only").empty())
set("seq_top_layer_only", "1");
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
if (get("seq_top_gcode_indices").empty())
set("seq_top_gcode_indices", "1");
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
if (get("use_perspective_camera").empty())
set("use_perspective_camera", "1");
@ -266,14 +274,14 @@ void AppConfig::save()
else
c << "# " << Slic3r::header_gcodeviewer_generated() << std::endl;
// Make sure the "no" category is written first.
for (const std::pair<std::string, std::string> &kvp : m_storage[""])
for (const auto& kvp : m_storage[""])
c << kvp.first << " = " << kvp.second << std::endl;
// Write the other categories.
for (const auto category : m_storage) {
for (const auto& category : m_storage) {
if (category.first.empty())
continue;
c << std::endl << "[" << category.first << "]" << std::endl;
for (const std::pair<std::string, std::string> &kvp : category.second)
for (const auto& kvp : category.second)
c << kvp.first << " = " << kvp.second << std::endl;
}
// Write vendor sections
@ -395,7 +403,7 @@ std::vector<std::string> AppConfig::get_mouse_device_names() const
static constexpr const char *prefix = "mouse_device:";
static const size_t prefix_len = strlen(prefix);
std::vector<std::string> out;
for (const std::pair<std::string, std::map<std::string, std::string>>& key_value_pair : m_storage)
for (const auto& key_value_pair : m_storage)
if (boost::starts_with(key_value_pair.first, prefix) && key_value_pair.first.size() > prefix_len)
out.emplace_back(key_value_pair.first.substr(prefix_len));
return out;

View File

@ -207,6 +207,62 @@ std::vector<double> BridgeDetector::bridge_direction_candidates() const
return angles;
}
/*
static void get_trapezoids(const ExPolygon &expoly, Polygons* polygons) const
{
ExPolygons expp;
expp.push_back(expoly);
boost::polygon::get_trapezoids(*polygons, expp);
}
void ExPolygon::get_trapezoids(ExPolygon clone, Polygons* polygons, double angle) const
{
clone.rotate(PI/2 - angle, Point(0,0));
clone.get_trapezoids(polygons);
for (Polygons::iterator polygon = polygons->begin(); polygon != polygons->end(); ++polygon)
polygon->rotate(-(PI/2 - angle), Point(0,0));
}
*/
// This algorithm may return more trapezoids than necessary
// (i.e. it may break a single trapezoid in several because
// other parts of the object have x coordinates in the middle)
static void get_trapezoids2(const ExPolygon &expoly, Polygons* polygons)
{
Polygons src_polygons = to_polygons(expoly);
// get all points of this ExPolygon
const Points pp = to_points(src_polygons);
// build our bounding box
BoundingBox bb(pp);
// get all x coordinates
std::vector<coord_t> xx;
xx.reserve(pp.size());
for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p)
xx.push_back(p->x());
std::sort(xx.begin(), xx.end());
// find trapezoids by looping from first to next-to-last coordinate
for (std::vector<coord_t>::const_iterator x = xx.begin(); x != xx.end()-1; ++x) {
coord_t next_x = *(x + 1);
if (*x != next_x)
// intersect with rectangle
// append results to return value
polygons_append(*polygons, intersection({ { { *x, bb.min.y() }, { next_x, bb.min.y() }, { next_x, bb.max.y() }, { *x, bb.max.y() } } }, src_polygons));
}
}
static void get_trapezoids2(const ExPolygon &expoly, Polygons* polygons, double angle)
{
ExPolygon clone = expoly;
clone.rotate(PI/2 - angle, Point(0,0));
get_trapezoids2(clone, polygons);
for (Polygon &polygon : *polygons)
polygon.rotate(-(PI/2 - angle), Point(0,0));
}
// Coverage is currently only used by the unit tests. It is extremely slow and unreliable!
Polygons BridgeDetector::coverage(double angle) const
{
if (angle == -1)
@ -228,7 +284,7 @@ Polygons BridgeDetector::coverage(double angle) const
for (ExPolygon &expoly : offset_ex(expolygon, 0.5f * float(this->spacing))) {
// Compute trapezoids according to a vertical orientation
Polygons trapezoids;
expoly.get_trapezoids2(&trapezoids, PI/2.0);
get_trapezoids2(expoly, &trapezoids, PI/2.0);
for (const Polygon &trapezoid : trapezoids) {
// not nice, we need a more robust non-numeric check
size_t n_supported = 0;

View File

@ -32,6 +32,7 @@ public:
BridgeDetector(const ExPolygons &_expolygons, const ExPolygons &_lower_slices, coord_t _extrusion_width);
// If bridge_direction_override != 0, then the angle is used instead of auto-detect.
bool detect_angle(double bridge_direction_override = 0.);
// Coverage is currently only used by the unit tests. It is extremely slow and unreliable!
Polygons coverage(double angle = -1) const;
void unsupported_edges(double angle, Polylines* unsupported) const;
Polylines unsupported_edges(double angle = -1) const;

532
src/libslic3r/Brim.cpp Normal file
View File

@ -0,0 +1,532 @@
#include "clipper/clipper_z.hpp"
#include "ClipperUtils.hpp"
#include "EdgeGrid.hpp"
#include "Layer.hpp"
#include "Print.hpp"
#include "ShortestPath.hpp"
#include "libslic3r.h"
#include <algorithm>
#include <numeric>
#include <unordered_set>
#include <tbb/parallel_for.h>
#ifndef NDEBUG
// #define BRIM_DEBUG_TO_SVG
#endif
namespace Slic3r {
static void append_and_translate(ExPolygons &dst, const ExPolygons &src, const PrintInstance &instance) {
size_t dst_idx = dst.size();
expolygons_append(dst, src);
for (; dst_idx < dst.size(); ++dst_idx)
dst[dst_idx].translate(instance.shift.x(), instance.shift.y());
}
static void append_and_translate(Polygons &dst, const Polygons &src, const PrintInstance &instance) {
size_t dst_idx = dst.size();
polygons_append(dst, src);
for (; dst_idx < dst.size(); ++dst_idx)
dst[dst_idx].translate(instance.shift.x(), instance.shift.y());
}
static float max_brim_width(const ConstPrintObjectPtrsAdaptor &objects)
{
assert(!objects.empty());
return float(std::accumulate(objects.begin(), objects.end(), 0.,
[](double partial_result, const PrintObject *object) {
return std::max(partial_result, object->config().brim_type == btNoBrim ? 0. : object->config().brim_width.value);
}));
}
static ConstPrintObjectPtrs get_top_level_objects_with_brim(const Print &print)
{
Polygons islands;
ConstPrintObjectPtrs island_to_object;
for (const PrintObject *object : print.objects()) {
Polygons islands_object;
islands_object.reserve(object->layers().front()->lslices.size());
for (const ExPolygon &ex_poly : object->layers().front()->lslices)
islands_object.emplace_back(ex_poly.contour);
islands.reserve(islands.size() + object->instances().size() * islands_object.size());
for (const PrintInstance &instance : object->instances())
for (Polygon &poly : islands_object) {
islands.emplace_back(poly);
islands.back().translate(instance.shift);
island_to_object.emplace_back(object);
}
}
assert(islands.size() == island_to_object.size());
ClipperLib_Z::Paths islands_clip;
islands_clip.reserve(islands.size());
for (const Polygon &poly : islands) {
islands_clip.emplace_back();
ClipperLib_Z::Path &island_clip = islands_clip.back();
island_clip.reserve(poly.points.size());
int island_idx = int(&poly - &islands.front());
// The Z coordinate carries index of the island used to get the pointer to the object.
for (const Point &pt : poly.points)
island_clip.emplace_back(pt.x(), pt.y(), island_idx + 1);
}
// Init Clipper
ClipperLib_Z::Clipper clipper;
// Assign the maximum Z from four points. This values is valid index of the island
clipper.ZFillFunction([](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top, const ClipperLib_Z::IntPoint &e2bot,
const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt) {
pt.Z = std::max(std::max(e1bot.Z, e1top.Z), std::max(e2bot.Z, e2top.Z));
});
// Add islands
clipper.AddPaths(islands_clip, ClipperLib_Z::ptSubject, true);
// Execute union operation to construct polytree
ClipperLib_Z::PolyTree islands_polytree;
clipper.Execute(ClipperLib_Z::ctUnion, islands_polytree, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd);
std::unordered_set<size_t> processed_objects_idx;
ConstPrintObjectPtrs top_level_objects_with_brim;
for (int i = 0; i < islands_polytree.ChildCount(); ++i) {
for (const ClipperLib_Z::IntPoint &point : islands_polytree.Childs[i]->Contour) {
if (point.Z != 0 && processed_objects_idx.find(island_to_object[point.Z - 1]->id().id) == processed_objects_idx.end()) {
top_level_objects_with_brim.emplace_back(island_to_object[point.Z - 1]);
processed_objects_idx.insert(island_to_object[point.Z - 1]->id().id);
}
}
}
return top_level_objects_with_brim;
}
static Polygons top_level_outer_brim_islands(const ConstPrintObjectPtrs &top_level_objects_with_brim)
{
Polygons islands;
for (const PrintObject *object : top_level_objects_with_brim) {
//FIXME how about the brim type?
float brim_offset = float(scale_(object->config().brim_offset.value));
Polygons islands_object;
for (const ExPolygon &ex_poly : object->layers().front()->lslices) {
Polygons contour_offset = offset(ex_poly.contour, brim_offset);
for (Polygon &poly : contour_offset)
poly.douglas_peucker(SCALED_RESOLUTION);
polygons_append(islands_object, std::move(contour_offset));
}
for (const PrintInstance &instance : object->instances())
append_and_translate(islands, islands_object, instance);
}
return islands;
}
static ExPolygons top_level_outer_brim_area(const Print &print, const ConstPrintObjectPtrs &top_level_objects_with_brim, const float no_brim_offset)
{
std::unordered_set<size_t> top_level_objects_idx;
top_level_objects_idx.reserve(top_level_objects_with_brim.size());
for (const PrintObject *object : top_level_objects_with_brim)
top_level_objects_idx.insert(object->id().id);
ExPolygons brim_area;
Polygons 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();
ExPolygons brim_area_object;
Polygons no_brim_area_object;
for (const ExPolygon &ex_poly : object->layers().front()->lslices) {
if ((brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner) && is_top_outer_brim)
append(brim_area_object, diff_ex(offset_ex(ex_poly.contour, brim_width + brim_offset), offset_ex(ex_poly.contour, brim_offset)));
if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim)
append(no_brim_area_object, offset(ex_poly.holes, -no_brim_offset));
if (brim_type != BrimType::btNoBrim)
append(no_brim_area_object, offset(ex_poly.contour, brim_offset));
no_brim_area_object.emplace_back(ex_poly.contour);
}
for (const PrintInstance &instance : object->instances()) {
append_and_translate(brim_area, brim_area_object, instance);
append_and_translate(no_brim_area, no_brim_area_object, instance);
}
}
return diff_ex(to_polygons(std::move(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)
{
std::unordered_set<size_t> top_level_objects_idx;
top_level_objects_idx.reserve(top_level_objects_with_brim.size());
for (const PrintObject *object : top_level_objects_with_brim)
top_level_objects_idx.insert(object->id().id);
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();
ExPolygons brim_area_object;
ExPolygons no_brim_area_object;
Polygons holes_object;
for (const ExPolygon &ex_poly : object->layers().front()->lslices) {
if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner) {
if (top_outer_brim)
no_brim_area_object.emplace_back(ex_poly);
else
append(brim_area_object, diff_ex(offset_ex(ex_poly.contour, brim_width + brim_offset), offset_ex(ex_poly.contour, brim_offset)));
}
if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btOuterAndInner)
append(brim_area_object, diff_ex(offset_ex(ex_poly.holes, -brim_offset), offset_ex(ex_poly.holes, -brim_width - brim_offset)));
if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btNoBrim)
append(no_brim_area_object, offset_ex(ex_poly.contour, no_brim_offset));
if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim)
append(no_brim_area_object, offset_ex(ex_poly.holes, -no_brim_offset));
append(holes_object, ex_poly.holes);
}
append(no_brim_area_object, offset_ex(object->layers().front()->lslices, brim_offset));
for (const PrintInstance &instance : object->instances()) {
append_and_translate(brim_area, brim_area_object, instance);
append_and_translate(no_brim_area, no_brim_area_object, instance);
append_and_translate(holes, holes_object, instance);
}
}
return diff_ex(intersection_ex(to_polygons(std::move(brim_area)), holes), no_brim_area);
}
// Flip orientation of open polylines to minimize travel distance.
static void optimize_polylines_by_reversing(Polylines *polylines)
{
for (size_t poly_idx = 1; poly_idx < polylines->size(); ++poly_idx) {
const Polyline &prev = (*polylines)[poly_idx - 1];
Polyline & next = (*polylines)[poly_idx];
if (!next.is_closed()) {
double dist_to_start = (next.first_point() - prev.last_point()).cast<double>().norm();
double dist_to_end = (next.last_point() - prev.last_point()).cast<double>().norm();
if (dist_to_end < dist_to_start)
next.reverse();
}
}
}
static Polylines connect_brim_lines(Polylines &&polylines, const Polygons &brim_area, float max_connection_length)
{
if (polylines.empty())
return Polylines();
BoundingBox bbox = get_extents(polylines);
bbox.merge(get_extents(brim_area));
EdgeGrid::Grid grid(bbox.inflated(SCALED_EPSILON));
grid.create(brim_area, polylines, coord_t(scale_(10.)));
struct Visitor
{
explicit Visitor(const EdgeGrid::Grid &grid) : grid(grid) {}
bool operator()(coord_t iy, coord_t ix)
{
// Called with a row and colum of the grid cell, which is intersected by a line.
auto cell_data_range = grid.cell_data_range(iy, ix);
this->intersect = false;
for (auto it_contour_and_segment = cell_data_range.first; it_contour_and_segment != cell_data_range.second; ++it_contour_and_segment) {
// End points of the line segment and their vector.
auto segment = grid.segment(*it_contour_and_segment);
if (Geometry::segments_intersect(segment.first, segment.second, brim_line.a, brim_line.b)) {
this->intersect = true;
return false;
}
}
// Continue traversing the grid along the edge.
return true;
}
const EdgeGrid::Grid &grid;
Line brim_line;
bool intersect;
} visitor(grid);
// Connect successive polylines if they are open, their ends are closer than max_connection_length.
// Remove empty polylines.
{
// Skip initial empty lines.
size_t poly_idx = 0;
for (; poly_idx < polylines.size() && polylines[poly_idx].empty(); ++ poly_idx) ;
size_t end = ++ poly_idx;
double max_connection_length2 = Slic3r::sqr(max_connection_length);
for (; poly_idx < polylines.size(); ++poly_idx) {
Polyline &next = polylines[poly_idx];
if (! next.empty()) {
Polyline &prev = polylines[end - 1];
bool connect = false;
if (! prev.is_closed() && ! next.is_closed()) {
double dist2 = (prev.last_point() - next.first_point()).cast<double>().squaredNorm();
if (dist2 <= max_connection_length2) {
visitor.brim_line.a = prev.last_point();
visitor.brim_line.b = next.first_point();
// Shrink the connection line to avoid collisions with the brim centerlines.
visitor.brim_line.extend(-SCALED_EPSILON);
grid.visit_cells_intersecting_line(visitor.brim_line.a, visitor.brim_line.b, visitor);
connect = ! visitor.intersect;
}
}
if (connect) {
append(prev.points, std::move(next.points));
} else {
if (end < poly_idx)
polylines[end] = std::move(next);
++ end;
}
}
}
if (end < polylines.size())
polylines.erase(polylines.begin() + end, polylines.end());
}
return std::move(polylines);
}
static void make_inner_brim(const Print &print, const ConstPrintObjectPtrs &top_level_objects_with_brim, ExtrusionEntityCollection &brim)
{
Flow flow = print.brim_flow();
ExPolygons islands_ex = inner_brim_area(print, top_level_objects_with_brim, 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) {
for (ExPolygon &poly_ex : islands_ex)
poly_ex.douglas_peucker(SCALED_RESOLUTION);
polygons_append(loops, to_polygons(islands_ex));
islands_ex = offset_ex(islands_ex, -float(flow.scaled_spacing()), jtSquare);
}
loops = union_pt_chained_outside_in(loops, false);
std::reverse(loops.begin(), loops.end());
extrusion_entities_append_loops(brim.entities, std::move(loops), erSkirt, float(flow.mm3_per_mm()),
float(flow.width), float(print.skirt_first_layer_height()));
}
// Produce brim lines around those objects, that have the brim enabled.
// 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, 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()));
for (size_t i = 0; i < num_loops; ++i) {
try_cancel();
islands = offset(islands, float(flow.scaled_spacing()), jtSquare);
for (Polygon &poly : islands)
poly.douglas_peucker(SCALED_RESOLUTION);
polygons_append(loops, offset(islands, -0.5f * float(flow.scaled_spacing())));
}
loops = union_pt_chained_outside_in(loops, false);
std::vector<Polylines> loops_pl_by_levels;
{
Polylines loops_pl = to_polylines(loops);
loops_pl_by_levels.assign(loops_pl.size(), Polylines());
tbb::parallel_for(tbb::blocked_range<size_t>(0, loops_pl.size()),
[&loops_pl_by_levels, &loops_pl, &islands_area](const tbb::blocked_range<size_t> &range) {
for (size_t i = range.begin(); i < range.end(); ++i) {
loops_pl_by_levels[i] = chain_polylines(intersection_pl({ std::move(loops_pl[i]) }, islands_area));
}
});
}
// output
ExtrusionEntityCollection brim;
// Reduce down to the ordered list of polylines.
Polylines all_loops;
for (Polylines &polylines : loops_pl_by_levels)
append(all_loops, std::move(polylines));
loops_pl_by_levels.clear();
// Flip orientation of open polylines to minimize travel distance.
optimize_polylines_by_reversing(&all_loops);
#ifdef BRIM_DEBUG_TO_SVG
static int irun = 0;
++ irun;
{
SVG svg(debug_out_path("brim-%d.svg", irun).c_str(), get_extents(all_loops));
svg.draw(union_ex(islands), "blue");
svg.draw(islands_area_ex, "green");
svg.draw(all_loops, "black", coord_t(scale_(0.1)));
}
#endif // BRIM_DEBUG_TO_SVG
all_loops = connect_brim_lines(std::move(all_loops), offset(islands_area_ex, float(SCALED_EPSILON)), flow.scaled_spacing() * 2.f);
#ifdef BRIM_DEBUG_TO_SVG
{
SVG svg(debug_out_path("brim-connected-%d.svg", irun).c_str(), get_extents(all_loops));
svg.draw(union_ex(islands), "blue");
svg.draw(islands_area_ex, "green");
svg.draw(all_loops, "black", coord_t(scale_(0.1)));
}
#endif // BRIM_DEBUG_TO_SVG
const bool could_brim_intersects_skirt = std::any_of(print.objects().begin(), print.objects().end(), [&print](PrintObject *object) {
const BrimType &bt = object->config().brim_type;
return (bt == btOuterOnly || bt == btOuterAndInner) && print.config().skirt_distance.value < object->config().brim_width;
});
// If there is a possibility that brim intersects skirt, go through loops and split those extrusions
// The result is either the original Polygon or a list of Polylines
if (! print.skirt().empty() && could_brim_intersects_skirt)
{
// Find the bounding polygons of the skirt
const Polygons skirt_inners = offset(dynamic_cast<ExtrusionLoop*>(print.skirt().entities.back())->polygon(),
-float(scale_(print.skirt_flow().spacing()))/2.f,
ClipperLib::jtRound,
float(scale_(0.1)));
const Polygons skirt_outers = offset(dynamic_cast<ExtrusionLoop*>(print.skirt().entities.front())->polygon(),
float(scale_(print.skirt_flow().spacing()))/2.f,
ClipperLib::jtRound,
float(scale_(0.1)));
// First calculate the trimming region.
ClipperLib_Z::Paths trimming;
{
ClipperLib_Z::Paths input_subject;
ClipperLib_Z::Paths input_clip;
for (const Polygon &poly : skirt_outers) {
input_subject.emplace_back();
ClipperLib_Z::Path &out = input_subject.back();
out.reserve(poly.points.size());
for (const Point &pt : poly.points)
out.emplace_back(pt.x(), pt.y(), 0);
}
for (const Polygon &poly : skirt_inners) {
input_clip.emplace_back();
ClipperLib_Z::Path &out = input_clip.back();
out.reserve(poly.points.size());
for (const Point &pt : poly.points)
out.emplace_back(pt.x(), pt.y(), 0);
}
// init Clipper
ClipperLib_Z::Clipper clipper;
// add polygons
clipper.AddPaths(input_subject, ClipperLib_Z::ptSubject, true);
clipper.AddPaths(input_clip, ClipperLib_Z::ptClip, true);
// perform operation
clipper.Execute(ClipperLib_Z::ctDifference, trimming, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd);
}
// Second, trim the extrusion loops with the trimming regions.
ClipperLib_Z::Paths loops_trimmed;
{
// Produce ClipperLib_Z::Paths from polylines (not necessarily closed).
ClipperLib_Z::Paths input_clip;
for (const Polyline &loop_pl : all_loops) {
input_clip.emplace_back();
ClipperLib_Z::Path& out = input_clip.back();
out.reserve(loop_pl.points.size());
int64_t loop_idx = &loop_pl - &all_loops.front();
for (const Point& pt : loop_pl.points)
// The Z coordinate carries index of the source loop.
out.emplace_back(pt.x(), pt.y(), loop_idx + 1);
}
// init Clipper
ClipperLib_Z::Clipper clipper;
clipper.ZFillFunction([](const ClipperLib_Z::IntPoint& e1bot, const ClipperLib_Z::IntPoint& e1top, const ClipperLib_Z::IntPoint& e2bot, const ClipperLib_Z::IntPoint& e2top, ClipperLib_Z::IntPoint& pt) {
// Assign a valid input loop identifier. Such an identifier is strictly positive, the next line is safe even in case one side of a segment
// hat the Z coordinate not set to the contour coordinate.
pt.Z = std::max(std::max(e1bot.Z, e1top.Z), std::max(e2bot.Z, e2top.Z));
});
// add polygons
clipper.AddPaths(input_clip, ClipperLib_Z::ptSubject, false);
clipper.AddPaths(trimming, ClipperLib_Z::ptClip, true);
// perform operation
ClipperLib_Z::PolyTree loops_trimmed_tree;
clipper.Execute(ClipperLib_Z::ctDifference, loops_trimmed_tree, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd);
ClipperLib_Z::PolyTreeToPaths(loops_trimmed_tree, loops_trimmed);
}
// Third, produce the extrusions, sorted by the source loop indices.
{
std::vector<std::pair<const ClipperLib_Z::Path*, size_t>> loops_trimmed_order;
loops_trimmed_order.reserve(loops_trimmed.size());
for (const ClipperLib_Z::Path &path : loops_trimmed) {
size_t input_idx = 0;
for (const ClipperLib_Z::IntPoint &pt : path)
if (pt.Z > 0) {
input_idx = (size_t)pt.Z;
break;
}
assert(input_idx != 0);
loops_trimmed_order.emplace_back(&path, input_idx);
}
std::stable_sort(loops_trimmed_order.begin(), loops_trimmed_order.end(),
[](const std::pair<const ClipperLib_Z::Path*, size_t> &l, const std::pair<const ClipperLib_Z::Path*, size_t> &r) {
return l.second < r.second;
});
Point last_pt(0, 0);
for (size_t i = 0; i < loops_trimmed_order.size();) {
// Find all pieces that the initial loop was split into.
size_t j = i + 1;
for (; j < loops_trimmed_order.size() && loops_trimmed_order[i].second == loops_trimmed_order[j].second; ++ j) ;
const ClipperLib_Z::Path &first_path = *loops_trimmed_order[i].first;
if (i + 1 == j && first_path.size() > 3 && first_path.front().X == first_path.back().X && first_path.front().Y == first_path.back().Y) {
auto *loop = new ExtrusionLoop();
brim.entities.emplace_back(loop);
loop->paths.emplace_back(erSkirt, float(flow.mm3_per_mm()), float(flow.width), float(print.skirt_first_layer_height()));
Points &points = loop->paths.front().polyline.points;
points.reserve(first_path.size());
for (const ClipperLib_Z::IntPoint &pt : first_path)
points.emplace_back(coord_t(pt.X), coord_t(pt.Y));
i = j;
} else {
//FIXME The path chaining here may not be optimal.
ExtrusionEntityCollection this_loop_trimmed;
this_loop_trimmed.entities.reserve(j - i);
for (; i < j; ++ i) {
this_loop_trimmed.entities.emplace_back(new ExtrusionPath(erSkirt, float(flow.mm3_per_mm()), float(flow.width), float(print.skirt_first_layer_height())));
const ClipperLib_Z::Path &path = *loops_trimmed_order[i].first;
Points &points = static_cast<ExtrusionPath*>(this_loop_trimmed.entities.back())->polyline.points;
points.reserve(path.size());
for (const ClipperLib_Z::IntPoint &pt : path)
points.emplace_back(coord_t(pt.X), coord_t(pt.Y));
}
chain_and_reorder_extrusion_entities(this_loop_trimmed.entities, &last_pt);
brim.entities.reserve(brim.entities.size() + this_loop_trimmed.entities.size());
append(brim.entities, std::move(this_loop_trimmed.entities));
this_loop_trimmed.entities.clear();
}
last_pt = brim.last_point();
}
}
} else {
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);
return brim;
}
} // namespace Slic3r

14
src/libslic3r/Brim.hpp Normal file
View File

@ -0,0 +1,14 @@
#ifndef slic3r_Brim_hpp_
#define slic3r_Brim_hpp_
namespace Slic3r {
class Print;
// Produce brim lines around those objects, that have the brim enabled.
// 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);
} // Slic3r
#endif // slic3r_Brim_hpp_

View File

@ -21,6 +21,8 @@ add_library(libslic3r STATIC
BoundingBox.hpp
BridgeDetector.cpp
BridgeDetector.hpp
Brim.cpp
Brim.hpp
ClipperUtils.cpp
ClipperUtils.hpp
Config.cpp
@ -307,8 +309,6 @@ target_link_libraries(libslic3r
nowide
${EXPAT_LIBRARIES}
glu-libtess
polypartition
poly2tri
qhull
semver
TBB::tbb

View File

@ -616,11 +616,11 @@ void ConfigBase::load(const boost::property_tree::ptree &tree)
}
// Load the config keys from the tail of a G-code file.
void ConfigBase::load_from_gcode_file(const std::string &file)
void ConfigBase::load_from_gcode_file(const std::string& file, bool check_header)
{
// 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;

View File

@ -1344,7 +1344,7 @@ public:
static bool has(T value)
{
for (const std::pair<std::string, int> &kvp : ConfigOptionEnum<T>::get_enum_values())
for (const auto &kvp : ConfigOptionEnum<T>::get_enum_values())
if (kvp.second == value)
return true;
return false;
@ -1358,11 +1358,11 @@ public:
// Initialize the map.
const t_config_enum_values &enum_keys_map = ConfigOptionEnum<T>::get_enum_values();
int cnt = 0;
for (const std::pair<std::string, int> &kvp : enum_keys_map)
for (const auto& kvp : enum_keys_map)
cnt = std::max(cnt, kvp.second);
cnt += 1;
names.assign(cnt, "");
for (const std::pair<std::string, int> &kvp : enum_keys_map)
for (const auto& kvp : enum_keys_map)
names[kvp.second] = kvp.first;
}
return names;
@ -1695,6 +1695,7 @@ public:
// Static configuration definition. Any value stored into this ConfigBase shall have its definition here.
virtual const ConfigDef* def() const = 0;
// Find ando/or create a ConfigOption instance for a given name.
using ConfigOptionResolver::optptr;
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) = 0;
// Collect names of all configuration values maintained by this configuration store.
virtual t_config_option_keys keys() const = 0;
@ -1790,7 +1791,7 @@ public:
void setenv_() const;
void load(const std::string &file);
void load_from_ini(const std::string &file);
void load_from_gcode_file(const std::string &file);
void load_from_gcode_file(const std::string& file, bool check_header = true);
// Returns number of key/value pairs extracted.
size_t load_from_gcode_string(const char* str);
void load(const boost::property_tree::ptree &tree);
@ -1946,8 +1947,9 @@ public:
int& opt_int(const t_config_option_key &opt_key, unsigned int idx) { return this->option<ConfigOptionInts>(opt_key)->get_at(idx); }
int opt_int(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast<const ConfigOptionInts*>(this->option(opt_key))->get_at(idx); }
// In ConfigManipulation::toggle_print_fff_options, it is called on option with type ConfigOptionEnumGeneric* and also ConfigOptionEnum*.
template<typename ENUM>
ENUM opt_enum(const t_config_option_key &opt_key) const { return (ENUM)dynamic_cast<const ConfigOptionEnumGeneric*>(this->option(opt_key))->value; }
ENUM opt_enum(const t_config_option_key &opt_key) const { return this->option<ConfigOptionEnum<ENUM>>(opt_key)->value; }
bool opt_bool(const t_config_option_key &opt_key) const { return this->option<ConfigOptionBool>(opt_key)->value != 0; }
bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option<ConfigOptionBools>(opt_key)->get_at(idx) != 0; }

View File

@ -25,90 +25,89 @@
namespace Slic3r {
EdgeGrid::Grid::Grid() :
m_rows(0), m_cols(0)
{
}
EdgeGrid::Grid::~Grid()
{
m_contours.clear();
m_cell_data.clear();
m_cells.clear();
}
void EdgeGrid::Grid::create(const Polygons &polygons, coord_t resolution)
{
// Count the contours.
size_t ncontours = 0;
for (size_t j = 0; j < polygons.size(); ++ j)
if (! polygons[j].points.empty())
++ ncontours;
// Collect the contours.
m_contours.assign(ncontours, nullptr);
ncontours = 0;
for (size_t j = 0; j < polygons.size(); ++ j)
if (! polygons[j].points.empty())
m_contours[ncontours ++] = &polygons[j].points;
m_contours.clear();
m_contours.reserve(std::count_if(polygons.begin(), polygons.end(), [](const Polygon &p) { return ! p.empty(); }));
for (const Polygon &polygon : polygons)
if (! polygon.empty())
m_contours.emplace_back(polygon.points, false);
create_from_m_contours(resolution);
}
void EdgeGrid::Grid::create(const std::vector<const Polygon*> &polygons, coord_t resolution)
{
// Count the contours.
size_t ncontours = 0;
for (size_t j = 0; j < polygons.size(); ++ j)
if (! polygons[j]->points.empty())
++ ncontours;
// Collect the contours.
m_contours.assign(ncontours, nullptr);
ncontours = 0;
for (size_t j = 0; j < polygons.size(); ++ j)
if (! polygons[j]->points.empty())
m_contours[ncontours ++] = &polygons[j]->points;
m_contours.clear();
m_contours.reserve(std::count_if(polygons.begin(), polygons.end(), [](const Polygon *p) { return ! p->empty(); }));
for (const Polygon *polygon : polygons)
if (! polygon->empty())
m_contours.emplace_back(polygon->points, false);
create_from_m_contours(resolution);
}
void EdgeGrid::Grid::create(const std::vector<Points> &polygons, coord_t resolution)
void EdgeGrid::Grid::create(const std::vector<Points> &polygons, coord_t resolution, bool open_polylines)
{
// Count the contours.
size_t ncontours = 0;
for (size_t j = 0; j < polygons.size(); ++ j)
if (! polygons[j].empty())
++ ncontours;
// Collect the contours.
m_contours.assign(ncontours, nullptr);
ncontours = 0;
for (size_t j = 0; j < polygons.size(); ++ j)
if (! polygons[j].empty())
m_contours[ncontours ++] = &polygons[j];
m_contours.clear();
m_contours.reserve(std::count_if(polygons.begin(), polygons.end(), [](const Points &p) { return p.size() > 1; }));
for (const Points &points : polygons)
if (points.size() > 1) {
const Point *begin = points.data();
const Point *end = points.data() + points.size();
bool open = open_polylines;
if (open_polylines) {
if (*begin == end[-1]) {
open = false;
-- end;
}
} else
assert(*begin != end[-1]);
m_contours.emplace_back(begin, end, open);
}
create_from_m_contours(resolution);
}
void EdgeGrid::Grid::create(const Polygons &polygons, const Polylines &polylines, coord_t resolution)
{
// Collect the contours.
m_contours.clear();
m_contours.reserve(
std::count_if(polygons.begin(), polygons.end(), [](const Polygon &p) { return p.size() > 1; }) +
std::count_if(polylines.begin(), polylines.end(), [](const Polyline &p) { return p.size() > 1; }));
for (const Polyline &polyline : polylines)
if (polyline.size() > 1) {
const Point *begin = polyline.points.data();
const Point *end = polyline.points.data() + polyline.size();
bool open = true;
if (*begin == end[-1]) {
open = false;
-- end;
}
m_contours.emplace_back(begin, end, open);
}
for (const Polygon &polygon : polygons)
if (polygon.size() > 1)
m_contours.emplace_back(polygon.points, false);
create_from_m_contours(resolution);
}
void EdgeGrid::Grid::create(const ExPolygon &expoly, coord_t resolution)
{
// Count the contours.
size_t ncontours = 0;
if (! expoly.contour.points.empty())
++ ncontours;
for (size_t j = 0; j < expoly.holes.size(); ++ j)
if (! expoly.holes[j].points.empty())
++ ncontours;
// Collect the contours.
m_contours.assign(ncontours, nullptr);
ncontours = 0;
if (! expoly.contour.points.empty())
m_contours[ncontours++] = &expoly.contour.points;
for (size_t j = 0; j < expoly.holes.size(); ++ j)
if (! expoly.holes[j].points.empty())
m_contours[ncontours++] = &expoly.holes[j].points;
m_contours.clear();
m_contours.reserve((expoly.contour.empty() ? 0 : 1) + std::count_if(expoly.holes.begin(), expoly.holes.end(), [](const Polygon &p) { return ! p.empty(); }));
if (! expoly.contour.empty())
m_contours.emplace_back(expoly.contour.points, false);
for (const Polygon &hole : expoly.holes)
if (! hole.empty())
m_contours.emplace_back(hole.points, false);
create_from_m_contours(resolution);
}
@ -117,25 +116,21 @@ void EdgeGrid::Grid::create(const ExPolygons &expolygons, coord_t resolution)
{
// Count the contours.
size_t ncontours = 0;
for (size_t i = 0; i < expolygons.size(); ++ i) {
const ExPolygon &expoly = expolygons[i];
if (! expoly.contour.points.empty())
for (const ExPolygon &expoly : expolygons) {
if (! expoly.contour.empty())
++ ncontours;
for (size_t j = 0; j < expoly.holes.size(); ++ j)
if (! expoly.holes[j].points.empty())
++ ncontours;
ncontours += std::count_if(expoly.holes.begin(), expoly.holes.end(), [](const Polygon &p) { return ! p.empty(); });
}
// Collect the contours.
m_contours.assign(ncontours, nullptr);
ncontours = 0;
for (size_t i = 0; i < expolygons.size(); ++ i) {
const ExPolygon &expoly = expolygons[i];
if (! expoly.contour.points.empty())
m_contours[ncontours++] = &expoly.contour.points;
for (size_t j = 0; j < expoly.holes.size(); ++ j)
if (! expoly.holes[j].points.empty())
m_contours[ncontours++] = &expoly.holes[j].points;
m_contours.clear();
m_contours.reserve(ncontours);
for (const ExPolygon &expoly : expolygons) {
if (! expoly.contour.empty())
m_contours.emplace_back(expoly.contour.points, false);
for (const Polygon &hole : expoly.holes)
if (! hole.empty())
m_contours.emplace_back(hole.points, false);
}
create_from_m_contours(resolution);
@ -151,11 +146,13 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
{
assert(resolution > 0);
// 1) Measure the bounding box.
for (size_t i = 0; i < m_contours.size(); ++ i) {
const Slic3r::Points &pts = *m_contours[i];
for (size_t j = 0; j < pts.size(); ++ j)
m_bbox.merge(pts[j]);
for (const Contour &contour : m_contours) {
assert(contour.num_segments() > 0);
assert(*contour.begin() != contour.end()[-1]);
for (const Slic3r::Point &pt : contour)
m_bbox.merge(pt);
}
coord_t eps = 16;
m_bbox.min(0) -= eps;
m_bbox.min(1) -= eps;
@ -170,11 +167,11 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
// 3) First round of contour rasterization, count the edges per grid cell.
for (size_t i = 0; i < m_contours.size(); ++ i) {
const Slic3r::Points &pts = *m_contours[i];
for (size_t j = 0; j < pts.size(); ++ j) {
const Contour &contour = m_contours[i];
for (size_t j = 0; j < contour.num_segments(); ++ j) {
// End points of the line segment.
Slic3r::Point p1(pts[j]);
Slic3r::Point p2 = pts[(j + 1 == pts.size()) ? 0 : j + 1];
Slic3r::Point p1(contour.segment_start(j));
Slic3r::Point p2(contour.segment_end(j));
p1(0) -= m_bbox.min(0);
p1(1) -= m_bbox.min(1);
p2(0) -= m_bbox.min(0);
@ -333,9 +330,9 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
assert(visitor.i == 0);
for (; visitor.i < m_contours.size(); ++ visitor.i) {
const Slic3r::Points &pts = *m_contours[visitor.i];
for (visitor.j = 0; visitor.j < pts.size(); ++ visitor.j)
this->visit_cells_intersecting_line(pts[visitor.j], pts[(visitor.j + 1 == pts.size()) ? 0 : visitor.j + 1], visitor);
const Contour &contour = m_contours[visitor.i];
for (visitor.j = 0; visitor.j < contour.num_segments(); ++ visitor.j)
this->visit_cells_intersecting_line(contour.segment_start(visitor.j), contour.segment_end(visitor.j), visitor);
}
}
@ -701,11 +698,12 @@ void EdgeGrid::Grid::calculate_sdf()
const Cell &cell = m_cells[r * m_cols + c];
// For each segment in the cell:
for (size_t i = cell.begin; i != cell.end; ++ i) {
const Slic3r::Points &pts = *m_contours[m_cell_data[i].first];
const Contour &contour = m_contours[m_cell_data[i].first];
assert(contour.closed());
size_t ipt = m_cell_data[i].second;
// End points of the line segment.
const Slic3r::Point &p1 = pts[ipt];
const Slic3r::Point &p2 = pts[(ipt + 1 == pts.size()) ? 0 : ipt + 1];
const Slic3r::Point &p1 = contour.segment_start(ipt);
const Slic3r::Point &p2 = contour.segment_end(ipt);
// Segment vector
const Slic3r::Point v_seg = p2 - p1;
// l2 of v_seg
@ -729,7 +727,7 @@ void EdgeGrid::Grid::calculate_sdf()
double dabs = sqrt(int64_t(v_pt(0)) * int64_t(v_pt(0)) + int64_t(v_pt(1)) * int64_t(v_pt(1)));
if (dabs < d_min) {
// Previous point.
const Slic3r::Point &p0 = pts[(ipt == 0) ? (pts.size() - 1) : ipt - 1];
const Slic3r::Point &p0 = contour.segment_prev(ipt);
Slic3r::Point v_seg_prev = p1 - p0;
int64_t t2_pt = int64_t(v_seg_prev(0)) * int64_t(v_pt(0)) + int64_t(v_seg_prev(1)) * int64_t(v_pt(1));
if (t2_pt > 0) {
@ -1049,7 +1047,7 @@ float EdgeGrid::Grid::signed_distance_bilinear(const Point &pt) const
return f;
}
EdgeGrid::Grid::ClosestPointResult EdgeGrid::Grid::closest_point(const Point &pt, coord_t search_radius) const
EdgeGrid::Grid::ClosestPointResult EdgeGrid::Grid::closest_point_signed_distance(const Point &pt, coord_t search_radius) const
{
BoundingBox bbox;
bbox.min = bbox.max = Point(pt(0) - m_bbox.min(0), pt(1) - m_bbox.min(1));
@ -1088,12 +1086,13 @@ EdgeGrid::Grid::ClosestPointResult EdgeGrid::Grid::closest_point(const Point &pt
for (int c = bbox.min(0); c <= bbox.max(0); ++ c) {
const Cell &cell = m_cells[r * m_cols + c];
for (size_t i = cell.begin; i < cell.end; ++ i) {
const size_t contour_idx = m_cell_data[i].first;
const Slic3r::Points &pts = *m_contours[contour_idx];
const size_t contour_idx = m_cell_data[i].first;
const Contour &contour = m_contours[contour_idx];
assert(contour.closed());
size_t ipt = m_cell_data[i].second;
// End points of the line segment.
const Slic3r::Point &p1 = pts[ipt];
const Slic3r::Point &p2 = pts[(ipt + 1 == pts.size()) ? 0 : ipt + 1];
const Slic3r::Point &p1 = contour.segment_start(ipt);
const Slic3r::Point &p2 = contour.segment_end(ipt);
const Slic3r::Point v_seg = p2 - p1;
const Slic3r::Point v_pt = pt - p1;
// dot(p2-p1, pt-p1)
@ -1105,7 +1104,7 @@ EdgeGrid::Grid::ClosestPointResult EdgeGrid::Grid::closest_point(const Point &pt
double dabs = sqrt(int64_t(v_pt(0)) * int64_t(v_pt(0)) + int64_t(v_pt(1)) * int64_t(v_pt(1)));
if (dabs < d_min) {
// Previous point.
const Slic3r::Point &p0 = pts[(ipt == 0) ? (pts.size() - 1) : ipt - 1];
const Slic3r::Point &p0 = contour.segment_prev(ipt);
Slic3r::Point v_seg_prev = p1 - p0;
int64_t t2_pt = int64_t(v_seg_prev(0)) * int64_t(v_pt(0)) + int64_t(v_seg_prev(1)) * int64_t(v_pt(1));
if (t2_pt > 0) {
@ -1161,9 +1160,9 @@ EdgeGrid::Grid::ClosestPointResult EdgeGrid::Grid::closest_point(const Point &pt
assert(result.t >= 0. && result.t <= 1.);
#ifndef NDEBUG
{
const Slic3r::Points &pts = *m_contours[result.contour_idx];
const Slic3r::Point &p1 = pts[result.start_point_idx];
const Slic3r::Point &p2 = pts[(result.start_point_idx + 1 == pts.size()) ? 0 : result.start_point_idx + 1];
const Contour &contour = m_contours[result.contour_idx];
const Slic3r::Point &p1 = contour.segment_start(result.start_point_idx);
const Slic3r::Point &p2 = contour.segment_end(result.start_point_idx);
Vec2d vfoot;
if (result.t == 0)
vfoot = p1.cast<double>() - pt.cast<double>();
@ -1217,11 +1216,12 @@ bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radiu
for (int c = bbox.min(0); c <= bbox.max(0); ++ c) {
const Cell &cell = m_cells[r * m_cols + c];
for (size_t i = cell.begin; i < cell.end; ++ i) {
const Slic3r::Points &pts = *m_contours[m_cell_data[i].first];
const Contour &contour = m_contours[m_cell_data[i].first];
assert(contour.closed());
size_t ipt = m_cell_data[i].second;
// End points of the line segment.
const Slic3r::Point &p1 = pts[ipt];
const Slic3r::Point &p2 = pts[(ipt + 1 == pts.size()) ? 0 : ipt + 1];
const Slic3r::Point &p1 = contour.segment_start(ipt);
const Slic3r::Point &p2 = contour.segment_end(ipt);
Slic3r::Point v_seg = p2 - p1;
Slic3r::Point v_pt = pt - p1;
// dot(p2-p1, pt-p1)
@ -1233,7 +1233,7 @@ bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radiu
double dabs = sqrt(int64_t(v_pt(0)) * int64_t(v_pt(0)) + int64_t(v_pt(1)) * int64_t(v_pt(1)));
if (dabs < d_min) {
// Previous point.
const Slic3r::Point &p0 = pts[(ipt == 0) ? (pts.size() - 1) : ipt - 1];
const Slic3r::Point &p0 = contour.segment_prev(ipt);
Slic3r::Point v_seg_prev = p1 - p0;
int64_t t2_pt = int64_t(v_seg_prev(0)) * int64_t(v_pt(0)) + int64_t(v_seg_prev(1)) * int64_t(v_pt(1));
if (t2_pt > 0) {
@ -1423,26 +1423,26 @@ std::vector<std::pair<EdgeGrid::Grid::ContourEdge, EdgeGrid::Grid::ContourEdge>>
const Cell &cell = m_cells[r * m_cols + c];
// For each pair of segments in the cell:
for (size_t i = cell.begin; i != cell.end; ++ i) {
const Slic3r::Points &ipts = *m_contours[m_cell_data[i].first];
const Contour &icontour = m_contours[m_cell_data[i].first];
size_t ipt = m_cell_data[i].second;
// End points of the line segment and their vector.
const Slic3r::Point &ip1 = ipts[ipt];
const Slic3r::Point &ip2 = ipts[(ipt + 1 == ipts.size()) ? 0 : ipt + 1];
const Slic3r::Point &ip1 = icontour.segment_start(ipt);
const Slic3r::Point &ip2 = icontour.segment_end(ipt);
for (size_t j = i + 1; j != cell.end; ++ j) {
const Slic3r::Points &jpts = *m_contours[m_cell_data[j].first];
size_t jpt = m_cell_data[j].second;
const Contour &jcontour = m_contours[m_cell_data[j].first];
size_t jpt = m_cell_data[j].second;
// End points of the line segment and their vector.
const Slic3r::Point &jp1 = jpts[jpt];
const Slic3r::Point &jp2 = jpts[(jpt + 1 == jpts.size()) ? 0 : jpt + 1];
if (&ipts == &jpts && (&ip1 == &jp2 || &jp1 == &ip2))
const Slic3r::Point &jp1 = jcontour.segment_start(jpt);
const Slic3r::Point &jp2 = jcontour.segment_end(jpt);
if (&icontour == &jcontour && (&ip1 == &jp2 || &jp1 == &ip2))
// Segments of the same contour share a common vertex.
continue;
if (Geometry::segments_intersect(ip1, ip2, jp1, jp2)) {
// The two segments intersect. Add them to the output.
int jfirst = (&jpts < &ipts) || (&jpts == &ipts && jpt < ipt);
int jfirst = (&jcontour < &icontour) || (&jcontour == &icontour && jpt < ipt);
out.emplace_back(jfirst ?
std::make_pair(std::make_pair(&ipts, ipt), std::make_pair(&jpts, jpt)) :
std::make_pair(std::make_pair(&ipts, ipt), std::make_pair(&jpts, jpt)));
std::make_pair(std::make_pair(&icontour, ipt), std::make_pair(&jcontour, jpt)) :
std::make_pair(std::make_pair(&icontour, ipt), std::make_pair(&jcontour, jpt)));
}
}
}
@ -1460,18 +1460,18 @@ bool EdgeGrid::Grid::has_intersecting_edges() const
const Cell &cell = m_cells[r * m_cols + c];
// For each pair of segments in the cell:
for (size_t i = cell.begin; i != cell.end; ++ i) {
const Slic3r::Points &ipts = *m_contours[m_cell_data[i].first];
const Contour &icontour = m_contours[m_cell_data[i].first];
size_t ipt = m_cell_data[i].second;
// End points of the line segment and their vector.
const Slic3r::Point &ip1 = ipts[ipt];
const Slic3r::Point &ip2 = ipts[(ipt + 1 == ipts.size()) ? 0 : ipt + 1];
const Slic3r::Point &ip1 = icontour.segment_start(ipt);
const Slic3r::Point &ip2 = icontour.segment_end(ipt);
for (size_t j = i + 1; j != cell.end; ++ j) {
const Slic3r::Points &jpts = *m_contours[m_cell_data[j].first];
const Contour &jcontour = m_contours[m_cell_data[j].first];
size_t jpt = m_cell_data[j].second;
// End points of the line segment and their vector.
const Slic3r::Point &jp1 = jpts[jpt];
const Slic3r::Point &jp2 = jpts[(jpt + 1 == jpts.size()) ? 0 : jpt + 1];
if (! (&ipts == &jpts && (&ip1 == &jp2 || &jp1 == &ip2)) &&
const Slic3r::Point &jp1 = jcontour.segment_start(jpt);
const Slic3r::Point &jp2 = jcontour.segment_end(jpt);
if (! (&icontour == &jcontour && (&ip1 == &jp2 || &jp1 == &ip2)) &&
Geometry::segments_intersect(ip1, ip2, jp1, jp2))
return true;
}
@ -1606,22 +1606,27 @@ void export_intersections_to_svg(const std::string &filename, const Polygons &po
SVG svg(filename.c_str(), bbox);
svg.draw(union_ex(polygons), "gray", 0.25f);
svg.draw_outline(polygons, "black");
std::set<const Points*> intersecting_contours;
std::set<const EdgeGrid::Contour*> intersecting_contours;
for (const std::pair<EdgeGrid::Grid::ContourEdge, EdgeGrid::Grid::ContourEdge> &ie : intersections) {
intersecting_contours.insert(ie.first.first);
intersecting_contours.insert(ie.second.first);
}
// Highlight the contours with intersections.
coord_t line_width = coord_t(scale_(0.01));
for (const Points *ic : intersecting_contours) {
svg.draw_outline(Polygon(*ic), "green");
svg.draw_outline(Polygon(*ic), "black", line_width);
for (const EdgeGrid::Contour *ic : intersecting_contours) {
if (ic->open())
svg.draw(Polyline(Points(ic->begin(), ic->end())), "green");
else {
Polygon polygon(Points(ic->begin(), ic->end()));
svg.draw_outline(polygon, "green");
svg.draw_outline(polygon, "black", line_width);
}
}
// Paint the intersections.
for (const std::pair<EdgeGrid::Grid::ContourEdge, EdgeGrid::Grid::ContourEdge> &intersecting_edges : intersections) {
auto edge = [](const EdgeGrid::Grid::ContourEdge &e) {
return Line(e.first->at(e.second),
e.first->at((e.second + 1 == e.first->size()) ? 0 : e.second + 1));
return Line(e.first->segment_start(e.second),
e.first->segment_end(e.second));
};
svg.draw(edge(intersecting_edges.first), "red", line_width);
svg.draw(edge(intersecting_edges.second), "red", line_width);

View File

@ -12,22 +12,89 @@
namespace Slic3r {
namespace EdgeGrid {
class Contour {
public:
Contour() = default;
Contour(const Slic3r::Point *begin, const Slic3r::Point *end, bool open) : m_begin(begin), m_end(end), m_open(open) {}
Contour(const Slic3r::Point *data, size_t size, bool open) : Contour(data, data + size, open) {}
Contour(const std::vector<Slic3r::Point> &pts, bool open) : Contour(pts.data(), pts.size(), open) {}
const Slic3r::Point *begin() const { return m_begin; }
const Slic3r::Point *end() const { return m_end; }
bool open() const { return m_open; }
bool closed() const { return ! m_open; }
// Start point of a segment idx.
const Slic3r::Point& segment_start(size_t idx) const {
assert(idx < this->num_segments());
return m_begin[idx];
}
// End point of a segment idx.
const Slic3r::Point& segment_end(size_t idx) const {
assert(idx < this->num_segments());
const Slic3r::Point *ptr = m_begin + idx + 1;
return ptr == m_end ? *m_begin : *ptr;
}
// Start point of a segment preceding idx.
const Slic3r::Point& segment_prev(size_t idx) const {
assert(idx < this->num_segments());
assert(idx > 0 || ! m_open);
return idx == 0 ? m_end[-1] : m_begin[idx - 1];
}
// Index of a segment preceding idx.
const size_t segment_idx_prev(size_t idx) const {
assert(idx < this->num_segments());
assert(idx > 0 || ! m_open);
return (idx == 0 ? this->size() : idx) - 1;
}
// Index of a segment preceding idx.
const size_t segment_idx_next(size_t idx) const {
assert(idx < this->num_segments());
++ idx;
return m_begin + idx == m_end ? 0 : idx;
}
size_t num_segments() const { return this->size() - (m_open ? 1 : 0); }
private:
size_t size() const { return m_end - m_begin; }
const Slic3r::Point *m_begin { nullptr };
const Slic3r::Point *m_end { nullptr };
bool m_open { false };
};
class Grid
{
public:
Grid();
~Grid();
Grid() = default;
Grid(const BoundingBox &bbox) : m_bbox(bbox) {}
void set_bbox(const BoundingBox &bbox) { m_bbox = bbox; }
// Fill in the grid with open polylines or closed contours.
// If open flag is indicated, then polylines_or_polygons are considered to be open by default.
// Only if the first point of a polyline is equal to the last point of a polyline,
// then the polyline is considered to be closed and the last repeated point is removed when
// inserted into the EdgeGrid.
// Most of the Grid functions expect all the contours to be closed, you have been warned!
void create(const std::vector<Points> &polylines_or_polygons, coord_t resolution, bool open);
void create(const Polygons &polygons, const Polylines &polylines, coord_t resolution);
// Fill in the grid with closed contours.
void create(const Polygons &polygons, coord_t resolution);
void create(const std::vector<const Polygon*> &polygons, coord_t resolution);
void create(const std::vector<Points> &polygons, coord_t resolution);
void create(const std::vector<Points> &polygons, coord_t resolution) { this->create(polygons, resolution, false); }
void create(const ExPolygon &expoly, coord_t resolution);
void create(const ExPolygons &expolygons, coord_t resolution);
void create(const ExPolygonCollection &expolygons, coord_t resolution);
const std::vector<const Slic3r::Points*>& contours() const { return m_contours; }
const std::vector<Contour>& contours() const { return m_contours; }
#if 0
// Test, whether the edges inside the grid intersect with the polygons provided.
@ -44,12 +111,14 @@ public:
// Fill in a rough m_signed_distance_field from the edge grid.
// The rough SDF is used by signed_distance() for distances outside of the search_radius.
// Only call this function for closed contours!
void calculate_sdf();
// Return an estimate of the signed distance based on m_signed_distance_field grid.
float signed_distance_bilinear(const Point &pt) const;
// Calculate a signed distance to the contours in search_radius from the point.
// Only call this function for closed contours!
struct ClosestPointResult {
size_t contour_idx = size_t(-1);
size_t start_point_idx = size_t(-1);
@ -60,12 +129,14 @@ public:
bool valid() const { return contour_idx != size_t(-1); }
};
ClosestPointResult closest_point(const Point &pt, coord_t search_radius) const;
ClosestPointResult closest_point_signed_distance(const Point &pt, coord_t search_radius) const;
// Only call this function for closed contours!
bool signed_distance_edges(const Point &pt, coord_t search_radius, coordf_t &result_min_dist, bool *pon_segment = nullptr) const;
// Calculate a signed distance to the contours in search_radius from the point. If no edge is found in search_radius,
// return an interpolated value from m_signed_distance_field, if it exists.
// Only call this function for closed contours!
bool signed_distance(const Point &pt, coord_t search_radius, coordf_t &result_min_dist) const;
const BoundingBox& bbox() const { return m_bbox; }
@ -76,8 +147,8 @@ public:
// For supports: Contours enclosing the rasterized edges.
Polygons contours_simplified(coord_t offset, bool fill_holes) const;
typedef std::pair<const Slic3r::Points*, size_t> ContourPoint;
typedef std::pair<const Slic3r::Points*, size_t> ContourEdge;
typedef std::pair<const Contour*, size_t> ContourPoint;
typedef std::pair<const Contour*, size_t> ContourEdge;
std::vector<std::pair<ContourEdge, ContourEdge>> intersecting_edges() const;
bool has_intersecting_edges() const;
@ -255,16 +326,16 @@ public:
std::pair<const Slic3r::Point&, const Slic3r::Point&> segment(const std::pair<size_t, size_t> &contour_and_segment_idx) const
{
const Slic3r::Points &ipts = *m_contours[contour_and_segment_idx.first];
size_t ipt = contour_and_segment_idx.second;
return std::pair<const Slic3r::Point&, const Slic3r::Point&>(ipts[ipt], ipts[ipt + 1 == ipts.size() ? 0 : ipt + 1]);
const Contour &contour = m_contours[contour_and_segment_idx.first];
size_t iseg = contour_and_segment_idx.second;
return std::pair<const Slic3r::Point&, const Slic3r::Point&>(contour.segment_start(iseg), contour.segment_end(iseg));
}
Line line(const std::pair<size_t, size_t> &contour_and_segment_idx) const
{
const Slic3r::Points &ipts = *m_contours[contour_and_segment_idx.first];
size_t ipt = contour_and_segment_idx.second;
return Line(ipts[ipt], ipts[ipt + 1 == ipts.size() ? 0 : ipt + 1]);
const Contour &contour = m_contours[contour_and_segment_idx.first];
size_t iseg = contour_and_segment_idx.second;
return Line(contour.segment_start(iseg), contour.segment_end(iseg));
}
protected:
@ -295,13 +366,13 @@ protected:
BoundingBox m_bbox;
// Grid dimensions.
coord_t m_resolution;
size_t m_rows;
size_t m_cols;
size_t m_rows = 0;
size_t m_cols = 0;
// Referencing the source contours.
// This format allows one to work with any Slic3r fixed point contour format
// (Polygon, ExPolygon, ExPolygonCollection etc).
std::vector<const Slic3r::Points*> m_contours;
std::vector<Contour> m_contours;
// Referencing a contour and a line segment of m_contours.
std::vector<std::pair<size_t, size_t> > m_cell_data;

View File

@ -104,7 +104,7 @@ std::vector<float> contour_distance(const EdgeGrid::Grid &grid, const size_t idx
double param_hi;
double param_end = resampled_point_parameters.back().curve_parameter;
{
const Slic3r::Points &ipts = *grid.contours()[it_contour_and_segment->first];
const EdgeGrid::Contour &contour = grid.contours()[it_contour_and_segment->first];
size_t ipt = it_contour_and_segment->second;
ResampledPoint key(ipt, false, 0.);
auto lower = [](const ResampledPoint& l, const ResampledPoint r) { return l.idx_src < r.idx_src || (l.idx_src == r.idx_src && int(l.interpolated) > int(r.interpolated)); };
@ -112,7 +112,7 @@ std::vector<float> contour_distance(const EdgeGrid::Grid &grid, const size_t idx
assert(it != resampled_point_parameters.end() && it->idx_src == ipt && ! it->interpolated);
double t2 = cross2(dir, vptpt2) / denom;
assert(t2 > - EPSILON && t2 < 1. + EPSILON);
if (++ ipt == ipts.size())
if (contour.begin() + (++ ipt) == contour.end())
param_hi = t2 * dir2.norm();
else
param_hi = it->curve_parameter + t2 * dir2.norm();
@ -251,7 +251,7 @@ std::vector<float> contour_distance2(const EdgeGrid::Grid &grid, const size_t id
#endif
struct Visitor {
Visitor(const EdgeGrid::Grid &grid, const size_t idx_contour, const std::vector<ResampledPoint> &resampled_point_parameters, double dist_same_contour_accept, double dist_same_contour_reject) :
grid(grid), idx_contour(idx_contour), contour(*grid.contours()[idx_contour]), resampled_point_parameters(resampled_point_parameters), dist_same_contour_accept(dist_same_contour_accept), dist_same_contour_reject(dist_same_contour_reject) {}
grid(grid), idx_contour(idx_contour), contour(grid.contours()[idx_contour]), resampled_point_parameters(resampled_point_parameters), dist_same_contour_accept(dist_same_contour_accept), dist_same_contour_reject(dist_same_contour_reject) {}
void init(const Points &contour, const Point &apoint) {
this->idx_point = &apoint - contour.data();
@ -283,15 +283,15 @@ std::vector<float> contour_distance2(const EdgeGrid::Grid &grid, const size_t id
double param_lo = resampled_point_parameters[this->idx_point].curve_parameter;
double param_hi;
double param_end = resampled_point_parameters.back().curve_parameter;
const Slic3r::Points &ipts = *grid.contours()[it_contour_and_segment->first];
const size_t ipt = it_contour_and_segment->second;
const EdgeGrid::Contour &contour = grid.contours()[it_contour_and_segment->first];
const size_t ipt = it_contour_and_segment->second;
{
ResampledPoint key(ipt, false, 0.);
auto lower = [](const ResampledPoint& l, const ResampledPoint r) { return l.idx_src < r.idx_src || (l.idx_src == r.idx_src && int(l.interpolated) > int(r.interpolated)); };
auto it = std::lower_bound(resampled_point_parameters.begin(), resampled_point_parameters.end(), key, lower);
assert(it != resampled_point_parameters.end() && it->idx_src == ipt && ! it->interpolated);
param_hi = t * sqrt(l2);
if (ipt + 1 < ipts.size())
if (contour.begin() + ipt + 1 < contour.end())
param_hi += it->curve_parameter;
}
if (param_lo > param_hi)
@ -307,9 +307,9 @@ std::vector<float> contour_distance2(const EdgeGrid::Grid &grid, const size_t id
// Bulge is estimated by 0.6 of the circle circumference drawn around the bisector.
// Test whether the contour is convex or concave.
bool inside =
(t == 0.) ? this->inside_corner(ipts, ipt, this->point) :
(t == 1.) ? this->inside_corner(ipts, ipt + 1 == ipts.size() ? 0 : ipt + 1, this->point) :
this->left_of_segment(ipts, ipt, this->point);
(t == 0.) ? this->inside_corner(contour, ipt, this->point) :
(t == 1.) ? this->inside_corner(contour, contour.segment_idx_next(ipt), this->point) :
this->left_of_segment(contour, ipt, this->point);
accept = inside && dist_along_contour > 0.6 * M_PI * dist;
}
}
@ -329,7 +329,7 @@ std::vector<float> contour_distance2(const EdgeGrid::Grid &grid, const size_t id
const EdgeGrid::Grid &grid;
const size_t idx_contour;
const Points &contour;
const EdgeGrid::Contour &contour;
const std::vector<ResampledPoint> &resampled_point_parameters;
const double dist_same_contour_accept;
const double dist_same_contour_reject;
@ -358,24 +358,28 @@ std::vector<float> contour_distance2(const EdgeGrid::Grid &grid, const size_t id
return Vec2d(- v.y(), v.x());
}
static bool inside_corner(const Slic3r::Points &contour, size_t i, const Point &pt_oposite) {
const Vec2d pt = pt_oposite.cast<double>();
size_t iprev = prev_idx_modulo(i, contour);
size_t inext = next_idx_modulo(i, contour);
Vec2d v1 = (contour[i] - contour[iprev]).cast<double>();
Vec2d v2 = (contour[inext] - contour[i]).cast<double>();
bool left_of_v1 = cross2(v1, pt - contour[iprev].cast<double>()) > 0.;
bool left_of_v2 = cross2(v2, pt - contour[i ].cast<double>()) > 0.;
return cross2(v1, v2) > 0 ?
left_of_v1 && left_of_v2 : // convex corner
left_of_v1 || left_of_v2; // concave corner
}
static bool left_of_segment(const Slic3r::Points &contour, size_t i, const Point &pt_oposite) {
const Vec2d pt = pt_oposite.cast<double>();
size_t inext = next_idx_modulo(i, contour);
Vec2d v = (contour[inext] - contour[i]).cast<double>();
return cross2(v, pt - contour[i].cast<double>()) > 0.;
}
static bool inside_corner(const EdgeGrid::Contour &contour, size_t i, const Point &pt_oposite)
{
const Vec2d pt = pt_oposite.cast<double>();
const Point &pt_prev = contour.segment_prev(i);
const Point &pt_this = contour.segment_start(i);
const Point &pt_next = contour.segment_end(i);
Vec2d v1 = (pt_this - pt_prev).cast<double>();
Vec2d v2 = (pt_next - pt_this).cast<double>();
bool left_of_v1 = cross2(v1, pt - pt_prev.cast<double>()) > 0.;
bool left_of_v2 = cross2(v2, pt - pt_this.cast<double>()) > 0.;
return cross2(v1, v2) > 0 ? left_of_v1 && left_of_v2 : // convex corner
left_of_v1 || left_of_v2; // concave corner
}
static bool left_of_segment(const EdgeGrid::Contour &contour, size_t i, const Point &pt_oposite)
{
const Vec2d pt = pt_oposite.cast<double>();
const Point &pt_this = contour.segment_start(i);
const Point &pt_next = contour.segment_end(i);
Vec2d v = (pt_next - pt_this).cast<double>();
return cross2(v, pt - pt_this.cast<double>()) > 0.;
}
} visitor(grid, idx_contour, resampled_point_parameters, 0.5 * compensation * M_PI, search_radius);
out.reserve(contour.size());
@ -441,6 +445,7 @@ Points resample_polygon(const Points &contour, double dist, std::vector<Resample
return out;
}
#if 0
static inline void smooth_compensation(std::vector<float> &compensation, float strength, size_t num_iterations)
{
std::vector<float> out(compensation);
@ -455,6 +460,7 @@ static inline void smooth_compensation(std::vector<float> &compensation, float s
out.swap(compensation);
}
}
#endif
static inline void smooth_compensation_banded(const Points &contour, float band, std::vector<float> &compensation, float strength, size_t num_iterations)
{

View File

@ -6,8 +6,6 @@
#include "Line.hpp"
#include "ClipperUtils.hpp"
#include "SVG.hpp"
#include "polypartition.h"
#include "poly2tri/poly2tri.h"
#include <algorithm>
#include <cassert>
#include <list>
@ -80,6 +78,13 @@ bool ExPolygon::is_valid() const
return true;
}
void ExPolygon::douglas_peucker(double tolerance)
{
this->contour.douglas_peucker(tolerance);
for (Polygon &poly : this->holes)
poly.douglas_peucker(tolerance);
}
bool ExPolygon::contains(const Line &line) const
{
return this->contains(Polyline(line.a, line.b));
@ -311,284 +316,6 @@ ExPolygon::medial_axis(double max_width, double min_width, Polylines* polylines)
polylines->insert(polylines->end(), tp.begin(), tp.end());
}
/*
void ExPolygon::get_trapezoids(Polygons* polygons) const
{
ExPolygons expp;
expp.push_back(*this);
boost::polygon::get_trapezoids(*polygons, expp);
}
void ExPolygon::get_trapezoids(Polygons* polygons, double angle) const
{
ExPolygon clone = *this;
clone.rotate(PI/2 - angle, Point(0,0));
clone.get_trapezoids(polygons);
for (Polygons::iterator polygon = polygons->begin(); polygon != polygons->end(); ++polygon)
polygon->rotate(-(PI/2 - angle), Point(0,0));
}
*/
// This algorithm may return more trapezoids than necessary
// (i.e. it may break a single trapezoid in several because
// other parts of the object have x coordinates in the middle)
void ExPolygon::get_trapezoids2(Polygons* polygons) const
{
// get all points of this ExPolygon
Points pp = *this;
// build our bounding box
BoundingBox bb(pp);
// get all x coordinates
std::vector<coord_t> xx;
xx.reserve(pp.size());
for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p)
xx.push_back(p->x());
std::sort(xx.begin(), xx.end());
// find trapezoids by looping from first to next-to-last coordinate
for (std::vector<coord_t>::const_iterator x = xx.begin(); x != xx.end()-1; ++x) {
coord_t next_x = *(x + 1);
if (*x != next_x)
// intersect with rectangle
// append results to return value
polygons_append(*polygons, intersection({ { { *x, bb.min.y() }, { next_x, bb.min.y() }, { next_x, bb.max.y() }, { *x, bb.max.y() } } }, to_polygons(*this)));
}
}
void ExPolygon::get_trapezoids2(Polygons* polygons, double angle) const
{
ExPolygon clone = *this;
clone.rotate(PI/2 - angle, Point(0,0));
clone.get_trapezoids2(polygons);
for (Polygons::iterator polygon = polygons->begin(); polygon != polygons->end(); ++polygon)
polygon->rotate(-(PI/2 - angle), Point(0,0));
}
// While this triangulates successfully, it's NOT a constrained triangulation
// as it will create more vertices on the boundaries than the ones supplied.
void ExPolygon::triangulate(Polygons* polygons) const
{
// first make trapezoids
Polygons trapezoids;
this->get_trapezoids2(&trapezoids);
// then triangulate each trapezoid
for (Polygons::iterator polygon = trapezoids.begin(); polygon != trapezoids.end(); ++polygon)
polygon->triangulate_convex(polygons);
}
/*
void ExPolygon::triangulate_pp(Polygons* polygons) const
{
// convert polygons
std::list<TPPLPoly> input;
ExPolygons expp = union_ex(simplify_polygons(to_polygons(*this), true));
for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) {
// contour
{
TPPLPoly p;
p.Init(int(ex->contour.points.size()));
//printf("%zu\n0\n", ex->contour.points.size());
for (const Point &point : ex->contour.points) {
size_t i = &point - &ex->contour.points.front();
p[i].x = point(0);
p[i].y = point(1);
//printf("%ld %ld\n", point->x(), point->y());
}
p.SetHole(false);
input.push_back(p);
}
// holes
for (Polygons::const_iterator hole = ex->holes.begin(); hole != ex->holes.end(); ++hole) {
TPPLPoly p;
p.Init(hole->points.size());
//printf("%zu\n1\n", hole->points.size());
for (const Point &point : hole->points) {
size_t i = &point - &hole->points.front();
p[i].x = point(0);
p[i].y = point(1);
//printf("%ld %ld\n", point->x(), point->y());
}
p.SetHole(true);
input.push_back(p);
}
}
// perform triangulation
std::list<TPPLPoly> output;
int res = TPPLPartition().Triangulate_MONO(&input, &output);
if (res != 1)
throw Slic3r::RuntimeError("Triangulation failed");
// convert output polygons
for (std::list<TPPLPoly>::iterator poly = output.begin(); poly != output.end(); ++poly) {
long num_points = poly->GetNumPoints();
Polygon p;
p.points.resize(num_points);
for (long i = 0; i < num_points; ++i) {
p.points[i](0) = coord_t((*poly)[i].x);
p.points[i](1) = coord_t((*poly)[i].y);
}
polygons->push_back(p);
}
}
*/
std::list<TPPLPoly> expoly_to_polypartition_input(const ExPolygon &ex)
{
std::list<TPPLPoly> input;
// contour
{
input.emplace_back();
TPPLPoly &p = input.back();
p.Init(int(ex.contour.points.size()));
for (const Point &point : ex.contour.points) {
size_t i = &point - &ex.contour.points.front();
p[i].x = point(0);
p[i].y = point(1);
}
p.SetHole(false);
}
// holes
for (const Polygon &hole : ex.holes) {
input.emplace_back();
TPPLPoly &p = input.back();
p.Init(hole.points.size());
for (const Point &point : hole.points) {
size_t i = &point - &hole.points.front();
p[i].x = point(0);
p[i].y = point(1);
}
p.SetHole(true);
}
return input;
}
std::list<TPPLPoly> expoly_to_polypartition_input(const ExPolygons &expps)
{
std::list<TPPLPoly> input;
for (const ExPolygon &ex : expps) {
// contour
{
input.emplace_back();
TPPLPoly &p = input.back();
p.Init(int(ex.contour.points.size()));
for (const Point &point : ex.contour.points) {
size_t i = &point - &ex.contour.points.front();
p[i].x = point(0);
p[i].y = point(1);
}
p.SetHole(false);
}
// holes
for (const Polygon &hole : ex.holes) {
input.emplace_back();
TPPLPoly &p = input.back();
p.Init(hole.points.size());
for (const Point &point : hole.points) {
size_t i = &point - &hole.points.front();
p[i].x = point(0);
p[i].y = point(1);
}
p.SetHole(true);
}
}
return input;
}
std::vector<Point> polypartition_output_to_triangles(const std::list<TPPLPoly> &output)
{
size_t num_triangles = 0;
for (const TPPLPoly &poly : output)
if (poly.GetNumPoints() >= 3)
num_triangles += (size_t)poly.GetNumPoints() - 2;
std::vector<Point> triangles;
triangles.reserve(triangles.size() + num_triangles * 3);
for (const TPPLPoly &poly : output) {
long num_points = poly.GetNumPoints();
if (num_points >= 3) {
const TPPLPoint *pt0 = &poly[0];
const TPPLPoint *pt1 = nullptr;
const TPPLPoint *pt2 = &poly[1];
for (long i = 2; i < num_points; ++ i) {
pt1 = pt2;
pt2 = &poly[i];
triangles.emplace_back(coord_t(pt0->x), coord_t(pt0->y));
triangles.emplace_back(coord_t(pt1->x), coord_t(pt1->y));
triangles.emplace_back(coord_t(pt2->x), coord_t(pt2->y));
}
}
}
return triangles;
}
void ExPolygon::triangulate_pp(Points *triangles) const
{
ExPolygons expp = union_ex(simplify_polygons(to_polygons(*this), true));
std::list<TPPLPoly> input = expoly_to_polypartition_input(expp);
// perform triangulation
std::list<TPPLPoly> output;
int res = TPPLPartition().Triangulate_MONO(&input, &output);
// int TPPLPartition::Triangulate_EC(TPPLPolyList *inpolys, TPPLPolyList *triangles) {
if (res != 1)
throw Slic3r::RuntimeError("Triangulation failed");
*triangles = polypartition_output_to_triangles(output);
}
// Uses the Poly2tri library maintained by Jan Niklas Hasse @jhasse // https://github.com/jhasse/poly2tri
// See https://github.com/jhasse/poly2tri/blob/master/README.md for the limitations of the library!
// No duplicate points are allowed, no very close points, holes must not touch outer contour etc.
void ExPolygon::triangulate_p2t(Polygons* polygons) const
{
ExPolygons expp = simplify_polygons_ex(*this, true);
for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) {
// TODO: prevent duplicate points
// contour
std::vector<p2t::Point*> ContourPoints;
for (const Point &pt : ex->contour.points)
// We should delete each p2t::Point object
ContourPoints.push_back(new p2t::Point(pt(0), pt(1)));
p2t::CDT cdt(ContourPoints);
// holes
for (Polygons::const_iterator hole = ex->holes.begin(); hole != ex->holes.end(); ++hole) {
std::vector<p2t::Point*> points;
for (const Point &pt : hole->points)
// will be destructed in SweepContext::~SweepContext
points.push_back(new p2t::Point(pt(0), pt(1)));
cdt.AddHole(points);
}
// perform triangulation
try {
cdt.Triangulate();
std::vector<p2t::Triangle*> triangles = cdt.GetTriangles();
for (std::vector<p2t::Triangle*>::const_iterator triangle = triangles.begin(); triangle != triangles.end(); ++triangle) {
Polygon p;
for (int i = 0; i <= 2; ++i) {
p2t::Point* point = (*triangle)->GetPoint(i);
p.points.push_back(Point(point->x, point->y));
}
polygons->push_back(p);
}
} catch (const Slic3r::RuntimeError & /* err */) {
assert(false);
// just ignore, don't triangulate
}
for (p2t::Point *ptr : ContourPoints)
delete ptr;
}
}
Lines ExPolygon::lines() const
{
Lines lines = this->contour.lines();

View File

@ -6,9 +6,6 @@
#include "Polyline.hpp"
#include <vector>
// polygon class of the polypartition library
class TPPLPoly;
namespace Slic3r {
class ExPolygon;
@ -49,6 +46,7 @@ public:
double area() const;
bool empty() const { return contour.points.empty(); }
bool is_valid() const;
void douglas_peucker(double tolerance);
// Contains the line / polyline / polylines etc COMPLETELY.
bool contains(const Line &line) const;
@ -69,14 +67,6 @@ public:
void simplify(double tolerance, ExPolygons* expolygons) const;
void medial_axis(double max_width, double min_width, ThickPolylines* polylines) const;
void medial_axis(double max_width, double min_width, Polylines* polylines) const;
// void get_trapezoids(Polygons* polygons) const;
// void get_trapezoids(Polygons* polygons, double angle) const;
void get_trapezoids2(Polygons* polygons) const;
void get_trapezoids2(Polygons* polygons, double angle) const;
void triangulate(Polygons* polygons) const;
// Triangulate into triples of points.
void triangulate_pp(Points *triangles) const;
void triangulate_p2t(Polygons* polygons) const;
Lines lines() const;
// Number of contours (outer contour with holes).
@ -249,6 +239,24 @@ inline Polygons to_polygons(ExPolygons &&src)
return polygons;
}
inline ExPolygons to_expolygons(const Polygons &polys)
{
ExPolygons ex_polys;
ex_polys.assign(polys.size(), ExPolygon());
for (size_t idx = 0; idx < polys.size(); ++idx)
ex_polys[idx].contour = polys[idx];
return ex_polys;
}
inline ExPolygons to_expolygons(Polygons &&polys)
{
ExPolygons ex_polys;
ex_polys.assign(polys.size(), ExPolygon());
for (size_t idx = 0; idx < polys.size(); ++idx)
ex_polys[idx].contour = std::move(polys[idx]);
return ex_polys;
}
inline void polygons_append(Polygons &dst, const ExPolygon &src)
{
dst.reserve(dst.size() + src.holes.size() + 1);
@ -330,10 +338,6 @@ extern std::vector<BoundingBox> get_extents_vector(const ExPolygons &polygons);
extern bool remove_sticks(ExPolygon &poly);
extern void keep_largest_contour_only(ExPolygons &polygons);
extern std::list<TPPLPoly> expoly_to_polypartition_input(const ExPolygons &expp);
extern std::list<TPPLPoly> expoly_to_polypartition_input(const ExPolygon &ex);
extern std::vector<Point> polypartition_output_to_triangles(const std::list<TPPLPoly> &output);
inline double area(const ExPolygons &polys)
{
double s = 0.;

View File

@ -7,6 +7,7 @@
#include <assert.h>
#include <string_view>
#include <numeric>
namespace Slic3r {
@ -102,6 +103,7 @@ public:
virtual double min_mm3_per_mm() const = 0;
virtual Polyline as_polyline() const = 0;
virtual void collect_polylines(Polylines &dst) const = 0;
virtual void collect_points(Points &dst) const = 0;
virtual Polylines as_polylines() const { Polylines dst; this->collect_polylines(dst); return dst; }
virtual double length() const = 0;
virtual double total_volume() const = 0;
@ -167,6 +169,7 @@ public:
double min_mm3_per_mm() const override { return this->mm3_per_mm; }
Polyline as_polyline() const override { return this->polyline; }
void collect_polylines(Polylines &dst) const override { if (! this->polyline.empty()) dst.emplace_back(this->polyline); }
void collect_points(Points &dst) const override { append(dst, this->polyline.points); }
double total_volume() const override { return mm3_per_mm * unscale<double>(length()); }
private:
@ -217,6 +220,12 @@ public:
double min_mm3_per_mm() const override;
Polyline as_polyline() const override;
void collect_polylines(Polylines &dst) const override { Polyline pl = this->as_polyline(); if (! pl.empty()) dst.emplace_back(std::move(pl)); }
void collect_points(Points &dst) const override {
size_t n = std::accumulate(paths.begin(), paths.end(), 0, [](const size_t n, const ExtrusionPath &p){ return n + p.polyline.size(); });
dst.reserve(dst.size() + n);
for (const ExtrusionPath &p : this->paths)
append(dst, p.polyline.points);
}
double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; }
};
@ -268,6 +277,12 @@ public:
double min_mm3_per_mm() const override;
Polyline as_polyline() const override { return this->polygon().split_at_first_point(); }
void collect_polylines(Polylines &dst) const override { Polyline pl = this->as_polyline(); if (! pl.empty()) dst.emplace_back(std::move(pl)); }
void collect_points(Points &dst) const override {
size_t n = std::accumulate(paths.begin(), paths.end(), 0, [](const size_t n, const ExtrusionPath &p){ return n + p.polyline.size(); });
dst.reserve(dst.size() + n);
for (const ExtrusionPath &p : this->paths)
append(dst, p.polyline.points);
}
double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; }
//static inline std::string role_to_string(ExtrusionLoopRole role);
@ -343,6 +358,25 @@ inline void extrusion_entities_append_loops(ExtrusionEntitiesPtr &dst, Polygons
loops.clear();
}
inline void extrusion_entities_append_loops_and_paths(ExtrusionEntitiesPtr &dst, Polylines &&polylines, ExtrusionRole role, double mm3_per_mm, float width, float height)
{
dst.reserve(dst.size() + polylines.size());
for (Polyline &polyline : polylines) {
if (polyline.is_valid()) {
if (polyline.is_closed()) {
ExtrusionPath extrusion_path(role, mm3_per_mm, width, height);
extrusion_path.polyline = std::move(polyline);
dst.emplace_back(new ExtrusionLoop(std::move(extrusion_path)));
} else {
ExtrusionPath *extrusion_path = new ExtrusionPath(role, mm3_per_mm, width, height);
extrusion_path->polyline = std::move(polyline);
dst.emplace_back(extrusion_path);
}
}
}
polylines.clear();
}
}
#endif

View File

@ -117,6 +117,11 @@ public:
extrusion_entity->collect_polylines(dst);
}
void collect_points(Points &dst) const override {
for (ExtrusionEntity* extrusion_entity : this->entities)
extrusion_entity->collect_points(dst);
}
double length() const override {
throw Slic3r::RuntimeError("Calling length() on a ExtrusionEntityCollection");
return 0.;

View File

@ -25,7 +25,7 @@ struct SurfaceFillParams
// in unscaled coordinates
coordf_t spacing = 0.;
// infill / perimeter overlap, in unscaled coordinates
coordf_t overlap = 0.;
// coordf_t overlap = 0.;
// Angle as provided by the region config, in radians.
float angle = 0.f;
// Non-negative for a bridge.
@ -34,7 +34,7 @@ struct SurfaceFillParams
// FillParams
float density = 0.f;
// Don't adjust spacing to fill the space evenly.
bool dont_adjust = false;
// bool dont_adjust = false;
// Length of the infill anchor along the perimeter line.
// 1000mm is roughly the maximum length line that fits into a 32bit coord_t.
float anchor_length = 1000.f;
@ -64,10 +64,10 @@ struct SurfaceFillParams
RETURN_COMPARE_NON_EQUAL(extruder);
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, pattern);
RETURN_COMPARE_NON_EQUAL(spacing);
RETURN_COMPARE_NON_EQUAL(overlap);
// RETURN_COMPARE_NON_EQUAL(overlap);
RETURN_COMPARE_NON_EQUAL(angle);
RETURN_COMPARE_NON_EQUAL(density);
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust);
// RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust);
RETURN_COMPARE_NON_EQUAL(anchor_length);
RETURN_COMPARE_NON_EQUAL(anchor_length_max);
RETURN_COMPARE_NON_EQUAL(flow.width);
@ -83,10 +83,10 @@ struct SurfaceFillParams
this->pattern == rhs.pattern &&
this->pattern == rhs.pattern &&
this->spacing == rhs.spacing &&
this->overlap == rhs.overlap &&
// this->overlap == rhs.overlap &&
this->angle == rhs.angle &&
this->density == rhs.density &&
this->dont_adjust == rhs.dont_adjust &&
// this->dont_adjust == rhs.dont_adjust &&
this->anchor_length == rhs.anchor_length &&
this->anchor_length_max == rhs.anchor_length_max &&
this->flow == rhs.flow &&
@ -130,7 +130,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
params.density = 100.f;
params.pattern = (surface.is_external() && ! is_bridge) ?
(surface.is_top() ? region_config.top_fill_pattern.value : region_config.bottom_fill_pattern.value) :
ipRectilinear;
region_config.top_fill_pattern == ipMonotonic ? ipMonotonic : ipRectilinear;
} else if (params.density <= 0)
continue;
@ -158,6 +158,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
params.spacing = params.flow.spacing();
// Don't limit anchor length for solid or bridging infill.
params.anchor_length = 1000.f;
params.anchor_length_max = 1000.f;
} else {
// it's internal infill, so we can calculate a generic flow spacing
// for all layers, for avoiding the ugly effect of
@ -173,13 +174,13 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
).spacing();
// Anchor a sparse infill to inner perimeters with the following anchor length:
params.anchor_length = float(region_config.infill_anchor);
if (region_config.infill_anchor.percent)
params.anchor_length = float(params.anchor_length * 0.01 * params.spacing);
params.anchor_length_max = float(region_config.infill_anchor_max);
if (region_config.infill_anchor_max.percent)
params.anchor_length_max = float(params.anchor_length_max * 0.01 * params.spacing);
}
params.anchor_length = std::min(params.anchor_length, params.anchor_length_max);
if (region_config.infill_anchor.percent)
params.anchor_length = float(params.anchor_length * 0.01 * params.spacing);
params.anchor_length_max = float(region_config.infill_anchor_max);
if (region_config.infill_anchor_max.percent)
params.anchor_length_max = float(params.anchor_length_max * 0.01 * params.spacing);
params.anchor_length = std::min(params.anchor_length, params.anchor_length_max);
}
auto it_params = set_surface_params.find(params);
if (it_params == set_surface_params.end())
@ -284,7 +285,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
if (internal_solid_fill == nullptr) {
// Produce another solid fill.
params.extruder = layerm.region()->extruder(frSolidInfill);
params.pattern = ipRectilinear;
params.pattern = layerm.region()->config().top_fill_pattern == ipMonotonic ? ipMonotonic : ipRectilinear;
params.density = 100.f;
params.extrusion_role = erInternalInfill;
params.angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
@ -384,7 +385,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
// apply half spacing using this flow's own spacing and generate infill
FillParams params;
params.density = float(0.01 * surface_fill.params.density);
params.dont_adjust = surface_fill.params.dont_adjust; // false
params.dont_adjust = false; // surface_fill.params.dont_adjust;
params.anchor_length = surface_fill.params.anchor_length;
params.anchor_length_max = surface_fill.params.anchor_length_max;
@ -532,6 +533,7 @@ void Layer::make_ironing()
}
}
if (ironing_params.extruder != -1) {
//TODO just_infill is currently not used.
ironing_params.just_infill = false;
ironing_params.line_spacing = config.ironing_spacing;
ironing_params.height = default_layer_height * 0.01 * config.ironing_flowrate;
@ -562,17 +564,54 @@ void Layer::make_ironing()
ExPolygons ironing_areas;
double nozzle_dmr = this->object()->print()->config().nozzle_diameter.values[ironing_params.extruder - 1];
if (ironing_params.just_infill) {
//TODO just_infill is currently not used.
// Just infill.
} else {
// Infill and perimeter.
// Merge top surfaces with the same ironing parameters.
Polygons polys;
for (size_t k = i; k < j; ++ k)
for (const Surface &surface : by_extruder[k].layerm->slices.surfaces)
if (surface.surface_type == stTop)
Polygons infills;
for (size_t k = i; k < j; ++ k) {
const IroningParams &ironing_params = by_extruder[k];
const PrintRegionConfig &region_config = ironing_params.layerm->region()->config();
bool iron_everything = region_config.ironing_type == IroningType::AllSolid;
bool iron_completely = iron_everything;
if (iron_everything) {
// Check whether there is any non-solid hole in the regions.
bool internal_infill_solid = region_config.fill_density.value > 95.;
for (const Surface &surface : ironing_params.layerm->fill_surfaces.surfaces)
if ((! internal_infill_solid && surface.surface_type == stInternal) || surface.surface_type == stInternalBridge || surface.surface_type == stInternalVoid) {
// Some fill region is not quite solid. Don't iron over the whole surface.
iron_completely = false;
break;
}
}
if (iron_completely) {
// Iron everything. This is likely only good for solid transparent objects.
for (const Surface &surface : ironing_params.layerm->slices.surfaces)
polygons_append(polys, surface.expolygon);
} else {
for (const Surface &surface : ironing_params.layerm->slices.surfaces)
if (surface.surface_type == stTop || (iron_everything && surface.surface_type == stBottom))
// stBottomBridge is not being ironed on purpose, as it would likely destroy the bridges.
polygons_append(polys, surface.expolygon);
}
if (iron_everything && ! iron_completely) {
// Add solid fill surfaces. This may not be ideal, as one will not iron perimeters touching these
// solid fill surfaces, but it is likely better than nothing.
for (const Surface &surface : ironing_params.layerm->fill_surfaces.surfaces)
if (surface.surface_type == stInternalSolid)
polygons_append(infills, surface.expolygon);
}
}
// Trim the top surfaces with half the nozzle diameter.
ironing_areas = intersection_ex(polys, offset(this->lslices, - float(scale_(0.5 * nozzle_dmr))));
if (! infills.empty()) {
// For IroningType::AllSolid only:
// Add solid infill areas for layers, that contain some non-ironable infil (sparse infill, bridge infill).
append(infills, to_polygons(std::move(ironing_areas)));
ironing_areas = union_ex(infills, true);
}
}
// Create the filler object.

View File

@ -678,6 +678,7 @@ static inline bool line_rounded_thick_segment_collision(
return intersects;
}
#ifndef NDEBUG
static inline bool inside_interval(double low, double high, double p)
{
return p >= low && p <= high;
@ -702,6 +703,7 @@ static inline bool cyclic_interval_inside_interval(double outer_low, double oute
}
return interval_inside_interval(outer_low, outer_high, inner_low, inner_high, double(SCALED_EPSILON));
}
#endif // NDEBUG
// #define INFILL_DEBUG_OUTPUT
@ -1129,7 +1131,7 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Po
intersection_points.reserve(infill_ordered.size() * 2);
for (const Polyline &pl : infill_ordered)
for (const Point *pt : { &pl.points.front(), &pl.points.back() }) {
EdgeGrid::Grid::ClosestPointResult cp = grid.closest_point(*pt, coord_t(SCALED_EPSILON));
EdgeGrid::Grid::ClosestPointResult cp = grid.closest_point_signed_distance(*pt, coord_t(SCALED_EPSILON));
if (cp.valid()) {
// The infill end point shall lie on the contour.
assert(cp.distance <= 3.);

View File

@ -2245,22 +2245,22 @@ static std::vector<MonotonicRegionLink> chain_monotonic_regions(
#endif /* NDEBUG */
// How many times to repeat the ant simulation (number of ant generations).
constexpr int num_rounds = 25;
constexpr int const num_rounds = 25;
// After how many rounds without an improvement to exit?
constexpr int num_rounds_no_change_exit = 8;
constexpr int const num_rounds_no_change_exit = 8;
// With how many ants each of the run will be performed?
const int num_ants = std::min(int(regions.size()), 10);
const int num_ants = std::min(int(regions.size()), 10);
// Base (initial) pheromone level. This value will be adjusted based on the length of the first greedy path found.
float pheromone_initial_deposit = 0.5f;
float pheromone_initial_deposit = 0.5f;
// Evaporation rate of pheromones.
constexpr float pheromone_evaporation = 0.1f;
constexpr float const pheromone_evaporation = 0.1f;
// Evaporation rate to diversify paths taken by individual ants.
constexpr float pheromone_diversification = 0.1f;
constexpr float const pheromone_diversification = 0.1f;
// Probability at which to take the next best path. Otherwise take the the path based on the cost distribution.
constexpr float probability_take_best = 0.9f;
constexpr float const probability_take_best = 0.9f;
// Exponents of the cost function.
constexpr float pheromone_alpha = 1.f; // pheromone exponent
constexpr float pheromone_beta = 2.f; // attractiveness weighted towards edge length
constexpr float const pheromone_alpha = 1.f; // pheromone exponent
constexpr float const pheromone_beta = 2.f; // attractiveness weighted towards edge length
AntPathMatrix path_matrix(regions, poly_with_offset, segs, pheromone_initial_deposit);
@ -2332,7 +2332,12 @@ static std::vector<MonotonicRegionLink> chain_monotonic_regions(
}
// Probability (unnormalized) of traversing a link between two monotonic regions.
auto path_probability = [pheromone_alpha, pheromone_beta](AntPath &path) {
auto path_probability = [
#ifndef __APPLE__
// clang complains when capturing constexpr constants.
pheromone_alpha, pheromone_beta
#endif // __APPLE__
](AntPath &path) {
return pow(path.pheromone, pheromone_alpha) * pow(path.visibility, pheromone_beta);
};

View File

@ -12,7 +12,7 @@ class Surface;
class FillRectilinear : public Fill
{
public:
Fill* clone() const override { return new FillRectilinear(*this); };
Fill* clone() const override { return new FillRectilinear(*this); }
~FillRectilinear() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
@ -32,18 +32,18 @@ protected:
class FillAlignedRectilinear : public FillRectilinear
{
public:
Fill* clone() const override { return new FillAlignedRectilinear(*this); };
Fill* clone() const override { return new FillAlignedRectilinear(*this); }
~FillAlignedRectilinear() override = default;
protected:
// Always generate infill at the same angle.
virtual float _layer_angle(size_t idx) const { return 0.f; }
virtual float _layer_angle(size_t idx) const override { return 0.f; }
};
class FillMonotonic : public FillRectilinear
{
public:
Fill* clone() const override { return new FillMonotonic(*this); };
Fill* clone() const override { return new FillMonotonic(*this); }
~FillMonotonic() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
bool no_sort() const override { return true; }
@ -52,7 +52,7 @@ public:
class FillGrid : public FillRectilinear
{
public:
Fill* clone() const override { return new FillGrid(*this); };
Fill* clone() const override { return new FillGrid(*this); }
~FillGrid() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
@ -64,7 +64,7 @@ protected:
class FillTriangles : public FillRectilinear
{
public:
Fill* clone() const override { return new FillTriangles(*this); };
Fill* clone() const override { return new FillTriangles(*this); }
~FillTriangles() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
@ -76,7 +76,7 @@ protected:
class FillStars : public FillRectilinear
{
public:
Fill* clone() const override { return new FillStars(*this); };
Fill* clone() const override { return new FillStars(*this); }
~FillStars() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
@ -88,7 +88,7 @@ protected:
class FillCubic : public FillRectilinear
{
public:
Fill* clone() const override { return new FillCubic(*this); };
Fill* clone() const override { return new FillCubic(*this); }
~FillCubic() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
@ -98,6 +98,6 @@ protected:
};
}; // namespace Slic3r
} // namespace Slic3r
#endif // slic3r_FillRectilinear_hpp_

View File

@ -19,9 +19,8 @@
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/nowide/fstream.hpp>
#include <boost/nowide/cstdio.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/log/trivial.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
@ -116,6 +115,7 @@ static constexpr const char* SOURCE_OFFSET_X_KEY = "source_offset_x";
static constexpr const char* SOURCE_OFFSET_Y_KEY = "source_offset_y";
static constexpr const char* SOURCE_OFFSET_Z_KEY = "source_offset_z";
static constexpr const char* SOURCE_IN_INCHES = "source_in_inches";
static constexpr const char* SOURCE_IN_METERS = "source_in_meters";
const unsigned int VALID_OBJECT_TYPES_COUNT = 1;
const char* VALID_OBJECT_TYPES[] =
@ -123,7 +123,6 @@ const char* VALID_OBJECT_TYPES[] =
"model"
};
const unsigned int INVALID_OBJECT_TYPES_COUNT = 4;
const char* INVALID_OBJECT_TYPES[] =
{
"solidsupport",
@ -257,9 +256,8 @@ namespace Slic3r {
public:
void log_errors()
{
for (const std::string& error : m_errors) {
printf("%s\n", error.c_str());
}
for (const std::string& error : m_errors)
BOOST_LOG_TRIVIAL(error) << error;
}
};
@ -392,6 +390,10 @@ namespace Slic3r {
bool m_check_version;
XML_Parser m_xml_parser;
// Error code returned by the application side of the parser. In that case the expat may not reliably deliver the error state
// after returning from XML_Parse() function, thus we keep the error state here.
bool m_parse_error { false };
std::string m_parse_error_message;
Model* m_model;
float m_unit_factor;
CurrentObject m_curr_object;
@ -417,7 +419,16 @@ namespace Slic3r {
private:
void _destroy_xml_parser();
void _stop_xml_parser();
void _stop_xml_parser(const std::string& msg = std::string());
bool parse_error() const { return m_parse_error; }
const char* parse_error_message() const {
return m_parse_error ?
// The error was signalled by the user code, not the expat parser.
(m_parse_error_message.empty() ? "Invalid 3MF format" : m_parse_error_message.c_str()) :
// The error was signalled by the expat parser.
XML_ErrorString(XML_GetErrorCode(m_xml_parser));
}
bool _load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config);
bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
@ -556,10 +567,14 @@ namespace Slic3r {
}
}
void _3MF_Importer::_stop_xml_parser()
void _3MF_Importer::_stop_xml_parser(const std::string &msg)
{
if (m_xml_parser != nullptr)
XML_StopParser(m_xml_parser, false);
assert(! m_parse_error);
assert(m_parse_error_message.empty());
assert(m_xml_parser != nullptr);
m_parse_error = true;
m_parse_error_message = msg;
XML_StopParser(m_xml_parser, false);
}
bool _3MF_Importer::_load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config)
@ -659,7 +674,7 @@ namespace Slic3r {
// select the geometry associated with the original model object
const Geometry* geometry = nullptr;
for (const IdToModelObjectMap::value_type& object : m_objects) {
if (static_cast<int>(object.second) == i) {
if (object.second == int(i)) {
IdToGeometryMap::const_iterator obj_geometry = m_geometries.find(object.first);
if (obj_geometry == m_geometries.end()) {
add_error("Unable to find object geometry");
@ -695,6 +710,10 @@ namespace Slic3r {
#endif // ENABLE_RELOAD_FROM_DISK_FOR_3MF
for (const IdToModelObjectMap::value_type& object : m_objects) {
if (object.second >= int(m_model->objects.size())) {
add_error("Unable to find object");
return false;
}
ModelObject* model_object = m_model->objects[object.second];
IdToGeometryMap::const_iterator obj_geometry = m_geometries.find(object.first);
if (obj_geometry == m_geometries.end()) {
@ -802,12 +821,13 @@ namespace Slic3r {
struct CallbackData
{
XML_Parser& parser;
_3MF_Importer& importer;
const mz_zip_archive_file_stat& stat;
CallbackData(XML_Parser& parser, const mz_zip_archive_file_stat& stat) : parser(parser), stat(stat) {}
CallbackData(XML_Parser& parser, _3MF_Importer& importer, const mz_zip_archive_file_stat& stat) : parser(parser), importer(importer), stat(stat) {}
};
CallbackData data(m_xml_parser, stat);
CallbackData data(m_xml_parser, *this, stat);
mz_bool res = 0;
@ -815,9 +835,9 @@ namespace Slic3r {
{
res = mz_zip_reader_extract_file_to_callback(&archive, stat.m_filename, [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t {
CallbackData* data = (CallbackData*)pOpaque;
if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0)) {
if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->importer.parse_error()) {
char error_buf[1024];
::sprintf(error_buf, "Error (%s) while parsing '%s' at line %d", XML_ErrorString(XML_GetErrorCode(data->parser)), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
::sprintf(error_buf, "Error (%s) while parsing '%s' at line %d", data->importer.parse_error_message(), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
throw Slic3r::FileIOError(error_buf);
}
@ -1221,7 +1241,8 @@ namespace Slic3r {
CustomGCode::Type type;
std::string extra;
if (tree.find("type") == tree.not_found()) {
pt::ptree attr_tree = tree.find("<xmlattr>")->second;
if (attr_tree.find("type") == attr_tree.not_found()) {
// It means that data was saved in old version (2.2.0 and older) of PrusaSlicer
// read old data ...
std::string gcode = tree.get<std::string> ("<xmlattr>.gcode");
@ -1374,6 +1395,10 @@ namespace Slic3r {
{
// deletes all non-built or non-instanced objects
for (const IdToModelObjectMap::value_type& object : m_objects) {
if (object.second >= int(m_model->objects.size())) {
add_error("Unable to find object");
return false;
}
ModelObject *model_object = m_model->objects[object.second];
if (model_object != nullptr && model_object->instances.size() == 0)
m_model->delete_object(model_object);
@ -1834,6 +1859,10 @@ namespace Slic3r {
stl_facet& facet = stl.facet_start[i];
for (unsigned int v = 0; v < 3; ++v) {
unsigned int tri_id = geometry.triangles[src_start_id + ii + v] * 3;
if (tri_id + 2 >= geometry.vertices.size()) {
add_error("Malformed triangle mesh");
return false;
}
facet.vertex[v] = Vec3f(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]);
}
}
@ -1850,10 +1879,6 @@ namespace Slic3r {
triangle_mesh.transform(object.instances.front()->get_transformation().get_matrix());
object.instances.front()->set_transformation(Slic3r::Geometry::Transformation());
}
else {
std::cout << "non-single instance !!!\n";
int a = 0;
}
}
#endif // ENABLE_RELOAD_FROM_DISK_FOR_3MF
@ -1897,6 +1922,8 @@ namespace Slic3r {
volume->source.mesh_offset(2) = ::atof(metadata.value.c_str());
else if (metadata.key == SOURCE_IN_INCHES)
volume->source.is_converted_from_inches = metadata.value == "1";
else if (metadata.key == SOURCE_IN_METERS)
volume->source.is_converted_from_meters = metadata.value == "1";
else
volume->config.set_deserialize(metadata.key, metadata.value);
}
@ -2414,7 +2441,7 @@ namespace Slic3r {
if (!volume->mesh().has_shared_vertices())
throw Slic3r::FileIOError("store_3mf() requires shared vertices");
volumes_offsets.insert({ volume, Offsets(vertices_count) }).first;
volumes_offsets.insert({ volume, Offsets(vertices_count) });
const indexed_triangle_set &its = volume->mesh().its;
if (its.vertices.empty()) {
@ -2806,6 +2833,8 @@ namespace Slic3r {
}
if (volume->source.is_converted_from_inches)
stream << prefix << SOURCE_IN_INCHES << "\" " << VALUE_ATTR << "=\"1\"/>\n";
if (volume->source.is_converted_from_meters)
stream << prefix << SOURCE_IN_METERS << "\" " << VALUE_ATTR << "=\"1\"/>\n";
}
// stores volume's config data

View File

@ -24,6 +24,7 @@ namespace pt = boost::property_tree;
#include <boost/filesystem/operations.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/log/trivial.hpp>
#include <boost/nowide/fstream.hpp>
#include "miniz_extension.hpp"
@ -63,23 +64,31 @@ namespace Slic3r
struct AMFParserContext
{
AMFParserContext(XML_Parser parser, DynamicPrintConfig* config, Model* model) :
m_version(0),
m_parser(parser),
m_model(*model),
m_object(nullptr),
m_volume(nullptr),
m_material(nullptr),
m_instance(nullptr),
m_config(config)
{
m_path.reserve(12);
}
void stop()
void stop(const std::string &msg = std::string())
{
assert(! m_error);
assert(m_error_message.empty());
m_error = true;
m_error_message = msg;
XML_StopParser(m_parser, 0);
}
bool error() const { return m_error; }
const char* error_message() const {
return m_error ?
// The error was signalled by the user code, not the expat parser.
(m_error_message.empty() ? "Invalid AMF format" : m_error_message.c_str()) :
// The error was signalled by the expat parser.
XML_ErrorString(XML_GetErrorCode(m_parser));
}
void startElement(const char *name, const char **atts);
void endElement(const char *name);
void endDocument();
@ -217,33 +226,37 @@ struct AMFParserContext
};
// Version of the amf file
unsigned int m_version;
unsigned int m_version { 0 };
// Current Expat XML parser instance.
XML_Parser m_parser;
// Error code returned by the application side of the parser. In that case the expat may not reliably deliver the error state
// after returning from XML_Parse() function, thus we keep the error state here.
bool m_error { false };
std::string m_error_message;
// Model to receive objects extracted from an AMF file.
Model &m_model;
// Current parsing path in the XML file.
std::vector<AMFNodeType> m_path;
// Current object allocated for an amf/object XML subtree.
ModelObject *m_object;
ModelObject *m_object { nullptr };
// Map from obect name to object idx & instances.
std::map<std::string, Object> m_object_instances_map;
// Vertices parsed for the current m_object.
std::vector<float> m_object_vertices;
// Current volume allocated for an amf/object/mesh/volume subtree.
ModelVolume *m_volume;
ModelVolume *m_volume { nullptr };
// Faces collected for the current m_volume.
std::vector<int> m_volume_facets;
// Transformation matrix of a volume mesh from its coordinate system to Object's coordinate system.
Transform3d m_volume_transform;
// Current material allocated for an amf/metadata subtree.
ModelMaterial *m_material;
ModelMaterial *m_material { nullptr };
// Current instance allocated for an amf/constellation/instance subtree.
Instance *m_instance;
Instance *m_instance { nullptr };
// Generic string buffer for vertices, face indices, metadata etc.
std::string m_value[5];
// Pointer to config to update if config data are stored inside the amf file
DynamicPrintConfig *m_config;
DynamicPrintConfig *m_config { nullptr };
private:
AMFParserContext& operator=(AMFParserContext&);
@ -591,9 +604,9 @@ void AMFParserContext::endElement(const char * /* name */)
// Faces of the current volume:
case NODE_TYPE_TRIANGLE:
assert(m_object && m_volume);
m_volume_facets.push_back(atoi(m_value[0].c_str()));
m_volume_facets.push_back(atoi(m_value[1].c_str()));
m_volume_facets.push_back(atoi(m_value[2].c_str()));
m_volume_facets.emplace_back(atoi(m_value[0].c_str()));
m_volume_facets.emplace_back(atoi(m_value[1].c_str()));
m_volume_facets.emplace_back(atoi(m_value[2].c_str()));
m_value[0].clear();
m_value[1].clear();
m_value[2].clear();
@ -616,6 +629,10 @@ void AMFParserContext::endElement(const char * /* name */)
for (unsigned int v = 0; v < 3; ++v)
{
unsigned int tri_id = m_volume_facets[i++] * 3;
if (tri_id < 0 || tri_id + 2 >= m_object_vertices.size()) {
this->stop("Malformed triangle mesh");
return;
}
facet.vertex[v] = Vec3f(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]);
}
}
@ -781,6 +798,9 @@ void AMFParserContext::endElement(const char * /* name */)
else if (strcmp(opt_key, "source_in_inches") == 0) {
m_volume->source.is_converted_from_inches = m_value[1] == "1";
}
else if (strcmp(opt_key, "source_in_meters") == 0) {
m_volume->source.is_converted_from_meters = m_value[1] == "1";
}
}
} else if (m_path.size() == 3) {
if (m_path[1] == NODE_TYPE_MATERIAL) {
@ -811,7 +831,7 @@ void AMFParserContext::endDocument()
{
for (const auto &object : m_object_instances_map) {
if (object.second.idx == -1) {
printf("Undefined object %s referenced in constellation\n", object.first.c_str());
BOOST_LOG_TRIVIAL(error) << "Undefined object " << object.first.c_str() << " referenced in constellation";
continue;
}
for (const Instance &instance : object.second.instances)
@ -834,13 +854,13 @@ bool load_amf_file(const char *path, DynamicPrintConfig *config, Model *model)
XML_Parser parser = XML_ParserCreate(nullptr); // encoding
if (!parser) {
printf("Couldn't allocate memory for parser\n");
BOOST_LOG_TRIVIAL(error) << "Couldn't allocate memory for parser";
return false;
}
FILE *pFile = boost::nowide::fopen(path, "rt");
if (pFile == nullptr) {
printf("Cannot open file %s\n", path);
BOOST_LOG_TRIVIAL(error) << "Cannot open file " << path;
return false;
}
@ -854,14 +874,12 @@ bool load_amf_file(const char *path, DynamicPrintConfig *config, Model *model)
for (;;) {
int len = (int)fread(buff, 1, 8192, pFile);
if (ferror(pFile)) {
printf("AMF parser: Read error\n");
BOOST_LOG_TRIVIAL(error) << "AMF parser: Read error";
break;
}
int done = feof(pFile);
if (XML_Parse(parser, buff, len, done) == XML_STATUS_ERROR) {
printf("AMF parser: Parse error at line %d:\n%s\n",
(int)XML_GetCurrentLineNumber(parser),
XML_ErrorString(XML_GetErrorCode(parser)));
if (XML_Parse(parser, buff, len, done) == XML_STATUS_ERROR || ctx.error()) {
BOOST_LOG_TRIVIAL(error) << "AMF parser: Parse error at line " << int(XML_GetCurrentLineNumber(parser)) << ": " << ctx.error_message();
break;
}
if (done) {
@ -892,14 +910,14 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
{
if (stat.m_uncomp_size == 0)
{
printf("Found invalid size\n");
BOOST_LOG_TRIVIAL(error) << "Found invalid size";
close_zip_reader(&archive);
return false;
}
XML_Parser parser = XML_ParserCreate(nullptr); // encoding
if (!parser) {
printf("Couldn't allocate memory for parser\n");
BOOST_LOG_TRIVIAL(error) << "Couldn't allocate memory for parser";
close_zip_reader(&archive);
return false;
}
@ -912,12 +930,13 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
struct CallbackData
{
XML_Parser& parser;
AMFParserContext& ctx;
const mz_zip_archive_file_stat& stat;
CallbackData(XML_Parser& parser, const mz_zip_archive_file_stat& stat) : parser(parser), stat(stat) {}
CallbackData(XML_Parser& parser, AMFParserContext& ctx, const mz_zip_archive_file_stat& stat) : parser(parser), ctx(ctx), stat(stat) {}
};
CallbackData data(parser, stat);
CallbackData data(parser, ctx, stat);
mz_bool res = 0;
@ -925,10 +944,10 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
{
res = mz_zip_reader_extract_file_to_callback(&archive, stat.m_filename, [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t {
CallbackData* data = (CallbackData*)pOpaque;
if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0))
if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->ctx.error())
{
char error_buf[1024];
::sprintf(error_buf, "Error (%s) while parsing '%s' at line %d", XML_ErrorString(XML_GetErrorCode(data->parser)), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
::sprintf(error_buf, "Error (%s) while parsing '%s' at line %d", data->ctx.error_message(), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
throw Slic3r::FileIOError(error_buf);
}
@ -937,14 +956,14 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
}
catch (std::exception& e)
{
printf("%s\n", e.what());
BOOST_LOG_TRIVIAL(error) << "Error reading AMF file: " << e.what();
close_zip_reader(&archive);
return false;
}
if (res == 0)
{
printf("Error while extracting model data from zip archive");
BOOST_LOG_TRIVIAL(error) << "Error while extracting model data from zip archive";
close_zip_reader(&archive);
return false;
}
@ -973,7 +992,7 @@ bool load_amf_archive(const char* path, DynamicPrintConfig* config, Model* model
if (!open_zip_reader(&archive, path))
{
printf("Unable to init zip reader\n");
BOOST_LOG_TRIVIAL(error) << "Unable to init zip reader";
return false;
}
@ -992,7 +1011,7 @@ bool load_amf_archive(const char* path, DynamicPrintConfig* config, Model* model
if (!extract_model_from_archive(archive, stat, config, model, check_version))
{
close_zip_reader(&archive);
printf("Archive does not contain a valid model");
BOOST_LOG_TRIVIAL(error) << "Archive does not contain a valid model";
return false;
}
}
@ -1216,6 +1235,8 @@ bool store_amf(const char* path, Model* model, const DynamicPrintConfig* config,
}
if (volume->source.is_converted_from_inches)
stream << " <metadata type=\"slic3r.source_in_inches\">1</metadata>\n";
if (volume->source.is_converted_from_meters)
stream << " <metadata type=\"slic3r.source_in_meters\">1</metadata>\n";
stream << std::setprecision(std::numeric_limits<float>::max_digits10);
const indexed_triangle_set &its = volume->mesh().its;
for (size_t i = 0; i < its.indices.size(); ++i) {
@ -1231,7 +1252,7 @@ bool store_amf(const char* path, Model* model, const DynamicPrintConfig* config,
if (!object->instances.empty()) {
for (ModelInstance *instance : object->instances) {
char buf[512];
sprintf(buf,
::sprintf(buf,
" <instance objectid=\"%zu\">\n"
" <deltax>%lf</deltax>\n"
" <deltay>%lf</deltay>\n"

View File

@ -2,8 +2,6 @@
#include <exception>
#include <boost/algorithm/string.hpp>
#include <boost/nowide/convert.hpp>
#include <boost/nowide/cstdio.hpp>
#include "miniz_extension.hpp"

View File

@ -170,7 +170,11 @@ namespace Slic3r {
// subdivide the retraction in segments
if (!wipe_path.empty()) {
// add tag for processor
#if ENABLE_VALIDATE_CUSTOM_GCODE
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Start) + "\n";
#else
gcode += ";" + GCodeProcessor::Wipe_Start_Tag + "\n";
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
for (const Line& line : wipe_path.lines()) {
double segment_length = line.length();
/* Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
@ -186,7 +190,11 @@ namespace Slic3r {
);
}
// add tag for processor
#if ENABLE_VALIDATE_CUSTOM_GCODE
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_End) + "\n";
#else
gcode += ";" + GCodeProcessor::Wipe_End_Tag + "\n";
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
gcodegen.set_last_pos(wipe_path.points.back());
}
@ -478,7 +486,7 @@ std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObjec
//FIXME should we use the printing extruders instead?
double gap_over_supports = object.config().support_material_contact_distance;
// FIXME should we test object.config().support_material_synchronize_layers ? Currently the support layers are synchronized with object layers iff soluble supports.
assert(!object.config().support_material || gap_over_supports != 0. || object.config().support_material_synchronize_layers);
assert(!object.has_support() || gap_over_supports != 0. || object.config().support_material_synchronize_layers);
if (gap_over_supports != 0.) {
gap_over_supports = std::max(0., gap_over_supports);
// Not a soluble support,
@ -610,6 +618,59 @@ namespace DoExport {
print_statistics.estimated_silent_print_time = processor.is_stealth_time_estimator_enabled() ?
get_time_dhms(result.time_statistics.modes[static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Stealth)].time) : "N/A";
}
#if ENABLE_VALIDATE_CUSTOM_GCODE
// if any reserved keyword is found, returns a std::vector containing the first MAX_COUNT keywords found
// into pairs containing:
// first: source
// second: keyword
// to be shown in the warning notification
// The returned vector is empty if no keyword has been found
static std::vector<std::pair<std::string, std::string>> validate_custom_gcode(const Print& print) {
static const unsigned int MAX_TAGS_COUNT = 5;
std::vector<std::pair<std::string, std::string>> ret;
auto check = [&ret](const std::string& source, const std::string& gcode) {
std::vector<std::string> tags;
if (GCodeProcessor::contains_reserved_tags(gcode, MAX_TAGS_COUNT, tags)) {
if (!tags.empty()) {
size_t i = 0;
while (ret.size() < MAX_TAGS_COUNT && i < tags.size()) {
ret.push_back({ source, tags[i] });
++i;
}
}
}
};
const GCodeConfig& config = print.config();
check(_(L("Start G-code")), config.start_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("End G-code")), config.end_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Before layer change G-code")), config.before_layer_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("After layer change G-code")), config.layer_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Tool change G-code")), config.toolchange_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Between objects G-code (for sequential printing)")), config.between_objects_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Color Change G-code")), config.color_change_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Pause Print G-code")), config.pause_print_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Template Custom G-code")), config.template_custom_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) {
for (const std::string& value : config.start_filament_gcode.values) {
check(_(L("Filament Start G-code")), value);
if (ret.size() == MAX_TAGS_COUNT)
break;
}
}
if (ret.size() < MAX_TAGS_COUNT) {
for (const std::string& value : config.end_filament_gcode.values) {
check(_(L("Filament End G-code")), value);
if (ret.size() == MAX_TAGS_COUNT)
break;
}
}
return ret;
}
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
} // namespace DoExport
void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb)
@ -622,6 +683,22 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re
print->set_started(psGCodeExport);
#if ENABLE_VALIDATE_CUSTOM_GCODE
// check if any custom gcode contains keywords used by the gcode processor to
// produce time estimation and gcode toolpaths
std::vector<std::pair<std::string, std::string>> validation_res = DoExport::validate_custom_gcode(*print);
if (!validation_res.empty()) {
std::string reports;
for (const auto& [source, keyword] : validation_res) {
reports += source + ": \"" + keyword + "\"\n";
}
print->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL,
_(L("Found reserved keyword(s) into custom g-code:")) + "\n" +
reports +
_(L("This may cause problems in g-code visualization and printing time estimation.")));
}
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
BOOST_LOG_TRIVIAL(info) << "Exporting G-code..." << log_memory_info();
// Remove the old g-code if it exists.
@ -851,7 +928,7 @@ namespace DoExport {
double extruded_volume = extruder.extruded_volume() + (has_wipe_tower ? wipe_tower_data.used_filament[extruder.id()] * 2.4052f : 0.f); // assumes 1.75mm filament diameter
double filament_weight = extruded_volume * extruder.filament_density() * 0.001;
double filament_cost = filament_weight * extruder.filament_cost() * 0.001;
auto append = [&extruder, &extruders](std::pair<std::string, unsigned int> &dst, const char *tmpl, double value) {
auto append = [&extruder](std::pair<std::string, unsigned int> &dst, const char *tmpl, double value) {
while (dst.second < extruder.id()) {
// Fill in the non-printing extruders with zeros.
dst.first += (dst.second > 0) ? ", 0" : "0";
@ -891,6 +968,7 @@ namespace DoExport {
}
}
#if 0
// Sort the PrintObjects by their increasing Z, likely useful for avoiding colisions on Deltas during sequential prints.
static inline std::vector<const PrintInstance*> sort_object_instances_by_max_z(const Print &print)
{
@ -903,6 +981,7 @@ static inline std::vector<const PrintInstance*> sort_object_instances_by_max_z(c
instances.emplace_back(&object->instances()[i]);
return instances;
}
#endif
// Produce a vector of PrintObjects in the order of their respective ModelObjects in print.model().
std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Print& print)
@ -937,14 +1016,9 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
m_last_height = 0.f;
m_last_layer_z = 0.f;
m_max_layer_z = 0.f;
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
m_last_width = 0.f;
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_last_mm3_per_mm = 0.;
#if !ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
m_last_width = 0.f;
#endif // !ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
// How many times will be change_layer() called?
@ -1037,7 +1111,11 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// adds tags for time estimators
if (print.config().remaining_times.value)
#if ENABLE_VALIDATE_CUSTOM_GCODE
_write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::First_Line_M73_Placeholder).c_str());
#else
_writeln(file, GCodeProcessor::First_Line_M73_Placeholder_Tag);
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
// Prepare the helper object for replacing placeholders in custom G-code and output filename.
m_placeholder_parser = print.placeholder_parser();
@ -1143,7 +1221,11 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false);
// adds tag for processor
#if ENABLE_VALIDATE_CUSTOM_GCODE
_write_format(file, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
#else
_write_format(file, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
// Write the custom start G-code
_writeln(file, start_gcode);
@ -1222,7 +1304,8 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
for (const LayerToPrint &ltp : layers_to_print) {
std::vector<LayerToPrint> lrs;
lrs.emplace_back(std::move(ltp));
this->process_layer(file, print, lrs, tool_ordering.tools_for_layer(ltp.print_z()), nullptr, *print_object_instance_sequential_active - object.instances().data());
this->process_layer(file, print, lrs, tool_ordering.tools_for_layer(ltp.print_z()), &ltp == &layers_to_print.back(),
nullptr, *print_object_instance_sequential_active - object.instances().data());
print.throw_if_canceled();
}
#ifdef HAS_PRESSURE_EQUALIZER
@ -1286,7 +1369,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
const LayerTools &layer_tools = tool_ordering.tools_for_layer(layer.first);
if (m_wipe_tower && layer_tools.has_wipe_tower)
m_wipe_tower->next_layer();
this->process_layer(file, print, layer.second, layer_tools, &print_object_instances_ordering, size_t(-1));
this->process_layer(file, print, layer.second, layer_tools, &layer == &layers_to_print.back(), &print_object_instances_ordering, size_t(-1));
print.throw_if_canceled();
}
#ifdef HAS_PRESSURE_EQUALIZER
@ -1303,7 +1386,11 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
_write(file, m_writer.set_fan(false));
// adds tag for processor
#if ENABLE_VALIDATE_CUSTOM_GCODE
_write_format(file, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
#else
_write_format(file, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
// Process filament-specific gcode in extruder order.
{
@ -1330,7 +1417,11 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// adds tags for time estimators
if (print.config().remaining_times.value)
#if ENABLE_VALIDATE_CUSTOM_GCODE
_write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Last_Line_M73_Placeholder).c_str());
#else
_writeln(file, GCodeProcessor::Last_Line_M73_Placeholder_Tag);
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
print.throw_if_canceled();
@ -1346,7 +1437,11 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
_write_format(file, "; total filament cost = %.2lf\n", print.m_print_statistics.total_cost);
if (print.m_print_statistics.total_toolchanges > 0)
_write_format(file, "; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges);
#if ENABLE_VALIDATE_CUSTOM_GCODE
_write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
#else
_writeln(file, GCodeProcessor::Estimated_Printing_Time_Placeholder_Tag);
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
// Append full config.
_write(file, "\n");
@ -1633,7 +1728,11 @@ namespace ProcessLayer
assert(m600_extruder_before_layer >= 0);
// Color Change or Tool Change as Color Change.
// add tag for processor
#if ENABLE_VALIDATE_CUSTOM_GCODE
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Color_Change) + ",T" + std::to_string(m600_extruder_before_layer) + "\n";
#else
gcode += ";" + GCodeProcessor::Color_Change_Tag + ",T" + std::to_string(m600_extruder_before_layer) + "\n";
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
if (!single_extruder_printer && m600_extruder_before_layer >= 0 && first_extruder_id != (unsigned)m600_extruder_before_layer
// && !MMU1
@ -1648,21 +1747,27 @@ namespace ProcessLayer
gcode += "\n";
}
}
else
{
else {
if (gcode_type == CustomGCode::PausePrint) // Pause print
{
// add tag for processor
#if ENABLE_VALIDATE_CUSTOM_GCODE
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Pause_Print) + "\n";
#else
gcode += ";" + GCodeProcessor::Pause_Print_Tag + "\n";
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
//! FIXME_in_fw show message during print pause
if (!pause_print_msg.empty())
gcode += "M117 " + pause_print_msg + "\n";
gcode += config.pause_print_gcode;
}
else
{
else {
// add tag for processor
#if ENABLE_VALIDATE_CUSTOM_GCODE
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Custom_Code) + "\n";
#else
gcode += ";" + GCodeProcessor::Custom_Code_Tag + "\n";
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
if (gcode_type == CustomGCode::Template) // Template Cistom Gcode
gcode += config.template_custom_gcode;
else // custom Gcode
@ -1755,6 +1860,7 @@ void GCode::process_layer(
// Set of object & print layers of the same PrintObject and with the same print_z.
const std::vector<LayerToPrint> &layers,
const LayerTools &layer_tools,
const bool last_layer,
// Pairs of PrintObject index and its instance index.
const std::vector<const PrintInstance*> *ordering,
// If set to size_t(-1), then print all copies of all objects.
@ -1790,7 +1896,7 @@ void GCode::process_layer(
// Just a reminder: A spiral vase mode is allowed for a single object, single material print only.
m_enable_loop_clipping = true;
if (m_spiral_vase && layers.size() == 1 && support_layer == nullptr) {
bool enable = (layer.id() > 0 || print.config().brim_width.value == 0.) && (layer.id() >= (size_t)print.config().skirt_height.value && ! print.has_infinite_skirt());
bool enable = (layer.id() > 0 || !print.has_brim()) && (layer.id() >= (size_t)print.config().skirt_height.value && ! print.has_infinite_skirt());
if (enable) {
for (const LayerRegion *layer_region : layer.regions())
if (size_t(layer_region->region()->config().bottom_solid_layers.value) > layer.id() ||
@ -1808,14 +1914,22 @@ void GCode::process_layer(
std::string gcode;
// add tag for processor
#if ENABLE_VALIDATE_CUSTOM_GCODE
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change) + "\n";
#else
gcode += ";" + GCodeProcessor::Layer_Change_Tag + "\n";
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
// export layer z
char buf[64];
sprintf(buf, ";Z:%g\n", print_z);
gcode += buf;
// export layer height
float height = first_layer ? static_cast<float>(print_z) : static_cast<float>(print_z) - m_last_layer_z;
#if ENABLE_VALIDATE_CUSTOM_GCODE
sprintf(buf, ";%s%g\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height).c_str(), height);
#else
sprintf(buf, ";%s%g\n", GCodeProcessor::Height_Tag.c_str(), height);
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
gcode += buf;
// update caches
m_last_layer_z = static_cast<float>(print_z);
@ -2138,11 +2252,13 @@ void GCode::process_layer(
// we apply spiral vase at this stage because it requires a full layer.
// Just a reminder: A spiral vase mode is allowed for a single object per layer, single material print only.
if (m_spiral_vase)
gcode = m_spiral_vase->process_layer(gcode);
gcode = m_spiral_vase->process_layer(std::move(gcode));
// Apply cooling logic; this may alter speeds.
if (m_cooling_buffer)
gcode = m_cooling_buffer->process_layer(gcode, layer.id());
gcode = m_cooling_buffer->process_layer(std::move(gcode), layer.id(),
// Flush the cooling buffer at each object layer or possibly at the last layer, even if it contains just supports (This should not happen).
object_layer || last_layer);
#ifdef HAS_PRESSURE_EQUALIZER
// Apply pressure equalization if enabled;
@ -2154,7 +2270,7 @@ void GCode::process_layer(
_write(file, gcode);
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
log_memory_info();
log_memory_info();
}
void GCode::apply_print_config(const PrintConfig &print_config)
@ -2457,10 +2573,11 @@ std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectBy
std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fills)
{
static constexpr const char *support_label = "support material";
static constexpr const char *support_interface_label = "support material interface";
std::string gcode;
if (! support_fills.entities.empty()) {
const char *support_label = "support material";
const char *support_interface_label = "support material interface";
const double support_speed = m_config.support_material_speed.value;
const double support_interface_speed = m_config.support_material_interface_speed.get_abs_value(support_speed);
for (const ExtrusionEntity *ee : support_fills.entities) {
@ -2473,9 +2590,14 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
gcode += this->extrude_path(*path, label, speed);
else {
const ExtrusionMultiPath *multipath = dynamic_cast<const ExtrusionMultiPath*>(ee);
assert(multipath != nullptr);
if (multipath)
gcode += this->extrude_multi_path(*multipath, label, speed);
else {
const ExtrusionEntityCollection *eec = dynamic_cast<const ExtrusionEntityCollection*>(ee);
assert(eec);
if (eec)
gcode += this->extrude_support(*eec);
}
}
}
}
@ -2634,17 +2756,23 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
if (path.role() != m_last_processor_extrusion_role) {
m_last_processor_extrusion_role = path.role();
#if ENABLE_VALIDATE_CUSTOM_GCODE
sprintf(buf, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(m_last_processor_extrusion_role).c_str());
#else
sprintf(buf, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(m_last_processor_extrusion_role).c_str());
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
gcode += buf;
}
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
if (last_was_wipe_tower || m_last_width != path.width) {
m_last_width = path.width;
#if ENABLE_VALIDATE_CUSTOM_GCODE
sprintf(buf, ";%s%g\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Width).c_str(), m_last_width);
#else
sprintf(buf, ";%s%g\n", GCodeProcessor::Width_Tag.c_str(), m_last_width);
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
gcode += buf;
}
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
if (last_was_wipe_tower || (m_last_mm3_per_mm != path.mm3_per_mm)) {
@ -2652,19 +2780,15 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
sprintf(buf, ";%s%f\n", GCodeProcessor::Mm3_Per_Mm_Tag.c_str(), m_last_mm3_per_mm);
gcode += buf;
}
#if !ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
if (last_was_wipe_tower || m_last_width != path.width) {
m_last_width = path.width;
sprintf(buf, ";%s%g\n", GCodeProcessor::Width_Tag.c_str(), m_last_width);
gcode += buf;
}
#endif // !ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
if (last_was_wipe_tower || std::abs(m_last_height - path.height) > EPSILON) {
m_last_height = path.height;
#if ENABLE_VALIDATE_CUSTOM_GCODE
sprintf(buf, ";%s%g\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height).c_str(), m_last_height);
#else
sprintf(buf, ";%s%g\n", GCodeProcessor::Height_Tag.c_str(), m_last_height);
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
gcode += buf;
}
@ -2735,10 +2859,10 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
Point last_post_before_retract = this->last_pos();
gcode += this->retract();
// When "Wipe while retracting" is enabled, then extruder moves to another position, and travel from this position can cross perimeters.
// Because of it, it is necessary to call avoid crossing perimeters for the path between previous last_post and last_post after calling retraction()
// Because of it, it is necessary to call avoid crossing perimeters again with new starting point after calling retraction()
// FIXME Lukas H.: Try to predict if this second calling of avoid crossing perimeters will be needed or not. It could save computations.
if (last_post_before_retract != this->last_pos() && m_config.avoid_crossing_perimeters) {
Polyline retract_travel = m_avoid_crossing_perimeters.travel_to(*this, last_post_before_retract);
append(retract_travel.points, travel.points);
Polyline retract_travel = m_avoid_crossing_perimeters.travel_to(*this, point);
travel = std::move(retract_travel);
}
} else

View File

@ -33,7 +33,7 @@ class GCode;
namespace { struct Item; }
struct PrintInstance;
using PrintObjectPtrs = std::vector<PrintObject*>;
class ConstPrintObjectPtrsAdaptor;
class OozePrevention {
public:
@ -131,14 +131,9 @@ public:
m_volumetric_speed(0),
m_last_pos_defined(false),
m_last_extrusion_role(erNone),
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
m_last_width(0.0f),
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_last_mm3_per_mm(0.0),
#if !ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
m_last_width(0.0f),
#endif // !ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
m_brim_done(false),
m_second_layer_things_done(false),
@ -201,6 +196,7 @@ private:
// Set of object & print layers of the same PrintObject and with the same print_z.
const std::vector<LayerToPrint> &layers,
const LayerTools &layer_tools,
const bool last_layer,
// Pairs of PrintObject index and its instance index.
const std::vector<const PrintInstance*> *ordering,
// If set to size_t(-1), then print all copies of all objects.
@ -332,14 +328,9 @@ private:
float m_last_height{ 0.0f };
float m_last_layer_z{ 0.0f };
float m_max_layer_z{ 0.0f };
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
float m_last_width{ 0.0f };
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
double m_last_mm3_per_mm;
#if !ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
float m_last_width{ 0.0f };
#endif // !ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
Point m_last_pos;

View File

@ -283,8 +283,10 @@ static size_t avoid_perimeters_inner(const AvoidCrossingPerimeters::Boundary &bo
AllIntersectionsVisitor visitor(edge_grid, intersections, Line(start, end));
edge_grid.visit_cells_intersecting_line(start, end, visitor);
Vec2d dir = (end - start).cast<double>();
for (Intersection &intersection : intersections)
intersection.distance = boundary.boundaries_params[intersection.border_idx][intersection.line_idx];
for (Intersection &intersection : intersections) {
float dist_from_line_begin = (intersection.point - boundary.boundaries[intersection.border_idx][intersection.line_idx]).cast<float>().norm();
intersection.distance = boundary.boundaries_params[intersection.border_idx][intersection.line_idx] + dist_from_line_begin;
}
std::sort(intersections.begin(), intersections.end(), [dir](const auto &l, const auto &r) { return (r.point - l.point).template cast<double>().dot(dir) > 0.; });
}
@ -568,7 +570,7 @@ static void precompute_polygon_distances(const Polygon &polygon, std::vector<flo
polygon_distances_out.assign(polygon.size() + 1, 0.f);
for (size_t point_idx = 1; point_idx < polygon.size(); ++point_idx)
polygon_distances_out[point_idx] = polygon_distances_out[point_idx - 1] + (polygon[point_idx].cast<float>() - polygon[point_idx - 1].cast<float>()).norm();
polygon_distances_out.back() = polygon_distances_out[polygon.size() - 1] + (polygon.last_point().cast<float>() - polygon.first_point().cast<float>()).norm();
polygon_distances_out.back() = polygon_distances_out[polygon.size() - 1] + (polygon.points.back().cast<float>() - polygon.points.front().cast<float>()).norm();
}
static void precompute_expolygon_distances(const ExPolygon &ex_polygon, std::vector<std::vector<float>> &expolygon_distances_out)
@ -596,7 +598,7 @@ static std::vector<float> contour_distance(const EdgeGrid::Grid &grid,
{
struct Visitor {
Visitor(const EdgeGrid::Grid &grid, const size_t contour_idx, const std::vector<float> &polygon_distances, double dist_same_contour_accept, double dist_same_contour_reject) :
grid(grid), idx_contour(contour_idx), contour(*grid.contours()[contour_idx]), boundary_parameters(polygon_distances), dist_same_contour_accept(dist_same_contour_accept), dist_same_contour_reject(dist_same_contour_reject) {}
grid(grid), idx_contour(contour_idx), contour(grid.contours()[contour_idx]), boundary_parameters(polygon_distances), dist_same_contour_accept(dist_same_contour_accept), dist_same_contour_reject(dist_same_contour_reject) {}
void init(const Points &contour, const Point &apoint)
{
@ -630,12 +632,12 @@ static std::vector<float> contour_distance(const EdgeGrid::Grid &grid,
// Complex case: The closest segment originates from the same contour as the starting point.
// Reject the closest point if its distance along the contour is reasonable compared to the current contour bisector
// (this->pt, foot).
const Slic3r::Points &ipts = *grid.contours()[it_contour_and_segment->first];
double param_lo = boundary_parameters[this->idx_point];
double param_hi = t * sqrt(l2);
double param_end = boundary_parameters.back();
const EdgeGrid::Contour &contour = grid.contours()[it_contour_and_segment->first];
double param_lo = boundary_parameters[this->idx_point];
double param_hi = t * sqrt(l2);
double param_end = boundary_parameters.back();
const size_t ipt = it_contour_and_segment->second;
if (ipt + 1 < ipts.size())
if (contour.begin() + ipt + 1 < contour.end())
param_hi += boundary_parameters[ipt > 0 ? ipt - 1 : 0];
if (param_lo > param_hi)
std::swap(param_lo, param_hi);
@ -649,9 +651,9 @@ static std::vector<float> contour_distance(const EdgeGrid::Grid &grid,
// longer than the bisector. That is, the path shall not bulge away from the bisector too much.
// Bulge is estimated by 0.6 of the circle circumference drawn around the bisector.
// Test whether the contour is convex or concave.
bool inside = (t == 0.) ? this->inside_corner(ipts, ipt, this->point) :
(t == 1.) ? this->inside_corner(ipts, ipt + 1 == ipts.size() ? 0 : ipt + 1, this->point) :
this->left_of_segment(ipts, ipt, this->point);
bool inside = (t == 0.) ? this->inside_corner(contour, ipt, this->point) :
(t == 1.) ? this->inside_corner(contour, contour.segment_idx_next(ipt), this->point) :
this->left_of_segment(contour, ipt, this->point);
accept = inside && dist_along_contour > 0.6 * M_PI * dist;
}
}
@ -668,7 +670,7 @@ static std::vector<float> contour_distance(const EdgeGrid::Grid &grid,
const EdgeGrid::Grid &grid;
const size_t idx_contour;
const Points &contour;
const EdgeGrid::Contour &contour;
const std::vector<float> &boundary_parameters;
const double dist_same_contour_accept;
@ -691,25 +693,27 @@ static std::vector<float> contour_distance(const EdgeGrid::Grid &grid,
return Vec2d(-v1.y() - v2.y(), v1.x() + v2.x());
}
static bool inside_corner(const Slic3r::Points &contour, size_t i, const Point &pt_oposite)
static bool inside_corner(const EdgeGrid::Contour &contour, size_t i, const Point &pt_oposite)
{
const Vec2d pt = pt_oposite.cast<double>();
size_t iprev = prev_idx_modulo(i, contour);
size_t inext = next_idx_modulo(i, contour);
Vec2d v1 = (contour[i] - contour[iprev]).cast<double>();
Vec2d v2 = (contour[inext] - contour[i]).cast<double>();
bool left_of_v1 = cross2(v1, pt - contour[iprev].cast<double>()) > 0.;
bool left_of_v2 = cross2(v2, pt - contour[i].cast<double>()) > 0.;
const Point &pt_prev = contour.segment_prev(i);
const Point &pt_this = contour.segment_start(i);
const Point &pt_next = contour.segment_end(i);
Vec2d v1 = (pt_this - pt_prev).cast<double>();
Vec2d v2 = (pt_next - pt_this).cast<double>();
bool left_of_v1 = cross2(v1, pt - pt_prev.cast<double>()) > 0.;
bool left_of_v2 = cross2(v2, pt - pt_this.cast<double>()) > 0.;
return cross2(v1, v2) > 0 ? left_of_v1 && left_of_v2 : // convex corner
left_of_v1 || left_of_v2; // concave corner
}
static bool left_of_segment(const Slic3r::Points &contour, size_t i, const Point &pt_oposite)
static bool left_of_segment(const EdgeGrid::Contour &contour, size_t i, const Point &pt_oposite)
{
const Vec2d pt = pt_oposite.cast<double>();
size_t inext = next_idx_modulo(i, contour);
Vec2d v = (contour[inext] - contour[i]).cast<double>();
return cross2(v, pt - contour[i].cast<double>()) > 0.;
const Vec2d pt = pt_oposite.cast<double>();
const Point &pt_this = contour.segment_start(i);
const Point &pt_next = contour.segment_end(i);
Vec2d v = (pt_next - pt_this).cast<double>();
return cross2(v, pt - pt_this.cast<double>()) > 0.;
}
} visitor(grid, contour_idx, poly_distances, 0.5 * compensation * M_PI, search_radius);
@ -727,10 +731,11 @@ static std::vector<float> contour_distance(const EdgeGrid::Grid &grid,
// Polygon offset which ensures that if a polygon breaks up into several separate parts, the original polygon will be used in these places.
// ExPolygons are handled one by one so returned ExPolygons could intersect.
static ExPolygons inner_offset(const ExPolygons &ex_polygons, double offset, double min_contour_width = scale_(0.001))
static ExPolygons inner_offset(const ExPolygons &ex_polygons, double offset)
{
double search_radius = 2. * (offset + min_contour_width);
ExPolygons ex_poly_result = ex_polygons;
double min_contour_width = 2. * offset + SCALED_EPSILON;
double search_radius = 2. * (offset + min_contour_width);
ExPolygons ex_poly_result = ex_polygons;
resample_expolygons(ex_poly_result, offset / 2);
for (ExPolygon &ex_poly : ex_poly_result) {

View File

@ -279,11 +279,24 @@ finished:
return new_feedrate;
}
std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_id)
std::string CoolingBuffer::process_layer(std::string &&gcode, size_t layer_id, bool flush)
{
std::vector<PerExtruderAdjustments> per_extruder_adjustments = this->parse_layer_gcode(gcode, m_current_pos);
float layer_time_stretched = this->calculate_layer_slowdown(per_extruder_adjustments);
return this->apply_layer_cooldown(gcode, layer_id, layer_time_stretched, per_extruder_adjustments);
// Cache the input G-code.
if (m_gcode.empty())
m_gcode = std::move(gcode);
else
m_gcode += gcode;
std::string out;
if (flush) {
// This is either an object layer or the very last print layer. Calculate cool down over the collected support layers
// and one object layer.
std::vector<PerExtruderAdjustments> per_extruder_adjustments = this->parse_layer_gcode(m_gcode, m_current_pos);
float layer_time_stretched = this->calculate_layer_slowdown(per_extruder_adjustments);
out = this->apply_layer_cooldown(m_gcode, layer_id, layer_time_stretched, per_extruder_adjustments);
m_gcode.clear();
}
return out;
}
// Parse the layer G-code for the moves, which could be adjusted.
@ -683,6 +696,13 @@ std::string CoolingBuffer::apply_layer_cooldown(
int min_fan_speed = EXTRUDER_CONFIG(min_fan_speed);
int fan_speed_new = EXTRUDER_CONFIG(fan_always_on) ? min_fan_speed : 0;
int disable_fan_first_layers = EXTRUDER_CONFIG(disable_fan_first_layers);
// Is the fan speed ramp enabled?
int full_fan_speed_layer = EXTRUDER_CONFIG(full_fan_speed_layer);
if (disable_fan_first_layers <= 0 && full_fan_speed_layer > 0) {
// When ramping up fan speed from disable_fan_first_layers to full_fan_speed_layer, force disable_fan_first_layers above zero,
// so there will be a zero fan speed at least at the 1st layer.
disable_fan_first_layers = 1;
}
if (int(layer_id) >= disable_fan_first_layers) {
int max_fan_speed = EXTRUDER_CONFIG(max_fan_speed);
float slowdown_below_layer_time = float(EXTRUDER_CONFIG(slowdown_below_layer_time));
@ -699,11 +719,6 @@ std::string CoolingBuffer::apply_layer_cooldown(
}
}
bridge_fan_speed = EXTRUDER_CONFIG(bridge_fan_speed);
// Is the fan speed ramp enabled?
int full_fan_speed_layer = EXTRUDER_CONFIG(full_fan_speed_layer);
// When ramping up fan speed from disable_fan_first_layers to full_fan_speed_layer, force disable_fan_first_layers above zero,
// so there will be a zero fan speed at least at the 1st layer.
disable_fan_first_layers = std::max(disable_fan_first_layers, 1);
if (int(layer_id) >= disable_fan_first_layers && int(layer_id) + 1 < full_fan_speed_layer) {
// Ramp up the fan speed from disable_fan_first_layers to full_fan_speed_layer.
float factor = float(int(layer_id + 1) - disable_fan_first_layers) / float(full_fan_speed_layer - disable_fan_first_layers);

View File

@ -25,7 +25,7 @@ public:
CoolingBuffer(GCode &gcodegen);
void reset();
void set_current_extruder(unsigned int extruder_id) { m_current_extruder = extruder_id; }
std::string process_layer(const std::string &gcode, size_t layer_id);
std::string process_layer(std::string &&gcode, size_t layer_id, bool flush);
GCode* gcodegen() { return &m_gcodegen; }
private:
@ -37,6 +37,7 @@ private:
std::string apply_layer_cooldown(const std::string &gcode, size_t layer_id, float layer_time, std::vector<PerExtruderAdjustments> &per_extruder_adjustments);
GCode& m_gcodegen;
// G-code snippet cached for the support layers preceding an object layer.
std::string m_gcode;
// Internal data.
// X,Y,Z,E,F

View File

@ -19,15 +19,31 @@
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
namespace Slic3r {
#if ENABLE_VALIDATE_CUSTOM_GCODE
const std::vector<std::string> GCodeProcessor::Reserved_Tags = {
"TYPE:",
"WIPE_START",
"WIPE_END",
"HEIGHT:",
"WIDTH:",
"LAYER_CHANGE",
"COLOR_CHANGE",
"PAUSE_PRINT",
"CUSTOM_GCODE",
"_GP_FIRST_LINE_M73_PLACEHOLDER",
"_GP_LAST_LINE_M73_PLACEHOLDER",
"_GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER"
};
#else
const std::string GCodeProcessor::Extrusion_Role_Tag = "TYPE:";
const std::string GCodeProcessor::Wipe_Start_Tag = "WIPE_START";
const std::string GCodeProcessor::Wipe_End_Tag = "WIPE_END";
const std::string GCodeProcessor::Height_Tag = "HEIGHT:";
const std::string GCodeProcessor::Width_Tag = "WIDTH:";
const std::string GCodeProcessor::Layer_Change_Tag = "LAYER_CHANGE";
const std::string GCodeProcessor::Color_Change_Tag = "COLOR_CHANGE";
const std::string GCodeProcessor::Pause_Print_Tag = "PAUSE_PRINT";
@ -36,17 +52,12 @@ const std::string GCodeProcessor::Custom_Code_Tag = "CUSTOM_GCODE";
const std::string GCodeProcessor::First_Line_M73_Placeholder_Tag = "; _GP_FIRST_LINE_M73_PLACEHOLDER";
const std::string GCodeProcessor::Last_Line_M73_Placeholder_Tag = "; _GP_LAST_LINE_M73_PLACEHOLDER";
const std::string GCodeProcessor::Estimated_Printing_Time_Placeholder_Tag = "; _GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER";
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
const float GCodeProcessor::Wipe_Width = 0.05f;
const float GCodeProcessor::Wipe_Height = 0.05f;
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
const std::string GCodeProcessor::Width_Tag = "WIDTH:";
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
#if !ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
const std::string GCodeProcessor::Width_Tag = "WIDTH:";
#endif // !ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
const std::string GCodeProcessor::Mm3_Per_Mm_Tag = "MM3_PER_MM:";
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
@ -324,7 +335,11 @@ void GCodeProcessor::TimeProcessor::reset()
machines[static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Normal)].enabled = true;
}
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, std::vector<MoveVertex>& moves)
#else
void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
{
boost::nowide::ifstream in(filename);
if (!in.good())
@ -362,11 +377,33 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
// replace placeholder lines with the proper final value
auto process_placeholders = [&](const std::string& gcode_line) {
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
unsigned int extra_lines_count = 0;
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
// remove trailing '\n'
std::string line = gcode_line.substr(0, gcode_line.length() - 1);
std::string ret;
#if ENABLE_VALIDATE_CUSTOM_GCODE
if (line.length() > 1) {
line = line.substr(1);
if (export_remaining_time_enabled &&
(line == reserved_tag(ETags::First_Line_M73_Placeholder) || line == reserved_tag(ETags::Last_Line_M73_Placeholder))) {
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
const TimeMachine& machine = machines[i];
if (machine.enabled) {
ret += format_line_M73(machine.line_m73_mask.c_str(),
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? 0 : 100,
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? time_in_minutes(machine.time) : 0);
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
++extra_lines_count;
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
}
}
}
else if (line == reserved_tag(ETags::Estimated_Printing_Time_Placeholder)) {
#else
if (export_remaining_time_enabled && (line == First_Line_M73_Placeholder_Tag || line == Last_Line_M73_Placeholder_Tag)) {
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
const TimeMachine& machine = machines[i];
@ -378,20 +415,28 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
}
}
else if (line == Estimated_Printing_Time_Placeholder_Tag) {
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
const TimeMachine& machine = machines[i];
PrintEstimatedTimeStatistics::ETimeMode mode = static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i);
if (mode == PrintEstimatedTimeStatistics::ETimeMode::Normal || machine.enabled) {
char buf[128];
sprintf(buf, "; estimated printing time (%s mode) = %s\n",
(mode == PrintEstimatedTimeStatistics::ETimeMode::Normal) ? "normal" : "silent",
get_time_dhms(machine.time).c_str());
ret += buf;
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
const TimeMachine& machine = machines[i];
PrintEstimatedTimeStatistics::ETimeMode mode = static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i);
if (mode == PrintEstimatedTimeStatistics::ETimeMode::Normal || machine.enabled) {
char buf[128];
sprintf(buf, "; estimated printing time (%s mode) = %s\n",
(mode == PrintEstimatedTimeStatistics::ETimeMode::Normal) ? "normal" : "silent",
get_time_dhms(machine.time).c_str());
ret += buf;
}
}
}
#if ENABLE_VALIDATE_CUSTOM_GCODE
}
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
return std::tuple(!ret.empty(), ret.empty() ? gcode_line : ret, (extra_lines_count == 0) ? extra_lines_count : extra_lines_count - 1);
#else
return std::make_pair(!ret.empty(), ret.empty() ? gcode_line : ret);
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
};
// check for temporary lines
@ -412,8 +457,12 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
auto g1_times_cache_it = Slic3r::reserve_vector<std::vector<TimeMachine::G1LinesCacheItem>::const_iterator>(machines.size());
for (const auto& machine : machines)
g1_times_cache_it.emplace_back(machine.g1_times_cache.begin());
// add lines M73 to exported gcode
auto process_line_G1 = [&]() {
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
unsigned int exported_lines_count = 0;
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
if (export_remaining_time_enabled) {
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
const TimeMachine& machine = machines[i];
@ -430,11 +479,17 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
export_line += format_line_M73(machine.line_m73_mask.c_str(),
to_export.first, to_export.second);
last_exported[i] = to_export;
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
++exported_lines_count;
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
}
}
}
}
}
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
return exported_lines_count;
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
};
// helper function to write to disk
@ -449,15 +504,30 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
export_line.clear();
};
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
unsigned int line_id = 0;
std::vector<std::pair<unsigned int, unsigned int>> offsets;
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
while (std::getline(in, gcode_line)) {
if (!in.good()) {
fclose(out);
throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nError while reading from file.\n"));
}
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
++line_id;
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
gcode_line += "\n";
// replace placeholder lines
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
auto [processed, result, lines_added_count] = process_placeholders(gcode_line);
if (processed && lines_added_count > 0)
offsets.push_back({ line_id, lines_added_count });
#else
auto [processed, result] = process_placeholders(gcode_line);
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
gcode_line = result;
if (!processed) {
// remove temporary lines
@ -468,8 +538,15 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
parser.parse_line(gcode_line,
[&](GCodeReader& reader, const GCodeReader::GCodeLine& line) {
if (line.cmd_is("G1")) {
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
unsigned int extra_lines_count = process_line_G1();
++g1_lines_counter;
if (extra_lines_count > 0)
offsets.push_back({ line_id, extra_lines_count });
#else
process_line_G1();
++g1_lines_counter;
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
}
});
}
@ -485,6 +562,19 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
fclose(out);
in.close();
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
// updates moves' gcode ids which have been modified by the insertion of the M73 lines
unsigned int curr_offset_id = 0;
unsigned int total_offset = 0;
for (MoveVertex& move : moves) {
while (curr_offset_id < static_cast<unsigned int>(offsets.size()) && offsets[curr_offset_id].first <= move.gcode_id) {
total_offset += offsets[curr_offset_id].second;
++curr_offset_id;
}
move.gcode_id += total_offset;
}
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
if (rename_file(out_path, filename))
throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + filename + '\n' +
"Is " + out_path + " locked?" + '\n');
@ -503,6 +593,64 @@ const std::vector<std::pair<GCodeProcessor::EProducer, std::string>> GCodeProces
unsigned int GCodeProcessor::s_result_id = 0;
#if ENABLE_VALIDATE_CUSTOM_GCODE
static inline bool starts_with(const std::string_view comment, const std::string_view tag)
{
size_t tag_len = tag.size();
return comment.size() >= tag_len && comment.substr(0, tag_len) == tag;
}
bool GCodeProcessor::contains_reserved_tag(const std::string& gcode, std::string& found_tag)
{
bool ret = false;
GCodeReader parser;
parser.parse_buffer(gcode, [&ret, &found_tag](GCodeReader& parser, const GCodeReader::GCodeLine& line) {
std::string comment = line.raw();
if (comment.length() > 2 && comment.front() == ';') {
comment = comment.substr(1);
for (const std::string& s : Reserved_Tags) {
if (starts_with(comment, s)) {
ret = true;
found_tag = comment;
parser.quit_parsing();
return;
}
}
}
});
return ret;
}
bool GCodeProcessor::contains_reserved_tags(const std::string& gcode, unsigned int max_count, std::vector<std::string>& found_tag)
{
max_count = std::max(max_count, 1U);
bool ret = false;
GCodeReader parser;
parser.parse_buffer(gcode, [&ret, &found_tag, max_count](GCodeReader& parser, const GCodeReader::GCodeLine& line) {
std::string comment = line.raw();
if (comment.length() > 2 && comment.front() == ';') {
comment = comment.substr(1);
for (const std::string& s : Reserved_Tags) {
if (starts_with(comment, s)) {
ret = true;
found_tag.push_back(comment);
if (found_tag.size() == max_count) {
parser.quit_parsing();
return;
}
}
}
}
});
return ret;
}
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
GCodeProcessor::GCodeProcessor()
{
reset();
@ -750,13 +898,14 @@ void GCodeProcessor::reset()
m_cached_position.reset();
m_wiping = false;
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
m_line_id = 0;
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
m_feedrate = 0.0f;
m_width = 0.0f;
m_height = 0.0f;
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
m_forced_width = 0.0f;
m_forced_height = 0.0f;
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
m_mm3_per_mm = 0.0f;
m_fan_speed = 0.0f;
@ -808,7 +957,11 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
if (cmd.length() == 0) {
const std::string_view comment = line.comment();
if (comment.length() > 1 && detect_producer(comment))
#if ENABLE_VALIDATE_CUSTOM_GCODE
m_parser.quit_parsing();
#else
m_parser.quit_parsing_file();
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
}
});
@ -817,7 +970,7 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
if (m_producer == EProducer::PrusaSlicer || m_producer == EProducer::Slic3rPE || m_producer == EProducer::Slic3r) {
DynamicPrintConfig config;
config.apply(FullPrintConfig::defaults());
config.load_from_gcode_file(filename);
config.load_from_gcode_file(filename, false);
apply_config(config);
}
}
@ -859,7 +1012,11 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
// post-process to add M73 lines into the gcode
if (apply_postprocess)
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
m_time_processor.post_process(filename, m_result.moves);
#else
m_time_processor.post_process(filename);
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
std::cout << "\n";
@ -935,6 +1092,10 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line)
{
/* std::cout << line.raw() << std::endl; */
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
++m_line_id;
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
// update start position
m_start_position = m_end_position;
@ -1004,11 +1165,13 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line)
}
}
#if !ENABLE_VALIDATE_CUSTOM_GCODE
static inline bool starts_with(const std::string_view comment, const std::string_view tag)
{
size_t tag_len = tag.size();
return comment.size() >= tag_len && comment.substr(0, tag_len) == tag;
}
#endif // !ENABLE_VALIDATE_CUSTOM_GCODE
#if __has_include(<charconv>)
template <typename T, typename = void>
@ -1061,6 +1224,25 @@ void GCodeProcessor::process_tags(const std::string_view comment)
if (m_producers_enabled && process_producers_tags(comment))
return;
#if ENABLE_VALIDATE_CUSTOM_GCODE
// extrusion role tag
if (starts_with(comment, reserved_tag(ETags::Role))) {
m_extrusion_role = ExtrusionEntity::string_to_role(comment.substr(reserved_tag(ETags::Role).length()));
return;
}
// wipe start tag
if (starts_with(comment, reserved_tag(ETags::Wipe_Start))) {
m_wiping = true;
return;
}
// wipe end tag
if (starts_with(comment, reserved_tag(ETags::Wipe_End))) {
m_wiping = false;
return;
}
#else
// extrusion role tag
if (starts_with(comment, Extrusion_Role_Tag)) {
m_extrusion_role = ExtrusionEntity::string_to_role(comment.substr(Extrusion_Role_Tag.length()));
@ -1078,9 +1260,23 @@ void GCodeProcessor::process_tags(const std::string_view comment)
m_wiping = false;
return;
}
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
if (!m_producers_enabled || m_producer == EProducer::PrusaSlicer) {
#if ENABLE_VALIDATE_CUSTOM_GCODE
// height tag
if (starts_with(comment, reserved_tag(ETags::Height))) {
if (!parse_number(comment.substr(reserved_tag(ETags::Height).size()), m_forced_height))
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ").";
return;
}
// width tag
if (starts_with(comment, reserved_tag(ETags::Width))) {
if (!parse_number(comment.substr(reserved_tag(ETags::Width).size()), m_forced_width))
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ").";
return;
}
#else
// height tag
if (starts_with(comment, Height_Tag)) {
if (!parse_number(comment.substr(Height_Tag.size()), m_forced_height))
@ -1093,26 +1289,56 @@ void GCodeProcessor::process_tags(const std::string_view comment)
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ").";
return;
}
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
}
#if ENABLE_VALIDATE_CUSTOM_GCODE
// color change tag
if (starts_with(comment, reserved_tag(ETags::Color_Change))) {
unsigned char extruder_id = 0;
if (starts_with(comment.substr(reserved_tag(ETags::Color_Change).size()), ",T")) {
int eid;
if (!parse_number(comment.substr(reserved_tag(ETags::Color_Change).size() + 2), eid) || eid < 0 || eid > 255) {
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Color_Change (" << comment << ").";
return;
}
extruder_id = static_cast<unsigned char>(eid);
}
m_extruder_colors[extruder_id] = static_cast<unsigned char>(m_extruder_offsets.size()) + m_cp_color.counter; // color_change position in list of color for preview
++m_cp_color.counter;
if (m_cp_color.counter == UCHAR_MAX)
m_cp_color.counter = 0;
if (m_extruder_id == extruder_id) {
m_cp_color.current = m_extruder_colors[extruder_id];
store_move_vertex(EMoveType::Color_change);
}
process_custom_gcode_time(CustomGCode::ColorChange);
return;
}
// pause print tag
if (comment == reserved_tag(ETags::Pause_Print)) {
store_move_vertex(EMoveType::Pause_Print);
process_custom_gcode_time(CustomGCode::PausePrint);
return;
}
// custom code tag
if (comment == reserved_tag(ETags::Custom_Code)) {
store_move_vertex(EMoveType::Custom_GCode);
return;
}
// layer change tag
if (comment == reserved_tag(ETags::Layer_Change)) {
++m_layer_id;
return;
}
#else
if ((!m_producers_enabled || m_producer == EProducer::PrusaSlicer) &&
starts_with(comment, Height_Tag)) {
// height tag
if (!parse_number(comment.substr(Height_Tag.size()), m_height))
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ").";
return;
}
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
// width tag
if (starts_with(comment, Width_Tag)) {
if (! parse_number(comment.substr(Width_Tag.size()), m_width_compare.last_tag_value))
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ").";
return;
}
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
// color change tag
if (starts_with(comment, Color_Change_Tag)) {
unsigned char extruder_id = 0;
@ -1153,6 +1379,13 @@ void GCodeProcessor::process_tags(const std::string_view comment)
return;
}
// layer change tag
if (comment == Layer_Change_Tag) {
++m_layer_id;
return;
}
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
// mm3_per_mm print tag
if (starts_with(comment, Mm3_Per_Mm_Tag)) {
@ -1161,12 +1394,6 @@ void GCodeProcessor::process_tags(const std::string_view comment)
return;
}
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
// layer change tag
if (comment == Layer_Change_Tag) {
++m_layer_id;
return;
}
}
bool GCodeProcessor::process_producers_tags(const std::string_view comment)
@ -1343,7 +1570,6 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string_view comment)
}
// geometry
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
// ; tool
std::string tag = " tool";
pos = comment.find(tag);
@ -1369,35 +1595,6 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string_view comment)
// ; layer
tag = " layer";
#else
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
// ; tool
std::string tag = " tool";
pos = comment.find(tag);
if (pos == 0) {
const std::string_view data = comment.substr(pos + tag.length());
std::string h_tag = "H";
size_t h_start = data.find(h_tag);
size_t h_end = data.find_first_of(' ', h_start);
std::string w_tag = "W";
size_t w_start = data.find(w_tag);
size_t w_end = data.find_first_of(' ', w_start);
if (h_start != data.npos) {
if (! parse_number(data.substr(h_start + 1, (h_end != data.npos) ? h_end - h_start - 1 : h_end), m_height_compare.last_tag_value))
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ").";
}
if (w_start != data.npos) {
if (! parse_number(data.substr(w_start + 1, (w_end != data.npos) ? w_end - w_start - 1 : w_end), m_width_compare.last_tag_value))
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ").";
}
return true;
}
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
// ; layer
std::string tag = " layer";
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
pos = comment.find(tag);
if (pos == 0) {
// skip lines "; layer end"
@ -1488,7 +1685,6 @@ bool GCodeProcessor::process_ideamaker_tags(const std::string_view comment)
}
// geometry
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
// width
tag = "WIDTH:";
pos = comment.find(tag);
@ -1506,27 +1702,6 @@ bool GCodeProcessor::process_ideamaker_tags(const std::string_view comment)
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ").";
return true;
}
#else
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
// width
tag = "WIDTH:";
pos = comment.find(tag);
if (pos != comment.npos) {
if (! parse_number(comment.substr(pos + tag.length()), m_width_compare.last_tag_value))
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ").";
return true;
}
// height
tag = "HEIGHT:";
pos = comment.find(tag);
if (pos != comment.npos) {
if (! parse_number(comment.substr(pos + tag.length()), m_height_compare.last_tag_value))
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ").";
return true;
}
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
// layer
pos = comment.find("LAYER:");
@ -1755,7 +1930,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
m_mm3_per_mm_compare.update(area_toolpath_cross_section, m_extrusion_role);
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
if (m_forced_height > 0.0f)
m_height = m_forced_height;
else {
@ -1768,25 +1942,10 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_height_compare.update(m_height, m_extrusion_role);
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
#else
if ((m_producers_enabled && m_producer != EProducer::PrusaSlicer) || m_height == 0.0f) {
if (m_end_position[Z] > m_extruded_last_z + EPSILON) {
m_height = m_end_position[Z] - m_extruded_last_z;
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_height_compare.update(m_height, m_extrusion_role);
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
m_extruded_last_z = m_end_position[Z];
}
}
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
if (m_forced_width > 0.0f)
m_width = m_forced_width;
else if (m_extrusion_role == erExternalPerimeter)
#else
if (m_extrusion_role == erExternalPerimeter)
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
// cross section: rectangle
m_width = delta_pos[E] * static_cast<float>(M_PI * sqr(1.05f * filament_radius)) / (delta_xyz * m_height);
else if (m_extrusion_role == erBridgeInfill || m_extrusion_role == erNone)
@ -2340,6 +2499,10 @@ void GCodeProcessor::process_T(const std::string_view command)
if (command.length() > 1) {
int eid = 0;
if (! parse_number(command.substr(1), eid) || eid < 0 || eid > 255) {
// Specific to the MMU2 V2 (see https://www.help.prusa3d.com/en/article/prusa-specific-g-codes_112173):
if (m_flavor == gcfMarlin && (command == "Tx" || command == "Tc" || command == "T?"))
return;
// T-1 is a valid gcode line for RepRap Firmwares (used to deselects all tools) see https://github.com/prusa3d/PrusaSlicer/issues/5677
if ((m_flavor != gcfRepRapFirmware && m_flavor != gcfRepRapSprinter) || eid != -1)
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid toolchange (" << command << ").";
@ -2372,6 +2535,9 @@ void GCodeProcessor::process_T(const std::string_view command)
void GCodeProcessor::store_move_vertex(EMoveType type)
{
MoveVertex vertex = {
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
m_line_id,
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
type,
m_extrusion_role,
m_extruder_id,

View File

@ -69,7 +69,34 @@ namespace Slic3r {
class GCodeProcessor
{
#if ENABLE_VALIDATE_CUSTOM_GCODE
static const std::vector<std::string> Reserved_Tags;
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
public:
#if ENABLE_VALIDATE_CUSTOM_GCODE
enum class ETags : unsigned char
{
Role,
Wipe_Start,
Wipe_End,
Height,
Width,
Layer_Change,
Color_Change,
Pause_Print,
Custom_Code,
First_Line_M73_Placeholder,
Last_Line_M73_Placeholder,
Estimated_Printing_Time_Placeholder
};
static const std::string& reserved_tag(ETags tag) { return Reserved_Tags[static_cast<unsigned char>(tag)]; }
// checks the given gcode for reserved tags and returns true when finding the 1st (which is returned into found_tag)
static bool contains_reserved_tag(const std::string& gcode, std::string& found_tag);
// checks the given gcode for reserved tags and returns true when finding any
// (the first max_count found tags are returned into found_tag)
static bool contains_reserved_tags(const std::string& gcode, unsigned int max_count, std::vector<std::string>& found_tag);
#else
static const std::string Extrusion_Role_Tag;
static const std::string Wipe_Start_Tag;
static const std::string Wipe_End_Tag;
@ -81,17 +108,13 @@ namespace Slic3r {
static const std::string First_Line_M73_Placeholder_Tag;
static const std::string Last_Line_M73_Placeholder_Tag;
static const std::string Estimated_Printing_Time_Placeholder_Tag;
static const std::string Width_Tag;
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
static const float Wipe_Width;
static const float Wipe_Height;
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
static const std::string Width_Tag;
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
#if !ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
static const std::string Width_Tag;
#endif // !ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
static const std::string Mm3_Per_Mm_Tag;
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
@ -173,6 +196,27 @@ namespace Slic3r {
float time() const;
};
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
struct MoveVertex
{
unsigned int gcode_id{ 0 };
EMoveType type{ EMoveType::Noop };
ExtrusionRole extrusion_role{ erNone };
unsigned char extruder_id{ 0 };
unsigned char cp_color_id{ 0 };
Vec3f position{ Vec3f::Zero() }; // mm
float delta_extruder{ 0.0f }; // mm
float feedrate{ 0.0f }; // mm/s
float width{ 0.0f }; // mm
float height{ 0.0f }; // mm
float mm3_per_mm{ 0.0f };
float fan_speed{ 0.0f }; // percentage
float time{ 0.0f }; // s
float volumetric_rate() const { return feedrate * mm3_per_mm; }
};
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
private:
struct TimeMachine
{
@ -253,10 +297,16 @@ namespace Slic3r {
void reset();
// post process the file with the given filename to add remaining time lines M73
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
// and updates moves' gcode ids accordingly
void post_process(const std::string& filename, std::vector<MoveVertex>& moves);
#else
void post_process(const std::string& filename);
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
};
public:
#if !ENABLE_GCODE_LINES_ID_IN_H_SLIDER
struct MoveVertex
{
EMoveType type{ EMoveType::Noop };
@ -274,6 +324,7 @@ namespace Slic3r {
float volumetric_rate() const { return feedrate * mm3_per_mm; }
};
#endif // !ENABLE_GCODE_LINES_ID_IN_H_SLIDER
struct Result
{
@ -404,13 +455,14 @@ namespace Slic3r {
CachedPosition m_cached_position;
bool m_wiping;
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
unsigned int m_line_id;
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
float m_feedrate; // mm/s
float m_width; // mm
float m_height; // mm
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
float m_forced_width; // mm
float m_forced_height; // mm
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
float m_mm3_per_mm;
float m_fan_speed; // percentage
ExtrusionRole m_extrusion_role;

View File

@ -15,7 +15,7 @@ static constexpr float ENFORCER_BLOCKER_PENALTY = 100;
// In case there are custom enforcers/blockers, the loop polygon shall always have
// sides smaller than this (so it isn't limited to original resolution).
static constexpr float MINIMAL_POLYGON_SIDE = scale_(0.2f);
static constexpr float MINIMAL_POLYGON_SIDE = scaled<float>(0.2f);
// When spAligned is active and there is a support enforcer,
// add this penalty to its center.
@ -664,7 +664,7 @@ static std::vector<size_t> find_enforcer_centers(const Polygon& polygon,
if (polygon.size() < 2 || enforcers_idxs.empty())
return out;
auto get_center_idx = [&polygon, &lengths](size_t start_idx, size_t end_idx) -> size_t {
auto get_center_idx = [&lengths](size_t start_idx, size_t end_idx) -> size_t {
assert(end_idx >= start_idx);
if (start_idx == end_idx)
return start_idx;
@ -750,35 +750,36 @@ void SeamPlacer::apply_custom_seam(const Polygon& polygon, size_t po_idx,
}
}
////////////////////////
// std::ostringstream os;
// os << std::setw(3) << std::setfill('0') << layer_id;
// int a = scale_(30.);
// SVG svg("custom_seam" + os.str() + ".svg", BoundingBox(Point(-a, -a), Point(a, a)));
// //if (! m_enforcers[po_idx].empty())
// // svg.draw(m_enforcers[po_idx][layer_id].polys, "blue");
// //if (! m_blockers[po_idx].empty())
// // svg.draw(m_blockers[po_idx][layer_id].polys, "red");
#if 0
std::ostringstream os;
os << std::setw(3) << std::setfill('0') << layer_id;
int a = scale_(30.);
SVG svg("custom_seam" + os.str() + ".svg", BoundingBox(Point(-a, -a), Point(a, a)));
if (! m_enforcers[po_idx].empty())
svg.draw(m_enforcers[po_idx][layer_id].polys, "blue");
if (! m_blockers[po_idx].empty())
svg.draw(m_blockers[po_idx][layer_id].polys, "red");
if (! blockers_idxs.empty()) {
;
}
size_t min_idx = std::min_element(penalties.begin(), penalties.end()) - penalties.begin();
// size_t min_idx = std::min_element(penalties.begin(), penalties.end()) - penalties.begin();
// //svg.draw(polygon.points[idx_min], "red", 6e5);
// for (size_t i=0; i<polygon.points.size(); ++i) {
// std::string fill;
// coord_t size = 0;
// if (min_idx == i) {
// fill = "yellow";
// size = 5e5;
// } else
// fill = (std::find(enforcers_idxs.begin(), enforcers_idxs.end(), i) != enforcers_idxs.end() ? "green" : "black");
// if (i != 0)
// svg.draw(polygon.points[i], fill, size);
// else
// svg.draw(polygon.points[i], "red", 5e5);
// }
//////////////////////
for (size_t i=0; i<polygon.points.size(); ++i) {
std::string fill;
coord_t size = 5e5;
if (min_idx == i)
fill = "yellow";
else
fill = (std::find(blockers_idxs.begin(), blockers_idxs.end(), i) != blockers_idxs.end() ? "green" : "black");
if (i != 0)
svg.draw(polygon.points[i], fill, size);
else
svg.draw(polygon.points[i], "red", 5e5);
}
#endif
}
@ -786,16 +787,16 @@ void SeamPlacer::apply_custom_seam(const Polygon& polygon, size_t po_idx,
std::optional<Point> SeamHistory::get_last_seam(const PrintObject* po, size_t layer_id, const BoundingBox& island_bb)
{
assert(layer_id >= m_layer_id);
if (layer_id > m_layer_id) {
assert(layer_id >= m_layer_id || layer_id == 0);
if (layer_id != m_layer_id) {
// Get seam was called for different layer than last time.
if (layer_id == 0) // seq printing
m_data_this_layer.clear();
m_data_last_layer = m_data_this_layer;
m_data_this_layer.clear();
m_layer_id = layer_id;
}
std::optional<Point> out;
auto seams_it = m_data_last_layer.find(po);

View File

@ -600,7 +600,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
return std::max(0.f, volume_to_wipe); // Soluble filament cannot be wiped in a random infill, neither the filament after it
// we will sort objects so that dedicated for wiping are at the beginning:
PrintObjectPtrs object_list = print.objects();
ConstPrintObjectPtrs object_list = print.objects().vector();
std::sort(object_list.begin(), object_list.end(), [](const PrintObject* a, const PrintObject* b) { return a->config().wipe_into_objects; });
// We will now iterate through

View File

@ -42,36 +42,32 @@ public:
{
// adds tag for analyzer:
char buf[64];
#if ENABLE_VALIDATE_CUSTOM_GCODE
sprintf(buf, ";%s%f\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height).c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming
m_gcode += buf;
sprintf(buf, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erWipeTower).c_str());
#else
sprintf(buf, ";%s%f\n", GCodeProcessor::Height_Tag.c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming
m_gcode += buf;
sprintf(buf, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erWipeTower).c_str());
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
m_gcode += buf;
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE || ENABLE_GCODE_VIEWER_DATA_CHECKING
change_analyzer_line_width(line_width);
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE || ENABLE_GCODE_VIEWER_DATA_CHECKING
}
}
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
WipeTowerWriter& change_analyzer_line_width(float line_width) {
// adds tag for analyzer:
char buf[64];
#if ENABLE_VALIDATE_CUSTOM_GCODE
sprintf(buf, ";%s%f\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Width).c_str(), line_width);
#else
sprintf(buf, ";%s%f\n", GCodeProcessor::Width_Tag.c_str(), line_width);
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
m_gcode += buf;
return *this;
}
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
#if !ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
WipeTowerWriter& change_analyzer_line_width(float line_width) {
// adds tag for analyzer:
char buf[64];
sprintf(buf, ";%s%f\n", GCodeProcessor::Width_Tag.c_str(), line_width);
m_gcode += buf;
return *this;
}
#endif // !ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE
WipeTowerWriter& change_analyzer_mm3_per_mm(float len, float e) {
static const float area = float(M_PI) * 1.75f * 1.75f / 4.f;
float mm3_per_mm = (len == 0.f ? 0.f : area * e / len);
@ -405,7 +401,7 @@ public:
WipeTowerWriter& append(const std::string& text) { m_gcode += text; return *this; }
std::vector<Vec2f> wipe_path() const
const std::vector<Vec2f>& wipe_path() const
{
return m_wipe_path;
}
@ -874,12 +870,8 @@ void WipeTower::toolchange_Unload(
const float line_width = m_perimeter_width * m_filpar[m_current_tool].ramming_line_width_multiplicator; // desired ramming line thickness
const float y_step = line_width * m_filpar[m_current_tool].ramming_step_multiplicator * m_extra_spacing; // spacing between lines in mm
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE || ENABLE_GCODE_VIEWER_DATA_CHECKING
writer.append("; CP TOOLCHANGE UNLOAD\n")
.change_analyzer_line_width(line_width);
#else
writer.append("; CP TOOLCHANGE UNLOAD\n");
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE || ENABLE_GCODE_VIEWER_DATA_CHECKING
unsigned i = 0; // iterates through ramming_speed
m_left_to_right = true; // current direction of ramming
@ -942,9 +934,7 @@ void WipeTower::toolchange_Unload(
}
}
Vec2f end_of_ramming(writer.x(),writer.y());
#if ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE || ENABLE_GCODE_VIEWER_DATA_CHECKING
writer.change_analyzer_line_width(m_perimeter_width); // so the next lines are not affected by ramming_line_width_multiplier
#endif // ENABLE_TOOLPATHS_WIDTH_HEIGHT_FROM_GCODE || ENABLE_GCODE_VIEWER_DATA_CHECKING
// Retraction:
float old_x = writer.x();

View File

@ -116,8 +116,13 @@ void GCodeReader::parse_file(const std::string &file, callback_t callback)
{
boost::nowide::ifstream f(file);
std::string line;
#if ENABLE_VALIDATE_CUSTOM_GCODE
m_parsing = true;
while (m_parsing && std::getline(f, line))
#else
m_parsing_file = true;
while (m_parsing_file && std::getline(f, line))
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
this->parse_line(line, callback);
}

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