Merge branch 'master' into lm_tm_hollowing

This commit is contained in:
Lukas Matena 2019-12-20 10:33:53 +01:00
commit b3f15b1c98
68 changed files with 1399 additions and 917 deletions

View File

@ -101,8 +101,8 @@ list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules/)
enable_testing ()
# Enable C++11 language standard.
set(CMAKE_CXX_STANDARD 14)
# Enable C++17 language standard.
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(NOT WIN32)

View File

@ -8,8 +8,13 @@ prusaslicer_add_cmake_project(
DEPENDS dep_boost dep_GMP dep_MPFR
)
include(GNUInstallDirs)
# CGAL, for whatever reason, makes itself non-relocatable by writing the build directory into
# CGALConfig-installation-dirs.cmake and including it in configure time.
# If this file is not present, it will not consider the stored absolute path
ExternalProject_Add_Step(dep_CGAL dep_CGAL_relocation_fix
DEPENDEES install
COMMAND ${CMAKE_COMMAND} -E remove CGALConfig-installation-dirs.cmake
WORKING_DIRECTORY "${DESTDIR}/usr/local/lib/cmake/CGAL"
)
WORKING_DIRECTORY "${DESTDIR}/usr/local/${CMAKE_INSTALL_LIBDIR}/cmake/CGAL"
)

2
deps/CMakeLists.txt vendored
View File

@ -60,7 +60,7 @@ function(prusaslicer_add_cmake_project projectname)
set(_gen "")
set(_build_j "-j${NPROC}")
if (MSVC)
set(_gen CMAKE_GENERATOR "${DEP_MSVC_GEN}")
set(_gen CMAKE_GENERATOR "${DEP_MSVC_GEN}" CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}")
set(_build_j "/m")
endif ()

View File

@ -19,7 +19,7 @@ if (MSVC)
else ()
ExternalProject_Add(dep_MPFR
URL https://www.mpfr.org/mpfr-3.1.6/mpfr-3.1.6.tar.bz2
URL http://ftp.vim.org/ftp/gnu/mpfr/mpfr-3.1.6.tar.bz2 https://www.mpfr.org/mpfr-3.1.6/mpfr-3.1.6.tar.bz2 # mirrors are allowed
BUILD_IN_SOURCE ON
CONFIGURE_COMMAND ./configure --prefix=${DESTDIR}/usr/local --with-gmp=${DESTDIR}/usr/local --with-pic
BUILD_COMMAND make -j

View File

@ -4,7 +4,7 @@
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="hex_x5F_plus">
<g>
<polygon fill="#ED6B21" points="2,8 2,11 8,15 14,11 14,8 "/>
<polygon fill="#ED6B21" points="1,8 1,11 8,16 15,11 15,8 " style="stroke:white;stroke-width:1"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 446 B

After

Width:  |  Height:  |  Size: 482 B

View File

@ -4,7 +4,7 @@
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="hex_x5F_plus">
<g>
<polygon fill="#ED6B21" points="8,1 2,5 2,7 2,8 14,8 14,7 14,5 "/>
<polygon fill="#ED6B21" points="8,0 1,5 1,7 1,8 15,8 15,7 15,5" style="stroke:white;stroke-width:1"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 454 B

After

Width:  |  Height:  |  Size: 487 B

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="edit_x5F_layers_x5F_all">
<line fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="2" y1="2" x2="6" y2="2"/>
<line fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="2" y1="6" x2="6" y2="6"/>
<line fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="2" y1="10" x2="14" y2="10"/>
<line fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="2" y1="14" x2="14" y2="14"/>
<path fill="#ED6B21" d="M14.62,4.37c-0.01-0.14,0.06-0.34,0.15-0.44l0.13-0.15c0.09-0.11,0.12-0.3,0.07-0.43l-0.2-0.49
c-0.05-0.13-0.21-0.24-0.35-0.25l-0.2-0.01c-0.14-0.01-0.33-0.1-0.42-0.21c-0.09-0.1-0.37-0.46-0.38-0.6l-0.01-0.2
c-0.01-0.14-0.12-0.3-0.25-0.35l-0.49-0.2C12.52,0.97,12.33,1,12.22,1.1l-0.15,0.13c-0.11,0.09-0.31,0.16-0.44,0.15
c-0.14-0.01-0.59-0.06-0.69-0.15L10.78,1.1c-0.11-0.09-0.3-0.12-0.43-0.07l-0.49,0.2C9.73,1.28,9.61,1.44,9.6,1.58l-0.01,0.2
C9.58,1.92,9.49,2.11,9.38,2.2c-0.1,0.09-0.46,0.37-0.6,0.38L8.58,2.6c-0.14,0.01-0.3,0.12-0.35,0.25l-0.2,0.49
C7.97,3.48,8,3.67,8.1,3.78l0.13,0.15c0.09,0.11,0.16,0.31,0.15,0.44C8.37,4.52,8.32,4.96,8.23,5.07L8.1,5.22
C8,5.33,7.97,5.52,8.03,5.65l0.2,0.49C8.28,6.27,8.44,6.39,8.58,6.4l0.2,0.01c0.14,0.01,0.33,0.1,0.42,0.21
c0.09,0.1,0.37,0.46,0.38,0.6l0.01,0.2c0.01,0.14,0.12,0.3,0.25,0.35l0.49,0.2C10.48,8.03,10.67,8,10.78,7.9l0.15-0.13
c0.11-0.09,0.31-0.16,0.44-0.15c0.14,0.01,0.59,0.06,0.69,0.15l0.15,0.13c0.11,0.09,0.3,0.12,0.43,0.07l0.49-0.2
c0.13-0.05,0.24-0.21,0.25-0.35l0.01-0.2c0.01-0.14,0.1-0.33,0.21-0.42s0.46-0.37,0.6-0.38l0.2-0.01c0.14-0.01,0.3-0.12,0.35-0.25
l0.2-0.49C15.03,5.52,15,5.33,14.9,5.22l-0.13-0.15C14.68,4.96,14.63,4.51,14.62,4.37z M11.5,6.6c-1.16,0-2.1-0.94-2.1-2.1
s0.94-2.1,2.1-2.1s2.1,0.94,2.1,2.1S12.66,6.6,11.5,6.6z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="edit_x5F_layers_x5F_some_1_">
<line fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="2" y1="11" x2="14" y2="11"/>
<line fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="2" y1="14" x2="14" y2="14"/>
<path fill="#ED6B21" d="M7.68,8.87c0.18,0.18,0.47,0.18,0.64,0L11.19,6c0.18-0.18,0.12-0.32-0.13-0.32H9.62
c-0.25,0-0.45-0.2-0.45-0.45V1.45C9.17,1.2,8.97,1,8.71,1H7.29C7.03,1,6.83,1.2,6.83,1.45v3.77c0,0.25-0.2,0.45-0.45,0.45H4.95
C4.7,5.68,4.64,5.82,4.81,6L7.68,8.87z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 931 B

View File

@ -0,0 +1,15 @@
<?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 id="extruder_x2B_funnel">
<rect x="1" y="1" display="none" fill="#FFFFFF" width="14" height="6"/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-miterlimit="10" x1="8" y1="9.37" x2="8" y2="15"/>
<polygon display="none" fill="#FFFFFF" points="5,7 5,8 8,10 11,8 11,7 "/>
<g>
<path fill="#FFFFFF" d="M14,2l0,4h-3c-0.55,0-1,0.45-1,1v0.47L8,8.8L6,7.46V7c0-0.55-0.45-1-1-1L2,6l0-4H14 M14,1H2
C1.45,1,1,1.45,1,2v4c0,0.55,0.45,1,1,1h3v1l2.45,1.63C7.61,9.74,7.81,9.8,8,9.8c0.19,0,0.39-0.06,0.55-0.17L11,8V7h3
c0.55,0,1-0.45,1-1V2C15,1.45,14.55,1,14,1L14,1z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 941 B

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="mirror_x5F_off">
<g>
<path fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M10,3.01l3,0c0.55,0,1,0.45,1,1v8c0,0.55-0.45,1-1,1h-3"/>
</g>
<g>
<path fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M6,3.01L3,3C2.45,3,2,3.45,2,4v8c0,0.55,0.45,1,1,1h3"/>
</g>
<g>
<g>
<line fill="none" stroke="#FFFFFF" stroke-linecap="round" stroke-miterlimit="10" x1="8" y1="1" x2="8" y2="3.5"/>
<line fill="none" stroke="#FFFFFF" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,3" x1="8" y1="6.5" x2="8" y2="11"/>
<line fill="none" stroke="#FFFFFF" stroke-linecap="round" stroke-miterlimit="10" x1="8" y1="12.5" x2="8" y2="15"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="mirror_x5F_on">
<g>
<path fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" d="M10,3.01l3,0
c0.55,0,1,0.45,1,1v8c0,0.55-0.45,1-1,1h-3"/>
</g>
<g>
<path fill="none" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" d="M6,3.01L3,3
C2.45,3,2,3.45,2,4v8c0,0.55,0.45,1,1,1h3"/>
</g>
<g>
<g>
<line fill="none" stroke="#FFFFFF" stroke-linecap="round" stroke-miterlimit="10" x1="8" y1="1" x2="8" y2="3.5"/>
<line fill="none" stroke="#FFFFFF" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,3" x1="8" y1="6.5" x2="8" y2="11"/>
<line fill="none" stroke="#FFFFFF" stroke-linecap="round" stroke-miterlimit="10" x1="8" y1="12.5" x2="8" y2="15"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,25 @@
<?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 id="notes">
<g>
<path fill="#FFFFFF" d="M11,2l0,12l-9,0L2,2H11 M11,1H2C1.45,1,1,1.45,1,2V14c0,0.55,0.45,1,1,1H11c0.55,0,1-0.45,1-1V2
C12,1.45,11.55,1,11,1L11,1z"/>
</g>
<path fill="#ED6B21" d="M14,3L14,3c-0.55,0-1,0.45-1,1v10c0,0.55,0.45,1,1,1h0c0.55,0,1-0.45,1-1V4C15,3.45,14.55,3,14,3z"/>
<polygon fill="#ED6B21" points="15,4 13,4 14,1 "/>
<g>
<line fill="none" stroke="#FFFFFF" stroke-linecap="round" stroke-miterlimit="10" x1="3" y1="4" x2="10" y2="4"/>
</g>
<g>
<line fill="none" stroke="#FFFFFF" stroke-linecap="round" stroke-miterlimit="10" x1="3" y1="6" x2="10" y2="6"/>
</g>
<g>
<line fill="none" stroke="#FFFFFF" stroke-linecap="round" stroke-miterlimit="10" x1="3" y1="8" x2="10" y2="8"/>
</g>
<g>
<line fill="none" stroke="#FFFFFF" stroke-linecap="round" stroke-miterlimit="10" x1="3" y1="10" x2="7" y2="10"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.6, 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">
<path id="undo_1_" fill="#FFFFFF" d="M1.95,7.01h10.24L8.86,2.51c-0.31-0.42-0.22-1.01,0.2-1.32c0.42-0.31,1.01-0.22,1.32,0.2
l4.44,6.01c0,0.01,0.01,0.01,0.01,0.02c0.01,0.01,0.02,0.03,0.03,0.04c0.01,0.02,0.03,0.05,0.04,0.07c0.01,0.02,0.02,0.03,0.03,0.05
c0.01,0.01,0.01,0.03,0.02,0.04c0.01,0.02,0.02,0.05,0.02,0.07c0.01,0.02,0.01,0.04,0.02,0.06c0,0.01,0,0.03,0.01,0.04
c0,0.02,0.01,0.05,0.01,0.07c0,0.02,0.01,0.05,0.01,0.07c0,0.01,0,0.01,0,0.02c0,0.01,0,0.01,0,0.02c0,0.02,0,0.05-0.01,0.07
c0,0.02,0,0.05-0.01,0.07c0,0.01,0,0.03-0.01,0.04c0,0.02-0.01,0.04-0.02,0.06c-0.01,0.02-0.01,0.05-0.02,0.07
c-0.01,0.01-0.01,0.03-0.02,0.04c-0.01,0.02-0.02,0.04-0.03,0.05c-0.01,0.02-0.02,0.04-0.04,0.07c-0.01,0.01-0.02,0.03-0.03,0.04
c0,0.01-0.01,0.01-0.01,0.02l-4.54,6.05c-0.19,0.25-0.47,0.38-0.76,0.38c-0.2,0-0.4-0.06-0.57-0.19c-0.42-0.31-0.5-0.91-0.19-1.32
l3.41-4.54H1.95C1.42,8.91,1,8.48,1,7.96C1,7.44,1.42,7.01,1.95,7.01z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.6, 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">
<path id="undo_1_" fill="#FFFFFF" d="M14.05,7.01H3.82l3.32-4.51c0.31-0.42,0.22-1.01-0.2-1.32c-0.42-0.31-1.01-0.22-1.32,0.2
L1.18,7.4c0,0.01-0.01,0.01-0.01,0.02C1.17,7.43,1.16,7.44,1.15,7.46C1.13,7.48,1.12,7.5,1.11,7.53C1.1,7.54,1.09,7.56,1.08,7.58
C1.08,7.59,1.07,7.61,1.06,7.62C1.06,7.65,1.05,7.67,1.04,7.69C1.04,7.71,1.03,7.73,1.02,7.75c0,0.01,0,0.03-0.01,0.04
c0,0.02-0.01,0.05-0.01,0.07C1.01,7.89,1,7.92,1,7.94c0,0.01,0,0.01,0,0.02c0,0.01,0,0.01,0,0.02c0,0.02,0,0.05,0.01,0.07
c0,0.02,0,0.05,0.01,0.07c0,0.01,0,0.03,0.01,0.04c0,0.02,0.01,0.04,0.02,0.06C1.05,8.26,1.06,8.28,1.07,8.3
c0.01,0.01,0.01,0.03,0.02,0.04C1.09,8.36,1.1,8.38,1.11,8.4c0.01,0.02,0.02,0.04,0.04,0.07c0.01,0.01,0.02,0.03,0.03,0.04
c0,0.01,0.01,0.01,0.01,0.02l4.54,6.05c0.19,0.25,0.47,0.38,0.76,0.38c0.2,0,0.4-0.06,0.57-0.19c0.42-0.31,0.5-0.91,0.19-1.32
L3.84,8.91h10.22c0.52,0,0.95-0.42,0.95-0.95C15,7.44,14.58,7.01,14.05,7.01z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -106,7 +106,7 @@ compatible_printers =
complete_objects = 0
default_acceleration = 1000
dont_support_bridges = 1
elefant_foot_compensation = 0
elefant_foot_compensation = 0.2
ensure_vertical_shell_thickness = 1
external_fill_pattern = rectilinear
external_perimeters_first = 0
@ -223,6 +223,7 @@ extruder_clearance_radius = 35
# Print parameters common to a 0.25mm diameter nozzle.
[print:*0.25nozzle*]
elefant_foot_compensation = 0
external_perimeter_extrusion_width = 0.25
extrusion_width = 0.25
first_layer_extrusion_width = 0.3
@ -238,6 +239,7 @@ support_material_xy_spacing = 150%
output_filename_format = {input_filename_base}_{nozzle_diameter[0]}n_{layer_height}mm_{filament_type[0]}_{printer_model}_{print_time}.gcode
[print:*0.25nozzleMK3*]
elefant_foot_compensation = 0
external_perimeter_extrusion_width = 0.25
extrusion_width = 0.25
first_layer_extrusion_width = 0.3
@ -271,6 +273,7 @@ fill_density = 20%
output_filename_format = {input_filename_base}_{nozzle_diameter[0]}n_{layer_height}mm_{filament_type[0]}_{printer_model}_{print_time}.gcode
[print:*0.25nozzleMINI*]
elefant_foot_compensation = 0
external_perimeter_extrusion_width = 0.25
extrusion_width = 0.25
first_layer_extrusion_width = 0.3
@ -2993,21 +2996,21 @@ inherits = *common 0.025*
exposure_time = 6
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Grey Tough @0.025]
inherits = *common 0.025*
exposure_time = 7
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Azure Blue Tough @0.025]
inherits = *common 0.025*
exposure_time = 7
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Maroon Tough @0.025]
@ -3015,56 +3018,56 @@ inherits = *common 0.025*
exposure_time = 6
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Beige Tough @0.025]
inherits = *common 0.025*
exposure_time = 6
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Pink Tough @0.025]
inherits = *common 0.025*
exposure_time = 7
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa White Tough @0.025]
inherits = *common 0.025*
exposure_time = 6.5
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Transparent Tough @0.025]
inherits = *common 0.025*
exposure_time = 6
initial_exposure_time = 15
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Green Dental Casting @0.025]
inherits = *common 0.025*
exposure_time = 12
initial_exposure_time = 40
material_type = Casting
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Transparent Green Tough @0.025]
inherits = *common 0.025*
exposure_time = 5
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Clear ABS like @0.025]
inherits = *common 0.025*
exposure_time = 6
initial_exposure_time = 30
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
## [sla_material:Prusa ABS like White @0.025]
## inherits = *common 0.025*
@ -3076,35 +3079,35 @@ inherits = *common 0.025*
exposure_time = 5
initial_exposure_time = 30
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Super Low Odor Cyan Tough @0.025]
inherits = *common 0.025*
exposure_time = 5
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Super Low Odor Magenta Tough @0.025]
inherits = *common 0.025*
exposure_time = 5
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Super Low Odor Yellow Tough @0.025]
inherits = *common 0.025*
exposure_time = 5
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Orange-Yellow Teeth Model @0.025]
inherits = *common 0.025*
exposure_time = 5
initial_exposure_time = 30
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
########### Materials 0.05
@ -3333,91 +3336,91 @@ inherits = *common 0.05*
exposure_time = 7
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Orange Tough @0.05]
inherits = *common 0.05*
exposure_time = 7.5
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Grey Tough @0.05]
inherits = *common 0.05*
exposure_time = 8.5
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Black Tough @0.05]
inherits = *common 0.05*
exposure_time = 6
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
## [sla_material:Prusa Super Low Odor Beige Tough @0.05]
## inherits = *common 0.05*
## exposure_time = 7.5
## initial_exposure_time = 35
## material_type = Tough
## material_vendor = Prusa
## material_vendor = Made for Prusa
## [sla_material:Prusa Super Low Odor White Tough @0.05]
## inherits = *common 0.05*
## exposure_time = 6.5
## initial_exposure_time = 35
## material_type = Tough
## material_vendor = Prusa
## material_vendor = Made for Prusa
## [sla_material:Prusa Super Low Odor Grey Tough @0.05]
## inherits = *common 0.05*
## exposure_time = 6.5
## initial_exposure_time = 35
## material_type = Tough
## material_vendor = Prusa
## material_vendor = Made for Prusa
[sla_material:Prusa Super Low Odor Cyan Tough @0.05]
inherits = *common 0.05*
exposure_time = 6
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Super Low Odor Magenta Tough @0.05]
inherits = *common 0.05*
exposure_time = 6
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Super Low Odor Yellow Tough @0.05]
inherits = *common 0.05*
exposure_time = 6
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
## [sla_material:Prusa Black High Tenacity @0.05]
## inherits = *common 0.05*
## exposure_time = 7
## initial_exposure_time = 35
## material_type = Tough
## material_vendor = Prusa
## material_vendor = Made for Prusa
[sla_material:Prusa Orange-Yellow Teeth Model @0.05]
inherits = *common 0.05*
exposure_time = 7
initial_exposure_time = 30
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Green Dental Casting @0.05]
inherits = *common 0.05*
exposure_time = 13
initial_exposure_time = 50
material_type = Casting
material_vendor = Prusa
material_vendor = Made for Prusa
## [sla_material:Prusa Yellow Solid @0.05]
## inherits = *common 0.05*
@ -3429,49 +3432,49 @@ inherits = *common 0.05*
exposure_time = 7.5
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Transparent Green Tough @0.05]
inherits = *common 0.05*
exposure_time = 6
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Transparent Red Tough @0.05]
inherits = *common 0.05*
exposure_time = 6
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Maroon Tough @0.05]
inherits = *common 0.05*
exposure_time = 7.5
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Pink Tough @0.05]
inherits = *common 0.05*
exposure_time = 8
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Azure Blue Tough @0.05]
inherits = *common 0.05*
exposure_time = 8
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Transparent Tough @0.05]
inherits = *common 0.05*
exposure_time = 7
initial_exposure_time = 15
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
## [sla_material:Prusa Yellow Flexible @0.05]
## inherits = *common 0.05*
@ -3483,7 +3486,7 @@ inherits = *common 0.05*
exposure_time = 5
initial_exposure_time = 15
material_type = Flexible
material_vendor = Prusa
material_vendor = Made for Prusa
## [sla_material:Prusa White Flexible @0.05]
## inherits = *common 0.05*
@ -3495,7 +3498,7 @@ inherits = *common 0.05*
exposure_time = 5
initial_exposure_time = 15
material_type = Flexible
material_vendor = Prusa
material_vendor = Made for Prusa
## [sla_material:Prusa Black Flexible @0.05]
## inherits = *common 0.05*
@ -3512,7 +3515,7 @@ inherits = *common 0.05*
exposure_time = 8
initial_exposure_time = 30
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
## [sla_material:Prusa ABS like White @0.05]
## inherits = *common 0.05*
@ -3524,14 +3527,14 @@ inherits = *common 0.05*
exposure_time = 13
initial_exposure_time = 45
material_type = Casting
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Grey High Tenacity @0.05]
inherits = *common 0.05*
exposure_time = 7
initial_exposure_time = 30
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
########### Materials 0.035
@ -3540,7 +3543,7 @@ inherits = *common 0.035*
exposure_time = 6
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
########### Materials 0.1
@ -3565,70 +3568,70 @@ inherits = *common 0.1*
exposure_time = 13
initial_exposure_time = 45
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Beige Tough @0.1]
inherits = *common 0.1*
exposure_time = 13
initial_exposure_time = 45
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Pink Tough @0.1]
inherits = *common 0.1*
exposure_time = 13
initial_exposure_time = 45
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Azure Blue Tough @0.1]
inherits = *common 0.1*
exposure_time = 13
initial_exposure_time = 45
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Maroon Tough @0.1]
inherits = *common 0.1*
exposure_time = 13
initial_exposure_time = 45
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa White Tough @0.1]
inherits = *common 0.1*
exposure_time = 13
initial_exposure_time = 45
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Black Tough @0.1]
inherits = *common 0.1*
exposure_time = 13
initial_exposure_time = 55
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Transparent Tough @0.1]
inherits = *common 0.1*
exposure_time = 8
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Green Dental Casting @0.1]
inherits = *common 0.1*
exposure_time = 15
initial_exposure_time = 50
material_type = Casting
material_vendor = Prusa
material_vendor = Made for Prusa
[sla_material:Prusa Transparent Green Tough @0.1]
inherits = *common 0.1*
exposure_time = 7
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa
material_vendor = Made for Prusa
[printer:*common*]
printer_technology = FFF

View File

