Merge branch 'master' into fs_CenterSupportForIsland
# Conflicts: # src/libslic3r/Geometry.hpp # tests/libslic3r/test_voronoi.cpp
@ -146,21 +146,33 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
# WIN10SDK_PATH is used to point CMake to the WIN10 SDK installation directory.
|
||||
# We pick it from environment if it is not defined in another way
|
||||
if(WIN32)
|
||||
if(NOT DEFINED WIN10SDK_PATH)
|
||||
if(DEFINED ENV{WIN10SDK_PATH})
|
||||
set(WIN10SDK_PATH "$ENV{WIN10SDK_PATH}")
|
||||
endif()
|
||||
if(NOT DEFINED WIN10SDK_PATH)
|
||||
if(DEFINED ENV{WIN10SDK_PATH})
|
||||
set(WIN10SDK_PATH "$ENV{WIN10SDK_PATH}")
|
||||
endif()
|
||||
if(DEFINED WIN10SDK_PATH AND NOT EXISTS "${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h")
|
||||
message("WIN10SDK_PATH is invalid: ${WIN10SDK_PATH}")
|
||||
message("${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h was not found")
|
||||
message("STL fixing by the Netfabb service will not be compiled")
|
||||
unset(WIN10SDK_PATH)
|
||||
endif()
|
||||
if(DEFINED WIN10SDK_PATH)
|
||||
if (EXISTS "${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h")
|
||||
set(WIN10SDK_INCLUDE_PATH "${WIN10SDK_PATH}/Include")
|
||||
else()
|
||||
message("WIN10SDK_PATH is invalid: ${WIN10SDK_PATH}")
|
||||
message("${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h was not found")
|
||||
message("STL fixing by the Netfabb service will not be compiled")
|
||||
unset(WIN10SDK_PATH)
|
||||
endif()
|
||||
if(WIN10SDK_PATH)
|
||||
else()
|
||||
# Try to use the default Windows 10 SDK path.
|
||||
set(WIN10SDK_INCLUDE_PATH "$ENV{WindowsSdkDir}/Include/$ENV{WindowsSDKVersion}")
|
||||
if (NOT EXISTS "${WIN10SDK_INCLUDE_PATH}/winrt/windows.graphics.printing3d.h")
|
||||
message("${WIN10SDK_INCLUDE_PATH}/winrt/windows.graphics.printing3d.h was not found")
|
||||
message("STL fixing by the Netfabb service will not be compiled")
|
||||
unset(WIN10SDK_INCLUDE_PATH)
|
||||
endif()
|
||||
endif()
|
||||
if(WIN10SDK_INCLUDE_PATH)
|
||||
message("Building with Win10 Netfabb STL fixing service support")
|
||||
add_definitions(-DHAS_WIN10SDK)
|
||||
include_directories("${WIN10SDK_PATH}/Include")
|
||||
include_directories("${WIN10SDK_INCLUDE_PATH}")
|
||||
else()
|
||||
message("Building without Win10 Netfabb STL fixing service support")
|
||||
endif()
|
||||
@ -226,17 +238,23 @@ if (NOT MSVC AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMP
|
||||
add_compile_options(-Wno-unknown-pragmas)
|
||||
endif()
|
||||
|
||||
if (SLIC3R_ASAN)
|
||||
add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
|
||||
endif()
|
||||
|
||||
if (SLIC3R_ASAN)
|
||||
# ASAN should be available on MSVC starting with Visual Studio 2019 16.9
|
||||
# https://devblogs.microsoft.com/cppblog/address-sanitizer-for-msvc-now-generally-available/
|
||||
add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
|
||||
|
||||
if (NOT MSVC)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=address")
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan")
|
||||
endif ()
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=partial-availability -Werror=unguarded-availability -Werror=unguarded-availability-new")
|
||||
@ -300,7 +318,7 @@ 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")
|
||||
set(_boost_components "system;filesystem;thread;log;locale;regex;chrono;atomic;date_time;iostreams")
|
||||
find_package(Boost ${MINIMUM_BOOST_VERSION} REQUIRED COMPONENTS ${_boost_components})
|
||||
|
||||
add_library(boost_libs INTERFACE)
|
||||
|
4
deps/deps-linux.cmake
vendored
@ -13,7 +13,7 @@ include("deps-unix-common.cmake")
|
||||
|
||||
ExternalProject_Add(dep_boost
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "https://dl.bintray.com/boostorg/release/1.75.0/source/boost_1_75_0.tar.gz"
|
||||
URL "https://boostorg.jfrog.io/artifactory/main/release/1.75.0/source/boost_1_75_0.tar.gz"
|
||||
URL_HASH SHA256=aeb26f80e80945e82ee93e5939baebdca47b9dee80a07d3144be1e1a6a66dd6a
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ./bootstrap.sh
|
||||
@ -100,5 +100,5 @@ ExternalProject_Add(dep_libcurl
|
||||
BUILD_COMMAND make "-j${NPROC}"
|
||||
INSTALL_COMMAND make install "DESTDIR=${DESTDIR}"
|
||||
)
|
||||
|
||||
add_dependencies(dep_openvdb dep_boost)
|
||||
|
||||
|
4
deps/deps-macos.cmake
vendored
@ -18,7 +18,7 @@ include("deps-unix-common.cmake")
|
||||
|
||||
ExternalProject_Add(dep_boost
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "https://dl.bintray.com/boostorg/release/1.75.0/source/boost_1_75_0.tar.gz"
|
||||
URL "https://boostorg.jfrog.io/artifactory/main/release/1.75.0/source/boost_1_75_0.tar.gz"
|
||||
URL_HASH SHA256=aeb26f80e80945e82ee93e5939baebdca47b9dee80a07d3144be1e1a6a66dd6a
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ./bootstrap.sh
|
||||
@ -87,5 +87,5 @@ ExternalProject_Add(dep_libcurl
|
||||
BUILD_COMMAND make "-j${NPROC}"
|
||||
INSTALL_COMMAND make install "DESTDIR=${DESTDIR}"
|
||||
)
|
||||
|
||||
add_dependencies(dep_openvdb dep_boost)
|
||||
|
||||
|
3
deps/deps-mingw.cmake
vendored
@ -9,7 +9,7 @@ include("deps-unix-common.cmake")
|
||||
|
||||
ExternalProject_Add(dep_boost
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "https://dl.bintray.com/boostorg/release/1.75.0/source/boost_1_75_0.tar.gz"
|
||||
URL "https://boostorg.jfrog.io/artifactory/main/release/1.75.0/source/boost_1_75_0.tar.gz"
|
||||
URL_HASH SHA256=aeb26f80e80945e82ee93e5939baebdca47b9dee80a07d3144be1e1a6a66dd6a
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND bootstrap.bat
|
||||
@ -59,3 +59,4 @@ ExternalProject_Add(dep_libcurl
|
||||
-DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local
|
||||
${DEP_CMAKE_OPTS}
|
||||
)
|
||||
|
||||
|
3
deps/deps-windows.cmake
vendored
@ -55,7 +55,7 @@ endmacro()
|
||||
|
||||
ExternalProject_Add(dep_boost
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "https://dl.bintray.com/boostorg/release/1.75.0/source/boost_1_75_0.tar.gz"
|
||||
URL "https://boostorg.jfrog.io/artifactory/main/release/1.75.0/source/boost_1_75_0.tar.gz"
|
||||
URL_HASH SHA256=aeb26f80e80945e82ee93e5939baebdca47b9dee80a07d3144be1e1a6a66dd6a
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND bootstrap.bat
|
||||
@ -296,3 +296,4 @@ if (${DEP_DEBUG})
|
||||
WORKING_DIRECTORY "${BINARY_DIR}"
|
||||
)
|
||||
endif ()
|
||||
|
||||
|
10
deps/wxWidgets/wxWidgets.cmake
vendored
@ -1,11 +1,4 @@
|
||||
if (APPLE)
|
||||
# The new OSX 11 (Big Sur) is not compatible with wxWidgets 3.1.3.
|
||||
# Let's use patched wxWidgets 3.1.4, even though it is not quite tested.
|
||||
set(_wx_git_tag v3.1.4-patched)
|
||||
else ()
|
||||
# Use the tested patched wxWidgets 3.1.3 everywhere else.
|
||||
set(_wx_git_tag v3.1.3-patched)
|
||||
endif ()
|
||||
set(_wx_git_tag v3.1.4-patched)
|
||||
|
||||
# set(_patch_command "")
|
||||
set(_wx_toolkit "")
|
||||
@ -27,6 +20,7 @@ prusaslicer_add_cmake_project(wxWidgets
|
||||
${_wx_toolkit}
|
||||
"-DCMAKE_DEBUG_POSTFIX:STRING="
|
||||
-DwxBUILD_DEBUG_LEVEL=0
|
||||
-DwxUSE_MEDIACTRL=OFF
|
||||
-DwxUSE_DETECT_SM=OFF
|
||||
-DwxUSE_UNICODE=ON
|
||||
-DwxUSE_OPENGL=ON
|
||||
|
8
resources/icons/fuzzy_skin.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.3, 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>
|
||||
<circle fill="#808080" cx="8" cy="8" r="0"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 400 B |
BIN
resources/icons/info.png
Normal file
After Width: | Height: | Size: 308 B |
67
resources/icons/notification_cancel.svg
Normal file
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 800 800"
|
||||
style="enable-background:new 0 0 800 800;"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="notification_cancel.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"><metadata
|
||||
id="metadata15"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs13" /><sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2066"
|
||||
id="namedview11"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.26"
|
||||
inkscape:cx="400"
|
||||
inkscape:cy="389.28571"
|
||||
inkscape:window-x="-11"
|
||||
inkscape:window-y="-11"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
.st0{fill:#ED6B21;}
|
||||
</style>
|
||||
|
||||
|
||||
<g
|
||||
id="g4"
|
||||
transform="matrix(0.9775,0,0,0.9775,53.547,53.54775)">
|
||||
<path
|
||||
id="path2"
|
||||
class="st0"
|
||||
d="M 597.2,701.3 H 110.6 C 53.2,701.3 6.5,654.6 6.5,597.2 V 110.6 C 6.5,53.2 53.2,6.5 110.6,6.5 h 486.6 c 57.4,0 104.1,46.7 104.1,104.1 v 486.6 c 0,57.4 -46.7,104.1 -104.1,104.1 z M 110.6,52.4 c -32,0 -58.2,26 -58.2,58.2 v 486.6 c 0,32 26,58.2 58.2,58.2 h 486.6 c 32,0 58.2,-26 58.2,-58.2 V 110.6 c 0,-32 -26,-58.2 -58.2,-58.2 z" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:#ed6b21;fill-opacity:1;stroke-width:0.674603"
|
||||
d="m 150.65676,738.12999 c -12.4717,-1.39663 -26.66772,-5.94192 -37.84321,-12.11671 -17.754551,-9.80992 -33.768844,-26.68981 -42.418124,-44.71089 -5.985061,-12.4701 -8.760227,-23.35456 -9.821918,-38.52249 -0.48061,-6.8663 -0.640464,-87.42616 -0.497289,-250.61508 0.195544,-222.88027 0.294923,-240.94223 1.356742,-246.58759 4.2349,-22.51562 13.68014,-40.62012 29.200931,-55.97194 14.237938,-14.082924 31.958648,-23.427941 52.602238,-27.739791 5.87892,-1.227937 14.00696,-1.268146 256.3492,-1.268146 h 250.27778 l 7.08334,1.561512 c 21.30688,4.697075 36.90336,13.216072 51.96052,28.381502 14.67865,14.784203 23.1932,30.350373 27.76125,50.752683 l 1.56791,7.00271 v 250.95239 c 0,242.72256 -0.0418,251.15149 -1.26428,257.0238 -9.30592,44.69034 -45.18963,77.43352 -89.75566,81.90028 -9.17898,0.92002 -488.33076,0.87927 -496.55943,-0.0425 z M 652.87275,692.49 c 19.93824,-6.17834 34.6922,-21.42493 40.00111,-41.33675 l 1.51306,-5.67494 V 399.58544 153.69259 l -1.52571,-5.73412 c -5.66288,-21.28292 -21.4158,-36.89778 -42.2051,-41.83523 -5.63965,-1.33941 -7.66026,-1.3488 -253.17948,-1.17613 l -247.49447,0.17405 -4.72222,1.5953 c -18.05932,6.10093 -31.7315,19.23923 -37.4918,36.0278 -1.04762,3.05333 -2.22128,7.52472 -2.60813,9.93642 -0.47859,2.9836 -0.705,81.91876 -0.70847,246.99889 -0.005,218.14117 0.10226,243.1829 1.05916,248.25397 4.27172,22.63802 22.24346,40.86392 44.80877,45.4425 3.58848,0.72811 49.16893,0.87009 250.95237,0.78171 l 246.56747,-0.10801 z"
|
||||
id="path17" /><rect
|
||||
y="239.60318"
|
||||
x="240.87302"
|
||||
height="321.58731"
|
||||
width="322.22223"
|
||||
id="rect30"
|
||||
style="fill:#ed6b21;stroke-width:0.4" /></svg>
|
After Width: | Height: | Size: 3.6 KiB |
67
resources/icons/notification_cancel_hover.svg
Normal file
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 800 800"
|
||||
style="enable-background:new 0 0 800 800;"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="notification_cancel_hover.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"><metadata
|
||||
id="metadata15"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs13" /><sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2066"
|
||||
id="namedview11"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.26"
|
||||
inkscape:cx="400"
|
||||
inkscape:cy="389.28571"
|
||||
inkscape:window-x="-11"
|
||||
inkscape:window-y="-11"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
.st0{fill:#ED6B21;}
|
||||
</style>
|
||||
|
||||
|
||||
<g
|
||||
id="g4"
|
||||
transform="matrix(1.173,0,0,1.173,-15.64045,-15.6397)">
|
||||
<path
|
||||
id="path2"
|
||||
class="st0"
|
||||
d="M 597.2,701.3 H 110.6 C 53.2,701.3 6.5,654.6 6.5,597.2 V 110.6 C 6.5,53.2 53.2,6.5 110.6,6.5 h 486.6 c 57.4,0 104.1,46.7 104.1,104.1 v 486.6 c 0,57.4 -46.7,104.1 -104.1,104.1 z M 110.6,52.4 c -32,0 -58.2,26 -58.2,58.2 v 486.6 c 0,32 26,58.2 58.2,58.2 h 486.6 c 32,0 58.2,-26 58.2,-58.2 V 110.6 c 0,-32 -26,-58.2 -58.2,-58.2 z" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:#ed6b21;fill-opacity:1;stroke-width:0.809524"
|
||||
d="M 100.89126,805.85899 C 85.925222,804.18303 68.889998,798.72868 55.47941,791.31894 34.173949,779.54703 14.956797,759.29116 4.5776612,737.66587 -2.604412,722.70175 -5.9346112,709.6404 -7.2086404,691.43888 -7.7853724,683.19932 -7.9771972,586.52749 -7.8053872,390.70078 -7.5707344,123.24446 -7.4514796,101.57011 -6.1772968,94.795676 -1.0954168,67.776932 10.238871,46.051532 28.86382,27.629348 45.949346,10.729839 67.214198,-0.4841812 91.986506,-5.6584012 99.04121,-7.1319256 108.79486,-7.1801764 399.60555,-7.1801764 h 300.33333 l 8.50001,1.8738144 c 25.56826,5.63649 44.28403,15.859286 62.35262,34.057802 17.61438,17.741044 27.83184,36.420448 33.3135,60.90322 l 1.8815,8.403252 V 399.20078 c 0,291.26707 -0.0502,301.38179 -1.51714,308.42856 -11.1671,53.62841 -54.22756,92.92022 -107.70679,98.28034 -11.01478,1.10402 -585.99691,1.05512 -595.87132,-0.051 z M 703.55045,751.091 c 23.92589,-7.41401 41.63064,-25.70992 48.00133,-49.6041 l 1.81567,-6.80993 V 399.60553 104.53411 L 751.5366,97.653164 C 744.74115,72.11366 725.83764,53.375828 700.89048,47.450888 694.1229,45.843596 691.69817,45.832328 397.07511,46.039532 l -296.99337,0.20886 -5.666662,1.91436 c -21.671184,7.321116 -38.0778,23.087076 -44.99016,43.23336 -1.257144,3.663996 -2.665536,9.029668 -3.129756,11.923708 -0.574308,3.58032 -0.846,98.30251 -0.850164,296.39866 -0.006,261.76941 0.122712,291.81948 1.270992,297.90477 5.126064,27.16562 26.692152,49.0367 53.77052,54.531 4.30618,0.87373 59.00272,1.04411 301.14285,0.93805 l 295.88096,-0.12961 z"
|
||||
id="path17" /><rect
|
||||
y="207.62682"
|
||||
x="209.15077"
|
||||
height="385.90479"
|
||||
width="386.66669"
|
||||
id="rect30"
|
||||
style="fill:#ed6b21;stroke-width:0.48" /></svg>
|
After Width: | Height: | Size: 3.7 KiB |
@ -28,6 +28,7 @@ src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
|
||||
src/slic3r/GUI/GUI.cpp
|
||||
src/slic3r/GUI/GUI_App.cpp
|
||||
src/slic3r/GUI/GUI_Init.cpp
|
||||
src/slic3r/GUI/GUI_Factories.cpp
|
||||
src/slic3r/GUI/GUI_ObjectLayers.cpp
|
||||
src/slic3r/GUI/GUI_ObjectList.cpp
|
||||
src/slic3r/GUI/GUI_ObjectManipulation.cpp
|
||||
|
@ -1,3 +1,5 @@
|
||||
min_slic3r_version = 2.3.1-beta
|
||||
0.0.9 Updated bed textures
|
||||
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.
|
||||
|
@ -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.8
|
||||
config_version = 0.0.9
|
||||
# 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%
|
||||
|
@ -1,2 +1,2 @@
|
||||
min_slic3r_version = 2.3.0
|
||||
min_slic3r_version = 2.3.1-beta
|
||||
0.0.1 Initial Artillery bundle
|
||||
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
@ -1,3 +1,6 @@
|
||||
min_slic3r_version = 2.3.1-beta
|
||||
0.0.16 Updated CR6-SE start g-code. Added and updated filament profiles.
|
||||
0.0.15 Added new printer models, filament profiles. Various improvements.
|
||||
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.
|
||||
|
@ -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.14
|
||||
config_version = 0.0.16
|
||||
# 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%
|
||||
@ -21,7 +21,7 @@ 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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:ENDER3BLTOUCH]
|
||||
name = Creality Ender-3 BLTouch
|
||||
@ -30,7 +30,7 @@ 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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:ENDER3V2]
|
||||
name = Creality Ender-3 V2
|
||||
@ -39,25 +39,25 @@ 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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @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: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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @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: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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:ENDER5]
|
||||
name = Creality Ender-5
|
||||
@ -66,7 +66,7 @@ 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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:ENDER5PLUS]
|
||||
name = Creality Ender-5 Plus
|
||||
@ -75,16 +75,16 @@ technology = FFF
|
||||
family = ENDER
|
||||
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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @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: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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:ENDER2]
|
||||
name = Creality Ender-2
|
||||
@ -93,25 +93,43 @@ technology = FFF
|
||||
family = ENDER
|
||||
bed_model = ender2_bed.stl
|
||||
bed_texture = ender2.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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
#[printer_model:CR6SE]
|
||||
#name = Creality CR-6 SE
|
||||
#variants = 0.4
|
||||
#technology = FFF
|
||||
#family = CR
|
||||
#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:CR5PRO]
|
||||
name = Creality CR-5 Pro
|
||||
variants = 0.4
|
||||
technology = FFF
|
||||
family = CR
|
||||
bed_model = cr5pro_bed.stl
|
||||
bed_texture = cr5pro.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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @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:CR5PROH]
|
||||
name = Creality CR-5 Pro H
|
||||
variants = 0.4
|
||||
technology = FFF
|
||||
family = CR
|
||||
bed_model = cr5pro_bed.stl
|
||||
bed_texture = cr5pro.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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:CR6SE]
|
||||
name = Creality CR-6 SE
|
||||
variants = 0.4
|
||||
technology = FFF
|
||||
family = CR
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:CR10MINI]
|
||||
name = Creality CR-10 Mini
|
||||
@ -120,16 +138,16 @@ technology = FFF
|
||||
family = CR
|
||||
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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @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: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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:CR10]
|
||||
name = Creality CR-10
|
||||
@ -138,7 +156,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10_bed.stl
|
||||
bed_texture = cr10.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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:CR10V2]
|
||||
name = Creality CR-10 V2
|
||||
@ -147,7 +165,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10v2_bed.stl
|
||||
bed_texture = cr10.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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:CR10V3]
|
||||
name = Creality CR-10 V3
|
||||
@ -156,7 +174,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10v2_bed.stl
|
||||
bed_texture = cr10.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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:CR10S]
|
||||
name = Creality CR-10 S
|
||||
@ -165,7 +183,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10_bed.stl
|
||||
bed_texture = cr10.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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:CR10SPRO]
|
||||
name = Creality CR-10 S Pro
|
||||
@ -174,7 +192,7 @@ technology = FFF
|
||||
family = CR
|
||||
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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:CR10SPROV2]
|
||||
name = Creality CR-10 S Pro V2
|
||||
@ -183,7 +201,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10v2_bed.stl
|
||||
bed_texture = cr10.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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:CR10S4]
|
||||
name = Creality CR-10 S4
|
||||
@ -192,7 +210,7 @@ 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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:CR10S5]
|
||||
name = Creality CR-10 S5
|
||||
@ -201,7 +219,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10s5_bed.stl
|
||||
bed_texture = cr10s5.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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:CR20]
|
||||
name = Creality CR-20
|
||||
@ -210,7 +228,7 @@ technology = FFF
|
||||
family = CR
|
||||
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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
[printer_model:CR20PRO]
|
||||
name = Creality CR-20 Pro
|
||||
@ -219,16 +237,25 @@ technology = FFF
|
||||
family = CR
|
||||
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
|
||||
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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @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:CR200B]
|
||||
name = Creality CR-200B
|
||||
variants = 0.4
|
||||
technology = FFF
|
||||
family = CR
|
||||
bed_model = cr200b_bed.stl
|
||||
bed_texture = cr200b.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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
#[printer_model:CRX]
|
||||
#name = Creality CR-X
|
||||
@ -237,7 +264,7 @@ default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @
|
||||
#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
|
||||
#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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
|
||||
|
||||
#[printer_model:CRXPRO]
|
||||
#name = Creality CR-X Pro
|
||||
@ -246,7 +273,7 @@ default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @
|
||||
#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
|
||||
#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; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @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.
|
||||
@ -254,6 +281,7 @@ default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @
|
||||
# Common print preset
|
||||
[print:*common*]
|
||||
avoid_crossing_perimeters = 0
|
||||
bridge_acceleration = 250
|
||||
bridge_angle = 0
|
||||
bridge_flow_ratio = 0.95
|
||||
bridge_speed = 25
|
||||
@ -261,6 +289,7 @@ brim_width = 0
|
||||
clip_multipart_objects = 1
|
||||
compatible_printers =
|
||||
complete_objects = 0
|
||||
default_acceleration = 500
|
||||
dont_support_bridges = 1
|
||||
elefant_foot_compensation = 0.1
|
||||
ensure_vertical_shell_thickness = 1
|
||||
@ -269,11 +298,11 @@ external_perimeters_first = 0
|
||||
external_perimeter_extrusion_width = 0.45
|
||||
external_perimeter_speed = 25
|
||||
extra_perimeters = 0
|
||||
extruder_clearance_height = 25
|
||||
extruder_clearance_radius = 45
|
||||
extruder_clearance_height = 34
|
||||
extruder_clearance_radius = 47
|
||||
extrusion_width = 0.45
|
||||
fill_angle = 45
|
||||
fill_density = 20%
|
||||
fill_density = 15%
|
||||
fill_pattern = grid
|
||||
first_layer_extrusion_width = 0.42
|
||||
first_layer_height = 0.2
|
||||
@ -307,9 +336,9 @@ print_settings_id =
|
||||
raft_layers = 0
|
||||
resolution = 0
|
||||
seam_position = nearest
|
||||
single_extruder_multi_material_priming = 1
|
||||
single_extruder_multi_material_priming = 0
|
||||
skirts = 1
|
||||
skirt_distance = 2
|
||||
skirt_distance = 3
|
||||
skirt_height = 2
|
||||
small_perimeter_speed = 25
|
||||
solid_infill_below_area = 0
|
||||
@ -335,7 +364,7 @@ support_material_pattern = rectilinear
|
||||
support_material_spacing = 2
|
||||
support_material_speed = 40
|
||||
support_material_synchronize_layers = 0
|
||||
support_material_threshold = 45
|
||||
support_material_threshold = 40
|
||||
support_material_with_sheath = 0
|
||||
support_material_xy_spacing = 60%
|
||||
thin_walls = 0
|
||||
@ -356,13 +385,15 @@ layer_height = 0.08
|
||||
perimeters = 3
|
||||
bottom_solid_layers = 9
|
||||
top_solid_layers = 11
|
||||
bridge_flow_ratio = 0.70
|
||||
|
||||
[print:*0.10mm*]
|
||||
inherits = *common*
|
||||
layer_height = 0.1
|
||||
layer_height = 0.10
|
||||
perimeters = 3
|
||||
bottom_solid_layers = 7
|
||||
top_solid_layers = 9
|
||||
bridge_flow_ratio = 0.70
|
||||
|
||||
[print:*0.12mm*]
|
||||
inherits = *common*
|
||||
@ -370,12 +401,14 @@ layer_height = 0.12
|
||||
perimeters = 3
|
||||
bottom_solid_layers = 6
|
||||
top_solid_layers = 7
|
||||
bridge_flow_ratio = 0.70
|
||||
|
||||
[print:*0.16mm*]
|
||||
inherits = *common*
|
||||
layer_height = 0.16
|
||||
bottom_solid_layers = 5
|
||||
top_solid_layers = 7
|
||||
bridge_flow_ratio = 0.85
|
||||
|
||||
[print:*0.20mm*]
|
||||
inherits = *common*
|
||||
@ -604,9 +637,11 @@ first_layer_bed_temperature = 60
|
||||
filament_cost = 19.00
|
||||
filament_density = 1.24
|
||||
filament_colour = #FF0000
|
||||
filament_spool_weight = 256
|
||||
|
||||
[filament:Devil Design PLA (Galaxy) @CREALITY]
|
||||
[filament:Devil Design PLA Galaxy @CREALITY]
|
||||
inherits = *PLA*
|
||||
renamed_from = "Devil Design PLA (Galaxy) @CREALITY"
|
||||
filament_vendor = Devil Design
|
||||
temperature = 225
|
||||
bed_temperature = 65
|
||||
@ -615,6 +650,7 @@ first_layer_bed_temperature = 65
|
||||
filament_cost = 19.00
|
||||
filament_density = 1.24
|
||||
filament_colour = #FF0000
|
||||
filament_spool_weight = 256
|
||||
|
||||
[filament:Extrudr PLA NX2 @CREALITY]
|
||||
inherits = *PLA*
|
||||
@ -673,6 +709,40 @@ filament_density = 1.24
|
||||
filament_colour = #125467
|
||||
filament_spool_weight = 238
|
||||
|
||||
[filament:3DJAKE ecoPLA Matt @CREALITY]
|
||||
inherits = *PLA*
|
||||
filament_vendor = 3DJAKE
|
||||
temperature = 195
|
||||
bed_temperature = 60
|
||||
first_layer_temperature = 195
|
||||
first_layer_bed_temperature = 60
|
||||
filament_cost = 24.99
|
||||
filament_density = 1.38
|
||||
filament_colour = #125467
|
||||
filament_spool_weight = 238
|
||||
|
||||
[filament:3DJAKE ecoPLA Tough @CREALITY]
|
||||
inherits = *PLA*
|
||||
filament_vendor = 3DJAKE
|
||||
temperature = 215
|
||||
bed_temperature = 60
|
||||
first_layer_temperature = 215
|
||||
first_layer_bed_temperature = 60
|
||||
filament_cost = 29.99
|
||||
filament_density = 1.21
|
||||
filament_colour = #125467
|
||||
|
||||
[filament:FormFutura Tough PLA @CREALITY]
|
||||
inherits = *PLA*
|
||||
filament_vendor = FormFutura
|
||||
temperature = 215
|
||||
bed_temperature = 60
|
||||
first_layer_temperature = 215
|
||||
first_layer_bed_temperature = 60
|
||||
filament_cost = 46.65
|
||||
filament_density = 1.21
|
||||
filament_colour = #ed000e
|
||||
|
||||
[filament:123-3D Jupiter PLA @CREALITY]
|
||||
inherits = *PLA*
|
||||
filament_vendor = 123-3D
|
||||
@ -712,7 +782,7 @@ printer_technology = FFF
|
||||
before_layer_gcode = ;BEFORE_LAYER_CHANGE\nG92 E0\n;[layer_z]\n\n
|
||||
between_objects_gcode =
|
||||
pause_print_gcode =
|
||||
deretract_speed = 0
|
||||
deretract_speed = 40
|
||||
extruder_colour = #FCE94F
|
||||
extruder_offset = 0x0
|
||||
gcode_flavor = marlin
|
||||
@ -735,23 +805,24 @@ machine_max_jerk_z = 0.4
|
||||
machine_min_extruding_rate = 0
|
||||
machine_min_travel_rate = 0
|
||||
layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z]
|
||||
max_layer_height = 0.3
|
||||
min_layer_height = 0.07
|
||||
max_layer_height = 0.28
|
||||
min_layer_height = 0.08
|
||||
max_print_height = 250
|
||||
nozzle_diameter = 0.4
|
||||
printer_notes =
|
||||
printer_settings_id =
|
||||
retract_before_travel = 1
|
||||
retract_before_wipe = 0%
|
||||
printer_variant = 0.4
|
||||
retract_before_travel = 2
|
||||
retract_before_wipe = 70%
|
||||
retract_layer_change = 1
|
||||
retract_length = 1
|
||||
retract_length = 5
|
||||
retract_length_toolchange = 1
|
||||
retract_lift = 0
|
||||
retract_lift_above = 0
|
||||
retract_lift_below = 0
|
||||
retract_restart_extra = 0
|
||||
retract_restart_extra_toolchange = 0
|
||||
retract_speed = 35
|
||||
retract_speed = 60
|
||||
single_extruder_multi_material = 0
|
||||
toolchange_gcode =
|
||||
use_firmware_retraction = 0
|
||||
@ -763,39 +834,6 @@ z_offset = 0
|
||||
printer_model =
|
||||
default_print_profile = 0.16mm OPTIMAL @CREALITY
|
||||
default_filament_profile = Generic PLA @CREALITY
|
||||
|
||||
[printer:Creality Ender-3]
|
||||
inherits = *common*
|
||||
renamed_from = "Creality ENDER-3"
|
||||
printer_model = ENDER3
|
||||
printer_variant = 0.4
|
||||
max_layer_height = 0.28
|
||||
min_layer_height = 0.08
|
||||
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_ENDER3\nPRINTER_HAS_BOWDEN
|
||||
bed_shape = 3x3,228x3,228x228,3x228
|
||||
max_print_height = 250
|
||||
machine_max_acceleration_e = 5000
|
||||
machine_max_acceleration_extruding = 500
|
||||
machine_max_acceleration_retracting = 1000
|
||||
machine_max_acceleration_x = 500
|
||||
machine_max_acceleration_y = 500
|
||||
machine_max_acceleration_z = 100
|
||||
machine_max_feedrate_e = 60
|
||||
machine_max_feedrate_x = 500
|
||||
machine_max_feedrate_y = 500
|
||||
machine_max_feedrate_z = 10
|
||||
machine_max_jerk_e = 5
|
||||
machine_max_jerk_x = 8
|
||||
machine_max_jerk_y = 8
|
||||
machine_max_jerk_z = 0.4
|
||||
machine_min_extruding_rate = 0
|
||||
machine_min_travel_rate = 0
|
||||
nozzle_diameter = 0.4
|
||||
retract_before_travel = 2
|
||||
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 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
|
||||
|
||||
@ -813,7 +851,6 @@ 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:*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
|
||||
@ -842,34 +879,44 @@ retract_restart_extra_toolchange = 0,0
|
||||
retract_speed = 60,60
|
||||
wipe = 1,1
|
||||
|
||||
[printer:Creality Ender-3]
|
||||
inherits = *common*
|
||||
renamed_from = "Creality ENDER-3"
|
||||
bed_shape = 3x3,228x3,228x228,3x228
|
||||
max_print_height = 250
|
||||
printer_model = ENDER3
|
||||
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_ENDER3\nPRINTER_HAS_BOWDEN
|
||||
|
||||
[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
|
||||
inherits = *common*
|
||||
renamed_from = "Creality Ender-3V2"
|
||||
printer_model = ENDER3V2
|
||||
bed_shape = 5x0,215x0,215x220,5x220
|
||||
max_print_height = 250
|
||||
printer_model = ENDER3V2
|
||||
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_ENDER3V2\nPRINTER_HAS_BOWDEN
|
||||
|
||||
#[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-3 Max]
|
||||
inherits = *common*
|
||||
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-4]
|
||||
inherits = *common*; *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; *descendingz*
|
||||
inherits = *common*; *descendingz*
|
||||
retract_length = 6
|
||||
bed_shape = 5x2.5,225x2.5,225x222.5,5x222.5
|
||||
max_print_height = 300
|
||||
@ -879,7 +926,7 @@ machine_max_acceleration_e = 1000
|
||||
machine_max_feedrate_z = 5
|
||||
|
||||
[printer:Creality Ender-5 Plus]
|
||||
inherits = Creality Ender-3; *slowabl*; *descendingz*
|
||||
inherits = *common*; *slowabl*; *descendingz*
|
||||
retract_length = 6
|
||||
bed_shape = 5x5,355x5,355x355,5x355
|
||||
max_print_height = 400
|
||||
@ -890,53 +937,69 @@ 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-6]
|
||||
inherits = *common*; *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
|
||||
inherits = *common*
|
||||
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
|
||||
|
||||
#[printer:Creality CR-6 SE]
|
||||
#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-5 Pro]
|
||||
inherits = *common*; *slowabl*; *descendingz*
|
||||
retract_length = 6
|
||||
bed_shape = 5x5,295x5,295x220,5x220
|
||||
max_print_height = 380
|
||||
printer_model = CR5PRO
|
||||
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_CR5PRO\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-5 Pro H]
|
||||
inherits = *common*; *slowabl*; *descendingz*
|
||||
retract_length = 3
|
||||
bed_shape = 5x5,295x5,295x220,5x220
|
||||
max_print_height = 380
|
||||
printer_model = CR5PROH
|
||||
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_CR5PROH\nPRINTER_HAS_BOWDEN
|
||||
|
||||
[printer:Creality CR-6 SE]
|
||||
inherits = *common*; *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 = *common*; *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
|
||||
inherits = *common*
|
||||
retract_length = 6
|
||||
bed_shape = 2.5x5,2.5x225,302.5x225,302.5x5
|
||||
bed_shape = 2.5x5,302.5x5,302.5x225,2.5x225
|
||||
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
|
||||
|
||||
#[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 Max]
|
||||
inherits = *common*; *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
|
||||
inherits = *common*
|
||||
retract_length = 6
|
||||
bed_shape = 5x5,305x5,305x305,5x305
|
||||
max_print_height = 400
|
||||
@ -944,7 +1007,7 @@ 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
|
||||
|
||||
[printer:Creality CR-10 V2]
|
||||
inherits = Creality Ender-3
|
||||
inherits = *common*
|
||||
retract_length = 6
|
||||
bed_shape = 5x5,305x5,305x305,5x305
|
||||
max_print_height = 400
|
||||
@ -952,7 +1015,7 @@ 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
|
||||
|
||||
[printer:Creality CR-10 V3]
|
||||
inherits = Creality Ender-3
|
||||
inherits = *common*
|
||||
retract_length = 1
|
||||
bed_shape = 5x5,305x5,305x305,5x305
|
||||
max_print_height = 400
|
||||
@ -960,7 +1023,7 @@ 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
|
||||
|
||||
[printer:Creality CR-10 S]
|
||||
inherits = Creality Ender-3
|
||||
inherits = *common*
|
||||
retract_length = 6
|
||||
bed_shape = 5x5,305x5,305x305,5x305
|
||||
max_print_height = 400
|
||||
@ -968,7 +1031,7 @@ 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
|
||||
|
||||
[printer:Creality CR-10 S Pro]
|
||||
inherits = Creality Ender-3; *slowabl*
|
||||
inherits = *common*; *slowabl*
|
||||
retract_length = 6
|
||||
bed_shape = 5x5,295x5,295x295,5x295
|
||||
max_print_height = 400
|
||||
@ -976,7 +1039,7 @@ 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
|
||||
|
||||
[printer:Creality CR-10 S Pro V2]
|
||||
inherits = Creality Ender-3; *slowabl*
|
||||
inherits = *common*; *slowabl*
|
||||
retract_length = 6
|
||||
bed_shape = 5x5,305x5,305x305,5x305
|
||||
max_print_height = 400
|
||||
@ -984,7 +1047,7 @@ 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
|
||||
|
||||
[printer:Creality CR-10 S4]
|
||||
inherits = Creality Ender-3
|
||||
inherits = *common*
|
||||
retract_length = 6
|
||||
bed_shape = 5x5,395x5,395x395,5x395
|
||||
max_print_height = 400
|
||||
@ -992,7 +1055,7 @@ 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
|
||||
|
||||
[printer:Creality CR-10 S5]
|
||||
inherits = Creality Ender-3
|
||||
inherits = *common*
|
||||
retract_length = 6
|
||||
bed_shape = 5x5,505x5,505x505,5x505
|
||||
max_print_height = 500
|
||||
@ -1000,25 +1063,32 @@ 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
|
||||
|
||||
[printer:Creality CR-20]
|
||||
inherits = Creality Ender-3
|
||||
inherits = *common*
|
||||
printer_model = CR20
|
||||
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_CR20\nPRINTER_HAS_BOWDEN
|
||||
|
||||
[printer:Creality CR-20 Pro]
|
||||
inherits = Creality Ender-3; *fastabl*
|
||||
inherits = *common*; *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-200B]
|
||||
inherits = *common*; *descendingz*
|
||||
bed_shape = 5x5,195x5,195x195,5x195
|
||||
max_print_height = 200
|
||||
printer_model = CR200B
|
||||
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_CR200B\nPRINTER_HAS_BOWDEN
|
||||
|
||||
[printer:Creality CR-8]
|
||||
inherits = *common*
|
||||
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*
|
||||
#inherits = *common*; *dualextruder*
|
||||
#retract_length = 6,6
|
||||
#bed_shape = 5x5,295x5,295x295,5x295
|
||||
#max_print_height = 400
|
||||
@ -1026,7 +1096,7 @@ printer_notes = Don't remove the following keywords! These keywords are used in
|
||||
#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*
|
||||
#inherits = *common*; *dualextruder*; *slowabl*
|
||||
#retract_length = 6,6
|
||||
#bed_shape = 5x5,295x5,295x295,5x295
|
||||
#max_print_height = 400
|
||||
|
BIN
resources/profiles/Creality/CR200B_thumbnail.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
resources/profiles/Creality/CR5PROH_thumbnail.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
resources/profiles/Creality/CR5PRO_thumbnail.png
Normal file
After Width: | Height: | Size: 38 KiB |
4
resources/profiles/Creality/cr200b.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="190mm" height="190mm" version="1.1" viewBox="0 0 190 190" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x=".25" y=".25" width="189.5" height="189.5" fill="none" stroke="#fff" stroke-width=".5"/>
|
||||
</svg>
|
After Width: | Height: | Size: 251 B |
2774
resources/profiles/Creality/cr200b_bed.stl
Normal file
4
resources/profiles/Creality/cr5pro.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="290mm" height="215mm" version="1.1" viewBox="0 0 290 215" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x=".25" y=".25" width="289.5" height="214.5" fill="none" stroke="#fff" stroke-width=".5"/>
|
||||
</svg>
|
After Width: | Height: | Size: 251 B |
2774
resources/profiles/Creality/cr5pro_bed.stl
Normal file
@ -1,2 +1,3 @@
|
||||
min_slic3r_version = 2.3.0
|
||||
min_slic3r_version = 2.3.1-beta
|
||||
0.0.1 Initial version
|
||||
0.0.2 Improved start gcode, changed filename format
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
[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/
|
||||
name = INAT
|
||||
config_version = 0.0.2
|
||||
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/INAT/
|
||||
|
||||
###
|
||||
### PRINTER LIST
|
||||
@ -133,7 +133,7 @@ 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
|
||||
output_filename_format = {input_filename_base}_{filament_type[0]}.gcode
|
||||
|
||||
|
||||
[print:0.2mm Standard @PROTON_X]
|
||||
@ -193,7 +193,7 @@ 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
|
||||
start_gcode = G28 ;Home\nG0 X-2 Y150 F6000 ;Move to the side\nG0 Z0.3 F200 ;Move nozzle down\nM192 ; Wait for probe temperature to settle\nG28 Z\nG29\nG0 X0 Y0 Z30 F6000\nM84 E\nM0\nG1 Z15.0 F6000 ;Move the platform down 15mm\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
|
||||
|
@ -1,3 +1,5 @@
|
||||
min_slic3r_version = 2.4.0-alpha0
|
||||
1.3.0-alpha0 Disabled thick bridges, updated support settings.
|
||||
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,4 +1,5 @@
|
||||
min_slic3r_version = 2.3.0-alpha3
|
||||
0.0.7 Added PLA, PETG profiles for 0.25 nozzle, fixed supports on 0.8 nozzle profile, fixed max volumetric speed, disabled elefant foot compensation
|
||||
0.0.6 Added material TPU 93A (SMARTFIL)
|
||||
0.0.5 Removed obsolete host keys.
|
||||
0.0.4 Added PLA, PETG profiles for 0.8 nozzle, update print materials
|
||||
|
@ -6,7 +6,7 @@
|
||||
name = TriLAB
|
||||
# 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.7
|
||||
# Where to get the updates from?
|
||||
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/TriLAB/
|
||||
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
|
||||
@ -17,16 +17,16 @@ config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/Prus
|
||||
|
||||
[printer_model:DQ2]
|
||||
name = DeltiQ 2
|
||||
variants = 0.4; 0.8
|
||||
variants = 0.4; 0.25; 0.8
|
||||
technology = FFF
|
||||
family = DeltiQ 2
|
||||
bed_model = dq2_bed.stl
|
||||
bed_texture = dq2_bed_texture.svg
|
||||
default_materials = DeltiQ - PLA - Generic; DeltiQ - PETG - Generic; DeltiQ - ABS - Generic; DeltiQ - PLA - ExtraFill (Fillamentum); DeltiQ - PETG (Devil Design); DeltiQ - ABS - ExtraFill (Fillamentum); DeltiQ - ASA - ExtraFill (Fillamentum); DeltiQ - CPE - HG100 (Fillamentum); DeltiQ FP2 - PLA - Generic; DeltiQ FP2 - PETG - Generic; DeltiQ FP2 - ABS - Generic; DeltiQ FP2 - PLA - ExtraFill (Fillamentum); DeltiQ FP2 - PETG (Devil Design); DeltiQ FP2 - ABS - ExtraFill (Fillamentum); DeltiQ FP2 - ASA - ExtraFill (Fillamentum); DeltiQ FP2 - CPE - HG100 (Fillamentum); DeltiQ FP2 - FLEX - Generic; DeltiQ FP2 - TPU 92A - FlexFill (Fillamentum); DeltiQ FP2 - TPU 98A - FlexFill (Fillamentum); DeltiQ FP2 - TPU 93A (SMARTFIL); DeltiQ - PLA - ExtraFill (Fillamentum) @0.8 nozzle
|
||||
default_materials = DeltiQ - PLA - Generic; DeltiQ - PETG - Generic; DeltiQ - ABS - Generic; DeltiQ - PLA - ExtraFill (Fillamentum); DeltiQ - PETG (Devil Design); DeltiQ - ABS - ExtraFill (Fillamentum); DeltiQ - ASA - ExtraFill (Fillamentum); DeltiQ - CPE - HG100 (Fillamentum); DeltiQ FP2 - PLA - Generic; DeltiQ FP2 - PETG - Generic; DeltiQ FP2 - ABS - Generic; DeltiQ FP2 - PLA - ExtraFill (Fillamentum); DeltiQ FP2 - PETG (Devil Design); DeltiQ FP2 - ABS - ExtraFill (Fillamentum); DeltiQ FP2 - ASA - ExtraFill (Fillamentum); DeltiQ FP2 - CPE - HG100 (Fillamentum); DeltiQ FP2 - FLEX - Generic; DeltiQ FP2 - TPU 92A - FlexFill (Fillamentum); DeltiQ FP2 - TPU 98A - FlexFill (Fillamentum); DeltiQ FP2 - TPU 93A (SMARTFIL); DeltiQ - PLA - ExtraFill (Fillamentum) @0.8 nozzle; DeltiQ - PLA - ExtraFill (Fillamentum) @0.25 nozzle
|
||||
|
||||
[printer_model:DQ2P]
|
||||
name = DeltiQ 2 Plus
|
||||
variants = 0.4; 0.8
|
||||
variants = 0.4; 0.25; 0.8
|
||||
technology = FFF
|
||||
family = DeltiQ 2
|
||||
bed_model = dq2_bed.stl
|
||||
@ -110,7 +110,7 @@ complete_objects = 0
|
||||
default_acceleration = 2000
|
||||
dont_support_bridges = 0
|
||||
draft_shield = 0
|
||||
elefant_foot_compensation = 0.2
|
||||
elefant_foot_compensation = 0.0
|
||||
ensure_vertical_shell_thickness = 0
|
||||
external_perimeter_extrusion_width = 0.45
|
||||
external_perimeter_speed = 30
|
||||
@ -150,7 +150,7 @@ min_skirt_length = 4
|
||||
notes =
|
||||
only_retract_when_crossing_perimeters = 1
|
||||
ooze_prevention = 0
|
||||
output_filename_format = {input_filename_base}_{printer_model}_{filament_type[0]}_{layer_height}mm_{print_time}.gcode
|
||||
output_filename_format = {input_filename_base}_{printer_model}_{filament_type[0]}_{layer_height}mm_{print_time}_{timestamp}.gcode
|
||||
overhangs = 1
|
||||
perimeter_acceleration = 1500
|
||||
perimeter_extruder = 1
|
||||
@ -283,6 +283,37 @@ travel_speed = 200
|
||||
max_print_speed = 40
|
||||
complete_objects = 1
|
||||
|
||||
[print:DeltiQ 0.07mm Quality @0.25 nozzle]
|
||||
inherits = DeltiQ 0.20mm Normal
|
||||
bottom_solid_layers = 6
|
||||
bottom_solid_min_thickness = 0.5
|
||||
bridge_speed = 60
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and nozzle_diameter[0]==0.25
|
||||
elefant_foot_compensation = 0.0
|
||||
external_perimeter_extrusion_width = 0.27
|
||||
extrusion_width = 0.25
|
||||
first_layer_extrusion_width = 0.26
|
||||
first_layer_height = 0.1
|
||||
infill_extrusion_width = 0.27
|
||||
infill_overlap = 50%
|
||||
layer_height = 0.07
|
||||
overhangs = 1
|
||||
perimeter_extrusion_width = 0.27
|
||||
perimeters = 5
|
||||
solid_infill_extrusion_width = 0.27
|
||||
skirts = 2
|
||||
support_material_extrusion_width = 0.27
|
||||
support_material_contact_distance = 0.1
|
||||
top_infill_extrusion_width = 0.27
|
||||
top_solid_layers = 6
|
||||
top_solid_min_thickness = 0.5
|
||||
thin_walls = 1
|
||||
|
||||
[print:DeltiQ 0.20mm Normal @0.25 nozzle]
|
||||
inherits = DeltiQ 0.07mm Quality @0.25 nozzle
|
||||
first_layer_height = 0.2
|
||||
layer_height = 0.2
|
||||
|
||||
[print:DeltiQ 0.40mm Normal @0.8 nozzle]
|
||||
inherits = DeltiQ 0.20mm Normal
|
||||
bottom_solid_layers = 3
|
||||
@ -290,7 +321,7 @@ bottom_solid_min_thickness = 1.2
|
||||
bridge_flow_ratio = 0.90
|
||||
bridge_speed = 20
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and nozzle_diameter[0]==0.8
|
||||
elefant_foot_compensation = 0.2
|
||||
elefant_foot_compensation = 0.0
|
||||
external_perimeter_extrusion_width = 0.80
|
||||
external_perimeter_speed = 30
|
||||
extrusion_width = 0.80
|
||||
@ -311,6 +342,8 @@ perimeters = 2
|
||||
small_perimeter_speed = 20
|
||||
solid_infill_extrusion_width = 0.8
|
||||
solid_infill_speed = 60
|
||||
support_material_extrusion_width = 0.8
|
||||
support_material_contact_distance = 0.2
|
||||
top_infill_extrusion_width = 0.8
|
||||
top_solid_infill_speed = 40
|
||||
top_solid_layers = 4
|
||||
@ -412,7 +445,7 @@ fan_below_layer_time = 20
|
||||
filament_vendor = Fillamentum
|
||||
filament_cost = 774
|
||||
filament_density = 1.08
|
||||
filament_max_volumetric_speed = 4
|
||||
filament_max_volumetric_speed = 8
|
||||
filament_retract_before_travel = 3
|
||||
filament_retract_before_wipe = 70%
|
||||
filament_retract_layer_change = 1
|
||||
@ -474,6 +507,19 @@ min_print_speed = 10
|
||||
slowdown_below_layer_time = 5
|
||||
temperature = 260
|
||||
|
||||
[filament:DeltiQ - PLA - ExtraFill (Fillamentum) @0.25 nozzle]
|
||||
inherits = DeltiQ - PLA - ExtraFill (Fillamentum)
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and !(printer_notes=~/.*FLEXPRINT.*/) and nozzle_diameter[0]==0.25
|
||||
|
||||
[filament:DeltiQ - PETG (Devil Design) @0.25 nozzle]
|
||||
inherits = DeltiQ - PETG (Devil Design)
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and !(printer_notes=~/.*FLEXPRINT.*/) and nozzle_diameter[0]==0.25
|
||||
first_layer_temperature = 225
|
||||
temperature = 220
|
||||
max_fan_speed = 65
|
||||
min_fan_speed = 40
|
||||
bridge_fan_speed = 100
|
||||
|
||||
[filament:DeltiQ - PLA - ExtraFill (Fillamentum) @0.8 nozzle]
|
||||
inherits = DeltiQ - PLA - ExtraFill (Fillamentum)
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and !(printer_notes=~/.*FLEXPRINT.*/) and nozzle_diameter[0]==0.8
|
||||
@ -536,7 +582,7 @@ filament_vendor = Generic
|
||||
filament_cost = 1870
|
||||
filament_density = 1.22
|
||||
filament_deretract_speed = nil
|
||||
filament_max_volumetric_speed = 0.7
|
||||
filament_max_volumetric_speed = 3.0
|
||||
filament_retract_before_travel = 2
|
||||
filament_retract_before_wipe = 70%
|
||||
filament_retract_layer_change = 0
|
||||
@ -634,7 +680,7 @@ filament_vendor = Fillamentum
|
||||
filament_cost = 1870
|
||||
filament_density = 1.22
|
||||
filament_deretract_speed = nil
|
||||
filament_max_volumetric_speed = 2.9
|
||||
filament_max_volumetric_speed = 3.0
|
||||
filament_retract_before_travel = 2
|
||||
filament_retract_before_wipe = 70%
|
||||
filament_retract_layer_change = 0
|
||||
@ -665,7 +711,7 @@ filament_vendor = Fillamentum
|
||||
filament_cost = 1870
|
||||
filament_density = 1.22
|
||||
filament_deretract_speed = nil
|
||||
filament_max_volumetric_speed = 2.9
|
||||
filament_max_volumetric_speed = 3.0
|
||||
filament_retract_before_travel = 2
|
||||
filament_retract_before_wipe = 70%
|
||||
filament_retract_layer_change = 0
|
||||
@ -689,7 +735,7 @@ extrusion_multiplier = 1.10
|
||||
filament_cost = 1870
|
||||
filament_density = 1.23
|
||||
filament_deretract_speed = nil
|
||||
filament_max_volumetric_speed = 2.9
|
||||
filament_max_volumetric_speed = 3.0
|
||||
filament_retract_before_wipe = 70%
|
||||
filament_retract_length = 2.5
|
||||
filament_retract_speed = 20
|
||||
@ -822,6 +868,15 @@ printer_model = DQ2
|
||||
printer_variant = 0.4
|
||||
max_print_height = 320
|
||||
|
||||
[printer:DeltiQ 2 - 0.25 nozzle]
|
||||
inherits = DeltiQ 2
|
||||
printer_variant = 0.25
|
||||
max_layer_height = 0.15
|
||||
min_layer_height = 0.07
|
||||
nozzle_diameter = 0.25
|
||||
default_filament_profile = "DeltiQ - PLA - ExtraFill (Fillamentum) @0.25 nozzle"
|
||||
default_print_profile = DeltiQ 0.07mm Quality @0.25 nozzle
|
||||
|
||||
[printer:DeltiQ 2 - 0.8 nozzle]
|
||||
inherits = DeltiQ 2
|
||||
printer_variant = 0.8
|
||||
@ -837,6 +892,15 @@ printer_model = DQ2P
|
||||
printer_variant = 0.4
|
||||
max_print_height = 500
|
||||
|
||||
[printer:DeltiQ 2 Plus - 0.25 nozzle]
|
||||
inherits = DeltiQ 2 Plus
|
||||
printer_variant = 0.25
|
||||
max_layer_height = 0.15
|
||||
min_layer_height = 0.07
|
||||
nozzle_diameter = 0.25
|
||||
default_filament_profile = "DeltiQ - PLA - ExtraFill (Fillamentum) @0.25 nozzle"
|
||||
default_print_profile = DeltiQ 0.07mm Quality @0.25 nozzle
|
||||
|
||||
[printer:DeltiQ 2 Plus - 0.8 nozzle]
|
||||
inherits = DeltiQ 2 Plus
|
||||
printer_variant = 0.8
|
||||
|
@ -58,9 +58,27 @@ if (SLIC3R_GUI)
|
||||
include(${wxWidgets_USE_FILE})
|
||||
|
||||
string(REGEX MATCH "wxpng" WX_PNG_BUILTIN ${wxWidgets_LIBRARIES})
|
||||
if (PNG_FOUND AND NOT WX_PNG_BUILTIN)
|
||||
list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX png)
|
||||
list(APPEND wxWidgets_LIBRARIES ${PNG_LIBRARIES})
|
||||
if (NOT WX_PNG_BUILTIN)
|
||||
find_package(JPEG QUIET)
|
||||
if (PNG_FOUND)
|
||||
list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX png)
|
||||
list(APPEND wxWidgets_LIBRARIES ${PNG_LIBRARIES})
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
string(REGEX MATCH "wxtiff" WX_TIFF_BUILTIN ${wxWidgets_LIBRARIES})
|
||||
if (NOT WX_TIFF_BUILTIN)
|
||||
find_package(TIFF QUIET)
|
||||
if (TIFF_FOUND)
|
||||
list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX tiff)
|
||||
list(APPEND wxWidgets_LIBRARIES ${TIFF_LIBRARIES})
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
string(REGEX MATCH "wxjpeg" WX_JPEG_BUILTIN ${wxWidgets_LIBRARIES})
|
||||
if (TIFF_FOUND AND NOT WX_JPEG_BUILTIN)
|
||||
list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX jpeg)
|
||||
list(APPEND wxWidgets_LIBRARIES ${JPEG_LIBRARIES})
|
||||
endif ()
|
||||
|
||||
string(REGEX MATCH "wxexpat" WX_EXPAT_BUILTIN ${wxWidgets_LIBRARIES})
|
||||
@ -68,7 +86,6 @@ if (SLIC3R_GUI)
|
||||
list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX expat)
|
||||
list(APPEND wxWidgets_LIBRARIES ${EXPAT_LIBRARIES})
|
||||
endif ()
|
||||
|
||||
# This is an issue in the new wxWidgets cmake build, doesn't deal with librt
|
||||
find_library(LIBRT rt)
|
||||
if(LIBRT)
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "libslic3r/GCode/PostProcessor.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/ModelArrange.hpp"
|
||||
#include "libslic3r/Platform.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
@ -603,6 +604,9 @@ bool CLI::setup(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
// Detect the operating system flavor after SLIC3R_LOGLEVEL is set.
|
||||
detect_platform();
|
||||
|
||||
#ifdef WIN32
|
||||
// Notify user if blacklisted library is already loaded (Nahimic)
|
||||
// If there are cases of no reports with blacklisted lib - this check should be performed later.
|
||||
|
@ -217,6 +217,11 @@ int APIENTRY wWinMain(HINSTANCE /* hInstance */, HINSTANCE /* hPrevInstance */,
|
||||
int wmain(int argc, wchar_t **argv)
|
||||
{
|
||||
#endif
|
||||
// Allow the asserts to open message box, such message box allows to ignore the assert and continue with the application.
|
||||
// Without this call, the seemingly same message box is being opened by the abort() function, but that is too late and
|
||||
// the application will be killed even if "Ignore" button is pressed.
|
||||
_set_error_mode(_OUT_TO_MSGBOX);
|
||||
|
||||
std::vector<wchar_t*> argv_extended;
|
||||
argv_extended.emplace_back(argv[0]);
|
||||
|
||||
|
@ -287,6 +287,11 @@ bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2)
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#ifdef CLIPPERLIB_INT32
|
||||
inline bool SlopesEqual(const cInt dx1, const cInt dy1, const cInt dx2, const cInt dy2, bool /* UseFullInt64Range */) {
|
||||
return int64_t(dy1) * int64_t(dx2) == int64_t(dx1) * int64_t(dy2);
|
||||
}
|
||||
#else
|
||||
inline bool SlopesEqual(const cInt dx1, const cInt dy1, const cInt dx2, const cInt dy2, bool UseFullInt64Range) {
|
||||
return (UseFullInt64Range) ?
|
||||
// |dx1| < 2^63, |dx2| < 2^63 etc,
|
||||
@ -296,6 +301,8 @@ inline bool SlopesEqual(const cInt dx1, const cInt dy1, const cInt dx2, const cI
|
||||
// therefore the following computation could be done with 64bit arithmetics.
|
||||
dy1 * dx2 == dx1 * dy2;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range)
|
||||
{ return SlopesEqual(e1.Delta.X, e1.Delta.Y, e2.Delta.X, e2.Delta.Y, UseFullInt64Range); }
|
||||
inline bool SlopesEqual(const IntPoint &pt1, const IntPoint &pt2, const IntPoint &pt3, bool UseFullInt64Range)
|
||||
@ -363,8 +370,8 @@ void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip)
|
||||
}
|
||||
else
|
||||
{
|
||||
b1 = Edge1.Bot.X - Edge1.Bot.Y * Edge1.Dx;
|
||||
b2 = Edge2.Bot.X - Edge2.Bot.Y * Edge2.Dx;
|
||||
b1 = double(Edge1.Bot.X) - double(Edge1.Bot.Y) * Edge1.Dx;
|
||||
b2 = double(Edge2.Bot.X) - double(Edge2.Bot.Y) * Edge2.Dx;
|
||||
double q = (b2-b1) / (Edge1.Dx - Edge2.Dx);
|
||||
ip.Y = Round(q);
|
||||
ip.X = (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) ?
|
||||
@ -569,6 +576,7 @@ bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b)
|
||||
// ClipperBase class methods ...
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef CLIPPERLIB_INT32
|
||||
// Called from ClipperBase::AddPath() to verify the scale of the input polygon coordinates.
|
||||
inline void RangeTest(const IntPoint& Pt, bool& useFullRange)
|
||||
{
|
||||
@ -583,6 +591,7 @@ inline void RangeTest(const IntPoint& Pt, bool& useFullRange)
|
||||
RangeTest(Pt, useFullRange);
|
||||
}
|
||||
}
|
||||
#endif // CLIPPERLIB_INT32
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Called from ClipperBase::AddPath() to construct the Local Minima List.
|
||||
@ -805,13 +814,17 @@ bool ClipperBase::AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, b
|
||||
try
|
||||
{
|
||||
edges[1].Curr = pg[1];
|
||||
#ifndef CLIPPERLIB_INT32
|
||||
RangeTest(pg[0], m_UseFullRange);
|
||||
RangeTest(pg[highI], m_UseFullRange);
|
||||
#endif // CLIPPERLIB_INT32
|
||||
InitEdge(&edges[0], &edges[1], &edges[highI], pg[0]);
|
||||
InitEdge(&edges[highI], &edges[0], &edges[highI-1], pg[highI]);
|
||||
for (int i = highI - 1; i >= 1; --i)
|
||||
{
|
||||
#ifndef CLIPPERLIB_INT32
|
||||
RangeTest(pg[i], m_UseFullRange);
|
||||
#endif // CLIPPERLIB_INT32
|
||||
InitEdge(&edges[i], &edges[i+1], &edges[i-1], pg[i]);
|
||||
}
|
||||
}
|
||||
@ -967,7 +980,9 @@ void ClipperBase::Clear()
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
m_MinimaList.clear();
|
||||
m_edges.clear();
|
||||
#ifndef CLIPPERLIB_INT32
|
||||
m_UseFullRange = false;
|
||||
#endif // CLIPPERLIB_INT32
|
||||
m_HasOpenPaths = false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
@ -3322,9 +3337,9 @@ DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2)
|
||||
if(pt2.X == pt1.X && pt2.Y == pt1.Y)
|
||||
return DoublePoint(0, 0);
|
||||
|
||||
double Dx = (double)(pt2.X - pt1.X);
|
||||
double dy = (double)(pt2.Y - pt1.Y);
|
||||
double f = 1 *1.0/ std::sqrt( Dx*Dx + dy*dy );
|
||||
double Dx = double(pt2.X - pt1.X);
|
||||
double dy = double(pt2.Y - pt1.Y);
|
||||
double f = 1.0 / std::sqrt( Dx*Dx + dy*dy );
|
||||
Dx *= f;
|
||||
dy *= f;
|
||||
return DoublePoint(dy, -Dx);
|
||||
@ -3530,8 +3545,9 @@ void ClipperOffset::DoOffset(double delta)
|
||||
}
|
||||
|
||||
//see offset_triginometry3.svg in the documentation folder ...
|
||||
if (MiterLimit > 2) m_miterLim = 2/(MiterLimit * MiterLimit);
|
||||
else m_miterLim = 0.5;
|
||||
m_miterLim = (MiterLimit > 2) ?
|
||||
2. / (MiterLimit * MiterLimit) :
|
||||
0.5;
|
||||
|
||||
double y;
|
||||
if (ArcTolerance <= 0.0) y = def_arc_tolerance;
|
||||
@ -3633,11 +3649,9 @@ void ClipperOffset::DoOffset(double delta)
|
||||
if (node.m_endtype == etOpenButt)
|
||||
{
|
||||
int j = len - 1;
|
||||
pt1 = IntPoint(Round(m_srcPoly[j].X + m_normals[j].X *
|
||||
delta), Round(m_srcPoly[j].Y + m_normals[j].Y * delta));
|
||||
pt1 = IntPoint(Round(m_srcPoly[j].X + m_normals[j].X * delta), Round(m_srcPoly[j].Y + m_normals[j].Y * delta));
|
||||
m_destPoly.push_back(pt1);
|
||||
pt1 = IntPoint(Round(m_srcPoly[j].X - m_normals[j].X *
|
||||
delta), Round(m_srcPoly[j].Y - m_normals[j].Y * delta));
|
||||
pt1 = IntPoint(Round(m_srcPoly[j].X - m_normals[j].X * delta), Round(m_srcPoly[j].Y - m_normals[j].Y * delta));
|
||||
m_destPoly.push_back(pt1);
|
||||
}
|
||||
else
|
||||
@ -3662,11 +3676,9 @@ void ClipperOffset::DoOffset(double delta)
|
||||
|
||||
if (node.m_endtype == etOpenButt)
|
||||
{
|
||||
pt1 = IntPoint(Round(m_srcPoly[0].X - m_normals[0].X * delta),
|
||||
Round(m_srcPoly[0].Y - m_normals[0].Y * delta));
|
||||
pt1 = IntPoint(Round(m_srcPoly[0].X - m_normals[0].X * delta), Round(m_srcPoly[0].Y - m_normals[0].Y * delta));
|
||||
m_destPoly.push_back(pt1);
|
||||
pt1 = IntPoint(Round(m_srcPoly[0].X + m_normals[0].X * delta),
|
||||
Round(m_srcPoly[0].Y + m_normals[0].Y * delta));
|
||||
pt1 = IntPoint(Round(m_srcPoly[0].X + m_normals[0].X * delta), Round(m_srcPoly[0].Y + m_normals[0].Y * delta));
|
||||
m_destPoly.push_back(pt1);
|
||||
}
|
||||
else
|
||||
@ -3753,7 +3765,7 @@ void ClipperOffset::DoRound(int j, int k)
|
||||
{
|
||||
double a = std::atan2(m_sinA,
|
||||
m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y);
|
||||
int steps = std::max((int)Round(m_StepsPerRad * std::fabs(a)), 1);
|
||||
auto steps = std::max<int>(Round(m_StepsPerRad * std::fabs(a)), 1);
|
||||
|
||||
double X = m_normals[k].X, Y = m_normals[k].Y, X2;
|
||||
for (int i = 0; i < steps; ++i)
|
||||
@ -3885,8 +3897,8 @@ void SimplifyPolygons(Paths &polys, PolyFillType fillType)
|
||||
|
||||
inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2)
|
||||
{
|
||||
double Dx = ((double)pt1.X - pt2.X);
|
||||
double dy = ((double)pt1.Y - pt2.Y);
|
||||
auto Dx = double(pt1.X - pt2.X);
|
||||
auto dy = double(pt1.Y - pt2.Y);
|
||||
return (Dx*Dx + dy*dy);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
@ -3937,8 +3949,8 @@ bool SlopesNearCollinear(const IntPoint& pt1,
|
||||
|
||||
bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd)
|
||||
{
|
||||
double Dx = (double)pt1.X - pt2.X;
|
||||
double dy = (double)pt1.Y - pt2.Y;
|
||||
auto Dx = double(pt1.X - pt2.X);
|
||||
auto dy = double(pt1.Y - pt2.Y);
|
||||
return ((Dx * Dx) + (dy * dy) <= distSqrd);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -71,12 +71,22 @@ enum PolyType { ptSubject, ptClip };
|
||||
//see http://glprogramming.com/red/chapter11.html
|
||||
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
|
||||
|
||||
// If defined, Clipper will work with 32bit signed int coordinates to reduce memory
|
||||
// consumption and to speed up exact orientation predicate calculation.
|
||||
// In that case, coordinates and their differences (vectors of the coordinates) have to fit int32_t.
|
||||
#define CLIPPERLIB_INT32
|
||||
|
||||
// Point coordinate type
|
||||
typedef int64_t cInt;
|
||||
// Maximum cInt value to allow a cross product calculation using 32bit expressions.
|
||||
static cInt const loRange = 0x3FFFFFFF;
|
||||
// Maximum allowed cInt value.
|
||||
static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
|
||||
#ifdef CLIPPERLIB_INT32
|
||||
// Coordinates and their differences (vectors of the coordinates) have to fit int32_t.
|
||||
typedef int32_t cInt;
|
||||
#else
|
||||
typedef int64_t cInt;
|
||||
// Maximum cInt value to allow a cross product calculation using 32bit expressions.
|
||||
static constexpr cInt const loRange = 0x3FFFFFFF; // 0x3FFFFFFF = 1 073 741 823
|
||||
// Maximum allowed cInt value.
|
||||
static constexpr cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
|
||||
#endif // CLIPPERLIB_INT32
|
||||
|
||||
struct IntPoint {
|
||||
cInt X;
|
||||
@ -289,7 +299,11 @@ enum EdgeSide { esLeft = 1, esRight = 2};
|
||||
class ClipperBase
|
||||
{
|
||||
public:
|
||||
ClipperBase() : m_UseFullRange(false), m_HasOpenPaths(false) {}
|
||||
ClipperBase() :
|
||||
#ifndef CLIPPERLIB_INT32
|
||||
m_UseFullRange(false),
|
||||
#endif // CLIPPERLIB_INT32
|
||||
m_HasOpenPaths(false) {}
|
||||
~ClipperBase() { Clear(); }
|
||||
bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
|
||||
bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed);
|
||||
@ -310,9 +324,14 @@ protected:
|
||||
// Local minima (Y, left edge, right edge) sorted by ascending Y.
|
||||
std::vector<LocalMinimum> m_MinimaList;
|
||||
|
||||
#ifdef CLIPPERLIB_INT32
|
||||
static constexpr const bool m_UseFullRange = false;
|
||||
#else // CLIPPERLIB_INT32
|
||||
// True if the input polygons have abs values higher than loRange, but lower than hiRange.
|
||||
// False if the input polygons have abs values lower or equal to loRange.
|
||||
bool m_UseFullRange;
|
||||
#endif // CLIPPERLIB_INT32
|
||||
|
||||
// A vector of edges per each input path.
|
||||
std::vector<std::vector<TEdge>> m_edges;
|
||||
// Don't remove intermediate vertices of a collinear sequence of points.
|
||||
|
@ -123,6 +123,8 @@ namespace ImGui
|
||||
const char ErrorMarker = 0x11;
|
||||
const char EjectButton = 0x12;
|
||||
const char EjectHoverButton = 0x13;
|
||||
const char CancelButton = 0x14;
|
||||
const char CancelHoverButton = 0x15;
|
||||
// void MyFunction(const char* name, const MyMatrix44& v);
|
||||
|
||||
}
|
||||
|
@ -28,4 +28,4 @@ add_library(libnest2d STATIC ${LIBNEST2D_SRCFILES})
|
||||
|
||||
target_include_directories(libnest2d PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
target_link_libraries(libnest2d PUBLIC clipper NLopt::nlopt TBB::tbb Boost::boost)
|
||||
target_compile_definitions(libnest2d PUBLIC USE_TBB LIBNEST2D_STATIC LIBNEST2D_OPTIMIZER_nlopt LIBNEST2D_GEOMETRIES_clipper)
|
||||
target_compile_definitions(libnest2d PUBLIC LIBNEST2D_THREADING_tbb LIBNEST2D_STATIC LIBNEST2D_OPTIMIZER_nlopt LIBNEST2D_GEOMETRIES_clipper)
|
||||
|
@ -26,7 +26,10 @@ template<> struct ShapeTag<PointImpl> { using Type = PointTag; };
|
||||
|
||||
// Type of coordinate units used by Clipper. Enough to specialize for point,
|
||||
// the rest of the types will work (Path, Polygon)
|
||||
template<> struct CoordType<PointImpl> { using Type = ClipperLib::cInt; };
|
||||
template<> struct CoordType<PointImpl> {
|
||||
using Type = ClipperLib::cInt;
|
||||
static const constexpr ClipperLib::cInt MM_IN_COORDS = 1000000;
|
||||
};
|
||||
|
||||
// Enough to specialize for path, it will work for multishape and Polygon
|
||||
template<> struct PointType<PathImpl> { using Type = PointImpl; };
|
||||
@ -95,6 +98,9 @@ inline void offset(PolygonImpl& sh, TCoord<PointImpl> distance, const PolygonTag
|
||||
// Offsetting reverts the orientation and also removes the last vertex
|
||||
// so boost will not have a closed polygon.
|
||||
|
||||
// we plan to replace contours
|
||||
sh.Holes.clear();
|
||||
|
||||
bool found_the_contour = false;
|
||||
for(auto& r : result) {
|
||||
if(ClipperLib::Orientation(r)) {
|
||||
|
@ -48,6 +48,7 @@ using TPoint = typename PointType<remove_cvref_t<Shape>>::Type;
|
||||
/// Getting the coordinate data type for a geometry class.
|
||||
template<class GeomClass> struct CoordType {
|
||||
using Type = typename CoordType<TPoint<GeomClass>>::Type;
|
||||
static const constexpr Type MM_IN_COORDS = Type{1};
|
||||
};
|
||||
|
||||
/// TCoord<GeomType> as shorthand for typename `CoordType<GeomType>::Type`.
|
||||
@ -473,8 +474,8 @@ inline _Box<P> _Box<P>::infinite(const P& center) {
|
||||
|
||||
// It is important for Mx and My to be strictly less than half of the
|
||||
// range of type C. width(), height() and area() will not overflow this way.
|
||||
C Mx = C((std::numeric_limits<C>::lowest() + 2 * getX(center)) / 2.01);
|
||||
C My = C((std::numeric_limits<C>::lowest() + 2 * getY(center)) / 2.01);
|
||||
C Mx = C((std::numeric_limits<C>::lowest() + 2 * getX(center)) / 4.01);
|
||||
C My = C((std::numeric_limits<C>::lowest() + 2 * getY(center)) / 4.01);
|
||||
|
||||
ret.maxCorner() = center - P{Mx, My};
|
||||
ret.minCorner() = center + P{Mx, My};
|
||||
|
@ -220,7 +220,9 @@ inline NfpResult<RawShape> nfpConvexOnly(const RawShape& sh,
|
||||
auto next = std::next(first);
|
||||
|
||||
while(next != sl::cend(sh)) {
|
||||
edgelist.emplace_back(*(first), *(next));
|
||||
if (pl::magnsq(*next - *first) > 0)
|
||||
edgelist.emplace_back(*(first), *(next));
|
||||
|
||||
++first; ++next;
|
||||
}
|
||||
}
|
||||
@ -230,7 +232,9 @@ inline NfpResult<RawShape> nfpConvexOnly(const RawShape& sh,
|
||||
auto next = std::next(first);
|
||||
|
||||
while(next != sl::cend(other)) {
|
||||
edgelist.emplace_back(*(next), *(first));
|
||||
if (pl::magnsq(*next - *first) > 0)
|
||||
edgelist.emplace_back(*(next), *(first));
|
||||
|
||||
++first; ++next;
|
||||
}
|
||||
}
|
||||
|
@ -130,6 +130,11 @@ std::size_t nest(Container&& cont,
|
||||
return nest<Placer, Selector>(cont.begin(), cont.end(), bin, dist, cfg, ctl);
|
||||
}
|
||||
|
||||
template<class T = double> enable_if_t<std::is_arithmetic<T>::value, TCoord<PointImpl>> mm(T val = T(1))
|
||||
{
|
||||
return TCoord<PointImpl>(val * CoordType<PointImpl>::MM_IN_COORDS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // LIBNEST2D_HPP
|
||||
|
63
src/libnest2d/include/libnest2d/parallel.hpp
Normal file
@ -0,0 +1,63 @@
|
||||
#ifndef LIBNEST2D_PARALLEL_HPP
|
||||
#define LIBNEST2D_PARALLEL_HPP
|
||||
|
||||
#include <iterator>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
|
||||
#ifdef LIBNEST2D_THREADING_tbb
|
||||
#include <tbb/parallel_for.h>
|
||||
#endif
|
||||
|
||||
#ifdef LIBNEST2D_THREADING_omp
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
namespace libnest2d { namespace __parallel {
|
||||
|
||||
template<class It>
|
||||
using TIteratorValue = typename std::iterator_traits<It>::value_type;
|
||||
|
||||
template<class Iterator>
|
||||
inline void enumerate(
|
||||
Iterator from, Iterator to,
|
||||
std::function<void(TIteratorValue<Iterator>, size_t)> fn,
|
||||
std::launch policy = std::launch::deferred | std::launch::async)
|
||||
{
|
||||
using TN = size_t;
|
||||
auto iN = to-from;
|
||||
TN N = iN < 0? 0 : TN(iN);
|
||||
|
||||
#ifdef LIBNEST2D_THREADING_tbb
|
||||
if((policy & std::launch::async) == std::launch::async) {
|
||||
tbb::parallel_for<TN>(0, N, [from, fn] (TN n) { fn(*(from + n), n); } );
|
||||
} else {
|
||||
for(TN n = 0; n < N; n++) fn(*(from + n), n);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LIBNEST2D_THREADING_omp
|
||||
if((policy & std::launch::async) == std::launch::async) {
|
||||
#pragma omp parallel for
|
||||
for(int n = 0; n < int(N); n++) fn(*(from + n), TN(n));
|
||||
}
|
||||
else {
|
||||
for(TN n = 0; n < N; n++) fn(*(from + n), n);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LIBNEST2D_THREADING_std
|
||||
std::vector<std::future<void>> rets(N);
|
||||
|
||||
auto it = from;
|
||||
for(TN b = 0; b < N; b++) {
|
||||
rets[b] = std::async(policy, fn, *it++, unsigned(b));
|
||||
}
|
||||
|
||||
for(TN fi = 0; fi < N; ++fi) rets[fi].wait();
|
||||
#endif
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif //LIBNEST2D_PARALLEL_HPP
|
@ -20,59 +20,9 @@
|
||||
// temporary
|
||||
//#include "../tools/svgtools.hpp"
|
||||
|
||||
#ifdef USE_TBB
|
||||
#include <tbb/parallel_for.h>
|
||||
#elif defined(_OPENMP)
|
||||
#include <omp.h>
|
||||
#endif
|
||||
#include <libnest2d/parallel.hpp>
|
||||
|
||||
namespace libnest2d {
|
||||
|
||||
namespace __parallel {
|
||||
|
||||
using std::function;
|
||||
using std::iterator_traits;
|
||||
template<class It>
|
||||
using TIteratorValue = typename iterator_traits<It>::value_type;
|
||||
|
||||
template<class Iterator>
|
||||
inline void enumerate(
|
||||
Iterator from, Iterator to,
|
||||
function<void(TIteratorValue<Iterator>, size_t)> fn,
|
||||
std::launch policy = std::launch::deferred | std::launch::async)
|
||||
{
|
||||
using TN = size_t;
|
||||
auto iN = to-from;
|
||||
TN N = iN < 0? 0 : TN(iN);
|
||||
|
||||
#ifdef USE_TBB
|
||||
if((policy & std::launch::async) == std::launch::async) {
|
||||
tbb::parallel_for<TN>(0, N, [from, fn] (TN n) { fn(*(from + n), n); } );
|
||||
} else {
|
||||
for(TN n = 0; n < N; n++) fn(*(from + n), n);
|
||||
}
|
||||
#elif defined(_OPENMP)
|
||||
if((policy & std::launch::async) == std::launch::async) {
|
||||
#pragma omp parallel for
|
||||
for(int n = 0; n < int(N); n++) fn(*(from + n), TN(n));
|
||||
}
|
||||
else {
|
||||
for(TN n = 0; n < N; n++) fn(*(from + n), n);
|
||||
}
|
||||
#else
|
||||
std::vector<std::future<void>> rets(N);
|
||||
|
||||
auto it = from;
|
||||
for(TN b = 0; b < N; b++) {
|
||||
rets[b] = std::async(policy, fn, *it++, unsigned(b));
|
||||
}
|
||||
|
||||
for(TN fi = 0; fi < N; ++fi) rets[fi].wait();
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace placers {
|
||||
|
||||
template<class RawShape>
|
||||
|
@ -82,6 +82,18 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
template<class ItemIt> void writeItems(ItemIt from, ItemIt to) {
|
||||
auto it = from;
|
||||
PackGroup pg;
|
||||
while(it != to) {
|
||||
if(it->binId() == BIN_ID_UNSET) continue;
|
||||
while(pg.size() <= size_t(it->binId())) pg.emplace_back();
|
||||
pg[it->binId()].emplace_back(*it);
|
||||
++it;
|
||||
}
|
||||
writePackGroup(pg);
|
||||
}
|
||||
|
||||
void addLayer() {
|
||||
svg_layers_.emplace_back(header());
|
||||
finished_ = false;
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
#include "Utils.hpp" // for next_highest_power_of_2()
|
||||
|
||||
extern "C"
|
||||
@ -752,6 +754,83 @@ void get_candidate_idxs(const TreeType& tree, const VectorType& v, std::vector<s
|
||||
return;
|
||||
}
|
||||
|
||||
// Predicate: need to be specialized for intersections of different geomteries
|
||||
template<class G> struct Intersecting {};
|
||||
|
||||
// Intersection predicate specialization for box-box intersections
|
||||
template<class CoordType, int NumD>
|
||||
struct Intersecting<Eigen::AlignedBox<CoordType, NumD>> {
|
||||
Eigen::AlignedBox<CoordType, NumD> box;
|
||||
|
||||
Intersecting(const Eigen::AlignedBox<CoordType, NumD> &bb): box{bb} {}
|
||||
|
||||
bool operator() (const typename Tree<NumD, CoordType>::Node &node) const
|
||||
{
|
||||
return box.intersects(node.bbox);
|
||||
}
|
||||
};
|
||||
|
||||
template<class G> auto intersecting(const G &g) { return Intersecting<G>{g}; }
|
||||
|
||||
template<class G> struct Containing {};
|
||||
|
||||
// Intersection predicate specialization for box-box intersections
|
||||
template<class CoordType, int NumD>
|
||||
struct Containing<Eigen::AlignedBox<CoordType, NumD>> {
|
||||
Eigen::AlignedBox<CoordType, NumD> box;
|
||||
|
||||
Containing(const Eigen::AlignedBox<CoordType, NumD> &bb): box{bb} {}
|
||||
|
||||
bool operator() (const typename Tree<NumD, CoordType>::Node &node) const
|
||||
{
|
||||
return box.contains(node.bbox);
|
||||
}
|
||||
};
|
||||
|
||||
template<class G> auto containing(const G &g) { return Containing<G>{g}; }
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<int Dims, typename T, typename Pred, typename Fn>
|
||||
void traverse_recurse(const Tree<Dims, T> &tree,
|
||||
size_t idx,
|
||||
Pred && pred,
|
||||
Fn && callback)
|
||||
{
|
||||
assert(tree.node(idx).is_valid());
|
||||
|
||||
if (!pred(tree.node(idx))) return;
|
||||
|
||||
if (tree.node(idx).is_leaf()) {
|
||||
callback(tree.node(idx).idx);
|
||||
} else {
|
||||
|
||||
// call this with left and right node idx:
|
||||
auto trv = [&](size_t idx) {
|
||||
traverse_recurse(tree, idx, std::forward<Pred>(pred),
|
||||
std::forward<Fn>(callback));
|
||||
};
|
||||
|
||||
// Left / right child node index.
|
||||
trv(Tree<Dims, T>::left_child_idx(idx));
|
||||
trv(Tree<Dims, T>::right_child_idx(idx));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Tree traversal with a predicate. Example usage:
|
||||
// traverse(tree, intersecting(QueryBox), [](size_t face_idx) {
|
||||
// /* ... */
|
||||
// });
|
||||
template<int Dims, typename T, typename Predicate, typename Fn>
|
||||
void traverse(const Tree<Dims, T> &tree, Predicate &&pred, Fn &&callback)
|
||||
{
|
||||
if (tree.empty()) return;
|
||||
|
||||
detail::traverse_recurse(tree, size_t(0), std::forward<Predicate>(pred),
|
||||
std::forward<Fn>(callback));
|
||||
}
|
||||
|
||||
} // namespace AABBTreeIndirect
|
||||
} // namespace Slic3r
|
||||
|
@ -68,14 +68,12 @@ void AppConfig::set_defaults()
|
||||
if (get("export_sources_full_pathnames").empty())
|
||||
set("export_sources_full_pathnames", "0");
|
||||
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
#ifdef _WIN32
|
||||
if (get("associate_3mf").empty())
|
||||
set("associate_3mf", "0");
|
||||
if (get("associate_stl").empty())
|
||||
set("associate_stl", "0");
|
||||
#endif // _WIN32
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
|
||||
// remove old 'use_legacy_opengl' parameter from this config, if present
|
||||
if (!get("use_legacy_opengl").empty())
|
||||
@ -127,14 +125,12 @@ void AppConfig::set_defaults()
|
||||
if (get("color_mapinulation_panel").empty())
|
||||
set("color_mapinulation_panel", "0");
|
||||
}
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
else {
|
||||
#ifdef _WIN32
|
||||
if (get("associate_gcode").empty())
|
||||
set("associate_gcode", "0");
|
||||
#endif // _WIN32
|
||||
}
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
|
||||
if (get("seq_top_layer_only").empty())
|
||||
set("seq_top_layer_only", "1");
|
||||
|
@ -225,24 +225,11 @@ BoundingBox3Base<PointClass>::max_size() const
|
||||
template coordf_t BoundingBox3Base<Vec3f>::max_size() const;
|
||||
template coordf_t BoundingBox3Base<Vec3d>::max_size() const;
|
||||
|
||||
// Align a coordinate to a grid. The coordinate may be negative,
|
||||
// the aligned value will never be bigger than the original one.
|
||||
static inline coord_t _align_to_grid(const coord_t coord, const coord_t spacing) {
|
||||
// Current C++ standard defines the result of integer division to be rounded to zero,
|
||||
// for both positive and negative numbers. Here we want to round down for negative
|
||||
// numbers as well.
|
||||
coord_t aligned = (coord < 0) ?
|
||||
((coord - spacing + 1) / spacing) * spacing :
|
||||
(coord / spacing) * spacing;
|
||||
assert(aligned <= coord);
|
||||
return aligned;
|
||||
}
|
||||
|
||||
void BoundingBox::align_to_grid(const coord_t cell_size)
|
||||
{
|
||||
if (this->defined) {
|
||||
min(0) = _align_to_grid(min(0), cell_size);
|
||||
min(1) = _align_to_grid(min(1), cell_size);
|
||||
min(0) = Slic3r::align_to_grid(min(0), cell_size);
|
||||
min(1) = Slic3r::align_to_grid(min(1), cell_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,22 +21,30 @@ public:
|
||||
min(pmin), max(pmax), defined(pmin(0) < pmax(0) && pmin(1) < pmax(1)) {}
|
||||
BoundingBoxBase(const PointClass &p1, const PointClass &p2, const PointClass &p3) :
|
||||
min(p1), max(p1), defined(false) { merge(p2); merge(p3); }
|
||||
BoundingBoxBase(const std::vector<PointClass>& points) : min(PointClass::Zero()), max(PointClass::Zero())
|
||||
|
||||
template<class It, class = IteratorOnly<It> >
|
||||
BoundingBoxBase(It from, It to) : min(PointClass::Zero()), max(PointClass::Zero())
|
||||
{
|
||||
if (points.empty()) {
|
||||
if (from == to) {
|
||||
this->defined = false;
|
||||
// throw Slic3r::InvalidArgument("Empty point set supplied to BoundingBoxBase constructor");
|
||||
} else {
|
||||
typename std::vector<PointClass>::const_iterator it = points.begin();
|
||||
this->min = *it;
|
||||
this->max = *it;
|
||||
for (++ it; it != points.end(); ++ it) {
|
||||
this->min = this->min.cwiseMin(*it);
|
||||
this->max = this->max.cwiseMax(*it);
|
||||
auto it = from;
|
||||
this->min = it->template cast<typename PointClass::Scalar>();
|
||||
this->max = this->min;
|
||||
for (++ it; it != to; ++ it) {
|
||||
auto vec = it->template cast<typename PointClass::Scalar>();
|
||||
this->min = this->min.cwiseMin(vec);
|
||||
this->max = this->max.cwiseMax(vec);
|
||||
}
|
||||
this->defined = (this->min(0) < this->max(0)) && (this->min(1) < this->max(1));
|
||||
}
|
||||
}
|
||||
|
||||
BoundingBoxBase(const std::vector<PointClass> &points)
|
||||
: BoundingBoxBase(points.begin(), points.end())
|
||||
{}
|
||||
|
||||
void reset() { this->defined = false; this->min = PointClass::Zero(); this->max = PointClass::Zero(); }
|
||||
void merge(const PointClass &point);
|
||||
void merge(const std::vector<PointClass> &points);
|
||||
@ -74,19 +82,27 @@ public:
|
||||
{ if (pmin(2) >= pmax(2)) BoundingBoxBase<PointClass>::defined = false; }
|
||||
BoundingBox3Base(const PointClass &p1, const PointClass &p2, const PointClass &p3) :
|
||||
BoundingBoxBase<PointClass>(p1, p1) { merge(p2); merge(p3); }
|
||||
BoundingBox3Base(const std::vector<PointClass>& points)
|
||||
|
||||
template<class It, class = IteratorOnly<It> > BoundingBox3Base(It from, It to)
|
||||
{
|
||||
if (points.empty())
|
||||
if (from == to)
|
||||
throw Slic3r::InvalidArgument("Empty point set supplied to BoundingBox3Base constructor");
|
||||
typename std::vector<PointClass>::const_iterator it = points.begin();
|
||||
this->min = *it;
|
||||
this->max = *it;
|
||||
for (++ it; it != points.end(); ++ it) {
|
||||
this->min = this->min.cwiseMin(*it);
|
||||
this->max = this->max.cwiseMax(*it);
|
||||
|
||||
auto it = from;
|
||||
this->min = it->template cast<typename PointClass::Scalar>();
|
||||
this->max = this->min;
|
||||
for (++ it; it != to; ++ it) {
|
||||
auto vec = it->template cast<typename PointClass::Scalar>();
|
||||
this->min = this->min.cwiseMin(vec);
|
||||
this->max = this->max.cwiseMax(vec);
|
||||
}
|
||||
this->defined = (this->min(0) < this->max(0)) && (this->min(1) < this->max(1)) && (this->min(2) < this->max(2));
|
||||
}
|
||||
|
||||
BoundingBox3Base(const std::vector<PointClass> &points)
|
||||
: BoundingBox3Base(points.begin(), points.end())
|
||||
{}
|
||||
|
||||
void merge(const PointClass &point);
|
||||
void merge(const std::vector<PointClass> &points);
|
||||
void merge(const BoundingBox3Base<PointClass> &bb);
|
||||
@ -188,9 +204,7 @@ public:
|
||||
class BoundingBoxf3 : public BoundingBox3Base<Vec3d>
|
||||
{
|
||||
public:
|
||||
BoundingBoxf3() : BoundingBox3Base<Vec3d>() {}
|
||||
BoundingBoxf3(const Vec3d &pmin, const Vec3d &pmax) : BoundingBox3Base<Vec3d>(pmin, pmax) {}
|
||||
BoundingBoxf3(const std::vector<Vec3d> &points) : BoundingBox3Base<Vec3d>(points) {}
|
||||
using BoundingBox3Base::BoundingBox3Base;
|
||||
|
||||
BoundingBoxf3 transformed(const Transform3d& matrix) const;
|
||||
};
|
||||
|
@ -40,7 +40,7 @@ void BridgeDetector::initialize()
|
||||
this->angle = -1.;
|
||||
|
||||
// Outset our bridge by an arbitrary amout; we'll use this outer margin for detecting anchors.
|
||||
Polygons grown = offset(to_polygons(this->expolygons), float(this->spacing));
|
||||
Polygons grown = offset(this->expolygons, float(this->spacing));
|
||||
|
||||
// Detect possible anchoring edges of this bridging region.
|
||||
// Detect what edges lie on lower slices by turning bridge contour and holes
|
||||
|
@ -320,7 +320,7 @@ static void make_inner_brim(const Print &print, const ConstPrintObjectPtrs &top_
|
||||
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()));
|
||||
float(flow.width()), float(print.skirt_first_layer_height()));
|
||||
}
|
||||
|
||||
// Produce brim lines around those objects, that have the brim enabled.
|
||||
@ -495,7 +495,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
|
||||
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()));
|
||||
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)
|
||||
@ -506,7 +506,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
|
||||
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())));
|
||||
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());
|
||||
@ -522,7 +522,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
|
||||
}
|
||||
}
|
||||
} 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()));
|
||||
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);
|
||||
|
@ -211,10 +211,14 @@ add_library(libslic3r STATIC
|
||||
PerimeterGenerator.hpp
|
||||
PlaceholderParser.cpp
|
||||
PlaceholderParser.hpp
|
||||
Platform.cpp
|
||||
Platform.hpp
|
||||
Point.cpp
|
||||
Point.hpp
|
||||
Polygon.cpp
|
||||
Polygon.hpp
|
||||
MutablePolygon.cpp
|
||||
MutablePolygon.hpp
|
||||
PolygonTrimmer.cpp
|
||||
PolygonTrimmer.hpp
|
||||
Polyline.cpp
|
||||
@ -285,6 +289,9 @@ add_library(libslic3r STATIC
|
||||
SimplifyMeshImpl.hpp
|
||||
SimplifyMesh.cpp
|
||||
MarchingSquares.hpp
|
||||
Execution/Execution.hpp
|
||||
Execution/ExecutionSeq.hpp
|
||||
Execution/ExecutionTBB.hpp
|
||||
Optimize/Optimizer.hpp
|
||||
Optimize/NLoptOptimizer.hpp
|
||||
Optimize/BruteforceOptimizer.hpp
|
||||
|
@ -57,6 +57,7 @@ err:
|
||||
}
|
||||
#endif /* CLIPPER_UTILS_DEBUG */
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
void scaleClipperPolygon(ClipperLib::Path &polygon)
|
||||
{
|
||||
CLIPPERUTILS_PROFILE_FUNC();
|
||||
@ -98,6 +99,7 @@ void unscaleClipperPolygons(ClipperLib::Paths &polygons)
|
||||
pit->Y >>= CLIPPER_OFFSET_POWER_OF_2;
|
||||
}
|
||||
}
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// legacy code from Clipper documentation
|
||||
@ -222,8 +224,10 @@ ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polylines &input)
|
||||
|
||||
ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit)
|
||||
{
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// scale input
|
||||
scaleClipperPolygons(input);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
|
||||
// perform offset
|
||||
ClipperLib::ClipperOffset co;
|
||||
@ -231,14 +235,20 @@ ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType
|
||||
co.ArcTolerance = miterLimit;
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled = delta;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||
co.AddPaths(input, joinType, endType);
|
||||
ClipperLib::Paths retval;
|
||||
co.Execute(retval, delta_scaled);
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// unscale output
|
||||
unscaleClipperPolygons(retval);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -257,14 +267,24 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta,
|
||||
{
|
||||
// printf("new ExPolygon offset\n");
|
||||
// 1) Offset the outer contour.
|
||||
const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled = delta;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
ClipperLib::Paths contours;
|
||||
{
|
||||
ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath(expolygon.contour);
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
scaleClipperPolygon(input);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
ClipperLib::ClipperOffset co;
|
||||
if (joinType == jtRound)
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||
@ -278,17 +298,23 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta,
|
||||
holes.reserve(expolygon.holes.size());
|
||||
for (Polygons::const_iterator it_hole = expolygon.holes.begin(); it_hole != expolygon.holes.end(); ++ it_hole) {
|
||||
ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole);
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
scaleClipperPolygon(input);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
ClipperLib::ClipperOffset co;
|
||||
if (joinType == jtRound)
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||
co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
|
||||
ClipperLib::Paths out;
|
||||
co.Execute(out, - delta_scaled);
|
||||
holes.insert(holes.end(), out.begin(), out.end());
|
||||
append(holes, std::move(out));
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,7 +331,9 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta,
|
||||
}
|
||||
|
||||
// 4) Unscale the output.
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
unscaleClipperPolygons(output);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -315,7 +343,11 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta,
|
||||
ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delta,
|
||||
ClipperLib::JoinType joinType, double miterLimit)
|
||||
{
|
||||
const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled = delta;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
// Offsetted ExPolygons before they are united.
|
||||
ClipperLib::Paths contours_cummulative;
|
||||
contours_cummulative.reserve(expolygons.size());
|
||||
@ -327,10 +359,16 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delt
|
||||
ClipperLib::Paths contours;
|
||||
{
|
||||
ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath(it_expoly->contour);
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
scaleClipperPolygon(input);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
ClipperLib::ClipperOffset co;
|
||||
if (joinType == jtRound)
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||
@ -351,10 +389,16 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delt
|
||||
{
|
||||
for (Polygons::const_iterator it_hole = it_expoly->holes.begin(); it_hole != it_expoly->holes.end(); ++ it_hole) {
|
||||
ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole);
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
scaleClipperPolygon(input);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
ClipperLib::ClipperOffset co;
|
||||
if (joinType == jtRound)
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||
@ -413,8 +457,10 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delt
|
||||
output = std::move(contours_cummulative);
|
||||
}
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// 4) Unscale the output.
|
||||
unscaleClipperPolygons(output);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -425,8 +471,10 @@ _offset2(const Polygons &polygons, const float delta1, const float delta2,
|
||||
// read input
|
||||
ClipperLib::Paths input = Slic3rMultiPoints_to_ClipperPaths(polygons);
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// scale input
|
||||
scaleClipperPolygons(input);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
|
||||
// prepare ClipperOffset object
|
||||
ClipperLib::ClipperOffset co;
|
||||
@ -435,8 +483,13 @@ _offset2(const Polygons &polygons, const float delta1, const float delta2,
|
||||
} else {
|
||||
co.MiterLimit = miterLimit;
|
||||
}
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled1 = delta1 * float(CLIPPER_OFFSET_SCALE);
|
||||
float delta_scaled2 = delta2 * float(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled1 = delta1;
|
||||
float delta_scaled2 = delta2;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ShortestEdgeLength = double(std::max(std::abs(delta_scaled1), std::abs(delta_scaled2)) * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR);
|
||||
|
||||
// perform first offset
|
||||
@ -450,8 +503,10 @@ _offset2(const Polygons &polygons, const float delta1, const float delta2,
|
||||
ClipperLib::Paths retval;
|
||||
co.Execute(retval, delta_scaled2);
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// unscale output
|
||||
unscaleClipperPolygons(retval);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -789,8 +844,10 @@ void safety_offset(ClipperLib::Paths* paths)
|
||||
{
|
||||
CLIPPERUTILS_PROFILE_FUNC();
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// scale input
|
||||
scaleClipperPolygons(*paths);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
|
||||
// perform offset (delta = scale 1e-05)
|
||||
ClipperLib::ClipperOffset co;
|
||||
@ -816,7 +873,11 @@ void safety_offset(ClipperLib::Paths* paths)
|
||||
CLIPPERUTILS_PROFILE_BLOCK(safety_offset_Execute);
|
||||
// offset outside by 10um
|
||||
ClipperLib::Paths out_this;
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
co.Execute(out_this, ccw ? 10.f * float(CLIPPER_OFFSET_SCALE) : -10.f * float(CLIPPER_OFFSET_SCALE));
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
co.Execute(out_this, ccw ? 10.f : -10.f);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
if (! ccw) {
|
||||
// Reverse the resulting contours once again.
|
||||
for (ClipperLib::Paths::iterator it = out_this.begin(); it != out_this.end(); ++ it)
|
||||
@ -830,8 +891,10 @@ void safety_offset(ClipperLib::Paths* paths)
|
||||
}
|
||||
*paths = std::move(out);
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// unscale output
|
||||
unscaleClipperPolygons(*paths);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
}
|
||||
|
||||
Polygons top_level_islands(const Slic3r::Polygons &polygons)
|
||||
@ -925,8 +988,10 @@ ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::v
|
||||
|
||||
// Add a new point to the output, scale by CLIPPER_OFFSET_SCALE and round to ClipperLib::cInt.
|
||||
auto add_offset_point = [&out](Vec2d pt) {
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
pt *= double(CLIPPER_OFFSET_SCALE);
|
||||
pt += Vec2d(0.5 - (pt.x() < 0), 0.5 - (pt.y() < 0));
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
pt += Vec2d(0.5 - (pt.x() < 0), 0.5 - (pt.y() < 0));
|
||||
out.emplace_back(ClipperLib::cInt(pt.x()), ClipperLib::cInt(pt.y()));
|
||||
};
|
||||
|
||||
@ -1075,8 +1140,10 @@ Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::v
|
||||
clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||
}
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// 4) Unscale the output.
|
||||
unscaleClipperPolygons(output);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
return ClipperPaths_to_Slic3rPolygons(output);
|
||||
}
|
||||
|
||||
@ -1119,8 +1186,10 @@ for (const std::vector<float>& ds : deltas)
|
||||
clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||
}
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// 4) Unscale the output.
|
||||
unscaleClipperPolygons(output);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
return ClipperPaths_to_Slic3rPolygons(output);
|
||||
}
|
||||
|
||||
@ -1152,7 +1221,9 @@ for (const std::vector<float>& ds : deltas)
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 3) Subtract holes from the contours.
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
unscaleClipperPolygons(contours);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
ExPolygons output;
|
||||
if (holes.empty()) {
|
||||
output.reserve(contours.size());
|
||||
@ -1160,7 +1231,9 @@ for (const std::vector<float>& ds : deltas)
|
||||
output.emplace_back(ClipperPath_to_Slic3rPolygon(path));
|
||||
} else {
|
||||
ClipperLib::Clipper clipper;
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
unscaleClipperPolygons(holes);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
clipper.AddPaths(contours, ClipperLib::ptSubject, true);
|
||||
clipper.AddPaths(holes, ClipperLib::ptClip, true);
|
||||
ClipperLib::PolyTree polytree;
|
||||
@ -1200,7 +1273,9 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<s
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 3) Subtract holes from the contours.
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
unscaleClipperPolygons(contours);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
ExPolygons output;
|
||||
if (holes.empty()) {
|
||||
output.reserve(contours.size());
|
||||
@ -1208,7 +1283,9 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<s
|
||||
output.emplace_back(ClipperPath_to_Slic3rPolygon(path));
|
||||
} else {
|
||||
ClipperLib::Clipper clipper;
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
unscaleClipperPolygons(holes);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
clipper.AddPaths(contours, ClipperLib::ptSubject, true);
|
||||
clipper.AddPaths(holes, ClipperLib::ptClip, true);
|
||||
ClipperLib::PolyTree polytree;
|
||||
|
@ -12,17 +12,23 @@ using ClipperLib::jtMiter;
|
||||
using ClipperLib::jtRound;
|
||||
using ClipperLib::jtSquare;
|
||||
|
||||
// Factor to convert from coord_t (which is int32) to an int64 type used by the Clipper library
|
||||
// for general offsetting (the offset(), offset2(), offset_ex() functions) and for the safety offset,
|
||||
// which is optionally executed by other functions (union, intersection, diff).
|
||||
// This scaling (cca 130t) is applied over the usual SCALING_FACTOR.
|
||||
// By the way, is the scalling for offset needed at all?
|
||||
// The reason to apply this scaling may be to match the resolution of the double mantissa.
|
||||
#define CLIPPER_OFFSET_POWER_OF_2 17
|
||||
// 2^17=131072
|
||||
#define CLIPPER_OFFSET_SCALE (1 << CLIPPER_OFFSET_POWER_OF_2)
|
||||
#define CLIPPER_OFFSET_SCALE_ROUNDING_DELTA ((1 << (CLIPPER_OFFSET_POWER_OF_2 - 1)) - 1)
|
||||
#define CLIPPER_MAX_COORD_UNSCALED (ClipperLib::hiRange / CLIPPER_OFFSET_SCALE)
|
||||
#define CLIPPERUTILS_UNSAFE_OFFSET
|
||||
|
||||
// #define CLIPPERUTILS_OFFSET_SCALE
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// Factor to convert from coord_t (which is int32) to an int64 type used by the Clipper library
|
||||
// for general offsetting (the offset(), offset2(), offset_ex() functions) and for the safety offset,
|
||||
// which is optionally executed by other functions (union, intersection, diff).
|
||||
// This scaling (cca 130t) is applied over the usual SCALING_FACTOR.
|
||||
// By the way, is the scalling for offset needed at all?
|
||||
// The reason to apply this scaling may be to match the resolution of the double mantissa.
|
||||
#define CLIPPER_OFFSET_POWER_OF_2 17
|
||||
// 2^17=131072
|
||||
#define CLIPPER_OFFSET_SCALE (1 << CLIPPER_OFFSET_POWER_OF_2)
|
||||
#define CLIPPER_OFFSET_SCALE_ROUNDING_DELTA ((1 << (CLIPPER_OFFSET_POWER_OF_2 - 1)) - 1)
|
||||
#define CLIPPER_MAX_COORD_UNSCALED (ClipperLib::hiRange / CLIPPER_OFFSET_SCALE)
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -47,8 +53,11 @@ ClipperLib::Paths _offset(ClipperLib::Path &&input, ClipperLib::EndType endType,
|
||||
ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit);
|
||||
inline Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3)
|
||||
{ return ClipperPaths_to_Slic3rPolygons(_offset(Slic3rMultiPoint_to_ClipperPath(polygon), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); }
|
||||
|
||||
#ifdef CLIPPERUTILS_UNSAFE_OFFSET
|
||||
inline Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3)
|
||||
{ return ClipperPaths_to_Slic3rPolygons(_offset(Slic3rMultiPoints_to_ClipperPaths(polygons), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); }
|
||||
#endif // CLIPPERUTILS_UNSAFE_OFFSET
|
||||
|
||||
// offset Polylines
|
||||
inline Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtSquare, double miterLimit = 3)
|
||||
@ -65,13 +74,18 @@ inline Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float
|
||||
{ return ClipperPaths_to_Slic3rPolygons(_offset(expolygons, delta, joinType, miterLimit)); }
|
||||
inline Slic3r::ExPolygons offset_ex(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3)
|
||||
{ return ClipperPaths_to_Slic3rExPolygons(_offset(Slic3rMultiPoint_to_ClipperPath(polygon), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); }
|
||||
|
||||
#ifdef CLIPPERUTILS_UNSAFE_OFFSET
|
||||
inline Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3)
|
||||
{ return ClipperPaths_to_Slic3rExPolygons(_offset(Slic3rMultiPoints_to_ClipperPaths(polygons), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); }
|
||||
#endif // CLIPPERUTILS_UNSAFE_OFFSET
|
||||
|
||||
inline Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3)
|
||||
{ return ClipperPaths_to_Slic3rExPolygons(_offset(expolygon, delta, joinType, miterLimit)); }
|
||||
inline Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3)
|
||||
{ return ClipperPaths_to_Slic3rExPolygons(_offset(expolygons, delta, joinType, miterLimit)); }
|
||||
|
||||
#ifdef CLIPPERUTILS_UNSAFE_OFFSET
|
||||
ClipperLib::Paths _offset2(const Slic3r::Polygons &polygons, const float delta1,
|
||||
const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
|
||||
double miterLimit = 3);
|
||||
@ -81,6 +95,8 @@ Slic3r::Polygons offset2(const Slic3r::Polygons &polygons, const float delta1,
|
||||
Slic3r::ExPolygons offset2_ex(const Slic3r::Polygons &polygons, const float delta1,
|
||||
const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
|
||||
double miterLimit = 3);
|
||||
#endif // CLIPPERUTILS_UNSAFE_OFFSET
|
||||
|
||||
Slic3r::ExPolygons offset2_ex(const Slic3r::ExPolygons &expolygons, const float delta1,
|
||||
const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
|
||||
double miterLimit = 3);
|
||||
@ -319,6 +335,7 @@ void safety_offset(ClipperLib::Paths* paths);
|
||||
|
||||
Polygons top_level_islands(const Slic3r::Polygons &polygons);
|
||||
|
||||
ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::vector<float> &deltas, double miter_limit);
|
||||
Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
|
||||
Polygons variable_offset_outer(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
|
||||
ExPolygons variable_offset_outer_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
|
||||
|
@ -1441,6 +1441,24 @@ private:
|
||||
class ConfigOptionDef
|
||||
{
|
||||
public:
|
||||
enum class GUIType {
|
||||
undefined,
|
||||
// Open enums, integer value could be one of the enumerated values or something else.
|
||||
i_enum_open,
|
||||
// Open enums, float value could be one of the enumerated values or something else.
|
||||
f_enum_open,
|
||||
// Color picker, string value.
|
||||
color,
|
||||
// ???
|
||||
select_open,
|
||||
// Currently unused.
|
||||
slider,
|
||||
// Static text
|
||||
legend,
|
||||
// Vector value, but edited as a single string.
|
||||
one_string,
|
||||
};
|
||||
|
||||
// Identifier of this option. It is stored here so that it is accessible through the by_serialization_key_ordinal map.
|
||||
t_config_option_key opt_key;
|
||||
// What type? bool, int, string etc.
|
||||
@ -1524,7 +1542,7 @@ public:
|
||||
// Usually empty.
|
||||
// Special values - "i_enum_open", "f_enum_open" to provide combo box for int or float selection,
|
||||
// "select_open" - to open a selection dialog (currently only a serial port selection).
|
||||
std::string gui_type;
|
||||
GUIType gui_type { GUIType::undefined };
|
||||
// Usually empty. Otherwise "serialized" or "show_value"
|
||||
// The flags may be combined.
|
||||
// "serialized" - vector valued option is entered in a single edit field. Values are separated by a semicolon.
|
||||
@ -1949,8 +1967,9 @@ public:
|
||||
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*.
|
||||
// Thus the virtual method getInt() is used to retrieve the enum value.
|
||||
template<typename ENUM>
|
||||
ENUM opt_enum(const t_config_option_key &opt_key) const { return this->option<ConfigOptionEnum<ENUM>>(opt_key)->value; }
|
||||
ENUM opt_enum(const t_config_option_key &opt_key) const { return static_cast<ENUM>(this->option(opt_key)->getInt()); }
|
||||
|
||||
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; }
|
||||
|
@ -621,7 +621,7 @@ ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, double min_c
|
||||
ExPolygon elephant_foot_compensation(const ExPolygon &input, const Flow &external_perimeter_flow, const double compensation)
|
||||
{
|
||||
// The contour shall be wide enough to apply the external perimeter plus compensation on both sides.
|
||||
double min_contour_width = double(external_perimeter_flow.width + external_perimeter_flow.spacing());
|
||||
double min_contour_width = double(external_perimeter_flow.width() + external_perimeter_flow.spacing());
|
||||
return elephant_foot_compensation(input, min_contour_width, compensation);
|
||||
}
|
||||
|
||||
|
@ -217,6 +217,28 @@ inline Polygons to_polygons(const ExPolygons &src)
|
||||
return polygons;
|
||||
}
|
||||
|
||||
inline ConstPolygonPtrs to_polygon_ptrs(const ExPolygon &src)
|
||||
{
|
||||
ConstPolygonPtrs polygons;
|
||||
polygons.reserve(src.holes.size() + 1);
|
||||
polygons.emplace_back(&src.contour);
|
||||
for (const Polygon &hole : src.holes)
|
||||
polygons.emplace_back(&hole);
|
||||
return polygons;
|
||||
}
|
||||
|
||||
inline ConstPolygonPtrs to_polygon_ptrs(const ExPolygons &src)
|
||||
{
|
||||
ConstPolygonPtrs polygons;
|
||||
polygons.reserve(number_polygons(src));
|
||||
for (const ExPolygon &expoly : src) {
|
||||
polygons.emplace_back(&expoly.contour);
|
||||
for (const Polygon &hole : expoly.holes)
|
||||
polygons.emplace_back(&hole);
|
||||
}
|
||||
return polygons;
|
||||
}
|
||||
|
||||
inline Polygons to_polygons(ExPolygon &&src)
|
||||
{
|
||||
Polygons polygons;
|
||||
|
132
src/libslic3r/Execution/Execution.hpp
Normal file
@ -0,0 +1,132 @@
|
||||
#ifndef EXECUTION_HPP
|
||||
#define EXECUTION_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
|
||||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Borrowed from C++20
|
||||
template<class T>
|
||||
using remove_cvref_t = std::remove_reference_t<std::remove_cv_t<T>>;
|
||||
|
||||
// Override for valid execution policies
|
||||
template<class EP> struct IsExecutionPolicy_ : public std::false_type {};
|
||||
|
||||
template<class EP> constexpr bool IsExecutionPolicy =
|
||||
IsExecutionPolicy_<remove_cvref_t<EP>>::value;
|
||||
|
||||
template<class EP, class T = void>
|
||||
using ExecutionPolicyOnly = std::enable_if_t<IsExecutionPolicy<EP>, T>;
|
||||
|
||||
namespace execution {
|
||||
|
||||
// This struct needs to be specialized for each execution policy.
|
||||
// See ExecutionSeq.hpp and ExecutionTBB.hpp for example.
|
||||
template<class EP, class En = void> struct Traits {};
|
||||
|
||||
template<class EP> using AsTraits = Traits<remove_cvref_t<EP>>;
|
||||
|
||||
// Each execution policy should declare two types of mutexes. A a spin lock and
|
||||
// a blocking mutex. These types should satisfy the BasicLockable concept.
|
||||
template<class EP> using SpinningMutex = typename Traits<EP>::SpinningMutex;
|
||||
template<class EP> using BlockingMutex = typename Traits<EP>::BlockingMutex;
|
||||
|
||||
// Query the available threads for concurrency.
|
||||
template<class EP, class = ExecutionPolicyOnly<EP> >
|
||||
size_t max_concurrency(const EP &ep)
|
||||
{
|
||||
return AsTraits<EP>::max_concurrency(ep);
|
||||
}
|
||||
|
||||
// foreach loop with the execution policy passed as argument. Granularity can
|
||||
// be specified explicitly. max_concurrency() can be used for optimal results.
|
||||
template<class EP, class It, class Fn, class = ExecutionPolicyOnly<EP>>
|
||||
void for_each(const EP &ep, It from, It to, Fn &&fn, size_t granularity = 1)
|
||||
{
|
||||
AsTraits<EP>::for_each(ep, from, to, std::forward<Fn>(fn), granularity);
|
||||
}
|
||||
|
||||
// A reduce operation with the execution policy passed as argument.
|
||||
// mergefn has T(const T&, const T&) signature
|
||||
// accessfn has T(I) signature if I is an integral type and
|
||||
// T(const I::value_type &) if I is an iterator type.
|
||||
template<class EP,
|
||||
class I,
|
||||
class MergeFn,
|
||||
class T,
|
||||
class AccessFn,
|
||||
class = ExecutionPolicyOnly<EP> >
|
||||
T reduce(const EP & ep,
|
||||
I from,
|
||||
I to,
|
||||
const T & init,
|
||||
MergeFn && mergefn,
|
||||
AccessFn &&accessfn,
|
||||
size_t granularity = 1)
|
||||
{
|
||||
return AsTraits<EP>::reduce(ep, from, to, init,
|
||||
std::forward<MergeFn>(mergefn),
|
||||
std::forward<AccessFn>(accessfn),
|
||||
granularity);
|
||||
}
|
||||
|
||||
// An overload of reduce method to be used with iterators as 'from' and 'to'
|
||||
// arguments. Access functor is omitted here.
|
||||
template<class EP,
|
||||
class I,
|
||||
class MergeFn,
|
||||
class T,
|
||||
class = ExecutionPolicyOnly<EP> >
|
||||
T reduce(const EP &ep,
|
||||
I from,
|
||||
I to,
|
||||
const T & init,
|
||||
MergeFn &&mergefn,
|
||||
size_t granularity = 1)
|
||||
{
|
||||
return reduce(
|
||||
ep, from, to, init, std::forward<MergeFn>(mergefn),
|
||||
[](const auto &i) { return i; }, granularity);
|
||||
}
|
||||
|
||||
template<class EP,
|
||||
class I,
|
||||
class T,
|
||||
class AccessFn,
|
||||
class = ExecutionPolicyOnly<EP>>
|
||||
T accumulate(const EP & ep,
|
||||
I from,
|
||||
I to,
|
||||
const T & init,
|
||||
AccessFn &&accessfn,
|
||||
size_t granularity = 1)
|
||||
{
|
||||
return reduce(ep, from, to, init, std::plus<T>{},
|
||||
std::forward<AccessFn>(accessfn), granularity);
|
||||
}
|
||||
|
||||
|
||||
template<class EP,
|
||||
class I,
|
||||
class T,
|
||||
class = ExecutionPolicyOnly<EP> >
|
||||
T accumulate(const EP &ep,
|
||||
I from,
|
||||
I to,
|
||||
const T & init,
|
||||
size_t granularity = 1)
|
||||
{
|
||||
return reduce(
|
||||
ep, from, to, init, std::plus<T>{}, [](const auto &i) { return i; },
|
||||
granularity);
|
||||
}
|
||||
|
||||
} // namespace execution_policy
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // EXECUTION_HPP
|
84
src/libslic3r/Execution/ExecutionSeq.hpp
Normal file
@ -0,0 +1,84 @@
|
||||
#ifndef EXECUTIONSEQ_HPP
|
||||
#define EXECUTIONSEQ_HPP
|
||||
|
||||
#ifdef PRUSASLICER_USE_EXECUTION_STD // Conflicts with our version of TBB
|
||||
#include <execution>
|
||||
#endif
|
||||
|
||||
#include "Execution.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Execution policy implementing dummy sequential algorithms
|
||||
struct ExecutionSeq {};
|
||||
|
||||
template<> struct IsExecutionPolicy_<ExecutionSeq> : public std::true_type {};
|
||||
|
||||
static constexpr ExecutionSeq ex_seq = {};
|
||||
|
||||
template<class EP> struct IsSequentialEP_ { static constexpr bool value = false; };
|
||||
|
||||
template<> struct IsSequentialEP_<ExecutionSeq>: public std::true_type {};
|
||||
#ifdef PRUSASLICER_USE_EXECUTION_STD
|
||||
template<> struct IsExecutionPolicy_<std::execution::sequenced_policy>: public std::true_type {};
|
||||
template<> struct IsSequentialEP_<std::execution::sequenced_policy>: public std::true_type {};
|
||||
#endif
|
||||
|
||||
template<class EP>
|
||||
constexpr bool IsSequentialEP = IsSequentialEP_<remove_cvref_t<EP>>::value;
|
||||
|
||||
template<class EP, class R = EP>
|
||||
using SequentialEPOnly = std::enable_if_t<IsSequentialEP<EP>, R>;
|
||||
|
||||
template<class EP>
|
||||
struct execution::Traits<EP, SequentialEPOnly<EP, void>> {
|
||||
private:
|
||||
struct _Mtx { inline void lock() {} inline void unlock() {} };
|
||||
|
||||
template<class Fn, class It>
|
||||
static IteratorOnly<It, void> loop_(It from, It to, Fn &&fn)
|
||||
{
|
||||
for (auto it = from; it != to; ++it) fn(*it);
|
||||
}
|
||||
|
||||
template<class Fn, class I>
|
||||
static IntegerOnly<I, void> loop_(I from, I to, Fn &&fn)
|
||||
{
|
||||
for (I i = from; i < to; ++i) fn(i);
|
||||
}
|
||||
|
||||
public:
|
||||
using SpinningMutex = _Mtx;
|
||||
using BlockingMutex = _Mtx;
|
||||
|
||||
template<class It, class Fn>
|
||||
static void for_each(const EP &,
|
||||
It from,
|
||||
It to,
|
||||
Fn &&fn,
|
||||
size_t /* ignore granularity */ = 1)
|
||||
{
|
||||
loop_(from, to, std::forward<Fn>(fn));
|
||||
}
|
||||
|
||||
template<class I, class MergeFn, class T, class AccessFn>
|
||||
static T reduce(const EP &,
|
||||
I from,
|
||||
I to,
|
||||
const T & init,
|
||||
MergeFn &&mergefn,
|
||||
AccessFn &&access,
|
||||
size_t /*granularity*/ = 1
|
||||
)
|
||||
{
|
||||
T acc = init;
|
||||
loop_(from, to, [&](auto &i) { acc = mergefn(acc, access(i)); });
|
||||
return acc;
|
||||
}
|
||||
|
||||
static size_t max_concurrency(const EP &) { return 1; }
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // EXECUTIONSEQ_HPP
|
77
src/libslic3r/Execution/ExecutionTBB.hpp
Normal file
@ -0,0 +1,77 @@
|
||||
#ifndef EXECUTIONTBB_HPP
|
||||
#define EXECUTIONTBB_HPP
|
||||
|
||||
#include <tbb/spin_mutex.h>
|
||||
#include <tbb/mutex.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/parallel_reduce.h>
|
||||
#include <tbb/task_arena.h>
|
||||
|
||||
#include "Execution.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
struct ExecutionTBB {};
|
||||
template<> struct IsExecutionPolicy_<ExecutionTBB> : public std::true_type {};
|
||||
|
||||
// Execution policy using Intel TBB library under the hood.
|
||||
static constexpr ExecutionTBB ex_tbb = {};
|
||||
|
||||
template<> struct execution::Traits<ExecutionTBB> {
|
||||
private:
|
||||
|
||||
template<class Fn, class It>
|
||||
static IteratorOnly<It, void> loop_(const tbb::blocked_range<It> &range, Fn &&fn)
|
||||
{
|
||||
for (auto &el : range) fn(el);
|
||||
}
|
||||
|
||||
template<class Fn, class I>
|
||||
static IntegerOnly<I, void> loop_(const tbb::blocked_range<I> &range, Fn &&fn)
|
||||
{
|
||||
for (I i = range.begin(); i < range.end(); ++i) fn(i);
|
||||
}
|
||||
|
||||
public:
|
||||
using SpinningMutex = tbb::spin_mutex;
|
||||
using BlockingMutex = tbb::mutex;
|
||||
|
||||
template<class It, class Fn>
|
||||
static void for_each(const ExecutionTBB &,
|
||||
It from, It to, Fn &&fn, size_t granularity)
|
||||
{
|
||||
tbb::parallel_for(tbb::blocked_range{from, to, granularity},
|
||||
[&fn](const auto &range) {
|
||||
loop_(range, std::forward<Fn>(fn));
|
||||
});
|
||||
}
|
||||
|
||||
template<class I, class MergeFn, class T, class AccessFn>
|
||||
static T reduce(const ExecutionTBB &,
|
||||
I from,
|
||||
I to,
|
||||
const T &init,
|
||||
MergeFn &&mergefn,
|
||||
AccessFn &&access,
|
||||
size_t granularity = 1
|
||||
)
|
||||
{
|
||||
return tbb::parallel_reduce(
|
||||
tbb::blocked_range{from, to, granularity}, init,
|
||||
[&](const auto &range, T subinit) {
|
||||
T acc = subinit;
|
||||
loop_(range, [&](auto &i) { acc = mergefn(acc, access(i)); });
|
||||
return acc;
|
||||
},
|
||||
std::forward<MergeFn>(mergefn));
|
||||
}
|
||||
|
||||
static size_t max_concurrency(const ExecutionTBB &)
|
||||
{
|
||||
return tbb::this_task_arena::max_concurrency();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // EXECUTIONTBB_HPP
|
@ -52,7 +52,9 @@ void ExtrusionPath::polygons_covered_by_spacing(Polygons &out, const float scale
|
||||
{
|
||||
// Instantiating the Flow class to get the line spacing.
|
||||
// Don't know the nozzle diameter, setting to zero. It shall not matter it shall be optimized out by the compiler.
|
||||
Flow flow(this->width, this->height, 0.f, is_bridge(this->role()));
|
||||
bool bridge = is_bridge(this->role());
|
||||
assert(! bridge || this->width == this->height);
|
||||
auto flow = bridge ? Flow::bridging_flow(this->width, 0.f) : Flow(this->width, this->height, 0.f);
|
||||
polygons_append(out, offset(this->polyline, 0.5f * float(flow.scaled_spacing()) + scaled_epsilon));
|
||||
}
|
||||
|
||||
|
@ -203,6 +203,8 @@ public:
|
||||
void reverse() override;
|
||||
const Point& first_point() const override { return this->paths.front().polyline.points.front(); }
|
||||
const Point& last_point() const override { return this->paths.back().polyline.points.back(); }
|
||||
size_t size() const { return this->paths.size(); }
|
||||
bool empty() const { return this->paths.empty(); }
|
||||
double length() const override;
|
||||
ExtrusionRole role() const override { return this->paths.empty() ? erNone : this->paths.front().role(); }
|
||||
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width.
|
||||
|
@ -28,6 +28,8 @@ struct SurfaceFillParams
|
||||
// coordf_t overlap = 0.;
|
||||
// Angle as provided by the region config, in radians.
|
||||
float angle = 0.f;
|
||||
// Is bridging used for this fill? Bridging parameters may be used even if this->flow.bridge() is not set.
|
||||
bool bridge;
|
||||
// Non-negative for a bridge.
|
||||
float bridge_angle = 0.f;
|
||||
|
||||
@ -42,7 +44,7 @@ struct SurfaceFillParams
|
||||
|
||||
// width, height of extrusion, nozzle diameter, is bridge
|
||||
// For the output, for fill generator.
|
||||
Flow flow = Flow(0.f, 0.f, 0.f, false);
|
||||
Flow flow;
|
||||
|
||||
// For the output
|
||||
ExtrusionRole extrusion_role = ExtrusionRole(0);
|
||||
@ -70,21 +72,22 @@ struct SurfaceFillParams
|
||||
// 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);
|
||||
RETURN_COMPARE_NON_EQUAL(flow.height);
|
||||
RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter);
|
||||
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, flow.bridge);
|
||||
RETURN_COMPARE_NON_EQUAL(flow.width());
|
||||
RETURN_COMPARE_NON_EQUAL(flow.height());
|
||||
RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter());
|
||||
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, bridge);
|
||||
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, extrusion_role);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator==(const SurfaceFillParams &rhs) const {
|
||||
return this->extruder == rhs.extruder &&
|
||||
this->pattern == rhs.pattern &&
|
||||
this->pattern == rhs.pattern &&
|
||||
this->spacing == rhs.spacing &&
|
||||
// this->overlap == rhs.overlap &&
|
||||
this->angle == rhs.angle &&
|
||||
this->bridge == rhs.bridge &&
|
||||
// this->bridge_angle == rhs.bridge_angle &&
|
||||
this->density == rhs.density &&
|
||||
// this->dont_adjust == rhs.dont_adjust &&
|
||||
this->anchor_length == rhs.anchor_length &&
|
||||
@ -128,6 +131,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
|
||||
if (surface.is_solid()) {
|
||||
params.density = 100.f;
|
||||
//FIXME for non-thick bridges, shall we allow a bottom surface pattern?
|
||||
params.pattern = (surface.is_external() && ! is_bridge) ?
|
||||
(surface.is_top() ? region_config.top_fill_pattern.value : region_config.bottom_fill_pattern.value) :
|
||||
region_config.top_fill_pattern == ipMonotonic ? ipMonotonic : ipRectilinear;
|
||||
@ -143,17 +147,13 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
params.bridge_angle = float(surface.bridge_angle);
|
||||
params.angle = float(Geometry::deg2rad(region_config.fill_angle.value));
|
||||
|
||||
// calculate the actual flow we'll be using for this infill
|
||||
params.flow = layerm.region()->flow(
|
||||
extrusion_role,
|
||||
(surface.thickness == -1) ? layer.height : surface.thickness, // extrusion height
|
||||
is_bridge || Fill::use_bridge_flow(params.pattern), // bridge flow?
|
||||
layer.id() == 0, // first layer?
|
||||
-1, // auto width
|
||||
*layer.object()
|
||||
);
|
||||
// Calculate the actual flow we'll be using for this infill.
|
||||
params.bridge = is_bridge || Fill::use_bridge_flow(params.pattern);
|
||||
params.flow = params.bridge ?
|
||||
layerm.bridging_flow(extrusion_role) :
|
||||
layerm.flow(extrusion_role, (surface.thickness == -1) ? layer.height : surface.thickness);
|
||||
|
||||
// Calculate flow spacing for infill pattern generation.
|
||||
// Calculate flow spacing for infill pattern generation.
|
||||
if (surface.is_solid() || is_bridge) {
|
||||
params.spacing = params.flow.spacing();
|
||||
// Don't limit anchor length for solid or bridging infill.
|
||||
@ -164,14 +164,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
// for all layers, for avoiding the ugly effect of
|
||||
// misaligned infill on first layer because of different extrusion width and
|
||||
// layer height
|
||||
params.spacing = layerm.region()->flow(
|
||||
frInfill,
|
||||
layer.object()->config().layer_height.value, // TODO: handle infill_every_layers?
|
||||
false, // no bridge
|
||||
false, // no first layer
|
||||
-1, // auto width
|
||||
*layer.object()
|
||||
).spacing();
|
||||
params.spacing = layerm.flow(frInfill, layer.object()->config().layer_height).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)
|
||||
@ -278,7 +271,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
region_id = region_some_infill;
|
||||
const LayerRegion& layerm = *layer.regions()[region_id];
|
||||
for (SurfaceFill &surface_fill : surface_fills)
|
||||
if (surface_fill.surface.surface_type == stInternalSolid && std::abs(layer.height - surface_fill.params.flow.height) < EPSILON) {
|
||||
if (surface_fill.surface.surface_type == stInternalSolid && std::abs(layer.height - surface_fill.params.flow.height()) < EPSILON) {
|
||||
internal_solid_fill = &surface_fill;
|
||||
break;
|
||||
}
|
||||
@ -290,14 +283,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
params.extrusion_role = erInternalInfill;
|
||||
params.angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
|
||||
// calculate the actual flow we'll be using for this infill
|
||||
params.flow = layerm.region()->flow(
|
||||
frSolidInfill,
|
||||
layer.height, // extrusion height
|
||||
false, // bridge flow?
|
||||
layer.id() == 0, // first layer?
|
||||
-1, // auto width
|
||||
*layer.object()
|
||||
);
|
||||
params.flow = layerm.flow(frSolidInfill);
|
||||
params.spacing = params.flow.spacing();
|
||||
surface_fills.emplace_back(params);
|
||||
surface_fills.back().surface.surface_type = stInternalSolid;
|
||||
@ -365,9 +351,9 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
||||
f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
|
||||
|
||||
// calculate flow spacing for infill pattern generation
|
||||
bool using_internal_flow = ! surface_fill.surface.is_solid() && ! surface_fill.params.flow.bridge;
|
||||
bool using_internal_flow = ! surface_fill.surface.is_solid() && ! surface_fill.params.bridge;
|
||||
double link_max_length = 0.;
|
||||
if (! surface_fill.params.flow.bridge) {
|
||||
if (! surface_fill.params.bridge) {
|
||||
#if 0
|
||||
link_max_length = layerm.region()->config().get_abs_value(surface.is_external() ? "external_fill_link_max_length" : "fill_link_max_length", flow.spacing());
|
||||
// printf("flow spacing: %f, is_external: %d, link_max_length: %lf\n", flow.spacing(), int(surface.is_external()), link_max_length);
|
||||
@ -380,7 +366,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
||||
// Maximum length of the perimeter segment linking two infill lines.
|
||||
f->link_max_length = (coord_t)scale_(link_max_length);
|
||||
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
|
||||
f->loop_clipping = coord_t(scale_(surface_fill.params.flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
|
||||
f->loop_clipping = coord_t(scale_(surface_fill.params.flow.nozzle_diameter()) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
|
||||
|
||||
// apply half spacing using this flow's own spacing and generate infill
|
||||
FillParams params;
|
||||
@ -402,15 +388,15 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
||||
// calculate actual flow from spacing (which might have been adjusted by the infill
|
||||
// pattern generator)
|
||||
double flow_mm3_per_mm = surface_fill.params.flow.mm3_per_mm();
|
||||
double flow_width = surface_fill.params.flow.width;
|
||||
double flow_width = surface_fill.params.flow.width();
|
||||
if (using_internal_flow) {
|
||||
// if we used the internal flow we're not doing a solid infill
|
||||
// so we can safely ignore the slight variation that might have
|
||||
// been applied to f->spacing
|
||||
} else {
|
||||
Flow new_flow = Flow::new_from_spacing(float(f->spacing), surface_fill.params.flow.nozzle_diameter, surface_fill.params.flow.height, surface_fill.params.flow.bridge);
|
||||
Flow new_flow = surface_fill.params.flow.with_spacing(float(f->spacing));
|
||||
flow_mm3_per_mm = new_flow.mm3_per_mm();
|
||||
flow_width = new_flow.width;
|
||||
flow_width = new_flow.width();
|
||||
}
|
||||
// Save into layer.
|
||||
ExtrusionEntityCollection* eec = nullptr;
|
||||
@ -420,7 +406,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
||||
extrusion_entities_append_paths(
|
||||
eec->entities, std::move(polylines),
|
||||
surface_fill.params.extrusion_role,
|
||||
flow_mm3_per_mm, float(flow_width), surface_fill.params.flow.height);
|
||||
flow_mm3_per_mm, float(flow_width), surface_fill.params.flow.height());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -618,9 +604,9 @@ void Layer::make_ironing()
|
||||
fill.spacing = ironing_params.line_spacing;
|
||||
fill.angle = float(ironing_params.angle + 0.25 * M_PI);
|
||||
fill.link_max_length = (coord_t)scale_(3. * fill.spacing);
|
||||
double height = ironing_params.height * fill.spacing / nozzle_dmr;
|
||||
Flow flow = Flow::new_from_spacing(float(nozzle_dmr), 0., float(height), false);
|
||||
double flow_mm3_per_mm = flow.mm3_per_mm();
|
||||
double extrusion_height = ironing_params.height * fill.spacing / nozzle_dmr;
|
||||
float extrusion_width = Flow::rounded_rectangle_extrusion_width_from_spacing(float(nozzle_dmr), float(extrusion_height));
|
||||
double flow_mm3_per_mm = nozzle_dmr * extrusion_height;
|
||||
Surface surface_fill(stTop, ExPolygon());
|
||||
for (ExPolygon &expoly : ironing_areas) {
|
||||
surface_fill.expolygon = std::move(expoly);
|
||||
@ -638,7 +624,7 @@ void Layer::make_ironing()
|
||||
extrusion_entities_append_paths(
|
||||
eec->entities, std::move(polylines),
|
||||
erIroning,
|
||||
flow_mm3_per_mm, float(flow.width), float(height));
|
||||
flow_mm3_per_mm, extrusion_width, float(extrusion_height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ void Fill3DHoneycomb::_fill_surface_single(
|
||||
// align bounding box to a multiple of our honeycomb grid module
|
||||
// (a module is 2*$distance since one $distance half-module is
|
||||
// growing while the other $distance half-module is shrinking)
|
||||
bb.merge(_align_to_grid(bb.min, Point(2*distance, 2*distance)));
|
||||
bb.merge(align_to_grid(bb.min, Point(2*distance, 2*distance)));
|
||||
|
||||
// generate pattern
|
||||
Polylines polylines = makeGrid(
|
||||
|
@ -133,26 +133,10 @@ public:
|
||||
static void connect_infill(Polylines &&infill_ordered, const Polygons &boundary, const BoundingBox& bbox, Polylines &polylines_out, const double spacing, const FillParams ¶ms);
|
||||
static void connect_infill(Polylines &&infill_ordered, const std::vector<const Polygon*> &boundary, const BoundingBox &bbox, Polylines &polylines_out, double spacing, const FillParams ¶ms);
|
||||
|
||||
static coord_t _adjust_solid_spacing(const coord_t width, const coord_t distance);
|
||||
static void connect_base_support(Polylines &&infill_ordered, const std::vector<const Polygon*> &boundary_src, const BoundingBox &bbox, Polylines &polylines_out, const double spacing, const FillParams ¶ms);
|
||||
static void connect_base_support(Polylines &&infill_ordered, const Polygons &boundary_src, const BoundingBox &bbox, Polylines &polylines_out, const double spacing, const FillParams ¶ms);
|
||||
|
||||
// Align a coordinate to a grid. The coordinate may be negative,
|
||||
// the aligned value will never be bigger than the original one.
|
||||
static coord_t _align_to_grid(const coord_t coord, const coord_t spacing) {
|
||||
// Current C++ standard defines the result of integer division to be rounded to zero,
|
||||
// for both positive and negative numbers. Here we want to round down for negative
|
||||
// numbers as well.
|
||||
coord_t aligned = (coord < 0) ?
|
||||
((coord - spacing + 1) / spacing) * spacing :
|
||||
(coord / spacing) * spacing;
|
||||
assert(aligned <= coord);
|
||||
return aligned;
|
||||
}
|
||||
static Point _align_to_grid(Point coord, Point spacing)
|
||||
{ return Point(_align_to_grid(coord(0), spacing(0)), _align_to_grid(coord(1), spacing(1))); }
|
||||
static coord_t _align_to_grid(coord_t coord, coord_t spacing, coord_t base)
|
||||
{ return base + _align_to_grid(coord - base, spacing); }
|
||||
static Point _align_to_grid(Point coord, Point spacing, Point base)
|
||||
{ return Point(_align_to_grid(coord(0), spacing(0), base(0)), _align_to_grid(coord(1), spacing(1), base(1))); }
|
||||
static coord_t _adjust_solid_spacing(const coord_t width, const coord_t distance);
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -24,11 +24,11 @@ void FillConcentric::_fill_surface_single(
|
||||
this->spacing = unscale<double>(distance);
|
||||
}
|
||||
|
||||
Polygons loops = to_polygons(std::move(expolygon));
|
||||
Polygons last = loops;
|
||||
Polygons loops = to_polygons(expolygon);
|
||||
ExPolygons last { std::move(expolygon) };
|
||||
while (! last.empty()) {
|
||||
last = offset2(last, -(distance + min_spacing/2), +min_spacing/2);
|
||||
append(loops, last);
|
||||
last = offset2_ex(last, -(distance + min_spacing/2), +min_spacing/2);
|
||||
append(loops, to_polygons(last));
|
||||
}
|
||||
|
||||
// generate paths from the outermost to the innermost, to avoid
|
||||
|
@ -166,7 +166,7 @@ void FillGyroid::_fill_surface_single(
|
||||
coord_t distance = coord_t(scale_(this->spacing) / density_adjusted);
|
||||
|
||||
// align bounding box to a multiple of our grid module
|
||||
bb.merge(_align_to_grid(bb.min, Point(2*M_PI*distance, 2*M_PI*distance)));
|
||||
bb.merge(align_to_grid(bb.min, Point(2*M_PI*distance, 2*M_PI*distance)));
|
||||
|
||||
// generate pattern
|
||||
Polylines polylines = make_gyroid_waves(
|
||||
|
@ -47,7 +47,7 @@ void FillHoneycomb::_fill_surface_single(
|
||||
// extend bounding box so that our pattern will be aligned with other layers
|
||||
// $bounding_box->[X1] and [Y1] represent the displacement between new bounding box offset and old one
|
||||
// The infill is not aligned to the object bounding box, but to a world coordinate system. Supposedly good enough.
|
||||
bounding_box.merge(_align_to_grid(bounding_box.min, Point(m.hex_width, m.pattern_height)));
|
||||
bounding_box.merge(align_to_grid(bounding_box.min, Point(m.hex_width, m.pattern_height)));
|
||||
}
|
||||
|
||||
coord_t x = bounding_box.min(0);
|
||||
|
@ -31,7 +31,7 @@ void FillLine::_fill_surface_single(
|
||||
} else {
|
||||
// extend bounding box so that our pattern will be aligned with other layers
|
||||
// Transform the reference point to the rotated coordinate system.
|
||||
bounding_box.merge(_align_to_grid(
|
||||
bounding_box.merge(align_to_grid(
|
||||
bounding_box.min,
|
||||
Point(this->_line_spacing, this->_line_spacing),
|
||||
direction.second.rotated(- direction.first)));
|
||||
@ -58,7 +58,7 @@ void FillLine::_fill_surface_single(
|
||||
pts.push_back(it->a);
|
||||
pts.push_back(it->b);
|
||||
}
|
||||
Polylines polylines = intersection_pl(polylines_src, offset(to_polygons(expolygon), scale_(0.02)), false);
|
||||
Polylines polylines = intersection_pl(polylines_src, offset(expolygon, scale_(0.02)), false);
|
||||
|
||||
// FIXME Vojtech: This is only performed for horizontal lines, not for the vertical lines!
|
||||
const float INFILL_OVERLAP_OVER_SPACING = 0.3f;
|
||||
|
@ -798,33 +798,44 @@ static std::vector<SegmentedIntersectionLine> slice_region_by_vertical_lines(con
|
||||
assert(l <= this_x);
|
||||
assert(r >= this_x);
|
||||
// Calculate the intersection position in y axis. x is known.
|
||||
if (p1(0) == this_x) {
|
||||
if (p2(0) == this_x) {
|
||||
if (p1.x() == this_x) {
|
||||
if (p2.x() == this_x) {
|
||||
// Ignore strictly vertical segments.
|
||||
continue;
|
||||
}
|
||||
is.pos_p = p1(1);
|
||||
const Point &p0 = prev_value_modulo(iPrev, contour);
|
||||
if (int64_t(p0.x() - p1.x()) * int64_t(p2.x() - p1.x()) > 0) {
|
||||
// Ignore points of a contour touching the infill line from one side.
|
||||
continue;
|
||||
}
|
||||
is.pos_p = p1.y();
|
||||
is.pos_q = 1;
|
||||
} else if (p2(0) == this_x) {
|
||||
is.pos_p = p2(1);
|
||||
} else if (p2.x() == this_x) {
|
||||
const Point &p3 = next_value_modulo(iSegment, contour);
|
||||
if (int64_t(p3.x() - p2.x()) * int64_t(p1.x() - p2.x()) > 0) {
|
||||
// Ignore points of a contour touching the infill line from one side.
|
||||
continue;
|
||||
}
|
||||
is.pos_p = p2.y();
|
||||
is.pos_q = 1;
|
||||
} else {
|
||||
// First calculate the intersection parameter 't' as a rational number with non negative denominator.
|
||||
if (p2(0) > p1(0)) {
|
||||
is.pos_p = this_x - p1(0);
|
||||
is.pos_q = p2(0) - p1(0);
|
||||
if (p2.x() > p1.x()) {
|
||||
is.pos_p = this_x - p1.x();
|
||||
is.pos_q = p2.x() - p1.x();
|
||||
} else {
|
||||
is.pos_p = p1(0) - this_x;
|
||||
is.pos_q = p1(0) - p2(0);
|
||||
is.pos_p = p1.x() - this_x;
|
||||
is.pos_q = p1.x() - p2.x();
|
||||
}
|
||||
assert(is.pos_p >= 0 && is.pos_p <= is.pos_q);
|
||||
assert(is.pos_q > 1);
|
||||
assert(is.pos_p > 0 && is.pos_p < is.pos_q);
|
||||
// Make an intersection point from the 't'.
|
||||
is.pos_p *= int64_t(p2(1) - p1(1));
|
||||
is.pos_p += p1(1) * int64_t(is.pos_q);
|
||||
is.pos_p *= int64_t(p2.y() - p1.y());
|
||||
is.pos_p += p1.y() * int64_t(is.pos_q);
|
||||
}
|
||||
// +-1 to take rounding into account.
|
||||
assert(is.pos() + 1 >= std::min(p1(1), p2(1)));
|
||||
assert(is.pos() <= std::max(p1(1), p2(1)) + 1);
|
||||
assert(is.pos() + 1 >= std::min(p1.y(), p2.y()));
|
||||
assert(is.pos() <= std::max(p1.y(), p2.y()) + 1);
|
||||
segs[i].intersections.push_back(is);
|
||||
}
|
||||
}
|
||||
@ -844,55 +855,46 @@ static std::vector<SegmentedIntersectionLine> slice_region_by_vertical_lines(con
|
||||
size_t j = 0;
|
||||
for (size_t i = 0; i < sil.intersections.size(); ++ i) {
|
||||
// What is the orientation of the segment at the intersection point?
|
||||
size_t iContour = sil.intersections[i].iContour;
|
||||
const Points &contour = poly_with_offset.contour(iContour).points;
|
||||
size_t iSegment = sil.intersections[i].iSegment;
|
||||
size_t iPrev = ((iSegment == 0) ? contour.size() : iSegment) - 1;
|
||||
coord_t dir = contour[iSegment](0) - contour[iPrev](0);
|
||||
bool low = dir > 0;
|
||||
sil.intersections[i].type = poly_with_offset.is_contour_outer(iContour) ?
|
||||
SegmentIntersection &is = sil.intersections[i];
|
||||
const size_t iContour = is.iContour;
|
||||
const Points &contour = poly_with_offset.contour(iContour).points;
|
||||
const size_t iSegment = is.iSegment;
|
||||
const size_t iPrev = prev_idx_modulo(iSegment, contour);
|
||||
const coord_t dir = contour[iSegment].x() - contour[iPrev].x();
|
||||
const bool low = dir > 0;
|
||||
is.type = poly_with_offset.is_contour_outer(iContour) ?
|
||||
(low ? SegmentIntersection::OUTER_LOW : SegmentIntersection::OUTER_HIGH) :
|
||||
(low ? SegmentIntersection::INNER_LOW : SegmentIntersection::INNER_HIGH);
|
||||
if (j > 0 && sil.intersections[i].iContour == sil.intersections[j-1].iContour) {
|
||||
// Two successive intersection points on a vertical line with the same contour. This may be a special case.
|
||||
if (sil.intersections[i].pos() == sil.intersections[j-1].pos()) {
|
||||
// Two successive segments meet exactly at the vertical line.
|
||||
#ifdef SLIC3R_DEBUG
|
||||
// Verify that the segments of sil.intersections[i] and sil.intersections[j-1] are adjoint.
|
||||
size_t iSegment2 = sil.intersections[j-1].iSegment;
|
||||
size_t iPrev2 = ((iSegment2 == 0) ? contour.size() : iSegment2) - 1;
|
||||
assert(iSegment == iPrev2 || iSegment2 == iPrev);
|
||||
#endif /* SLIC3R_DEBUG */
|
||||
if (sil.intersections[i].type == sil.intersections[j-1].type) {
|
||||
bool take_next = true;
|
||||
if (j > 0) {
|
||||
SegmentIntersection &is2 = sil.intersections[j - 1];
|
||||
if (iContour == is2.iContour && is.pos_q == 1 && is2.pos_q == 1) {
|
||||
// Two successive intersection points on a vertical line with the same contour, both points are end points of their respective contour segments.
|
||||
if (is.pos_p == is2.pos_p) {
|
||||
// Two successive segments meet exactly at the vertical line.
|
||||
// Verify that the segments of sil.intersections[i] and sil.intersections[j-1] are adjoint.
|
||||
assert(iSegment == prev_idx_modulo(is2.iSegment, contour) || is2.iSegment == iPrev);
|
||||
assert(is.type == is2.type);
|
||||
// Two successive segments of the same direction (both to the right or both to the left)
|
||||
// meet exactly at the vertical line.
|
||||
// Remove the second intersection point.
|
||||
} else {
|
||||
// This is a loop returning to the same point.
|
||||
// It may as well be a vertex of a loop touching this vertical line.
|
||||
// Remove both the lines.
|
||||
-- j;
|
||||
take_next = false;
|
||||
} else if (is.type == is2.type) {
|
||||
// Two non successive segments of the same direction (both to the right or both to the left)
|
||||
// meet exactly at the vertical line. That means there is a Z shaped path, where the center segment
|
||||
// of the Z shaped path is aligned with this vertical line.
|
||||
// Remove one of the intersection points while maximizing the vertical segment length.
|
||||
if (low) {
|
||||
// Remove the second intersection point, keep the first intersection point.
|
||||
} else {
|
||||
// Remove the first intersection point, keep the second intersection point.
|
||||
sil.intersections[j-1] = sil.intersections[i];
|
||||
}
|
||||
take_next = false;
|
||||
}
|
||||
} else if (sil.intersections[i].type == sil.intersections[j-1].type) {
|
||||
// Two non successive segments of the same direction (both to the right or both to the left)
|
||||
// meet exactly at the vertical line. That means there is a Z shaped path, where the center segment
|
||||
// of the Z shaped path is aligned with this vertical line.
|
||||
// Remove one of the intersection points while maximizing the vertical segment length.
|
||||
if (low) {
|
||||
// Remove the second intersection point, keep the first intersection point.
|
||||
} else {
|
||||
// Remove the first intersection point, keep the second intersection point.
|
||||
sil.intersections[j-1] = sil.intersections[i];
|
||||
}
|
||||
} else {
|
||||
// Vertical line intersects a contour segment at a general position (not at one of its end points).
|
||||
// or the contour just touches this vertical line with a vertical segment or a sequence of vertical segments.
|
||||
// Keep both intersection points.
|
||||
if (j < i)
|
||||
sil.intersections[j] = sil.intersections[i];
|
||||
++ j;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
if (take_next) {
|
||||
// Vertical line intersects a contour segment at a general position (not at one of its end points).
|
||||
if (j < i)
|
||||
sil.intersections[j] = sil.intersections[i];
|
||||
@ -905,7 +907,13 @@ static std::vector<SegmentedIntersectionLine> slice_region_by_vertical_lines(con
|
||||
}
|
||||
|
||||
// Verify the segments. If something is wrong, give up.
|
||||
#define ASSERT_THROW(CONDITION) do { assert(CONDITION); if (! (CONDITION)) throw InfillFailedException(); } while (0)
|
||||
#ifdef INFILL_DEBUG_OUTPUT
|
||||
#define INFILL_DEBUG_ASSERT(CONDITION)
|
||||
try {
|
||||
#else // INFILL_DEBUG_OUTPUT
|
||||
#define INFILL_DEBUG_ASSERT(CONDITION) assert(CONDITION)
|
||||
#endif // INFILL_DEBUG_OUTPUT
|
||||
#define ASSERT_THROW(CONDITION) do { INFILL_DEBUG_ASSERT(CONDITION); if (! (CONDITION)) throw InfillFailedException(); } while (0)
|
||||
for (size_t i_seg = 0; i_seg < segs.size(); ++ i_seg) {
|
||||
SegmentedIntersectionLine &sil = segs[i_seg];
|
||||
// The intersection points have to be even.
|
||||
@ -925,6 +933,56 @@ static std::vector<SegmentedIntersectionLine> slice_region_by_vertical_lines(con
|
||||
}
|
||||
}
|
||||
#undef ASSERT_THROW
|
||||
#undef INFILL_DEBUG_ASSERT
|
||||
#ifdef INFILL_DEBUG_OUTPUT
|
||||
} catch (const InfillFailedException & /* ex */) {
|
||||
// Export the buggy result into an SVG file.
|
||||
static int iRun = 0;
|
||||
BoundingBox bbox = get_extents(poly_with_offset.polygons_src);
|
||||
bbox.offset(scale_(3.));
|
||||
::Slic3r::SVG svg(debug_out_path("slice_region_by_vertical_lines-failed-%d.svg", iRun ++), bbox);
|
||||
svg.draw(poly_with_offset.polygons_src);
|
||||
svg.draw_outline(poly_with_offset.polygons_src, "green");
|
||||
svg.draw_outline(poly_with_offset.polygons_outer, "green");
|
||||
svg.draw_outline(poly_with_offset.polygons_inner, "green");
|
||||
for (size_t i_seg = 0; i_seg < segs.size(); ++i_seg) {
|
||||
SegmentedIntersectionLine &sil = segs[i_seg];
|
||||
for (size_t i = 0; i < sil.intersections.size();) {
|
||||
// An intersection segment crossing the bigger contour may cross the inner offsetted contour even number of times.
|
||||
if (sil.intersections[i].type != SegmentIntersection::OUTER_LOW) {
|
||||
svg.draw(Point(sil.pos, sil.intersections[i].pos()), "red");
|
||||
break;
|
||||
}
|
||||
size_t j = i + 1;
|
||||
if (j == sil.intersections.size()) {
|
||||
svg.draw(Point(sil.pos, sil.intersections[i].pos()), "magenta");
|
||||
break;
|
||||
}
|
||||
if (! (sil.intersections[j].type == SegmentIntersection::INNER_LOW || sil.intersections[j].type == SegmentIntersection::OUTER_HIGH)) {
|
||||
svg.draw(Point(sil.pos, sil.intersections[j].pos()), "blue");
|
||||
break;
|
||||
}
|
||||
for (; j < sil.intersections.size() && sil.intersections[j].is_inner(); ++j);
|
||||
if (j == sil.intersections.size()) {
|
||||
svg.draw(Point(sil.pos, sil.intersections[j - 1].pos()), "magenta");
|
||||
break;
|
||||
}
|
||||
if ((j & 1) != 1 || sil.intersections[j].type != SegmentIntersection::OUTER_HIGH) {
|
||||
svg.draw(Point(sil.pos, sil.intersections[j].pos()), "red");
|
||||
break;
|
||||
}
|
||||
if (! (i + 1 == j || sil.intersections[j - 1].type == SegmentIntersection::INNER_HIGH)) {
|
||||
svg.draw(Point(sil.pos, sil.intersections[j].pos()), "red");
|
||||
break;
|
||||
}
|
||||
svg.draw(Line(Point(sil.pos, sil.intersections[i].pos()), Point(sil.pos, sil.intersections[j].pos())), "black");
|
||||
i = j + 1;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
throw;
|
||||
}
|
||||
#endif //INFILL_DEBUG_OUTPUT
|
||||
|
||||
return segs;
|
||||
}
|
||||
@ -2714,10 +2772,10 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
|
||||
// extend bounding box so that our pattern will be aligned with other layers
|
||||
// Transform the reference point to the rotated coordinate system.
|
||||
Point refpt = rotate_vector.second.rotated(- rotate_vector.first);
|
||||
// _align_to_grid will not work correctly with positive pattern_shift.
|
||||
// align_to_grid will not work correctly with positive pattern_shift.
|
||||
coord_t pattern_shift_scaled = coord_t(scale_(pattern_shift)) % line_spacing;
|
||||
refpt.x() -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled);
|
||||
bounding_box.merge(_align_to_grid(
|
||||
bounding_box.merge(align_to_grid(
|
||||
bounding_box.min,
|
||||
Point(line_spacing, line_spacing),
|
||||
refpt));
|
||||
@ -2825,6 +2883,45 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
|
||||
return true;
|
||||
}
|
||||
|
||||
void make_fill_lines(const ExPolygonWithOffset &poly_with_offset, Point refpt, double angle, coord_t x_margin, coord_t line_spacing, coord_t pattern_shift, Polylines &fill_lines)
|
||||
{
|
||||
BoundingBox bounding_box = poly_with_offset.bounding_box_src();
|
||||
// Don't produce infill lines, which fully overlap with the infill perimeter.
|
||||
coord_t x_min = bounding_box.min.x() + x_margin;
|
||||
coord_t x_max = bounding_box.max.x() - x_margin;
|
||||
// extend bounding box so that our pattern will be aligned with other layers
|
||||
// align_to_grid will not work correctly with positive pattern_shift.
|
||||
coord_t pattern_shift_scaled = pattern_shift % line_spacing;
|
||||
refpt.x() -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled);
|
||||
bounding_box.merge(Slic3r::align_to_grid(bounding_box.min, Point(line_spacing, line_spacing), refpt));
|
||||
|
||||
// Intersect a set of euqally spaced vertical lines wiht expolygon.
|
||||
// n_vlines = ceil(bbox_width / line_spacing)
|
||||
const size_t n_vlines = (bounding_box.max.x() - bounding_box.min.x() + line_spacing - 1) / line_spacing;
|
||||
const double cos_a = cos(angle);
|
||||
const double sin_a = sin(angle);
|
||||
for (const SegmentedIntersectionLine &vline : slice_region_by_vertical_lines(poly_with_offset, n_vlines, bounding_box.min.x(), line_spacing))
|
||||
if (vline.pos >= x_min) {
|
||||
if (vline.pos > x_max)
|
||||
break;
|
||||
for (auto it = vline.intersections.begin(); it != vline.intersections.end();) {
|
||||
auto it_low = it ++;
|
||||
assert(it_low->type == SegmentIntersection::OUTER_LOW);
|
||||
if (it_low->type != SegmentIntersection::OUTER_LOW)
|
||||
continue;
|
||||
auto it_high = it;
|
||||
assert(it_high->type == SegmentIntersection::OUTER_HIGH);
|
||||
if (it_high->type == SegmentIntersection::OUTER_HIGH) {
|
||||
if (angle == 0.)
|
||||
fill_lines.emplace_back(Point(vline.pos, it_low->pos()), Point(vline.pos, it_high->pos()));
|
||||
else
|
||||
fill_lines.emplace_back(Point(vline.pos, it_low->pos()).rotated(cos_a, sin_a), Point(vline.pos, it_high->pos()).rotated(cos_a, sin_a));
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FillRectilinear::fill_surface_by_multilines(const Surface *surface, FillParams params, const std::initializer_list<SweepParams> &sweep_params, Polylines &polylines_out)
|
||||
{
|
||||
assert(sweep_params.size() > 1);
|
||||
@ -2843,42 +2940,8 @@ bool FillRectilinear::fill_surface_by_multilines(const Surface *surface, FillPar
|
||||
std::pair<float, Point> rotate_vector = this->_infill_direction(surface);
|
||||
for (const SweepParams &sweep : sweep_params) {
|
||||
// Rotate polygons so that we can work with vertical lines here
|
||||
double angle = rotate_vector.first + sweep.angle_base;
|
||||
ExPolygonWithOffset poly_with_offset(poly_with_offset_base, - angle);
|
||||
BoundingBox bounding_box = poly_with_offset.bounding_box_src();
|
||||
// Don't produce infill lines, which fully overlap with the infill perimeter.
|
||||
coord_t x_min = bounding_box.min.x() + line_width + coord_t(SCALED_EPSILON);
|
||||
coord_t x_max = bounding_box.max.x() - line_width - coord_t(SCALED_EPSILON);
|
||||
// extend bounding box so that our pattern will be aligned with other layers
|
||||
// Transform the reference point to the rotated coordinate system.
|
||||
Point refpt = rotate_vector.second.rotated(- angle);
|
||||
// _align_to_grid will not work correctly with positive pattern_shift.
|
||||
coord_t pattern_shift_scaled = coord_t(scale_(sweep.pattern_shift)) % line_spacing;
|
||||
refpt.x() -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled);
|
||||
bounding_box.merge(_align_to_grid(bounding_box.min, Point(line_spacing, line_spacing), refpt));
|
||||
|
||||
// Intersect a set of euqally spaced vertical lines wiht expolygon.
|
||||
// n_vlines = ceil(bbox_width / line_spacing)
|
||||
const size_t n_vlines = (bounding_box.max.x() - bounding_box.min.x() + line_spacing - 1) / line_spacing;
|
||||
const double cos_a = cos(angle);
|
||||
const double sin_a = sin(angle);
|
||||
for (const SegmentedIntersectionLine &vline : slice_region_by_vertical_lines(poly_with_offset, n_vlines, bounding_box.min.x(), line_spacing))
|
||||
if (vline.pos > x_min) {
|
||||
if (vline.pos >= x_max)
|
||||
break;
|
||||
for (auto it = vline.intersections.begin(); it != vline.intersections.end();) {
|
||||
auto it_low = it ++;
|
||||
assert(it_low->type == SegmentIntersection::OUTER_LOW);
|
||||
if (it_low->type != SegmentIntersection::OUTER_LOW)
|
||||
continue;
|
||||
auto it_high = it;
|
||||
assert(it_high->type == SegmentIntersection::OUTER_HIGH);
|
||||
if (it_high->type == SegmentIntersection::OUTER_HIGH) {
|
||||
fill_lines.emplace_back(Point(vline.pos, it_low->pos()).rotated(cos_a, sin_a), Point(vline.pos, it_high->pos()).rotated(cos_a, sin_a));
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
}
|
||||
float angle = rotate_vector.first + sweep.angle_base;
|
||||
make_fill_lines(ExPolygonWithOffset(poly_with_offset_base, - angle), rotate_vector.second.rotated(-angle), angle, line_width + coord_t(SCALED_EPSILON), line_spacing, coord_t(scale_(sweep.pattern_shift)), fill_lines);
|
||||
}
|
||||
|
||||
if (params.dont_connect() || fill_lines.size() <= 1) {
|
||||
@ -2954,4 +3017,29 @@ Polylines FillCubic::fill_surface(const Surface *surface, const FillParams ¶
|
||||
return polylines_out;
|
||||
}
|
||||
|
||||
Polylines FillSupportBase::fill_surface(const Surface *surface, const FillParams ¶ms)
|
||||
{
|
||||
assert(! params.full_infill());
|
||||
|
||||
Polylines polylines_out;
|
||||
std::pair<float, Point> rotate_vector = this->_infill_direction(surface);
|
||||
ExPolygonWithOffset poly_with_offset(surface->expolygon, - rotate_vector.first, float(scale_(this->overlap - 0.5 * this->spacing)));
|
||||
if (poly_with_offset.n_contours > 0) {
|
||||
Polylines fill_lines;
|
||||
coord_t line_spacing = coord_t(scale_(this->spacing) / params.density);
|
||||
// Create infill lines, keep them vertical.
|
||||
make_fill_lines(poly_with_offset, rotate_vector.second.rotated(- rotate_vector.first), 0, 0, line_spacing, 0, fill_lines);
|
||||
// Both the poly_with_offset and polylines_out are rotated, so the infill lines are strictly vertical.
|
||||
connect_base_support(std::move(fill_lines), poly_with_offset.polygons_outer, poly_with_offset.bounding_box_outer(), polylines_out, this->spacing, params);
|
||||
// Rotate back by rotate_vector.first
|
||||
const double cos_a = cos(rotate_vector.first);
|
||||
const double sin_a = sin(rotate_vector.first);
|
||||
for (Polyline &pl : polylines_out)
|
||||
for (Point &pt : pl.points)
|
||||
pt.rotate(cos_a, sin_a);
|
||||
}
|
||||
return polylines_out;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
|
@ -97,6 +97,17 @@ protected:
|
||||
float _layer_angle(size_t idx) const override { return 0.f; }
|
||||
};
|
||||
|
||||
class FillSupportBase : public FillRectilinear
|
||||
{
|
||||
public:
|
||||
Fill* clone() const override { return new FillSupportBase(*this); }
|
||||
~FillSupportBase() override = default;
|
||||
Polylines fill_surface(const Surface *surface, const FillParams ¶ms) override;
|
||||
|
||||
protected:
|
||||
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
|
||||
float _layer_angle(size_t idx) const override { return 0.f; }
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
|
@ -122,20 +122,13 @@ double Flow::extrusion_width(const std::string& opt_key, const ConfigOptionResol
|
||||
|
||||
// This constructor builds a Flow object from an extrusion width config setting
|
||||
// and other context properties.
|
||||
Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height, float bridge_flow_ratio)
|
||||
Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height)
|
||||
{
|
||||
// we need layer height unless it's a bridge
|
||||
if (height <= 0 && bridge_flow_ratio == 0)
|
||||
if (height <= 0)
|
||||
throw Slic3r::InvalidArgument("Invalid flow height supplied to new_from_config_width()");
|
||||
|
||||
float w;
|
||||
if (bridge_flow_ratio > 0) {
|
||||
// If bridge flow was requested, calculate the bridge width.
|
||||
height = w = (bridge_flow_ratio == 1.) ?
|
||||
// optimization to avoid sqrt()
|
||||
nozzle_diameter :
|
||||
sqrt(bridge_flow_ratio) * nozzle_diameter;
|
||||
} else if (! width.percent && width.value == 0.) {
|
||||
if (! width.percent && width.value == 0.) {
|
||||
// If user left option to 0, calculate a sane default width.
|
||||
w = auto_extrusion_width(role, nozzle_diameter);
|
||||
} else {
|
||||
@ -143,71 +136,89 @@ Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent
|
||||
w = float(width.get_abs_value(height));
|
||||
}
|
||||
|
||||
return Flow(w, height, nozzle_diameter, bridge_flow_ratio > 0);
|
||||
return Flow(w, height, rounded_rectangle_extrusion_spacing(w, height), nozzle_diameter, false);
|
||||
}
|
||||
|
||||
// This constructor builds a Flow object from a given centerline spacing.
|
||||
Flow Flow::new_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge)
|
||||
// Adjust extrusion flow for new extrusion line spacing, maintaining the old spacing between extrusions.
|
||||
Flow Flow::with_spacing(float new_spacing) const
|
||||
{
|
||||
// we need layer height unless it's a bridge
|
||||
if (height <= 0 && !bridge)
|
||||
throw Slic3r::InvalidArgument("Invalid flow height supplied to new_from_spacing()");
|
||||
// Calculate width from spacing.
|
||||
// For normal extrusons, extrusion width is wider than the spacing due to the rounding and squishing of the extrusions.
|
||||
// For bridge extrusions, the extrusions are placed with a tiny BRIDGE_EXTRA_SPACING gaps between the threads.
|
||||
float width = float(bridge ?
|
||||
(spacing - BRIDGE_EXTRA_SPACING) :
|
||||
#ifdef HAS_PERIMETER_LINE_OVERLAP
|
||||
(spacing + PERIMETER_LINE_OVERLAP_FACTOR * height * (1. - 0.25 * PI));
|
||||
#else
|
||||
(spacing + height * (1. - 0.25 * PI)));
|
||||
#endif
|
||||
return Flow(width, bridge ? width : height, nozzle_diameter, bridge);
|
||||
Flow out = *this;
|
||||
if (m_bridge) {
|
||||
// Diameter of the rounded extrusion.
|
||||
assert(m_width == m_height);
|
||||
float gap = m_spacing - m_width;
|
||||
auto new_diameter = new_spacing - gap;
|
||||
out.m_width = out.m_height = new_diameter;
|
||||
} else {
|
||||
assert(m_width >= m_height);
|
||||
out.m_width += new_spacing - m_spacing;
|
||||
if (out.m_width < out.m_height)
|
||||
throw Slic3r::InvalidArgument("Invalid spacing supplied to Flow::with_spacing()");
|
||||
}
|
||||
out.m_spacing = new_spacing;
|
||||
return out;
|
||||
}
|
||||
|
||||
// This method returns the centerline spacing between two adjacent extrusions
|
||||
// having the same extrusion width (and other properties).
|
||||
float Flow::spacing() const
|
||||
// Adjust the width / height of a rounded extrusion model to reach the prescribed cross section area while maintaining extrusion spacing.
|
||||
Flow Flow::with_cross_section(float area_new) const
|
||||
{
|
||||
#ifdef HAS_PERIMETER_LINE_OVERLAP
|
||||
if (this->bridge)
|
||||
return this->width + BRIDGE_EXTRA_SPACING;
|
||||
// rectangle with semicircles at the ends
|
||||
float min_flow_spacing = this->width - this->height * (1. - 0.25 * PI);
|
||||
float res = this->width - PERIMETER_LINE_OVERLAP_FACTOR * (this->width - min_flow_spacing);
|
||||
#else
|
||||
float res = float(this->bridge ? (this->width + BRIDGE_EXTRA_SPACING) : (this->width - this->height * (1. - 0.25 * PI)));
|
||||
#endif
|
||||
// assert(res > 0.f);
|
||||
if (res <= 0.f)
|
||||
throw FlowErrorNegativeSpacing();
|
||||
return res;
|
||||
assert(! m_bridge);
|
||||
assert(m_width >= m_height);
|
||||
|
||||
// Adjust for bridge_flow_ratio, maintain the extrusion spacing.
|
||||
float area = this->mm3_per_mm();
|
||||
if (area_new > area + EPSILON) {
|
||||
// Increasing the flow rate.
|
||||
float new_full_spacing = area_new / m_height;
|
||||
if (new_full_spacing > m_spacing) {
|
||||
// Filling up the spacing without an air gap. Grow the extrusion in height.
|
||||
float height = area_new / m_spacing;
|
||||
return Flow(rounded_rectangle_extrusion_width_from_spacing(m_spacing, height), height, m_spacing, m_nozzle_diameter, false);
|
||||
} else {
|
||||
return this->with_width(rounded_rectangle_extrusion_width_from_spacing(area / m_height, m_height));
|
||||
}
|
||||
} else if (area_new < area - EPSILON) {
|
||||
// Decreasing the flow rate.
|
||||
float width_new = m_width - (area - area_new) / m_height;
|
||||
assert(width_new > 0);
|
||||
if (width_new > m_height) {
|
||||
// Shrink the extrusion width.
|
||||
return this->with_width(width_new);
|
||||
} else {
|
||||
// Create a rounded extrusion.
|
||||
auto dmr = float(sqrt(area_new / M_PI));
|
||||
return Flow(dmr, dmr, m_spacing, m_nozzle_diameter, false);
|
||||
}
|
||||
} else
|
||||
return *this;
|
||||
}
|
||||
|
||||
// This method returns the centerline spacing between an extrusion using this
|
||||
// flow and another one using another flow.
|
||||
// this->spacing(other) shall return the same value as other.spacing(*this)
|
||||
float Flow::spacing(const Flow &other) const
|
||||
float Flow::rounded_rectangle_extrusion_spacing(float width, float height)
|
||||
{
|
||||
assert(this->height == other.height);
|
||||
assert(this->bridge == other.bridge);
|
||||
float res = float(this->bridge ?
|
||||
0.5 * this->width + 0.5 * other.width + BRIDGE_EXTRA_SPACING :
|
||||
0.5 * this->spacing() + 0.5 * other.spacing());
|
||||
// assert(res > 0.f);
|
||||
if (res <= 0.f)
|
||||
throw FlowErrorNegativeSpacing();
|
||||
return res;
|
||||
auto out = width - height * float(1. - 0.25 * PI);
|
||||
if (out <= 0.f)
|
||||
throw FlowErrorNegativeSpacing();
|
||||
return out;
|
||||
}
|
||||
|
||||
float Flow::rounded_rectangle_extrusion_width_from_spacing(float spacing, float height)
|
||||
{
|
||||
return float(spacing + height * (1. - 0.25 * PI));
|
||||
}
|
||||
|
||||
float Flow::bridge_extrusion_spacing(float dmr)
|
||||
{
|
||||
return dmr + BRIDGE_EXTRA_SPACING;
|
||||
}
|
||||
|
||||
// This method returns extrusion volume per head move unit.
|
||||
double Flow::mm3_per_mm() const
|
||||
{
|
||||
float res = this->bridge ?
|
||||
float res = m_bridge ?
|
||||
// Area of a circle with dmr of this->width.
|
||||
float((this->width * this->width) * 0.25 * PI) :
|
||||
float((m_width * m_width) * 0.25 * PI) :
|
||||
// Rectangle with semicircles at the ends. ~ h (w - 0.215 h)
|
||||
float(this->height * (this->width - this->height * (1. - 0.25 * PI)));
|
||||
float(m_height * (m_width - m_height * (1. - 0.25 * PI)));
|
||||
//assert(res > 0.);
|
||||
if (res <= 0.)
|
||||
throw FlowErrorNegativeFlow();
|
||||
@ -222,9 +233,7 @@ Flow support_material_flow(const PrintObject *object, float layer_height)
|
||||
(object->config().support_material_extrusion_width.value > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width,
|
||||
// if object->config().support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
|
||||
float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_extruder-1)),
|
||||
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value),
|
||||
// bridge_flow_ratio
|
||||
0.f);
|
||||
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value));
|
||||
}
|
||||
|
||||
Flow support_material_1st_layer_flow(const PrintObject *object, float layer_height)
|
||||
@ -235,9 +244,7 @@ Flow support_material_1st_layer_flow(const PrintObject *object, float layer_heig
|
||||
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
|
||||
(width.value > 0) ? width : object->config().extrusion_width,
|
||||
float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_extruder-1)),
|
||||
(layer_height > 0.f) ? layer_height : float(object->config().first_layer_height.get_abs_value(object->config().layer_height.value)),
|
||||
// bridge_flow_ratio
|
||||
0.f);
|
||||
(layer_height > 0.f) ? layer_height : float(object->config().first_layer_height.get_abs_value(object->config().layer_height.value)));
|
||||
}
|
||||
|
||||
Flow support_material_interface_flow(const PrintObject *object, float layer_height)
|
||||
@ -248,9 +255,7 @@ Flow support_material_interface_flow(const PrintObject *object, float layer_heig
|
||||
(object->config().support_material_extrusion_width > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width,
|
||||
// if object->config().support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
|
||||
float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_interface_extruder-1)),
|
||||
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value),
|
||||
// bridge_flow_ratio
|
||||
0.f);
|
||||
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,11 +13,6 @@ class PrintObject;
|
||||
// Extra spacing of bridge threads, in mm.
|
||||
#define BRIDGE_EXTRA_SPACING 0.05
|
||||
|
||||
// Overlap factor of perimeter lines. Currently no overlap.
|
||||
#ifdef HAS_PERIMETER_LINE_OVERLAP
|
||||
#define PERIMETER_LINE_OVERLAP_FACTOR 1.0
|
||||
#endif
|
||||
|
||||
enum FlowRole {
|
||||
frExternalPerimeter,
|
||||
frPerimeter,
|
||||
@ -56,26 +51,26 @@ public:
|
||||
class Flow
|
||||
{
|
||||
public:
|
||||
Flow() = default;
|
||||
Flow(float width, float height, float nozzle_diameter) :
|
||||
Flow(width, height, rounded_rectangle_extrusion_spacing(width, height), nozzle_diameter, false) {}
|
||||
|
||||
// Non bridging flow: Maximum width of an extrusion with semicircles at the ends.
|
||||
// Bridging flow: Bridge thread diameter.
|
||||
float width;
|
||||
float width() const { return m_width; }
|
||||
coord_t scaled_width() const { return coord_t(scale_(m_width)); }
|
||||
// Non bridging flow: Layer height.
|
||||
// Bridging flow: Bridge thread diameter = layer height.
|
||||
float height;
|
||||
float height() const { return m_height; }
|
||||
// Spacing between the extrusion centerlines.
|
||||
float spacing() const { return m_spacing; }
|
||||
coord_t scaled_spacing() const { return coord_t(scale_(m_spacing)); }
|
||||
// Nozzle diameter.
|
||||
float nozzle_diameter;
|
||||
float nozzle_diameter() const { return m_nozzle_diameter; }
|
||||
// Is it a bridge?
|
||||
bool bridge;
|
||||
|
||||
Flow(float _w, float _h, float _nd, bool _bridge = false) :
|
||||
width(_w), height(_h), nozzle_diameter(_nd), bridge(_bridge) {}
|
||||
|
||||
float spacing() const;
|
||||
float spacing(const Flow &other) const;
|
||||
double mm3_per_mm() const;
|
||||
coord_t scaled_width() const { return coord_t(scale_(this->width)); }
|
||||
coord_t scaled_spacing() const { return coord_t(scale_(this->spacing())); }
|
||||
coord_t scaled_spacing(const Flow &other) const { return coord_t(scale_(this->spacing(other))); }
|
||||
bool bridge() const { return m_bridge; }
|
||||
// Cross section area of the extrusion.
|
||||
double mm3_per_mm() const;
|
||||
|
||||
// Elephant foot compensation spacing to be used to detect narrow parts, where the elephant foot compensation cannot be applied.
|
||||
// To be used on frExternalPerimeter only.
|
||||
@ -83,13 +78,32 @@ public:
|
||||
// Here an overlap of 0.2x external perimeter spacing is allowed for by the elephant foot compensation.
|
||||
coord_t scaled_elephant_foot_spacing() const { return coord_t(0.5f * float(this->scaled_width() + 0.6f * this->scaled_spacing())); }
|
||||
|
||||
bool operator==(const Flow &rhs) const { return this->width == rhs.width && this->height == rhs.height && this->nozzle_diameter == rhs.nozzle_diameter && this->bridge == rhs.bridge; }
|
||||
bool operator==(const Flow &rhs) const { return m_width == rhs.m_width && m_height == rhs.m_height && m_nozzle_diameter == rhs.m_nozzle_diameter && m_bridge == rhs.m_bridge; }
|
||||
|
||||
static Flow new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height, float bridge_flow_ratio);
|
||||
// Create a flow from the spacing of extrusion lines.
|
||||
// This method is used exclusively to calculate new flow of 100% infill, where the extrusion width was allowed to scale
|
||||
// to fit a region with integer number of lines.
|
||||
static Flow new_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge);
|
||||
Flow with_width (float width) const {
|
||||
assert(! m_bridge);
|
||||
return Flow(width, m_height, rounded_rectangle_extrusion_spacing(width, m_height), m_nozzle_diameter, m_bridge);
|
||||
}
|
||||
Flow with_height(float height) const {
|
||||
assert(! m_bridge);
|
||||
return Flow(m_width, height, rounded_rectangle_extrusion_spacing(m_width, height), m_nozzle_diameter, m_bridge);
|
||||
}
|
||||
// Adjust extrusion flow for new extrusion line spacing, maintaining the old spacing between extrusions.
|
||||
Flow with_spacing(float spacing) const;
|
||||
// Adjust the width / height of a rounded extrusion model to reach the prescribed cross section area while maintaining extrusion spacing.
|
||||
Flow with_cross_section(float area) const;
|
||||
Flow with_flow_ratio(double ratio) const { return this->with_cross_section(this->mm3_per_mm() * ratio); }
|
||||
|
||||
static Flow bridging_flow(float dmr, float nozzle_diameter) { return Flow { dmr, dmr, bridge_extrusion_spacing(dmr), nozzle_diameter, true }; }
|
||||
|
||||
static Flow new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height);
|
||||
|
||||
// Spacing of extrusions with rounded extrusion model.
|
||||
static float rounded_rectangle_extrusion_spacing(float width, float height);
|
||||
// Width of extrusions with rounded extrusion model.
|
||||
static float rounded_rectangle_extrusion_width_from_spacing(float spacing, float height);
|
||||
// Spacing of round thread extrusions.
|
||||
static float bridge_extrusion_spacing(float dmr);
|
||||
|
||||
// Sane extrusion width defautl based on nozzle diameter.
|
||||
// The defaults were derived from manual Prusa MK3 profiles.
|
||||
@ -100,6 +114,20 @@ public:
|
||||
// on active extruder etc. Therefore the value calculated by this function shall be used as a hint only.
|
||||
static double extrusion_width(const std::string &opt_key, const ConfigOptionFloatOrPercent *opt, const ConfigOptionResolver &config, const unsigned int first_printing_extruder = 0);
|
||||
static double extrusion_width(const std::string &opt_key, const ConfigOptionResolver &config, const unsigned int first_printing_extruder = 0);
|
||||
|
||||
private:
|
||||
Flow(float width, float height, float spacing, float nozzle_diameter, bool bridge) :
|
||||
m_width(width), m_height(height), m_spacing(spacing), m_nozzle_diameter(nozzle_diameter), m_bridge(bridge)
|
||||
{
|
||||
// Gap fill violates this condition.
|
||||
//assert(width >= height);
|
||||
}
|
||||
|
||||
float m_width { 0 };
|
||||
float m_height { 0 };
|
||||
float m_spacing { 0 };
|
||||
float m_nozzle_diameter { 0 };
|
||||
bool m_bridge { false };
|
||||
};
|
||||
|
||||
extern Flow support_material_flow(const PrintObject *object, float layer_height = 0.f);
|
||||
|
@ -2014,9 +2014,10 @@ namespace Slic3r {
|
||||
typedef std::map<int, ObjectData> IdToObjectDataMap;
|
||||
|
||||
bool m_fullpath_sources{ true };
|
||||
bool m_zip64 { true };
|
||||
|
||||
public:
|
||||
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data = nullptr);
|
||||
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data, bool zip64);
|
||||
|
||||
private:
|
||||
bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data);
|
||||
@ -2036,10 +2037,11 @@ namespace Slic3r {
|
||||
bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model, const DynamicPrintConfig* config);
|
||||
};
|
||||
|
||||
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data)
|
||||
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data, bool zip64)
|
||||
{
|
||||
clear_errors();
|
||||
m_fullpath_sources = fullpath_sources;
|
||||
m_zip64 = zip64;
|
||||
return _save_model_to_file(filename, model, config, thumbnail_data);
|
||||
}
|
||||
|
||||
@ -2233,9 +2235,13 @@ namespace Slic3r {
|
||||
{
|
||||
mz_zip_writer_staged_context context;
|
||||
if (!mz_zip_writer_add_staged_open(&archive, &context, MODEL_FILE.c_str(),
|
||||
// Maximum expected and allowed 3MF file size is 16GiB.
|
||||
// This switches the ZIP file to a 64bit mode, which adds a tiny bit of overhead to file records.
|
||||
(uint64_t(1) << 30) * 16,
|
||||
m_zip64 ?
|
||||
// Maximum expected and allowed 3MF file size is 16GiB.
|
||||
// This switches the ZIP file to a 64bit mode, which adds a tiny bit of overhead to file records.
|
||||
(uint64_t(1) << 30) * 16 :
|
||||
// Maximum expected 3MF file size is 4GB-1. This is a workaround for interoperability with Windows 10 3D model fixing API, see
|
||||
// GH issue #6193.
|
||||
(uint64_t(1) << 32) - 1,
|
||||
nullptr, nullptr, 0, MZ_DEFAULT_COMPRESSION, nullptr, 0, nullptr, 0)) {
|
||||
add_error("Unable to add model file to archive");
|
||||
return false;
|
||||
@ -2926,13 +2932,13 @@ bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool c
|
||||
return res;
|
||||
}
|
||||
|
||||
bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data)
|
||||
bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data, bool zip64)
|
||||
{
|
||||
if (path == nullptr || model == nullptr)
|
||||
return false;
|
||||
|
||||
_3MF_Exporter exporter;
|
||||
bool res = exporter.save_model_to_file(path, *model, config, fullpath_sources, thumbnail_data);
|
||||
bool res = exporter.save_model_to_file(path, *model, config, fullpath_sources, thumbnail_data, zip64);
|
||||
if (!res)
|
||||
exporter.log_errors();
|
||||
|
||||
|
@ -33,7 +33,7 @@ namespace Slic3r {
|
||||
|
||||
// Save the given model and the config data contained in the given Print into a 3mf file.
|
||||
// The model could be modified during the export process if meshes are not repaired or have no shared vertices
|
||||
extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data = nullptr);
|
||||
extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data = nullptr, bool zip64 = true);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
|
@ -87,7 +87,7 @@ PNGBuffer read_png(const mz_zip_archive_file_stat &entry,
|
||||
}
|
||||
|
||||
ArchiveData extract_sla_archive(const std::string &zipfname,
|
||||
const std::string &exclude)
|
||||
const std::string &exclude)
|
||||
{
|
||||
ArchiveData arch;
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <chrono>
|
||||
#include <math.h>
|
||||
#include <string_view>
|
||||
|
||||
@ -285,6 +286,7 @@ namespace Slic3r {
|
||||
config.set_key_value("next_extruder", new ConfigOptionInt((int)new_extruder_id));
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(tcr.print_z));
|
||||
config.set_key_value("toolchange_z", new ConfigOptionFloat(z));
|
||||
// config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
||||
toolchange_gcode_str = gcodegen.placeholder_parser_process("toolchange_gcode", toolchange_gcode, new_extruder_id, &config);
|
||||
check_add_eol(toolchange_gcode_str);
|
||||
@ -433,19 +435,18 @@ namespace Slic3r {
|
||||
{
|
||||
std::string gcode;
|
||||
assert(m_layer_idx >= 0);
|
||||
if (!m_brim_done || gcodegen.writer().need_toolchange(extruder_id) || finish_layer) {
|
||||
if (gcodegen.writer().need_toolchange(extruder_id) || finish_layer) {
|
||||
if (m_layer_idx < (int)m_tool_changes.size()) {
|
||||
if (!(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size()))
|
||||
throw Slic3r::RuntimeError("Wipe tower generation failed, possibly due to empty first layer.");
|
||||
|
||||
|
||||
// Calculate where the wipe tower layer will be printed. -1 means that print z will not change,
|
||||
// resulting in a wipe tower with sparse layers.
|
||||
double wipe_tower_z = -1;
|
||||
bool ignore_sparse = false;
|
||||
if (gcodegen.config().wipe_tower_no_sparse_layers.value) {
|
||||
wipe_tower_z = m_last_wipe_tower_print_z;
|
||||
ignore_sparse = (m_brim_done && m_tool_changes[m_layer_idx].size() == 1 && m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool);
|
||||
ignore_sparse = (m_tool_changes[m_layer_idx].size() == 1 && m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool);
|
||||
if (m_tool_change_idx == 0 && !ignore_sparse)
|
||||
wipe_tower_z = m_last_wipe_tower_print_z + m_tool_changes[m_layer_idx].front().layer_height;
|
||||
}
|
||||
@ -455,7 +456,6 @@ namespace Slic3r {
|
||||
m_last_wipe_tower_print_z = wipe_tower_z;
|
||||
}
|
||||
}
|
||||
m_brim_done = true;
|
||||
}
|
||||
return gcode;
|
||||
}
|
||||
@ -755,8 +755,16 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re
|
||||
BOOST_LOG_TRIVIAL(debug) << "Start processing gcode, " << log_memory_info();
|
||||
m_processor.process_file(path_tmp, true, [print]() { print->throw_if_canceled(); });
|
||||
DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics);
|
||||
#if ENABLE_GCODE_WINDOW
|
||||
if (result != nullptr) {
|
||||
*result = std::move(m_processor.extract_result());
|
||||
// set the filename to the correct value
|
||||
result->filename = path;
|
||||
}
|
||||
#else
|
||||
if (result != nullptr)
|
||||
*result = std::move(m_processor.extract_result());
|
||||
#endif // ENABLE_GCODE_WINDOW
|
||||
BOOST_LOG_TRIVIAL(debug) << "Finished processing gcode, " << log_memory_info();
|
||||
|
||||
if (rename_file(path_tmp, path))
|
||||
@ -776,7 +784,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re
|
||||
namespace DoExport {
|
||||
static void init_gcode_processor(const PrintConfig& config, GCodeProcessor& processor, bool& silent_time_estimator_enabled)
|
||||
{
|
||||
silent_time_estimator_enabled = (config.gcode_flavor == gcfMarlin) && config.silent_mode;
|
||||
silent_time_estimator_enabled = (config.gcode_flavor == gcfMarlinLegacy || config.gcode_flavor == gcfMarlinFirmware)
|
||||
&& config.silent_mode;
|
||||
processor.reset();
|
||||
processor.apply_config(config);
|
||||
processor.enable_stealth_time_estimator(silent_time_estimator_enabled);
|
||||
@ -1104,15 +1113,15 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
||||
const double layer_height = first_object->config().layer_height.value;
|
||||
const double first_layer_height = first_object->config().first_layer_height.get_abs_value(layer_height);
|
||||
for (const PrintRegion* region : print.regions()) {
|
||||
_write_format(file, "; external perimeters extrusion width = %.2fmm\n", region->flow(frExternalPerimeter, layer_height, false, false, -1., *first_object).width);
|
||||
_write_format(file, "; perimeters extrusion width = %.2fmm\n", region->flow(frPerimeter, layer_height, false, false, -1., *first_object).width);
|
||||
_write_format(file, "; infill extrusion width = %.2fmm\n", region->flow(frInfill, layer_height, false, false, -1., *first_object).width);
|
||||
_write_format(file, "; solid infill extrusion width = %.2fmm\n", region->flow(frSolidInfill, layer_height, false, false, -1., *first_object).width);
|
||||
_write_format(file, "; top infill extrusion width = %.2fmm\n", region->flow(frTopSolidInfill, layer_height, false, false, -1., *first_object).width);
|
||||
_write_format(file, "; external perimeters extrusion width = %.2fmm\n", region->flow(*first_object, frExternalPerimeter, layer_height).width());
|
||||
_write_format(file, "; perimeters extrusion width = %.2fmm\n", region->flow(*first_object, frPerimeter, layer_height).width());
|
||||
_write_format(file, "; infill extrusion width = %.2fmm\n", region->flow(*first_object, frInfill, layer_height).width());
|
||||
_write_format(file, "; solid infill extrusion width = %.2fmm\n", region->flow(*first_object, frSolidInfill, layer_height).width());
|
||||
_write_format(file, "; top infill extrusion width = %.2fmm\n", region->flow(*first_object, frTopSolidInfill, layer_height).width());
|
||||
if (print.has_support_material())
|
||||
_write_format(file, "; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width);
|
||||
_write_format(file, "; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width());
|
||||
if (print.config().first_layer_extrusion_width.value > 0)
|
||||
_write_format(file, "; first layer extrusion width = %.2fmm\n", region->flow(frPerimeter, first_layer_height, false, true, -1., *first_object).width);
|
||||
_write_format(file, "; first layer extrusion width = %.2fmm\n", region->flow(*first_object, frPerimeter, first_layer_height, true).width());
|
||||
_write_format(file, "\n");
|
||||
}
|
||||
print.throw_if_canceled();
|
||||
@ -1128,6 +1137,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
||||
// Prepare the helper object for replacing placeholders in custom G-code and output filename.
|
||||
m_placeholder_parser = print.placeholder_parser();
|
||||
m_placeholder_parser.update_timestamp();
|
||||
m_placeholder_parser_context.rng = std::mt19937(std::chrono::high_resolution_clock::now().time_since_epoch().count());
|
||||
print.update_object_placeholders(m_placeholder_parser.config_writable(), ".gcode");
|
||||
|
||||
// Get optimal tool ordering to minimize tool switches of a multi-exruder print.
|
||||
@ -1346,7 +1356,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
||||
bbox_prime.offset(0.5f);
|
||||
bool overlap = bbox_prime.overlap(bbox_print);
|
||||
|
||||
if (print.config().gcode_flavor == gcfMarlin) {
|
||||
if (print.config().gcode_flavor == gcfMarlinLegacy || print.config().gcode_flavor == gcfMarlinFirmware) {
|
||||
_write(file, this->retract());
|
||||
_write(file, "M300 S800 P500\n"); // Beep for 500ms, tone 800Hz.
|
||||
if (overlap) {
|
||||
@ -1549,7 +1559,8 @@ static bool custom_gcode_sets_temperature(const std::string &gcode, const int mc
|
||||
// Do not process this piece of G-code by the time estimator, it already knows the values through another sources.
|
||||
void GCode::print_machine_envelope(FILE *file, Print &print)
|
||||
{
|
||||
if (print.config().gcode_flavor.value == gcfMarlin && print.config().machine_limits_usage.value == MachineLimitsUsage::EmitToGCode) {
|
||||
if ((print.config().gcode_flavor.value == gcfMarlinLegacy || print.config().gcode_flavor.value == gcfMarlinFirmware)
|
||||
&& print.config().machine_limits_usage.value == MachineLimitsUsage::EmitToGCode) {
|
||||
fprintf(file, "M201 X%d Y%d Z%d E%d ; sets maximum accelerations, mm/sec^2\n",
|
||||
int(print.config().machine_max_acceleration_x.values.front() + 0.5),
|
||||
int(print.config().machine_max_acceleration_y.values.front() + 0.5),
|
||||
@ -1560,10 +1571,20 @@ void GCode::print_machine_envelope(FILE *file, Print &print)
|
||||
int(print.config().machine_max_feedrate_y.values.front() + 0.5),
|
||||
int(print.config().machine_max_feedrate_z.values.front() + 0.5),
|
||||
int(print.config().machine_max_feedrate_e.values.front() + 0.5));
|
||||
|
||||
// Now M204 - acceleration. This one is quite hairy thanks to how Marlin guys care about
|
||||
// backwards compatibility: https://github.com/prusa3d/PrusaSlicer/issues/1089
|
||||
// Legacy Marlin should export travel acceleration the same as printing acceleration.
|
||||
// MarlinFirmware has the two separated.
|
||||
int travel_acc = print.config().gcode_flavor == gcfMarlinLegacy
|
||||
? int(print.config().machine_max_acceleration_extruding.values.front() + 0.5)
|
||||
: int(print.config().machine_max_acceleration_travel.values.front() + 0.5);
|
||||
fprintf(file, "M204 P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n",
|
||||
int(print.config().machine_max_acceleration_extruding.values.front() + 0.5),
|
||||
int(print.config().machine_max_acceleration_retracting.values.front() + 0.5),
|
||||
int(print.config().machine_max_acceleration_extruding.values.front() + 0.5));
|
||||
travel_acc);
|
||||
|
||||
|
||||
fprintf(file, "M205 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/sec\n",
|
||||
print.config().machine_max_jerk_x.values.front(),
|
||||
print.config().machine_max_jerk_y.values.front(),
|
||||
@ -1705,7 +1726,9 @@ namespace ProcessLayer
|
||||
{
|
||||
|
||||
static std::string emit_custom_gcode_per_print_z(
|
||||
GCode &gcodegen,
|
||||
const CustomGCode::Item *custom_gcode,
|
||||
unsigned int current_extruder_id,
|
||||
// ID of the first extruder printing this layer.
|
||||
unsigned int first_extruder_id,
|
||||
const PrintConfig &config)
|
||||
@ -1746,13 +1769,19 @@ namespace ProcessLayer
|
||||
// && !MMU1
|
||||
) {
|
||||
//! FIXME_in_fw show message during print pause
|
||||
gcode += config.pause_print_gcode;// pause print
|
||||
DynamicConfig cfg;
|
||||
cfg.set_key_value("color_change_extruder", new ConfigOptionInt(m600_extruder_before_layer));
|
||||
gcode += gcodegen.placeholder_parser_process("pause_print_gcode", config.pause_print_gcode, current_extruder_id, &cfg);
|
||||
gcode += "\n";
|
||||
gcode += "M117 Change filament for Extruder " + std::to_string(m600_extruder_before_layer) + "\n";
|
||||
}
|
||||
else {
|
||||
gcode += config.color_change_gcode;//ColorChangeCode;
|
||||
gcode += gcodegen.placeholder_parser_process("color_change_gcode", config.color_change_gcode, current_extruder_id);
|
||||
gcode += "\n";
|
||||
//FIXME Tell G-code writer that M600 filled the extruder, thus the G-code writer shall reset the extruder to unretracted state after
|
||||
// return from M600. Thus the G-code generated by the following line is ignored.
|
||||
// see GH issue #6362
|
||||
gcodegen.writer().unretract();
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -1767,7 +1796,7 @@ namespace ProcessLayer
|
||||
//! FIXME_in_fw show message during print pause
|
||||
if (!pause_print_msg.empty())
|
||||
gcode += "M117 " + pause_print_msg + "\n";
|
||||
gcode += config.pause_print_gcode;
|
||||
gcode += gcodegen.placeholder_parser_process("pause_print_gcode", config.pause_print_gcode, current_extruder_id);
|
||||
}
|
||||
else {
|
||||
// add tag for processor
|
||||
@ -1776,8 +1805,8 @@ namespace ProcessLayer
|
||||
#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;
|
||||
if (gcode_type == CustomGCode::Template) // Template Custom Gcode
|
||||
gcode += gcodegen.placeholder_parser_process("template_custom_gcode", config.template_custom_gcode, current_extruder_id);
|
||||
else // custom Gcode
|
||||
gcode += custom_gcode->extra;
|
||||
|
||||
@ -1810,7 +1839,8 @@ namespace Skirt {
|
||||
// Extrude skirt at the print_z of the raft layers and normal object layers
|
||||
// not at the print_z of the interlaced support material layers.
|
||||
std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder_out;
|
||||
assert(skirt_done.empty());
|
||||
//For sequential print, the following test may fail when extruding the 2nd and other objects.
|
||||
// assert(skirt_done.empty());
|
||||
if (skirt_done.empty() && print.has_skirt() && ! print.skirt().entities.empty() && layer_tools.has_skirt) {
|
||||
skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out);
|
||||
skirt_done.emplace_back(layer_tools.print_z);
|
||||
@ -1985,7 +2015,7 @@ void GCode::process_layer(
|
||||
|
||||
if (single_object_instance_idx == size_t(-1)) {
|
||||
// Normal (non-sequential) print.
|
||||
gcode += ProcessLayer::emit_custom_gcode_per_print_z(layer_tools.custom_gcode, first_extruder_id, print.config());
|
||||
gcode += ProcessLayer::emit_custom_gcode_per_print_z(*this, layer_tools.custom_gcode, m_writer.extruder()->id(), first_extruder_id, print.config());
|
||||
}
|
||||
// Extrude skirt at the print_z of the raft layers and normal object layers
|
||||
// not at the print_z of the interlaced support material layers.
|
||||
@ -2165,14 +2195,13 @@ void GCode::process_layer(
|
||||
const std::pair<size_t, size_t> loops = loops_it->second;
|
||||
this->set_origin(0., 0.);
|
||||
m_avoid_crossing_perimeters.use_external_mp();
|
||||
Flow layer_skirt_flow(print.skirt_flow());
|
||||
layer_skirt_flow.height = float(m_skirt_done.back() - (m_skirt_done.size() == 1 ? 0. : m_skirt_done[m_skirt_done.size() - 2]));
|
||||
Flow layer_skirt_flow = print.skirt_flow().with_height(float(m_skirt_done.back() - (m_skirt_done.size() == 1 ? 0. : m_skirt_done[m_skirt_done.size() - 2])));
|
||||
double mm3_per_mm = layer_skirt_flow.mm3_per_mm();
|
||||
for (size_t i = loops.first; i < loops.second; ++i) {
|
||||
// Adjust flow according to this layer's layer height.
|
||||
ExtrusionLoop loop = *dynamic_cast<const ExtrusionLoop*>(print.skirt().entities[i]);
|
||||
for (ExtrusionPath &path : loop.paths) {
|
||||
path.height = layer_skirt_flow.height;
|
||||
path.height = layer_skirt_flow.height();
|
||||
path.mm3_per_mm = mm3_per_mm;
|
||||
}
|
||||
//FIXME using the support_material_speed of the 1st object printed.
|
||||
@ -2838,9 +2867,11 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
|
||||
Polyline travel { this->last_pos(), point };
|
||||
|
||||
// check whether a straight travel move would need retraction
|
||||
bool needs_retraction = this->needs_retraction(travel, role);
|
||||
bool needs_retraction = this->needs_retraction(travel, role);
|
||||
// check whether wipe could be disabled without causing visible stringing
|
||||
bool could_be_wipe_disabled = false;
|
||||
bool could_be_wipe_disabled = false;
|
||||
// Save state of use_external_mp_once for the case that will be needed to call twice m_avoid_crossing_perimeters.travel_to.
|
||||
const bool used_external_mp_once = m_avoid_crossing_perimeters.used_external_mp_once();
|
||||
|
||||
// if a retraction would be needed, try to use avoid_crossing_perimeters to plan a
|
||||
// multi-hop travel path inside the configuration space
|
||||
@ -2868,8 +2899,13 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
|
||||
// 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, point);
|
||||
travel = std::move(retract_travel);
|
||||
// If in the previous call of m_avoid_crossing_perimeters.travel_to was use_external_mp_once set to true restore this value for next call.
|
||||
if (used_external_mp_once)
|
||||
m_avoid_crossing_perimeters.use_external_mp_once();
|
||||
travel = m_avoid_crossing_perimeters.travel_to(*this, point);
|
||||
// If state of use_external_mp_once was changed reset it to right value.
|
||||
if (used_external_mp_once)
|
||||
m_avoid_crossing_perimeters.reset_once_modifiers();
|
||||
}
|
||||
} else
|
||||
// Reset the wipe path when traveling, so one would not wipe along an old path.
|
||||
@ -2992,6 +3028,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
||||
config.set_key_value("next_extruder", new ConfigOptionInt((int)extruder_id));
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
|
||||
config.set_key_value("toolchange_z", new ConfigOptionFloat(print_z));
|
||||
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
||||
toolchange_gcode_parsed = placeholder_parser_process("toolchange_gcode", toolchange_gcode, extruder_id, &config);
|
||||
gcode += toolchange_gcode_parsed;
|
||||
|
@ -75,8 +75,8 @@ public:
|
||||
m_tool_changes(tool_changes),
|
||||
m_final_purge(final_purge),
|
||||
m_layer_idx(-1),
|
||||
m_tool_change_idx(0),
|
||||
m_brim_done(false) {}
|
||||
m_tool_change_idx(0)
|
||||
{}
|
||||
|
||||
std::string prime(GCode &gcodegen);
|
||||
void next_layer() { ++ m_layer_idx; m_tool_change_idx = 0; }
|
||||
@ -105,8 +105,6 @@ private:
|
||||
// Current layer index.
|
||||
int m_layer_idx;
|
||||
int m_tool_change_idx;
|
||||
bool m_brim_done;
|
||||
bool i_have_brim = false;
|
||||
double m_last_wipe_tower_print_z = 0.f;
|
||||
};
|
||||
|
||||
@ -373,7 +371,7 @@ private:
|
||||
void print_machine_envelope(FILE *file, Print &print);
|
||||
void _print_first_layer_bed_temperature(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
|
||||
void _print_first_layer_extruder_temperatures(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
|
||||
// this flag triggers first layer speeds
|
||||
// On the first printing layer. This flag triggers first layer speeds.
|
||||
bool on_first_layer() const { return m_layer != nullptr && m_layer->id() == 0; }
|
||||
|
||||
friend ObjectByExtruder& object_by_extruder(
|
||||
|
@ -18,6 +18,7 @@ public:
|
||||
// Routing around the objects vs. inside a single object.
|
||||
void use_external_mp(bool use = true) { m_use_external_mp = use; };
|
||||
void use_external_mp_once() { m_use_external_mp_once = true; }
|
||||
bool used_external_mp_once() { return m_use_external_mp_once; }
|
||||
void disable_once() { m_disabled_once = true; }
|
||||
bool disabled_once() const { return m_disabled_once; }
|
||||
void reset_once_modifiers() { m_use_external_mp_once = false; m_disabled_once = false; }
|
||||
|
@ -4,8 +4,14 @@
|
||||
#include "GCodeProcessor.hpp"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#if ENABLE_GCODE_WINDOW
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#endif // ENABLE_GCODE_WINDOW
|
||||
|
||||
#include <float.h>
|
||||
#include <assert.h>
|
||||
@ -20,6 +26,7 @@
|
||||
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
|
||||
static const float DEFAULT_TRAVEL_ACCELERATION = 1250.0f;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -184,8 +191,13 @@ void GCodeProcessor::TimeMachine::reset()
|
||||
enabled = false;
|
||||
acceleration = 0.0f;
|
||||
max_acceleration = 0.0f;
|
||||
travel_acceleration = 0.0f;
|
||||
max_travel_acceleration = 0.0f;
|
||||
extrude_factor_override_percentage = 1.0f;
|
||||
time = 0.0f;
|
||||
#if ENABLE_EXTENDED_M73_LINES
|
||||
stop_times = std::vector<StopTime>();
|
||||
#endif // ENABLE_EXTENDED_M73_LINES
|
||||
curr.reset();
|
||||
prev.reset();
|
||||
gcode_time.reset();
|
||||
@ -313,6 +325,13 @@ void GCodeProcessor::TimeMachine::calculate_time(size_t keep_last_n_blocks)
|
||||
layers_time[block.layer_id - 1] += block_time;
|
||||
}
|
||||
g1_times_cache.push_back({ block.g1_line_id, time });
|
||||
#if ENABLE_EXTENDED_M73_LINES
|
||||
// update times for remaining time to printer stop placeholders
|
||||
auto it_stop_time = std::lower_bound(stop_times.begin(), stop_times.end(), block.g1_line_id,
|
||||
[](const StopTime& t, unsigned int value) { return t.g1_line_id < value; });
|
||||
if (it_stop_time != stop_times.end() && it_stop_time->g1_line_id == block.g1_line_id)
|
||||
it_stop_time->elapsed_time = time;
|
||||
#endif // ENABLE_EXTENDED_M73_LINES
|
||||
}
|
||||
|
||||
if (keep_last_n_blocks)
|
||||
@ -355,7 +374,16 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
|
||||
return int(::roundf(time_in_seconds / 60.0f));
|
||||
};
|
||||
|
||||
#if ENABLE_EXTENDED_M73_LINES
|
||||
auto time_in_last_minute = [](float time_in_seconds) {
|
||||
assert(time_in_seconds <= 60.0f);
|
||||
return time_in_seconds / 60.0f;
|
||||
};
|
||||
|
||||
auto format_line_M73_main = [](const std::string& mask, int percent, int time) {
|
||||
#else
|
||||
auto format_line_M73 = [](const std::string& mask, int percent, int time) {
|
||||
#endif // ENABLE_EXTENDED_M73_LINES
|
||||
char line_M73[64];
|
||||
sprintf(line_M73, mask.c_str(),
|
||||
std::to_string(percent).c_str(),
|
||||
@ -363,14 +391,47 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
|
||||
return std::string(line_M73);
|
||||
};
|
||||
|
||||
#if ENABLE_EXTENDED_M73_LINES
|
||||
auto format_line_M73_stop_int = [](const std::string& mask, int time) {
|
||||
char line_M73[64];
|
||||
sprintf(line_M73, mask.c_str(), std::to_string(time).c_str());
|
||||
return std::string(line_M73);
|
||||
};
|
||||
|
||||
auto format_time_float = [](float time) {
|
||||
char time_str[64];
|
||||
sprintf(time_str, "%.2f", time);
|
||||
return std::string(time_str);
|
||||
};
|
||||
|
||||
auto format_line_M73_stop_float = [format_time_float](const std::string& mask, float time) {
|
||||
char line_M73[64];
|
||||
sprintf(line_M73, mask.c_str(), format_time_float(time).c_str());
|
||||
return std::string(line_M73);
|
||||
};
|
||||
#endif // ENABLE_EXTENDED_M73_LINES
|
||||
|
||||
GCodeReader parser;
|
||||
std::string gcode_line;
|
||||
size_t g1_lines_counter = 0;
|
||||
// keeps track of last exported pair <percent, remaining time>
|
||||
#if ENABLE_EXTENDED_M73_LINES
|
||||
std::array<std::pair<int, int>, static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count)> last_exported_main;
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
|
||||
last_exported_main[i] = { 0, time_in_minutes(machines[i].time) };
|
||||
}
|
||||
|
||||
// keeps track of last exported remaining time to next printer stop
|
||||
std::array<int, static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count)> last_exported_stop;
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
|
||||
last_exported_stop[i] = time_in_minutes(machines[i].time);
|
||||
}
|
||||
#else
|
||||
std::array<std::pair<int, int>, static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count)> last_exported;
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
|
||||
last_exported[i] = { 0, time_in_minutes(machines[i].time) };
|
||||
}
|
||||
#endif // ENABLE_EXTENDED_M73_LINES
|
||||
|
||||
// buffer line to export only when greater than 64K to reduce writing calls
|
||||
std::string export_line;
|
||||
@ -393,12 +454,32 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
|
||||
const TimeMachine& machine = machines[i];
|
||||
if (machine.enabled) {
|
||||
#if ENABLE_EXTENDED_M73_LINES
|
||||
// export pair <percent, remaining time>
|
||||
ret += format_line_M73_main(machine.line_m73_main_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
|
||||
|
||||
// export remaining time to next printer stop
|
||||
if (line == reserved_tag(ETags::First_Line_M73_Placeholder) && !machine.stop_times.empty()) {
|
||||
int to_export_stop = time_in_minutes(machine.stop_times.front().elapsed_time);
|
||||
ret += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop);
|
||||
last_exported_stop[i] = to_export_stop;
|
||||
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
++extra_lines_count;
|
||||
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
}
|
||||
#else
|
||||
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
|
||||
#endif // ENABLE_EXTENDED_M73_LINES
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -467,11 +548,23 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
|
||||
const TimeMachine& machine = machines[i];
|
||||
if (machine.enabled) {
|
||||
// export pair <percent, remaining time>
|
||||
// Skip all machine.g1_times_cache below g1_lines_counter.
|
||||
auto& it = g1_times_cache_it[i];
|
||||
while (it != machine.g1_times_cache.end() && it->id < g1_lines_counter)
|
||||
++it;
|
||||
if (it != machine.g1_times_cache.end() && it->id == g1_lines_counter) {
|
||||
#if ENABLE_EXTENDED_M73_LINES
|
||||
std::pair<int, int> to_export_main = { int(100.0f * it->elapsed_time / machine.time),
|
||||
time_in_minutes(machine.time - it->elapsed_time) };
|
||||
if (last_exported_main[i] != to_export_main) {
|
||||
export_line += format_line_M73_main(machine.line_m73_main_mask.c_str(),
|
||||
to_export_main.first, to_export_main.second);
|
||||
last_exported_main[i] = to_export_main;
|
||||
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
++exported_lines_count;
|
||||
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
#else
|
||||
float elapsed_time = it->elapsed_time;
|
||||
std::pair<int, int> to_export = { int(100.0f * elapsed_time / machine.time),
|
||||
time_in_minutes(machine.time - elapsed_time) };
|
||||
@ -482,7 +575,54 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
|
||||
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
++exported_lines_count;
|
||||
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
#endif // ENABLE_EXTENDED_M73_LINES
|
||||
}
|
||||
#if ENABLE_EXTENDED_M73_LINES
|
||||
// export remaining time to next printer stop
|
||||
auto it_stop = std::upper_bound(machine.stop_times.begin(), machine.stop_times.end(), it->elapsed_time,
|
||||
[](float value, const TimeMachine::StopTime& t) { return value < t.elapsed_time; });
|
||||
if (it_stop != machine.stop_times.end()) {
|
||||
int to_export_stop = time_in_minutes(it_stop->elapsed_time - it->elapsed_time);
|
||||
if (last_exported_stop[i] != to_export_stop) {
|
||||
if (to_export_stop > 0) {
|
||||
if (last_exported_stop[i] != to_export_stop) {
|
||||
export_line += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop);
|
||||
last_exported_stop[i] = to_export_stop;
|
||||
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
++exported_lines_count;
|
||||
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
}
|
||||
}
|
||||
else {
|
||||
bool is_last = false;
|
||||
auto next_it = it + 1;
|
||||
is_last |= (next_it == machine.g1_times_cache.end());
|
||||
|
||||
if (next_it != machine.g1_times_cache.end()) {
|
||||
auto next_it_stop = std::upper_bound(machine.stop_times.begin(), machine.stop_times.end(), next_it->elapsed_time,
|
||||
[](float value, const TimeMachine::StopTime& t) { return value < t.elapsed_time; });
|
||||
is_last |= (next_it_stop != it_stop);
|
||||
|
||||
std::string time_float_str = format_time_float(time_in_last_minute(it_stop->elapsed_time - it->elapsed_time));
|
||||
std::string next_time_float_str = format_time_float(time_in_last_minute(it_stop->elapsed_time - next_it->elapsed_time));
|
||||
is_last |= (std::stof(time_float_str) > 0.0f && std::stof(next_time_float_str) == 0.0f);
|
||||
}
|
||||
|
||||
if (is_last) {
|
||||
if (std::distance(machine.stop_times.begin(), it_stop) == static_cast<ptrdiff_t>(machine.stop_times.size() - 1))
|
||||
export_line += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop);
|
||||
else
|
||||
export_line += format_line_M73_stop_float(machine.line_m73_stop_mask.c_str(), time_in_last_minute(it_stop->elapsed_time - it->elapsed_time));
|
||||
|
||||
last_exported_stop[i] = to_export_stop;
|
||||
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
++exported_lines_count;
|
||||
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_EXTENDED_M73_LINES
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -594,12 +734,6 @@ 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;
|
||||
@ -610,7 +744,7 @@ bool GCodeProcessor::contains_reserved_tag(const std::string& gcode, std::string
|
||||
if (comment.length() > 2 && comment.front() == ';') {
|
||||
comment = comment.substr(1);
|
||||
for (const std::string& s : Reserved_Tags) {
|
||||
if (starts_with(comment, s)) {
|
||||
if (boost::starts_with(comment, s)) {
|
||||
ret = true;
|
||||
found_tag = comment;
|
||||
parser.quit_parsing();
|
||||
@ -635,7 +769,7 @@ bool GCodeProcessor::contains_reserved_tags(const std::string& gcode, unsigned i
|
||||
if (comment.length() > 2 && comment.front() == ';') {
|
||||
comment = comment.substr(1);
|
||||
for (const std::string& s : Reserved_Tags) {
|
||||
if (starts_with(comment, s)) {
|
||||
if (boost::starts_with(comment, s)) {
|
||||
ret = true;
|
||||
found_tag.push_back(comment);
|
||||
if (found_tag.size() == max_count) {
|
||||
@ -654,8 +788,15 @@ bool GCodeProcessor::contains_reserved_tags(const std::string& gcode, unsigned i
|
||||
GCodeProcessor::GCodeProcessor()
|
||||
{
|
||||
reset();
|
||||
#if ENABLE_EXTENDED_M73_LINES
|
||||
m_time_processor.machines[static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Normal)].line_m73_main_mask = "M73 P%s R%s\n";
|
||||
m_time_processor.machines[static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Normal)].line_m73_stop_mask = "M73 C%s\n";
|
||||
m_time_processor.machines[static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Stealth)].line_m73_main_mask = "M73 Q%s S%s\n";
|
||||
m_time_processor.machines[static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Stealth)].line_m73_stop_mask = "M73 D%s\n";
|
||||
#else
|
||||
m_time_processor.machines[static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Normal)].line_m73_mask = "M73 P%s R%s\n";
|
||||
m_time_processor.machines[static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Stealth)].line_m73_mask = "M73 Q%s S%s\n";
|
||||
#endif // ENABLE_EXTENDED_M73_LINES
|
||||
}
|
||||
|
||||
void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
@ -678,13 +819,20 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
m_extruder_colors[i] = static_cast<unsigned char>(i);
|
||||
}
|
||||
|
||||
m_extruder_temps.resize(extruders_count);
|
||||
|
||||
m_filament_diameters.resize(config.filament_diameter.values.size());
|
||||
for (size_t i = 0; i < config.filament_diameter.values.size(); ++i) {
|
||||
m_filament_diameters[i] = static_cast<float>(config.filament_diameter.values[i]);
|
||||
}
|
||||
|
||||
if (m_flavor == gcfMarlin && config.machine_limits_usage.value != MachineLimitsUsage::Ignore)
|
||||
if ((m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) && config.machine_limits_usage.value != MachineLimitsUsage::Ignore) {
|
||||
m_time_processor.machine_limits = reinterpret_cast<const MachineEnvelopeConfig&>(config);
|
||||
if (m_flavor == gcfMarlinLegacy) {
|
||||
// Legacy Marlin does not have separate travel acceleration, it uses the 'extruding' value instead.
|
||||
m_time_processor.machine_limits.machine_max_acceleration_travel = m_time_processor.machine_limits.machine_max_acceleration_extruding;
|
||||
}
|
||||
}
|
||||
|
||||
// Filament load / unload times are not specific to a firmware flavor. Let anybody use it if they find it useful.
|
||||
// As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they
|
||||
@ -702,6 +850,9 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
float max_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_extruding, i);
|
||||
m_time_processor.machines[i].max_acceleration = max_acceleration;
|
||||
m_time_processor.machines[i].acceleration = (max_acceleration > 0.0f) ? max_acceleration : DEFAULT_ACCELERATION;
|
||||
float max_travel_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_travel, i);
|
||||
m_time_processor.machines[i].max_travel_acceleration = max_travel_acceleration;
|
||||
m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION;
|
||||
}
|
||||
|
||||
m_time_processor.export_remaining_time_enabled = config.remaining_times.value;
|
||||
@ -776,6 +927,8 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
m_extruder_colors[i] = static_cast<unsigned char>(i);
|
||||
}
|
||||
|
||||
m_extruder_temps.resize(m_result.extruders_count);
|
||||
|
||||
const ConfigOptionFloats* filament_load_time = config.option<ConfigOptionFloats>("filament_load_time");
|
||||
if (filament_load_time != nullptr) {
|
||||
m_time_processor.filament_load_times.resize(filament_load_time->values.size());
|
||||
@ -792,7 +945,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
}
|
||||
}
|
||||
|
||||
if (m_flavor == gcfMarlin) {
|
||||
if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) {
|
||||
const ConfigOptionFloats* machine_max_acceleration_x = config.option<ConfigOptionFloats>("machine_max_acceleration_x");
|
||||
if (machine_max_acceleration_x != nullptr)
|
||||
m_time_processor.machine_limits.machine_max_acceleration_x.values = machine_max_acceleration_x->values;
|
||||
@ -849,6 +1002,15 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
if (machine_max_acceleration_retracting != nullptr)
|
||||
m_time_processor.machine_limits.machine_max_acceleration_retracting.values = machine_max_acceleration_retracting->values;
|
||||
|
||||
|
||||
// Legacy Marlin does not have separate travel acceleration, it uses the 'extruding' value instead.
|
||||
const ConfigOptionFloats* machine_max_acceleration_travel = config.option<ConfigOptionFloats>(m_flavor == gcfMarlinLegacy
|
||||
? "machine_max_acceleration_extruding"
|
||||
: "machine_max_acceleration_travel");
|
||||
if (machine_max_acceleration_travel != nullptr)
|
||||
m_time_processor.machine_limits.machine_max_acceleration_travel.values = machine_max_acceleration_travel->values;
|
||||
|
||||
|
||||
const ConfigOptionFloats* machine_min_extruding_rate = config.option<ConfigOptionFloats>("machine_min_extruding_rate");
|
||||
if (machine_min_extruding_rate != nullptr)
|
||||
m_time_processor.machine_limits.machine_min_extruding_rate.values = machine_min_extruding_rate->values;
|
||||
@ -862,6 +1024,9 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
float max_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_extruding, i);
|
||||
m_time_processor.machines[i].max_acceleration = max_acceleration;
|
||||
m_time_processor.machines[i].acceleration = (max_acceleration > 0.0f) ? max_acceleration : DEFAULT_ACCELERATION;
|
||||
float max_travel_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_travel, i);
|
||||
m_time_processor.machines[i].max_travel_acceleration = max_travel_acceleration;
|
||||
m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION;
|
||||
}
|
||||
|
||||
if (m_time_processor.machine_limits.machine_max_acceleration_x.values.size() > 1)
|
||||
@ -910,6 +1075,10 @@ void GCodeProcessor::reset()
|
||||
for (size_t i = 0; i < Min_Extruder_Count; ++i) {
|
||||
m_extruder_colors[i] = static_cast<unsigned char>(i);
|
||||
}
|
||||
m_extruder_temps.resize(Min_Extruder_Count);
|
||||
for (size_t i = 0; i < Min_Extruder_Count; ++i) {
|
||||
m_extruder_temps[i] = 0.0f;
|
||||
}
|
||||
|
||||
m_filament_diameters = std::vector<float>(Min_Extruder_Count, 1.75f);
|
||||
m_extruded_last_z = 0.0f;
|
||||
@ -966,9 +1135,14 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
|
||||
config.load_from_gcode_file(filename, false);
|
||||
apply_config(config);
|
||||
}
|
||||
else if (m_producer == EProducer::Simplify3D)
|
||||
apply_config_simplify3d(filename);
|
||||
}
|
||||
|
||||
// process gcode
|
||||
#if ENABLE_GCODE_WINDOW
|
||||
m_result.filename = filename;
|
||||
#endif // ENABLE_GCODE_WINDOW
|
||||
m_result.id = ++s_result_id;
|
||||
// 1st move must be a dummy move
|
||||
m_result.moves.emplace_back(MoveVertex());
|
||||
@ -1081,6 +1255,59 @@ std::vector<float> GCodeProcessor::get_layers_time(PrintEstimatedTimeStatistics:
|
||||
std::vector<float>();
|
||||
}
|
||||
|
||||
void GCodeProcessor::apply_config_simplify3d(const std::string& filename)
|
||||
{
|
||||
struct BedSize
|
||||
{
|
||||
double x{ 0.0 };
|
||||
double y{ 0.0 };
|
||||
|
||||
bool is_defined() const { return x > 0.0 && y > 0.0; }
|
||||
};
|
||||
|
||||
BedSize bed_size;
|
||||
|
||||
m_parser.parse_file(filename, [this, &bed_size](GCodeReader& reader, const GCodeReader::GCodeLine& line) {
|
||||
auto extract_float = [](const std::string& cmt, const std::string& key, double& out) {
|
||||
size_t pos = cmt.find(key);
|
||||
if (pos != cmt.npos) {
|
||||
pos = cmt.find(',', pos);
|
||||
if (pos != cmt.npos) {
|
||||
out = std::stod(cmt.substr(pos + 1));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const std::string& comment = line.raw();
|
||||
if (comment.length() > 2 && comment.front() == ';') {
|
||||
if (bed_size.x == 0.0)
|
||||
extract_float(comment, "strokeXoverride", bed_size.x);
|
||||
if (bed_size.y == 0.0)
|
||||
extract_float(comment, "strokeYoverride", bed_size.y);
|
||||
|
||||
// check for early exit
|
||||
if (bed_size.is_defined()) {
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
m_parser.quit_parsing();
|
||||
#else
|
||||
m_parser.quit_parsing_file();
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (bed_size.is_defined()) {
|
||||
m_result.bed_shape = {
|
||||
{ 0.0, 0.0 },
|
||||
{ bed_size.x, 0.0 },
|
||||
{ bed_size.x, bed_size.y },
|
||||
{ 0.0, bed_size.y }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
/* std::cout << line.raw() << std::endl; */
|
||||
@ -1109,6 +1336,7 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line)
|
||||
case 21: { process_G21(line); break; } // Set Units to Millimeters
|
||||
case 22: { process_G22(line); break; } // Firmware controlled retract
|
||||
case 23: { process_G23(line); break; } // Firmware controlled unretract
|
||||
case 28: { process_G28(line); break; } // Move to origin
|
||||
case 90: { process_G90(line); break; } // Set to Absolute Positioning
|
||||
case 91: { process_G91(line); break; } // Set to Relative Positioning
|
||||
case 92: { process_G92(line); break; } // Set Position
|
||||
@ -1123,9 +1351,11 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line)
|
||||
case 1: { process_M1(line); break; } // Sleep or Conditional stop
|
||||
case 82: { process_M82(line); break; } // Set extruder to absolute mode
|
||||
case 83: { process_M83(line); break; } // Set extruder to relative mode
|
||||
case 104: { process_M104(line); break; } // Set extruder temperature
|
||||
case 106: { process_M106(line); break; } // Set fan speed
|
||||
case 107: { process_M107(line); break; } // Disable fan
|
||||
case 108: { process_M108(line); break; } // Set tool (Sailfish)
|
||||
case 109: { process_M109(line); break; } // Set extruder temperature and wait
|
||||
case 132: { process_M132(line); break; } // Recall stored home offsets
|
||||
case 135: { process_M135(line); break; } // Set tool (MakerWare)
|
||||
case 201: { process_M201(line); break; } // Set max printing acceleration
|
||||
@ -1158,14 +1388,6 @@ 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>
|
||||
struct is_from_chars_convertible : std::false_type {};
|
||||
@ -1219,37 +1441,37 @@ void GCodeProcessor::process_tags(const std::string_view comment)
|
||||
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
// extrusion role tag
|
||||
if (starts_with(comment, reserved_tag(ETags::Role))) {
|
||||
if (boost::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))) {
|
||||
if (boost::starts_with(comment, reserved_tag(ETags::Wipe_Start))) {
|
||||
m_wiping = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// wipe end tag
|
||||
if (starts_with(comment, reserved_tag(ETags::Wipe_End))) {
|
||||
if (boost::starts_with(comment, reserved_tag(ETags::Wipe_End))) {
|
||||
m_wiping = false;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
// extrusion role tag
|
||||
if (starts_with(comment, Extrusion_Role_Tag)) {
|
||||
if (boost::starts_with(comment, Extrusion_Role_Tag)) {
|
||||
m_extrusion_role = ExtrusionEntity::string_to_role(comment.substr(Extrusion_Role_Tag.length()));
|
||||
return;
|
||||
}
|
||||
|
||||
// wipe start tag
|
||||
if (starts_with(comment, Wipe_Start_Tag)) {
|
||||
if (boost::starts_with(comment, Wipe_Start_Tag)) {
|
||||
m_wiping = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// wipe end tag
|
||||
if (starts_with(comment, Wipe_End_Tag)) {
|
||||
if (boost::starts_with(comment, Wipe_End_Tag)) {
|
||||
m_wiping = false;
|
||||
return;
|
||||
}
|
||||
@ -1258,26 +1480,26 @@ void GCodeProcessor::process_tags(const std::string_view comment)
|
||||
if (!m_producers_enabled || m_producer == EProducer::PrusaSlicer) {
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
// height tag
|
||||
if (starts_with(comment, reserved_tag(ETags::Height))) {
|
||||
if (boost::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 (boost::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 (boost::starts_with(comment, Height_Tag)) {
|
||||
if (!parse_number(comment.substr(Height_Tag.size()), m_forced_height))
|
||||
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ").";
|
||||
return;
|
||||
}
|
||||
// width tag
|
||||
if (starts_with(comment, Width_Tag)) {
|
||||
if (boost::starts_with(comment, Width_Tag)) {
|
||||
if (!parse_number(comment.substr(Width_Tag.size()), m_forced_width))
|
||||
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ").";
|
||||
return;
|
||||
@ -1287,9 +1509,9 @@ void GCodeProcessor::process_tags(const std::string_view comment)
|
||||
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
// color change tag
|
||||
if (starts_with(comment, reserved_tag(ETags::Color_Change))) {
|
||||
if (boost::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")) {
|
||||
if (boost::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 << ").";
|
||||
@ -1333,9 +1555,9 @@ void GCodeProcessor::process_tags(const std::string_view comment)
|
||||
}
|
||||
#else
|
||||
// color change tag
|
||||
if (starts_with(comment, Color_Change_Tag)) {
|
||||
if (boost::starts_with(comment, Color_Change_Tag)) {
|
||||
unsigned char extruder_id = 0;
|
||||
if (starts_with(comment.substr(Color_Change_Tag.size()), ",T")) {
|
||||
if (boost::starts_with(comment.substr(Color_Change_Tag.size()), ",T")) {
|
||||
int eid;
|
||||
if (! parse_number(comment.substr(Color_Change_Tag.size() + 2), eid) || eid < 0 || eid > 255) {
|
||||
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Color_Change (" << comment << ").";
|
||||
@ -1381,7 +1603,7 @@ void GCodeProcessor::process_tags(const std::string_view comment)
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
// mm3_per_mm print tag
|
||||
if (starts_with(comment, Mm3_Per_Mm_Tag)) {
|
||||
if (boost::starts_with(comment, Mm3_Per_Mm_Tag)) {
|
||||
if (! parse_number(comment.substr(Mm3_Per_Mm_Tag.size()), m_mm3_per_mm_compare.last_tag_value))
|
||||
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Mm3_Per_Mm (" << comment << ").";
|
||||
return;
|
||||
@ -1447,23 +1669,23 @@ bool GCodeProcessor::process_cura_tags(const std::string_view comment)
|
||||
if (pos != comment.npos) {
|
||||
const std::string_view flavor = comment.substr(pos + tag.length());
|
||||
if (flavor == "BFB")
|
||||
m_flavor = gcfMarlin; // << ???????????????????????
|
||||
m_flavor = gcfMarlinLegacy; // is this correct ?
|
||||
else if (flavor == "Mach3")
|
||||
m_flavor = gcfMach3;
|
||||
else if (flavor == "Makerbot")
|
||||
m_flavor = gcfMakerWare;
|
||||
else if (flavor == "UltiGCode")
|
||||
m_flavor = gcfMarlin; // << ???????????????????????
|
||||
m_flavor = gcfMarlinLegacy; // is this correct ?
|
||||
else if (flavor == "Marlin(Volumetric)")
|
||||
m_flavor = gcfMarlin; // << ???????????????????????
|
||||
m_flavor = gcfMarlinLegacy; // is this correct ?
|
||||
else if (flavor == "Griffin")
|
||||
m_flavor = gcfMarlin; // << ???????????????????????
|
||||
m_flavor = gcfMarlinLegacy; // is this correct ?
|
||||
else if (flavor == "Repetier")
|
||||
m_flavor = gcfRepetier;
|
||||
else if (flavor == "RepRap")
|
||||
m_flavor = gcfRepRapFirmware;
|
||||
else if (flavor == "Marlin")
|
||||
m_flavor = gcfMarlin;
|
||||
m_flavor = gcfMarlinLegacy;
|
||||
else
|
||||
BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown flavor: " << flavor;
|
||||
|
||||
@ -1485,89 +1707,109 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string_view comment)
|
||||
{
|
||||
// extrusion roles
|
||||
|
||||
// in older versions the comments did not contain the key 'feature'
|
||||
std::string_view cmt = comment;
|
||||
size_t pos = cmt.find(" feature");
|
||||
if (pos == 0)
|
||||
cmt.remove_prefix(8);
|
||||
|
||||
// ; skirt
|
||||
size_t pos = comment.find(" skirt");
|
||||
pos = cmt.find(" skirt");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erSkirt;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; outer perimeter
|
||||
pos = comment.find(" outer perimeter");
|
||||
pos = cmt.find(" outer perimeter");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erExternalPerimeter;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; inner perimeter
|
||||
pos = comment.find(" inner perimeter");
|
||||
pos = cmt.find(" inner perimeter");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erPerimeter;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; gap fill
|
||||
pos = comment.find(" gap fill");
|
||||
pos = cmt.find(" gap fill");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erGapFill;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; infill
|
||||
pos = comment.find(" infill");
|
||||
pos = cmt.find(" infill");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erInternalInfill;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; solid layer
|
||||
pos = comment.find(" solid layer");
|
||||
pos = cmt.find(" solid layer");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erNone; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
m_extrusion_role = erSolidInfill;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; bridge
|
||||
pos = comment.find(" bridge");
|
||||
pos = cmt.find(" bridge");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erBridgeInfill;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; support
|
||||
pos = comment.find(" support");
|
||||
pos = cmt.find(" support");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erSupportMaterial;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; dense support
|
||||
pos = cmt.find(" dense support");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erSupportMaterialInterface;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; prime pillar
|
||||
pos = comment.find(" prime pillar");
|
||||
pos = cmt.find(" prime pillar");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erWipeTower;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; ooze shield
|
||||
pos = comment.find(" ooze shield");
|
||||
pos = cmt.find(" ooze shield");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erNone; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
m_extrusion_role = erNone; // Missing mapping
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; raft
|
||||
pos = comment.find(" raft");
|
||||
pos = cmt.find(" raft");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erSkirt;
|
||||
m_extrusion_role = erSupportMaterial;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; internal single extrusion
|
||||
pos = cmt.find(" internal single extrusion");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erNone; // Missing mapping
|
||||
return true;
|
||||
}
|
||||
|
||||
// geometry
|
||||
// ; tool
|
||||
std::string tag = " tool";
|
||||
pos = comment.find(tag);
|
||||
pos = cmt.find(tag);
|
||||
if (pos == 0) {
|
||||
const std::string_view data = comment.substr(pos + tag.length());
|
||||
const std::string_view data = cmt.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);
|
||||
@ -1588,10 +1830,10 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string_view comment)
|
||||
|
||||
// ; layer
|
||||
tag = " layer";
|
||||
pos = comment.find(tag);
|
||||
pos = cmt.find(tag);
|
||||
if (pos == 0) {
|
||||
// skip lines "; layer end"
|
||||
const std::string_view data = comment.substr(pos + tag.length());
|
||||
const std::string_view data = cmt.substr(pos + tag.length());
|
||||
size_t end_start = data.find("end");
|
||||
if (end_start == data.npos)
|
||||
++m_layer_id;
|
||||
@ -2007,9 +2249,11 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
|
||||
}
|
||||
|
||||
// calculates block acceleration
|
||||
float acceleration = is_extrusion_only_move(delta_pos) ?
|
||||
get_retract_acceleration(static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i)) :
|
||||
get_acceleration(static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i));
|
||||
float acceleration =
|
||||
(type == EMoveType::Travel) ? get_travel_acceleration(static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i)) :
|
||||
(is_extrusion_only_move(delta_pos) ?
|
||||
get_retract_acceleration(static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i)) :
|
||||
get_acceleration(static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i)));
|
||||
|
||||
for (unsigned char a = X; a <= E; ++a) {
|
||||
float axis_max_acceleration = get_axis_max_acceleration(static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i), static_cast<Axis>(a));
|
||||
@ -2148,6 +2392,32 @@ void GCodeProcessor::process_G23(const GCodeReader::GCodeLine& line)
|
||||
store_move_vertex(EMoveType::Unretract);
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_G28(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
std::string_view cmd = line.cmd();
|
||||
std::string new_line_raw = { cmd.data(), cmd.size() };
|
||||
bool found = false;
|
||||
if (line.has_x()) {
|
||||
new_line_raw += " X0";
|
||||
found = true;
|
||||
}
|
||||
if (line.has_y()) {
|
||||
new_line_raw += " Y0";
|
||||
found = true;
|
||||
}
|
||||
if (line.has_z()) {
|
||||
new_line_raw += " Z0";
|
||||
found = true;
|
||||
}
|
||||
if (!found)
|
||||
new_line_raw += " X0 Y0 Z0";
|
||||
|
||||
GCodeReader::GCodeLine new_gline;
|
||||
GCodeReader reader;
|
||||
reader.parse_line(new_line_raw, [&](GCodeReader& reader, const GCodeReader::GCodeLine& gline) { new_gline = gline; });
|
||||
process_G1(new_gline);
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_G90(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
m_global_positioning_type = EPositioningType::Absolute;
|
||||
@ -2211,6 +2481,13 @@ void GCodeProcessor::process_M83(const GCodeReader::GCodeLine& line)
|
||||
m_e_local_positioning_type = EPositioningType::Relative;
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_M104(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
float new_temp;
|
||||
if (line.has_value('S', new_temp))
|
||||
m_extruder_temps[m_extruder_id] = new_temp;
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_M106(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
if (!line.has('P')) {
|
||||
@ -2243,6 +2520,21 @@ void GCodeProcessor::process_M108(const GCodeReader::GCodeLine& line)
|
||||
process_T(cmd.substr(pos));
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_M109(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
float new_temp;
|
||||
if (line.has_value('R', new_temp)) {
|
||||
float val;
|
||||
if (line.has_value('T', val)) {
|
||||
size_t eid = static_cast<size_t>(val);
|
||||
if (eid < m_extruder_temps.size())
|
||||
m_extruder_temps[eid] = new_temp;
|
||||
}
|
||||
else
|
||||
m_extruder_temps[m_extruder_id] = new_temp;
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_M132(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
// This command is used by Makerbot to load the current home position from EEPROM
|
||||
@ -2308,7 +2600,7 @@ void GCodeProcessor::process_M203(const GCodeReader::GCodeLine& line)
|
||||
|
||||
// see http://reprap.org/wiki/G-code#M203:_Set_maximum_feedrate
|
||||
// http://smoothieware.org/supported-g-codes
|
||||
float factor = (m_flavor == gcfMarlin || m_flavor == gcfSmoothie) ? 1.0f : MMMIN_TO_MMSEC;
|
||||
float factor = (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfSmoothie) ? 1.0f : MMMIN_TO_MMSEC;
|
||||
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
|
||||
if (static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i) == PrintEstimatedTimeStatistics::ETimeMode::Normal ||
|
||||
@ -2335,10 +2627,11 @@ void GCodeProcessor::process_M204(const GCodeReader::GCodeLine& line)
|
||||
if (static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i) == PrintEstimatedTimeStatistics::ETimeMode::Normal ||
|
||||
m_time_processor.machine_envelope_processing_enabled) {
|
||||
if (line.has_value('S', value)) {
|
||||
// Legacy acceleration format. This format is used by the legacy Marlin, MK2 or MK3 firmware,
|
||||
// and it is also generated by Slic3r to control acceleration per extrusion type
|
||||
// (there is a separate acceleration settings in Slicer for perimeter, first layer etc).
|
||||
// Legacy acceleration format. This format is used by the legacy Marlin, MK2 or MK3 firmware
|
||||
// It is also generated by PrusaSlicer to control acceleration per extrusion type
|
||||
// (perimeters, first layer etc) when 'Marlin (legacy)' flavor is used.
|
||||
set_acceleration(static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i), value);
|
||||
set_travel_acceleration(static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i), value);
|
||||
if (line.has_value('T', value))
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i, value);
|
||||
}
|
||||
@ -2348,11 +2641,9 @@ void GCodeProcessor::process_M204(const GCodeReader::GCodeLine& line)
|
||||
set_acceleration(static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i), value);
|
||||
if (line.has_value('R', value))
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i, value);
|
||||
if (line.has_value('T', value)) {
|
||||
if (line.has_value('T', value))
|
||||
// Interpret the T value as the travel acceleration in the new Marlin format.
|
||||
//FIXME Prusa3D firmware currently does not support travel acceleration value independent from the extruding acceleration value.
|
||||
// set_travel_acceleration(value);
|
||||
}
|
||||
set_travel_acceleration(static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2482,7 +2773,7 @@ void GCodeProcessor::process_T(const std::string_view command)
|
||||
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?"))
|
||||
if ((m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) && (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
|
||||
@ -2518,7 +2809,7 @@ void GCodeProcessor::store_move_vertex(EMoveType type)
|
||||
{
|
||||
MoveVertex vertex = {
|
||||
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
m_line_id,
|
||||
(type == EMoveType::Color_change || type == EMoveType::Pause_Print || type == EMoveType::Custom_GCode) ? m_line_id + 1 : m_line_id,
|
||||
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
type,
|
||||
m_extrusion_role,
|
||||
@ -2531,9 +2822,23 @@ void GCodeProcessor::store_move_vertex(EMoveType type)
|
||||
m_height,
|
||||
m_mm3_per_mm,
|
||||
m_fan_speed,
|
||||
m_extruder_temps[m_extruder_id],
|
||||
static_cast<float>(m_result.moves.size())
|
||||
};
|
||||
m_result.moves.emplace_back(vertex);
|
||||
|
||||
#if ENABLE_EXTENDED_M73_LINES
|
||||
// stores stop time placeholders for later use
|
||||
if (type == EMoveType::Color_change || type == EMoveType::Pause_Print) {
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
|
||||
TimeMachine& machine = m_time_processor.machines[i];
|
||||
if (!machine.enabled)
|
||||
continue;
|
||||
|
||||
machine.stop_times.push_back({ m_g1_line_id, 0.0f });
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_EXTENDED_M73_LINES
|
||||
}
|
||||
|
||||
float GCodeProcessor::minimum_feedrate(PrintEstimatedTimeStatistics::ETimeMode mode, float feedrate) const
|
||||
@ -2609,6 +2914,22 @@ void GCodeProcessor::set_acceleration(PrintEstimatedTimeStatistics::ETimeMode mo
|
||||
}
|
||||
}
|
||||
|
||||
float GCodeProcessor::get_travel_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode) const
|
||||
{
|
||||
size_t id = static_cast<size_t>(mode);
|
||||
return (id < m_time_processor.machines.size()) ? m_time_processor.machines[id].travel_acceleration : DEFAULT_TRAVEL_ACCELERATION;
|
||||
}
|
||||
|
||||
void GCodeProcessor::set_travel_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode, float value)
|
||||
{
|
||||
size_t id = static_cast<size_t>(mode);
|
||||
if (id < m_time_processor.machines.size()) {
|
||||
m_time_processor.machines[id].travel_acceleration = (m_time_processor.machines[id].max_travel_acceleration == 0.0f) ? value :
|
||||
// Clamp the acceleration with the maximum.
|
||||
std::min(value, m_time_processor.machines[id].max_travel_acceleration);
|
||||
}
|
||||
}
|
||||
|
||||
float GCodeProcessor::get_filament_load_time(size_t extruder_id)
|
||||
{
|
||||
return (m_time_processor.filament_load_times.empty() || m_time_processor.extruder_unloaded) ?
|
||||
|
@ -121,6 +121,7 @@ namespace Slic3r {
|
||||
private:
|
||||
using AxisCoords = std::array<float, 4>;
|
||||
using ExtruderColors = std::vector<unsigned char>;
|
||||
using ExtruderTemps = std::vector<float>;
|
||||
|
||||
enum class EUnits : unsigned char
|
||||
{
|
||||
@ -211,6 +212,7 @@ namespace Slic3r {
|
||||
float height{ 0.0f }; // mm
|
||||
float mm3_per_mm{ 0.0f };
|
||||
float fan_speed{ 0.0f }; // percentage
|
||||
float temperature{ 0.0f }; // Celsius degrees
|
||||
float time{ 0.0f }; // s
|
||||
|
||||
float volumetric_rate() const { return feedrate * mm3_per_mm; }
|
||||
@ -249,9 +251,23 @@ namespace Slic3r {
|
||||
float acceleration; // mm/s^2
|
||||
// hard limit for the acceleration, to which the firmware will clamp.
|
||||
float max_acceleration; // mm/s^2
|
||||
float travel_acceleration; // mm/s^2
|
||||
// hard limit for the travel acceleration, to which the firmware will clamp.
|
||||
float max_travel_acceleration; // mm/s^2
|
||||
float extrude_factor_override_percentage;
|
||||
float time; // s
|
||||
#if ENABLE_EXTENDED_M73_LINES
|
||||
struct StopTime
|
||||
{
|
||||
unsigned int g1_line_id;
|
||||
float elapsed_time;
|
||||
};
|
||||
std::vector<StopTime> stop_times;
|
||||
std::string line_m73_main_mask;
|
||||
std::string line_m73_stop_mask;
|
||||
#else
|
||||
std::string line_m73_mask;
|
||||
#endif // ENABLE_EXTENDED_M73_LINES
|
||||
State curr;
|
||||
State prev;
|
||||
CustomGCodeTime gcode_time;
|
||||
@ -320,6 +336,7 @@ namespace Slic3r {
|
||||
float height{ 0.0f }; // mm
|
||||
float mm3_per_mm{ 0.0f };
|
||||
float fan_speed{ 0.0f }; // percentage
|
||||
float temperature{ 0.0f }; // Celsius degrees
|
||||
float time{ 0.0f }; // s
|
||||
|
||||
float volumetric_rate() const { return feedrate * mm3_per_mm; }
|
||||
@ -334,13 +351,15 @@ namespace Slic3r {
|
||||
std::vector<std::string> filament;
|
||||
std::string printer;
|
||||
|
||||
void reset()
|
||||
{
|
||||
void reset() {
|
||||
print = "";
|
||||
filament = std::vector<std::string>();
|
||||
printer = "";
|
||||
}
|
||||
};
|
||||
#if ENABLE_GCODE_WINDOW
|
||||
std::string filename;
|
||||
#endif // ENABLE_GCODE_WINDOW
|
||||
unsigned int id;
|
||||
std::vector<MoveVertex> moves;
|
||||
Pointfs bed_shape;
|
||||
@ -468,6 +487,7 @@ namespace Slic3r {
|
||||
ExtrusionRole m_extrusion_role;
|
||||
unsigned char m_extruder_id;
|
||||
ExtruderColors m_extruder_colors;
|
||||
ExtruderTemps m_extruder_temps;
|
||||
std::vector<float> m_filament_diameters;
|
||||
float m_extruded_last_z;
|
||||
unsigned int m_g1_line_id;
|
||||
@ -507,7 +527,6 @@ namespace Slic3r {
|
||||
GCodeProcessor();
|
||||
|
||||
void apply_config(const PrintConfig& config);
|
||||
void apply_config(const DynamicPrintConfig& config);
|
||||
void enable_stealth_time_estimator(bool enabled);
|
||||
bool is_stealth_time_estimator_enabled() const {
|
||||
return m_time_processor.machines[static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Stealth)].enabled;
|
||||
@ -532,6 +551,8 @@ namespace Slic3r {
|
||||
std::vector<float> get_layers_time(PrintEstimatedTimeStatistics::ETimeMode mode) const;
|
||||
|
||||
private:
|
||||
void apply_config(const DynamicPrintConfig& config);
|
||||
void apply_config_simplify3d(const std::string& filename);
|
||||
void process_gcode_line(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Process tags embedded into comments
|
||||
@ -568,6 +589,9 @@ namespace Slic3r {
|
||||
// Firmware controlled Unretract
|
||||
void process_G23(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Move to origin
|
||||
void process_G28(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set to Absolute Positioning
|
||||
void process_G90(const GCodeReader::GCodeLine& line);
|
||||
|
||||
@ -586,6 +610,9 @@ namespace Slic3r {
|
||||
// Set extruder to relative mode
|
||||
void process_M83(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set extruder temperature
|
||||
void process_M104(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set fan speed
|
||||
void process_M106(const GCodeReader::GCodeLine& line);
|
||||
|
||||
@ -595,6 +622,9 @@ namespace Slic3r {
|
||||
// Set tool (Sailfish)
|
||||
void process_M108(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set extruder temperature and wait
|
||||
void process_M109(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Recall stored home offsets
|
||||
void process_M132(const GCodeReader::GCodeLine& line);
|
||||
|
||||
@ -641,7 +671,9 @@ namespace Slic3r {
|
||||
float get_axis_max_jerk(PrintEstimatedTimeStatistics::ETimeMode mode, Axis axis) const;
|
||||
float get_retract_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode) const;
|
||||
float get_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode) const;
|
||||
void set_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode, float value);
|
||||
void set_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode, float value);
|
||||
float get_travel_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode) const;
|
||||
void set_travel_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode, float value);
|
||||
float get_filament_load_time(size_t extruder_id);
|
||||
float get_filament_unload_time(size_t extruder_id);
|
||||
|
||||
|
@ -329,6 +329,16 @@ void ToolOrdering::reorder_extruders(unsigned int last_extruder_id)
|
||||
lt.extruders.front() = last_extruder_id;
|
||||
break;
|
||||
}
|
||||
|
||||
// On first layer with wipe tower, prefer a soluble extruder
|
||||
// at the beginning, so it is not wiped on the first layer.
|
||||
if (lt == m_layer_tools[0] && m_print_config_ptr && m_print_config_ptr->wipe_tower) {
|
||||
for (size_t i = 0; i<lt.extruders.size(); ++i)
|
||||
if (m_print_config_ptr->filament_soluble.get_at(lt.extruders[i]-1)) { // 1-based...
|
||||
std::swap(lt.extruders[i], lt.extruders.front());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
last_extruder_id = lt.extruders.back();
|
||||
}
|
||||
|
@ -9,17 +9,6 @@
|
||||
#include "BoundingBox.hpp"
|
||||
|
||||
|
||||
// Experimental "Peter's wipe tower" feature was partially implemented, inspired by
|
||||
// PJR's idea of alternating two perpendicular wiping directions on a square tower.
|
||||
// It is probably never going to be finished, there are multiple remaining issues
|
||||
// and there is probably no need to go down this way. m_peters_wipe_tower variable
|
||||
// turns this on, maybe it should just be removed. Anyway, the issues are
|
||||
// - layer's are not exactly square
|
||||
// - variable width for higher levels
|
||||
// - make sure it is not too sparse (apply max_bridge_distance and make last wipe longer)
|
||||
// - enable enhanced first layer adhesion
|
||||
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
@ -122,8 +111,10 @@ public:
|
||||
|
||||
WipeTowerWriter& feedrate(float f)
|
||||
{
|
||||
if (f != m_current_feedrate)
|
||||
if (f != m_current_feedrate) {
|
||||
m_gcode += "G1" + set_format_F(f) + "\n";
|
||||
m_current_feedrate = f;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -242,6 +233,14 @@ public:
|
||||
return (*this);
|
||||
}
|
||||
|
||||
WipeTowerWriter& rectangle(const WipeTower::box_coordinates& box, const float f = 0.f)
|
||||
{
|
||||
rectangle(Vec2f(box.ld.x(), box.ld.y()),
|
||||
box.ru.x() - box.lu.x(),
|
||||
box.ru.y() - box.rd.y(), f);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
WipeTowerWriter& load(float e, float f = 0.f)
|
||||
{
|
||||
if (e == 0.f && (f == 0.f || f == m_current_feedrate))
|
||||
@ -343,7 +342,7 @@ public:
|
||||
WipeTowerWriter& speed_override_backup()
|
||||
{
|
||||
// This is only supported by Prusa at this point (https://github.com/prusa3d/PrusaSlicer/issues/3114)
|
||||
if (m_gcode_flavor == gcfMarlin)
|
||||
if (m_gcode_flavor == gcfMarlinLegacy || m_gcode_flavor == gcfMarlinFirmware)
|
||||
m_gcode += "M220 B\n";
|
||||
return *this;
|
||||
}
|
||||
@ -351,7 +350,7 @@ public:
|
||||
// Let the firmware restore the active speed override value.
|
||||
WipeTowerWriter& speed_override_restore()
|
||||
{
|
||||
if (m_gcode_flavor == gcfMarlin)
|
||||
if (m_gcode_flavor == gcfMarlinLegacy || m_gcode_flavor == gcfMarlinFirmware)
|
||||
m_gcode += "M220 R\n";
|
||||
return *this;
|
||||
}
|
||||
@ -520,15 +519,24 @@ WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<fl
|
||||
m_wipe_tower_pos(config.wipe_tower_x, config.wipe_tower_y),
|
||||
m_wipe_tower_width(float(config.wipe_tower_width)),
|
||||
m_wipe_tower_rotation_angle(float(config.wipe_tower_rotation_angle)),
|
||||
m_wipe_tower_brim_width(float(config.wipe_tower_brim_width)),
|
||||
m_y_shift(0.f),
|
||||
m_z_pos(0.f),
|
||||
m_is_first_layer(false),
|
||||
m_bridging(float(config.wipe_tower_bridging)),
|
||||
m_no_sparse_layers(config.wipe_tower_no_sparse_layers),
|
||||
m_gcode_flavor(config.gcode_flavor),
|
||||
m_travel_speed(config.travel_speed),
|
||||
m_current_tool(initial_tool),
|
||||
wipe_volumes(wiping_matrix)
|
||||
{
|
||||
// Read absolute value of first layer speed, if given as percentage,
|
||||
// it is taken over following default. Speeds from config are not
|
||||
// easily accessible here.
|
||||
const float default_speed = 60.f;
|
||||
m_first_layer_speed = config.get_abs_value("first_layer_speed", default_speed);
|
||||
if (m_first_layer_speed == 0.f) // just to make sure autospeed doesn't break it.
|
||||
m_first_layer_speed = default_speed / 2.f;
|
||||
|
||||
// If this is a single extruder MM printer, we will use all the SE-specific config values.
|
||||
// Otherwise, the defaults will be used to turn off the SE stuff.
|
||||
if (m_semm) {
|
||||
@ -555,6 +563,7 @@ void WipeTower::set_extruder(size_t idx, const PrintConfig& config)
|
||||
m_filpar.push_back(FilamentParameters());
|
||||
|
||||
m_filpar[idx].material = config.filament_type.get_at(idx);
|
||||
m_filpar[idx].is_soluble = config.filament_soluble.get_at(idx);
|
||||
m_filpar[idx].temperature = config.temperature.get_at(idx);
|
||||
m_filpar[idx].first_layer_temperature = config.first_layer_temperature.get_at(idx);
|
||||
|
||||
@ -679,7 +688,7 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
|
||||
if (m_set_extruder_trimpot)
|
||||
writer.set_extruder_trimpot(550);
|
||||
writer.speed_override_restore()
|
||||
.feedrate(6000)
|
||||
.feedrate(m_travel_speed * 60.f)
|
||||
.flush_planner_queue()
|
||||
.reset_extruder()
|
||||
.append("; CP PRIMING END\n"
|
||||
@ -693,21 +702,14 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
|
||||
m_old_temperature = -1; // If the priming is turned off in config, the temperature changing commands will not actually appear
|
||||
// in the output gcode - we should not remember emitting them (we will output them twice in the worst case)
|
||||
|
||||
// so that tool_change() will know to extrude the wipe tower brim:
|
||||
m_print_brim = true;
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool)
|
||||
{
|
||||
if ( m_print_brim )
|
||||
return toolchange_Brim();
|
||||
|
||||
size_t old_tool = m_current_tool;
|
||||
|
||||
float wipe_area = 0.f;
|
||||
bool last_change_in_layer = false;
|
||||
float wipe_area = 0.f;
|
||||
float wipe_volume = 0.f;
|
||||
|
||||
// Finds this toolchange info
|
||||
@ -715,9 +717,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool)
|
||||
{
|
||||
for (const auto &b : m_layer_info->tool_changes)
|
||||
if ( b.new_tool == tool ) {
|
||||
wipe_volume = b.wipe_volume;
|
||||
if (tool == m_layer_info->tool_changes.back().new_tool)
|
||||
last_change_in_layer = true;
|
||||
wipe_volume = b.wipe_volume;
|
||||
wipe_area = b.required_depth * m_layer_info->extra_spacing;
|
||||
break;
|
||||
}
|
||||
@ -726,17 +726,17 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool)
|
||||
// Otherwise we are going to Unload only. And m_layer_info would be invalid.
|
||||
}
|
||||
|
||||
box_coordinates cleaning_box(
|
||||
box_coordinates cleaning_box(
|
||||
Vec2f(m_perimeter_width / 2.f, m_perimeter_width / 2.f),
|
||||
m_wipe_tower_width - m_perimeter_width,
|
||||
(tool != (unsigned int)(-1) ? /*m_layer_info->depth*/wipe_area+m_depth_traversed-0.5f*m_perimeter_width
|
||||
(tool != (unsigned int)(-1) ? wipe_area+m_depth_traversed-0.5f*m_perimeter_width
|
||||
: m_wipe_tower_depth-m_perimeter_width));
|
||||
|
||||
WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar);
|
||||
writer.set_extrusion_flow(m_extrusion_flow)
|
||||
.set_z(m_z_pos)
|
||||
.set_initial_tool(m_current_tool)
|
||||
.set_y_shift(m_y_shift + (tool!=(unsigned int)(-1) && (m_current_shape == SHAPE_REVERSED && !m_peters_wipe_tower) ? m_layer_info->depth - m_layer_info->toolchanges_depth(): 0.f))
|
||||
.set_y_shift(m_y_shift + (tool!=(unsigned int)(-1) && (m_current_shape == SHAPE_REVERSED) ? m_layer_info->depth - m_layer_info->toolchanges_depth(): 0.f))
|
||||
.append(";--------------------\n"
|
||||
"; CP TOOLCHANGE START\n")
|
||||
.comment_with_value(" toolchange #", m_num_tool_changes + 1); // the number is zero-based
|
||||
@ -758,7 +758,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool)
|
||||
// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
|
||||
if (tool != (unsigned int)-1){ // This is not the last change.
|
||||
toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material,
|
||||
m_is_first_layer ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature);
|
||||
is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature);
|
||||
toolchange_Change(writer, tool, m_filpar[tool].material); // Change the tool, set a speed override for soluble and flex materials.
|
||||
toolchange_Load(writer, cleaning_box);
|
||||
writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road
|
||||
@ -769,24 +769,10 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool)
|
||||
|
||||
m_depth_traversed += wipe_area;
|
||||
|
||||
if (last_change_in_layer) {// draw perimeter line
|
||||
writer.set_y_shift(m_y_shift);
|
||||
if (m_peters_wipe_tower)
|
||||
writer.rectangle(Vec2f::Zero(), m_layer_info->depth + 3*m_perimeter_width, m_wipe_tower_depth);
|
||||
else {
|
||||
writer.rectangle(Vec2f::Zero(), m_wipe_tower_width, m_layer_info->depth + m_perimeter_width);
|
||||
if (layer_finished()) { // no finish_layer will be called, we must wipe the nozzle
|
||||
writer.add_wipe_point(writer.x(), writer.y())
|
||||
.add_wipe_point(writer.x()> m_wipe_tower_width / 2.f ? 0.f : m_wipe_tower_width, writer.y());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_set_extruder_trimpot)
|
||||
writer.set_extruder_trimpot(550); // Reset the extruder current to a normal value.
|
||||
writer.speed_override_restore();
|
||||
writer.feedrate(6000)
|
||||
writer.feedrate(m_travel_speed * 60.f)
|
||||
.flush_planner_queue()
|
||||
.reset_extruder()
|
||||
.append("; CP TOOLCHANGE END\n"
|
||||
@ -800,62 +786,6 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool)
|
||||
return construct_tcr(writer, false, old_tool);
|
||||
}
|
||||
|
||||
WipeTower::ToolChangeResult WipeTower::toolchange_Brim(bool sideOnly, float y_offset)
|
||||
{
|
||||
size_t old_tool = m_current_tool;
|
||||
|
||||
const box_coordinates wipeTower_box(
|
||||
Vec2f::Zero(),
|
||||
m_wipe_tower_width,
|
||||
m_wipe_tower_depth);
|
||||
|
||||
WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar);
|
||||
writer.set_extrusion_flow(m_extrusion_flow * 1.1f)
|
||||
.set_z(m_z_pos) // Let the writer know the current Z position as a base for Z-hop.
|
||||
.set_initial_tool(m_current_tool)
|
||||
.append(";-------------------------------------\n"
|
||||
"; CP WIPE TOWER FIRST LAYER BRIM START\n");
|
||||
|
||||
Vec2f initial_position = wipeTower_box.lu - Vec2f(m_perimeter_width * 6.f, 0);
|
||||
writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
|
||||
|
||||
writer.extrude_explicit(wipeTower_box.ld - Vec2f(m_perimeter_width * 6.f, 0), // Prime the extruder left of the wipe tower.
|
||||
1.5f * m_extrusion_flow * (wipeTower_box.lu.y() - wipeTower_box.ld.y()), 2400);
|
||||
|
||||
// The tool is supposed to be active and primed at the time when the wipe tower brim is extruded.
|
||||
// Extrude 4 rounds of a brim around the future wipe tower.
|
||||
box_coordinates box(wipeTower_box);
|
||||
// the brim shall have 'normal' spacing with no extra void space
|
||||
float spacing = m_perimeter_width - m_layer_height*float(1.-M_PI_4);
|
||||
for (size_t i = 0; i < 4; ++ i) {
|
||||
box.expand(spacing);
|
||||
writer.travel (box.ld, 7000)
|
||||
.extrude(box.lu, 2100).extrude(box.ru)
|
||||
.extrude(box.rd ).extrude(box.ld);
|
||||
}
|
||||
|
||||
box.expand(-spacing);
|
||||
writer.add_wipe_point(writer.x(), writer.y())
|
||||
.add_wipe_point(box.ld)
|
||||
.add_wipe_point(box.rd);
|
||||
|
||||
writer.append("; CP WIPE TOWER FIRST LAYER BRIM END\n"
|
||||
";-----------------------------------\n");
|
||||
|
||||
// Save actual brim width to be later passed to the Print object, which will use it
|
||||
// for skirt calculation and pass it to GLCanvas for precise preview box
|
||||
m_wipe_tower_brim_width = wipeTower_box.ld.x() - box.ld.x() + spacing/2.f;
|
||||
|
||||
m_print_brim = false; // Mark the brim as extruded
|
||||
|
||||
// Ask our writer about how much material was consumed:
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
|
||||
void WipeTower::toolchange_Unload(
|
||||
@ -952,7 +882,7 @@ void WipeTower::toolchange_Unload(
|
||||
// be already set and there is no need to change anything. Also, the temperature could be changed
|
||||
// for wrong extruder.
|
||||
if (m_semm) {
|
||||
if (new_temperature != 0 && (new_temperature != m_old_temperature || m_is_first_layer) ) { // Set the extruder temperature, but don't wait.
|
||||
if (new_temperature != 0 && (new_temperature != m_old_temperature || is_first_layer()) ) { // Set the extruder temperature, but don't wait.
|
||||
// If the required temperature is the same as last time, don't emit the M104 again (if user adjusted the value, it would be reset)
|
||||
// However, always change temperatures on the first layer (this is to avoid issues with priming lines turned off).
|
||||
writer.set_extruder_temp(new_temperature, false);
|
||||
@ -1012,7 +942,10 @@ void WipeTower::toolchange_Change(
|
||||
// gcode could have left the extruder somewhere, we cannot just start extruding. We should also inform the
|
||||
// postprocessor that we absolutely want to have this in the gcode, even if it thought it is the same as before.
|
||||
Vec2f current_pos = writer.pos_rotated();
|
||||
writer.append(std::string("G1 X") + std::to_string(current_pos.x()) + " Y" + std::to_string(current_pos.y()) + never_skip_tag() + "\n");
|
||||
writer.feedrate(m_travel_speed * 60.f) // see https://github.com/prusa3d/PrusaSlicer/issues/5483
|
||||
.append(std::string("G1 X") + std::to_string(current_pos.x())
|
||||
+ " Y" + std::to_string(current_pos.y())
|
||||
+ never_skip_tag() + "\n");
|
||||
|
||||
// The toolchange Tn command will be inserted later, only in case that the user does
|
||||
// not provide a custom toolchange gcode.
|
||||
@ -1058,9 +991,8 @@ void WipeTower::toolchange_Wipe(
|
||||
float wipe_volume)
|
||||
{
|
||||
// Increase flow on first layer, slow down print.
|
||||
writer.set_extrusion_flow(m_extrusion_flow * (m_is_first_layer ? 1.18f : 1.f))
|
||||
writer.set_extrusion_flow(m_extrusion_flow * (is_first_layer() ? 1.18f : 1.f))
|
||||
.append("; CP TOOLCHANGE WIPE\n");
|
||||
float wipe_coeff = m_is_first_layer ? 0.5f : 1.f;
|
||||
const float& xl = cleaning_box.ld.x();
|
||||
const float& xr = cleaning_box.rd.x();
|
||||
|
||||
@ -1070,7 +1002,9 @@ void WipeTower::toolchange_Wipe(
|
||||
|
||||
float x_to_wipe = volume_to_length(wipe_volume, m_perimeter_width, m_layer_height);
|
||||
float dy = m_extra_spacing*m_perimeter_width;
|
||||
float wipe_speed = 1600.f;
|
||||
|
||||
const float target_speed = is_first_layer() ? m_first_layer_speed * 60.f : 4800.f;
|
||||
float wipe_speed = 0.33f * target_speed;
|
||||
|
||||
// if there is less than 2.5*m_perimeter_width to the edge, advance straightaway (there is likely a blob anyway)
|
||||
if ((m_left_to_right ? xr-writer.x() : writer.x()-xl) < 2.5f*m_perimeter_width) {
|
||||
@ -1081,17 +1015,17 @@ void WipeTower::toolchange_Wipe(
|
||||
// now the wiping itself:
|
||||
for (int i = 0; true; ++i) {
|
||||
if (i!=0) {
|
||||
if (wipe_speed < 1610.f) wipe_speed = 1800.f;
|
||||
else if (wipe_speed < 1810.f) wipe_speed = 2200.f;
|
||||
else if (wipe_speed < 2210.f) wipe_speed = 4200.f;
|
||||
else wipe_speed = std::min(4800.f, wipe_speed + 50.f);
|
||||
if (wipe_speed < 0.34f * target_speed) wipe_speed = 0.375f * target_speed;
|
||||
else if (wipe_speed < 0.377 * target_speed) wipe_speed = 0.458f * target_speed;
|
||||
else if (wipe_speed < 0.46f * target_speed) wipe_speed = 0.875f * target_speed;
|
||||
else wipe_speed = std::min(target_speed, wipe_speed + 50.f);
|
||||
}
|
||||
|
||||
float traversed_x = writer.x();
|
||||
if (m_left_to_right)
|
||||
writer.extrude(xr - (i % 4 == 0 ? 0 : 1.5f*m_perimeter_width), writer.y(), wipe_speed * wipe_coeff);
|
||||
writer.extrude(xr - (i % 4 == 0 ? 0 : 1.5f*m_perimeter_width), writer.y(), wipe_speed);
|
||||
else
|
||||
writer.extrude(xl + (i % 4 == 1 ? 0 : 1.5f*m_perimeter_width), writer.y(), wipe_speed * wipe_coeff);
|
||||
writer.extrude(xl + (i % 4 == 1 ? 0 : 1.5f*m_perimeter_width), writer.y(), wipe_speed);
|
||||
|
||||
if (writer.y()+float(EPSILON) > cleaning_box.lu.y()-0.5f*m_perimeter_width)
|
||||
break; // in case next line would not fit
|
||||
@ -1107,17 +1041,16 @@ void WipeTower::toolchange_Wipe(
|
||||
m_left_to_right = !m_left_to_right;
|
||||
}
|
||||
|
||||
// this is neither priming nor not the last toolchange on this layer - we are
|
||||
// going back to the model - wipe the nozzle.
|
||||
if (m_layer_info != m_plan.end() && m_current_tool != m_layer_info->tool_changes.back().new_tool) {
|
||||
// We may be going back to the model - wipe the nozzle. If this is followed
|
||||
// by finish_layer, this wipe path will be overwritten.
|
||||
writer.add_wipe_point(writer.x(), writer.y())
|
||||
.add_wipe_point(writer.x(), writer.y() - dy)
|
||||
.add_wipe_point(! m_left_to_right ? m_wipe_tower_width : 0.f, writer.y() - dy);
|
||||
|
||||
if (m_layer_info != m_plan.end() && m_current_tool != m_layer_info->tool_changes.back().new_tool)
|
||||
m_left_to_right = !m_left_to_right;
|
||||
writer.add_wipe_point(writer.x(), writer.y())
|
||||
.add_wipe_point(writer.x(), writer.y() - dy)
|
||||
.add_wipe_point(m_left_to_right ? m_wipe_tower_width : 0.f, writer.y() - dy);
|
||||
|
||||
}
|
||||
|
||||
writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow.
|
||||
writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow.
|
||||
}
|
||||
|
||||
|
||||
@ -1125,9 +1058,8 @@ void WipeTower::toolchange_Wipe(
|
||||
|
||||
WipeTower::ToolChangeResult WipeTower::finish_layer()
|
||||
{
|
||||
// This should only be called if the layer is not finished yet.
|
||||
// Otherwise the caller would likely travel to the wipe tower in vain.
|
||||
assert(! this->layer_finished());
|
||||
m_current_layer_finished = true;
|
||||
|
||||
size_t old_tool = m_current_tool;
|
||||
|
||||
@ -1135,61 +1067,75 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
|
||||
writer.set_extrusion_flow(m_extrusion_flow)
|
||||
.set_z(m_z_pos)
|
||||
.set_initial_tool(m_current_tool)
|
||||
.set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED && !m_peters_wipe_tower ? m_layer_info->toolchanges_depth() : 0.f))
|
||||
.append(";--------------------\n"
|
||||
"; CP EMPTY GRID START\n")
|
||||
.comment_with_value(" layer #", m_num_layer_changes + 1);
|
||||
.set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f));
|
||||
|
||||
|
||||
// Slow down on the 1st layer.
|
||||
float speed_factor = m_is_first_layer ? 0.5f : 1.f;
|
||||
bool first_layer = is_first_layer();
|
||||
float feedrate = first_layer ? m_first_layer_speed * 60.f : 2900.f;
|
||||
float current_depth = m_layer_info->depth - m_layer_info->toolchanges_depth();
|
||||
box_coordinates fill_box(Vec2f(m_perimeter_width, m_depth_traversed + m_perimeter_width),
|
||||
m_wipe_tower_width - 2 * m_perimeter_width, current_depth-m_perimeter_width);
|
||||
box_coordinates fill_box(Vec2f(m_perimeter_width, m_layer_info->depth-(current_depth-m_perimeter_width)),
|
||||
m_wipe_tower_width - 2 * m_perimeter_width, current_depth-m_perimeter_width);
|
||||
|
||||
|
||||
writer.set_initial_position((m_left_to_right ? fill_box.ru : fill_box.lu), // so there is never a diagonal travel
|
||||
m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
|
||||
|
||||
bool toolchanges_on_layer = m_layer_info->toolchanges_depth() > WT_EPSILON;
|
||||
box_coordinates box = fill_box;
|
||||
for (int i=0;i<2;++i) {
|
||||
if (! toolchanges_on_layer) {
|
||||
if (i==0) box.expand(m_perimeter_width);
|
||||
else box.expand(-m_perimeter_width);
|
||||
}
|
||||
else i=2; // only draw the inner perimeter, outer has been already drawn by tool_change(...)
|
||||
writer.rectangle(box.ld, box.rd.x()-box.ld.x(), box.ru.y()-box.rd.y(), 2900*speed_factor);
|
||||
}
|
||||
box_coordinates wt_box(Vec2f(0.f, (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)),
|
||||
m_wipe_tower_width, m_layer_info->depth + m_perimeter_width);
|
||||
|
||||
// inner perimeter of the sparse section, if there is space for it:
|
||||
if (fill_box.ru.y() - fill_box.rd.y() > m_perimeter_width - WT_EPSILON)
|
||||
writer.rectangle(fill_box.ld, fill_box.rd.x()-fill_box.ld.x(), fill_box.ru.y()-fill_box.rd.y(), feedrate);
|
||||
|
||||
// we are in one of the corners, travel to ld along the perimeter:
|
||||
if (writer.x() > fill_box.ld.x()+EPSILON) writer.travel(fill_box.ld.x(),writer.y());
|
||||
if (writer.y() > fill_box.ld.y()+EPSILON) writer.travel(writer.x(),fill_box.ld.y());
|
||||
|
||||
if (m_is_first_layer && m_adhesion) {
|
||||
// Extrude a dense infill at the 1st layer to improve 1st layer adhesion of the wipe tower.
|
||||
box.expand(-m_perimeter_width/2.f);
|
||||
int nsteps = int(floor((box.lu.y() - box.ld.y()) / (2*m_perimeter_width)));
|
||||
float step = (box.lu.y() - box.ld.y()) / nsteps;
|
||||
writer.travel(box.ld - Vec2f(m_perimeter_width/2.f, m_perimeter_width/2.f));
|
||||
if (nsteps >= 0)
|
||||
for (int i = 0; i < nsteps; ++i) {
|
||||
writer.extrude(box.ld.x()+m_perimeter_width/2.f, writer.y() + 0.5f * step);
|
||||
writer.extrude(box.rd.x() - m_perimeter_width / 2.f, writer.y());
|
||||
writer.extrude(box.rd.x() - m_perimeter_width / 2.f, writer.y() + 0.5f * step);
|
||||
writer.extrude(box.ld.x() + m_perimeter_width / 2.f, writer.y());
|
||||
// Extrude infill to support the material to be printed above.
|
||||
const float dy = (fill_box.lu.y() - fill_box.ld.y() - m_perimeter_width);
|
||||
float left = fill_box.lu.x() + 2*m_perimeter_width;
|
||||
float right = fill_box.ru.x() - 2 * m_perimeter_width;
|
||||
if (dy > m_perimeter_width)
|
||||
{
|
||||
writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f))
|
||||
.append(";--------------------\n"
|
||||
"; CP EMPTY GRID START\n")
|
||||
.comment_with_value(" layer #", m_num_layer_changes + 1);
|
||||
|
||||
// Is there a soluble filament wiped/rammed at the next layer?
|
||||
// If so, the infill should not be sparse.
|
||||
bool solid_infill = m_layer_info+1 == m_plan.end()
|
||||
? false
|
||||
: std::any_of((m_layer_info+1)->tool_changes.begin(),
|
||||
(m_layer_info+1)->tool_changes.end(),
|
||||
[this](const WipeTowerInfo::ToolChange& tch) {
|
||||
return m_filpar[tch.new_tool].is_soluble
|
||||
|| m_filpar[tch.old_tool].is_soluble;
|
||||
});
|
||||
solid_infill |= first_layer && m_adhesion;
|
||||
|
||||
if (solid_infill) {
|
||||
float sparse_factor = 1.5f; // 1=solid, 2=every other line, etc.
|
||||
if (first_layer) { // the infill should touch perimeters
|
||||
left -= m_perimeter_width;
|
||||
right += m_perimeter_width;
|
||||
sparse_factor = 1.f;
|
||||
}
|
||||
writer.add_wipe_point(writer.x(), writer.y())
|
||||
.add_wipe_point(box.rd.x()-m_perimeter_width/2.f,writer.y());
|
||||
}
|
||||
else { // Extrude a sparse infill to support the material to be printed above.
|
||||
const float dy = (fill_box.lu.y() - fill_box.ld.y() - m_perimeter_width);
|
||||
const float left = fill_box.lu.x() + 2*m_perimeter_width;
|
||||
const float right = fill_box.ru.x() - 2 * m_perimeter_width;
|
||||
if (dy > m_perimeter_width)
|
||||
{
|
||||
// Extrude an inverse U at the left of the region.
|
||||
writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f))
|
||||
.extrude(fill_box.lu + Vec2f(m_perimeter_width * 2, 0.f), 2900 * speed_factor);
|
||||
float y = fill_box.ld.y() + m_perimeter_width;
|
||||
int n = dy / (m_perimeter_width * sparse_factor);
|
||||
float spacing = (dy-m_perimeter_width)/(n-1);
|
||||
int i=0;
|
||||
for (i=0; i<n; ++i) {
|
||||
writer.extrude(writer.x(), y, feedrate)
|
||||
.extrude(i%2 ? left : right, y);
|
||||
y = y + spacing;
|
||||
}
|
||||
writer.extrude(writer.x(), fill_box.lu.y());
|
||||
} else {
|
||||
// Extrude an inverse U at the left of the region and the sparse infill.
|
||||
writer.extrude(fill_box.lu + Vec2f(m_perimeter_width * 2, 0.f), feedrate);
|
||||
|
||||
const int n = 1+int((right-left)/m_bridging);
|
||||
const float dx = (right-left)/n;
|
||||
@ -1198,18 +1144,40 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
|
||||
writer.travel(x,writer.y());
|
||||
writer.extrude(x,i%2 ? fill_box.rd.y() : fill_box.ru.y());
|
||||
}
|
||||
writer.add_wipe_point(Vec2f(writer.x(), writer.y()))
|
||||
.add_wipe_point(Vec2f(left, writer.y()));
|
||||
}
|
||||
else {
|
||||
writer.add_wipe_point(Vec2f(writer.x(), writer.y()))
|
||||
.add_wipe_point(Vec2f(right, writer.y()));
|
||||
}
|
||||
}
|
||||
writer.append("; CP EMPTY GRID END\n"
|
||||
";------------------\n\n\n\n\n\n\n");
|
||||
|
||||
m_depth_traversed = m_wipe_tower_depth-m_perimeter_width;
|
||||
writer.append("; CP EMPTY GRID END\n"
|
||||
";------------------\n\n\n\n\n\n\n");
|
||||
}
|
||||
|
||||
// outer perimeter (always):
|
||||
writer.rectangle(wt_box, feedrate);
|
||||
|
||||
// brim (first layer only)
|
||||
if (first_layer) {
|
||||
box_coordinates box = wt_box;
|
||||
float spacing = m_perimeter_width - m_layer_height*float(1.-M_PI_4);
|
||||
// How many perimeters shall the brim have?
|
||||
size_t loops_num = (m_wipe_tower_brim_width + spacing/2.f) / spacing;
|
||||
|
||||
for (size_t i = 0; i < loops_num; ++ i) {
|
||||
box.expand(spacing);
|
||||
writer.rectangle(box);
|
||||
}
|
||||
|
||||
// Save actual brim width to be later passed to the Print object, which will use it
|
||||
// for skirt calculation and pass it to GLCanvas for precise preview box
|
||||
m_wipe_tower_brim_width_real = wt_box.ld.x() - box.ld.x() + spacing/2.f;
|
||||
wt_box = box;
|
||||
}
|
||||
|
||||
// Now prepare future wipe. box contains rectangle that was extruded last (ccw).
|
||||
Vec2f target = (writer.pos() == wt_box.ld ? wt_box.rd :
|
||||
(writer.pos() == wt_box.rd ? wt_box.ru :
|
||||
(writer.pos() == wt_box.ru ? wt_box.lu :
|
||||
wt_box.ld)));
|
||||
writer.add_wipe_point(writer.pos())
|
||||
.add_wipe_point(target);
|
||||
|
||||
|
||||
// Ask our writer about how much material was consumed.
|
||||
@ -1222,23 +1190,22 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
|
||||
}
|
||||
|
||||
// Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box
|
||||
void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, bool brim, float wipe_volume)
|
||||
void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool,
|
||||
unsigned int new_tool, float wipe_volume)
|
||||
{
|
||||
assert(m_plan.empty() || m_plan.back().z <= z_par + WT_EPSILON); // refuses to add a layer below the last one
|
||||
|
||||
if (m_plan.empty() || m_plan.back().z + WT_EPSILON < z_par) // if we moved to a new layer, we'll add it to m_plan first
|
||||
m_plan.push_back(WipeTowerInfo(z_par, layer_height_par));
|
||||
|
||||
if (brim) { // this toolchange prints brim - we must add it to m_plan, but not to count its depth
|
||||
m_plan.back().tool_changes.push_back(WipeTowerInfo::ToolChange(old_tool, new_tool));
|
||||
return;
|
||||
}
|
||||
if (m_first_layer_idx == size_t(-1) && (! m_no_sparse_layers || old_tool != new_tool))
|
||||
m_first_layer_idx = m_plan.size() - 1;
|
||||
|
||||
if (old_tool==new_tool) // new layer without toolchanges - we are done
|
||||
return;
|
||||
if (old_tool == new_tool) // new layer without toolchanges - we are done
|
||||
return;
|
||||
|
||||
// this is an actual toolchange - let's calculate depth to reserve on the wipe tower
|
||||
float depth = 0.f;
|
||||
float depth = 0.f;
|
||||
float width = m_wipe_tower_width - 3*m_perimeter_width;
|
||||
float length_to_extrude = volume_to_length(0.25f * std::accumulate(m_filpar[old_tool].ramming_speed.begin(), m_filpar[old_tool].ramming_speed.end(), 0.f),
|
||||
m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator,
|
||||
@ -1288,28 +1255,65 @@ void WipeTower::save_on_last_wipe()
|
||||
if (m_layer_info->tool_changes.size()==0) // we have no way to save anything on an empty layer
|
||||
continue;
|
||||
|
||||
for (const auto &toolchange : m_layer_info->tool_changes)
|
||||
// Which toolchange will finish_layer extrusions be subtracted from?
|
||||
int idx = first_toolchange_to_nonsoluble(m_layer_info->tool_changes);
|
||||
|
||||
for (int i=0; i<int(m_layer_info->tool_changes.size()); ++i) {
|
||||
auto& toolchange = m_layer_info->tool_changes[i];
|
||||
tool_change(toolchange.new_tool);
|
||||
|
||||
float width = m_wipe_tower_width - 3*m_perimeter_width; // width we draw into
|
||||
float length_to_save = 2*(m_wipe_tower_width+m_wipe_tower_depth) + (!layer_finished() ? finish_layer().total_extrusion_length_in_plane() : 0.f);
|
||||
float length_to_wipe = volume_to_length(m_layer_info->tool_changes.back().wipe_volume,
|
||||
m_perimeter_width,m_layer_info->height) - m_layer_info->tool_changes.back().first_wipe_line - length_to_save;
|
||||
if (i == idx) {
|
||||
float width = m_wipe_tower_width - 3*m_perimeter_width; // width we draw into
|
||||
float length_to_save = finish_layer().total_extrusion_length_in_plane();
|
||||
float length_to_wipe = volume_to_length(toolchange.wipe_volume,
|
||||
m_perimeter_width, m_layer_info->height) - toolchange.first_wipe_line - length_to_save;
|
||||
|
||||
length_to_wipe = std::max(length_to_wipe,0.f);
|
||||
float depth_to_wipe = m_perimeter_width * (std::floor(length_to_wipe/width) + ( length_to_wipe > 0.f ? 1.f : 0.f ) ) * m_extra_spacing;
|
||||
length_to_wipe = std::max(length_to_wipe,0.f);
|
||||
float depth_to_wipe = m_perimeter_width * (std::floor(length_to_wipe/width) + ( length_to_wipe > 0.f ? 1.f : 0.f ) ) * m_extra_spacing;
|
||||
|
||||
//depth += (int(length_to_extrude / width) + 1) * m_perimeter_width;
|
||||
m_layer_info->tool_changes.back().required_depth = m_layer_info->tool_changes.back().ramming_depth + depth_to_wipe;
|
||||
toolchange.required_depth = toolchange.ramming_depth + depth_to_wipe;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Return index of first toolchange that switches to non-soluble extruder
|
||||
// ot -1 if there is no such toolchange.
|
||||
int WipeTower::first_toolchange_to_nonsoluble(
|
||||
const std::vector<WipeTowerInfo::ToolChange>& tool_changes) const
|
||||
{
|
||||
for (size_t idx=0; idx<tool_changes.size(); ++idx)
|
||||
if (! m_filpar[tool_changes[idx].new_tool].is_soluble)
|
||||
return idx;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult& first,
|
||||
WipeTower::ToolChangeResult& second)
|
||||
{
|
||||
assert(first.new_tool == second.initial_tool);
|
||||
WipeTower::ToolChangeResult out = first;
|
||||
if (first.end_pos != second.start_pos) {
|
||||
char buf[2048]; // Add a travel move from tc1.end_pos to tc2.start_pos.
|
||||
sprintf(buf, "G1 X%.3f Y%.3f F7200\n", second.start_pos.x(), second.start_pos.y());
|
||||
out.gcode += buf;
|
||||
}
|
||||
out.gcode += second.gcode;
|
||||
out.extrusions.insert(out.extrusions.end(), second.extrusions.begin(), second.extrusions.end());
|
||||
out.end_pos = second.end_pos;
|
||||
out.wipe_path = second.wipe_path;
|
||||
out.initial_tool = first.initial_tool;
|
||||
out.new_tool = second.new_tool;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
// Processes vector m_plan and calls respective functions to generate G-code for the wipe tower
|
||||
// Resulting ToolChangeResults are appended into vector "result"
|
||||
void WipeTower::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &result)
|
||||
{
|
||||
if (m_plan.empty())
|
||||
|
||||
return;
|
||||
|
||||
m_extra_spacing = 1.f;
|
||||
@ -1320,9 +1324,6 @@ void WipeTower::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &
|
||||
plan_tower();
|
||||
}
|
||||
|
||||
if (m_peters_wipe_tower)
|
||||
make_wipe_tower_square();
|
||||
|
||||
m_layer_info = m_plan.begin();
|
||||
|
||||
// we don't know which extruder to start with - we'll set it according to the first toolchange
|
||||
@ -1341,65 +1342,41 @@ void WipeTower::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &
|
||||
std::vector<WipeTower::ToolChangeResult> layer_result;
|
||||
for (auto layer : m_plan)
|
||||
{
|
||||
set_layer(layer.z,layer.height,0,layer.z == m_plan.front().z,layer.z == m_plan.back().z);
|
||||
if (m_peters_wipe_tower)
|
||||
m_internal_rotation += 90.f;
|
||||
else
|
||||
m_internal_rotation += 180.f;
|
||||
set_layer(layer.z, layer.height, 0, false/*layer.z == m_plan.front().z*/, layer.z == m_plan.back().z);
|
||||
m_internal_rotation += 180.f;
|
||||
|
||||
if (!m_peters_wipe_tower && m_layer_info->depth < m_wipe_tower_depth - m_perimeter_width)
|
||||
if (m_layer_info->depth < m_wipe_tower_depth - m_perimeter_width)
|
||||
m_y_shift = (m_wipe_tower_depth-m_layer_info->depth-m_perimeter_width)/2.f;
|
||||
|
||||
for (const auto &toolchange : layer.tool_changes)
|
||||
layer_result.emplace_back(tool_change(toolchange.new_tool));
|
||||
int idx = first_toolchange_to_nonsoluble(layer.tool_changes);
|
||||
ToolChangeResult finish_layer_tcr;
|
||||
|
||||
if (! layer_finished()) {
|
||||
auto finish_layer_toolchange = finish_layer();
|
||||
if ( ! layer.tool_changes.empty() ) { // we will merge it to the last toolchange
|
||||
auto& last_toolchange = layer_result.back();
|
||||
if (last_toolchange.end_pos != finish_layer_toolchange.start_pos) {
|
||||
char buf[2048]; // Add a travel move from tc1.end_pos to tc2.start_pos.
|
||||
sprintf(buf, "G1 X%.3f Y%.3f F7200\n", finish_layer_toolchange.start_pos.x(), finish_layer_toolchange.start_pos.y());
|
||||
last_toolchange.gcode += buf;
|
||||
}
|
||||
last_toolchange.gcode += finish_layer_toolchange.gcode;
|
||||
last_toolchange.extrusions.insert(last_toolchange.extrusions.end(), finish_layer_toolchange.extrusions.begin(), finish_layer_toolchange.extrusions.end());
|
||||
last_toolchange.end_pos = finish_layer_toolchange.end_pos;
|
||||
last_toolchange.wipe_path = finish_layer_toolchange.wipe_path;
|
||||
}
|
||||
if (idx == -1) {
|
||||
// if there is no toolchange switching to non-soluble, finish layer
|
||||
// will be called at the very beginning. That's the last possibility
|
||||
// where a nonsoluble tool can be.
|
||||
finish_layer_tcr = finish_layer();
|
||||
}
|
||||
|
||||
for (int i=0; i<int(layer.tool_changes.size()); ++i) {
|
||||
layer_result.emplace_back(tool_change(layer.tool_changes[i].new_tool));
|
||||
if (i == idx) // finish_layer will be called after this toolchange
|
||||
finish_layer_tcr = finish_layer();
|
||||
}
|
||||
|
||||
if (layer_result.empty()) {
|
||||
// there is nothing to merge finish_layer with
|
||||
layer_result.emplace_back(std::move(finish_layer_tcr));
|
||||
}
|
||||
else {
|
||||
if (idx == -1)
|
||||
layer_result[0] = merge_tcr(finish_layer_tcr, layer_result[0]);
|
||||
else
|
||||
layer_result.emplace_back(std::move(finish_layer_toolchange));
|
||||
layer_result[idx] = merge_tcr(layer_result[idx], finish_layer_tcr);
|
||||
}
|
||||
|
||||
result.emplace_back(std::move(layer_result));
|
||||
m_is_first_layer = false;
|
||||
}
|
||||
}
|
||||
|
||||
void WipeTower::make_wipe_tower_square()
|
||||
{
|
||||
const float width = m_wipe_tower_width - 3 * m_perimeter_width;
|
||||
const float depth = m_wipe_tower_depth - m_perimeter_width;
|
||||
// area that we actually print into is width*depth
|
||||
float side = sqrt(depth * width);
|
||||
|
||||
m_wipe_tower_width = side + 3 * m_perimeter_width;
|
||||
m_wipe_tower_depth = side + 2 * m_perimeter_width;
|
||||
// For all layers, find how depth changed and update all toolchange depths
|
||||
for (auto &lay : m_plan)
|
||||
{
|
||||
side = sqrt(lay.depth * width);
|
||||
float width_ratio = width / side;
|
||||
|
||||
//lay.extra_spacing = width_ratio;
|
||||
for (auto &tch : lay.tool_changes)
|
||||
tch.required_depth *= width_ratio;
|
||||
}
|
||||
|
||||
plan_tower(); // propagates depth downwards again (width has changed)
|
||||
for (auto& lay : m_plan) // depths set, now the spacing
|
||||
lay.extra_spacing = lay.depth / lay.toolchanges_depth();
|
||||
}
|
||||
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -84,6 +84,37 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct box_coordinates
|
||||
{
|
||||
box_coordinates(float left, float bottom, float width, float height) :
|
||||
ld(left , bottom ),
|
||||
lu(left , bottom + height),
|
||||
rd(left + width, bottom ),
|
||||
ru(left + width, bottom + height) {}
|
||||
box_coordinates(const Vec2f &pos, float width, float height) : box_coordinates(pos(0), pos(1), width, height) {}
|
||||
void translate(const Vec2f &shift) {
|
||||
ld += shift; lu += shift;
|
||||
rd += shift; ru += shift;
|
||||
}
|
||||
void translate(const float dx, const float dy) { translate(Vec2f(dx, dy)); }
|
||||
void expand(const float offset) {
|
||||
ld += Vec2f(- offset, - offset);
|
||||
lu += Vec2f(- offset, offset);
|
||||
rd += Vec2f( offset, - offset);
|
||||
ru += Vec2f( offset, offset);
|
||||
}
|
||||
void expand(const float offset_x, const float offset_y) {
|
||||
ld += Vec2f(- offset_x, - offset_y);
|
||||
lu += Vec2f(- offset_x, offset_y);
|
||||
rd += Vec2f( offset_x, - offset_y);
|
||||
ru += Vec2f( offset_x, offset_y);
|
||||
}
|
||||
Vec2f ld; // left down
|
||||
Vec2f lu; // left upper
|
||||
Vec2f rd; // right lower
|
||||
Vec2f ru; // right upper
|
||||
};
|
||||
|
||||
// Construct ToolChangeResult from current state of WipeTower and WipeTowerWriter.
|
||||
// WipeTowerWriter is moved from !
|
||||
ToolChangeResult construct_tcr(WipeTowerWriter& writer,
|
||||
@ -102,13 +133,13 @@ public:
|
||||
|
||||
// Appends into internal structure m_plan containing info about the future wipe tower
|
||||
// to be used before building begins. The entries must be added ordered in z.
|
||||
void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, bool brim, float wipe_volume = 0.f);
|
||||
void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, float wipe_volume = 0.f);
|
||||
|
||||
// Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result"
|
||||
void generate(std::vector<std::vector<ToolChangeResult>> &result);
|
||||
|
||||
float get_depth() const { return m_wipe_tower_depth; }
|
||||
float get_brim_width() const { return m_wipe_tower_brim_width; }
|
||||
float get_brim_width() const { return m_wipe_tower_brim_width_real; }
|
||||
|
||||
|
||||
|
||||
@ -129,9 +160,8 @@ public:
|
||||
{
|
||||
m_z_pos = print_z;
|
||||
m_layer_height = layer_height;
|
||||
m_is_first_layer = is_first_layer;
|
||||
m_print_brim = is_first_layer;
|
||||
m_depth_traversed = 0.f;
|
||||
m_current_layer_finished = false;
|
||||
m_current_shape = (! is_first_layer && m_current_shape == SHAPE_NORMAL) ? SHAPE_REVERSED : SHAPE_NORMAL;
|
||||
if (is_first_layer) {
|
||||
this->m_num_layer_changes = 0;
|
||||
@ -175,7 +205,7 @@ public:
|
||||
|
||||
// Is the current layer finished?
|
||||
bool layer_finished() const {
|
||||
return ( (m_is_first_layer ? m_wipe_tower_depth - m_perimeter_width : m_layer_info->depth) - WT_EPSILON < m_depth_traversed);
|
||||
return m_current_layer_finished;
|
||||
}
|
||||
|
||||
std::vector<float> get_used_filament() const { return m_used_filament_length; }
|
||||
@ -183,6 +213,7 @@ public:
|
||||
|
||||
struct FilamentParameters {
|
||||
std::string material = "PLA";
|
||||
bool is_soluble = false;
|
||||
int temperature = 0;
|
||||
int first_layer_temperature = 0;
|
||||
float loading_speed = 0.f;
|
||||
@ -208,7 +239,6 @@ private:
|
||||
SHAPE_REVERSED = -1
|
||||
};
|
||||
|
||||
const bool m_peters_wipe_tower = false; // sparse wipe tower inspired by Peter's post processor - not finished yet
|
||||
const float Width_To_Nozzle_Ratio = 1.25f; // desired line width (oval) in multiples of nozzle diameter - may not be actually neccessary to adjust
|
||||
const float WT_EPSILON = 1e-3f;
|
||||
float filament_area() const {
|
||||
@ -220,15 +250,18 @@ private:
|
||||
Vec2f m_wipe_tower_pos; // Left front corner of the wipe tower in mm.
|
||||
float m_wipe_tower_width; // Width of the wipe tower.
|
||||
float m_wipe_tower_depth = 0.f; // Depth of the wipe tower
|
||||
float m_wipe_tower_brim_width = 0.f; // Width of brim (mm)
|
||||
float m_wipe_tower_brim_width = 0.f; // Width of brim (mm) from config
|
||||
float m_wipe_tower_brim_width_real = 0.f; // Width of brim (mm) after generation
|
||||
float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis)
|
||||
float m_internal_rotation = 0.f;
|
||||
float m_y_shift = 0.f; // y shift passed to writer
|
||||
float m_z_pos = 0.f; // Current Z position.
|
||||
float m_layer_height = 0.f; // Current layer height.
|
||||
size_t m_max_color_changes = 0; // Maximum number of color changes per layer.
|
||||
bool m_is_first_layer = false;// Is this the 1st layer of the print? If so, print the brim around the waste tower.
|
||||
int m_old_temperature = -1; // To keep track of what was the last temp that we set (so we don't issue the command when not neccessary)
|
||||
float m_travel_speed = 0.f;
|
||||
float m_first_layer_speed = 0.f;
|
||||
size_t m_first_layer_idx = size_t(-1);
|
||||
|
||||
// G-code generator parameters.
|
||||
float m_cooling_tube_retraction = 0.f;
|
||||
@ -267,9 +300,12 @@ private:
|
||||
const std::vector<std::vector<float>> wipe_volumes;
|
||||
|
||||
float m_depth_traversed = 0.f; // Current y position at the wipe tower.
|
||||
bool m_current_layer_finished = false;
|
||||
bool m_left_to_right = true;
|
||||
float m_extra_spacing = 1.f;
|
||||
|
||||
bool is_first_layer() const { return size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; }
|
||||
|
||||
// Calculates extrusion flow needed to produce required line width for given layer height
|
||||
float extrusion_flow(float layer_height = -1.f) const // negative layer_height - return current m_extrusion_flow
|
||||
{
|
||||
@ -293,39 +329,7 @@ private:
|
||||
void save_on_last_wipe();
|
||||
|
||||
|
||||
struct box_coordinates
|
||||
{
|
||||
box_coordinates(float left, float bottom, float width, float height) :
|
||||
ld(left , bottom ),
|
||||
lu(left , bottom + height),
|
||||
rd(left + width, bottom ),
|
||||
ru(left + width, bottom + height) {}
|
||||
box_coordinates(const Vec2f &pos, float width, float height) : box_coordinates(pos(0), pos(1), width, height) {}
|
||||
void translate(const Vec2f &shift) {
|
||||
ld += shift; lu += shift;
|
||||
rd += shift; ru += shift;
|
||||
}
|
||||
void translate(const float dx, const float dy) { translate(Vec2f(dx, dy)); }
|
||||
void expand(const float offset) {
|
||||
ld += Vec2f(- offset, - offset);
|
||||
lu += Vec2f(- offset, offset);
|
||||
rd += Vec2f( offset, - offset);
|
||||
ru += Vec2f( offset, offset);
|
||||
}
|
||||
void expand(const float offset_x, const float offset_y) {
|
||||
ld += Vec2f(- offset_x, - offset_y);
|
||||
lu += Vec2f(- offset_x, offset_y);
|
||||
rd += Vec2f( offset_x, - offset_y);
|
||||
ru += Vec2f( offset_x, offset_y);
|
||||
}
|
||||
Vec2f ld; // left down
|
||||
Vec2f lu; // left upper
|
||||
Vec2f rd; // right lower
|
||||
Vec2f ru; // right upper
|
||||
};
|
||||
|
||||
|
||||
// to store information about tool changes for a given layer
|
||||
// to store information about tool changes for a given layer
|
||||
struct WipeTowerInfo{
|
||||
struct ToolChange {
|
||||
size_t old_tool;
|
||||
@ -355,11 +359,10 @@ private:
|
||||
// Stores information about used filament length per extruder:
|
||||
std::vector<float> m_used_filament_length;
|
||||
|
||||
|
||||
// Returns gcode for wipe tower brim
|
||||
// sideOnly -- set to false -- experimental, draw brim on sides of wipe tower
|
||||
// offset -- set to 0 -- experimental, offset to replace brim in front / rear of wipe tower
|
||||
ToolChangeResult toolchange_Brim(bool sideOnly = false, float y_offset = 0.f);
|
||||
// Return index of first toolchange that switches to non-soluble extruder
|
||||
// ot -1 if there is no such toolchange.
|
||||
int first_toolchange_to_nonsoluble(
|
||||
const std::vector<WipeTowerInfo::ToolChange>& tool_changes) const;
|
||||
|
||||
void toolchange_Unload(
|
||||
WipeTowerWriter &writer,
|
||||
@ -385,6 +388,6 @@ private:
|
||||
|
||||
|
||||
|
||||
}; // namespace Slic3r
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // WipeTowerPrusaMM_hpp_
|
||||
|
@ -20,7 +20,8 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
|
||||
this->config.apply(print_config, true);
|
||||
m_extrusion_axis = this->config.get_extrusion_axis();
|
||||
m_single_extruder_multi_material = print_config.single_extruder_multi_material.value;
|
||||
m_max_acceleration = std::lrint((print_config.gcode_flavor.value == gcfMarlin && print_config.machine_limits_usage.value == MachineLimitsUsage::EmitToGCode) ?
|
||||
bool is_marlin = print_config.gcode_flavor.value == gcfMarlinLegacy || print_config.gcode_flavor.value == gcfMarlinFirmware;
|
||||
m_max_acceleration = std::lrint((is_marlin && print_config.machine_limits_usage.value == MachineLimitsUsage::EmitToGCode) ?
|
||||
print_config.machine_max_acceleration_extruding.values.front() : 0);
|
||||
}
|
||||
|
||||
@ -48,7 +49,8 @@ std::string GCodeWriter::preamble()
|
||||
}
|
||||
if (FLAVOR_IS(gcfRepRapSprinter) ||
|
||||
FLAVOR_IS(gcfRepRapFirmware) ||
|
||||
FLAVOR_IS(gcfMarlin) ||
|
||||
FLAVOR_IS(gcfMarlinLegacy) ||
|
||||
FLAVOR_IS(gcfMarlinFirmware) ||
|
||||
FLAVOR_IS(gcfTeacup) ||
|
||||
FLAVOR_IS(gcfRepetier) ||
|
||||
FLAVOR_IS(gcfSmoothie))
|
||||
@ -205,8 +207,12 @@ std::string GCodeWriter::set_acceleration(unsigned int acceleration)
|
||||
// M202: Set max travel acceleration
|
||||
gcode << "M202 X" << acceleration << " Y" << acceleration;
|
||||
} else if (FLAVOR_IS(gcfRepRapFirmware)) {
|
||||
// M204: Set default acceleration
|
||||
gcode << "M204 P" << acceleration;
|
||||
// M204: Set default acceleration
|
||||
gcode << "M204 P" << acceleration;
|
||||
} else if (FLAVOR_IS(gcfMarlinFirmware)) {
|
||||
// This is new MarlinFirmware with separated print/retraction/travel acceleration.
|
||||
// Use M204 P, we don't want to override travel acc by M204 S (which is deprecated anyway).
|
||||
gcode << "M204 P" << acceleration;
|
||||
} else {
|
||||
// M204: Set default acceleration
|
||||
gcode << "M204 S" << acceleration;
|
||||
|
@ -245,8 +245,7 @@ Polygon convex_hull(Points points)
|
||||
return hull;
|
||||
}
|
||||
|
||||
Pointf3s
|
||||
convex_hull(Pointf3s points)
|
||||
Pointf3s convex_hull(Pointf3s points)
|
||||
{
|
||||
assert(points.size() >= 3);
|
||||
// sort input points
|
||||
@ -304,8 +303,7 @@ convex_hull(Pointf3s points)
|
||||
return hull;
|
||||
}
|
||||
|
||||
Polygon
|
||||
convex_hull(const Polygons &polygons)
|
||||
Polygon convex_hull(const Polygons &polygons)
|
||||
{
|
||||
Points pp;
|
||||
for (Polygons::const_iterator p = polygons.begin(); p != polygons.end(); ++p) {
|
||||
@ -1089,11 +1087,13 @@ bool
|
||||
MedialAxis::validate_edge(const VD::edge_type* edge)
|
||||
{
|
||||
// prevent overflows and detect almost-infinite edges
|
||||
#ifndef CLIPPERLIB_INT32
|
||||
if (std::abs(edge->vertex0()->x()) > double(CLIPPER_MAX_COORD_UNSCALED) ||
|
||||
std::abs(edge->vertex0()->y()) > double(CLIPPER_MAX_COORD_UNSCALED) ||
|
||||
std::abs(edge->vertex1()->x()) > double(CLIPPER_MAX_COORD_UNSCALED) ||
|
||||
std::abs(edge->vertex1()->y()) > double(CLIPPER_MAX_COORD_UNSCALED))
|
||||
return false;
|
||||
#endif // CLIPPERLIB_INT32
|
||||
|
||||
// construct the line representing this edge of the Voronoi diagram
|
||||
const Line line(
|
||||
|
@ -299,20 +299,23 @@ bool liang_barsky_line_clipping(
|
||||
|
||||
// Ugly named variant, that accepts the squared line
|
||||
// Don't call me with a nearly zero length vector!
|
||||
// sympy:
|
||||
// factor(solve([a * x + b * y + c, x**2 + y**2 - r**2], [x, y])[0])
|
||||
// factor(solve([a * x + b * y + c, x**2 + y**2 - r**2], [x, y])[1])
|
||||
template<typename T>
|
||||
int ray_circle_intersections_r2_lv2_c(T r2, T a, T b, T lv2, T c, std::pair<Eigen::Matrix<T, 2, 1, Eigen::DontAlign>, Eigen::Matrix<T, 2, 1, Eigen::DontAlign>> &out)
|
||||
{
|
||||
T d = r2 - c * c / lv2;
|
||||
if (d < T(0))
|
||||
T d2 = r2 * lv2 - c * c;
|
||||
if (d2 < T(0))
|
||||
return 0;
|
||||
T x0 = - a * c / lv2;
|
||||
T y0 = - b * c / lv2;
|
||||
T mult = sqrt(d / lv2);
|
||||
out.first.x() = x0 + b * mult;
|
||||
out.first.y() = y0 - a * mult;
|
||||
out.second.x() = x0 - b * mult;
|
||||
out.second.y() = y0 + a * mult;
|
||||
return mult == T(0) ? 1 : 2;
|
||||
T x0 = - a * c;
|
||||
T y0 = - b * c;
|
||||
T d = sqrt(d2);
|
||||
out.first.x() = (x0 + b * d) / lv2;
|
||||
out.first.y() = (y0 - a * d) / lv2;
|
||||
out.second.x() = (x0 - b * d) / lv2;
|
||||
out.second.y() = (y0 + a * d) / lv2;
|
||||
return d == T(0) ? 1 : 2;
|
||||
}
|
||||
template<typename T>
|
||||
int ray_circle_intersections(T r, T a, T b, T c, std::pair<Eigen::Matrix<T, 2, 1, Eigen::DontAlign>, Eigen::Matrix<T, 2, 1, Eigen::DontAlign>> &out)
|
||||
|
@ -59,7 +59,10 @@ public:
|
||||
// (this collection contains only ExtrusionEntityCollection objects)
|
||||
ExtrusionEntityCollection fills;
|
||||
|
||||
Flow flow(FlowRole role, bool bridge = false, double width = -1) const;
|
||||
Flow flow(FlowRole role) const;
|
||||
Flow flow(FlowRole role, double layer_height) const;
|
||||
Flow bridging_flow(FlowRole role) const;
|
||||
|
||||
void slices_to_fill_surfaces_clipped();
|
||||
void prepare_fill_surfaces();
|
||||
void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces);
|
||||
@ -97,6 +100,7 @@ typedef std::vector<LayerRegion*> LayerRegionPtrs;
|
||||
class Layer
|
||||
{
|
||||
public:
|
||||
// Sequential index of this layer in PrintObject::m_layers, offsetted by the number of raft layers.
|
||||
size_t id() const { return m_id; }
|
||||
void set_id(size_t id) { m_id = id; }
|
||||
PrintObject* object() { return m_object; }
|
||||
@ -112,7 +116,7 @@ public:
|
||||
|
||||
// Collection of expolygons generated by slicing the possibly multiple meshes of the source geometry
|
||||
// (with possibly differing extruder ID and slicing parameters) and merged.
|
||||
// For the first layer, if the ELephant foot compensation is applied, this lslice is uncompensated, therefore
|
||||
// For the first layer, if the Elephant foot compensation is applied, this lslice is uncompensated, therefore
|
||||
// it includes the Elephant foot effect, thus it corresponds to the shape of the printed 1st layer.
|
||||
// These lslices aka islands are chained by the shortest traverse distance and this traversal
|
||||
// order will be applied by the G-code generator to the extrusions fitting into these lslices.
|
||||
@ -167,7 +171,7 @@ protected:
|
||||
virtual ~Layer();
|
||||
|
||||
private:
|
||||
// sequential number of layer, 0-based
|
||||
// Sequential index of layer, 0-based, offsetted by number of raft layers.
|
||||
size_t m_id;
|
||||
PrintObject *m_object;
|
||||
LayerRegionPtrs m_regions;
|
||||
|
@ -15,16 +15,31 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
Flow LayerRegion::flow(FlowRole role, bool bridge, double width) const
|
||||
Flow LayerRegion::flow(FlowRole role) const
|
||||
{
|
||||
return m_region->flow(
|
||||
role,
|
||||
m_layer->height,
|
||||
bridge,
|
||||
m_layer->id() == 0,
|
||||
width,
|
||||
*m_layer->object()
|
||||
);
|
||||
return this->flow(role, m_layer->height);
|
||||
}
|
||||
|
||||
Flow LayerRegion::flow(FlowRole role, double layer_height) const
|
||||
{
|
||||
return m_region->flow(*m_layer->object(), role, layer_height, m_layer->id() == 0);
|
||||
}
|
||||
|
||||
Flow LayerRegion::bridging_flow(FlowRole role) const
|
||||
{
|
||||
const PrintRegion ®ion = *this->region();
|
||||
const PrintRegionConfig ®ion_config = region.config();
|
||||
if (this->layer()->object()->config().thick_bridges) {
|
||||
// The old Slic3r way (different from all other slicers): Use rounded extrusions.
|
||||
// Get the configured nozzle_diameter for the extruder associated to the flow role requested.
|
||||
// Here this->extruder(role) - 1 may underflow to MAX_INT, but then the get_at() will follback to zero'th element, so everything is all right.
|
||||
auto nozzle_diameter = float(region.print()->config().nozzle_diameter.get_at(region.extruder(role) - 1));
|
||||
// Applies default bridge spacing.
|
||||
return Flow::bridging_flow(float(sqrt(region_config.bridge_flow_ratio)) * nozzle_diameter, nozzle_diameter);
|
||||
} else {
|
||||
// The same way as other slicers: Use normal extrusions. Apply bridge_flow_ratio while maintaining the original spacing.
|
||||
return this->flow(role).with_flow_ratio(region_config.bridge_flow_ratio);
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in layerm->fill_surfaces by trimming the layerm->slices by the cummulative layerm->fill_surfaces.
|
||||
@ -59,6 +74,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
|
||||
const PrintRegionConfig ®ion_config = this->region()->config();
|
||||
// This needs to be in sync with PrintObject::_slice() slicing_mode_normal_below_layer!
|
||||
bool spiral_vase = print_config.spiral_vase &&
|
||||
//FIXME account for raft layers.
|
||||
(this->layer()->id() >= size_t(region_config.bottom_solid_layers.value) &&
|
||||
this->layer()->print_z >= region_config.bottom_solid_min_thickness - EPSILON);
|
||||
|
||||
@ -84,7 +100,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
|
||||
|
||||
g.layer_id = (int)this->layer()->id();
|
||||
g.ext_perimeter_flow = this->flow(frExternalPerimeter);
|
||||
g.overhang_flow = this->region()->flow(frPerimeter, -1, true, false, -1, *this->layer()->object());
|
||||
g.overhang_flow = this->bridging_flow(frPerimeter);
|
||||
g.solid_infill_flow = this->flow(frSolidInfill);
|
||||
|
||||
g.process();
|
||||
@ -200,7 +216,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
|
||||
break;
|
||||
}
|
||||
// Grown by 3mm.
|
||||
Polygons polys = offset(to_polygons(bridges[i].expolygon), margin, EXTERNAL_SURFACES_OFFSET_PARAMETERS);
|
||||
Polygons polys = offset(bridges[i].expolygon, margin, EXTERNAL_SURFACES_OFFSET_PARAMETERS);
|
||||
if (idx_island == -1) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Bridge did not fall into the source region!";
|
||||
} else {
|
||||
@ -266,11 +282,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
|
||||
// would get merged into a single one while they need different directions
|
||||
// also, supply the original expolygon instead of the grown one, because in case
|
||||
// of very thin (but still working) anchors, the grown expolygon would go beyond them
|
||||
BridgeDetector bd(
|
||||
initial,
|
||||
lower_layer->lslices,
|
||||
this->flow(frInfill, true).scaled_width()
|
||||
);
|
||||
BridgeDetector bd(initial, lower_layer->lslices, this->bridging_flow(frInfill).scaled_width());
|
||||
#ifdef SLIC3R_DEBUG
|
||||
printf("Processing bridge at layer %zu:\n", this->layer()->id());
|
||||
#endif
|
||||
|
@ -106,13 +106,8 @@ template<class C> bool all_of(const C &container)
|
||||
});
|
||||
}
|
||||
|
||||
template<class T> struct remove_cvref
|
||||
{
|
||||
using type =
|
||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||
};
|
||||
|
||||
template<class T> using remove_cvref_t = typename remove_cvref<T>::type;
|
||||
template<class T>
|
||||
using remove_cvref_t = std::remove_reference_t<std::remove_cv_t<T>>;
|
||||
|
||||
/// Exactly like Matlab https://www.mathworks.com/help/matlab/ref/linspace.html
|
||||
template<class T, class I, class = IntegerOnly<I>>
|
||||
|
@ -110,33 +110,19 @@ struct CGALMesh { _EpicMesh m; };
|
||||
// Converions from and to CGAL mesh
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class _Mesh> void triangle_mesh_to_cgal(const TriangleMesh &M, _Mesh &out)
|
||||
template<class _Mesh>
|
||||
void triangle_mesh_to_cgal(const std::vector<stl_vertex> & V,
|
||||
const std::vector<stl_triangle_vertex_indices> &F,
|
||||
_Mesh &out)
|
||||
{
|
||||
using Index3 = std::array<size_t, 3>;
|
||||
if (F.empty()) return;
|
||||
|
||||
if (M.empty()) return;
|
||||
for (auto &v : V)
|
||||
out.add_vertex(typename _Mesh::Point{v.x(), v.y(), v.z()});
|
||||
|
||||
std::vector<typename _Mesh::Point> points;
|
||||
std::vector<Index3> indices;
|
||||
points.reserve(M.its.vertices.size());
|
||||
indices.reserve(M.its.indices.size());
|
||||
for (auto &v : M.its.vertices) points.emplace_back(v.x(), v.y(), v.z());
|
||||
for (auto &_f : M.its.indices) {
|
||||
auto f = _f.cast<size_t>();
|
||||
indices.emplace_back(Index3{f(0), f(1), f(2)});
|
||||
}
|
||||
|
||||
CGALProc::orient_polygon_soup(points, indices);
|
||||
CGALProc::polygon_soup_to_polygon_mesh(points, indices, out);
|
||||
|
||||
// Number the faces because 'orient_to_bound_a_volume' needs a face <--> index map
|
||||
unsigned index = 0;
|
||||
for (auto face : out.faces()) face = CGAL::SM_Face_index(index++);
|
||||
|
||||
if(CGAL::is_closed(out))
|
||||
CGALProc::orient_to_bound_a_volume(out);
|
||||
else
|
||||
throw Slic3r::RuntimeError("Mesh not watertight");
|
||||
using VI = typename _Mesh::Vertex_index;
|
||||
for (auto &f : F)
|
||||
out.add_face(VI(f(0)), VI(f(1)), VI(f(2)));
|
||||
}
|
||||
|
||||
inline Vec3d to_vec3d(const _EpicMesh::Point &v)
|
||||
@ -164,22 +150,30 @@ template<class _Mesh> TriangleMesh cgal_to_triangle_mesh(const _Mesh &cgalmesh)
|
||||
}
|
||||
|
||||
for (auto &face : cgalmesh.faces()) {
|
||||
auto vtc = cgalmesh.vertices_around_face(cgalmesh.halfedge(face));
|
||||
int i = 0;
|
||||
Vec3i trface;
|
||||
for (auto v : vtc) trface(i++) = static_cast<int>(v);
|
||||
facets.emplace_back(trface);
|
||||
auto vtc = cgalmesh.vertices_around_face(cgalmesh.halfedge(face));
|
||||
|
||||
int i = 0;
|
||||
Vec3i facet;
|
||||
for (auto v : vtc) {
|
||||
if (i > 2) { i = 0; break; }
|
||||
facet(i++) = v;
|
||||
}
|
||||
|
||||
if (i == 3)
|
||||
facets.emplace_back(facet);
|
||||
}
|
||||
|
||||
TriangleMesh out{points, facets};
|
||||
out.require_shared_vertices();
|
||||
out.repair();
|
||||
return out;
|
||||
}
|
||||
|
||||
std::unique_ptr<CGALMesh, CGALMeshDeleter> triangle_mesh_to_cgal(const TriangleMesh &M)
|
||||
std::unique_ptr<CGALMesh, CGALMeshDeleter>
|
||||
triangle_mesh_to_cgal(const std::vector<stl_vertex> &V,
|
||||
const std::vector<stl_triangle_vertex_indices> &F)
|
||||
{
|
||||
std::unique_ptr<CGALMesh, CGALMeshDeleter> out(new CGALMesh{});
|
||||
triangle_mesh_to_cgal(M, out->m);
|
||||
triangle_mesh_to_cgal(V, F, out->m);
|
||||
return out;
|
||||
}
|
||||
|
||||
@ -238,8 +232,8 @@ template<class Op> void _mesh_boolean_do(Op &&op, TriangleMesh &A, const Triangl
|
||||
{
|
||||
CGALMesh meshA;
|
||||
CGALMesh meshB;
|
||||
triangle_mesh_to_cgal(A, meshA.m);
|
||||
triangle_mesh_to_cgal(B, meshB.m);
|
||||
triangle_mesh_to_cgal(A.its.vertices, A.its.indices, meshA.m);
|
||||
triangle_mesh_to_cgal(B.its.vertices, B.its.indices, meshB.m);
|
||||
|
||||
_cgal_do(op, meshA, meshB);
|
||||
|
||||
@ -264,7 +258,7 @@ void intersect(TriangleMesh &A, const TriangleMesh &B)
|
||||
bool does_self_intersect(const TriangleMesh &mesh)
|
||||
{
|
||||
CGALMesh cgalm;
|
||||
triangle_mesh_to_cgal(mesh, cgalm.m);
|
||||
triangle_mesh_to_cgal(mesh.its.vertices, mesh.its.indices, cgalm.m);
|
||||
return CGALProc::does_self_intersect(cgalm.m);
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,19 @@ namespace cgal {
|
||||
struct CGALMesh;
|
||||
struct CGALMeshDeleter { void operator()(CGALMesh *ptr); };
|
||||
|
||||
std::unique_ptr<CGALMesh, CGALMeshDeleter> triangle_mesh_to_cgal(const TriangleMesh &M);
|
||||
std::unique_ptr<CGALMesh, CGALMeshDeleter>
|
||||
triangle_mesh_to_cgal(const std::vector<stl_vertex> &V,
|
||||
const std::vector<stl_triangle_vertex_indices> &F);
|
||||
|
||||
inline std::unique_ptr<CGALMesh, CGALMeshDeleter> triangle_mesh_to_cgal(const indexed_triangle_set &M)
|
||||
{
|
||||
return triangle_mesh_to_cgal(M.vertices, M.indices);
|
||||
}
|
||||
inline std::unique_ptr<CGALMesh, CGALMeshDeleter> triangle_mesh_to_cgal(const TriangleMesh &M)
|
||||
{
|
||||
return triangle_mesh_to_cgal(M.its);
|
||||
}
|
||||
|
||||
TriangleMesh cgal_to_triangle_mesh(const CGALMesh &cgalmesh);
|
||||
|
||||
// Do boolean mesh difference with CGAL bypassing igl.
|
||||
|
@ -1302,52 +1302,54 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
||||
|
||||
void ModelObject::split(ModelObjectPtrs* new_objects)
|
||||
{
|
||||
if (this->volumes.size() > 1) {
|
||||
// We can't split meshes if there's more than one volume, because
|
||||
// we can't group the resulting meshes by object afterwards
|
||||
new_objects->emplace_back(this);
|
||||
return;
|
||||
}
|
||||
for (ModelVolume* volume : this->volumes) {
|
||||
if (volume->type() != ModelVolumeType::MODEL_PART)
|
||||
continue;
|
||||
|
||||
ModelVolume* volume = this->volumes.front();
|
||||
TriangleMeshPtrs meshptrs = volume->mesh().split();
|
||||
size_t counter = 1;
|
||||
for (TriangleMesh *mesh : meshptrs) {
|
||||
TriangleMeshPtrs meshptrs = volume->mesh().split();
|
||||
size_t counter = 1;
|
||||
for (TriangleMesh* mesh : meshptrs) {
|
||||
|
||||
// FIXME: crashes if not satisfied
|
||||
if (mesh->facets_count() < 3) continue;
|
||||
// FIXME: crashes if not satisfied
|
||||
if (mesh->facets_count() < 3) continue;
|
||||
|
||||
mesh->repair();
|
||||
mesh->repair();
|
||||
|
||||
// XXX: this seems to be the only real usage of m_model, maybe refactor this so that it's not needed?
|
||||
ModelObject* new_object = m_model->add_object();
|
||||
new_object->name = this->name + (meshptrs.size() > 1 ? "_" + std::to_string(counter++) : "");
|
||||
// XXX: this seems to be the only real usage of m_model, maybe refactor this so that it's not needed?
|
||||
ModelObject* new_object = m_model->add_object();
|
||||
if (meshptrs.size() == 1) {
|
||||
new_object->name = volume->name;
|
||||
// Don't copy the config's ID.
|
||||
new_object->config.assign_config(this->config.size() > 0 ? this->config : volume->config);
|
||||
}
|
||||
else {
|
||||
new_object->name = this->name + (meshptrs.size() > 1 ? "_" + std::to_string(counter++) : "");
|
||||
// Don't copy the config's ID.
|
||||
new_object->config.assign_config(this->config);
|
||||
}
|
||||
assert(new_object->config.id().valid());
|
||||
assert(new_object->config.id() != this->config.id());
|
||||
new_object->instances.reserve(this->instances.size());
|
||||
for (const ModelInstance* model_instance : this->instances)
|
||||
new_object->add_instance(*model_instance);
|
||||
ModelVolume* new_vol = new_object->add_volume(*volume, std::move(*mesh));
|
||||
|
||||
// Don't copy the config's ID.
|
||||
new_object->config.assign_config(this->config);
|
||||
assert(new_object->config.id().valid());
|
||||
assert(new_object->config.id() != this->config.id());
|
||||
new_object->instances.reserve(this->instances.size());
|
||||
for (const ModelInstance *model_instance : this->instances)
|
||||
new_object->add_instance(*model_instance);
|
||||
ModelVolume* new_vol = new_object->add_volume(*volume, std::move(*mesh));
|
||||
for (ModelInstance* model_instance : new_object->instances)
|
||||
{
|
||||
Vec3d shift = model_instance->get_transformation().get_matrix(true) * new_vol->get_offset();
|
||||
model_instance->set_offset(model_instance->get_offset() + shift);
|
||||
}
|
||||
|
||||
for (ModelInstance* model_instance : new_object->instances)
|
||||
{
|
||||
Vec3d shift = model_instance->get_transformation().get_matrix(true) * new_vol->get_offset();
|
||||
model_instance->set_offset(model_instance->get_offset() + shift);
|
||||
new_vol->set_offset(Vec3d::Zero());
|
||||
// reset the source to disable reload from disk
|
||||
new_vol->source = ModelVolume::Source();
|
||||
new_objects->emplace_back(new_object);
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
new_vol->set_offset(Vec3d::Zero());
|
||||
// reset the source to disable reload from disk
|
||||
new_vol->source = ModelVolume::Source();
|
||||
new_objects->emplace_back(new_object);
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void ModelObject::merge()
|
||||
{
|
||||
if (this->volumes.size() == 1) {
|
||||
@ -1738,6 +1740,7 @@ size_t ModelVolume::split(unsigned int max_extruders)
|
||||
this->object->volumes[ivolume]->translate(offset);
|
||||
this->object->volumes[ivolume]->name = name + "_" + std::to_string(idx + 1);
|
||||
this->object->volumes[ivolume]->config.set_deserialize("extruder", auto_extruder_id(max_extruders, extruder_counter));
|
||||
this->object->volumes[ivolume]->m_is_splittable = 0;
|
||||
delete mesh;
|
||||
++ idx;
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ public:
|
||||
bool has_duplicate_points() const;
|
||||
// Remove exact duplicates, return true if any duplicate has been removed.
|
||||
bool remove_duplicate_points();
|
||||
void clear() { this->points.clear(); }
|
||||
void append(const Point &point) { this->points.push_back(point); }
|
||||
void append(const Points &src) { this->append(src.begin(), src.end()); }
|
||||
void append(const Points::const_iterator &begin, const Points::const_iterator &end) { this->points.insert(this->points.end(), begin, end); }
|
||||
|
360
src/libslic3r/MutablePolygon.cpp
Normal file
@ -0,0 +1,360 @@
|
||||
#include "MutablePolygon.hpp"
|
||||
#include "Line.hpp"
|
||||
#include "libslic3r.h"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Remove exact duplicate points. May reduce the polygon down to empty polygon.
|
||||
void remove_duplicates(MutablePolygon &polygon)
|
||||
{
|
||||
if (! polygon.empty()) {
|
||||
auto begin = polygon.begin();
|
||||
auto it = begin;
|
||||
for (++ it; it != begin;) {
|
||||
auto prev = it.prev();
|
||||
if (*prev == *it)
|
||||
it = it.remove();
|
||||
else
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove nearly duplicate points. May reduce the polygon down to empty polygon.
|
||||
void remove_duplicates(MutablePolygon &polygon, double eps)
|
||||
{
|
||||
if (! polygon.empty()) {
|
||||
auto eps2 = eps * eps;
|
||||
auto begin = polygon.begin();
|
||||
auto it = begin;
|
||||
for (++ it; it != begin;) {
|
||||
auto prev = it.prev();
|
||||
if ((*it - *prev).cast<double>().squaredNorm() < eps2)
|
||||
it = it.remove();
|
||||
else
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adapted from Cura ConstPolygonRef::smooth_corner_complex() by Tim Kuipers.
|
||||
// A concave corner at it1 with position p1 has been removed by the caller between it0 and it2, where |p2 - p0| < shortcut_length.
|
||||
// Now try to close a concave crack by walking left from it0 and right from it2 as long as the new clipping edge is smaller than shortcut_length
|
||||
// and the new clipping edge is still inside the polygon (it is a diagonal, it does not intersect polygon boundary).
|
||||
// Once the traversal stops (always at a clipping edge shorter than shortcut_length), the final trapezoid is clipped with a new clipping edge of shortcut_length.
|
||||
// Return true if a hole was completely closed (degenerated to an empty polygon) or a single CCW triangle was left, which is not to be simplified any further.
|
||||
// it0, it2 are updated to the final clipping edge.
|
||||
static bool clip_narrow_corner(
|
||||
const Vec2i64 p1,
|
||||
MutablePolygon::iterator &it0,
|
||||
MutablePolygon::iterator &it2,
|
||||
MutablePolygon::range &unprocessed_range,
|
||||
int64_t dist2_current,
|
||||
const int64_t shortcut_length)
|
||||
{
|
||||
MutablePolygon &polygon = it0.polygon();
|
||||
assert(polygon.size() >= 2);
|
||||
|
||||
const int64_t shortcut_length2 = sqr(shortcut_length);
|
||||
|
||||
enum Status {
|
||||
Free,
|
||||
Blocked,
|
||||
Far,
|
||||
};
|
||||
Status forward = Free;
|
||||
Status backward = Free;
|
||||
|
||||
Vec2i64 p0 = it0->cast<int64_t>();
|
||||
Vec2i64 p2 = it2->cast<int64_t>();
|
||||
Vec2i64 p02;
|
||||
Vec2i64 p22;
|
||||
int64_t dist2_next = 0;
|
||||
|
||||
// As long as there is at least a single triangle left in the polygon.
|
||||
while (polygon.size() >= 3) {
|
||||
assert(dist2_current <= shortcut_length2);
|
||||
if (forward == Far && backward == Far) {
|
||||
p02 = it0.prev()->cast<int64_t>();
|
||||
p22 = it2.next()->cast<int64_t>();
|
||||
auto d2 = (p22 - p02).squaredNorm();
|
||||
if (d2 <= shortcut_length2) {
|
||||
// The region was narrow until now and it is still narrow. Trim at both sides.
|
||||
it0 = unprocessed_range.remove_back(it0).prev();
|
||||
it2 = unprocessed_range.remove_front(it2);
|
||||
if (polygon.size() <= 2)
|
||||
// A hole degenerated to an empty polygon.
|
||||
return true;
|
||||
forward = Free;
|
||||
backward = Free;
|
||||
dist2_current = d2;
|
||||
p0 = p02;
|
||||
p2 = p22;
|
||||
} else {
|
||||
// The region is widening. Stop traversal and trim the final trapezoid.
|
||||
dist2_next = d2;
|
||||
break;
|
||||
}
|
||||
} else if (forward != Free && backward != Free)
|
||||
// One of the corners is blocked, the other is blocked or too far. Stop traversal.
|
||||
break;
|
||||
// Try to proceed by flipping a diagonal.
|
||||
// Progress by keeping the distance of the clipping edge end points equal to initial p1.
|
||||
//FIXME This is an arbitrary condition, maybe a more local condition will be better (take a shorter diagonal?).
|
||||
if (forward == Free && (backward != Free || (p2 - p1).squaredNorm() < (p0 - p1).cast<int64_t>().squaredNorm())) {
|
||||
p22 = it2.next()->cast<int64_t>();
|
||||
if (cross2(p2 - p0, p22 - p0) > 0)
|
||||
forward = Blocked;
|
||||
else {
|
||||
// New clipping edge lenght.
|
||||
auto d2 = (p22 - p0).squaredNorm();
|
||||
if (d2 > shortcut_length2) {
|
||||
forward = Far;
|
||||
dist2_next = d2;
|
||||
} else {
|
||||
forward = Free;
|
||||
// Make one step in the forward direction.
|
||||
it2 = unprocessed_range.remove_front(it2);
|
||||
p2 = p22;
|
||||
dist2_current = d2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assert(backward == Free);
|
||||
p02 = it0.prev()->cast<int64_t>();
|
||||
if (cross2(p02 - p2, p0 - p2) > 0)
|
||||
backward = Blocked;
|
||||
else {
|
||||
// New clipping edge lenght.
|
||||
auto d2 = (p2 - p02).squaredNorm();
|
||||
if (d2 > shortcut_length2) {
|
||||
backward = Far;
|
||||
dist2_next = d2;
|
||||
} else {
|
||||
backward = Free;
|
||||
// Make one step in the backward direction.
|
||||
it0 = unprocessed_range.remove_back(it0).prev();
|
||||
p0 = p02;
|
||||
dist2_current = d2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(dist2_current <= shortcut_length2);
|
||||
assert(polygon.size() >= 2);
|
||||
assert(polygon.size() == 2 || forward == Blocked || forward == Far);
|
||||
assert(polygon.size() == 2 || backward == Blocked || backward == Far);
|
||||
|
||||
if (polygon.size() <= 3) {
|
||||
// A hole degenerated to an empty polygon, or a tiny triangle remained.
|
||||
#ifndef NDEBUG
|
||||
bool blocked = forward == Blocked || backward == Blocked;
|
||||
assert(polygon.size() < 3 ||
|
||||
// Remaining triangle is CCW oriented. Both sides must be "blocked", but the other side may have not been
|
||||
// updated after the the p02 / p22 became united into a single point.
|
||||
blocked ||
|
||||
// Remaining triangle is concave, however both of its arms are long.
|
||||
(forward == Far && backward == Far));
|
||||
if (polygon.size() == 3) {
|
||||
// Verify that the remaining triangle is CCW or CW.
|
||||
p02 = it0.prev()->cast<int64_t>();
|
||||
p22 = it2.next()->cast<int64_t>();
|
||||
assert(p02 == p22);
|
||||
auto orient1 = cross2(p02 - p2, p0 - p2);
|
||||
auto orient2 = cross2(p2 - p0, p22 - p0);
|
||||
assert(orient1 > 0 == blocked);
|
||||
assert(orient2 > 0 == blocked);
|
||||
}
|
||||
#endif // _NDEBUG
|
||||
if (polygon.size() < 3 || (forward == Far && backward == Far)) {
|
||||
polygon.clear();
|
||||
} else {
|
||||
// The remaining triangle is CCW oriented, keep it.
|
||||
assert(forward == Blocked || backward == Blocked);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(dist2_current <= shortcut_length2);
|
||||
if ((forward == Blocked && backward == Blocked) || dist2_current > sqr(shortcut_length - int64_t(SCALED_EPSILON))) {
|
||||
// The crack is filled, keep the last clipping edge.
|
||||
} else if (dist2_next < sqr(shortcut_length - int64_t(SCALED_EPSILON))) {
|
||||
// To avoid creating tiny edges.
|
||||
if (forward == Far)
|
||||
it0 = unprocessed_range.remove_back(it0).prev();
|
||||
if (backward == Far)
|
||||
it2 = unprocessed_range.remove_front(it2);
|
||||
if (polygon.size() <= 2)
|
||||
// A hole degenerated to an empty polygon.
|
||||
return true;
|
||||
} else if (forward == Blocked || backward == Blocked) {
|
||||
// One side is far, the other blocked.
|
||||
assert(forward == Far || backward == Far);
|
||||
if (forward == Far) {
|
||||
// Sort, so we will clip the 1st edge.
|
||||
std::swap(p0, p2);
|
||||
std::swap(p02, p22);
|
||||
}
|
||||
// Find point on (p0, p02) at distance shortcut_length from p2.
|
||||
// Circle intersects a line at two points, however because |p2 - p0| < shortcut_length,
|
||||
// only the second intersection is valid. Because |p2 - p02| > shortcut_length, such
|
||||
// intersection should always be found on (p0, p02).
|
||||
#ifndef NDEBUG
|
||||
auto dfar2 = (p02 - p2).squaredNorm();
|
||||
assert(dfar2 >= shortcut_length2);
|
||||
#endif // NDEBUG
|
||||
const Vec2d v = (p02 - p0).cast<double>();
|
||||
const Vec2d d = (p0 - p2).cast<double>();
|
||||
const double a = v.squaredNorm();
|
||||
const double b = 2. * double(d.dot(v));
|
||||
double u = b * b - 4. * a * (d.squaredNorm() - shortcut_length2);
|
||||
assert(u > 0.);
|
||||
u = sqrt(u);
|
||||
double t = (- b + u) / (2. * a);
|
||||
assert(t > 0. && t < 1.);
|
||||
(backward == Far ? *it2 : *it0) += (v.cast<double>() * t).cast<coord_t>();
|
||||
} else {
|
||||
// The trapezoid (it0.prev(), it0, it2, it2.next()) is widening. Trim it.
|
||||
assert(forward == Far && backward == Far);
|
||||
assert(dist2_next > shortcut_length2);
|
||||
const double dcurrent = sqrt(double(dist2_current));
|
||||
double t = (shortcut_length - dcurrent) / (sqrt(double(dist2_next)) - dcurrent);
|
||||
assert(t > 0. && t < 1.);
|
||||
*it0 += ((p02 - p0).cast<double>() * t).cast<coord_t>();
|
||||
*it2 += ((p22 - p2).cast<double>() * t).cast<coord_t>();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// adapted from Cura ConstPolygonRef::smooth_outward() by Tim Kuipers.
|
||||
void smooth_outward(MutablePolygon &polygon, coord_t clip_dist_scaled)
|
||||
{
|
||||
remove_duplicates(polygon, scaled<double>(0.01));
|
||||
|
||||
const auto clip_dist_scaled2 = sqr<int64_t>(clip_dist_scaled);
|
||||
const auto clip_dist_scaled2eps = sqr(clip_dist_scaled + int64_t(SCALED_EPSILON));
|
||||
const auto foot_dist_min2 = sqr(SCALED_EPSILON);
|
||||
|
||||
// Each source point will be visited exactly once.
|
||||
MutablePolygon::range unprocessed_range(polygon);
|
||||
while (! unprocessed_range.empty() && polygon.size() > 2) {
|
||||
auto it1 = unprocessed_range.process_next();
|
||||
auto it0 = it1.prev();
|
||||
auto it2 = it1.next();
|
||||
const Point p0 = *it0;
|
||||
const Point p1 = *it1;
|
||||
const Point p2 = *it2;
|
||||
const Vec2i64 v1 = (p0 - p1).cast<int64_t>();
|
||||
const Vec2i64 v2 = (p2 - p1).cast<int64_t>();
|
||||
if (cross2(v1, v2) > 0) {
|
||||
// Concave corner.
|
||||
int64_t dot = v1.dot(v2);
|
||||
auto l2v1 = double(v1.squaredNorm());
|
||||
auto l2v2 = double(v2.squaredNorm());
|
||||
if (dot > 0 || Slic3r::sqr(double(dot)) * 2. < l2v1 * l2v2) {
|
||||
// Angle between v1 and v2 bigger than 135 degrees.
|
||||
// Simplify the sharp angle.
|
||||
Vec2i64 v02 = (p2 - p0).cast<int64_t>();
|
||||
int64_t l2v02 = v02.squaredNorm();
|
||||
it1.remove();
|
||||
if (l2v02 < clip_dist_scaled2) {
|
||||
// (p0, p2) is short.
|
||||
// Clip a sharp concave corner by possibly expanding the trimming region left of it0 and right of it2.
|
||||
// Updates it0, it2 and num_to_process.
|
||||
if (clip_narrow_corner(p1.cast<int64_t>(), it0, it2, unprocessed_range, l2v02, clip_dist_scaled))
|
||||
// Trimmed down to an empty polygon or to a single CCW triangle.
|
||||
return;
|
||||
} else {
|
||||
// Clip an obtuse corner.
|
||||
if (l2v02 > clip_dist_scaled2eps) {
|
||||
Vec2d v1d = v1.cast<double>();
|
||||
Vec2d v2d = v2.cast<double>();
|
||||
// Sort v1d, v2d, shorter first.
|
||||
bool swap = l2v1 > l2v2;
|
||||
if (swap) {
|
||||
std::swap(v1d, v2d);
|
||||
std::swap(l2v1, l2v2);
|
||||
}
|
||||
double lv1 = sqrt(l2v1);
|
||||
double lv2 = sqrt(l2v2);
|
||||
// Bisector between v1 and v2.
|
||||
Vec2d bisector = v1d / lv1 + v2d / lv2;
|
||||
double l2bisector = bisector.squaredNorm();
|
||||
// Squared distance of the end point of v1 to the bisector.
|
||||
double d2 = l2v1 - sqr(v1d.dot(bisector)) / l2bisector;
|
||||
if (d2 < foot_dist_min2) {
|
||||
// Height of the p1, p0, p2 triangle is tiny. Just remove p1.
|
||||
} else if (d2 < 0.25 * clip_dist_scaled2 + SCALED_EPSILON) {
|
||||
// The shorter vector is too close to the bisector. Trim the shorter vector fully,
|
||||
// trim the longer vector partially.
|
||||
// Intersection of a circle at p2 of radius = clip_dist_scaled
|
||||
// with a ray (p1, p0), take the intersection after the foot point.
|
||||
// The intersection shall always exist because |p2 - p1| > clip_dist_scaled.
|
||||
const double b = - 2. * v1d.cast<double>().dot(v2d);
|
||||
double u = b * b - 4. * l2v2 * (double(l2v1) - clip_dist_scaled2);
|
||||
assert(u > 0.);
|
||||
// Take the second intersection along v2.
|
||||
double t = (- b + sqrt(u)) / (2. * l2v2);
|
||||
assert(t > 0. && t < 1.);
|
||||
Point pt_new = p1 + (t * v2d).cast<coord_t>();
|
||||
#ifndef NDEBUG
|
||||
double d2new = (pt_new - (swap ? p2 : p0)).cast<double>().squaredNorm();
|
||||
assert(std::abs(d2new - clip_dist_scaled2) < 1e-5 * clip_dist_scaled2);
|
||||
#endif // NDEBUG
|
||||
it2.insert(pt_new);
|
||||
} else {
|
||||
// Cut the corner with a line perpendicular to the bisector.
|
||||
double t = sqrt(0.25 * clip_dist_scaled2 / d2);
|
||||
double t2 = t * lv1 / lv2;
|
||||
assert(t > 0. && t < 1.);
|
||||
assert(t2 > 0. && t2 < 1.);
|
||||
Point p0 = p1 + (v1d * t ).cast<coord_t>();
|
||||
Point p2 = p1 + (v2d * t2).cast<coord_t>();
|
||||
if (swap)
|
||||
std::swap(p0, p2);
|
||||
it2.insert(p2).insert(p0);
|
||||
}
|
||||
} else {
|
||||
// Just remove p1.
|
||||
assert(l2v02 >= clip_dist_scaled2 && l2v02 <= clip_dist_scaled2eps);
|
||||
}
|
||||
}
|
||||
it1 = it2;
|
||||
} else
|
||||
++ it1;
|
||||
} else
|
||||
++ it1;
|
||||
}
|
||||
|
||||
if (polygon.size() == 3) {
|
||||
// Check whether the last triangle is clockwise oriented (it is a hole) and its height is below clip_dist_scaled.
|
||||
// If so, fill in the hole.
|
||||
const Point p0 = *polygon.begin().prev();
|
||||
const Point p1 = *polygon.begin();
|
||||
const Point p2 = *polygon.begin().next();
|
||||
Vec2i64 v1 = (p0 - p1).cast<int64_t>();
|
||||
Vec2i64 v2 = (p2 - p1).cast<int64_t>();
|
||||
if (cross2(v1, v2) > 0) {
|
||||
// CW triangle. Measure its height.
|
||||
const Vec2i64 v3 = (p2 - p0).cast<int64_t>();
|
||||
int64_t l12 = v1.squaredNorm();
|
||||
int64_t l22 = v2.squaredNorm();
|
||||
int64_t l32 = v3.squaredNorm();
|
||||
if (l22 > l12 && l22 > l32) {
|
||||
std::swap(v1, v2);
|
||||
std::swap(l12, l22);
|
||||
} else if (l32 > l12 && l32 > l22) {
|
||||
v1 = v3;
|
||||
l12 = l32;
|
||||
}
|
||||
auto h2 = l22 - sqr(double(v1.dot(v2))) / double(l12);
|
||||
if (h2 < clip_dist_scaled2)
|
||||
// CW triangle with a low height. Close the hole.
|
||||
polygon.clear();
|
||||
}
|
||||
} else if (polygon.size() < 3)
|
||||
polygon.clear();
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
335
src/libslic3r/MutablePolygon.hpp
Normal file
@ -0,0 +1,335 @@
|
||||
#ifndef slic3r_MutablePolygon_hpp_
|
||||
#define slic3r_MutablePolygon_hpp_
|
||||
|
||||
#include "Point.hpp"
|
||||
#include "Polygon.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Polygon implemented as a loop of double linked elements.
|
||||
// All elements are allocated in a single std::vector<>, thus integer indices are used for
|
||||
// referencing the previous and next element and inside iterators to survive reallocation
|
||||
// of the vector.
|
||||
class MutablePolygon
|
||||
{
|
||||
public:
|
||||
using IndexType = int32_t;
|
||||
using PointType = Point;
|
||||
class const_iterator {
|
||||
public:
|
||||
bool operator==(const const_iterator &rhs) const { assert(m_data == rhs.m_data); assert(this->valid()); return m_idx == rhs.m_idx; }
|
||||
bool operator!=(const const_iterator &rhs) const { return ! (*this == rhs); }
|
||||
const_iterator& operator--() { assert(this->valid()); m_idx = m_data->at(m_idx).prev; return *this; }
|
||||
const_iterator operator--(int) { const_iterator result(*this); --(*this); return result; }
|
||||
const_iterator& operator++() { assert(this->valid()); m_idx = m_data->at(m_idx).next; return *this; }
|
||||
const_iterator operator++(int) { const_iterator result(*this); ++(*this); return result; }
|
||||
const_iterator prev() const { assert(this->valid()); return { m_data, m_data->at(m_idx).prev }; }
|
||||
const_iterator next() const { assert(this->valid()); return { m_data, m_data->at(m_idx).next }; }
|
||||
bool valid() const { return m_idx >= 0; }
|
||||
const PointType& operator*() const { return m_data->at(m_idx).point; }
|
||||
const PointType* operator->() const { return &m_data->at(m_idx).point; }
|
||||
const MutablePolygon& polygon() const { assert(this->valid()); return *m_data; }
|
||||
IndexType size() const { assert(this->valid()); return m_data->size(); }
|
||||
private:
|
||||
const_iterator(const MutablePolygon *data, IndexType idx) : m_data(data), m_idx(idx) {}
|
||||
friend class MutablePolygon;
|
||||
const MutablePolygon *m_data;
|
||||
IndexType m_idx;
|
||||
};
|
||||
|
||||
class iterator {
|
||||
public:
|
||||
bool operator==(const iterator &rhs) const { assert(m_data == rhs.m_data); assert(this->valid()); return m_idx == rhs.m_idx; }
|
||||
bool operator!=(const iterator &rhs) const { return !(*this == rhs); }
|
||||
iterator& operator--() { assert(this->valid()); m_idx = m_data->at(m_idx).prev; return *this; }
|
||||
iterator operator--(int) { iterator result(*this); --(*this); return result; }
|
||||
iterator& operator++() { assert(this->valid()); m_idx = m_data->at(m_idx).next; return *this; }
|
||||
iterator operator++(int) { iterator result(*this); ++(*this); return result; }
|
||||
iterator prev() const { assert(this->valid()); return { m_data, m_data->at(m_idx).prev }; }
|
||||
iterator next() const { assert(this->valid()); return { m_data, m_data->at(m_idx).next }; }
|
||||
bool valid() const { return m_idx >= 0; }
|
||||
PointType& operator*() const { return m_data->at(m_idx).point; }
|
||||
PointType* operator->() const { return &m_data->at(m_idx).point; }
|
||||
MutablePolygon& polygon() const { assert(this->valid()); return *m_data; }
|
||||
IndexType size() const { assert(this->valid()); return m_data->size(); }
|
||||
iterator& remove() { this->m_idx = m_data->remove(*this).m_idx; return *this; }
|
||||
iterator insert(const PointType pt) const { return m_data->insert(*this, pt); }
|
||||
private:
|
||||
iterator(MutablePolygon *data, IndexType idx) : m_data(data), m_idx(idx) {}
|
||||
friend class MutablePolygon;
|
||||
MutablePolygon *m_data;
|
||||
IndexType m_idx;
|
||||
friend class range;
|
||||
};
|
||||
|
||||
// Iterator range for maintaining a range of unprocessed items, see smooth_outward().
|
||||
class range
|
||||
{
|
||||
public:
|
||||
range(MutablePolygon& poly) : range(poly.begin(), poly.end()) {}
|
||||
range(MutablePolygon::iterator begin, MutablePolygon::iterator end) : m_begin(begin), m_end(end) {}
|
||||
|
||||
// Start of a range, inclusive. If range is empty, then ! begin().valid().
|
||||
MutablePolygon::iterator begin() const { return m_begin; }
|
||||
// End of a range, inclusive. If range is empty, then ! end().valid().
|
||||
MutablePolygon::iterator end() const { return m_end; }
|
||||
// Is the range empty?
|
||||
bool empty() const { return !m_begin.valid(); }
|
||||
|
||||
// Return begin() and shorten the range by advancing front.
|
||||
MutablePolygon::iterator process_next() {
|
||||
assert(!this->empty());
|
||||
MutablePolygon::iterator out = m_begin;
|
||||
this->advance_front();
|
||||
return out;
|
||||
}
|
||||
|
||||
void advance_front() {
|
||||
assert(! this->empty());
|
||||
if (m_begin == m_end)
|
||||
this->make_empty();
|
||||
else
|
||||
++ m_begin;
|
||||
}
|
||||
|
||||
void retract_back() {
|
||||
assert(! this->empty());
|
||||
if (m_begin == m_end)
|
||||
this->make_empty();
|
||||
else
|
||||
-- m_end;
|
||||
}
|
||||
|
||||
MutablePolygon::iterator remove_front(MutablePolygon::iterator it) {
|
||||
if (! this->empty() && m_begin == it)
|
||||
this->advance_front();
|
||||
return it.remove();
|
||||
}
|
||||
|
||||
MutablePolygon::iterator remove_back(MutablePolygon::iterator it) {
|
||||
if (! this->empty() && m_end == it)
|
||||
this->retract_back();
|
||||
return it.remove();
|
||||
}
|
||||
|
||||
private:
|
||||
// Range from begin to end, inclusive.
|
||||
// If the range is valid, then both m_begin and m_end are invalid.
|
||||
MutablePolygon::iterator m_begin;
|
||||
MutablePolygon::iterator m_end;
|
||||
|
||||
void make_empty() {
|
||||
m_begin.m_idx = -1;
|
||||
m_end.m_idx = -1;
|
||||
}
|
||||
};
|
||||
|
||||
MutablePolygon() = default;
|
||||
MutablePolygon(const Polygon &rhs, size_t reserve = 0) : MutablePolygon(rhs.points.begin(), rhs.points.end(), reserve) {}
|
||||
MutablePolygon(std::initializer_list<Point> rhs, size_t reserve = 0) : MutablePolygon(rhs.begin(), rhs.end(), reserve) {}
|
||||
|
||||
template<typename IT>
|
||||
MutablePolygon(IT begin, IT end, size_t reserve = 0) {
|
||||
this->assign_inner(begin, end, reserve);
|
||||
};
|
||||
|
||||
template<typename IT>
|
||||
void assign(IT begin, IT end, size_t reserve = 0) {
|
||||
m_data.clear();
|
||||
m_head = IndexType(-1);
|
||||
m_head_free = { IndexType(-1) };
|
||||
this->assign_inner(begin, end, reserve);
|
||||
};
|
||||
|
||||
void assign(const Polygon &rhs, size_t reserve = 0) {
|
||||
assign(rhs.points.begin(), rhs.points.end(), reserve);
|
||||
}
|
||||
|
||||
void polygon(Polygon &out) const {
|
||||
out.points.clear();
|
||||
if (this->valid()) {
|
||||
out.points.reserve(this->size());
|
||||
auto it = this->cbegin();
|
||||
out.points.emplace_back(*it);
|
||||
for (++ it; it != this->cbegin(); ++ it)
|
||||
out.points.emplace_back(*it);
|
||||
}
|
||||
};
|
||||
|
||||
Polygon polygon() const {
|
||||
Polygon out;
|
||||
this->polygon(out);
|
||||
return out;
|
||||
};
|
||||
|
||||
bool empty() const { return this->m_size == 0; }
|
||||
size_t size() const { return this->m_size; }
|
||||
size_t capacity() const { return this->m_data.capacity(); }
|
||||
bool valid() const { return this->m_size >= 3; }
|
||||
void clear() { m_data.clear(); m_size = 0; m_head = IndexType(-1); m_head_free = IndexType(-1); }
|
||||
|
||||
iterator begin() { return { this, m_head }; }
|
||||
const_iterator cbegin() const { return { this, m_head }; }
|
||||
const_iterator begin() const { return this->cbegin(); }
|
||||
// End points to the last item before roll over. This is different from the usual end() concept!
|
||||
iterator end() { return { this, this->empty() ? -1 : this->at(m_head).prev }; }
|
||||
const_iterator cend() const { return { this, this->empty() ? -1 : this->at(m_head).prev }; }
|
||||
const_iterator end() const { return this->cend(); }
|
||||
|
||||
// Returns iterator following the removed element. Returned iterator will become invalid if last point is removed.
|
||||
// If begin() is removed, then the next element will become the new begin().
|
||||
iterator remove(const iterator it) { assert(it.m_data == this); return { this, this->remove(it.m_idx) }; }
|
||||
// Insert a new point before it. Returns iterator to the newly inserted point.
|
||||
// begin() will not change, end() may point to the newly inserted point.
|
||||
iterator insert(const iterator it, const PointType pt) { assert(it.m_data == this); return { this, this->insert(it.m_idx, pt) }; }
|
||||
|
||||
private:
|
||||
struct LinkedPoint {
|
||||
// 8 bytes
|
||||
PointType point;
|
||||
// 4 bytes
|
||||
IndexType prev;
|
||||
// 4 bytes
|
||||
IndexType next;
|
||||
};
|
||||
std::vector<LinkedPoint> m_data;
|
||||
// Number of points in the linked list.
|
||||
IndexType m_size { 0 };
|
||||
IndexType m_head { IndexType(-1) };
|
||||
// Head of the free list.
|
||||
IndexType m_head_free { IndexType(-1) };
|
||||
|
||||
LinkedPoint& at(IndexType i) { return m_data[i]; }
|
||||
const LinkedPoint& at(IndexType i) const { return m_data[i]; }
|
||||
|
||||
template<typename IT>
|
||||
void assign_inner(IT begin, IT end, size_t reserve) {
|
||||
m_size = IndexType(end - begin);
|
||||
if (m_size > 0) {
|
||||
m_head = 0;
|
||||
m_data.reserve(std::max<size_t>(m_size, reserve));
|
||||
auto i = IndexType(-1);
|
||||
auto j = IndexType(1);
|
||||
for (auto it = begin; it != end; ++ it)
|
||||
m_data.push_back({ *it, i ++, j ++ });
|
||||
m_data.front().prev = m_size - 1;
|
||||
m_data.back ().next = 0;
|
||||
}
|
||||
};
|
||||
|
||||
IndexType remove(const IndexType i) {
|
||||
assert(i >= 0);
|
||||
assert(m_size > 0);
|
||||
assert(m_head != -1);
|
||||
LinkedPoint &lp = this->at(i);
|
||||
IndexType prev = lp.prev;
|
||||
IndexType next = lp.next;
|
||||
lp.next = m_head_free;
|
||||
m_head_free = i;
|
||||
if (-- m_size == 0)
|
||||
m_head = -1;
|
||||
else if (m_head == i)
|
||||
m_head = next;
|
||||
assert(! this->empty() || (prev == i && next == i));
|
||||
if (this->empty())
|
||||
return IndexType(-1);
|
||||
this->at(prev).next = next;
|
||||
this->at(next).prev = prev;
|
||||
return next;
|
||||
}
|
||||
|
||||
IndexType insert(const IndexType i, const Point pt) {
|
||||
assert(i >= 0);
|
||||
IndexType n;
|
||||
IndexType j = this->at(i).prev;
|
||||
if (m_head_free == -1) {
|
||||
// Allocate a new item.
|
||||
n = IndexType(m_data.size());
|
||||
m_data.push_back({ pt, j, i });
|
||||
} else {
|
||||
n = m_head_free;
|
||||
LinkedPoint &nlp = this->at(n);
|
||||
m_head_free = nlp.next;
|
||||
nlp = { pt, j, i };
|
||||
}
|
||||
this->at(j).next = n;
|
||||
this->at(i).prev = n;
|
||||
++ m_size;
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
IndexType insert(const IndexType i, const Point pt) {
|
||||
assert(i >= 0);
|
||||
if (this->at(i).point == pt)
|
||||
return i;
|
||||
IndexType j = this->at(i).next;
|
||||
if (this->at(j).point == pt)
|
||||
return i;
|
||||
IndexType n;
|
||||
if (m_head_free == -1) {
|
||||
// Allocate a new item.
|
||||
n = IndexType(m_data.size());
|
||||
m_data.push_back({ pt, i, j });
|
||||
} else {
|
||||
LinkedPoint &nlp = this->at(m_head_free);
|
||||
m_head_free = nlp.next;
|
||||
nlp = { pt, i, j };
|
||||
}
|
||||
this->at(i).next = n;
|
||||
this->at(j).prev = n;
|
||||
++ m_size;
|
||||
return n;
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
inline bool operator==(const MutablePolygon &p1, const MutablePolygon &p2)
|
||||
{
|
||||
if (p1.size() != p2.size())
|
||||
return false;
|
||||
if (p1.empty())
|
||||
return true;
|
||||
auto begin = p1.cbegin();
|
||||
auto it = begin;
|
||||
auto it2 = p2.cbegin();
|
||||
for (;;) {
|
||||
if (! (*it == *it2))
|
||||
return false;
|
||||
if (++ it == begin)
|
||||
return true;
|
||||
++ it2;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool operator!=(const MutablePolygon &p1, const MutablePolygon &p2) { return ! (p1 == p2); }
|
||||
|
||||
// Remove exact duplicate points. May reduce the polygon down to empty polygon.
|
||||
void remove_duplicates(MutablePolygon &polygon);
|
||||
void remove_duplicates(MutablePolygon &polygon, double eps);
|
||||
|
||||
void smooth_outward(MutablePolygon &polygon, coord_t clip_dist_scaled);
|
||||
|
||||
inline Polygon smooth_outward(Polygon polygon, coord_t clip_dist_scaled)
|
||||
{
|
||||
MutablePolygon mp(polygon, polygon.size() * 2);
|
||||
smooth_outward(mp, clip_dist_scaled);
|
||||
mp.polygon(polygon);
|
||||
return polygon;
|
||||
}
|
||||
|
||||
inline Polygons smooth_outward(Polygons polygons, coord_t clip_dist_scaled)
|
||||
{
|
||||
MutablePolygon mp;
|
||||
for (Polygon &polygon : polygons) {
|
||||
mp.assign(polygon, polygon.size() * 2);
|
||||
smooth_outward(mp, clip_dist_scaled);
|
||||
mp.polygon(polygon);
|
||||
}
|
||||
polygons.erase(std::remove_if(polygons.begin(), polygons.end(), [](const auto &p){ return p.empty(); }), polygons.end());
|
||||
return polygons;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // slic3r_MutablePolygon_hpp_
|
@ -22,74 +22,54 @@ namespace Slic3r {
|
||||
class TriangleMeshDataAdapter {
|
||||
public:
|
||||
const TriangleMesh &mesh;
|
||||
float voxel_scale;
|
||||
|
||||
size_t polygonCount() const { return mesh.its.indices.size(); }
|
||||
size_t pointCount() const { return mesh.its.vertices.size(); }
|
||||
size_t vertexCount(size_t) const { return 3; }
|
||||
|
||||
// Return position pos in local grid index space for polygon n and vertex v
|
||||
void getIndexSpacePoint(size_t n, size_t v, openvdb::Vec3d& pos) const;
|
||||
// The actual mesh will appear to openvdb as scaled uniformly by voxel_size
|
||||
// And the voxel count per unit volume can be affected this way.
|
||||
void getIndexSpacePoint(size_t n, size_t v, openvdb::Vec3d& pos) const
|
||||
{
|
||||
auto vidx = size_t(mesh.its.indices[n](Eigen::Index(v)));
|
||||
Slic3r::Vec3d p = mesh.its.vertices[vidx].cast<double>() * voxel_scale;
|
||||
pos = {p.x(), p.y(), p.z()};
|
||||
}
|
||||
|
||||
TriangleMeshDataAdapter(const TriangleMesh &m, float voxel_sc = 1.f)
|
||||
: mesh{m}, voxel_scale{voxel_sc} {};
|
||||
};
|
||||
|
||||
class Contour3DDataAdapter {
|
||||
public:
|
||||
const sla::Contour3D &mesh;
|
||||
|
||||
size_t polygonCount() const { return mesh.faces3.size() + mesh.faces4.size(); }
|
||||
size_t pointCount() const { return mesh.points.size(); }
|
||||
size_t vertexCount(size_t n) const { return n < mesh.faces3.size() ? 3 : 4; }
|
||||
|
||||
// Return position pos in local grid index space for polygon n and vertex v
|
||||
void getIndexSpacePoint(size_t n, size_t v, openvdb::Vec3d& pos) const;
|
||||
};
|
||||
|
||||
void TriangleMeshDataAdapter::getIndexSpacePoint(size_t n,
|
||||
size_t v,
|
||||
openvdb::Vec3d &pos) const
|
||||
{
|
||||
auto vidx = size_t(mesh.its.indices[n](Eigen::Index(v)));
|
||||
Slic3r::Vec3d p = mesh.its.vertices[vidx].cast<double>();
|
||||
pos = {p.x(), p.y(), p.z()};
|
||||
}
|
||||
|
||||
void Contour3DDataAdapter::getIndexSpacePoint(size_t n,
|
||||
size_t v,
|
||||
openvdb::Vec3d &pos) const
|
||||
{
|
||||
size_t vidx = 0;
|
||||
if (n < mesh.faces3.size()) vidx = size_t(mesh.faces3[n](Eigen::Index(v)));
|
||||
else vidx = size_t(mesh.faces4[n - mesh.faces3.size()](Eigen::Index(v)));
|
||||
|
||||
Slic3r::Vec3d p = mesh.points[vidx];
|
||||
pos = {p.x(), p.y(), p.z()};
|
||||
}
|
||||
|
||||
|
||||
// TODO: Do I need to call initialize? Seems to work without it as well but the
|
||||
// docs say it should be called ones. It does a mutex lock-unlock sequence all
|
||||
// even if was called previously.
|
||||
openvdb::FloatGrid::Ptr mesh_to_grid(const TriangleMesh &mesh,
|
||||
openvdb::FloatGrid::Ptr mesh_to_grid(const TriangleMesh & mesh,
|
||||
const openvdb::math::Transform &tr,
|
||||
float exteriorBandWidth,
|
||||
float interiorBandWidth,
|
||||
int flags)
|
||||
float voxel_scale,
|
||||
float exteriorBandWidth,
|
||||
float interiorBandWidth,
|
||||
int flags)
|
||||
{
|
||||
openvdb::initialize();
|
||||
|
||||
TriangleMeshPtrs meshparts = mesh.split();
|
||||
TriangleMeshPtrs meshparts_raw = mesh.split();
|
||||
auto meshparts = reserve_vector<std::unique_ptr<TriangleMesh>>(meshparts_raw.size());
|
||||
for (auto *p : meshparts_raw)
|
||||
meshparts.emplace_back(p);
|
||||
|
||||
auto it = std::remove_if(meshparts.begin(), meshparts.end(),
|
||||
[](TriangleMesh *m){
|
||||
m->require_shared_vertices();
|
||||
return !m->is_manifold() || m->volume() < EPSILON;
|
||||
});
|
||||
auto it = std::remove_if(meshparts.begin(), meshparts.end(), [](auto &m) {
|
||||
m->require_shared_vertices();
|
||||
return m->volume() < EPSILON;
|
||||
});
|
||||
|
||||
meshparts.erase(it, meshparts.end());
|
||||
|
||||
openvdb::FloatGrid::Ptr grid;
|
||||
for (TriangleMesh *m : meshparts) {
|
||||
for (auto &m : meshparts) {
|
||||
auto subgrid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
|
||||
TriangleMeshDataAdapter{*m}, tr, exteriorBandWidth,
|
||||
TriangleMeshDataAdapter{*m, voxel_scale}, tr, exteriorBandWidth,
|
||||
interiorBandWidth, flags);
|
||||
|
||||
if (grid && subgrid) openvdb::tools::csgUnion(*grid, *subgrid);
|
||||
@ -106,19 +86,9 @@ openvdb::FloatGrid::Ptr mesh_to_grid(const TriangleMesh &mesh,
|
||||
interiorBandWidth, flags);
|
||||
}
|
||||
|
||||
return grid;
|
||||
}
|
||||
grid->insertMeta("voxel_scale", openvdb::FloatMetadata(voxel_scale));
|
||||
|
||||
openvdb::FloatGrid::Ptr mesh_to_grid(const sla::Contour3D &mesh,
|
||||
const openvdb::math::Transform &tr,
|
||||
float exteriorBandWidth,
|
||||
float interiorBandWidth,
|
||||
int flags)
|
||||
{
|
||||
openvdb::initialize();
|
||||
return openvdb::tools::meshToVolume<openvdb::FloatGrid>(
|
||||
Contour3DDataAdapter{mesh}, tr, exteriorBandWidth, interiorBandWidth,
|
||||
flags);
|
||||
return grid;
|
||||
}
|
||||
|
||||
template<class Grid>
|
||||
@ -136,12 +106,17 @@ sla::Contour3D _volumeToMesh(const Grid &grid,
|
||||
openvdb::tools::volumeToMesh(grid, points, triangles, quads, isovalue,
|
||||
adaptivity, relaxDisorientedTriangles);
|
||||
|
||||
float scale = 1.;
|
||||
try {
|
||||
scale = grid.template metaValue<float>("voxel_scale");
|
||||
} catch (...) { }
|
||||
|
||||
sla::Contour3D ret;
|
||||
ret.points.reserve(points.size());
|
||||
ret.faces3.reserve(triangles.size());
|
||||
ret.faces4.reserve(quads.size());
|
||||
|
||||
for (auto &v : points) ret.points.emplace_back(to_vec3d(v));
|
||||
for (auto &v : points) ret.points.emplace_back(to_vec3d(v) / scale);
|
||||
for (auto &v : triangles) ret.faces3.emplace_back(to_vec3i(v));
|
||||
for (auto &v : quads) ret.faces4.emplace_back(to_vec4i(v));
|
||||
|
||||
@ -166,9 +141,18 @@ sla::Contour3D grid_to_contour3d(const openvdb::FloatGrid &grid,
|
||||
relaxDisorientedTriangles);
|
||||
}
|
||||
|
||||
openvdb::FloatGrid::Ptr redistance_grid(const openvdb::FloatGrid &grid, double iso, double er, double ir)
|
||||
openvdb::FloatGrid::Ptr redistance_grid(const openvdb::FloatGrid &grid,
|
||||
double iso,
|
||||
double er,
|
||||
double ir)
|
||||
{
|
||||
return openvdb::tools::levelSetRebuild(grid, float(iso), float(er), float(ir));
|
||||
auto new_grid = openvdb::tools::levelSetRebuild(grid, float(iso),
|
||||
float(er), float(ir));
|
||||
|
||||
// Copies voxel_scale metadata, if it exists.
|
||||
new_grid->insertMeta(*grid.deepCopyMeta());
|
||||
|
||||
return new_grid;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -21,14 +21,16 @@ inline Vec3d to_vec3d(const openvdb::Vec3s &v) { return to_vec3f(v).cast<double>
|
||||
inline Vec3i to_vec3i(const openvdb::Vec3I &v) { return Vec3i{int(v[0]), int(v[1]), int(v[2])}; }
|
||||
inline Vec4i to_vec4i(const openvdb::Vec4I &v) { return Vec4i{int(v[0]), int(v[1]), int(v[2]), int(v[3])}; }
|
||||
|
||||
// Here voxel_scale defines the scaling of voxels which affects the voxel count.
|
||||
// 1.0 value means a voxel for every unit cube. 2 means the model is scaled to
|
||||
// be 2x larger and the voxel count is increased by the increment in the scaled
|
||||
// volume, thus 4 times. This kind a sampling accuracy selection is not
|
||||
// achievable through the Transform parameter. (TODO: or is it?)
|
||||
// The resulting grid will contain the voxel_scale in its metadata under the
|
||||
// "voxel_scale" key to be used in grid_to_mesh function.
|
||||
openvdb::FloatGrid::Ptr mesh_to_grid(const TriangleMesh & mesh,
|
||||
const openvdb::math::Transform &tr = {},
|
||||
float exteriorBandWidth = 3.0f,
|
||||
float interiorBandWidth = 3.0f,
|
||||
int flags = 0);
|
||||
|
||||
openvdb::FloatGrid::Ptr mesh_to_grid(const sla::Contour3D & mesh,
|
||||
const openvdb::math::Transform &tr = {},
|
||||
float voxel_scale = 1.f,
|
||||
float exteriorBandWidth = 3.0f,
|
||||
float interiorBandWidth = 3.0f,
|
||||
int flags = 0);
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
static ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thick_polyline, ExtrusionRole role, Flow &flow, const float tolerance)
|
||||
static ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, const float tolerance)
|
||||
{
|
||||
ExtrusionPaths paths;
|
||||
ExtrusionPath path(role);
|
||||
@ -62,15 +62,15 @@ static ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thi
|
||||
path.polyline.append(line.b);
|
||||
// Convert from spacing to extrusion width based on the extrusion model
|
||||
// of a square extrusion ended with semi circles.
|
||||
flow.width = unscale<float>(w) + flow.height * float(1. - 0.25 * PI);
|
||||
Flow new_flow = flow.with_width(unscale<float>(w) + flow.height() * float(1. - 0.25 * PI));
|
||||
#ifdef SLIC3R_DEBUG
|
||||
printf(" filling %f gap\n", flow.width);
|
||||
#endif
|
||||
path.mm3_per_mm = flow.mm3_per_mm();
|
||||
path.width = flow.width;
|
||||
path.height = flow.height;
|
||||
path.mm3_per_mm = new_flow.mm3_per_mm();
|
||||
path.width = new_flow.width();
|
||||
path.height = new_flow.height();
|
||||
} else {
|
||||
thickness_delta = fabs(scale_(flow.width) - w);
|
||||
thickness_delta = fabs(scale_(flow.width()) - w);
|
||||
if (thickness_delta <= tolerance) {
|
||||
// the width difference between this line and the current flow width is
|
||||
// within the accepted tolerance
|
||||
@ -88,7 +88,7 @@ static ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thi
|
||||
return paths;
|
||||
}
|
||||
|
||||
static void variable_width(const ThickPolylines& polylines, ExtrusionRole role, Flow flow, std::vector<ExtrusionEntity*> &out)
|
||||
static void variable_width(const ThickPolylines& polylines, ExtrusionRole role, const Flow &flow, std::vector<ExtrusionEntity*> &out)
|
||||
{
|
||||
// This value determines granularity of adaptive width, as G-code does not allow
|
||||
// variable extrusion within a single move; this value shall only affect the amount
|
||||
@ -205,8 +205,8 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
||||
paths,
|
||||
intersection_pl({ polygon }, perimeter_generator.lower_slices_polygons()),
|
||||
role,
|
||||
is_external ? perimeter_generator.ext_mm3_per_mm() : perimeter_generator.mm3_per_mm(),
|
||||
is_external ? perimeter_generator.ext_perimeter_flow.width : perimeter_generator.perimeter_flow.width,
|
||||
is_external ? perimeter_generator.ext_mm3_per_mm() : perimeter_generator.mm3_per_mm(),
|
||||
is_external ? perimeter_generator.ext_perimeter_flow.width() : perimeter_generator.perimeter_flow.width(),
|
||||
(float)perimeter_generator.layer_height);
|
||||
|
||||
// get overhang paths by checking what parts of this loop fall
|
||||
@ -217,8 +217,8 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
||||
diff_pl({ polygon }, perimeter_generator.lower_slices_polygons()),
|
||||
erOverhangPerimeter,
|
||||
perimeter_generator.mm3_per_mm_overhang(),
|
||||
perimeter_generator.overhang_flow.width,
|
||||
perimeter_generator.overhang_flow.height);
|
||||
perimeter_generator.overhang_flow.width(),
|
||||
perimeter_generator.overhang_flow.height());
|
||||
|
||||
// Reapply the nearest point search for starting point.
|
||||
// We allow polyline reversal because Clipper may have randomly reversed polylines during clipping.
|
||||
@ -226,8 +226,8 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
||||
} else {
|
||||
ExtrusionPath path(role);
|
||||
path.polyline = polygon.split_at_first_point();
|
||||
path.mm3_per_mm = is_external ? perimeter_generator.ext_mm3_per_mm() : perimeter_generator.mm3_per_mm();
|
||||
path.width = is_external ? perimeter_generator.ext_perimeter_flow.width : perimeter_generator.perimeter_flow.width;
|
||||
path.mm3_per_mm = is_external ? perimeter_generator.ext_mm3_per_mm() : perimeter_generator.mm3_per_mm();
|
||||
path.width = is_external ? perimeter_generator.ext_perimeter_flow.width() : perimeter_generator.perimeter_flow.width();
|
||||
path.height = (float)perimeter_generator.layer_height;
|
||||
paths.push_back(path);
|
||||
}
|
||||
@ -286,7 +286,7 @@ void PerimeterGenerator::process()
|
||||
m_ext_mm3_per_mm = this->ext_perimeter_flow.mm3_per_mm();
|
||||
coord_t ext_perimeter_width = this->ext_perimeter_flow.scaled_width();
|
||||
coord_t ext_perimeter_spacing = this->ext_perimeter_flow.scaled_spacing();
|
||||
coord_t ext_perimeter_spacing2 = this->ext_perimeter_flow.scaled_spacing(this->perimeter_flow);
|
||||
coord_t ext_perimeter_spacing2 = scaled<coord_t>(0.5f * (this->ext_perimeter_flow.spacing() + this->perimeter_flow.spacing()));
|
||||
|
||||
// overhang perimeters
|
||||
m_mm3_per_mm_overhang = this->overhang_flow.mm3_per_mm();
|
||||
@ -346,7 +346,7 @@ void PerimeterGenerator::process()
|
||||
if (this->config->thin_walls) {
|
||||
// the following offset2 ensures almost nothing in @thin_walls is narrower than $min_width
|
||||
// (actually, something larger than that still may exist due to mitering or other causes)
|
||||
coord_t min_width = coord_t(scale_(this->ext_perimeter_flow.nozzle_diameter / 3));
|
||||
coord_t min_width = coord_t(scale_(this->ext_perimeter_flow.nozzle_diameter() / 3));
|
||||
ExPolygons expp = offset2_ex(
|
||||
// medial axis requires non-overlapping geometry
|
||||
diff_ex(to_polygons(last),
|
||||
|