@ -1,8 +1,5 @@
cmake_minimum_required(VERSION 3.0)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_definitions(-D_BSD_SOURCE -D_DEFAULT_SOURCE) # To enable various useful macros and functions on Unices
remove_definitions(-D_UNICODE -DUNICODE)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

View File

@ -15,5 +15,5 @@ add_library(hidapi STATIC ${HIDAPI_IMPL})
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
# Don't link the udev library, as there are two versions out there (libudev.so.0, libudev.so.1), so they are linked explicitely.
# target_link_libraries(hidapi udev)
target_link_libraries(hidapi)
target_link_libraries(hidapi dl)
endif()

5
src/hidapi/README.md Normal file
View File

@ -0,0 +1,5 @@
** hidapi is a c++ library for communicating with USB and Bluetooth HID devices on Linux, Mac and Windows.**
For more information go to https://github.com/libusb/hidapi
THIS DIRECTORY CONTAINS THE hidapi-0.9.0 7da5cc9 SOURCE DISTRIBUTION.

View File

@ -679,133 +679,73 @@ ClipperLib::PolyTree union_pt(ExPolygons &&subject, bool safety_offset_)
return _clipper_do<ClipperLib::PolyTree>(ClipperLib::ctUnion, std::move(subject), Polygons(), ClipperLib::pftEvenOdd, safety_offset_);
}
Polygons
union_pt_chained(const Polygons &subject, bool safety_offset_)
{
ClipperLib::PolyTree polytree = union_pt(subject, safety_offset_);
Polygons retval;
traverse_pt(polytree.Childs, &retval);
return retval;
}
static ClipperLib::PolyNodes order_nodes(const ClipperLib::PolyNodes &nodes)
// Simple spatial ordering of Polynodes
ClipperLib::PolyNodes order_nodes(const ClipperLib::PolyNodes &nodes)
{
// collect ordering points
Points ordering_points;
ordering_points.reserve(nodes.size());
for (const ClipperLib::PolyNode *node : nodes)
ordering_points.emplace_back(Point(node->Contour.front().X, node->Contour.front().Y));
ordering_points.emplace_back(
Point(node->Contour.front().X, node->Contour.front().Y));
// perform the ordering
ClipperLib::PolyNodes ordered_nodes = chain_clipper_polynodes(ordering_points, nodes);
ClipperLib::PolyNodes ordered_nodes =
chain_clipper_polynodes(ordering_points, nodes);
return ordered_nodes;
}
enum class e_ordering {
ORDER_POLYNODES,
DONT_ORDER_POLYNODES
};
template<e_ordering o>
void foreach_node(const ClipperLib::PolyNodes &nodes,
std::function<void(const ClipperLib::PolyNode *)> fn);
template<> void foreach_node<e_ordering::DONT_ORDER_POLYNODES>(
const ClipperLib::PolyNodes & nodes,
std::function<void(const ClipperLib::PolyNode *)> fn)
static void traverse_pt_noholes(const ClipperLib::PolyNodes &nodes, Polygons *out)
{
for (auto &n : nodes) fn(n);
foreach_node<e_ordering::ON>(nodes, [&out](const ClipperLib::PolyNode *node)
{
traverse_pt_noholes(node->Childs, out);
out->emplace_back(ClipperPath_to_Slic3rPolygon(node->Contour));
if (node->IsHole()) out->back().reverse(); // ccw
});
}
template<> void foreach_node<e_ordering::ORDER_POLYNODES>(
const ClipperLib::PolyNodes & nodes,
std::function<void(const ClipperLib::PolyNode *)> fn)
{
auto ordered_nodes = order_nodes(nodes);
for (auto &n : ordered_nodes) fn(n);
}
template<e_ordering o>
void _traverse_pt(const ClipperLib::PolyNodes &nodes, Polygons *retval)
static void traverse_pt_old(ClipperLib::PolyNodes &nodes, Polygons* retval)
{
/* use a nearest neighbor search to order these children
TODO: supply start_near to chained_path() too? */
// collect ordering points
Points ordering_points;
ordering_points.reserve(nodes.size());
for (ClipperLib::PolyNodes::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
Point p((*it)->Contour.front().X, (*it)->Contour.front().Y);
ordering_points.push_back(p);
}
// perform the ordering
ClipperLib::PolyNodes ordered_nodes = chain_clipper_polynodes(ordering_points, nodes);
// push results recursively
foreach_node<o>(nodes, [&retval](const ClipperLib::PolyNode *node) {
for (ClipperLib::PolyNodes::iterator it = ordered_nodes.begin(); it != ordered_nodes.end(); ++it) {
// traverse the next depth
_traverse_pt<o>(node->Childs, retval);
retval->emplace_back(ClipperPath_to_Slic3rPolygon(node->Contour));
if (node->IsHole()) retval->back().reverse(); // ccw
});
traverse_pt_old((*it)->Childs, retval);
retval->push_back(ClipperPath_to_Slic3rPolygon((*it)->Contour));
if ((*it)->IsHole()) retval->back().reverse(); // ccw
}
}
template<e_ordering o>
void _traverse_pt(const ClipperLib::PolyNode *tree, ExPolygons *retval)
Polygons union_pt_chained(const Polygons &subject, bool safety_offset_)
{
if (!retval || !tree) return;
ClipperLib::PolyTree polytree = union_pt(subject, safety_offset_);
ExPolygons &retv = *retval;
Polygons retval;
traverse_pt_old(polytree.Childs, &retval);
return retval;
std::function<void(const ClipperLib::PolyNode*, ExPolygon&)> hole_fn;
// TODO: This needs to be tested:
// ClipperLib::PolyTree polytree = union_pt(subject, safety_offset_);
auto contour_fn = [&retv, &hole_fn](const ClipperLib::PolyNode *pptr) {
ExPolygon poly;
poly.contour.points = ClipperPath_to_Slic3rPolygon(pptr->Contour);
auto fn = std::bind(hole_fn, std::placeholders::_1, poly);
foreach_node<o>(pptr->Childs, fn);
retv.push_back(poly);
};
hole_fn = [&contour_fn](const ClipperLib::PolyNode *pptr, ExPolygon& poly)
{
poly.holes.emplace_back();
poly.holes.back().points = ClipperPath_to_Slic3rPolygon(pptr->Contour);
foreach_node<o>(pptr->Childs, contour_fn);
};
contour_fn(tree);
}
template<e_ordering o>
void _traverse_pt(const ClipperLib::PolyNodes &nodes, ExPolygons *retval)
{
// Here is the actual traverse
foreach_node<o>(nodes, [&retval](const ClipperLib::PolyNode *node) {
_traverse_pt<o>(node, retval);
});
}
void traverse_pt(const ClipperLib::PolyNode *tree, ExPolygons *retval)
{
_traverse_pt<e_ordering::ORDER_POLYNODES>(tree, retval);
}
void traverse_pt_unordered(const ClipperLib::PolyNode *tree, ExPolygons *retval)
{
_traverse_pt<e_ordering::DONT_ORDER_POLYNODES>(tree, retval);
}
void traverse_pt(const ClipperLib::PolyNodes &nodes, Polygons *retval)
{
_traverse_pt<e_ordering::ORDER_POLYNODES>(nodes, retval);
}
void traverse_pt(const ClipperLib::PolyNodes &nodes, ExPolygons *retval)
{
_traverse_pt<e_ordering::ORDER_POLYNODES>(nodes, retval);
}
void traverse_pt_unordered(const ClipperLib::PolyNodes &nodes, Polygons *retval)
{
_traverse_pt<e_ordering::DONT_ORDER_POLYNODES>(nodes, retval);
}
void traverse_pt_unordered(const ClipperLib::PolyNodes &nodes, ExPolygons *retval)
{
_traverse_pt<e_ordering::DONT_ORDER_POLYNODES>(nodes, retval);
// Polygons retval;
// traverse_pt_noholes(polytree.Childs, &retval);
// return retval;
}
Polygons simplify_polygons(const Polygons &subject, bool preserve_collinear)

View File

@ -214,7 +214,6 @@ inline Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject, bool safety_
return _clipper_ex(ClipperLib::ctUnion, to_polygons(subject), Slic3r::Polygons(), safety_offset_);
}
ClipperLib::PolyTree union_pt(const Slic3r::Polygons &subject, bool safety_offset_ = false);
ClipperLib::PolyTree union_pt(const Slic3r::ExPolygons &subject, bool safety_offset_ = false);
ClipperLib::PolyTree union_pt(Slic3r::Polygons &&subject, bool safety_offset_ = false);
@ -222,13 +221,95 @@ ClipperLib::PolyTree union_pt(Slic3r::ExPolygons &&subject, bool safety_offset_
Slic3r::Polygons union_pt_chained(const Slic3r::Polygons &subject, bool safety_offset_ = false);
void traverse_pt(const ClipperLib::PolyNodes &nodes, Slic3r::Polygons *retval);
void traverse_pt(const ClipperLib::PolyNodes &nodes, Slic3r::ExPolygons *retval);
void traverse_pt(const ClipperLib::PolyNode *tree, Slic3r::ExPolygons *retval);
ClipperLib::PolyNodes order_nodes(const ClipperLib::PolyNodes &nodes);
// Implementing generalized loop (foreach) over a list of nodes which can be
// ordered or unordered (performance gain) based on template parameter
enum class e_ordering {
ON,
OFF
};
// Create a template struct, template functions can not be partially specialized
template<e_ordering o, class Fn> struct _foreach_node {
void operator()(const ClipperLib::PolyNodes &nodes, Fn &&fn);
};
// Specialization with NO ordering
template<class Fn> struct _foreach_node<e_ordering::OFF, Fn> {
void operator()(const ClipperLib::PolyNodes &nodes, Fn &&fn)
{
for (auto &n : nodes) fn(n);
}
};
// Specialization with ordering
template<class Fn> struct _foreach_node<e_ordering::ON, Fn> {
void operator()(const ClipperLib::PolyNodes &nodes, Fn &&fn)
{
auto ordered_nodes = order_nodes(nodes);
for (auto &n : nodes) fn(n);
}
};
// Wrapper function for the foreach_node which can deduce arguments automatically
template<e_ordering o, class Fn>
void foreach_node(const ClipperLib::PolyNodes &nodes, Fn &&fn)
{
_foreach_node<o, Fn>()(nodes, std::forward<Fn>(fn));
}
// Collecting polygons of the tree into a list of Polygons, holes have clockwise
// orientation.
template<e_ordering ordering = e_ordering::OFF>
void traverse_pt(const ClipperLib::PolyNode *tree, Polygons *out)
{
if (!tree) return; // terminates recursion
// Push the contour of the current level
out->emplace_back(ClipperPath_to_Slic3rPolygon(tree->Contour));
// Do the recursion for all the children.
traverse_pt<ordering>(tree->Childs, out);
}
// Collecting polygons of the tree into a list of ExPolygons.
template<e_ordering ordering = e_ordering::OFF>
void traverse_pt(const ClipperLib::PolyNode *tree, ExPolygons *out)
{
if (!tree) return;
else if(tree->IsHole()) {
// Levels of holes are skipped and handled together with the
// contour levels.
traverse_pt<ordering>(tree->Childs, out);
return;
}
ExPolygon level;
level.contour = ClipperPath_to_Slic3rPolygon(tree->Contour);
foreach_node<ordering>(tree->Childs,
[out, &level] (const ClipperLib::PolyNode *node) {
// Holes are collected here.
level.holes.emplace_back(ClipperPath_to_Slic3rPolygon(node->Contour));
// By doing a recursion, a new level expoly is created with the contour
// and holes of the lower level. Doing this for all the childs.
traverse_pt<ordering>(node->Childs, out);
});
out->emplace_back(level);
}
template<e_ordering o = e_ordering::OFF, class ExOrJustPolygons>
void traverse_pt(const ClipperLib::PolyNodes &nodes, ExOrJustPolygons *retval)
{
foreach_node<o>(nodes, [&retval](const ClipperLib::PolyNode *node) {
traverse_pt<o>(node, retval);
});
}
void traverse_pt_unordered(const ClipperLib::PolyNodes &nodes, Slic3r::Polygons *retval);
void traverse_pt_unordered(const ClipperLib::PolyNodes &nodes, Slic3r::ExPolygons *retval);
void traverse_pt_unordered(const ClipperLib::PolyNode *tree, Slic3r::ExPolygons *retval);
/* OTHER */
Slic3r::Polygons simplify_polygons(const Slic3r::Polygons &subject, bool preserve_collinear = false);

View File

@ -612,7 +612,7 @@ void ConfigBase::load_from_gcode_file(const std::string &file)
}
ifs.seekg(0, ifs.end);
auto file_length = ifs.tellg();
auto data_length = std::min<std::fstream::streampos>(65535, file_length);
auto data_length = std::min<std::fstream::pos_type>(65535, file_length);
ifs.seekg(file_length - data_length, ifs.beg);
std::vector<char> data(size_t(data_length) + 1, 0);
ifs.read(data.data(), data_length);

View File

@ -472,7 +472,7 @@ static inline void smooth_compensation_banded(const Points &contour, float band,
float l2 = (pthis - pprev).squaredNorm();
if (l2 < dist_min2) {
float l = sqrt(l2);
int jprev = exchange(j, prev_idx_modulo(j, contour));
int jprev = std::exchange(j, prev_idx_modulo(j, contour));
while (j != i) {
const Vec2f pp = contour[j].cast<float>();
const float lthis = (pp - pprev).norm();
@ -487,7 +487,7 @@ static inline void smooth_compensation_banded(const Points &contour, float band,
prev = use_min ? std::min(prev, compensation[j]) : compensation[j];
pprev = pp;
l = lnext;
jprev = exchange(j, prev_idx_modulo(j, contour));
jprev = std::exchange(j, prev_idx_modulo(j, contour));
}
}
@ -497,7 +497,7 @@ static inline void smooth_compensation_banded(const Points &contour, float band,
l2 = (pprev - pthis).squaredNorm();
if (l2 < dist_min2) {
float l = sqrt(l2);
int jprev = exchange(j, next_idx_modulo(j, contour));
int jprev = std::exchange(j, next_idx_modulo(j, contour));
while (j != i) {
const Vec2f pp = contour[j].cast<float>();
const float lthis = (pp - pprev).norm();
@ -512,7 +512,7 @@ static inline void smooth_compensation_banded(const Points &contour, float band,
next = use_min ? std::min(next, compensation[j]) : compensation[j];
pprev = pp;
l = lnext;
jprev = exchange(j, next_idx_modulo(j, contour));
jprev = std::exchange(j, next_idx_modulo(j, contour));
}
}

View File

@ -34,8 +34,12 @@ namespace pt = boost::property_tree;
// VERSION NUMBERS
// 0 : .3mf, files saved by older slic3r or other applications. No version definition in them.
// 1 : Introduction of 3mf versioning. No other change in data saved into 3mf files.
// 2 : Meshes saved in their local system; Volumes' matrices and source data added to Metadata/Slic3r_PE_model.config file.
const unsigned int VERSION_3MF = 2;
// 2 : Volumes' matrices and source data added to Metadata/Slic3r_PE_model.config file, meshes transformed back to their coordinate system on loading.
// WARNING !! -> the version number has been rolled back to 1
// the next change should use 3
const unsigned int VERSION_3MF = 1;
// Allow loading version 2 file as well.
const unsigned int VERSION_3MF_COMPATIBLE = 2;
const char* SLIC3RPE_3MF_VERSION = "slic3rpe:Version3mf"; // definition of the metadata name saved into .model file
const std::string MODEL_FOLDER = "3D/";
@ -52,7 +56,7 @@ const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights
const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/Prusa_Slicer_layer_config_ranges.xml";
const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt";
const std::string SLA_DRAIN_HOLES_FILE = "Metadata/Slic3r_PE_sla_drain_holes.txt";
const std::string CUSTOM_GCODE_PER_HEIGHT_FILE = "Metadata/Prusa_Slicer_custom_gcode_per_height.xml";
const std::string CUSTOM_GCODE_PER_PRINT_Z_FILE = "Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml";
const char* MODEL_TAG = "model";
const char* RESOURCES_TAG = "resources";
@ -422,7 +426,7 @@ namespace Slic3r {
void _extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_sla_drain_holes_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_custom_gcode_per_height_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_custom_gcode_per_print_z_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, const std::string& archive_filename);
bool _extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model);
@ -638,10 +642,10 @@ namespace Slic3r {
// extract slic3r print config file
_extract_print_config_from_archive(archive, stat, config, filename);
}
if (boost::algorithm::iequals(name, CUSTOM_GCODE_PER_HEIGHT_FILE))
if (boost::algorithm::iequals(name, CUSTOM_GCODE_PER_PRINT_Z_FILE))
{
// extract slic3r layer config ranges file
_extract_custom_gcode_per_height_from_archive(archive, stat);
_extract_custom_gcode_per_print_z_from_archive(archive, stat);
}
else if (boost::algorithm::iequals(name, MODEL_CONFIG_FILE))
{
@ -1163,7 +1167,7 @@ namespace Slic3r {
return true;
}
void _3MF_Importer::_extract_custom_gcode_per_height_from_archive(::mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
void _3MF_Importer::_extract_custom_gcode_per_print_z_from_archive(::mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
{
if (stat.m_uncomp_size > 0)
{
@ -1178,24 +1182,23 @@ namespace Slic3r {
pt::ptree main_tree;
pt::read_xml(iss, main_tree);
if (main_tree.front().first != "custom_gcodes_per_height")
if (main_tree.front().first != "custom_gcodes_per_print_z")
return;
pt::ptree code_tree = main_tree.front().second;
if (!m_model->custom_gcode_per_height.empty())
m_model->custom_gcode_per_height.clear();
m_model->custom_gcode_per_print_z.clear();
for (const auto& code : code_tree)
{
if (code.first != "code")
continue;
pt::ptree tree = code.second;
double height = tree.get<double>("<xmlattr>.height");
std::string gcode = tree.get<std::string>("<xmlattr>.gcode");
int extruder = tree.get<int>("<xmlattr>.extruder");
std::string color = tree.get<std::string>("<xmlattr>.color");
double print_z = tree.get<double> ("<xmlattr>.print_z" );
std::string gcode = tree.get<std::string> ("<xmlattr>.gcode" );
int extruder = tree.get<int> ("<xmlattr>.extruder" );
std::string color = tree.get<std::string> ("<xmlattr>.color" );
m_model->custom_gcode_per_height.push_back(Model::CustomGCode(height, gcode, extruder, color)) ;
m_model->custom_gcode_per_print_z.push_back(Model::CustomGCode{print_z, gcode, extruder, color}) ;
}
}
}
@ -1611,7 +1614,7 @@ namespace Slic3r {
{
m_version = (unsigned int)atoi(m_curr_characters.c_str());
if (m_check_version && (m_version > VERSION_3MF))
if (m_check_version && (m_version > VERSION_3MF_COMPATIBLE))
{
// std::string msg = _(L("The selected 3mf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible."));
// throw version_error(msg.c_str());
@ -1797,20 +1800,19 @@ namespace Slic3r {
return false;
}
Slic3r::Geometry::Transformation transform;
if (m_version > 1)
Transform3d volume_matrix_to_object = Transform3d::Identity();
bool has_transform = false;
// extract the volume transformation from the volume's metadata, if present
for (const Metadata& metadata : volume_data.metadata)
{
// extract the volume transformation from the volume's metadata, if present
for (const Metadata& metadata : volume_data.metadata)
if (metadata.key == MATRIX_KEY)
{
if (metadata.key == MATRIX_KEY)
{
transform.set_from_string(metadata.value);
break;
}
volume_matrix_to_object = Slic3r::Geometry::transform3d_from_string(metadata.value);
has_transform = ! volume_matrix_to_object.isApprox(Transform3d::Identity(), 1e-10);
break;
}
}
Transform3d inv_matrix = transform.get_matrix().inverse();
Transform3d inv_matrix = volume_matrix_to_object.inverse();
// splits volume out of imported geometry
TriangleMesh triangle_mesh;
@ -1831,10 +1833,10 @@ namespace Slic3r {
{
unsigned int tri_id = geometry.triangles[src_start_id + ii + v] * 3;
Vec3f vertex(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]);
if (m_version > 1)
facet.vertex[v] = has_transform ?
// revert the vertices to the original mesh reference system
vertex = (inv_matrix * vertex.cast<double>()).cast<float>();
::memcpy(facet.vertex[v].data(), (const void*)vertex.data(), 3 * sizeof(float));
(inv_matrix * vertex.cast<double>()).cast<float>() :
vertex;
}
}
@ -1843,8 +1845,8 @@ namespace Slic3r {
ModelVolume* volume = object.add_volume(std::move(triangle_mesh));
// apply the volume matrix taken from the metadata, if present
if (m_version > 1)
volume->set_transformation(transform);
if (has_transform)
volume->set_transformation(Slic3r::Geometry::Transformation(volume_matrix_to_object));
volume->calculate_convex_hull();
// apply the remaining volume's metadata
@ -1985,7 +1987,7 @@ namespace Slic3r {
bool _add_sla_drain_holes_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config);
bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data);
bool _add_custom_gcode_per_height_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model);
};
#if ENABLE_THUMBNAIL_GENERATOR
@ -2096,9 +2098,9 @@ namespace Slic3r {
}
// Adds custom gcode per height file ("Metadata/Prusa_Slicer_custom_gcode_per_height.xml").
// Adds custom gcode per height file ("Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml").
// All custom gcode per height of whole Model are stored here
if (!_add_custom_gcode_per_height_file_to_archive(archive, model))
if (!_add_custom_gcode_per_print_z_file_to_archive(archive, model))
{
close_zip_writer(&archive);
boost::filesystem::remove(filename);
@ -2622,6 +2624,9 @@ namespace Slic3r {
bool _3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data)
{
std::stringstream stream;
// Store mesh transformation in full precision, as the volumes are stored transformed and they need to be transformed back
// when loaded as accurately as possible.
stream << std::setprecision(std::numeric_limits<double>::max_digits10);
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
stream << "<" << CONFIG_TAG << ">\n";
@ -2719,20 +2724,20 @@ namespace Slic3r {
return true;
}
bool _3MF_Exporter::_add_custom_gcode_per_height_file_to_archive( mz_zip_archive& archive, Model& model)
bool _3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive( mz_zip_archive& archive, Model& model)
{
std::string out = "";
if (!model.custom_gcode_per_height.empty())
if (!model.custom_gcode_per_print_z.empty())
{
pt::ptree tree;
pt::ptree& main_tree = tree.add("custom_gcodes_per_height", "");
pt::ptree& main_tree = tree.add("custom_gcodes_per_print_z", "");
for (const Model::CustomGCode& code : model.custom_gcode_per_height)
for (const Model::CustomGCode& code : model.custom_gcode_per_print_z)
{
pt::ptree& code_tree = main_tree.add("code", "");
// store minX and maxZ
code_tree.put("<xmlattr>.height" , code.height );
code_tree.put("<xmlattr>.print_z" , code.print_z );
code_tree.put("<xmlattr>.gcode" , code.gcode );
code_tree.put("<xmlattr>.extruder" , code.extruder );
code_tree.put("<xmlattr>.color" , code.color );
@ -2751,9 +2756,9 @@ bool _3MF_Exporter::_add_custom_gcode_per_height_file_to_archive( mz_zip_archive
if (!out.empty())
{
if (!mz_zip_writer_add_mem(&archive, CUSTOM_GCODE_PER_HEIGHT_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
if (!mz_zip_writer_add_mem(&archive, CUSTOM_GCODE_PER_PRINT_Z_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
{
add_error("Unable to add custom Gcodes per height file to archive");
add_error("Unable to add custom Gcodes per print_z file to archive");
return false;
}
}

View File

@ -41,8 +41,11 @@ namespace pt = boost::property_tree;
// Added x and y components of rotation
// Added x, y and z components of scale
// Added x, y and z components of mirror
// 3 : Meshes saved in their local system; Added volumes' matrices and source data
const unsigned int VERSION_AMF = 3;
// 3 : Added volumes' matrices and source data, meshes transformed back to their coordinate system on loading.
// WARNING !! -> the version number has been rolled back to 2
// the next change should use 4
const unsigned int VERSION_AMF = 2;
const unsigned int VERSION_AMF_COMPATIBLE = 3;
const char* SLIC3RPE_AMF_VERSION = "slic3rpe_amf_version";
const char* SLIC3R_CONFIG_TYPE = "slic3rpe_config";
@ -228,6 +231,8 @@ struct AMFParserContext
ModelVolume *m_volume;
// Faces collected for the current m_volume.
std::vector<int> m_volume_facets;
// Transformation matrix of a volume mesh from its coordinate system to Object's coordinate system.
Transform3d m_volume_transform;
// Current material allocated for an amf/metadata subtree.
ModelMaterial *m_material;
// Current instance allocated for an amf/constellation/instance subtree.
@ -319,6 +324,7 @@ void AMFParserContext::startElement(const char *name, const char **atts)
else if (strcmp(name, "volume") == 0) {
assert(! m_volume);
m_volume = m_object->add_volume(TriangleMesh());
m_volume_transform = Transform3d::Identity();
node_type_new = NODE_TYPE_VOLUME;
}
} else if (m_path[2] == NODE_TYPE_INSTANCE) {
@ -578,27 +584,25 @@ void AMFParserContext::endElement(const char * /* name */)
stl.stats.original_num_facets = stl.stats.number_of_facets;
stl_allocate(&stl);
Slic3r::Geometry::Transformation transform;
if (m_version > 2)
transform = m_volume->get_transformation();
Transform3d inv_matrix = transform.get_matrix().inverse();
bool has_transform = ! m_volume_transform.isApprox(Transform3d::Identity(), 1e-10);
Transform3d inv_matrix = m_volume_transform.inverse();
for (size_t i = 0; i < m_volume_facets.size();) {
stl_facet &facet = stl.facet_start[i/3];
for (unsigned int v = 0; v < 3; ++v)
{
unsigned int tri_id = m_volume_facets[i++] * 3;
Vec3f vertex(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]);
if (m_version > 2)
facet.vertex[v] = has_transform ?
// revert the vertices to the original mesh reference system
vertex = (inv_matrix * vertex.cast<double>()).cast<float>();
::memcpy((void*)facet.vertex[v].data(), (const void*)vertex.data(), 3 * sizeof(float));
(inv_matrix * vertex.cast<double>()).cast<float>() :
vertex;
}
}
}
stl_get_size(&stl);
mesh.repair();
m_volume->set_mesh(std::move(mesh));
if (has_transform)
m_volume->set_transformation(m_volume_transform);
if (m_volume->source.input_file.empty() && (m_volume->type() == ModelVolumeType::MODEL_PART))
{
m_volume->source.object_idx = (int)m_model.objects.size() - 1;
@ -637,7 +641,7 @@ void AMFParserContext::endElement(const char * /* name */)
int extruder = atoi(m_value[2].c_str());
const std::string& color = m_value[3];
m_model.custom_gcode_per_height.push_back(Model::CustomGCode(height, gcode, extruder, color));
m_model.custom_gcode_per_print_z.push_back(Model::CustomGCode{height, gcode, extruder, color});
for (std::string& val: m_value)
val.clear();
@ -718,9 +722,7 @@ void AMFParserContext::endElement(const char * /* name */)
m_volume->set_type(ModelVolume::type_from_string(m_value[1]));
}
else if (strcmp(opt_key, "matrix") == 0) {
Geometry::Transformation transform;
transform.set_from_string(m_value[1]);
m_volume->set_transformation(transform);
m_volume_transform = Slic3r::Geometry::transform3d_from_string(m_value[1]);
}
else if (strcmp(opt_key, "source_file") == 0) {
m_volume->source.input_file = m_value[1];
@ -910,7 +912,7 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
ctx.endDocument();
if (check_version && (ctx.m_version > VERSION_AMF))
if (check_version && (ctx.m_version > VERSION_AMF_COMPATIBLE))
{
// std::string msg = _(L("The selected amf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible."));
// throw std::runtime_error(msg.c_str());
@ -1146,6 +1148,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
stream << " <metadata type=\"slic3r.volume_type\">" << ModelVolume::type_to_string(volume->type()) << "</metadata>\n";
stream << " <metadata type=\"slic3r.matrix\">";
const Transform3d& matrix = volume->get_matrix();
stream << std::setprecision(std::numeric_limits<double>::max_digits10);
for (int r = 0; r < 4; ++r)
{
for (int c = 0; c < 4; ++c)
@ -1165,6 +1168,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
stream << " <metadata type=\"slic3r.source_offset_y\">" << volume->source.mesh_offset(1) << "</metadata>\n";
stream << " <metadata type=\"slic3r.source_offset_z\">" << volume->source.mesh_offset(2) << "</metadata>\n";
}
stream << std::setprecision(std::numeric_limits<float>::max_digits10);
const indexed_triangle_set &its = volume->mesh().its;
for (size_t i = 0; i < its.indices.size(); ++i) {
stream << " <triangle>\n";
@ -1221,21 +1225,21 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
stream << " </constellation>\n";
}
if (!model->custom_gcode_per_height.empty())
if (!model->custom_gcode_per_print_z.empty())
{
std::string out = "";
pt::ptree tree;
pt::ptree& main_tree = tree.add("custom_gcodes_per_height", "");
for (const Model::CustomGCode& code : model->custom_gcode_per_height)
for (const Model::CustomGCode& code : model->custom_gcode_per_print_z)
{
pt::ptree& code_tree = main_tree.add("code", "");
// store minX and maxZ
code_tree.put("<xmlattr>.height", code.height);
code_tree.put("<xmlattr>.gcode", code.gcode);
code_tree.put("<xmlattr>.extruder", code.extruder);
code_tree.put("<xmlattr>.color", code.color);
code_tree.put("<xmlattr>.print_z" , code.print_z );
code_tree.put("<xmlattr>.gcode" , code.gcode );
code_tree.put("<xmlattr>.extruder" , code.extruder );
code_tree.put("<xmlattr>.color" , code.color );
}
if (!tree.empty())

View File

@ -936,7 +936,7 @@ void GCode::_do_export(Print& print, FILE* file)
// Initialize custom gcode
Model* model = print.get_object(0)->model_object()->get_model();
m_custom_g_code_heights = model->custom_gcode_per_height;
m_custom_gcode_per_print_z = model->custom_gcode_per_print_z;
// Initialize autospeed.
{
@ -1124,20 +1124,22 @@ void GCode::_do_export(Print& print, FILE* file)
}
print.throw_if_canceled();
// #ys_FIXME_no_exported_codes
/*
/* To avoid change filament for non-used extruder for Multi-material,
* check model->custom_gcode_per_height using tool_ordering values
* */
if (!m_custom_g_code_heights. empty())
* check model->custom_gcode_per_print_z using tool_ordering values
* /
if (!m_custom_gcode_per_print_z. empty())
{
bool delete_executed = false;
auto it = m_custom_g_code_heights.end();
while (it != m_custom_g_code_heights.begin())
auto it = m_custom_gcode_per_print_z.end();
while (it != m_custom_gcode_per_print_z.begin())
{
--it;
if (it->gcode != ColorChangeCode)
continue;
auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), LayerTools(it->height));
auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), LayerTools(it->print_z));
bool used_extruder = false;
for (; it_layer_tools != tool_ordering.end(); it_layer_tools++)
@ -1154,16 +1156,16 @@ void GCode::_do_export(Print& print, FILE* file)
/* If we are there, current extruder wouldn't be used,
* so this color change is a redundant move.
* Delete this item from m_custom_g_code_heights
* */
it = m_custom_g_code_heights.erase(it);
* Delete this item from m_custom_gcode_per_print_z
* /
it = m_custom_gcode_per_print_z.erase(it);
delete_executed = true;
}
if (delete_executed)
model->custom_gcode_per_height = m_custom_g_code_heights;
model->custom_gcode_per_print_z = m_custom_gcode_per_print_z;
}
*/
m_cooling_buffer->set_current_extruder(initial_extruder_id);
@ -1461,7 +1463,7 @@ void GCode::_do_export(Print& print, FILE* file)
dst.first += buf;
++ dst.second;
};
print.m_print_statistics.filament_stats.insert(std::pair<size_t, float>(extruder.id(), (float)used_filament));
print.m_print_statistics.filament_stats.insert(std::pair<size_t, float>{extruder.id(), (float)used_filament});
append(out_filament_used_mm, "%.1lf", used_filament);
append(out_filament_used_cm3, "%.1lf", extruded_volume * 0.001);
if (filament_weight > 0.) {
@ -1835,15 +1837,15 @@ void GCode::process_layer(
std::string custom_code = "";
std::string pause_print_msg = "";
int m600_before_extruder = -1;
while (!m_custom_g_code_heights.empty() && m_custom_g_code_heights.front().height-EPSILON < layer.print_z) {
custom_code = m_custom_g_code_heights.front().gcode;
while (!m_custom_gcode_per_print_z.empty() && m_custom_gcode_per_print_z.front().print_z - EPSILON < layer.print_z) {
custom_code = m_custom_gcode_per_print_z.front().gcode;
if (custom_code == ColorChangeCode && m_custom_g_code_heights.front().extruder > 0)
m600_before_extruder = m_custom_g_code_heights.front().extruder - 1;
if (custom_code == ColorChangeCode && m_custom_gcode_per_print_z.front().extruder > 0)
m600_before_extruder = m_custom_gcode_per_print_z.front().extruder - 1;
if (custom_code == PausePrintCode)
pause_print_msg = m_custom_g_code_heights.front().color;
pause_print_msg = m_custom_gcode_per_print_z.front().color;
m_custom_g_code_heights.erase(m_custom_g_code_heights.begin());
m_custom_gcode_per_print_z.erase(m_custom_gcode_per_print_z.begin());
colorprint_change = true;
}

View File

@ -367,7 +367,7 @@ protected:
* Updated before the export and erased during the process,
* so no toolchange occurs twice.
* */
std::vector<Model::CustomGCode> m_custom_g_code_heights;
std::vector<Model::CustomGCode> m_custom_gcode_per_print_z;
// Time estimators
GCodeTimeEstimator m_normal_time_estimator;

View File

@ -10,6 +10,11 @@
namespace Slic3r {
// Additional Codes which can be set by user using DoubleSlider
static constexpr char ColorChangeCode[] = "M600";
static constexpr char PausePrintCode[] = "M601";
static constexpr char ExtruderChangeCode[] = "tool_change";
class GCodeWriter {
public:
GCodeConfig config;

View File

@ -1187,14 +1187,12 @@ MedialAxis::validate_edge(const VD::edge_type* edge)
return true;
}
const Line&
MedialAxis::retrieve_segment(const VD::cell_type* cell) const
const Line& MedialAxis::retrieve_segment(const VD::cell_type* cell) const
{
return this->lines[cell->source_index()];
}
const Point&
MedialAxis::retrieve_endpoint(const VD::cell_type* cell) const
const Point& MedialAxis::retrieve_endpoint(const VD::cell_type* cell) const
{
const Line& line = this->retrieve_segment(cell);
if (cell->source_category() == SOURCE_CATEGORY_SEGMENT_START_POINT) {
@ -1208,11 +1206,8 @@ void assemble_transform(Transform3d& transform, const Vec3d& translation, const
{
transform = Transform3d::Identity();
transform.translate(translation);
transform.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ()));
transform.rotate(Eigen::AngleAxisd(rotation(1), Vec3d::UnitY()));
transform.rotate(Eigen::AngleAxisd(rotation(0), Vec3d::UnitX()));
transform.scale(scale);
transform.scale(mirror);
transform.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(rotation(1), Vec3d::UnitY()) * Eigen::AngleAxisd(rotation(0), Vec3d::UnitX()));
transform.scale(scale.cwiseProduct(mirror));
}
Transform3d assemble_transform(const Vec3d& translation, const Vec3d& rotation, const Vec3d& scale, const Vec3d& mirror)
@ -1420,32 +1415,6 @@ void Transformation::set_from_transform(const Transform3d& transform)
// std::cout << "something went wrong in extracting data from matrix" << std::endl;
}
void Transformation::set_from_string(const std::string& transform_str)
{
Transform3d transform = Transform3d::Identity();
if (!transform_str.empty())
{
std::vector<std::string> mat_elements_str;
boost::split(mat_elements_str, transform_str, boost::is_any_of(" "), boost::token_compress_on);
unsigned int size = (unsigned int)mat_elements_str.size();
if (size == 16)
{
unsigned int i = 0;
for (unsigned int r = 0; r < 4; ++r)
{
for (unsigned int c = 0; c < 4; ++c)
{
transform(r, c) = ::atof(mat_elements_str[i++].c_str());
}
}
}
}
set_from_transform(transform);
}
void Transformation::reset()
{
m_offset = Vec3d::Zero();
@ -1536,6 +1505,33 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation
return out;
}
// For parsing a transformation matrix from 3MF / AMF.
Transform3d transform3d_from_string(const std::string& transform_str)
{
Transform3d transform = Transform3d::Identity();
if (!transform_str.empty())
{
std::vector<std::string> mat_elements_str;
boost::split(mat_elements_str, transform_str, boost::is_any_of(" "), boost::token_compress_on);
unsigned int size = (unsigned int)mat_elements_str.size();
if (size == 16)
{
unsigned int i = 0;
for (unsigned int r = 0; r < 4; ++r)
{
for (unsigned int c = 0; c < 4; ++c)
{
transform(r, c) = ::atof(mat_elements_str[i++].c_str());
}
}
}
}
return transform;
}
Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
{
return

View File

@ -360,7 +360,6 @@ public:
void set_mirror(Axis axis, double mirror);
void set_from_transform(const Transform3d& transform);
void set_from_string(const std::string& transform_str);
void reset();
@ -385,6 +384,9 @@ private:
}
};
// For parsing a transformation matrix from 3MF / AMF.
extern Transform3d transform3d_from_string(const std::string& transform_str);
// Rotation when going from the first coordinate system with rotation rot_xyz_from applied
// to a coordinate system with rot_xyz_to applied.
extern Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to);

View File

@ -18,6 +18,8 @@
#include "SVG.hpp"
#include <Eigen/Dense>
#include "GCodeWriter.hpp"
#include "GCode/PreviewData.hpp"
namespace Slic3r {
@ -43,7 +45,7 @@ Model& Model::assign_copy(const Model &rhs)
}
// copy custom code per height
this->custom_gcode_per_height = rhs.custom_gcode_per_height;
this->custom_gcode_per_print_z = rhs.custom_gcode_per_print_z;
return *this;
}
@ -64,7 +66,7 @@ Model& Model::assign_copy(Model &&rhs)
rhs.objects.clear();
// copy custom code per height
this->custom_gcode_per_height = rhs.custom_gcode_per_height;
this->custom_gcode_per_print_z = rhs.custom_gcode_per_print_z;
return *this;
}
@ -124,6 +126,8 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c
if (add_default_instances)
model.add_default_instances();
update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, config);
return model;
}
@ -159,6 +163,8 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig
if (add_default_instances)
model.add_default_instances();
update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, config);
return model;
}
@ -595,16 +601,15 @@ std::string Model::propose_export_file_name_and_path(const std::string &new_exte
std::vector<std::pair<double, DynamicPrintConfig>> Model::get_custom_tool_changes(double default_layer_height, size_t num_extruders) const
{
std::vector<std::pair<double, DynamicPrintConfig>> custom_tool_changes;
if (!custom_gcode_per_height.empty()) {
for (const CustomGCode& custom_gcode : custom_gcode_per_height)
if (custom_gcode.gcode == ExtruderChangeCode) {
DynamicPrintConfig config;
// If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders
config.set_key_value("extruder", new ConfigOptionInt(custom_gcode.extruder > num_extruders ? 0 : custom_gcode.extruder));
// For correct extruders(tools) changing, we should decrease custom_gcode.height value by one default layer height
custom_tool_changes.push_back({ custom_gcode.height - default_layer_height, config });
}
}
for (const CustomGCode& custom_gcode : custom_gcode_per_print_z)
if (custom_gcode.gcode == ExtruderChangeCode) {
DynamicPrintConfig config;
// If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders
config.set_key_value("extruder", new ConfigOptionInt(custom_gcode.extruder > num_extruders ? 0 : custom_gcode.extruder));
// For correct extruders(tools) changing, we should decrease custom_gcode.height value by one default layer height
custom_tool_changes.push_back({ custom_gcode.print_z - default_layer_height, config });
}
return custom_tool_changes;
}
@ -1304,6 +1309,8 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
}
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;
}
@ -1359,6 +1366,8 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
model_volume->set_mirror(Vec3d(1., 1., 1.));
// Move the reference point of the volume to compensate for the change of the instance trafo.
model_volume->set_offset(volume_offset_correction * volume_trafo.get_offset());
// reset the source to disable reload from disk
model_volume->source = ModelVolume::Source();
}
this->invalidate_bounding_box();
@ -1670,6 +1679,8 @@ size_t ModelVolume::split(unsigned int max_extruders)
this->calculate_convex_hull();
// Assign a new unique ID, so that a new GLVolume will be generated.
this->set_new_unique_id();
// reset the source to disable reload from disk
this->source = ModelVolume::Source();
}
else
this->object->volumes.insert(this->object->volumes.begin() + (++ivolume), new ModelVolume(object, *this, std::move(*mesh)));
@ -1940,6 +1951,30 @@ extern bool model_has_advanced_features(const Model &model)
return false;
}
extern void update_custom_gcode_per_print_z_from_config(std::vector<Model::CustomGCode>& custom_gcode_per_print_z, DynamicPrintConfig* config)
{
if (!config->has("colorprint_heights"))
return;
const std::vector<std::string>& colors = GCodePreviewData::ColorPrintColors();
const auto& colorprint_values = config->option<ConfigOptionFloats>("colorprint_heights")->values;
if (!colorprint_values.empty())
{
custom_gcode_per_print_z.clear();
custom_gcode_per_print_z.reserve(colorprint_values.size());
int i = 0;
for (auto val : colorprint_values)
custom_gcode_per_print_z.emplace_back(Model::CustomGCode{ val, ColorChangeCode, 1, colors[(++i)%7] });
}
/* There is one and only place this configuration option is used now.
* It wouldn't be used in the future, so erase it.
* */
config->erase("colorprint_heights");
}
#ifndef NDEBUG
// Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.
void check_model_ids_validity(const Model &model)

View File

@ -470,6 +470,7 @@ public:
const Geometry::Transformation& get_transformation() const { return m_transformation; }
void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; }
void set_transformation(const Transform3d &trafo) { m_transformation.set_from_transform(trafo); }
const Vec3d& get_offset() const { return m_transformation.get_offset(); }
double get_offset(Axis axis) const { return m_transformation.get_offset(axis); }
@ -753,33 +754,30 @@ public:
// Extensions for color print
struct CustomGCode
{
CustomGCode(double height, const std::string& code, int extruder, const std::string& color) :
height(height), gcode(code), extruder(extruder), color(color) {}
bool operator<(const CustomGCode& other) const { return other.height > this->height; }
bool operator<(const CustomGCode& other) const { return other.print_z > this->print_z; }
bool operator==(const CustomGCode& other) const
{
return (other.height == this->height) &&
(other.gcode == this->gcode) &&
(other.extruder == this->extruder )&&
(other.color == this->color );
return (other.print_z == this->print_z ) &&
(other.gcode == this->gcode ) &&
(other.extruder == this->extruder ) &&
(other.color == this->color );
}
bool operator!=(const CustomGCode& other) const
{
return (other.height != this->height) ||
(other.gcode != this->gcode) ||
(other.extruder != this->extruder )||
(other.color != this->color );
return (other.print_z != this->print_z ) ||
(other.gcode != this->gcode ) ||
(other.extruder != this->extruder ) ||
(other.color != this->color );
}
double height;
double print_z;
std::string gcode;
int extruder; // 0 - "gcode" will be applied for whole print
// else - "gcode" will be applied only for "extruder" print
std::string color; // if gcode is equal to PausePrintCode,
// this field is used for save a short message shown on Printer display
};
std::vector<CustomGCode> custom_gcode_per_height;
std::vector<CustomGCode> custom_gcode_per_print_z;
// Default constructor assigns a new ID to the model.
Model() { assert(this->id().valid()); }
@ -845,7 +843,7 @@ public:
// Propose an output path, replace extension. The new_extension shall contain the initial dot.
std::string propose_export_file_name_and_path(const std::string &new_extension) const;
// from custom_gcode_per_height get just tool_change codes
// from custom_gcode_per_print_z get just tool_change codes
std::vector<std::pair<double, DynamicPrintConfig>> get_custom_tool_changes(double default_layer_height, size_t num_extruders) const;
private:
@ -881,6 +879,10 @@ extern bool model_volume_list_changed(const ModelObject &model_object_old, const
extern bool model_has_multi_part_objects(const Model &model);
// If the model has advanced features, then it cannot be processed in simple mode.
extern bool model_has_advanced_features(const Model &model);
/* If loaded configuration has a "colorprint_heights" option (if it was imported from older Slicer),
* then model.custom_gcode_per_print_z should be updated considering this option
* */
extern void update_custom_gcode_per_print_z_from_config(std::vector<Model::CustomGCode>& custom_gcode_per_print_z, DynamicPrintConfig* config);
#ifndef NDEBUG
// Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.

View File

@ -739,10 +739,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
model_object_status.emplace(model_object->id(), ModelObjectStatus::Old);
// But if custom gcode per layer height was changed
if (m_model.custom_gcode_per_height != model.custom_gcode_per_height) {
if (m_model.custom_gcode_per_print_z != model.custom_gcode_per_print_z) {
// we should stop background processing
update_apply_status(this->invalidate_step(psGCodeExport));
m_model.custom_gcode_per_height = model.custom_gcode_per_height;
m_model.custom_gcode_per_print_z = model.custom_gcode_per_print_z;
}
} else if (model_object_list_extended(m_model, model)) {
// Add new objects. Their volumes and configs will be synchronized later.

View File

@ -71,12 +71,6 @@ enum SLAPillarConnectionMode {
slapcmDynamic
};
// ys_FIXME ! may be, it's not a best place
// Additional Codes which can be set by user using DoubleSlider
static const std::string ColorChangeCode = "M600";
static const std::string PausePrintCode = "M601";
static const std::string ExtruderChangeCode = "tool_change";
template<> inline const t_config_enum_values& ConfigOptionEnum<PrinterTechnology>::get_enum_values() {
static t_config_enum_values keys_map;
if (keys_map.empty()) {

View File

@ -339,18 +339,15 @@ PadSkeleton divide_blueprint(const ExPolygons &bp)
for (ClipperLib::PolyTree::PolyNode *node : ptree.Childs) {
ExPolygon poly(ClipperPath_to_Slic3rPolygon(node->Contour));
for (ClipperLib::PolyTree::PolyNode *child : node->Childs) {
if (child->IsHole()) {
poly.holes.emplace_back(
ClipperPath_to_Slic3rPolygon(child->Contour));
poly.holes.emplace_back(
ClipperPath_to_Slic3rPolygon(child->Contour));
traverse_pt_unordered(child->Childs, &ret.inner);
}
else traverse_pt_unordered(child, &ret.inner);
traverse_pt(child->Childs, &ret.inner);
}
ret.outer.emplace_back(poly);
}
return ret;
}
@ -432,9 +429,11 @@ public:
ExPolygons fullpad = diff_ex(fullcvh, model_bp_sticks);
remove_redundant_parts(fullpad);
PadSkeleton divided = divide_blueprint(fullpad);
remove_redundant_parts(divided.outer);
remove_redundant_parts(divided.inner);
outer = std::move(divided.outer);
inner = std::move(divided.inner);
}

View File

@ -43,6 +43,7 @@ std::vector<std::pair<size_t, bool>> chain_segments_closest_point(std::vector<En
assert(next_idx < end_points.size());
EndPointType &end_point = end_points[next_idx];
end_point.chain_id = 1;
out.emplace_back(next_idx / 2, (next_idx & 1) != 0);
this_idx = next_idx ^ 1;
}
#ifndef NDEBUG
@ -72,7 +73,7 @@ std::vector<std::pair<size_t, bool>> chain_segments_greedy_constrained_reversals
else if (num_segments == 1)
{
// Just sort the end points so that the first point visited is closest to start_near.
out.emplace_back(0, start_near != nullptr &&
out.emplace_back(0, could_reverse_func(0) && start_near != nullptr &&
(end_point_func(0, true) - *start_near).template cast<double>().squaredNorm() < (end_point_func(0, false) - *start_near).template cast<double>().squaredNorm());
}
else
@ -999,13 +1000,13 @@ std::vector<std::pair<size_t, bool>> chain_extrusion_entities(std::vector<Extrus
auto segment_end_point = [&entities](size_t idx, bool first_point) -> const Point& { return first_point ? entities[idx]->first_point() : entities[idx]->last_point(); };
auto could_reverse = [&entities](size_t idx) { const ExtrusionEntity *ee = entities[idx]; return ee->is_loop() || ee->can_reverse(); };
std::vector<std::pair<size_t, bool>> out = chain_segments_greedy_constrained_reversals<Point, decltype(segment_end_point), decltype(could_reverse)>(segment_end_point, could_reverse, entities.size(), start_near);
for (size_t i = 0; i < entities.size(); ++ i) {
ExtrusionEntity *ee = entities[i];
for (std::pair<size_t, bool> &segment : out) {
ExtrusionEntity *ee = entities[segment.first];
if (ee->is_loop())
// Ignore reversals for loops, as the start point equals the end point.
out[i].second = false;
segment.second = false;
// Is can_reverse() respected by the reversals?
assert(entities[i]->can_reverse() || ! out[i].second);
assert(ee->can_reverse() || ! segment.second);
}
return out;
}

View File

@ -224,38 +224,14 @@ std::vector<coordf_t> layer_height_profile_from_ranges(
// Based on the work of @platsch
// Fill layer_height_profile by heights ensuring a prescribed maximum cusp height.
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
std::vector<double> layer_height_profile_adaptive(const SlicingParameters& slicing_params,
const ModelObject& object, float cusp_value)
#else
std::vector<coordf_t> layer_height_profile_adaptive(
const SlicingParameters &slicing_params,
const t_layer_config_ranges & /* layer_config_ranges */,
const ModelVolumePtrs &volumes)
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
std::vector<double> layer_height_profile_adaptive(const SlicingParameters& slicing_params, const ModelObject& object, float quality_factor)
{
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
// 1) Initialize the SlicingAdaptive class with the object meshes.
SlicingAdaptive as;
as.set_slicing_parameters(slicing_params);
as.set_object(object);
#else
// 1) Initialize the SlicingAdaptive class with the object meshes.
SlicingAdaptive as;
as.set_slicing_parameters(slicing_params);
for (const ModelVolume* volume : volumes)
if (volume->is_model_part())
as.add_mesh(&volume->mesh());
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
as.prepare();
as.prepare(object);
// 2) Generate layers using the algorithm of @platsch
// loop until we have at least one layer and the max slice_z reaches the object height
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
double cusp_value = 0.2;
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
std::vector<double> layer_height_profile;
layer_height_profile.push_back(0.0);
layer_height_profile.push_back(slicing_params.first_object_layer_height);
@ -263,39 +239,41 @@ std::vector<coordf_t> layer_height_profile_adaptive(
layer_height_profile.push_back(slicing_params.first_object_layer_height);
layer_height_profile.push_back(slicing_params.first_object_layer_height);
}
double slice_z = slicing_params.first_object_layer_height;
int current_facet = 0;
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
while (slice_z <= slicing_params.object_print_z_height()) {
double height = slicing_params.max_layer_height;
#else
double height = slicing_params.first_object_layer_height;
while ((slice_z - height) <= slicing_params.object_print_z_height()) {
height = 999.0;
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
double print_z = slicing_params.first_object_layer_height;
// last facet visited by the as.next_layer_height() function, where the facets are sorted by their increasing Z span.
size_t current_facet = 0;
// loop until we have at least one layer and the max slice_z reaches the object height
while (print_z + EPSILON < slicing_params.object_print_z_height()) {
float height = slicing_params.max_layer_height;
// Slic3r::debugf "\n Slice layer: %d\n", $id;
// determine next layer height
double cusp_height = as.cusp_height((float)slice_z, cusp_value, current_facet);
float cusp_height = as.next_layer_height(float(print_z), quality_factor, current_facet);
#if 0
// check for horizontal features and object size
/*
if($self->config->get_value('match_horizontal_surfaces')) {
my $horizontal_dist = $adaptive_slicing[$region_id]->horizontal_facet_distance(scale $slice_z+$cusp_height, $min_height);
if(($horizontal_dist < $min_height) && ($horizontal_dist > 0)) {
Slic3r::debugf "Horizontal feature ahead, distance: %f\n", $horizontal_dist;
# can we shrink the current layer a bit?
if($cusp_height-($min_height-$horizontal_dist) > $min_height) {
# yes we can
$cusp_height = $cusp_height-($min_height-$horizontal_dist);
Slic3r::debugf "Shrink layer height to %f\n", $cusp_height;
}else{
# no, current layer would become too thin
$cusp_height = $cusp_height+$horizontal_dist;
Slic3r::debugf "Widen layer height to %f\n", $cusp_height;
if (this->config.match_horizontal_surfaces.value) {
coordf_t horizontal_dist = as.horizontal_facet_distance(print_z + height, min_layer_height);
if ((horizontal_dist < min_layer_height) && (horizontal_dist > 0)) {
#ifdef SLIC3R_DEBUG
std::cout << "Horizontal feature ahead, distance: " << horizontal_dist << std::endl;
#endif
// can we shrink the current layer a bit?
if (height-(min_layer_height - horizontal_dist) > min_layer_height) {
// yes we can
height -= (min_layer_height - horizontal_dist);
#ifdef SLIC3R_DEBUG
std::cout << "Shrink layer height to " << height << std::endl;
#endif
} else {
// no, current layer would become too thin
height += horizontal_dist;
#ifdef SLIC3R_DEBUG
std::cout << "Widen layer height to " << height << std::endl;
#endif
}
}
}
*/
#endif
height = std::min(cusp_height, height);
// apply z-gradation
@ -308,22 +286,22 @@ std::vector<coordf_t> layer_height_profile_adaptive(
// look for an applicable custom range
/*
if (my $range = first { $_->[0] <= $slice_z && $_->[1] > $slice_z } @{$self->layer_height_ranges}) {
if (my $range = first { $_->[0] <= $print_z && $_->[1] > $print_z } @{$self->layer_height_ranges}) {
$height = $range->[2];
# if user set custom height to zero we should just skip the range and resume slicing over it
if ($height == 0) {
$slice_z += $range->[1] - $range->[0];
$print_z += $range->[1] - $range->[0];
next;
}
}
*/
layer_height_profile.push_back(slice_z);
layer_height_profile.push_back(print_z);
layer_height_profile.push_back(height);
slice_z += height;
print_z += height;
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
layer_height_profile.push_back(slice_z);
layer_height_profile.push_back(print_z);
layer_height_profile.push_back(height);
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
}
@ -722,11 +700,7 @@ int generate_layer_height_texture(
const Vec3crd &color1 = palette_raw[idx1];
const Vec3crd &color2 = palette_raw[idx2];
coordf_t z = cell_to_z * coordf_t(cell);
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
assert((lo - EPSILON <= z) && (z <= hi + EPSILON));
#else
assert(z >= lo && z <= hi);
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
assert(lo - EPSILON <= z && z <= hi + EPSILON);
// Intensity profile to visualize the layers.
coordf_t intensity = cos(M_PI * 0.7 * (mid - z) / h);
// Color mapping from layer height to RGB.

View File

@ -18,12 +18,7 @@ namespace Slic3r
class PrintConfig;
class PrintObjectConfig;
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
class ModelObject;
#else
class ModelVolume;
typedef std::vector<ModelVolume*> ModelVolumePtrs;
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
// Parameters to guide object slicing and support generation.
// The slicing parameters account for a raft and whether the 1st object layer is printed with a normal or a bridging flow
@ -142,10 +137,9 @@ extern std::vector<coordf_t> layer_height_profile_from_ranges(
const SlicingParameters &slicing_params,
const t_layer_config_ranges &layer_config_ranges);
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
extern std::vector<double> layer_height_profile_adaptive(
const SlicingParameters& slicing_params,
const ModelObject& object, float cusp_value);
const ModelObject& object, float quality_factor);
struct HeightProfileSmoothingParams
{
@ -159,12 +153,6 @@ struct HeightProfileSmoothingParams
extern std::vector<double> smooth_height_profile(
const std::vector<double>& profile, const SlicingParameters& slicing_params,
const HeightProfileSmoothingParams& smoothing_params);
#else
extern std::vector<coordf_t> layer_height_profile_adaptive(
const SlicingParameters &slicing_params,
const t_layer_config_ranges &layer_config_ranges,
const ModelVolumePtrs &volumes);
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
enum LayerHeightEditActionType : unsigned int {
LAYER_HEIGHT_EDIT_ACTION_INCREASE = 0,

View File

@ -1,156 +1,211 @@
#include "libslic3r.h"
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
#include "Model.hpp"
#else
#include "TriangleMesh.hpp"
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
#include "SlicingAdaptive.hpp"
#include <boost/log/trivial.hpp>
// Based on the work of Florens Waserfall (@platch on github)
// and his paper
// Florens Wasserfall, Norman Hendrich, Jianwei Zhang:
// Adaptive Slicing for the FDM Process Revisited
// 13th IEEE Conference on Automation Science and Engineering (CASE-2017), August 20-23, Xi'an, China. DOI: 10.1109/COASE.2017.8256074
// https://tams.informatik.uni-hamburg.de/publications/2017/Adaptive%20Slicing%20for%20the%20FDM%20Process%20Revisited.pdf
// Vojtech believes that there is a bug in @platch's derivation of the triangle area error metric.
// Following Octave code paints graphs of recommended layer height versus surface slope angle.
#if 0
adeg=0:1:85;
a=adeg*pi/180;
t=tan(a);
tsqr=sqrt(tan(a));
lerr=1./cos(a);
lerr2=1./(0.3+cos(a));
plot(adeg, t, 'b', adeg, sqrt(t), 'g', adeg, 0.5 * lerr, 'm', adeg, 0.5 * lerr2, 'r')
xlabel("angle(deg), 0 - horizontal wall, 90 - vertical wall");
ylabel("layer height");
legend("tan(a) as cura - topographic lines distance limit", "sqrt(tan(a)) as PrusaSlicer - error triangle area limit", "old slic3r - max distance metric", "new slic3r - Waserfall paper");
#endif
#ifndef NDEBUG
#define ADAPTIVE_LAYER_HEIGHT_DEBUG
#endif /* NDEBUG */
namespace Slic3r
{
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void SlicingAdaptive::clear()
{
m_meshes.clear();
m_faces.clear();
m_face_normal_z.clear();
}
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
std::pair<float, float> face_z_span(const stl_facet *f)
static inline std::pair<float, float> face_z_span(const stl_facet &f)
{
return std::pair<float, float>(
std::min(std::min(f->vertex[0](2), f->vertex[1](2)), f->vertex[2](2)),
std::max(std::max(f->vertex[0](2), f->vertex[1](2)), f->vertex[2](2)));
std::min(std::min(f.vertex[0](2), f.vertex[1](2)), f.vertex[2](2)),
std::max(std::max(f.vertex[0](2), f.vertex[1](2)), f.vertex[2](2)));
}
void SlicingAdaptive::prepare()
// By Florens Waserfall aka @platch:
// This constant essentially describes the volumetric error at the surface which is induced
// by stacking "elliptic" extrusion threads. It is empirically determined by
// 1. measuring the surface profile of printed parts to find
// the ratio between layer height and profile height and then
// 2. computing the geometric difference between the model-surface and the elliptic profile.
//
// The definition of the roughness formula is in
// https://tams.informatik.uni-hamburg.de/publications/2017/Adaptive%20Slicing%20for%20the%20FDM%20Process%20Revisited.pdf
// (page 51, formula (8))
// Currenty @platch's error metric formula is not used.
static constexpr double SURFACE_CONST = 0.18403;
// for a given facet, compute maximum height within the allowed surface roughness / stairstepping deviation
static inline float layer_height_from_slope(const SlicingAdaptive::FaceZ &face, float max_surface_deviation)
{
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
if (m_object == nullptr)
return;
// @platch's formula, see his paper "Adaptive Slicing for the FDM Process Revisited".
// return float(max_surface_deviation / (SURFACE_CONST + 0.5 * std::abs(normal_z)));
// Constant stepping in horizontal direction, as used by Cura.
// return (face.n_cos > 1e-5) ? float(max_surface_deviation * face.n_sin / face.n_cos) : FLT_MAX;
m_faces.clear();
m_face_normal_z.clear();
// Constant error measured as an area of the surface error triangle, Vojtech's formula.
// return (face.n_cos > 1e-5) ? float(1.44 * max_surface_deviation * sqrt(face.n_sin / face.n_cos)) : FLT_MAX;
m_mesh = m_object->raw_mesh();
const ModelInstance* first_instance = m_object->instances.front();
m_mesh.transform(first_instance->get_matrix(), first_instance->is_left_handed());
// Constant error measured as an area of the surface error triangle, Vojtech's formula with clamping to roughness at 90 degrees.
return std::min(max_surface_deviation / 0.184f, (face.n_cos > 1e-5) ? float(1.44 * max_surface_deviation * sqrt(face.n_sin / face.n_cos)) : FLT_MAX);
// Constant stepping along the surface, equivalent to the "surface roughness" metric by Perez and later Pandey et all, see @platch's paper for references.
// return float(max_surface_deviation * face.n_sin);
}
void SlicingAdaptive::clear()
{
m_faces.clear();
}
void SlicingAdaptive::prepare(const ModelObject &object)
{
this->clear();
TriangleMesh mesh = object.raw_mesh();
const ModelInstance &first_instance = *object.instances.front();
mesh.transform(first_instance.get_matrix(), first_instance.is_left_handed());
// 1) Collect faces from mesh.
m_faces.reserve(m_mesh.stl.stats.number_of_facets);
for (stl_facet& face : m_mesh.stl.facet_start)
{
face.normal.normalize();
m_faces.emplace_back(&face);
m_faces.reserve(mesh.stl.stats.number_of_facets);
for (const stl_facet &face : mesh.stl.facet_start) {
Vec3f n = face.normal.normalized();
m_faces.emplace_back(FaceZ({ face_z_span(face), std::abs(n.z()), std::sqrt(n.x() * n.x() + n.y() * n.y()) }));
}
#else
// 1) Collect faces of all meshes.
int nfaces_total = 0;
for (std::vector<const TriangleMesh*>::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh)
nfaces_total += (*it_mesh)->stl.stats.number_of_facets;
m_faces.reserve(nfaces_total);
for (std::vector<const TriangleMesh*>::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh)
for (const stl_facet& face : (*it_mesh)->stl.facet_start)
m_faces.emplace_back(&face);
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
// 2) Sort faces lexicographically by their Z span.
std::sort(m_faces.begin(), m_faces.end(), [](const stl_facet *f1, const stl_facet *f2) { return face_z_span(f1) < face_z_span(f2); });
// 3) Generate Z components of the facet normals.
m_face_normal_z.assign(m_faces.size(), 0.0f);
for (size_t iface = 0; iface < m_faces.size(); ++ iface)
m_face_normal_z[iface] = m_faces[iface]->normal(2);
std::sort(m_faces.begin(), m_faces.end(), [](const FaceZ &f1, const FaceZ &f2) { return f1.z_span < f2.z_span; });
}
float SlicingAdaptive::cusp_height(float z, float cusp_value, int &current_facet)
// current_facet is in/out parameter, rememebers the index of the last face of m_faces visited,
// where this function will start from.
// print_z - the top print surface of the previous layer.
// returns height of the next layer.
float SlicingAdaptive::next_layer_height(const float print_z, float quality_factor, size_t &current_facet)
{
float height = (float)m_slicing_params.max_layer_height;
bool first_hit = false;
float height = (float)m_slicing_params.max_layer_height;
float max_surface_deviation;
{
#if 0
// @platch's formula for quality:
double delta_min = SURFACE_CONST * m_slicing_params.min_layer_height;
double delta_mid = (SURFACE_CONST + 0.5) * m_slicing_params.layer_height;
double delta_max = (SURFACE_CONST + 0.5) * m_slicing_params.max_layer_height;
#else
// Vojtech's formula for triangle area error metric.
double delta_min = m_slicing_params.min_layer_height;
double delta_mid = m_slicing_params.layer_height;
double delta_max = m_slicing_params.max_layer_height;
#endif
max_surface_deviation = (quality_factor < 0.5f) ?
lerp(delta_min, delta_mid, 2. * quality_factor) :
lerp(delta_max, delta_mid, 2. * (1. - quality_factor));
}
// find all facets intersecting the slice-layer
int ordered_id = current_facet;
for (; ordered_id < int(m_faces.size()); ++ ordered_id) {
std::pair<float, float> zspan = face_z_span(m_faces[ordered_id]);
// facet's minimum is higher than slice_z -> end loop
if (zspan.first >= z)
break;
// facet's maximum is higher than slice_z -> store the first event for next cusp_height call to begin at this point
if (zspan.second > z) {
// first event?
if (! first_hit) {
first_hit = true;
current_facet = ordered_id;
}
// skip touching facets which could otherwise cause small cusp values
if (zspan.second <= z + EPSILON)
continue;
// compute cusp-height for this facet and store minimum of all heights
float normal_z = m_face_normal_z[ordered_id];
height = std::min(height, (normal_z == 0.0f) ? (float)m_slicing_params.max_layer_height : std::abs(cusp_value / normal_z));
}
size_t ordered_id = current_facet;
{
bool first_hit = false;
for (; ordered_id < m_faces.size(); ++ ordered_id) {
const std::pair<float, float> &zspan = m_faces[ordered_id].z_span;
// facet's minimum is higher than slice_z -> end loop
if (zspan.first >= print_z)
break;
// facet's maximum is higher than slice_z -> store the first event for next cusp_height call to begin at this point
if (zspan.second > print_z) {
// first event?
if (! first_hit) {
first_hit = true;
current_facet = ordered_id;
}
// skip touching facets which could otherwise cause small cusp values
if (zspan.second < print_z + EPSILON)
continue;
// compute cusp-height for this facet and store minimum of all heights
height = std::min(height, layer_height_from_slope(m_faces[ordered_id], max_surface_deviation));
}
}
}
// lower height limit due to printer capabilities
height = std::max(height, float(m_slicing_params.min_layer_height));
// check for sloped facets inside the determined layer and correct height if necessary
if (height > m_slicing_params.min_layer_height) {
for (; ordered_id < int(m_faces.size()); ++ ordered_id) {
std::pair<float, float> zspan = face_z_span(m_faces[ordered_id]);
if (height > float(m_slicing_params.min_layer_height)) {
for (; ordered_id < m_faces.size(); ++ ordered_id) {
const std::pair<float, float> &zspan = m_faces[ordered_id].z_span;
// facet's minimum is higher than slice_z + height -> end loop
if (zspan.first >= z + height)
if (zspan.first >= print_z + height)
break;
// skip touching facets which could otherwise cause small cusp values
if (zspan.second <= z + EPSILON)
if (zspan.second < print_z + EPSILON)
continue;
// Compute cusp-height for this facet and check against height.
float normal_z = m_face_normal_z[ordered_id];
float cusp = (normal_z == 0.0f) ? (float)m_slicing_params.max_layer_height : std::abs(cusp_value / normal_z);
float reduced_height = layer_height_from_slope(m_faces[ordered_id], max_surface_deviation);
float z_diff = zspan.first - z;
// handle horizontal facets
if (normal_z > 0.999f) {
// Slic3r::debugf "cusp computation, height is reduced from %f", $height;
float z_diff = zspan.first - print_z;
if (reduced_height < z_diff) {
assert(z_diff < height + EPSILON);
// The currently visited triangle's slope limits the next layer height so much, that
// the lowest point of the currently visible triangle is already above the newly proposed layer height.
// This means, that we need to limit the layer height so that the offending newly visited triangle
// is just above of the new layer.
#ifdef ADAPTIVE_LAYER_HEIGHT_DEBUG
BOOST_LOG_TRIVIAL(trace) << "cusp computation, height is reduced from " << height << "to " << z_diff << " due to z-diff";
#endif /* ADAPTIVE_LAYER_HEIGHT_DEBUG */
height = z_diff;
// Slic3r::debugf "to %f due to near horizontal facet\n", $height;
} else if (cusp > z_diff) {
if (cusp < height) {
// Slic3r::debugf "cusp computation, height is reduced from %f", $height;
height = cusp;
// Slic3r::debugf "to %f due to new cusp height\n", $height;
}
} else {
// Slic3r::debugf "cusp computation, height is reduced from %f", $height;
height = z_diff;
// Slic3r::debugf "to z-diff: %f\n", $height;
} else if (reduced_height < height) {
#ifdef ADAPTIVE_LAYER_HEIGHT_DEBUG
BOOST_LOG_TRIVIAL(trace) << "adaptive layer computation: height is reduced from " << height << "to " << reduced_height << " due to higher facet";
#endif /* ADAPTIVE_LAYER_HEIGHT_DEBUG */
height = reduced_height;
}
}
// lower height limit due to printer capabilities again
height = std::max(height, float(m_slicing_params.min_layer_height));
}
// Slic3r::debugf "cusp computation, layer-bottom at z:%f, cusp_value:%f, resulting layer height:%f\n", unscale $z, $cusp_value, $height;
#ifdef ADAPTIVE_LAYER_HEIGHT_DEBUG
BOOST_LOG_TRIVIAL(trace) << "adaptive layer computation, layer-bottom at z:" << print_z << ", quality_factor:" << quality_factor << ", resulting layer height:" << height;
#endif /* ADAPTIVE_LAYER_HEIGHT_DEBUG */
return height;
}
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
// Returns the distance to the next horizontal facet in Z-dir
// to consider horizontal object features in slice thickness
float SlicingAdaptive::horizontal_facet_distance(float z)
{
for (size_t i = 0; i < m_faces.size(); ++ i) {
std::pair<float, float> zspan = face_z_span(m_faces[i]);
std::pair<float, float> zspan = m_faces[i].z_span;
// facet's minimum is higher than max forward distance -> end loop
if (zspan.first > z + m_slicing_params.max_layer_height)
break;
// min_z == max_z -> horizontal facet
if ((zspan.first > z) && (zspan.first == zspan.second))
if (zspan.first > z && zspan.first == zspan.second)
return zspan.first - z;
}
@ -158,6 +213,5 @@ float SlicingAdaptive::horizontal_facet_distance(float z)
return (z + (float)m_slicing_params.max_layer_height > (float)m_slicing_params.object_print_z_height()) ?
std::max((float)m_slicing_params.object_print_z_height() - z, 0.f) : (float)m_slicing_params.max_layer_height;
}
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
}; // namespace Slic3r

View File

@ -5,50 +5,36 @@
#include "Slicing.hpp"
#include "admesh/stl.h"
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
#include "TriangleMesh.hpp"
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
namespace Slic3r
{
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
class ModelVolume;
#else
class TriangleMesh;
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
class SlicingAdaptive
{
public:
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void clear();
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void set_slicing_parameters(SlicingParameters params) { m_slicing_params = params; }
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void set_object(const ModelObject& object) { m_object = &object; }
#else
void add_mesh(const TriangleMesh* mesh) { m_meshes.push_back(mesh); }
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void prepare();
float cusp_height(float z, float cusp_value, int &current_facet);
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void clear();
void set_slicing_parameters(SlicingParameters params) { m_slicing_params = params; }
void prepare(const ModelObject &object);
// Return next layer height starting from the last print_z, using a quality measure
// (quality in range from 0 to 1, 0 - highest quality at low layer heights, 1 - lowest print quality at high layer heights).
// The layer height curve shall be centered roughly around the default profile's layer height for quality 0.5.
float next_layer_height(const float print_z, float quality, size_t &current_facet);
float horizontal_facet_distance(float z);
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
struct FaceZ {
std::pair<float, float> z_span;
// Cosine of the normal vector towards the Z axis.
float n_cos;
// Sine of the normal vector towards the Z axis.
float n_sin;
};
protected:
SlicingParameters m_slicing_params;
SlicingParameters m_slicing_params;
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
const ModelObject* m_object;
TriangleMesh m_mesh;
#else
std::vector<const TriangleMesh*> m_meshes;
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
// Collected faces of all meshes, sorted by raising Z of the bottom most face.
std::vector<const stl_facet*> m_faces;
// Z component of face normals, normalized.
std::vector<float> m_face_normal_z;
std::vector<FaceZ> m_faces;
};
}; // namespace Slic3r

View File

@ -53,4 +53,7 @@
// Enable selection for missing files in reload from disk command
#define ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION (1 && ENABLE_2_2_0_ALPHA1)
// Enable closing 3Dconnextion imgui settings dialog by clicking on [X] and [Close] buttons
#define ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG (1 && ENABLE_2_2_0_ALPHA1)
#endif // _technologies_h_

View File

@ -217,14 +217,6 @@ inline typename CONTAINER_TYPE::value_type& next_value_modulo(typename CONTAINER
return container[next_idx_modulo(idx, container.size())];
}
template<class T, class U = T>
inline T exchange(T& obj, U&& new_value)
{
T old_value = std::move(obj);
obj = std::forward<U>(new_value);
return old_value;
}
extern std::string xml_escape(std::string text);

View File

@ -116,7 +116,5 @@
<string>NSApplication</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>NSRequiresAquaSystemAppearance</key>
<true/>
</dict>
</plist>

View File

@ -191,7 +191,6 @@ Bed3D::Bed3D()
: m_type(Custom)
, m_custom_texture("")
, m_custom_model("")
, m_requires_canvas_update(false)
, m_vbo_id(0)
, m_scale_factor(1.0f)
{
@ -205,7 +204,6 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c
std::string cst_texture(custom_texture);
if (!cst_texture.empty())
{
std::replace(cst_texture.begin(), cst_texture.end(), '\\', '/');
if ((!boost::algorithm::iends_with(custom_texture, ".png") && !boost::algorithm::iends_with(custom_texture, ".svg")) || !boost::filesystem::exists(custom_texture))
cst_texture = "";
}
@ -214,7 +212,6 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c
std::string cst_model(custom_model);
if (!cst_model.empty())
{
std::replace(cst_model.begin(), cst_model.end(), '\\', '/');
if (!boost::algorithm::iends_with(custom_model, ".stl") || !boost::filesystem::exists(custom_model))
cst_model = "";
}
@ -438,6 +435,7 @@ void Bed3D::render_texture(const std::string& filename, bool bottom, GLCanvas3D&
render_default(bottom);
return;
}
canvas.request_extra_frame();
}
// starts generating the main texture, compression will run asynchronously
@ -457,6 +455,7 @@ void Bed3D::render_texture(const std::string& filename, bool bottom, GLCanvas3D&
render_default(bottom);
return;
}
canvas.request_extra_frame();
}
// starts generating the main texture, compression will run asynchronously
@ -481,13 +480,9 @@ void Bed3D::render_texture(const std::string& filename, bool bottom, GLCanvas3D&
if (m_temp_texture.get_id() != 0)
m_temp_texture.reset();
m_requires_canvas_update = true;
}
else if (m_requires_canvas_update && m_texture.all_compressed_data_sent_to_gpu())
m_requires_canvas_update = false;
canvas.request_extra_frame();
if (m_texture.all_compressed_data_sent_to_gpu() && canvas.is_keeping_dirty())
canvas.stop_keeping_dirty();
}
if (m_triangles.get_vertices_count() > 0)
{

View File

@ -86,8 +86,6 @@ private:
mutable GLTexture m_texture;
// temporary texture shown until the main texture has still no levels compressed
mutable GLTexture m_temp_texture;
// used to trigger 3D scene update once all compressed textures have been sent to GPU
mutable bool m_requires_canvas_update;
mutable Shader m_shader;
mutable unsigned int m_vbo_id;
mutable GLBed m_model;

View File

@ -94,12 +94,13 @@ void BackgroundSlicingProcess::process_fff()
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data);
#endif // ENABLE_THUMBNAIL_GENERATOR
if (m_fff_print->model().custom_gcode_per_height != GUI::wxGetApp().model().custom_gcode_per_height) {
GUI::wxGetApp().model().custom_gcode_per_height = m_fff_print->model().custom_gcode_per_height;
// #ys_FIXME : controll text
/* #ys_FIXME_no_exported_codes
if (m_fff_print->model().custom_gcode_per_print_z != GUI::wxGetApp().model().custom_gcode_per_print_z) {
GUI::wxGetApp().model().custom_gcode_per_print_z = m_fff_print->model().custom_gcode_per_print_z;
GUI::show_info(nullptr, _(L("To except of redundant tool manipulation, \n"
"Color change(s) for unused extruder(s) was(were) deleted")), _(L("Info")));
}
*/
if (this->set_step_started(bspsGCodeFinalize)) {
if (! m_export_path.empty()) {

View File

@ -61,9 +61,7 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf
{
m_shape = default_pt.values;
m_custom_texture = custom_texture.value.empty() ? NONE : custom_texture.value;
std::replace(m_custom_texture.begin(), m_custom_texture.end(), '\\', '/');
m_custom_model = custom_model.value.empty() ? NONE : custom_model.value;
std::replace(m_custom_model.begin(), m_custom_model.end(), '\\', '/');
auto sbsizer = new wxStaticBoxSizer(wxVERTICAL, this, _(L("Shape")));
sbsizer->GetStaticBox()->SetFont(wxGetApp().bold_font());
@ -546,8 +544,6 @@ void BedShapePanel::load_texture()
return;
}
std::replace(file_name.begin(), file_name.end(), '\\', '/');
wxBusyCursor wait;
m_custom_texture = file_name;
@ -571,8 +567,6 @@ void BedShapePanel::load_model()
return;
}
std::replace(file_name.begin(), file_name.end(), '\\', '/');
wxBusyCursor wait;
m_custom_model = file_name;

View File

@ -133,7 +133,7 @@ GLCanvas3D::LayersEditing::LayersEditing()
, m_slicing_parameters(nullptr)
, m_layer_height_profile_modified(false)
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
, m_adaptive_cusp(0.0f)
, m_adaptive_quality(0.5f)
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
, state(Unknown)
, band_width(2.0f)
@ -268,24 +268,24 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
ImGui::Separator();
if (imgui.button(_(L("Adaptive"))))
wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), Event<float>(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, m_adaptive_cusp));
wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), Event<float>(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, m_adaptive_quality));
ImGui::SameLine();
float text_align = ImGui::GetCursorPosX();
ImGui::AlignTextToFramePadding();
imgui.text(_(L("Cusp (mm)")));
imgui.text(_(L("Quality / Speed")));
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::TextUnformatted(_(L("I am a tooltip")));
ImGui::TextUnformatted(_(L("Higher print quality versus higher print speed.")));
ImGui::EndTooltip();
}
ImGui::SameLine();
float widget_align = ImGui::GetCursorPosX();
ImGui::PushItemWidth(imgui.get_style_scaling() * 120.0f);
m_adaptive_cusp = clamp(0.0f, 0.5f * (float)m_slicing_parameters->layer_height, m_adaptive_cusp);
ImGui::SliderFloat("", &m_adaptive_cusp, 0.0f, 0.5f * (float)m_slicing_parameters->layer_height, "%.3f");
m_adaptive_quality = clamp(0.0f, 1.f, m_adaptive_quality);
ImGui::SliderFloat("", &m_adaptive_quality, 0.0f, 1.f, "%.2f");
ImGui::Separator();
if (imgui.button(_(L("Smooth"))))
@ -645,10 +645,10 @@ void GLCanvas3D::LayersEditing::reset_layer_height_profile(GLCanvas3D& canvas)
}
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas, float cusp)
void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor)
{
this->update_slicing_parameters();
m_layer_height_profile = layer_height_profile_adaptive(*m_slicing_parameters, *m_model_object, cusp);
m_layer_height_profile = layer_height_profile_adaptive(*m_slicing_parameters, *m_model_object, quality_factor);
const_cast<ModelObject*>(m_model_object)->layer_height_profile = m_layer_height_profile;
m_layers_texture.valid = false;
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
@ -712,11 +712,6 @@ void GLCanvas3D::LayersEditing::update_slicing_parameters()
m_slicing_parameters = new SlicingParameters();
*m_slicing_parameters = PrintObject::slicing_parameters(*m_config, *m_model_object, m_object_max_z);
}
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
if (m_adaptive_cusp == 0.0f)
m_adaptive_cusp = 0.25f * m_slicing_parameters->layer_height;
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
}
float GLCanvas3D::LayersEditing::thickness_bar_width(const GLCanvas3D &canvas)
@ -1016,24 +1011,25 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
std::vector<float>& colors,
std::vector<std::string>& cp_legend_items)
{
std::vector<Model::CustomGCode> custom_gcode_per_height = wxGetApp().plater()->model().custom_gcode_per_height;
std::vector<Model::CustomGCode> custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z;
const int extruders_cnt = wxGetApp().extruders_edited_cnt();
if (extruders_cnt == 1)
{
if (custom_gcode_per_height.empty()) {
cp_legend_items.push_back(I18N::translate_utf8(L("Default print color")));
if (custom_gcode_per_print_z.empty()) {
cp_legend_items.emplace_back(I18N::translate_utf8(L("Default print color")));
colors = colors_in;
return;
}
std::vector<std::pair<double, double>> cp_values;
cp_values.reserve(custom_gcode_per_print_z.size());
std::vector<double> print_zs = canvas.get_current_print_zs(true);
for (auto custom_code : custom_gcode_per_height)
for (auto custom_code : custom_gcode_per_print_z)
{
if (custom_code.gcode != ColorChangeCode)
continue;
auto lower_b = std::lower_bound(print_zs.begin(), print_zs.end(), custom_code.height - DoubleSlider::epsilon());
auto lower_b = std::lower_bound(print_zs.begin(), print_zs.end(), custom_code.print_z - DoubleSlider::epsilon());
if (lower_b == print_zs.end())
continue;
@ -1044,14 +1040,14 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
// to avoid duplicate values, check adding values
if (cp_values.empty() ||
!(cp_values.back().first == previous_z && cp_values.back().second == current_z))
cp_values.push_back(std::pair<double, double>(previous_z, current_z));
cp_values.emplace_back(std::pair<double, double>(previous_z, current_z));
}
const auto items_cnt = (int)cp_values.size();
if (items_cnt == 0) // There is no one color change, but there is/are some pause print or custom Gcode
{
cp_legend_items.push_back(I18N::translate_utf8(L("Default print color")));
cp_legend_items.push_back(I18N::translate_utf8(L("Pause print or custom G-code")));
cp_legend_items.emplace_back(I18N::translate_utf8(L("Default print color")));
cp_legend_items.emplace_back(I18N::translate_utf8(L("Pause print or custom G-code")));
colors = colors_in;
return;
}
@ -1060,7 +1056,7 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
colors.resize(colors_in.size(), 0.0);
::memcpy((void*)(colors.data()), (const void*)(colors_in.data() + (color_cnt - 1) * 4), 4 * sizeof(float));
cp_legend_items.push_back(I18N::translate_utf8(L("Pause print or custom G-code")));
cp_legend_items.emplace_back(I18N::translate_utf8(L("Pause print or custom G-code")));
size_t color_pos = 4;
for (int i = items_cnt; i >= 0; --i, color_pos+=4)
@ -1072,15 +1068,15 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
std::string id_str = std::to_string(i + 1) + ": ";
if (i == 0) {
cp_legend_items.push_back(id_str + (boost::format(I18N::translate_utf8(L("up to %.2f mm"))) % cp_values[0].first).str());
cp_legend_items.emplace_back(id_str + (boost::format(I18N::translate_utf8(L("up to %.2f mm"))) % cp_values[0].first).str());
break;
}
if (i == items_cnt) {
cp_legend_items.push_back(id_str + (boost::format(I18N::translate_utf8(L("above %.2f mm"))) % cp_values[i - 1].second).str());
cp_legend_items.emplace_back(id_str + (boost::format(I18N::translate_utf8(L("above %.2f mm"))) % cp_values[i - 1].second).str());
continue;
}
cp_legend_items.push_back(id_str + (boost::format(I18N::translate_utf8(L("%.2f - %.2f mm"))) % cp_values[i - 1].second % cp_values[i].first).str());
cp_legend_items.emplace_back(id_str + (boost::format(I18N::translate_utf8(L("%.2f - %.2f mm"))) % cp_values[i - 1].second % cp_values[i].first).str());
}
}
else
@ -1094,20 +1090,20 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
size_t color_in_pos = 4 * (color_cnt - 1);
for (unsigned int i = 0; i < (unsigned int)extruders_cnt; ++i)
cp_legend_items.push_back((boost::format(I18N::translate_utf8(L("Extruder %d"))) % (i + 1)).str());
cp_legend_items.emplace_back((boost::format(I18N::translate_utf8(L("Extruder %d"))) % (i + 1)).str());
::memcpy((void*)(colors.data() + color_pos), (const void*)(colors_in.data() + color_in_pos), 4 * sizeof(float));
color_pos += 4;
color_in_pos -= 4;
cp_legend_items.push_back(I18N::translate_utf8(L("Pause print or custom G-code")));
cp_legend_items.emplace_back(I18N::translate_utf8(L("Pause print or custom G-code")));
int cnt = custom_gcode_per_height.size();
int cnt = custom_gcode_per_print_z.size();
for (int i = cnt-1; i >= 0; --i)
if (custom_gcode_per_height[i].gcode == ColorChangeCode) {
if (custom_gcode_per_print_z[i].gcode == ColorChangeCode) {
::memcpy((void*)(colors.data() + color_pos), (const void*)(colors_in.data() + color_in_pos), 4 * sizeof(float));
color_pos += 4;
color_in_pos -= 4;
cp_legend_items.push_back((boost::format(I18N::translate_utf8(L("Color change for Extruder %d at %.2f mm"))) % custom_gcode_per_height[i].extruder % custom_gcode_per_height[i].height).str());
cp_legend_items.emplace_back((boost::format(I18N::translate_utf8(L("Color change for Extruder %d at %.2f mm"))) % custom_gcode_per_print_z[i].extruder % custom_gcode_per_print_z[i].print_z).str());
}
}
}
@ -1398,7 +1394,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
, m_gizmos(*this)
, m_use_clipping_planes(false)
, m_sidebar_field("")
, m_keep_dirty(false)
, m_extra_frame_requested(false)
, m_config(nullptr)
, m_process(nullptr)
, m_model(nullptr)
@ -1640,8 +1636,6 @@ void GLCanvas3D::bed_shape_changed()
refresh_camera_scene_box();
m_camera.requires_zoom_to_bed = true;
m_dirty = true;
if (m_bed.is_prusa())
start_keeping_dirty();
}
void GLCanvas3D::set_color_by(const std::string& value)
@ -1694,10 +1688,10 @@ void GLCanvas3D::reset_layer_height_profile()
m_dirty = true;
}
void GLCanvas3D::adaptive_layer_height_profile(float cusp)
void GLCanvas3D::adaptive_layer_height_profile(float quality_factor)
{
wxGetApp().plater()->take_snapshot(_(L("Variable layer height - Adaptive")));
m_layers_editing.adaptive_layer_height_profile(*this, cusp);
m_layers_editing.adaptive_layer_height_profile(*this, quality_factor);
m_layers_editing.state = LayersEditing::Completed;
m_dirty = true;
}
@ -1931,7 +1925,11 @@ void GLCanvas3D::render()
m_camera.debug_render();
#endif // ENABLE_CAMERA_STATISTICS
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog(*this);
#else
wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height());
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
wxGetApp().imgui()->render();
@ -2636,9 +2634,10 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
_refresh_if_shown_on_screen();
if (m_keep_dirty || mouse3d_controller_applied)
if (m_extra_frame_requested || mouse3d_controller_applied)
{
m_dirty = true;
m_extra_frame_requested = false;
evt.RequestMore();
}
else
@ -5395,7 +5394,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
// For coloring by a color_print(M600), return a parsed color.
bool color_by_color_print() const { return color_print_values!=nullptr; }
const size_t color_print_color_idx_by_layer_idx(const size_t layer_idx) const {
const Model::CustomGCode value(layers[layer_idx]->print_z + EPSILON, "", 0, "");
const Model::CustomGCode value{layers[layer_idx]->print_z + EPSILON, "", 0, ""};
auto it = std::lower_bound(color_print_values->begin(), color_print_values->end(), value);
return (it - color_print_values->begin()) % number_tools();
}
@ -5406,7 +5405,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
auto it = std::find_if(color_print_values->begin(), color_print_values->end(),
[print_z](const Model::CustomGCode& code)
{ return fabs(code.height - print_z) < EPSILON; });
{ return fabs(code.print_z - print_z) < EPSILON; });
if (it != color_print_values->end())
{
const std::string& code = it->gcode;
@ -5426,7 +5425,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
}
}
const Model::CustomGCode value(print_z + EPSILON, "", 0, "");
const Model::CustomGCode value{print_z + EPSILON, "", 0, ""};
it = std::lower_bound(color_print_values->begin(), color_print_values->end(), value);
while (it != color_print_values->begin())
{

View File

@ -185,7 +185,7 @@ private:
bool m_layer_height_profile_modified;
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
mutable float m_adaptive_cusp;
mutable float m_adaptive_quality;
mutable HeightProfileSmoothingParams m_smooth_params;
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
@ -236,8 +236,8 @@ private:
void accept_changes(GLCanvas3D& canvas);
void reset_layer_height_profile(GLCanvas3D& canvas);
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void adaptive_layer_height_profile(GLCanvas3D& canvas, float cusp);
void smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_paramsn);
void adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor);
void smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_params);
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
static float get_cursor_z_relative(const GLCanvas3D& canvas);
@ -436,7 +436,9 @@ private:
bool m_use_clipping_planes;
mutable SlaCap m_sla_caps[2];
std::string m_sidebar_field;
bool m_keep_dirty;
// when true renders an extra frame by not resetting m_dirty to false
// see request_extra_frame()
bool m_extra_frame_requested;
mutable GLVolumeCollection m_volumes;
Selection m_selection;
@ -540,7 +542,7 @@ public:
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void reset_layer_height_profile();
void adaptive_layer_height_profile(float cusp);
void adaptive_layer_height_profile(float quality_factor);
void smooth_layer_height_profile(const HeightProfileSmoothingParams& smoothing_params);
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
@ -665,9 +667,7 @@ public:
void set_cursor(ECursorType type);
void msw_rescale();
bool is_keeping_dirty() const { return m_keep_dirty; }
void start_keeping_dirty() { m_keep_dirty = true; }
void stop_keeping_dirty() { m_keep_dirty = false; }
void request_extra_frame() { m_extra_frame_requested = true; }
int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); }
void force_main_toolbar_left_action(int item_id) { m_main_toolbar.force_left_action(item_id, *this); }

View File

@ -333,17 +333,12 @@ unsigned GUI_App::get_colour_approx_luma(const wxColour &colour)
}
bool GUI_App::dark_mode()
{
const unsigned luma = get_colour_approx_luma(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
return luma < 128;
}
bool GUI_App::dark_mode_menus()
{
#if __APPLE__
return mac_dark_mode();
#else
return dark_mode();
const unsigned luma = get_colour_approx_luma(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
return luma < 128;
#endif
}

View File

@ -109,7 +109,6 @@ public:
static unsigned get_colour_approx_luma(const wxColour &colour);
static bool dark_mode();
static bool dark_mode_menus();
void init_label_colours();
void update_label_colours_from_appconfig();
void init_fonts();

View File

@ -1193,7 +1193,13 @@ void ObjectList::get_settings_choice(const wxString& category_name)
{
wxArrayString names;
wxArrayInt selections;
wxDataViewItem item = GetSelection();
/* If we try to add settings for object/part from 3Dscene,
* for the second try there is selected ItemSettings in ObjectList.
* So, check if selected item isn't SettingsItem. And get a SettingsItem's parent item, if yes
*/
const wxDataViewItem selected_item = GetSelection();
wxDataViewItem item = m_objects_model->GetItemType(selected_item) & itSettings ? m_objects_model->GetParent(selected_item) : selected_item;
const ItemType item_type = m_objects_model->GetItemType(item);
@ -1319,11 +1325,17 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name)
{
std::vector<std::string> options = get_options_for_bundle(bundle_name);
const Selection& selection = scene_selection();
wxDataViewItem item = GetSelectedItemsCount() > 1 && selection.is_single_full_object() ?
m_objects_model->GetItemById(selection.get_object_idx()) :
GetSelection();
const wxDataViewItem sel_item = // when all instances in object are selected
GetSelectedItemsCount() > 1 && selection.is_single_full_object() ?
m_objects_model->GetItemById(selection.get_object_idx()) :
GetSelection();
ItemType item_type = m_objects_model->GetItemType(item);
/* If we try to add settings for object/part from 3Dscene,
* for the second try there is selected ItemSettings in ObjectList.
* So, check if selected item isn't SettingsItem. And get a SettingsItem's parent item, if yes
*/
wxDataViewItem item = m_objects_model->GetItemType(sel_item) & itSettings ? m_objects_model->GetParent(sel_item) : sel_item;
const ItemType item_type = m_objects_model->GetItemType(item);
/* Because of we couldn't edited layer_height for ItVolume from settings list,
* correct options according to the selected item type :
@ -1547,17 +1559,21 @@ wxMenuItem* ObjectList::append_menu_item_change_type(wxMenu* menu)
wxMenuItem* ObjectList::append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent)
{
wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _(L("Set as a Separated Object")), "",
[this](wxCommandEvent&) { split_instances(); }, "", menu, [](){return wxGetApp().plater()->can_set_instance_to_object(); }, parent);
[this](wxCommandEvent&) { split_instances(); }, "", menu);
/* New behavior logic:
* 1. Split Object to several separated object, if ALL instances are selected
* 2. Separate selected instances from the initial object to the separated object,
* if some (not all) instances are selected
*/
parent->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt) {
evt.SetText(wxGetApp().plater()->canvas3D()->get_selection().is_single_full_object() ?
_(L("Set as a Separated Objects")) : _(L("Set as a Separated Object")));
}, menu_item->GetId());
parent->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt)
{
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
evt.SetText(selection.is_single_full_object() ?
_(L("Set as a Separated Objects")) : _(L("Set as a Separated Object")));
evt.Enable(wxGetApp().plater()->can_set_instance_to_object());
}, menu_item->GetId());
return menu_item;
}
@ -1608,7 +1624,8 @@ void ObjectList::append_menu_item_export_stl(wxMenu* menu) const
void ObjectList::append_menu_item_reload_from_disk(wxMenu* menu) const
{
append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")),
[this](wxCommandEvent&) { wxGetApp().plater()->reload_from_disk(); }, "", menu, []() { return wxGetApp().plater()->can_reload_from_disk(); }, wxGetApp().plater());
[this](wxCommandEvent&) { wxGetApp().plater()->reload_from_disk(); }, "", menu,
[]() { return wxGetApp().plater()->can_reload_from_disk(); }, wxGetApp().plater());
}
void ObjectList::append_menu_item_change_extruder(wxMenu* menu) const
@ -1727,13 +1744,22 @@ wxMenu* ObjectList::create_settings_popupmenu(wxMenu *parent_menu)
wxMenu *menu = new wxMenu;
settings_menu_hierarchy settings_menu;
const bool is_part = !(m_objects_model->GetItemType(GetSelection()) == itObject || scene_selection().is_single_full_object());
/* If we try to add settings for object/part from 3Dscene,
* for the second try there is selected ItemSettings in ObjectList.
* So, check if selected item isn't SettingsItem. And get a SettingsItem's parent item, if yes
*/
const wxDataViewItem selected_item = GetSelection();
wxDataViewItem item = m_objects_model->GetItemType(selected_item) & itSettings ? m_objects_model->GetParent(selected_item) : selected_item;
const bool is_part = !(m_objects_model->GetItemType(item) == itObject || scene_selection().is_single_full_object());
get_options_menu(settings_menu, is_part);
for (auto cat : settings_menu) {
append_menu_item(menu, wxID_ANY, _(cat.first), "",
[menu, this](wxCommandEvent& event) { get_settings_choice(menu->GetLabel(event.GetId())); },
CATEGORY_ICON.find(cat.first) == CATEGORY_ICON.end() ? wxNullBitmap : CATEGORY_ICON.at(cat.first), parent_menu);
CATEGORY_ICON.find(cat.first) == CATEGORY_ICON.end() ? wxNullBitmap : CATEGORY_ICON.at(cat.first), parent_menu,
[this]() { return true; }, wxGetApp().plater());
}
return menu;
@ -1753,7 +1779,8 @@ void ObjectList::create_freq_settings_popupmenu(wxMenu *menu, const bool is_obje
append_menu_item(menu, wxID_ANY, _(it.first), "",
[menu, this](wxCommandEvent& event) { get_freq_settings_choice(menu->GetLabel(event.GetId())); },
CATEGORY_ICON.find(it.first) == CATEGORY_ICON.end() ? wxNullBitmap : CATEGORY_ICON.at(it.first), menu);
CATEGORY_ICON.find(it.first) == CATEGORY_ICON.end() ? wxNullBitmap : CATEGORY_ICON.at(it.first), menu,
[this]() { return true; }, wxGetApp().plater());
}
#if 0
// Add "Quick" settings bundles
@ -1766,7 +1793,8 @@ void ObjectList::create_freq_settings_popupmenu(wxMenu *menu, const bool is_obje
append_menu_item(menu, wxID_ANY, wxString::Format(_(L("Quick Add Settings (%s)")), _(it.first)), "",
[menu, this](wxCommandEvent& event) { get_freq_settings_choice(menu->GetLabel(event.GetId())); },
CATEGORY_ICON.find(it.first) == CATEGORY_ICON.end() ? wxNullBitmap : CATEGORY_ICON.at(it.first), menu);
CATEGORY_ICON.find(it.first) == CATEGORY_ICON.end() ? wxNullBitmap : CATEGORY_ICON.at(it.first), menu,
[this]() { return true; }, wxGetApp().plater());
}
#endif
}
@ -3006,7 +3034,8 @@ void ObjectList::update_selections()
else if (selection.is_single_full_object() || selection.is_multiple_full_object())
{
const Selection::ObjectIdxsToInstanceIdxsMap& objects_content = selection.get_content();
if (m_selection_mode & (smSettings | smLayer | smLayerRoot))
// it's impossible to select Settings, Layer or LayerRoot for several objects
if (!selection.is_multiple_full_object() && (m_selection_mode & (smSettings | smLayer | smLayerRoot)))
{
auto obj_idx = objects_content.begin()->first;
wxDataViewItem obj_item = m_objects_model->GetItemById(obj_idx);
@ -3850,8 +3879,8 @@ void ObjectList::show_multi_selection_menu()
GetSelections(sels);
for (const wxDataViewItem& item : sels)
if (!(m_objects_model->GetItemType(item) & (itVolume | itObject)))
// show this menu only for Object(s)/Volume(s) selection
if (!(m_objects_model->GetItemType(item) & (itVolume | itObject | itInstance)))
// show this menu only for Objects(Instances mixed with Objects)/Volumes selection
return;
wxMenu* menu = new wxMenu();
@ -3861,7 +3890,12 @@ void ObjectList::show_multi_selection_menu()
_(L("Select extruder number for selected objects and/or parts")),
[this](wxCommandEvent&) { extruder_selection(); }, "", menu);
PopupMenu(menu);
append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")),
[this](wxCommandEvent&) { wxGetApp().plater()->reload_from_disk(); }, "", menu, []() {
return wxGetApp().plater()->can_reload_from_disk();
}, wxGetApp().plater());
wxGetApp().plater()->PopupMenu(menu);
}
void ObjectList::extruder_selection()
@ -3939,8 +3973,15 @@ void ObjectList::update_after_undo_redo()
Plater::SuppressSnapshots suppress(wxGetApp().plater());
// Unselect all objects before deleting them, so that no change of selection is emitted during deletion.
unselect_objects();//this->UnselectAll();
/* To avoid execution of selection_changed()
* from wxEVT_DATAVIEW_SELECTION_CHANGED emitted from DeleteAll(),
* wrap this two functions into m_prevent_list_events *
* */
m_prevent_list_events = true;
this->UnselectAll();
m_objects_model->DeleteAll();
m_prevent_list_events = false;
size_t obj_idx = 0;
std::vector<size_t> obj_idxs;

View File

@ -366,6 +366,8 @@ public:
void update_printable_state(int obj_idx, int instance_idx);
void toggle_printable_state(wxDataViewItem item);
void show_multi_selection_menu();
private:
#ifdef __WXOSX__
// void OnChar(wxKeyEvent& event);
@ -384,8 +386,6 @@ private:
void OnEditingStarted(wxDataViewEvent &event);
#endif /* __WXMSW__ */
void OnEditingDone(wxDataViewEvent &event);
void show_multi_selection_menu();
void extruder_selection();
void set_extruder_for_selected_items(const int extruder) const ;

View File

@ -569,7 +569,7 @@ void Preview::update_view_type(bool slice_completed)
{
const DynamicPrintConfig& config = wxGetApp().preset_bundle->project_config;
const wxString& choice = !wxGetApp().plater()->model().custom_gcode_per_height.empty() /*&&
const wxString& choice = !wxGetApp().plater()->model().custom_gcode_per_print_z.empty() /*&&
(wxGetApp().extruders_edited_cnt()==1 || !slice_completed) */?
_(L("Color Print")) :
config.option<ConfigOptionFloats>("wiping_volumes_matrix")->values.size() > 1 ?
@ -600,7 +600,7 @@ void Preview::create_double_slider()
Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) {
Model& model = wxGetApp().plater()->model();
model.custom_gcode_per_height = m_slider->GetTicksValues();
model.custom_gcode_per_print_z = m_slider->GetTicksValues();
m_schedule_background_process();
update_view_type(false);
@ -646,7 +646,7 @@ void Preview::check_slider_values(std::vector<Model::CustomGCode>& ticks_from_mo
ticks_from_model.erase(std::remove_if(ticks_from_model.begin(), ticks_from_model.end(),
[layers_z](Model::CustomGCode val)
{
auto it = std::lower_bound(layers_z.begin(), layers_z.end(), val.height - DoubleSlider::epsilon());
auto it = std::lower_bound(layers_z.begin(), layers_z.end(), val.print_z - DoubleSlider::epsilon());
return it == layers_z.end();
}),
ticks_from_model.end());
@ -669,7 +669,7 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool kee
bool snap_to_min = force_sliders_full_range || m_slider->is_lower_at_min();
bool snap_to_max = force_sliders_full_range || m_slider->is_higher_at_max();
std::vector<Model::CustomGCode> &ticks_from_model = wxGetApp().plater()->model().custom_gcode_per_height;
std::vector<Model::CustomGCode> &ticks_from_model = wxGetApp().plater()->model().custom_gcode_per_print_z;
check_slider_values(ticks_from_model, layers_z);
m_slider->SetSliderValues(layers_z);
@ -789,7 +789,7 @@ void Preview::load_print_as_fff(bool keep_z_range)
colors.push_back("#808080"); // gray color for pause print or custom G-code
if (!gcode_preview_data_valid)
color_print_values = wxGetApp().plater()->model().custom_gcode_per_height;
color_print_values = wxGetApp().plater()->model().custom_gcode_per_print_z;
}
else if (gcode_preview_data_valid || (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::Tool) )
{

View File

@ -136,12 +136,25 @@ void GLGizmoCut::on_render_for_picking() const
void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit)
{
const float approx_height = m_imgui->scaled(11.0f);
y = std::min(y, bottom_limit - approx_height);
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
static float last_y = 0.0f;
static float last_h = 0.0f;
m_imgui->begin(_(L("Cut")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
// adjust window position to avoid overlap the view toolbar
float win_h = ImGui::GetWindowHeight();
y = std::min(y, bottom_limit - win_h);
ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always);
if ((last_h != win_h) || (last_y != y))
{
// ask canvas for another frame to render the window in the correct position
m_parent.request_extra_frame();
if (last_h != win_h)
last_h = win_h;
if (last_y != y)
last_y = y;
}
ImGui::AlignTextToFramePadding();
m_imgui->text("Z");
ImGui::SameLine();

View File

@ -749,17 +749,36 @@ void GLGizmoSlaSupports::make_line_segments() const
void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_limit)
{
if (!m_c->m_model_object)
static float last_y = 0.0f;
static float last_h = 0.0f;
if (! m_c->m_model_object)
return;
bool first_run = true; // This is a hack to redraw the button when all points are removed,
// so it is not delayed until the background process finishes.
RENDER_AGAIN:
const float approx_height = m_imgui->scaled(18.0f);
y = std::min(y, bottom_limit - approx_height);
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
//m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
//const ImVec2 window_size(m_imgui->scaled(18.f, 16.f));
//ImGui::SetNextWindowPos(ImVec2(x, y - std::max(0.f, y+window_size.y-bottom_limit) ));
//ImGui::SetNextWindowSize(ImVec2(window_size));
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
// adjust window position to avoid overlap the view toolbar
float win_h = ImGui::GetWindowHeight();
y = std::min(y, bottom_limit - win_h);
ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always);
if ((last_h != win_h) || (last_y != y))
{
// ask canvas for another frame to render the window in the correct position
m_parent.request_extra_frame();
if (last_h != win_h)
last_h = win_h;
if (last_y != y)
last_y = y;
}
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
const float settings_sliders_left = std::max(m_imgui->calc_text_size(m_desc.at("minimal_distance")).x, m_imgui->calc_text_size(m_desc.at("points_density")).x) + m_imgui->scaled(1.f);

View File

@ -20,10 +20,6 @@ GLGizmosManager::GLGizmosManager(GLCanvas3D& parent)
, m_enabled(false)
, m_icons_texture_dirty(true)
, m_current(Undefined)
, m_overlay_icons_size(Default_Icons_Size)
, m_overlay_scale(1.0f)
, m_overlay_border(5.0f)
, m_overlay_gap_y(5.0f)
, m_tooltip("")
, m_serializing(false)
{
@ -53,19 +49,18 @@ size_t GLGizmosManager::get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const
return Undefined;
float cnv_h = (float)m_parent.get_canvas_size().get_height();
float height = get_total_overlay_height();
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
float scaled_border = m_overlay_border * m_overlay_scale;
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
float top_y = 0.5f * (cnv_h - height) + scaled_border;
float height = get_scaled_total_height();
float icons_size = m_layout.scaled_icons_size();
float border = m_layout.scaled_border();
float stride_y = m_layout.scaled_stride_y();
float top_y = 0.5f * (cnv_h - height) + border;
// is mouse horizontally in the area?
if ((scaled_border <= (float)mouse_pos(0) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size))) {
if ((border <= (float)mouse_pos(0) && ((float)mouse_pos(0) <= border + icons_size))) {
// which icon is it on?
size_t from_top = (size_t)((float)mouse_pos(1) - top_y)/scaled_stride_y;
size_t from_top = (size_t)((float)mouse_pos(1) - top_y) / stride_y;
// is it really on the icon or already past the border?
if ((float)mouse_pos(1) <= top_y + from_top*scaled_stride_y + scaled_icons_size) {
if ((float)mouse_pos(1) <= top_y + from_top * stride_y + icons_size) {
std::vector<size_t> selectable = get_selectable_idxs();
if (from_top < selectable.size())
return selectable[from_top];
@ -113,18 +108,18 @@ bool GLGizmosManager::init()
void GLGizmosManager::set_overlay_icon_size(float size)
{
if (m_overlay_icons_size != size)
if (m_layout.icons_size != size)
{
m_overlay_icons_size = size;
m_layout.icons_size = size;
m_icons_texture_dirty = true;
}
}
void GLGizmosManager::set_overlay_scale(float scale)
{
if (m_overlay_scale != scale)
if (m_layout.scale != scale)
{
m_overlay_scale = scale;
m_layout.scale = scale;
m_icons_texture_dirty = true;
}
}
@ -873,26 +868,27 @@ void GLGizmosManager::do_render_overlay() const
float zoom = (float)m_parent.get_camera().get_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
float height = get_total_overlay_height();
float width = get_total_overlay_width();
float scaled_border = m_overlay_border * m_overlay_scale * inv_zoom;
float height = get_scaled_total_height();
float width = get_scaled_total_width();
float zoomed_border = m_layout.scaled_border() * inv_zoom;
float top_x = (-0.5f * cnv_w) * inv_zoom;
float top_y = (0.5f * height) * inv_zoom;
float zoomed_top_x = (-0.5f * cnv_w) * inv_zoom;
float zoomed_top_y = (0.5f * height) * inv_zoom;
float left = top_x;
float top = top_y;
float right = left + width * inv_zoom;
float bottom = top - height * inv_zoom;
float zoomed_left = zoomed_top_x;
float zoomed_top = zoomed_top_y;
float zoomed_right = zoomed_left + width * inv_zoom;
float zoomed_bottom = zoomed_top - height * inv_zoom;
render_background(left, top, right, bottom, scaled_border);
render_background(zoomed_left, zoomed_top, zoomed_right, zoomed_bottom, zoomed_border);
top_x += scaled_border;
top_y -= scaled_border;
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale * inv_zoom;
zoomed_top_x += zoomed_border;
zoomed_top_y -= zoomed_border;
float icons_size = m_layout.scaled_icons_size();
float zoomed_icons_size = icons_size * inv_zoom;
float zoomed_stride_y = m_layout.scaled_stride_y() * inv_zoom;
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale * inv_zoom;
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
unsigned int icons_texture_id = m_icons_texture.get_id();
int tex_width = m_icons_texture.get_width();
int tex_height = m_icons_texture.get_height();
@ -913,53 +909,36 @@ void GLGizmosManager::do_render_overlay() const
int icon_idx = m_current == idx ? 2 : (m_hover == idx ? 1 : 0);
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
float u_icon_size = m_overlay_icons_size * m_overlay_scale * inv_tex_width;
float v_icon_size = m_overlay_icons_size * m_overlay_scale * inv_tex_height;
float u_icon_size = icons_size * inv_tex_width;
float v_icon_size = icons_size * inv_tex_height;
float v_top = sprite_id * v_icon_size;
float u_left = icon_idx * u_icon_size;
float v_bottom = v_top + v_icon_size;
float u_right = u_left + u_icon_size;
GLTexture::render_sub_texture(icons_texture_id, top_x, top_x + scaled_icons_size, top_y - scaled_icons_size, top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } });
GLTexture::render_sub_texture(icons_texture_id, zoomed_top_x, zoomed_top_x + zoomed_icons_size, zoomed_top_y - zoomed_icons_size, zoomed_top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } });
if (idx == m_current) {
float toolbar_top = cnv_h - m_parent.get_view_toolbar_height();
gizmo->render_input_window(width, 0.5f * cnv_h - top_y * zoom, toolbar_top);
gizmo->render_input_window(width, 0.5f * cnv_h - zoomed_top_y * zoom, toolbar_top);
}
top_y -= scaled_stride_y;
zoomed_top_y -= zoomed_stride_y;
}
}
float GLGizmosManager::get_total_overlay_height() const
float GLGizmosManager::get_scaled_total_height() const
{
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
float scaled_border = m_overlay_border * m_overlay_scale;
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
float height = 2.0f * scaled_border;
/*for (size_t idx=0; idx<m_gizmos.size(); ++idx)
{
if ((m_gizmos[idx] == nullptr) || !m_gizmos[idx]->is_selectable())
continue;
height += scaled_stride_y;
}*/
height += get_selectable_idxs().size() * scaled_stride_y;
return height - scaled_gap_y;
return m_layout.scale * (2.0f * m_layout.border + (float)get_selectable_idxs().size() * m_layout.stride_y() - m_layout.gap_y);
}
float GLGizmosManager::get_total_overlay_width() const
float GLGizmosManager::get_scaled_total_width() const
{
return (2.0f * m_overlay_border + m_overlay_icons_size) * m_overlay_scale;
return 2.0f * m_layout.scaled_border() + m_layout.scaled_icons_size();
}
GLGizmoBase* GLGizmosManager::get_current() const
{
if (m_current==Undefined || m_gizmos.empty())
return nullptr;
else
return m_gizmos[m_current].get();
return ((m_current == Undefined) || m_gizmos.empty()) ? nullptr : m_gizmos[m_current].get();
}
bool GLGizmosManager::generate_icons_texture() const
@ -984,7 +963,7 @@ bool GLGizmosManager::generate_icons_texture() const
states.push_back(std::make_pair(2, false)); // Disabled
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
unsigned int sprite_size_px = (unsigned int)(m_overlay_icons_size * m_overlay_scale);
unsigned int sprite_size_px = (unsigned int)m_layout.scaled_icons_size();
// // force even size
// if (sprite_size_px % 2 != 0)
// sprite_size_px += 1;

View File

@ -65,12 +65,28 @@ public:
};
private:
struct Layout
{
float scale{ 1.0f };
float icons_size{ Default_Icons_Size };
float border{ 5.0f };
float gap_y{ 5.0f };
float stride_y() const { return icons_size + gap_y;}
float scaled_icons_size() const { return scale * icons_size; }
float scaled_border() const { return scale * border; }
float scaled_gap_y() const { return scale * gap_y; }
float scaled_stride_y() const { return scale * stride_y(); }
};
GLCanvas3D& m_parent;
bool m_enabled;
std::vector<std::unique_ptr<GLGizmoBase>> m_gizmos;
mutable GLTexture m_icons_texture;
mutable bool m_icons_texture_dirty;
BackgroundTexture m_background_texture;
Layout m_layout;
EType m_current;
EType m_hover;
@ -80,11 +96,6 @@ private:
void activate_gizmo(EType type);
float m_overlay_icons_size;
float m_overlay_scale;
float m_overlay_border;
float m_overlay_gap_y;
struct MouseCapture
{
bool left;
@ -205,8 +216,8 @@ private:
void render_background(float left, float top, float right, float bottom, float border) const;
void do_render_overlay() const;
float get_total_overlay_height() const;
float get_total_overlay_width() const;
float get_scaled_total_height() const;
float get_scaled_total_width() const;
bool generate_icons_texture() const;

View File

@ -254,6 +254,16 @@ bool ImGuiWrapper::begin(const wxString &name, int flags)
return begin(into_u8(name), flags);
}
bool ImGuiWrapper::begin(const std::string& name, bool* close, int flags)
{
return ImGui::Begin(name.c_str(), close, (ImGuiWindowFlags)flags);
}
bool ImGuiWrapper::begin(const wxString& name, bool* close, int flags)
{
return begin(into_u8(name), close, flags);
}
void ImGuiWrapper::end()
{
ImGui::End();

View File

@ -56,6 +56,8 @@ public:
bool begin(const std::string &name, int flags = 0);
bool begin(const wxString &name, int flags = 0);
bool begin(const std::string& name, bool* close, int flags = 0);
bool begin(const wxString& name, bool* close, int flags = 0);
void end();
bool button(const wxString &label);

View File

@ -380,16 +380,6 @@ void MainFrame::on_dpi_changed(const wxRect &suggested_rect)
this->Maximize(is_maximized);
}
static std::string menu_icon(const std::string& icon_name)
{
#ifdef __WXMSW__
const std::string folder = "white\\";
#else
const std::string folder = "white/";
#endif
return wxGetApp().dark_mode_menus() ? folder+icon_name : icon_name;
}
void MainFrame::init_menubar()
{
#ifdef __APPLE__
@ -403,7 +393,7 @@ void MainFrame::init_menubar()
[this](wxCommandEvent&) { if (m_plater) m_plater->new_project(); }, "", nullptr,
[this](){return m_plater != nullptr && can_start_new_project(); }, this);
append_menu_item(fileMenu, wxID_ANY, _(L("&Open Project")) + dots + "\tCtrl+O", _(L("Open a project file")),
[this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, menu_icon("open"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, "open", nullptr,
[this](){return m_plater != nullptr; }, this);
wxMenu* recent_projects_menu = new wxMenu();
@ -441,60 +431,65 @@ void MainFrame::init_menubar()
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_recent_projects.GetCount() > 0); }, recent_projects_submenu->GetId());
append_menu_item(fileMenu, wxID_ANY, _(L("&Save Project")) + "\tCtrl+S", _(L("Save current project file")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(into_path(m_plater->get_project_filename(".3mf"))); }, menu_icon("save"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(into_path(m_plater->get_project_filename(".3mf"))); }, "save", nullptr,
[this](){return m_plater != nullptr && can_save(); }, this);
#ifdef __APPLE__
append_menu_item(fileMenu, wxID_ANY, _(L("Save Project &as")) + dots + "\tCtrl+Shift+S", _(L("Save current project file as")),
#else
append_menu_item(fileMenu, wxID_ANY, _(L("Save Project &as")) + dots + "\tCtrl+Alt+S", _(L("Save current project file as")),
#endif // __APPLE__
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(); }, menu_icon("save"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(); }, "save", nullptr,
[this](){return m_plater != nullptr && can_save(); }, this);
fileMenu->AppendSeparator();
wxMenu* import_menu = new wxMenu();
append_menu_item(import_menu, wxID_ANY, _(L("Import STL/OBJ/AM&F/3MF")) + dots + "\tCtrl+I", _(L("Load a model")),
[this](wxCommandEvent&) { if (m_plater) m_plater->add_model(); }, menu_icon("import_plater"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->add_model(); }, "import_plater", nullptr,
[this](){return m_plater != nullptr; }, this);
import_menu->AppendSeparator();
append_menu_item(import_menu, wxID_ANY, _(L("Import &Config")) + dots + "\tCtrl+L", _(L("Load exported configuration file")),
[this](wxCommandEvent&) { load_config_file(); }, menu_icon("import_config"));
[this](wxCommandEvent&) { load_config_file(); }, "import_config", nullptr,
[this]() {return true; }, this);
append_menu_item(import_menu, wxID_ANY, _(L("Import Config from &project")) + dots +"\tCtrl+Alt+L", _(L("Load configuration from project file")),
[this](wxCommandEvent&) { if (m_plater) m_plater->extract_config_from_project(); }, menu_icon("import_config"));
[this](wxCommandEvent&) { if (m_plater) m_plater->extract_config_from_project(); }, "import_config", nullptr,
[this]() {return true; }, this);
import_menu->AppendSeparator();
append_menu_item(import_menu, wxID_ANY, _(L("Import Config &Bundle")) + dots, _(L("Load presets from a bundle")),
[this](wxCommandEvent&) { load_configbundle(); }, menu_icon("import_config_bundle"));
[this](wxCommandEvent&) { load_configbundle(); }, "import_config_bundle", nullptr,
[this]() {return true; }, this);
append_submenu(fileMenu, import_menu, wxID_ANY, _(L("&Import")), "");
wxMenu* export_menu = new wxMenu();
wxMenuItem* item_export_gcode = append_menu_item(export_menu, wxID_ANY, _(L("Export &G-code")) + dots +"\tCtrl+G", _(L("Export current plate as G-code")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(); }, menu_icon("export_gcode"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(); }, "export_gcode", nullptr,
[this](){return can_export_gcode(); }, this);
m_changeable_menu_items.push_back(item_export_gcode);
wxMenuItem* item_send_gcode = append_menu_item(export_menu, wxID_ANY, _(L("S&end G-code")) + dots +"\tCtrl+Shift+G", _(L("Send to print current plate as G-code")),
[this](wxCommandEvent&) { if (m_plater) m_plater->send_gcode(); }, menu_icon("export_gcode"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->send_gcode(); }, "export_gcode", nullptr,
[this](){return can_send_gcode(); }, this);
m_changeable_menu_items.push_back(item_send_gcode);
export_menu->AppendSeparator();
append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &STL")) + dots, _(L("Export current plate as STL")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, menu_icon("export_plater"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, "export_plater", nullptr,
[this](){return can_export_model(); }, this);
append_menu_item(export_menu, wxID_ANY, _(L("Export plate as STL &including supports")) + dots, _(L("Export current plate as STL including supports")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(true); }, menu_icon("export_plater"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(true); }, "export_plater", nullptr,
[this](){return can_export_supports(); }, this);
append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &AMF")) + dots, _(L("Export current plate as AMF")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_amf(); }, menu_icon("export_plater"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->export_amf(); }, "export_plater", nullptr,
[this](){return can_export_model(); }, this);
export_menu->AppendSeparator();
append_menu_item(export_menu, wxID_ANY, _(L("Export &toolpaths as OBJ")) + dots, _(L("Export toolpaths as OBJ")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_toolpaths_to_obj(); }, menu_icon("export_plater"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->export_toolpaths_to_obj(); }, "export_plater", nullptr,
[this]() {return can_export_toolpaths(); }, this);
export_menu->AppendSeparator();
append_menu_item(export_menu, wxID_ANY, _(L("Export &Config")) +dots +"\tCtrl+E", _(L("Export current configuration to file")),
[this](wxCommandEvent&) { export_config(); }, menu_icon("export_config"));
[this](wxCommandEvent&) { export_config(); }, "export_config", nullptr,
[this]() {return true; }, this);
append_menu_item(export_menu, wxID_ANY, _(L("Export Config &Bundle")) + dots, _(L("Export all presets to file")),
[this](wxCommandEvent&) { export_configbundle(); }, menu_icon("export_config_bundle"));
[this](wxCommandEvent&) { export_configbundle(); }, "export_config_bundle", nullptr,
[this]() {return true; }, this);
append_submenu(fileMenu, export_menu, wxID_ANY, _(L("&Export")), "");
fileMenu->AppendSeparator();
@ -522,11 +517,12 @@ void MainFrame::init_menubar()
fileMenu->AppendSeparator();
#endif
m_menu_item_reslice_now = append_menu_item(fileMenu, wxID_ANY, _(L("(Re)Slice No&w")) + "\tCtrl+R", _(L("Start new slicing process")),
[this](wxCommandEvent&) { reslice_now(); }, menu_icon("re_slice"), nullptr,
[this](wxCommandEvent&) { reslice_now(); }, "re_slice", nullptr,
[this](){return m_plater != nullptr && can_reslice(); }, this);
fileMenu->AppendSeparator();
append_menu_item(fileMenu, wxID_ANY, _(L("&Repair STL file")) + dots, _(L("Automatically repair an STL file")),
[this](wxCommandEvent&) { repair_stl(); }, menu_icon("wrench"));
[this](wxCommandEvent&) { repair_stl(); }, "wrench", nullptr,
[this]() {return true; }, this);
fileMenu->AppendSeparator();
append_menu_item(fileMenu, wxID_EXIT, _(L("&Quit")), wxString::Format(_(L("Quit %s")), SLIC3R_APP_NAME),
[this](wxCommandEvent&) { Close(false); });
@ -562,10 +558,10 @@ void MainFrame::init_menubar()
editMenu->AppendSeparator();
append_menu_item(editMenu, wxID_ANY, _(L("&Delete selected")) + sep + hotkey_delete,
_(L("Deletes the current selection")),[this](wxCommandEvent&) { m_plater->remove_selected(); },
menu_icon("remove_menu"), nullptr, [this](){return can_delete(); }, this);
"remove_menu", nullptr, [this](){return can_delete(); }, this);
append_menu_item(editMenu, wxID_ANY, _(L("Delete &all")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + hotkey_delete,
_(L("Deletes all objects")), [this](wxCommandEvent&) { m_plater->reset_with_confirm(); },
menu_icon("delete_all_menu"), nullptr, [this](){return can_delete_all(); }, this);
"delete_all_menu", nullptr, [this](){return can_delete_all(); }, this);
editMenu->AppendSeparator();
append_menu_item(editMenu, wxID_ANY, _(L("&Undo")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "Z",
@ -578,10 +574,10 @@ void MainFrame::init_menubar()
editMenu->AppendSeparator();
append_menu_item(editMenu, wxID_ANY, _(L("&Copy")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "C",
_(L("Copy selection to clipboard")), [this](wxCommandEvent&) { m_plater->copy_selection_to_clipboard(); },
menu_icon("copy_menu"), nullptr, [this](){return m_plater->can_copy_to_clipboard(); }, this);
"copy_menu", nullptr, [this](){return m_plater->can_copy_to_clipboard(); }, this);
append_menu_item(editMenu, wxID_ANY, _(L("&Paste")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "V",
_(L("Paste clipboard")), [this](wxCommandEvent&) { m_plater->paste_from_clipboard(); },
menu_icon("paste_menu"), nullptr, [this](){return m_plater->can_paste_from_clipboard(); }, this);
"paste_menu", nullptr, [this](){return m_plater->can_paste_from_clipboard(); }, this);
}
// Window menu
@ -590,26 +586,30 @@ void MainFrame::init_menubar()
size_t tab_offset = 0;
if (m_plater) {
append_menu_item(windowMenu, wxID_HIGHEST + 1, _(L("&Plater Tab")) + "\tCtrl+1", _(L("Show the plater")),
[this](wxCommandEvent&) { select_tab(0); }, menu_icon("plater"));
[this](wxCommandEvent&) { select_tab(0); }, "plater", nullptr,
[this]() {return true; }, this);
tab_offset += 1;
}
if (tab_offset > 0) {
windowMenu->AppendSeparator();
}
append_menu_item(windowMenu, wxID_HIGHEST + 2, _(L("P&rint Settings Tab")) + "\tCtrl+2", _(L("Show the print settings")),
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 0); }, menu_icon("cog"));
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 0); }, "cog", nullptr,
[this]() {return true; }, this);
wxMenuItem* item_material_tab = append_menu_item(windowMenu, wxID_HIGHEST + 3, _(L("&Filament Settings Tab")) + "\tCtrl+3", _(L("Show the filament settings")),
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 1); }, menu_icon("spool"));
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 1); }, "spool", nullptr,
[this]() {return true; }, this);
m_changeable_menu_items.push_back(item_material_tab);
append_menu_item(windowMenu, wxID_HIGHEST + 4, _(L("Print&er Settings Tab")) + "\tCtrl+4", _(L("Show the printer settings")),
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 2); }, menu_icon("printer"));
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 2); }, "printer", nullptr,
[this]() {return true; }, this);
if (m_plater) {
windowMenu->AppendSeparator();
append_menu_item(windowMenu, wxID_HIGHEST + 5, _(L("3&D")) + "\tCtrl+5", _(L("Show the 3D editing view")),
[this](wxCommandEvent&) { m_plater->select_view_3D("3D"); }, menu_icon("editor_menu"), nullptr,
[this](wxCommandEvent&) { m_plater->select_view_3D("3D"); }, "editor_menu", nullptr,
[this](){return can_change_view(); }, this);
append_menu_item(windowMenu, wxID_HIGHEST + 6, _(L("Pre&view")) + "\tCtrl+6", _(L("Show the 3D slices preview")),
[this](wxCommandEvent&) { m_plater->select_view_3D("Preview"); }, menu_icon("preview_menu"), nullptr,
[this](wxCommandEvent&) { m_plater->select_view_3D("Preview"); }, "preview_menu", nullptr,
[this](){return can_change_view(); }, this);
}
@ -628,7 +628,8 @@ void MainFrame::init_menubar()
windowMenu->AppendSeparator();
append_menu_item(windowMenu, wxID_ANY, _(L("Print &Host Upload Queue")) + "\tCtrl+J", _(L("Display the Print Host Upload Queue window")),
[this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, menu_icon("upload_queue"));
[this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "upload_queue", nullptr,
[this]() {return true; }, this);
}
// View menu
@ -727,7 +728,7 @@ void MainFrame::update_menubar()
m_changeable_menu_items[miSend] ->SetItemLabel((is_fff ? _(L("S&end G-code")) : _(L("S&end to print"))) + dots + "\tCtrl+Shift+G");
m_changeable_menu_items[miMaterialTab] ->SetItemLabel((is_fff ? _(L("&Filament Settings Tab")) : _(L("Mate&rial Settings Tab"))) + "\tCtrl+3");
m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(this, menu_icon(is_fff ? "spool": "resin")));
m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(this, is_fff ? "spool": "resin"));
}
// To perform the "Quck Slice", "Quick Slice and Save As", "Repeat last Quick Slice" and "Slice to SVG".

View File

@ -5,6 +5,9 @@
#include "GUI_App.hpp"
#include "PresetBundle.hpp"
#include "AppConfig.hpp"
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
#include "GLCanvas3D.hpp"
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
#include <wx/glcanvas.h>
@ -184,7 +187,10 @@ Mouse3DController::Mouse3DController()
, m_device(nullptr)
, m_device_str("")
, m_running(false)
, m_settings_dialog(false)
, m_show_settings_dialog(false)
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
, m_settings_dialog_closed_by_user(false)
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
{
m_last_time = std::chrono::high_resolution_clock::now();
}
@ -229,8 +235,11 @@ bool Mouse3DController::apply(Camera& camera)
if (!m_running && is_device_connected())
{
disconnect_device();
// hides the settings dialog if the user re-plug the device
m_settings_dialog = false;
// hides the settings dialog if the user un-plug the device
m_show_settings_dialog = false;
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
m_settings_dialog_closed_by_user = false;
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
}
// check if the user plugged the device
@ -240,88 +249,144 @@ bool Mouse3DController::apply(Camera& camera)
return is_device_connected() ? m_state.apply(camera) : false;
}
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
#else
void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
{
if (!m_running || !m_settings_dialog)
if (!m_running || !m_show_settings_dialog)
return;
ImGuiWrapper& imgui = *wxGetApp().imgui();
imgui.set_next_window_pos(0.5f * (float)canvas_width, 0.5f * (float)canvas_height, ImGuiCond_Always, 0.5f, 0.5f);
imgui.begin(_(L("3Dconnexion settings")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
const ImVec4& color = ImGui::GetStyleColorVec4(ImGuiCol_Separator);
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text(_(L("Device:")));
ImGui::PopStyleColor();
ImGui::SameLine();
imgui.text(m_device_str);
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text(_(L("Speed:")));
ImGui::PopStyleColor();
float translation_scale = (float)m_state.get_translation_scale() / State::DefaultTranslationScale;
if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.5f, 2.0f, "%.1f"))
m_state.set_translation_scale(State::DefaultTranslationScale * (double)translation_scale);
float rotation_scale = m_state.get_rotation_scale() / State::DefaultRotationScale;
if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.5f, 2.0f, "%.1f"))
m_state.set_rotation_scale(State::DefaultRotationScale * rotation_scale);
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text(_(L("Deadzone:")));
ImGui::PopStyleColor();
float translation_deadzone = (float)m_state.get_translation_deadzone();
if (imgui.slider_float(_(L("Translation")) + "##2", &translation_deadzone, 0.0f, (float)State::MaxTranslationDeadzone, "%.2f"))
m_state.set_translation_deadzone((double)translation_deadzone);
float rotation_deadzone = m_state.get_rotation_deadzone();
if (imgui.slider_float(_(L("Rotation")) + "##2", &rotation_deadzone, 0.0f, State::MaxRotationDeadzone, "%.2f"))
m_state.set_rotation_deadzone(rotation_deadzone);
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
ImGui::Separator();
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text("DEBUG:");
imgui.text("Vectors:");
ImGui::PopStyleColor();
Vec3f translation = m_state.get_translation().cast<float>();
Vec3f rotation = m_state.get_rotation();
ImGui::InputFloat3("Translation##3", translation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
ImGui::InputFloat3("Rotation##3", rotation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text("Queue size:");
ImGui::PopStyleColor();
int translation_size[2] = { (int)m_state.get_translation_queue_size(), (int)m_state.get_translation_queue_max_size() };
int rotation_size[2] = { (int)m_state.get_rotation_queue_size(), (int)m_state.get_rotation_queue_max_size() };
int buttons_size[2] = { (int)m_state.get_buttons_queue_size(), (int)m_state.get_buttons_queue_max_size() };
ImGui::InputInt2("Translation##4", translation_size, ImGuiInputTextFlags_ReadOnly);
ImGui::InputInt2("Rotation##4", rotation_size, ImGuiInputTextFlags_ReadOnly);
ImGui::InputInt2("Buttons", buttons_size, ImGuiInputTextFlags_ReadOnly);
int queue_size = (int)m_state.get_queues_max_size();
if (ImGui::InputInt("Max size", &queue_size, 1, 1, ImGuiInputTextFlags_ReadOnly))
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
// when the user clicks on [X] or [Close] button we need to trigger
// an extra frame to let the dialog disappear
if (m_settings_dialog_closed_by_user)
{
if (queue_size > 0)
m_state.set_queues_max_size(queue_size);
m_show_settings_dialog = false;
m_settings_dialog_closed_by_user = false;
canvas.request_extra_frame();
return;
}
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text("Camera:");
ImGui::PopStyleColor();
Vec3f target = wxGetApp().plater()->get_camera().get_target().cast<float>();
ImGui::InputFloat3("Target", target.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
Size cnv_size = canvas.get_canvas_size();
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
ImGuiWrapper& imgui = *wxGetApp().imgui();
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
imgui.set_next_window_pos(0.5f * (float)cnv_size.get_width(), 0.5f * (float)cnv_size.get_height(), ImGuiCond_Always, 0.5f, 0.5f);
#else
imgui.set_next_window_pos(0.5f * (float)canvas_width, 0.5f * (float)canvas_height, ImGuiCond_Always, 0.5f, 0.5f);
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
static ImVec2 last_win_size(0.0f, 0.0f);
bool shown = true;
if (imgui.begin(_(L("3Dconnexion settings")), &shown, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse))
{
if (shown)
{
ImVec2 win_size = ImGui::GetWindowSize();
if ((last_win_size.x != win_size.x) || (last_win_size.y != win_size.y))
{
// when the user clicks on [X] button, the next time the dialog is shown
// has a dummy size, so we trigger an extra frame to let it have the correct size
last_win_size = win_size;
canvas.request_extra_frame();
}
#else
imgui.begin(_(L("3Dconnexion settings")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
const ImVec4& color = ImGui::GetStyleColorVec4(ImGuiCol_Separator);
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text(_(L("Device:")));
ImGui::PopStyleColor();
ImGui::SameLine();
imgui.text(m_device_str);
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text(_(L("Speed:")));
ImGui::PopStyleColor();
float translation_scale = (float)m_state.get_translation_scale() / State::DefaultTranslationScale;
if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.5f, 2.0f, "%.1f"))
m_state.set_translation_scale(State::DefaultTranslationScale * (double)translation_scale);
float rotation_scale = m_state.get_rotation_scale() / State::DefaultRotationScale;
if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.5f, 2.0f, "%.1f"))
m_state.set_rotation_scale(State::DefaultRotationScale * rotation_scale);
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text(_(L("Deadzone:")));
ImGui::PopStyleColor();
float translation_deadzone = (float)m_state.get_translation_deadzone();
if (imgui.slider_float(_(L("Translation")) + "##2", &translation_deadzone, 0.0f, (float)State::MaxTranslationDeadzone, "%.2f"))
m_state.set_translation_deadzone((double)translation_deadzone);
float rotation_deadzone = m_state.get_rotation_deadzone();
if (imgui.slider_float(_(L("Rotation")) + "##2", &rotation_deadzone, 0.0f, State::MaxRotationDeadzone, "%.2f"))
m_state.set_rotation_deadzone(rotation_deadzone);
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
ImGui::Separator();
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text("DEBUG:");
imgui.text("Vectors:");
ImGui::PopStyleColor();
Vec3f translation = m_state.get_translation().cast<float>();
Vec3f rotation = m_state.get_rotation();
ImGui::InputFloat3("Translation##3", translation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
ImGui::InputFloat3("Rotation##3", rotation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text("Queue size:");
ImGui::PopStyleColor();
int translation_size[2] = { (int)m_state.get_translation_queue_size(), (int)m_state.get_translation_queue_max_size() };
int rotation_size[2] = { (int)m_state.get_rotation_queue_size(), (int)m_state.get_rotation_queue_max_size() };
int buttons_size[2] = { (int)m_state.get_buttons_queue_size(), (int)m_state.get_buttons_queue_max_size() };
ImGui::InputInt2("Translation##4", translation_size, ImGuiInputTextFlags_ReadOnly);
ImGui::InputInt2("Rotation##4", rotation_size, ImGuiInputTextFlags_ReadOnly);
ImGui::InputInt2("Buttons", buttons_size, ImGuiInputTextFlags_ReadOnly);
int queue_size = (int)m_state.get_queues_max_size();
if (ImGui::InputInt("Max size", &queue_size, 1, 1, ImGuiInputTextFlags_ReadOnly))
{
if (queue_size > 0)
m_state.set_queues_max_size(queue_size);
}
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text("Camera:");
ImGui::PopStyleColor();
Vec3f target = wxGetApp().plater()->get_camera().get_target().cast<float>();
ImGui::InputFloat3("Target", target.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
ImGui::Separator();
if (imgui.button(_(L("Close"))))
{
// the user clicked on the [Close] button
m_settings_dialog_closed_by_user = true;
canvas.set_as_dirty();
}
}
else
{
// the user clicked on the [X] button
m_settings_dialog_closed_by_user = true;
canvas.set_as_dirty();
}
}
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
imgui.end();
}

View File

@ -18,6 +18,9 @@ namespace Slic3r {
namespace GUI {
struct Camera;
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
class GLCanvas3D;
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
class Mouse3DController
{
@ -130,7 +133,13 @@ class Mouse3DController
hid_device* m_device;
std::string m_device_str;
bool m_running;
bool m_settings_dialog;
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
mutable bool m_show_settings_dialog;
// set to true when ther user closes the dialog by clicking on [X] or [Close] buttons
mutable bool m_settings_dialog_closed_by_user;
#else
bool m_show_settings_dialog;
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
std::chrono::time_point<std::chrono::high_resolution_clock> m_last_time;
public:
@ -146,9 +155,13 @@ public:
bool apply(Camera& camera);
bool is_settings_dialog_shown() const { return m_settings_dialog; }
void show_settings_dialog(bool show) { m_settings_dialog = show && is_running(); }
bool is_settings_dialog_shown() const { return m_show_settings_dialog; }
void show_settings_dialog(bool show) { m_show_settings_dialog = show && is_running(); }
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
void render_settings_dialog(GLCanvas3D& canvas) const;
#else
void render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const;
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
private:
bool connect_device();

View File

@ -2252,7 +2252,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
config += std::move(config_loaded);
}
this->model.custom_gcode_per_height = model.custom_gcode_per_height;
this->model.custom_gcode_per_print_z = model.custom_gcode_per_print_z;
}
if (load_config)
@ -2671,7 +2671,7 @@ void Plater::priv::reset()
// The hiding of the slicing results, if shown, is not taken care by the background process, so we do it here
this->sidebar->show_sliced_info_sizer(false);
model.custom_gcode_per_height.clear();
model.custom_gcode_per_print_z.clear();
}
void Plater::priv::mirror(Axis axis)
@ -3219,34 +3219,48 @@ void Plater::priv::reload_from_disk()
while (!missing_input_paths.empty())
{
// ask user to select the missing file
std::string search = missing_input_paths.back().string();
wxFileDialog dialog(q, _(L("Please select the file to reload:")), "", search, file_wildcards(FT_MODEL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
fs::path search = missing_input_paths.back();
wxString title = _(L("Please select the file to reload"));
#if defined(__APPLE__)
title += " (" + from_u8(search.filename().string()) + "):";
#else
title += ":";
#endif // __APPLE__
wxFileDialog dialog(q, title, "", from_u8(search.filename().string()), file_wildcards(FT_MODEL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if (dialog.ShowModal() != wxID_OK)
return;
std::string sel_filename_path = dialog.GetPath().ToUTF8().data();
std::string sel_filename = fs::path(sel_filename_path).filename().string();
if (boost::algorithm::iends_with(search, sel_filename))
if (boost::algorithm::iequals(search.filename().string(), sel_filename))
{
input_paths.push_back(sel_filename_path);
missing_input_paths.pop_back();
std::string sel_path = fs::path(sel_filename_path).remove_filename().string();
fs::path sel_path = fs::path(sel_filename_path).remove_filename().string();
std::vector<fs::path>::iterator it = missing_input_paths.begin();
while (it != missing_input_paths.end())
{
// try to use the path of the selected file with all remaining missing files
std::string repathed_filename = sel_path + "/" + it->filename().string();
fs::path repathed_filename = sel_path;
repathed_filename /= it->filename();
if (fs::exists(repathed_filename))
{
input_paths.push_back(repathed_filename);
input_paths.push_back(repathed_filename.string());
it = missing_input_paths.erase(it);
}
else
++it;
}
}
else
{
wxString message = _(L("It is not allowed to change the file to reload")) + " (" + from_u8(search.filename().string()) + ").\n" + _(L("Do you want to retry")) + " ?";
wxMessageDialog dlg(q, message, wxMessageBoxCaptionStr, wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION);
if (dlg.ShowModal() != wxID_YES)
return;
}
}
#endif // ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
@ -3281,7 +3295,8 @@ void Plater::priv::reload_from_disk()
int new_volume_idx = old_volume->source.volume_idx;
int new_object_idx = old_volume->source.object_idx;
if (old_volume->source.input_file == path)
if (boost::algorithm::iequals(fs::path(old_volume->source.input_file).filename().string(),
fs::path(path).filename().string()))
{
assert(new_object_idx < (int)new_model.objects.size());
ModelObject* new_model_object = new_model.objects[new_object_idx];
@ -3295,6 +3310,7 @@ void Plater::priv::reload_from_disk()
new_volume->set_material_id(old_volume->material_id());
new_volume->set_transformation(old_volume->get_transformation());
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
new_volume->source.input_file = path;
std::swap(old_model_object->volumes[old_v.volume_idx], old_model_object->volumes.back());
old_model_object->delete_volume(old_model_object->volumes.size() - 1);
}
@ -3593,7 +3609,10 @@ void Plater::priv::on_right_click(RBtnEvent& evt)
if (evt.data.second) // right button was clicked on empty space
menu = &default_menu;
else
{
sidebar->obj_list()->show_multi_selection_menu();
return;
}
}
else
{
@ -4623,6 +4642,13 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_uppe
remove(obj_idx);
p->load_model_objects(new_objects);
Selection& selection = p->get_selection();
size_t last_id = p->model.objects.size() - 1;
for (size_t i = 0; i < new_objects.size(); ++i)
{
selection.add_object((unsigned int)(last_id - i), i == 0);
}
}
void Plater::export_gcode()
@ -5157,6 +5183,7 @@ const DynamicPrintConfig* Plater::get_plater_config() const
return p->config;
}
// Get vector of extruder colors considering filament color, if extruder color is undefined.
std::vector<std::string> Plater::get_extruder_colors_from_plater_config() const
{
const Slic3r::DynamicPrintConfig* config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
@ -5176,13 +5203,17 @@ std::vector<std::string> Plater::get_extruder_colors_from_plater_config() const
return extruder_colors;
}
/* Get vector of colors used for rendering of a Preview scene in "Color print" mode
* It consists of extruder colors and colors, saved in model.custom_gcode_per_print_z
*/
std::vector<std::string> Plater::get_colors_for_color_print() const
{
std::vector<std::string> colors = get_extruder_colors_from_plater_config();
colors.reserve(colors.size() + p->model.custom_gcode_per_print_z.size());
for (const Model::CustomGCode& code : p->model.custom_gcode_per_height)
for (const Model::CustomGCode& code : p->model.custom_gcode_per_print_z)
if (code.gcode == ColorChangeCode)
colors.push_back(code.color);
colors.emplace_back(code.color);
return colors;
}

View File

@ -29,6 +29,7 @@
#include "libslic3r/libslic3r.h"
#include "libslic3r/Utils.hpp"
#include "GUI_App.hpp"
// Store the print/filament/printer presets into a "presets" subdirectory of the Slic3rPE config dir.
// This breaks compatibility with the upstream Slic3r if the --datadir is used to switch between the two versions.
@ -868,6 +869,9 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
}
// 4) Load the project config values (the per extruder wipe matrix etc).
this->project_config.apply_only(config, s_project_options);
update_custom_gcode_per_print_z_from_config(GUI::wxGetApp().plater()->model().custom_gcode_per_print_z, &this->project_config);
break;
}
case ptSLA:

View File

@ -14,6 +14,7 @@
#include <wx/colordlg.h>
#include <boost/algorithm/string/replace.hpp>
#include <boost/nowide/cstdio.hpp>
#include "BitmapCache.hpp"
#include "GUI.hpp"
@ -57,7 +58,7 @@ void msw_rescale_menu(wxMenu* menu)
#endif /* __WXMSW__ */
#endif /* no __WXGTK__ */
void enable_menu_item(wxUpdateUIEvent& evt, std::function<bool()> const cb_condition, wxMenuItem* item)
void enable_menu_item(wxUpdateUIEvent& evt, std::function<bool()> const cb_condition, wxMenuItem* item, wxWindow* win)
{
const bool enable = cb_condition();
evt.Enable(enable);
@ -66,7 +67,7 @@ void enable_menu_item(wxUpdateUIEvent& evt, std::function<bool()> const cb_condi
const auto it = msw_menuitem_bitmaps.find(item->GetId());
if (it != msw_menuitem_bitmaps.end())
{
const wxBitmap& item_icon = create_scaled_bitmap(nullptr, it->second, 16, false, !enable);
const wxBitmap& item_icon = create_scaled_bitmap(win, it->second, 16, false, !enable);
if (item_icon.IsOk())
item->SetBitmap(item_icon);
}
@ -94,8 +95,8 @@ wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const
menu->Bind(wxEVT_MENU, cb, id);
if (parent) {
parent->Bind(wxEVT_UPDATE_UI, [cb_condition, item](wxUpdateUIEvent& evt) {
enable_menu_item(evt, cb_condition, item); }, id);
parent->Bind(wxEVT_UPDATE_UI, [cb_condition, item, parent](wxUpdateUIEvent& evt) {
enable_menu_item(evt, cb_condition, item, parent); }, id);
}
return item;
@ -108,7 +109,7 @@ wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const
if (id == wxID_ANY)
id = wxNewId();
const wxBitmap& bmp = !icon.empty() ? create_scaled_bitmap(nullptr, icon) : wxNullBitmap; // FIXME: pass window ptr
const wxBitmap& bmp = !icon.empty() ? create_scaled_bitmap(parent, icon) : wxNullBitmap; // FIXME: pass window ptr
//#ifdef __WXMSW__
#ifndef __WXGTK__
if (bmp.IsOk())
@ -126,7 +127,7 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxStrin
wxMenuItem* item = new wxMenuItem(menu, id, string, description);
if (!icon.empty()) {
item->SetBitmap(create_scaled_bitmap(nullptr, icon)); // FIXME: pass window ptr
item->SetBitmap(create_scaled_bitmap(parent, icon)); // FIXME: pass window ptr
//#ifdef __WXMSW__
#ifndef __WXGTK__
msw_menuitem_bitmaps[id] = icon;
@ -137,8 +138,8 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxStrin
menu->Append(item);
if (parent) {
parent->Bind(wxEVT_UPDATE_UI, [cb_condition, item](wxUpdateUIEvent& evt) {
enable_menu_item(evt, cb_condition, item); }, id);
parent->Bind(wxEVT_UPDATE_UI, [cb_condition, item, parent](wxUpdateUIEvent& evt) {
enable_menu_item(evt, cb_condition, item, parent); }, id);
}
return item;
@ -424,6 +425,28 @@ static float get_svg_scale_factor(wxWindow *win)
#endif
}
// in the Dark mode of any platform, we should draw icons in respect to OS background
static std::string icon_name_respected_to_mode(const std::string& bmp_name_in)
{
#ifdef __WXMSW__
const std::string folder = "white\\";
#else
const std::string folder = "white/";
#endif
std::string bmp_name = Slic3r::GUI::wxGetApp().dark_mode() ? folder + bmp_name_in : bmp_name_in;
boost::replace_last(bmp_name, ".png", "");
FILE* fp = NULL;
fp = boost::nowide::fopen(Slic3r::var(bmp_name + ".svg").c_str(), "rb");
if (!fp)
{
bmp_name = bmp_name_in;
boost::replace_last(bmp_name, ".png", "");
if (fp) fclose(fp);
}
return bmp_name;
}
// If an icon has horizontal orientation (width > height) call this function with is_horizontal = true
wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in,
const int px_cnt/* = 16*/, const bool is_horizontal /* = false*/, const bool grayscale/* = false*/)
@ -450,8 +473,10 @@ wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in,
scale_base = (unsigned int)(em_unit(win) * px_cnt * 0.1f + 0.5f);
std::string bmp_name = bmp_name_in;
boost::replace_last(bmp_name, ".png", "");
// std::string bmp_name = bmp_name_in;
// boost::replace_last(bmp_name, ".png", "");
std::string bmp_name = icon_name_respected_to_mode(bmp_name_in);
// Try loading an SVG first, then PNG if SVG is not found:
wxBitmap *bmp = cache.load_svg(bmp_name, width, height, scale_factor, grayscale);
@ -2538,7 +2563,7 @@ std::vector<t_custom_code> DoubleSlider::GetTicksValues() const
for (const TICK_CODE& tick : m_ticks_) {
if (tick.tick > val_size)
break;
values.push_back(t_custom_code(m_values[tick.tick], tick.gcode, tick.extruder, tick.color));
values.emplace_back(t_custom_code{m_values[tick.tick], tick.gcode, tick.extruder, tick.color});
}
return values;
@ -2553,12 +2578,12 @@ void DoubleSlider::SetTicksValues(const std::vector<t_custom_code>& heights)
m_ticks_.clear();
for (auto h : heights) {
auto it = std::lower_bound(m_values.begin(), m_values.end(), h.height - epsilon());
auto it = std::lower_bound(m_values.begin(), m_values.end(), h.print_z - epsilon());
if (it == m_values.end())
continue;
m_ticks_.insert(TICK_CODE(it-m_values.begin(), h.gcode, h.extruder, h.color));
m_ticks_.emplace(TICK_CODE{int(it-m_values.begin()), h.gcode, h.extruder, h.color});
}
if (!was_empty && m_ticks_.empty())
@ -2642,7 +2667,7 @@ void DoubleSlider::draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoin
return;
wxBitmap* icon = m_is_action_icon_focesed ? &m_bmp_add_tick_off.bmp() : &m_bmp_add_tick_on.bmp();
if (m_ticks_.find(tick) != m_ticks_.end())
if (m_ticks_.find(TICK_CODE{tick}) != m_ticks_.end())
icon = m_is_action_icon_focesed ? &m_bmp_del_tick_off.bmp() : &m_bmp_del_tick_on.bmp();
wxCoord x_draw, y_draw;
@ -3081,7 +3106,7 @@ wxString DoubleSlider::get_tooltip(IconFocus icon_focus)
else if (m_is_action_icon_focesed)
{
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
const auto tick_code_it = m_ticks_.find(tick);
const auto tick_code_it = m_ticks_.find(TICK_CODE{tick});
tooltip = tick_code_it == m_ticks_.end() ? (m_state == msSingleExtruder ?
_(L("For add color change use left mouse button click")) :
_(L("For add change extruder use left mouse button click"))) + "\n" +
@ -3240,13 +3265,13 @@ void DoubleSlider::action_tick(const TicksAction action)
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
const auto it = m_ticks_.find(tick);
const auto it = m_ticks_.find(TICK_CODE{tick});
if (it != m_ticks_.end()) // erase this tick
{
if (action == taAdd)
return;
m_ticks_.erase(TICK_CODE(tick));
m_ticks_.erase(TICK_CODE{tick});
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
Refresh();
@ -3350,7 +3375,7 @@ void DoubleSlider::OnRightDown(wxMouseEvent& event)
{
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
// if on this Z doesn't exist tick
auto it = m_ticks_.find(tick);
auto it = m_ticks_.find(TICK_CODE{ tick });
if (it == m_ticks_.end())
{
// show context menu on OnRightUp()
@ -3387,7 +3412,7 @@ int DoubleSlider::get_extruder_for_tick(int tick)
if (m_ticks_.empty())
return 0;
auto it = m_ticks_.lower_bound(tick);
auto it = m_ticks_.lower_bound(TICK_CODE{tick});
while (it != m_ticks_.begin()) {
--it;
if(it->gcode == Slic3r::ExtruderChangeCode)
@ -3454,7 +3479,7 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event)
else if (m_show_edit_menu) {
wxMenu menu;
std::set<TICK_CODE>::iterator it = m_ticks_.find(m_selection == ssLower ? m_lower_value : m_higher_value);
std::set<TICK_CODE>::iterator it = m_ticks_.find(TICK_CODE{ m_selection == ssLower ? m_lower_value : m_higher_value });
const bool is_color_change = it->gcode == Slic3r::ColorChangeCode;
append_menu_item(&menu, wxID_ANY, it->gcode == Slic3r::ColorChangeCode ? _(L("Edit color")) :
@ -3526,7 +3551,7 @@ void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/)
{
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
// if on this Z doesn't exist tick
auto it = m_ticks_.find(tick);
auto it = m_ticks_.find(TICK_CODE{ tick });
if (it == m_ticks_.end())
{
std::string color = "";
@ -3535,7 +3560,7 @@ void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/)
std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
if (m_state == msSingleExtruder && !m_ticks_.empty()) {
auto before_tick_it = std::lower_bound(m_ticks_.begin(), m_ticks_.end(), tick);
auto before_tick_it = std::lower_bound(m_ticks_.begin(), m_ticks_.end(), TICK_CODE{ tick });
while (before_tick_it != m_ticks_.begin()) {
--before_tick_it;
if (before_tick_it->gcode == Slic3r::ColorChangeCode) {
@ -3580,7 +3605,7 @@ void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/)
extruder = get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value);
}
m_ticks_.insert(TICK_CODE(tick, code, extruder, color));
m_ticks_.emplace(TICK_CODE{tick, code, extruder, color});
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
Refresh();
@ -3592,7 +3617,7 @@ void DoubleSlider::edit_tick()
{
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
// if on this Z exists tick
std::set<TICK_CODE>::iterator it = m_ticks_.find(tick);
std::set<TICK_CODE>::iterator it = m_ticks_.find(TICK_CODE{ tick });
if (it != m_ticks_.end())
{
std::string edited_value;
@ -3619,7 +3644,7 @@ void DoubleSlider::edit_tick()
}
m_ticks_.erase(it);
m_ticks_.insert(changed_tick);
m_ticks_.emplace(changed_tick);
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
}
@ -3632,9 +3657,9 @@ void DoubleSlider::change_extruder(int extruder)
std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
// if on this Y doesn't exist tick
if (m_ticks_.find(tick) == m_ticks_.end())
if (m_ticks_.find(TICK_CODE{tick}) == m_ticks_.end())
{
m_ticks_.insert(TICK_CODE(tick, Slic3r::ExtruderChangeCode, extruder, extruder == 0 ? "" : colors[extruder-1]));
m_ticks_.emplace(TICK_CODE{tick, Slic3r::ExtruderChangeCode, extruder, extruder == 0 ? "" : colors[extruder-1]});
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
Refresh();
@ -3672,7 +3697,7 @@ void DoubleSlider::edit_extruder_sequence()
while (tick <= m_max_value)
{
int cur_extruder = m_extruders_sequence.extruders[extruder];
m_ticks_.insert(TICK_CODE(tick, Slic3r::ExtruderChangeCode, cur_extruder + 1, colors[cur_extruder]));
m_ticks_.emplace(TICK_CODE{tick, Slic3r::ExtruderChangeCode, cur_extruder + 1, colors[cur_extruder]});
extruder++;
if (extruder == extr_cnt)
@ -3680,12 +3705,12 @@ void DoubleSlider::edit_extruder_sequence()
if (m_extruders_sequence.is_mm_intervals)
{
value += m_extruders_sequence.interval_by_mm;
auto it = std::lower_bound(m_values.begin(), m_values.end(), value - epsilon());
auto val_it = std::lower_bound(m_values.begin(), m_values.end(), value - epsilon());
if (it == m_values.end())
if (val_it == m_values.end())
break;
tick = it - m_values.begin();
tick = val_it - m_values.begin();
}
else
tick += m_extruders_sequence.interval_by_layers;

View File

@ -17,6 +17,7 @@
#include <set>
#include <functional>
#include "libslic3r/Model.hpp"
#include "libslic3r/GCodeWriter.hpp"
namespace Slic3r {
enum class ModelVolumeType : int;
@ -958,24 +959,12 @@ private:
struct TICK_CODE
{
TICK_CODE(int tick):tick(tick), gcode(Slic3r::ColorChangeCode), extruder(0), color("") {}
TICK_CODE(int tick, const std::string& code) :
tick(tick), gcode(code), extruder(0) {}
TICK_CODE(int tick, int extruder) :
tick(tick), gcode(Slic3r::ColorChangeCode), extruder(extruder) {}
TICK_CODE(int tick, const std::string& code, int extruder, const std::string& color) :
tick(tick), gcode(code), extruder(extruder), color(color) {}
bool operator<(const TICK_CODE& other) const { return other.tick > this->tick; }
bool operator>(const TICK_CODE& other) const { return other.tick < this->tick; }
TICK_CODE operator=(const TICK_CODE& other) const {
TICK_CODE ret_val(other.tick, other.gcode, other.extruder, other.color);
return ret_val;
}
int tick;
std::string gcode;
int extruder;
int tick = 0;
std::string gcode = Slic3r::ColorChangeCode;
int extruder = 0;
std::string color;
};

View File

@ -1,5 +1,6 @@
#include <catch2/catch.hpp>
#include <numeric>
#include <iostream>
#include <boost/filesystem.hpp>
@ -223,3 +224,78 @@ SCENARIO("Various Clipper operations - t/clipper.t", "[ClipperUtils]") {
}
}
}
template<e_ordering o = e_ordering::OFF, class P, class Tree>
double polytree_area(const Tree &tree, std::vector<P> *out)
{
traverse_pt<o>(tree, out);
return std::accumulate(out->begin(), out->end(), 0.0,
[](double a, const P &p) { return a + p.area(); });
}
size_t count_polys(const ExPolygons& expolys)
{
size_t c = 0;
for (auto &ep : expolys) c += ep.holes.size() + 1;
return c;
}
TEST_CASE("Traversing Clipper PolyTree", "[ClipperUtils]") {
// Create a polygon representing unit box
Polygon unitbox;
const auto UNIT = coord_t(1. / SCALING_FACTOR);
unitbox.points = {{0, 0}, {UNIT, 0}, {UNIT, UNIT}, {0, UNIT}};
Polygon box_frame = unitbox;
box_frame.scale(20, 10);
Polygon hole_left = unitbox;
hole_left.scale(8);
hole_left.translate(UNIT, UNIT);
hole_left.reverse();
Polygon hole_right = hole_left;
hole_right.translate(UNIT * 10, 0);
Polygon inner_left = unitbox;
inner_left.scale(4);
inner_left.translate(UNIT * 3, UNIT * 3);
Polygon inner_right = inner_left;
inner_right.translate(UNIT * 10, 0);
Polygons reference = union_({box_frame, hole_left, hole_right, inner_left, inner_right});
ClipperLib::PolyTree tree = union_pt(reference);
double area_sum = box_frame.area() + hole_left.area() +
hole_right.area() + inner_left.area() +
inner_right.area();
REQUIRE(area_sum > 0);
SECTION("Traverse into Polygons WITHOUT spatial ordering") {
Polygons output;
REQUIRE(area_sum == Approx(polytree_area(tree.GetFirst(), &output)));
REQUIRE(output.size() == reference.size());
}
SECTION("Traverse into ExPolygons WITHOUT spatial ordering") {
ExPolygons output;
REQUIRE(area_sum == Approx(polytree_area(tree.GetFirst(), &output)));
REQUIRE(count_polys(output) == reference.size());
}
SECTION("Traverse into Polygons WITH spatial ordering") {
Polygons output;
REQUIRE(area_sum == Approx(polytree_area<e_ordering::ON>(tree.GetFirst(), &output)));
REQUIRE(output.size() == reference.size());
}
SECTION("Traverse into ExPolygons WITH spatial ordering") {
ExPolygons output;
REQUIRE(area_sum == Approx(polytree_area<e_ordering::ON>(tree.GetFirst(), &output)));
REQUIRE(count_polys(output) == reference.size());
}
}

View File

@ -3,7 +3,7 @@
set(SLIC3R_APP_NAME "PrusaSlicer")
set(SLIC3R_APP_KEY "PrusaSlicer")
set(SLIC3R_VERSION "2.1.0")
set(SLIC3R_VERSION "2.2.0-alpha0")
set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN")
set(SLIC3R_RC_VERSION "2,1,0,0")
set(SLIC3R_RC_VERSION_DOTS "2.1.0.0")
set(SLIC3R_RC_VERSION "2,2,0,0")
set(SLIC3R_RC_VERSION_DOTS "2.2.0.0")