mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-14 07:45:58 +08:00
Merge remote-tracking branch 'remotes/prusa/master' into masterPE
This commit is contained in:
commit
1999974f7a
@ -2,6 +2,8 @@ project(Slic3r)
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
|
||||
include("version.inc")
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(SLIC3R_RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/resources")
|
||||
file(TO_NATIVE_PATH "${SLIC3R_RESOURCES_DIR}" SLIC3R_RESOURCES_DIR_WIN)
|
||||
|
||||
@ -22,7 +24,10 @@ endif()
|
||||
|
||||
option(SLIC3R_STATIC "Compile Slic3r with static libraries (Boost, TBB, glew)" ${SLIC3R_STATIC_INITIAL})
|
||||
option(SLIC3R_GUI "Compile Slic3r with GUI components (OpenGL, wxWidgets)" 1)
|
||||
option(SLIC3R_FHS "Assume Slic3r is to be installed in a FHS directory structure" 0)
|
||||
option(SLIC3R_WX_STABLE "Build against wxWidgets stable (3.0) as oppsed to dev (3.1) on Linux" 0)
|
||||
option(SLIC3R_PROFILE "Compile Slic3r with an invasive Shiny profiler" 0)
|
||||
option(SLIC3R_PCH "Use precompiled headers" 1)
|
||||
option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
|
||||
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
|
||||
option(SLIC3R_PERL_XS "Compile XS Perl module and enable Perl unit and integration tests" 0)
|
||||
@ -33,6 +38,15 @@ option(SLIC3R_SYNTAXONLY "Only perform source code correctness checking,
|
||||
option(SLIC3R_BUILD_SANDBOXES "Build development sandboxes" OFF)
|
||||
option(SLIC3R_BUILD_TESTS "Build unit tests" OFF)
|
||||
|
||||
# Print out the SLIC3R_* cache options
|
||||
get_cmake_property(_cache_vars CACHE_VARIABLES)
|
||||
list (SORT _cache_vars)
|
||||
foreach (_cache_var ${_cache_vars})
|
||||
if("${_cache_var}" MATCHES "^SLIC3R_")
|
||||
message(STATUS "${_cache_var}: ${${_cache_var}}")
|
||||
endif ()
|
||||
endforeach()
|
||||
|
||||
if (MSVC)
|
||||
if (SLIC3R_MSVC_COMPILE_PARALLEL)
|
||||
add_compile_options(/MP)
|
||||
@ -42,7 +56,6 @@ if (MSVC)
|
||||
add_compile_options(-bigobj -Zm316)
|
||||
endif ()
|
||||
|
||||
|
||||
# Display and check CMAKE_PREFIX_PATH
|
||||
message(STATUS "SLIC3R_STATIC: ${SLIC3R_STATIC}")
|
||||
if (NOT "${CMAKE_PREFIX_PATH}" STREQUAL "")
|
||||
@ -100,21 +113,26 @@ if(WIN32)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "OS X Deployment target (SDK version)" FORCE)
|
||||
message("OS X SDK Path: ${CMAKE_OSX_SYSROOT}")
|
||||
if (CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
message("OS X Deployment Target: ${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
else ()
|
||||
message("OS X Deployment Target: (default)")
|
||||
endif ()
|
||||
message(STATUS "Mac OS deployment target (SDK version): ${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
endif ()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
# Workaround for an old CMake, which does not understand CMAKE_CXX_STANDARD.
|
||||
add_compile_options(-std=c++11 -Wall -Wno-reorder)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
if (CMAKE_VERSION VERSION_LESS "3.1")
|
||||
# Workaround for an old CMake, which does not understand CMAKE_CXX_STANDARD.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX)
|
||||
# Adding -fext-numeric-literals to enable GCC extensions on definitions of quad float literals, which are required by Boost.
|
||||
add_compile_options(-fext-numeric-literals)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals" )
|
||||
|
||||
if (SLIC3R_SYNTAXONLY)
|
||||
set(CMAKE_CXX_ARCHIVE_CREATE "true")
|
||||
@ -131,9 +149,15 @@ if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX)
|
||||
endif()
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
add_compile_options(-Wall)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder" )
|
||||
|
||||
# On GCC and Clang, no return from a non-void function is a warning only. Here, we make it an error.
|
||||
add_compile_options(-Werror=return-type)
|
||||
|
||||
#removes LOTS of extraneous Eigen warnings
|
||||
add_compile_options(-Wno-ignored-attributes)
|
||||
|
||||
if (SLIC3R_ASAN)
|
||||
add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
|
||||
@ -146,12 +170,14 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STRE
|
||||
endif()
|
||||
|
||||
# Where all the bundled libraries reside?
|
||||
set(LIBDIR ${CMAKE_CURRENT_SOURCE_DIR}/src/)
|
||||
set(LIBDIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
set(LIBDIR_BIN ${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||
# For the bundled boost libraries (boost::nowide)
|
||||
include_directories(${LIBDIR})
|
||||
# For generated header files
|
||||
include_directories(${LIBDIR_BIN}/platform)
|
||||
# For libslic3r.h
|
||||
include_directories(${LIBDIR}/clipper ${LIBDIR}/polypartition)
|
||||
#set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
if(WIN32)
|
||||
# BOOST_ALL_NO_LIB: Avoid the automatic linking of Boost libraries on Windows. Rather rely on explicit linking.
|
||||
@ -215,7 +241,6 @@ endif()
|
||||
# The Intel TBB library will use the std::exception_ptr feature of C++11.
|
||||
add_definitions(-DTBB_USE_CAPTURED_EXCEPTION=0)
|
||||
|
||||
#set(CURL_DEBUG 1)
|
||||
find_package(CURL REQUIRED)
|
||||
include_directories(${CURL_INCLUDE_DIRS})
|
||||
|
||||
@ -239,7 +264,7 @@ endif()
|
||||
|
||||
# Find eigen3 or use bundled version
|
||||
if (NOT SLIC3R_STATIC)
|
||||
find_package(Eigen3)
|
||||
find_package(Eigen3 3)
|
||||
endif ()
|
||||
if (NOT Eigen3_FOUND)
|
||||
set(Eigen3_FOUND 1)
|
||||
@ -280,7 +305,6 @@ include_directories(${GLEW_INCLUDE_DIRS})
|
||||
# l10n
|
||||
set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization")
|
||||
add_custom_target(pot
|
||||
# FIXME: file list stale
|
||||
COMMAND xgettext --keyword=L --from-code=UTF-8 --debug
|
||||
-f "${L10N_DIR}/list.txt"
|
||||
-o "${L10N_DIR}/Slic3rPE.pot"
|
||||
@ -307,5 +331,12 @@ if(SLIC3R_BUILD_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
file(GLOB MyVar var/*.png)
|
||||
install(FILES ${MyVar} DESTINATION share/slic3r-prusa3d)
|
||||
|
||||
# Resources install target, configure fhs.hpp on UNIX
|
||||
if (WIN32)
|
||||
install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/resources")
|
||||
else ()
|
||||
set(SLIC3R_FHS_RESOURCES "${CMAKE_INSTALL_FULL_DATAROOTDIR}/slic3r-prusa3d")
|
||||
install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${SLIC3R_FHS_RESOURCES}")
|
||||
endif ()
|
||||
configure_file(${LIBDIR}/platform/unix/fhs.hpp.in ${LIBDIR_BIN}/platform/unix/fhs.hpp)
|
||||
|
@ -68,11 +68,37 @@ function(export_all_flags _filename)
|
||||
set(_compile_definitions "$<TARGET_PROPERTY:${_target},COMPILE_DEFINITIONS>")
|
||||
set(_compile_flags "$<TARGET_PROPERTY:${_target},COMPILE_FLAGS>")
|
||||
set(_compile_options "$<TARGET_PROPERTY:${_target},COMPILE_OPTIONS>")
|
||||
|
||||
#handle config-specific cxx flags
|
||||
string(TOUPPER ${CMAKE_BUILD_TYPE} _config)
|
||||
set(_build_cxx_flags ${CMAKE_CXX_FLAGS_${_config}})
|
||||
|
||||
#handle fpie option
|
||||
get_target_property(_fpie ${_target} POSITION_INDEPENDENT_CODE)
|
||||
if (_fpie AND CMAKE_POSITION_INDEPENDENT_CODE)
|
||||
list(APPEND _compile_options ${CMAKE_CXX_COMPILE_OPTIONS_PIC})
|
||||
endif()
|
||||
|
||||
#handle compiler standard (GCC only)
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
get_target_property(_cxx_standard ${_target} CXX_STANDARD)
|
||||
if ((NOT "${_cxx_standard}" STREQUAL NOTFOUND) AND (NOT "${_cxx_standard}" STREQUAL ""))
|
||||
get_target_property(_cxx_extensions ${_target} CXX_EXTENSIONS)
|
||||
get_property(_exists TARGET ${_target} PROPERTY CXX_EXTENSIONS SET)
|
||||
if (NOT _exists OR ${_cxx_extensions})
|
||||
list(APPEND _compile_options "-std=gnu++${_cxx_standard}")
|
||||
else()
|
||||
list(APPEND _compile_options "-std=c++${_cxx_standard}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(_include_directories "$<$<BOOL:${_include_directories}>:-I$<JOIN:${_include_directories},\n-I>\n>")
|
||||
set(_compile_definitions "$<$<BOOL:${_compile_definitions}>:-D$<JOIN:${_compile_definitions},\n-D>\n>")
|
||||
set(_compile_flags "$<$<BOOL:${_compile_flags}>:$<JOIN:${_compile_flags},\n>\n>")
|
||||
set(_compile_options "$<$<BOOL:${_compile_options}>:$<JOIN:${_compile_options},\n>\n>")
|
||||
file(GENERATE OUTPUT "${_filename}" CONTENT "${_compile_definitions}${_include_directories}${_compile_flags}${_compile_options}\n")
|
||||
set(_cxx_flags "$<$<BOOL:${CMAKE_CXX_FLAGS}>:${CMAKE_CXX_FLAGS}\n>$<$<BOOL:${_build_cxx_flags}>:${_build_cxx_flags}\n>")
|
||||
file(GENERATE OUTPUT "${_filename}" CONTENT "${_compile_definitions}${_include_directories}${_compile_flags}${_compile_options}${_cxx_flags}\n")
|
||||
endfunction()
|
||||
|
||||
function(add_precompiled_header _target _input)
|
||||
|
23
deps/CMakeLists.txt
vendored
23
deps/CMakeLists.txt
vendored
@ -6,6 +6,7 @@
|
||||
# All the dependencies are installed in a `destdir` directory in the root of the build directory,
|
||||
# in a traditional Unix-style prefix structure. The destdir can be used directly by CMake
|
||||
# when building Slic3r - to do this, set the CMAKE_PREFIX_PATH to ${destdir}/usr/local.
|
||||
# Warning: On UNIX/Linux, you also need to set -DSLIC3R_STATIC=1 when building Slic3r.
|
||||
#
|
||||
# For better clarity of console output, it's recommended to _not_ use a parallelized build
|
||||
# for the top-level command, ie. use `make -j 1` or `ninja -j 1` to force single-threaded top-level
|
||||
@ -32,6 +33,7 @@ endif ()
|
||||
|
||||
set(DESTDIR "${CMAKE_CURRENT_BINARY_DIR}/destdir" CACHE PATH "Destination directory")
|
||||
option(DEP_DEBUG "Build debug variants (only applicable on Windows)" ON)
|
||||
option(DEP_WX_STABLE "Build against wxWidgets stable 3.0 as opposed to default 3.1 (Linux only)" OFF)
|
||||
|
||||
message(STATUS "Slic3r deps DESTDIR: ${DESTDIR}")
|
||||
message(STATUS "Slic3r deps debug build: ${DEP_DEBUG}")
|
||||
@ -49,11 +51,22 @@ if (MSVC)
|
||||
message(FATAL_ERROR "Unable to detect architecture")
|
||||
endif ()
|
||||
elseif (APPLE)
|
||||
set(DEPS_OSX_TARGET "10.9" CACHE STRING "OS X SDK version to build against")
|
||||
set(DEPS_OSX_SYSROOT
|
||||
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX${DEPS_OSX_TARGET}.sdk"
|
||||
CACHE PATH "OS X SDK directory"
|
||||
)
|
||||
message("OS X SDK Path: ${CMAKE_OSX_SYSROOT}")
|
||||
if (CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
set(DEP_OSX_TARGET "${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
message("OS X Deployment Target: ${DEP_OSX_TARGET}")
|
||||
else ()
|
||||
# Attempt to infer the SDK version from the CMAKE_OSX_SYSROOT,
|
||||
# this is done because wxWidgets need the min version explicitly set
|
||||
string(REGEX MATCH "[0-9]+[.][0-9]+[.]sdk$" DEP_OSX_TARGET "${CMAKE_OSX_SYSROOT}")
|
||||
string(REGEX MATCH "^[0-9]+[.][0-9]+" DEP_OSX_TARGET "${DEP_OSX_TARGET}")
|
||||
|
||||
if (NOT DEP_OSX_TARGET)
|
||||
message(FATAL_ERROR "Could not determine OS X SDK version. Please use -DCMAKE_OSX_DEPLOYMENT_TARGET=<version>")
|
||||
endif ()
|
||||
|
||||
message("OS X Deployment Target (inferred from default): ${DEP_OSX_TARGET}")
|
||||
endif ()
|
||||
|
||||
include("deps-macos.cmake")
|
||||
else ()
|
||||
|
27
deps/deps-linux.cmake
vendored
27
deps/deps-linux.cmake
vendored
@ -25,6 +25,19 @@ ExternalProject_Add(dep_boost
|
||||
INSTALL_COMMAND "" # b2 does that already
|
||||
)
|
||||
|
||||
ExternalProject_Add(dep_libpng
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "https://github.com/glennrp/libpng/archive/v1.6.36.tar.gz"
|
||||
URL_HASH SHA256=5bef5a850a9255365a2dc344671b7e9ef810de491bd479c2506ac3c337e2d84f
|
||||
CMAKE_GENERATOR "${DEP_MSVC_GEN}"
|
||||
CMAKE_ARGS
|
||||
-DPNG_SHARED=OFF
|
||||
-DPNG_TESTS=OFF
|
||||
${DEP_CMAKE_OPTS}
|
||||
INSTALL_COMMAND make install "DESTDIR=${DESTDIR}"
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
|
||||
ExternalProject_Add(dep_libopenssl
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "https://github.com/openssl/openssl/archive/OpenSSL_1_1_0g.tar.gz"
|
||||
@ -88,16 +101,24 @@ ExternalProject_Add(dep_libcurl
|
||||
INSTALL_COMMAND make install "DESTDIR=${DESTDIR}"
|
||||
)
|
||||
|
||||
if (DEP_WX_STABLE)
|
||||
set(DEP_WX_URL "https://github.com/wxWidgets/wxWidgets/releases/download/v3.0.4/wxWidgets-3.0.4.tar.bz2")
|
||||
set(DEP_WX_HASH "SHA256=96157f988d261b7368e5340afa1a0cad943768f35929c22841f62c25b17bf7f0")
|
||||
else ()
|
||||
set(DEP_WX_URL "https://github.com/wxWidgets/wxWidgets/releases/download/v3.1.1/wxWidgets-3.1.1.tar.bz2")
|
||||
set(DEP_WX_HASH "SHA256=c925dfe17e8f8b09eb7ea9bfdcfcc13696a3e14e92750effd839f5e10726159e")
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(dep_wxwidgets
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "https://github.com/wxWidgets/wxWidgets/releases/download/v3.1.1/wxWidgets-3.1.1.tar.bz2"
|
||||
URL_HASH SHA256=c925dfe17e8f8b09eb7ea9bfdcfcc13696a3e14e92750effd839f5e10726159e
|
||||
URL "${DEP_WX_URL}"
|
||||
URL_HASH "${DEP_WX_HASH}"
|
||||
BUILD_IN_SOURCE 1
|
||||
PATCH_COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/wxwidgets-pngprefix.h" src/png/pngprefix.h
|
||||
CONFIGURE_COMMAND ./configure
|
||||
"--prefix=${DESTDIR}/usr/local"
|
||||
--disable-shared
|
||||
--with-gtk=2
|
||||
--with-gtk=2
|
||||
--with-opengl
|
||||
--enable-unicode
|
||||
--enable-graphics_ctx
|
||||
|
43
deps/deps-macos.cmake
vendored
43
deps/deps-macos.cmake
vendored
@ -1,13 +1,24 @@
|
||||
|
||||
# This ensures dependencies don't use SDK features which are not available in the version specified by Deployment target
|
||||
# That can happen when one uses a recent SDK but specifies an older Deployment target
|
||||
set(DEP_WERRORS_SDK "-Werror=partial-availability -Werror=unguarded-availability -Werror=unguarded-availability-new")
|
||||
|
||||
set(DEP_CMAKE_OPTS
|
||||
"-DCMAKE_POSITION_INDEPENDENT_CODE=ON"
|
||||
"-DCMAKE_OSX_SYSROOT=${DEPS_OSX_SYSROOT}"
|
||||
"-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPS_OSX_TARGET}"
|
||||
"-DCMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT}"
|
||||
"-DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}"
|
||||
"-DCMAKE_CXX_FLAGS=${DEP_WERRORS_SDK}"
|
||||
"-DCMAKE_C_FLAGS=${DEP_WERRORS_SDK}"
|
||||
)
|
||||
|
||||
include("deps-unix-common.cmake")
|
||||
|
||||
|
||||
set(DEP_BOOST_OSX_TARGET "")
|
||||
if (CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
set(DEP_BOOST_OSX_TARGET "-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
endif ()
|
||||
|
||||
ExternalProject_Add(dep_boost
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.gz"
|
||||
@ -23,8 +34,8 @@ ExternalProject_Add(dep_boost
|
||||
variant=release
|
||||
threading=multi
|
||||
boost.locale.icu=off
|
||||
"cflags=-fPIC -mmacosx-version-min=${DEPS_OSX_TARGET}"
|
||||
"cxxflags=-fPIC -mmacosx-version-min=${DEPS_OSX_TARGET}"
|
||||
"cflags=-fPIC ${DEP_BOOST_OSX_TARGET}"
|
||||
"cxxflags=-fPIC ${DEP_BOOST_OSX_TARGET}"
|
||||
install
|
||||
INSTALL_COMMAND "" # b2 does that already
|
||||
)
|
||||
@ -76,18 +87,32 @@ ExternalProject_Add(dep_libcurl
|
||||
INSTALL_COMMAND make install "DESTDIR=${DESTDIR}"
|
||||
)
|
||||
|
||||
ExternalProject_Add(dep_libpng
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "https://github.com/glennrp/libpng/archive/v1.6.36.tar.gz"
|
||||
URL_HASH SHA256=5bef5a850a9255365a2dc344671b7e9ef810de491bd479c2506ac3c337e2d84f
|
||||
CMAKE_GENERATOR "${DEP_MSVC_GEN}"
|
||||
CMAKE_ARGS
|
||||
-DPNG_SHARED=OFF
|
||||
-DPNG_TESTS=OFF
|
||||
${DEP_CMAKE_OPTS}
|
||||
INSTALL_COMMAND make install "DESTDIR=${DESTDIR}"
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
|
||||
|
||||
ExternalProject_Add(dep_wxwidgets
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "https://github.com/wxWidgets/wxWidgets/releases/download/v3.1.1/wxWidgets-3.1.1.tar.bz2"
|
||||
URL_HASH SHA256=c925dfe17e8f8b09eb7ea9bfdcfcc13696a3e14e92750effd839f5e10726159e
|
||||
URL "https://github.com/wxWidgets/wxWidgets/releases/download/v3.1.2/wxWidgets-3.1.2.tar.bz2"
|
||||
URL_HASH SHA256=4cb8d23d70f9261debf7d6cfeca667fc0a7d2b6565adb8f1c484f9b674f1f27a
|
||||
BUILD_IN_SOURCE 1
|
||||
PATCH_COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/wxwidgets-pngprefix.h" src/png/pngprefix.h
|
||||
CONFIGURE_COMMAND ./configure
|
||||
CONFIGURE_COMMAND env "CXXFLAGS=${DEP_WERRORS_SDK}" "CFLAGS=${DEP_WERRORS_SDK}" ./configure
|
||||
"--prefix=${DESTDIR}/usr/local"
|
||||
--disable-shared
|
||||
--with-osx_cocoa
|
||||
"--with-macosx-version-min=${DEPS_OSX_TARGET}"
|
||||
"--with-macosx-sdk=${DEPS_OSX_SYSROOT}"
|
||||
--with-macosx-sdk=${CMAKE_OSX_SYSROOT}
|
||||
"--with-macosx-version-min=${DEP_OSX_TARGET}"
|
||||
--with-opengl
|
||||
--with-regex=builtin
|
||||
--with-libpng=builtin
|
||||
|
13
deps/deps-unix-common.cmake
vendored
13
deps/deps-unix-common.cmake
vendored
@ -35,16 +35,3 @@ ExternalProject_Add(dep_nlopt
|
||||
INSTALL_COMMAND make install "DESTDIR=${DESTDIR}"
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
|
||||
ExternalProject_Add(dep_libpng
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "http://prdownloads.sourceforge.net/libpng/libpng-1.6.35.tar.xz?download"
|
||||
URL_HASH SHA256=23912ec8c9584917ed9b09c5023465d71709dce089be503c7867fec68a93bcd7
|
||||
CMAKE_GENERATOR "${DEP_MSVC_GEN}"
|
||||
CMAKE_ARGS
|
||||
-DPNG_SHARED=OFF
|
||||
-DPNG_TESTS=OFF
|
||||
${DEP_CMAKE_OPTS}
|
||||
INSTALL_COMMAND make install "DESTDIR=${DESTDIR}"
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
|
39
deps/deps-windows.cmake
vendored
39
deps/deps-windows.cmake
vendored
@ -15,8 +15,8 @@ endif ()
|
||||
|
||||
ExternalProject_Add(dep_boost
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "https://dl.bintray.com/boostorg/release/1.63.0/source/boost_1_63_0.tar.gz"
|
||||
URL_HASH SHA256=fe34a4e119798e10b8cc9e565b3b0284e9fd3977ec8a1b19586ad1dec397088b
|
||||
URL "https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.gz"
|
||||
URL_HASH SHA256=bd0df411efd9a585e5a2212275f8762079fed8842264954675a4fddc46cfcf60
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND bootstrap.bat
|
||||
BUILD_COMMAND b2.exe
|
||||
@ -121,7 +121,8 @@ ExternalProject_Add(dep_zlib
|
||||
URL_HASH SHA256=4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066
|
||||
CMAKE_GENERATOR "${DEP_MSVC_GEN}"
|
||||
CMAKE_ARGS
|
||||
"-DINSTALL_BIN_DIR=${CMAKE_CURRENT_BINARY_DIR}\\fallout" # I found no better way of preventing zlib creating & installing DLLs :-/
|
||||
-DSKIP_INSTALL_FILES=ON # Prevent installation of man pages et al.
|
||||
"-DINSTALL_BIN_DIR=${CMAKE_CURRENT_BINARY_DIR}\\fallout" # I found no better way of preventing zlib from creating & installing DLLs :-/
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
"-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR}\\usr\\local"
|
||||
BUILD_COMMAND msbuild /P:Configuration=Release INSTALL.vcxproj
|
||||
@ -136,17 +137,31 @@ if (${DEP_DEBUG})
|
||||
WORKING_DIRECTORY "${BINARY_DIR}"
|
||||
)
|
||||
endif ()
|
||||
# The following steps are unfortunately needed to remove the _static suffix on libraries
|
||||
ExternalProject_Add_Step(dep_zlib fix_static
|
||||
DEPENDEES install
|
||||
COMMAND "${CMAKE_COMMAND}" -E rename zlibstatic.lib zlib.lib
|
||||
WORKING_DIRECTORY "${DESTDIR}\\usr\\local\\lib\\"
|
||||
)
|
||||
if (${DEP_DEBUG})
|
||||
ExternalProject_Add_Step(dep_zlib fix_static_debug
|
||||
DEPENDEES install
|
||||
COMMAND "${CMAKE_COMMAND}" -E rename zlibstaticd.lib zlibd.lib
|
||||
WORKING_DIRECTORY "${DESTDIR}\\usr\\local\\lib\\"
|
||||
)
|
||||
endif ()
|
||||
|
||||
|
||||
ExternalProject_Add(dep_libpng
|
||||
DEPENDS dep_zlib
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "http://prdownloads.sourceforge.net/libpng/libpng-1.6.35.tar.xz?download"
|
||||
URL_HASH SHA256=23912ec8c9584917ed9b09c5023465d71709dce089be503c7867fec68a93bcd7
|
||||
URL "https://github.com/glennrp/libpng/archive/v1.6.36.tar.gz"
|
||||
URL_HASH SHA256=5bef5a850a9255365a2dc344671b7e9ef810de491bd479c2506ac3c337e2d84f
|
||||
CMAKE_GENERATOR "${DEP_MSVC_GEN}"
|
||||
CMAKE_ARGS
|
||||
-DPNG_SHARED=OFF
|
||||
-DPNG_TESTS=OFF
|
||||
-DSKIP_INSTALL_FILES=ON # Prevent installation of man pages et al.
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
"-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR}\\usr\\local"
|
||||
BUILD_COMMAND msbuild /P:Configuration=Release INSTALL.vcxproj
|
||||
@ -161,6 +176,20 @@ if (${DEP_DEBUG})
|
||||
WORKING_DIRECTORY "${BINARY_DIR}"
|
||||
)
|
||||
endif ()
|
||||
# The following steps are unfortunately needed to remove the _static suffix on libraries
|
||||
# (And also overwrite the dynamic .lib)
|
||||
ExternalProject_Add_Step(dep_libpng fix_static
|
||||
DEPENDEES install
|
||||
COMMAND "${CMAKE_COMMAND}" -E rename libpng16_static.lib libpng16.lib
|
||||
WORKING_DIRECTORY "${DESTDIR}\\usr\\local\\lib\\"
|
||||
)
|
||||
if (${DEP_DEBUG})
|
||||
ExternalProject_Add_Step(dep_libpng fix_static_debug
|
||||
DEPENDEES install
|
||||
COMMAND "${CMAKE_COMMAND}" -E rename libpng16_staticd.lib libpng16d.lib
|
||||
WORKING_DIRECTORY "${DESTDIR}\\usr\\local\\lib\\"
|
||||
)
|
||||
endif ()
|
||||
|
||||
|
||||
if (${DEPS_BITS} EQUAL 32)
|
||||
|
66
doc/How to build - Linux et al.md
Normal file
66
doc/How to build - Linux et al.md
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
# Building Slic3r PE on UNIX/Linux
|
||||
|
||||
Slic3r PE uses the CMake build system and requires several dependencies.
|
||||
The dependencies can be listed in `deps/deps-linux.cmake`, although they don't necessarily need to be as recent
|
||||
as the versions listed - generally versions available on conservative Linux distros such as Debian stable or CentOS should suffice.
|
||||
|
||||
Perl is not required any more.
|
||||
|
||||
In a typical situaction, one would open a command line, go to the Slic3r sources, create a directory called `build` or similar,
|
||||
`cd` into it and call:
|
||||
|
||||
cmake ..
|
||||
make -jN
|
||||
|
||||
where `N` is the number of CPU cores available.
|
||||
|
||||
Additional CMake flags may be applicable as explained below.
|
||||
|
||||
### Dependency resolution
|
||||
|
||||
By default Slic3r looks for dependencies the default way CMake looks for them, ie. in default system locations.
|
||||
On Linux this will typically make Slic3r depend on dynamically loaded libraries from the system, however, Slic3r can be told
|
||||
to specifically look for static libraries with the `SLIC3R_STATIC` flag passed to cmake:
|
||||
|
||||
cmake .. -DSLIC3R_STATIC=1
|
||||
|
||||
Additionally, Slic3r can be built in a static manner mostly independent of the system libraries with a dependencies bundle
|
||||
created using CMake script in the `deps` directory (these are not interconnected with the rest of the CMake scripts).
|
||||
|
||||
Note: We say _mostly independent_ because it's still expected the system will provide some transitive dependencies, such as GTK for wxWidgets.
|
||||
|
||||
To do this, go to the `deps` directory, create a `build` subdirectory (or the like) and use:
|
||||
|
||||
cmake .. -DDESTDIR=<target destdir>
|
||||
|
||||
where the target destdir is a directory of your choosing where the dependencies will be installed.
|
||||
You can also omit the `DESTDIR` option to use the default, in that case the `destdir` will be created inside the `build` directory where `cmake` is run.
|
||||
|
||||
To pass the destdir path to the top-level Slic3r CMake script, use the `CMAKE_PREFIX_PATH` option along with turning on `SLIC3R_STATIC`:
|
||||
|
||||
cmake .. -DSLIC3R_STATIC=1 -DCMAKE_PREFIX_PATH=<path to destdir>/usr/local
|
||||
|
||||
Note that `/usr/local` needs to be appended to the destdir path and also the prefix path should be absolute.
|
||||
|
||||
**Warning**: Once the dependency bundle is installed in a destdir, the destdir cannot be moved elsewhere.
|
||||
This is because wxWidgets hardcode the installation path.
|
||||
|
||||
### Build variant
|
||||
|
||||
By default Scli3r builds the release variant.
|
||||
To create a debug build, use the following CMake flag:
|
||||
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
|
||||
### Installation
|
||||
|
||||
In runtime, Slic3r needs a way to access its resource files. By default, it looks for a `resources` directory relative to its binary.
|
||||
|
||||
If you instead wnat Slic3r installed in a structure according to the Filesystem Hierarchy Standard, use the `SLIC3R_FHS` flag
|
||||
|
||||
cmake .. -DSLIC3R_FHS=1
|
||||
|
||||
This will make Slic3r look for a fixed-location `share/slic3r-prusa3d` directory instead (note that the location becomes hardcoded).
|
||||
|
||||
You can then use the `make install` target to install Slic3r.
|
63
doc/How to build - Mac OS.md
Normal file
63
doc/How to build - Mac OS.md
Normal file
@ -0,0 +1,63 @@
|
||||
|
||||
# Building Slic3r PE on Mac OS
|
||||
|
||||
To build Slic3r PE on Mac OS, you will need to install XCode, [CMake](https://cmake.org/) (available on Brew) and possibly git.
|
||||
|
||||
### Dependencies
|
||||
|
||||
Slic3r comes with a set of CMake scripts to build its dependencies, it lives in the `deps` directory.
|
||||
Open a terminal window and navigate to Slic3r sources directory and then to `deps`.
|
||||
Use the following commands to build the dependencies:
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
|
||||
This will create a dependencies bundle inside the `build/destdir` directory.
|
||||
You can also customize the bundle output path using the `-DDESTDIR=<some path>` option passed to `cmake`.
|
||||
|
||||
**Warning**: Once the dependency bundle is installed in a destdir, the destdir cannot be moved elsewhere.
|
||||
(This is because wxWidgets hardcode the installation path.)
|
||||
|
||||
|
||||
### Building Slic3r
|
||||
|
||||
If dependencies built without an error, you can proceed to build Slic3r itself.
|
||||
Go back to top level Slic3r sources directory and use these commands:
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_PREFIX_PATH="$PWD/../deps/build/destdir/usr/local"
|
||||
|
||||
The `CMAKE_PREFIX_PATH` is the path to the dependencies bundle but with `/usr/local` appended - if you set a custom path
|
||||
using the `DESTDIR` option, you will need to change this accordingly. **Warning:** the `CMAKE_PREFIX_PATH` needs to be an absolute path.
|
||||
|
||||
The CMake command above prepares Slic3r for building from the command line.
|
||||
To start the build, use
|
||||
|
||||
make -jN
|
||||
|
||||
where `N` is the number of CPU cores, so, for example `make -j4` for a 4-core machine.
|
||||
|
||||
Alternatively, if you would like to use XCode GUI, modify the `cmake` command to include the `-GXcode` option:
|
||||
|
||||
cmake .. -GXcode -DCMAKE_PREFIX_PATH="$PWD/../deps/build/destdir/usr/local"
|
||||
|
||||
and then open the `Slic3r.xcodeproj` file.
|
||||
This should open up XCode where you can perform build using the GUI or perform other tasks.
|
||||
|
||||
### Note on Mac OS X SDKs
|
||||
|
||||
By default Slic3r builds against whichever SDK is the default on the current system.
|
||||
|
||||
This can be customized. The `CMAKE_OSX_SYSROOT` option sets the path to the SDK directory location
|
||||
and the `CMAKE_OSX_DEPLOYMENT_TARGET` option sets the target OS X system version (eg. `10.14` or similar).
|
||||
Note you can set just one value and the other will be guessed automatically.
|
||||
In case you set both, the two settings need to agree with each other. (Building with a lower deployment target
|
||||
is currently unsupported because some of the dependencies don't support this, most notably wxWidgets.)
|
||||
|
||||
Please note that the `CMAKE_OSX_DEPLOYMENT_TARGET` and `CMAKE_OSX_SYSROOT` options need to be set the same
|
||||
on both the dependencies bundle as well as Slic3r PE itself.
|
||||
|
||||
Official Mac Slic3r builds are currently built against SDK 10.9 to ensure compatibility with older Macs.
|
@ -1,99 +1,98 @@
|
||||
|
||||
### NOTE: This document is currently outdated wrt. the new post-Perl Slic3rPE. A new build process and the description thereof is a work in progress and is comming soon. Please stay tuned.
|
||||
|
||||
--
|
||||
|
||||
|
||||
# Building Slic3r PE on Microsoft Windows
|
||||
|
||||
The currently supported way of building Slic3r PE on Windows is with CMake and MS Visual Studio 2013
|
||||
using our Perl binary distribution (compiled from official Perl sources).
|
||||
The currently supported way of building Slic3r PE on Windows is with CMake and MS Visual Studio 2013.
|
||||
You can use the free [Visual Studio 2013 Community Edition](https://www.visualstudio.com/vs/older-downloads/).
|
||||
CMake installer can be downloaded from [the official website](https://cmake.org/download/).
|
||||
|
||||
Other setups (such as mingw + Strawberry Perl) _may_ work, but we cannot guarantee this will work
|
||||
and cannot provide guidance.
|
||||
Building with newer versions of MSVS (2015, 2017) may work too as reported by some of our users.
|
||||
|
||||
_Note:_ Thanks to [**@supermerill**](https://github.com/supermerill) for testing and inspiration on this guide.
|
||||
|
||||
### Geting the dependencies
|
||||
### Dependencies
|
||||
|
||||
First, download and upnack our Perl + wxWidgets binary distribution:
|
||||
On Windows Slic3r is built against statically built libraries.
|
||||
We provide a prebuilt package of all the needed dependencies.
|
||||
The package comes in a several variants:
|
||||
|
||||
- 32 bit, release mode: [wperl32-5.24.0-2018-03-02.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=wperl32-5.24.0-2018-03-02.7z)
|
||||
- 64 bit, release mode: [wperl64-5.24.0-2018-03-02.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=wperl64-5.24.0-2018-03-02.7z)
|
||||
- 64 bit, release mode + debug symbols: [wperl64d-5.24.0-2018-03-02.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=wperl64d-5.24.0-2018-03-02.7z)
|
||||
- [64 bit, Release mode only](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-64.7z) (41 MB, 578 MB unpacked)
|
||||
- [64 bit, Release and Debug mode](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-64-dev.7z) (88 MB, 1.3 GB unpacked)
|
||||
- [32 bit, Release mode only](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-32.7z) (38 MB, 520 MB unpacked)
|
||||
- [32 bit, Release and Debug mode](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-32-dev.7z) (74 MB, 1.1 GB unpacked)
|
||||
|
||||
It is recommended to unpack this package into `C:\`.
|
||||
When unsure, use the _Release mode only_ variant, the _Release and Debug_ variant is only needed for debugging & developement.
|
||||
|
||||
Apart from wxWidgets and Perl, you will also need additional dependencies:
|
||||
If you're unsure where to unpack the package, unpack it into `C:\local\` (but it can really be anywhere).
|
||||
|
||||
- Boost
|
||||
- Intel TBB
|
||||
- libcurl
|
||||
Alternatively you can also compile the dependencies yourself, see below.
|
||||
|
||||
We have prepared a binary package of the listed libraries:
|
||||
### Building Slic3r PE with Visual Studio
|
||||
|
||||
- 32 bit: [slic3r-destdir-32.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=2%2Fslic3r-destdir-32.7z)
|
||||
- 64 bit: [slic3r-destdir-64.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=2%2Fslic3r-destdir-64.7z)
|
||||
First obtain the Slic3 PE sources via either git or by extracting the source archive.
|
||||
|
||||
It is recommended you unpack this package into `C:\local\` as the environment
|
||||
setup script expects it there.
|
||||
Then you will need to note down the so-called 'prefix path' to the dependencies, this is the location of the dependencies packages + `\usr\local` appended.
|
||||
For example on 64 bits this would be `C:\local\destdir-64\usr\local`. The prefix path will need to be passed to CMake.
|
||||
|
||||
Alternatively you can also compile the additional dependencies yourself.
|
||||
There is a [powershell script](./deps-build/windows/slic3r-makedeps.ps1) which automates this process.
|
||||
When ready, open the relevant Visual Studio command line and `cd` into the directory with Slic3r sources.
|
||||
Use these commands to prepare Visual Studio solution file:
|
||||
|
||||
### Building Slic3r PE
|
||||
|
||||
Once the dependencies are set up in their respective locations,
|
||||
go to the `wperl*` directory extracted earlier and launch the `cmdline.lnk` file
|
||||
which opens a command line prompt with appropriate environment variables set up.
|
||||
|
||||
In this command line, `cd` into the directory with Slic3r sources
|
||||
and use these commands to build the Slic3r from the command line:
|
||||
|
||||
perl Build.PL
|
||||
perl Build.PL --gui
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release
|
||||
nmake
|
||||
cd ..
|
||||
perl slic3r.pl
|
||||
cmake .. -G "Visual Studio 12 Win64" -DCMAKE_PREFIX_PATH="<insert prefix path here>"
|
||||
|
||||
The above commands use `nmake` Makefiles.
|
||||
You may also build Slic3r PE with other build tools:
|
||||
Note that if you're building a 32-bit variant, you will need to change the `"Visual Studio 12 Win64"` to just `"Visual Studio 12"`.
|
||||
|
||||
Conversely, if you're using Visual Studio version other than 2013, the version number will need to be changed accordingly.
|
||||
|
||||
### Building with Visual Studio
|
||||
If `cmake` has finished without errors, go to the build directory and open the `Slic3r.sln` solution file in Visual Studio.
|
||||
Before building, make sure you're building the right project (use one of those starting with `slic3r_app_...`) and that you're building
|
||||
with the right configuration, ie. _Release_ vs. _Debug_. When unsure, choose _Release_.
|
||||
Note that you won't be able to build a _Debug_ variant against a _Release_-only dependencies package.
|
||||
|
||||
To build and debug Slic3r PE with Visual Studio (64 bits), replace the `cmake` command with:
|
||||
#### Installing using the `INSTALL` project
|
||||
|
||||
cmake .. -G "Visual Studio 12 Win64" -DCMAKE_CONFIGURATION_TYPES=RelWithDebInfo
|
||||
Slic3r PE can be run from the Visual Studio or from Visual Studio's build directory (`src\Release` or `src\Debug`),
|
||||
but for longer-term usage you migth want to install somewhere using the `INSTALL` project.
|
||||
By default, this installs into `C:\Program Files\Slic3r`.
|
||||
To customize the install path, use the `-DCMAKE_INSTALL_PREFIX=<path of your choice>` when invoking `cmake`.
|
||||
|
||||
For the 32-bit variant, use:
|
||||
### Building from the command line
|
||||
|
||||
cmake .. -G "Visual Studio 12" -DCMAKE_CONFIGURATION_TYPES=RelWithDebInfo
|
||||
There are several options for building from the command line:
|
||||
|
||||
After `cmake` has finished, go to the build directory and open the `Slic3r.sln` solution file.
|
||||
This should open Visual Studio and load the Slic3r solution containing all the projects.
|
||||
Make sure you use Visual Studio 2013 to open the solution.
|
||||
- [msbuild](https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-reference?view=vs-2017&viewFallbackFrom=vs-2013)
|
||||
- [Ninja](https://ninja-build.org/)
|
||||
- [nmake](https://docs.microsoft.com/en-us/cpp/build/nmake-reference?view=vs-2017)
|
||||
|
||||
You can then use the usual Visual Studio controls to build Slic3r (Hit `F5` to build and run with debugger).
|
||||
If you want to run or debug Slic3r from within Visual Studio, make sure the `XS` project is activated.
|
||||
It should be set as the Startup project by CMake by default, but you might want to check anyway.
|
||||
There are multiple projects in the Slic3r solution, but only the `XS` project is configured with the right
|
||||
commands to run and debug Slic3r.
|
||||
To build with msbuild, use the same CMake command as in previous paragraph and then build using
|
||||
|
||||
The above cmake commands generate Visual Studio project files with the `RelWithDebInfo` configuration only.
|
||||
If you also want to use the `Release` configuration, you can generate Visual Studio projects with:
|
||||
msbuild /P:Configuration=Release ALL_BUILD.vcxproj
|
||||
|
||||
-DCMAKE_CONFIGURATION_TYPES=Release;RelWithDebInfo
|
||||
To build with Ninja or nmake, replace the `-G` option in the CMake call with `-G Ninja` or `-G "NMake Makefiles"` , respectively.
|
||||
Then use either `ninja` or `nmake` to start the build.
|
||||
|
||||
(The `Debug` configuration is not supported as of now.)
|
||||
To install, use `msbuild /P:Configuration=Release INSTALL.vcxproj` , `ninja install` , or `nmake install` .
|
||||
|
||||
### Building with ninja
|
||||
### Building the dependencies package yourself
|
||||
|
||||
To use [Ninja](https://ninja-build.org/), replace the `cmake` and `nmake` commands with:
|
||||
The dependencies package is built using CMake scripts inside the `deps` subdirectory of Slic3r PE sources.
|
||||
(This is intentionally not interconnected with the CMake scripts in the rest of the sources.)
|
||||
|
||||
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release
|
||||
ninja
|
||||
Open the preferred Visual Studio command line (64 or 32 bit variant) and `cd` into the directory with Slic3r sources.
|
||||
Then `cd` into the `deps` directory and use these commands to build:
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "Visual Studio 12 Win64" -DDESTDIR="C:\local\destdir-custom"
|
||||
msbuild ALL_BUILD.vcxproj
|
||||
|
||||
You can also use the Visual Studio GUI or other generators as mentioned above.
|
||||
|
||||
The `DESTDIR` option is the location where the bundle will be installed.
|
||||
This may be customized. If you leave it empty, the `DESTDIR` will be places inside the same `build` directory.
|
||||
|
||||
Note that the build variant that you may choose using Visual Studio (ie. _Release_ or _Debug_ etc.) when building the dependency package is **not relevant**.
|
||||
The dependency build will by default build _both_ the _Release_ and _Debug_ variants regardless of what you choose in Visual Studio.
|
||||
You can disable building of the debug variant by passing the `-DDEP_DEBUG=OFF` option to CMake, this will only produce a _Release_ build.
|
||||
|
||||
Refer to the CMake scripts inside the `deps` directory to see which dependencies are built in what versions and how this is done.
|
||||
|
BIN
resources/icons/gcode.icns
Normal file
BIN
resources/icons/gcode.icns
Normal file
Binary file not shown.
BIN
resources/icons/mode_expert_sq.png
Normal file
BIN
resources/icons/mode_expert_sq.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 164 B |
BIN
resources/icons/mode_middle_sq.png
Normal file
BIN
resources/icons/mode_middle_sq.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 158 B |
BIN
resources/icons/mode_off_sq.png
Normal file
BIN
resources/icons/mode_off_sq.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 159 B |
BIN
resources/icons/mode_simple_sq.png
Normal file
BIN
resources/icons/mode_simple_sq.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 158 B |
BIN
resources/icons/stl.icns
Normal file
BIN
resources/icons/stl.icns
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,32 +1,37 @@
|
||||
xs/src/slic3r/GUI/AboutDialog.cpp
|
||||
xs/src/slic3r/GUI/BedShapeDialog.cpp
|
||||
xs/src/slic3r/GUI/BedShapeDialog.hpp
|
||||
xs/src/slic3r/GUI/BonjourDialog.cpp
|
||||
xs/src/slic3r/GUI/ButtonsDescription.cpp
|
||||
xs/src/slic3r/GUI/ConfigSnapshotDialog.cpp
|
||||
xs/src/slic3r/GUI/ConfigWizard.cpp
|
||||
xs/src/slic3r/GUI/FirmwareDialog.cpp
|
||||
xs/src/slic3r/GUI/GLCanvas3D.cpp
|
||||
xs/src/slic3r/GUI/GUI.cpp
|
||||
xs/src/slic3r/GUI/MsgDialog.cpp
|
||||
xs/src/slic3r/GUI/Tab.cpp
|
||||
xs/src/slic3r/GUI/Tab.hpp
|
||||
xs/src/slic3r/GUI/Field.cpp
|
||||
xs/src/slic3r/GUI/OptionsGroup.cpp
|
||||
xs/src/slic3r/GUI/Preset.cpp
|
||||
xs/src/slic3r/GUI/PresetBundle.cpp
|
||||
xs/src/slic3r/GUI/PresetHints.cpp
|
||||
xs/src/slic3r/GUI/Preferences.cpp
|
||||
xs/src/slic3r/GUI/RammingChart.cpp
|
||||
xs/src/slic3r/GUI/UpdateDialogs.cpp
|
||||
xs/src/slic3r/GUI/WipeTowerDialog.cpp
|
||||
xs/src/slic3r/Utils/OctoPrint.cpp
|
||||
xs/src/slic3r/Utils/PresetUpdater.cpp
|
||||
xs/src/libslic3r/Print.cpp
|
||||
xs/src/libslic3r/PrintConfig.cpp
|
||||
xs/src/libslic3r/GCode/PreviewData.cpp
|
||||
lib/Slic3r/GUI.pm
|
||||
lib/Slic3r/GUI/MainFrame.pm
|
||||
lib/Slic3r/GUI/Plater.pm
|
||||
lib/Slic3r/GUI/Plater/2D.pm
|
||||
lib/Slic3r/GUI/Plater/3DPreview.pm
|
||||
src/slic3r/GUI/AboutDialog.cpp
|
||||
src/slic3r/GUI/BedShapeDialog.cpp
|
||||
src/slic3r/GUI/BedShapeDialog.hpp
|
||||
src/slic3r/GUI/BonjourDialog.cpp
|
||||
src/slic3r/GUI/ButtonsDescription.cpp
|
||||
src/slic3r/GUI/ConfigSnapshotDialog.cpp
|
||||
src/slic3r/GUI/ConfigWizard.cpp
|
||||
src/slic3r/GUI/Field.cpp
|
||||
src/slic3r/GUI/FirmwareDialog.cpp
|
||||
src/slic3r/GUI/GLCanvas3D.cpp
|
||||
src/slic3r/GUI/GLGizmo.cpp
|
||||
src/slic3r/GUI/GUI.cpp
|
||||
src/slic3r/GUI/GUI_App.cpp
|
||||
src/slic3r/GUI/GUI_ObjectList.cpp
|
||||
src/slic3r/GUI/GUI_ObjectManipulation.cpp
|
||||
src/slic3r/GUI/GUI_Preview.cpp
|
||||
src/slic3r/GUI/KBShortcutsDialog.cpp
|
||||
src/slic3r/GUI/MainFrame.cpp
|
||||
src/slic3r/GUI/MsgDialog.cpp
|
||||
src/slic3r/GUI/Plater.cpp
|
||||
src/slic3r/GUI/Preferences.cpp
|
||||
src/slic3r/GUI/Preset.cpp
|
||||
src/slic3r/GUI/PresetBundle.cpp
|
||||
src/slic3r/GUI/PresetHints.cpp
|
||||
src/slic3r/GUI/PrintHostDialogs.cpp
|
||||
src/slic3r/GUI/RammingChart.cpp
|
||||
src/slic3r/GUI/SysInfoDialog.cpp
|
||||
src/slic3r/GUI/Tab.cpp
|
||||
src/slic3r/GUI/Tab.hpp
|
||||
src/slic3r/GUI/UpdateDialogs.cpp
|
||||
src/slic3r/GUI/WipeTowerDialog.cpp
|
||||
src/slic3r/Utils/OctoPrint.cpp
|
||||
src/slic3r/Utils/PresetUpdater.cpp
|
||||
src/slic3r/Utils/FixModelByWin10.cpp
|
||||
src/libslic3r/Print.cpp
|
||||
src/libslic3r/PrintConfig.cpp
|
||||
src/libslic3r/GCode/PreviewData.cpp
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
6894
resources/localization/zh_CN/Slic3rPE_zh_new.po
Normal file
6894
resources/localization/zh_CN/Slic3rPE_zh_new.po
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
BIN
resources/models/sl1_bed.stl
Normal file
BIN
resources/models/sl1_bed.stl
Normal file
Binary file not shown.
@ -33,6 +33,7 @@ if(PNG_FOUND AND NOT RASTERIZER_FORCE_BUILTIN_LIBPNG)
|
||||
else()
|
||||
set(ZLIB_LIBRARY "")
|
||||
message(WARNING "Using builtin libpng. This can cause crashes on some platforms.")
|
||||
set(SKIP_INSTALL_ALL 1) # Prevent png+zlib from creating install targets
|
||||
add_subdirectory(png/zlib)
|
||||
set(ZLIB_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/png/zlib ${CMAKE_CURRENT_BINARY_DIR}/png/zlib)
|
||||
include_directories(${ZLIB_INCLUDE_DIR})
|
||||
@ -49,7 +50,6 @@ if (SLIC3R_GUI)
|
||||
if(WIN32)
|
||||
message(STATUS "WXWIN environment set to: $ENV{WXWIN}")
|
||||
elseif(UNIX)
|
||||
message(STATUS "wx-config path: ${wxWidgets_CONFIG_EXECUTABLE}")
|
||||
set(wxWidgets_USE_UNICODE ON)
|
||||
if(SLIC3R_STATIC)
|
||||
set(wxWidgets_USE_STATIC ON)
|
||||
@ -58,7 +58,23 @@ if (SLIC3R_GUI)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(wxWidgets REQUIRED COMPONENTS base core adv html gl)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
if (SLIC3R_WX_STABLE)
|
||||
find_package(wxWidgets 3.0 REQUIRED COMPONENTS base core adv html gl)
|
||||
else ()
|
||||
find_package(wxWidgets 3.1 QUIET COMPONENTS base core adv html gl)
|
||||
if (NOT wxWidgets_FOUND)
|
||||
message(FATAL_ERROR "\nCould not find wxWidgets 3.1.\nHint: On Linux you can set -DSLIC3R_WX_STABLE=1 to use wxWidgets 3.0")
|
||||
endif ()
|
||||
endif ()
|
||||
else ()
|
||||
find_package(wxWidgets 3.1 REQUIRED COMPONENTS base core adv html gl)
|
||||
endif ()
|
||||
|
||||
if(UNIX)
|
||||
message(STATUS "wx-config path: ${wxWidgets_CONFIG_EXECUTABLE}")
|
||||
endif()
|
||||
|
||||
include(${wxWidgets_USE_FILE})
|
||||
endif()
|
||||
|
||||
@ -188,3 +204,15 @@ else ()
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
|
||||
# Slic3r binary install target
|
||||
if (WIN32)
|
||||
install(TARGETS slic3r RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
if (MSVC)
|
||||
install(TARGETS slic3r_app_gui RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
install(TARGETS slic3r_app_console RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
install(TARGETS slic3r_app_noconsole RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
endif ()
|
||||
else ()
|
||||
install(TARGETS slic3r RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||
endif ()
|
||||
|
@ -53,9 +53,9 @@
|
||||
#endif
|
||||
|
||||
#define EIGEN_DEVICE_FUNC __host__ __device__
|
||||
// We need math_functions.hpp to ensure that that EIGEN_USING_STD_MATH macro
|
||||
// We need cuda_runtime.h to ensure that that EIGEN_USING_STD_MATH macro
|
||||
// works properly on the device side
|
||||
#include <math_functions.hpp>
|
||||
#include <cuda_runtime.h>
|
||||
#else
|
||||
#define EIGEN_DEVICE_FUNC
|
||||
#endif
|
||||
|
@ -305,7 +305,8 @@ template<> struct ldlt_inplace<Lower>
|
||||
if (size <= 1)
|
||||
{
|
||||
transpositions.setIdentity();
|
||||
if (numext::real(mat.coeff(0,0)) > static_cast<RealScalar>(0) ) sign = PositiveSemiDef;
|
||||
if(size==0) sign = ZeroSign;
|
||||
else if (numext::real(mat.coeff(0,0)) > static_cast<RealScalar>(0) ) sign = PositiveSemiDef;
|
||||
else if (numext::real(mat.coeff(0,0)) < static_cast<RealScalar>(0)) sign = NegativeSemiDef;
|
||||
else sign = ZeroSign;
|
||||
return true;
|
||||
|
@ -153,8 +153,6 @@ class Array
|
||||
: Base(std::move(other))
|
||||
{
|
||||
Base::_check_template_params();
|
||||
if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic)
|
||||
Base::_set_noalias(other);
|
||||
}
|
||||
EIGEN_DEVICE_FUNC
|
||||
Array& operator=(Array&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_assignable<Scalar>::value)
|
||||
|
@ -160,7 +160,7 @@ rcond_estimate_helper(typename Decomposition::RealScalar matrix_norm, const Deco
|
||||
{
|
||||
typedef typename Decomposition::RealScalar RealScalar;
|
||||
eigen_assert(dec.rows() == dec.cols());
|
||||
if (dec.rows() == 0) return RealScalar(1);
|
||||
if (dec.rows() == 0) return NumTraits<RealScalar>::infinity();
|
||||
if (matrix_norm == RealScalar(0)) return RealScalar(0);
|
||||
if (dec.rows() == 1) return RealScalar(1);
|
||||
const RealScalar inverse_matrix_norm = rcond_invmatrix_L1_norm_estimate(dec);
|
||||
|
@ -43,6 +43,7 @@ template<typename Derived> class MapBase<Derived, ReadOnlyAccessors>
|
||||
enum {
|
||||
RowsAtCompileTime = internal::traits<Derived>::RowsAtCompileTime,
|
||||
ColsAtCompileTime = internal::traits<Derived>::ColsAtCompileTime,
|
||||
InnerStrideAtCompileTime = internal::traits<Derived>::InnerStrideAtCompileTime,
|
||||
SizeAtCompileTime = Base::SizeAtCompileTime
|
||||
};
|
||||
|
||||
@ -187,8 +188,11 @@ template<typename Derived> class MapBase<Derived, ReadOnlyAccessors>
|
||||
void checkSanity(typename internal::enable_if<(internal::traits<T>::Alignment>0),void*>::type = 0) const
|
||||
{
|
||||
#if EIGEN_MAX_ALIGN_BYTES>0
|
||||
// innerStride() is not set yet when this function is called, so we optimistically assume the lowest plausible value:
|
||||
const Index minInnerStride = InnerStrideAtCompileTime == Dynamic ? 1 : Index(InnerStrideAtCompileTime);
|
||||
EIGEN_ONLY_USED_FOR_DEBUG(minInnerStride);
|
||||
eigen_assert(( ((internal::UIntPtr(m_data) % internal::traits<Derived>::Alignment) == 0)
|
||||
|| (cols() * rows() * innerStride() * sizeof(Scalar)) < internal::traits<Derived>::Alignment ) && "data is not aligned");
|
||||
|| (cols() * rows() * minInnerStride * sizeof(Scalar)) < internal::traits<Derived>::Alignment ) && "data is not aligned");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -616,21 +616,28 @@ template<typename Scalar>
|
||||
struct random_default_impl<Scalar, false, true>
|
||||
{
|
||||
static inline Scalar run(const Scalar& x, const Scalar& y)
|
||||
{
|
||||
typedef typename conditional<NumTraits<Scalar>::IsSigned,std::ptrdiff_t,std::size_t>::type ScalarX;
|
||||
if(y<x)
|
||||
{
|
||||
if (y <= x)
|
||||
return x;
|
||||
// the following difference might overflow on a 32 bits system,
|
||||
// but since y>=x the result converted to an unsigned long is still correct.
|
||||
std::size_t range = ScalarX(y)-ScalarX(x);
|
||||
std::size_t offset = 0;
|
||||
// rejection sampling
|
||||
std::size_t divisor = 1;
|
||||
std::size_t multiplier = 1;
|
||||
if(range<RAND_MAX) divisor = (std::size_t(RAND_MAX)+1)/(range+1);
|
||||
else multiplier = 1 + range/(std::size_t(RAND_MAX)+1);
|
||||
// ScalarU is the unsigned counterpart of Scalar, possibly Scalar itself.
|
||||
typedef typename make_unsigned<Scalar>::type ScalarU;
|
||||
// ScalarX is the widest of ScalarU and unsigned int.
|
||||
// We'll deal only with ScalarX and unsigned int below thus avoiding signed
|
||||
// types and arithmetic and signed overflows (which are undefined behavior).
|
||||
typedef typename conditional<(ScalarU(-1) > unsigned(-1)), ScalarU, unsigned>::type ScalarX;
|
||||
// The following difference doesn't overflow, provided our integer types are two's
|
||||
// complement and have the same number of padding bits in signed and unsigned variants.
|
||||
// This is the case in most modern implementations of C++.
|
||||
ScalarX range = ScalarX(y) - ScalarX(x);
|
||||
ScalarX offset = 0;
|
||||
ScalarX divisor = 1;
|
||||
ScalarX multiplier = 1;
|
||||
const unsigned rand_max = RAND_MAX;
|
||||
if (range <= rand_max) divisor = (rand_max + 1) / (range + 1);
|
||||
else multiplier = 1 + range / (rand_max + 1);
|
||||
// Rejection sampling.
|
||||
do {
|
||||
offset = (std::size_t(std::rand()) * multiplier) / divisor;
|
||||
offset = (unsigned(std::rand()) * multiplier) / divisor;
|
||||
} while (offset > range);
|
||||
return Scalar(ScalarX(x) + offset);
|
||||
}
|
||||
@ -1006,7 +1013,8 @@ inline int log2(int x)
|
||||
|
||||
/** \returns the square root of \a x.
|
||||
*
|
||||
* It is essentially equivalent to \code using std::sqrt; return sqrt(x); \endcode,
|
||||
* It is essentially equivalent to
|
||||
* \code using std::sqrt; return sqrt(x); \endcode
|
||||
* but slightly faster for float/double and some compilers (e.g., gcc), thanks to
|
||||
* specializations when SSE is enabled.
|
||||
*
|
||||
|
@ -274,8 +274,6 @@ class Matrix
|
||||
: Base(std::move(other))
|
||||
{
|
||||
Base::_check_template_params();
|
||||
if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic)
|
||||
Base::_set_noalias(other);
|
||||
}
|
||||
EIGEN_DEVICE_FUNC
|
||||
Matrix& operator=(Matrix&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_assignable<Scalar>::value)
|
||||
|
@ -444,16 +444,24 @@ template<typename Derived> class MatrixBase
|
||||
///////// MatrixFunctions module /////////
|
||||
|
||||
typedef typename internal::stem_function<Scalar>::type StemFunction;
|
||||
const MatrixExponentialReturnValue<Derived> exp() const;
|
||||
#define EIGEN_MATRIX_FUNCTION(ReturnType, Name, Description) \
|
||||
/** \returns an expression of the matrix Description of \c *this. \brief This function requires the <a href="unsupported/group__MatrixFunctions__Module.html"> unsupported MatrixFunctions module</a>. To compute the coefficient-wise Description use ArrayBase::##Name . */ \
|
||||
const ReturnType<Derived> Name() const;
|
||||
#define EIGEN_MATRIX_FUNCTION_1(ReturnType, Name, Description, Argument) \
|
||||
/** \returns an expression of the matrix Description of \c *this. \brief This function requires the <a href="unsupported/group__MatrixFunctions__Module.html"> unsupported MatrixFunctions module</a>. To compute the coefficient-wise Description use ArrayBase::##Name . */ \
|
||||
const ReturnType<Derived> Name(Argument) const;
|
||||
|
||||
EIGEN_MATRIX_FUNCTION(MatrixExponentialReturnValue, exp, exponential)
|
||||
/** \brief Helper function for the <a href="unsupported/group__MatrixFunctions__Module.html"> unsupported MatrixFunctions module</a>.*/
|
||||
const MatrixFunctionReturnValue<Derived> matrixFunction(StemFunction f) const;
|
||||
const MatrixFunctionReturnValue<Derived> cosh() const;
|
||||
const MatrixFunctionReturnValue<Derived> sinh() const;
|
||||
const MatrixFunctionReturnValue<Derived> cos() const;
|
||||
const MatrixFunctionReturnValue<Derived> sin() const;
|
||||
const MatrixSquareRootReturnValue<Derived> sqrt() const;
|
||||
const MatrixLogarithmReturnValue<Derived> log() const;
|
||||
const MatrixPowerReturnValue<Derived> pow(const RealScalar& p) const;
|
||||
const MatrixComplexPowerReturnValue<Derived> pow(const std::complex<RealScalar>& p) const;
|
||||
EIGEN_MATRIX_FUNCTION(MatrixFunctionReturnValue, cosh, hyperbolic cosine)
|
||||
EIGEN_MATRIX_FUNCTION(MatrixFunctionReturnValue, sinh, hyperbolic sine)
|
||||
EIGEN_MATRIX_FUNCTION(MatrixFunctionReturnValue, cos, cosine)
|
||||
EIGEN_MATRIX_FUNCTION(MatrixFunctionReturnValue, sin, sine)
|
||||
EIGEN_MATRIX_FUNCTION(MatrixSquareRootReturnValue, sqrt, square root)
|
||||
EIGEN_MATRIX_FUNCTION(MatrixLogarithmReturnValue, log, logarithm)
|
||||
EIGEN_MATRIX_FUNCTION_1(MatrixPowerReturnValue, pow, power to \c p, const RealScalar& p)
|
||||
EIGEN_MATRIX_FUNCTION_1(MatrixComplexPowerReturnValue, pow, power to \c p, const std::complex<RealScalar>& p)
|
||||
|
||||
protected:
|
||||
EIGEN_DEVICE_FUNC MatrixBase() : Base() {}
|
||||
|
@ -169,6 +169,9 @@ void TriangularViewImpl<MatrixType,Mode,Dense>::solveInPlace(const MatrixBase<Ot
|
||||
OtherDerived& other = _other.const_cast_derived();
|
||||
eigen_assert( derived().cols() == derived().rows() && ((Side==OnTheLeft && derived().cols() == other.rows()) || (Side==OnTheRight && derived().cols() == other.cols())) );
|
||||
eigen_assert((!(Mode & ZeroDiag)) && bool(Mode & (Upper|Lower)));
|
||||
// If solving for a 0x0 matrix, nothing to do, simply return.
|
||||
if (derived().cols() == 0)
|
||||
return;
|
||||
|
||||
enum { copy = (internal::traits<OtherDerived>::Flags & RowMajorBit) && OtherDerived::IsVectorAtCompileTime && OtherDerived::SizeAtCompileTime!=1};
|
||||
typedef typename internal::conditional<copy,
|
||||
|
@ -159,11 +159,12 @@ template<> EIGEN_STRONG_INLINE Packet8i pdiv<Packet8i>(const Packet8i& /*a*/, co
|
||||
|
||||
#ifdef __FMA__
|
||||
template<> EIGEN_STRONG_INLINE Packet8f pmadd(const Packet8f& a, const Packet8f& b, const Packet8f& c) {
|
||||
#if ( EIGEN_COMP_GNUC_STRICT || (EIGEN_COMP_CLANG && (EIGEN_COMP_CLANG<308)) )
|
||||
// clang stupidly generates a vfmadd213ps instruction plus some vmovaps on registers,
|
||||
// and gcc stupidly generates a vfmadd132ps instruction,
|
||||
// so let's enforce it to generate a vfmadd231ps instruction since the most common use case is to accumulate
|
||||
// the result of the product.
|
||||
#if ( (EIGEN_COMP_GNUC_STRICT && EIGEN_COMP_GNUC<80) || (EIGEN_COMP_CLANG) )
|
||||
// Clang stupidly generates a vfmadd213ps instruction plus some vmovaps on registers,
|
||||
// and even register spilling with clang>=6.0 (bug 1637).
|
||||
// Gcc stupidly generates a vfmadd132ps instruction.
|
||||
// So let's enforce it to generate a vfmadd231ps instruction since the most common use
|
||||
// case is to accumulate the result of the product.
|
||||
Packet8f res = c;
|
||||
__asm__("vfmadd231ps %[a], %[b], %[c]" : [c] "+x" (res) : [a] "x" (a), [b] "x" (b));
|
||||
return res;
|
||||
@ -172,7 +173,7 @@ template<> EIGEN_STRONG_INLINE Packet8f pmadd(const Packet8f& a, const Packet8f&
|
||||
#endif
|
||||
}
|
||||
template<> EIGEN_STRONG_INLINE Packet4d pmadd(const Packet4d& a, const Packet4d& b, const Packet4d& c) {
|
||||
#if ( EIGEN_COMP_GNUC_STRICT || (EIGEN_COMP_CLANG && (EIGEN_COMP_CLANG<308)) )
|
||||
#if ( (EIGEN_COMP_GNUC_STRICT && EIGEN_COMP_GNUC<80) || (EIGEN_COMP_CLANG) )
|
||||
// see above
|
||||
Packet4d res = c;
|
||||
__asm__("vfmadd231pd %[a], %[b], %[c]" : [c] "+x" (res) : [a] "x" (a), [b] "x" (b));
|
||||
|
@ -648,13 +648,13 @@ template<> EIGEN_STRONG_INLINE Packet8d preverse(const Packet8d& a)
|
||||
template<> EIGEN_STRONG_INLINE Packet16f pabs(const Packet16f& a)
|
||||
{
|
||||
// _mm512_abs_ps intrinsic not found, so hack around it
|
||||
return (__m512)_mm512_and_si512((__m512i)a, _mm512_set1_epi32(0x7fffffff));
|
||||
return _mm512_castsi512_ps(_mm512_and_si512(_mm512_castps_si512(a), _mm512_set1_epi32(0x7fffffff)));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8d pabs(const Packet8d& a) {
|
||||
// _mm512_abs_ps intrinsic not found, so hack around it
|
||||
return (__m512d)_mm512_and_si512((__m512i)a,
|
||||
_mm512_set1_epi64(0x7fffffffffffffff));
|
||||
return _mm512_castsi512_pd(_mm512_and_si512(_mm512_castpd_si512(a),
|
||||
_mm512_set1_epi64(0x7fffffffffffffff)));
|
||||
}
|
||||
|
||||
#ifdef EIGEN_VECTORIZE_AVX512DQ
|
||||
|
@ -29,7 +29,7 @@
|
||||
// type Eigen::half (inheriting from CUDA's __half struct) with
|
||||
// operator overloads such that it behaves basically as an arithmetic
|
||||
// type. It will be quite slow on CPUs (so it is recommended to stay
|
||||
// in fp32 for CPUs, except for simple parameter conversions, I/O
|
||||
// in float32_bits for CPUs, except for simple parameter conversions, I/O
|
||||
// to disk and the likes), but fast on GPUs.
|
||||
|
||||
|
||||
@ -50,38 +50,45 @@ struct half;
|
||||
namespace half_impl {
|
||||
|
||||
#if !defined(EIGEN_HAS_CUDA_FP16)
|
||||
|
||||
// Make our own __half definition that is similar to CUDA's.
|
||||
struct __half {
|
||||
EIGEN_DEVICE_FUNC __half() {}
|
||||
explicit EIGEN_DEVICE_FUNC __half(unsigned short raw) : x(raw) {}
|
||||
// Make our own __half_raw definition that is similar to CUDA's.
|
||||
struct __half_raw {
|
||||
EIGEN_DEVICE_FUNC __half_raw() : x(0) {}
|
||||
explicit EIGEN_DEVICE_FUNC __half_raw(unsigned short raw) : x(raw) {}
|
||||
unsigned short x;
|
||||
};
|
||||
|
||||
#elif defined(EIGEN_CUDACC_VER) && EIGEN_CUDACC_VER < 90000
|
||||
// In CUDA < 9.0, __half is the equivalent of CUDA 9's __half_raw
|
||||
typedef __half __half_raw;
|
||||
#endif
|
||||
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC __half raw_uint16_to_half(unsigned short x);
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC __half float_to_half_rtne(float ff);
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC float half_to_float(__half h);
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC __half_raw raw_uint16_to_half(unsigned short x);
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC __half_raw float_to_half_rtne(float ff);
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC float half_to_float(__half_raw h);
|
||||
|
||||
struct half_base : public __half {
|
||||
struct half_base : public __half_raw {
|
||||
EIGEN_DEVICE_FUNC half_base() {}
|
||||
EIGEN_DEVICE_FUNC half_base(const half_base& h) : __half(h) {}
|
||||
EIGEN_DEVICE_FUNC half_base(const __half& h) : __half(h) {}
|
||||
EIGEN_DEVICE_FUNC half_base(const half_base& h) : __half_raw(h) {}
|
||||
EIGEN_DEVICE_FUNC half_base(const __half_raw& h) : __half_raw(h) {}
|
||||
#if defined(EIGEN_HAS_CUDA_FP16) && defined(EIGEN_CUDACC_VER) && EIGEN_CUDACC_VER >= 90000
|
||||
EIGEN_DEVICE_FUNC half_base(const __half& h) : __half_raw(*(__half_raw*)&h) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace half_impl
|
||||
|
||||
// Class definition.
|
||||
struct half : public half_impl::half_base {
|
||||
#if !defined(EIGEN_HAS_CUDA_FP16)
|
||||
typedef half_impl::__half __half;
|
||||
#if !defined(EIGEN_HAS_CUDA_FP16) || (defined(EIGEN_CUDACC_VER) && EIGEN_CUDACC_VER < 90000)
|
||||
typedef half_impl::__half_raw __half_raw;
|
||||
#endif
|
||||
|
||||
EIGEN_DEVICE_FUNC half() {}
|
||||
|
||||
EIGEN_DEVICE_FUNC half(const __half& h) : half_impl::half_base(h) {}
|
||||
EIGEN_DEVICE_FUNC half(const __half_raw& h) : half_impl::half_base(h) {}
|
||||
EIGEN_DEVICE_FUNC half(const half& h) : half_impl::half_base(h) {}
|
||||
#if defined(EIGEN_HAS_CUDA_FP16) && defined(EIGEN_CUDACC_VER) && EIGEN_CUDACC_VER >= 90000
|
||||
EIGEN_DEVICE_FUNC half(const __half& h) : half_impl::half_base(h) {}
|
||||
#endif
|
||||
|
||||
explicit EIGEN_DEVICE_FUNC half(bool b)
|
||||
: half_impl::half_base(half_impl::raw_uint16_to_half(b ? 0x3c00 : 0)) {}
|
||||
@ -138,12 +145,66 @@ struct half : public half_impl::half_base {
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct numeric_limits<Eigen::half> {
|
||||
static const bool is_specialized = true;
|
||||
static const bool is_signed = true;
|
||||
static const bool is_integer = false;
|
||||
static const bool is_exact = false;
|
||||
static const bool has_infinity = true;
|
||||
static const bool has_quiet_NaN = true;
|
||||
static const bool has_signaling_NaN = true;
|
||||
static const float_denorm_style has_denorm = denorm_present;
|
||||
static const bool has_denorm_loss = false;
|
||||
static const std::float_round_style round_style = std::round_to_nearest;
|
||||
static const bool is_iec559 = false;
|
||||
static const bool is_bounded = false;
|
||||
static const bool is_modulo = false;
|
||||
static const int digits = 11;
|
||||
static const int digits10 = 3; // according to http://half.sourceforge.net/structstd_1_1numeric__limits_3_01half__float_1_1half_01_4.html
|
||||
static const int max_digits10 = 5; // according to http://half.sourceforge.net/structstd_1_1numeric__limits_3_01half__float_1_1half_01_4.html
|
||||
static const int radix = 2;
|
||||
static const int min_exponent = -13;
|
||||
static const int min_exponent10 = -4;
|
||||
static const int max_exponent = 16;
|
||||
static const int max_exponent10 = 4;
|
||||
static const bool traps = true;
|
||||
static const bool tinyness_before = false;
|
||||
|
||||
static Eigen::half (min)() { return Eigen::half_impl::raw_uint16_to_half(0x400); }
|
||||
static Eigen::half lowest() { return Eigen::half_impl::raw_uint16_to_half(0xfbff); }
|
||||
static Eigen::half (max)() { return Eigen::half_impl::raw_uint16_to_half(0x7bff); }
|
||||
static Eigen::half epsilon() { return Eigen::half_impl::raw_uint16_to_half(0x0800); }
|
||||
static Eigen::half round_error() { return Eigen::half(0.5); }
|
||||
static Eigen::half infinity() { return Eigen::half_impl::raw_uint16_to_half(0x7c00); }
|
||||
static Eigen::half quiet_NaN() { return Eigen::half_impl::raw_uint16_to_half(0x7e00); }
|
||||
static Eigen::half signaling_NaN() { return Eigen::half_impl::raw_uint16_to_half(0x7e00); }
|
||||
static Eigen::half denorm_min() { return Eigen::half_impl::raw_uint16_to_half(0x1); }
|
||||
};
|
||||
|
||||
// If std::numeric_limits<T> is specialized, should also specialize
|
||||
// std::numeric_limits<const T>, std::numeric_limits<volatile T>, and
|
||||
// std::numeric_limits<const volatile T>
|
||||
// https://stackoverflow.com/a/16519653/
|
||||
template<>
|
||||
struct numeric_limits<const Eigen::half> : numeric_limits<Eigen::half> {};
|
||||
template<>
|
||||
struct numeric_limits<volatile Eigen::half> : numeric_limits<Eigen::half> {};
|
||||
template<>
|
||||
struct numeric_limits<const volatile Eigen::half> : numeric_limits<Eigen::half> {};
|
||||
} // end namespace std
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace half_impl {
|
||||
|
||||
#if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
|
||||
#if defined(EIGEN_HAS_CUDA_FP16) && defined(EIGEN_CUDA_ARCH) && EIGEN_CUDA_ARCH >= 530
|
||||
|
||||
// Intrinsics for native fp16 support. Note that on current hardware,
|
||||
// these are no faster than fp32 arithmetic (you need to use the half2
|
||||
// these are no faster than float32_bits arithmetic (you need to use the half2
|
||||
// versions to get the ALU speed increased), but you do save the
|
||||
// conversion steps back and forth.
|
||||
|
||||
@ -202,7 +263,7 @@ EIGEN_STRONG_INLINE __device__ bool operator >= (const half& a, const half& b) {
|
||||
#else // Emulate support for half floats
|
||||
|
||||
// Definitions for CPUs and older CUDA, mostly working through conversion
|
||||
// to/from fp32.
|
||||
// to/from float32_bits.
|
||||
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half operator + (const half& a, const half& b) {
|
||||
return half(float(a) + float(b));
|
||||
@ -269,34 +330,35 @@ EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half operator / (const half& a, Index b) {
|
||||
// these in hardware. If we need more performance on older/other CPUs, they are
|
||||
// also possible to vectorize directly.
|
||||
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC __half raw_uint16_to_half(unsigned short x) {
|
||||
__half h;
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC __half_raw raw_uint16_to_half(unsigned short x) {
|
||||
__half_raw h;
|
||||
h.x = x;
|
||||
return h;
|
||||
}
|
||||
|
||||
union FP32 {
|
||||
union float32_bits {
|
||||
unsigned int u;
|
||||
float f;
|
||||
};
|
||||
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC __half float_to_half_rtne(float ff) {
|
||||
#if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 300
|
||||
return __float2half(ff);
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC __half_raw float_to_half_rtne(float ff) {
|
||||
#if defined(EIGEN_HAS_CUDA_FP16) && defined(EIGEN_CUDA_ARCH) && EIGEN_CUDA_ARCH >= 300
|
||||
__half tmp_ff = __float2half(ff);
|
||||
return *(__half_raw*)&tmp_ff;
|
||||
|
||||
#elif defined(EIGEN_HAS_FP16_C)
|
||||
__half h;
|
||||
__half_raw h;
|
||||
h.x = _cvtss_sh(ff, 0);
|
||||
return h;
|
||||
|
||||
#else
|
||||
FP32 f; f.f = ff;
|
||||
float32_bits f; f.f = ff;
|
||||
|
||||
const FP32 f32infty = { 255 << 23 };
|
||||
const FP32 f16max = { (127 + 16) << 23 };
|
||||
const FP32 denorm_magic = { ((127 - 15) + (23 - 10) + 1) << 23 };
|
||||
const float32_bits f32infty = { 255 << 23 };
|
||||
const float32_bits f16max = { (127 + 16) << 23 };
|
||||
const float32_bits denorm_magic = { ((127 - 15) + (23 - 10) + 1) << 23 };
|
||||
unsigned int sign_mask = 0x80000000u;
|
||||
__half o;
|
||||
__half_raw o;
|
||||
o.x = static_cast<unsigned short>(0x0u);
|
||||
|
||||
unsigned int sign = f.u & sign_mask;
|
||||
@ -335,17 +397,17 @@ EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC __half float_to_half_rtne(float ff) {
|
||||
#endif
|
||||
}
|
||||
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC float half_to_float(__half h) {
|
||||
#if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 300
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC float half_to_float(__half_raw h) {
|
||||
#if defined(EIGEN_HAS_CUDA_FP16) && defined(EIGEN_CUDA_ARCH) && EIGEN_CUDA_ARCH >= 300
|
||||
return __half2float(h);
|
||||
|
||||
#elif defined(EIGEN_HAS_FP16_C)
|
||||
return _cvtsh_ss(h.x);
|
||||
|
||||
#else
|
||||
const FP32 magic = { 113 << 23 };
|
||||
const float32_bits magic = { 113 << 23 };
|
||||
const unsigned int shifted_exp = 0x7c00 << 13; // exponent mask after shift
|
||||
FP32 o;
|
||||
float32_bits o;
|
||||
|
||||
o.u = (h.x & 0x7fff) << 13; // exponent/mantissa bits
|
||||
unsigned int exp = shifted_exp & o.u; // just the exponent
|
||||
@ -370,7 +432,7 @@ EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool (isinf)(const half& a) {
|
||||
return (a.x & 0x7fff) == 0x7c00;
|
||||
}
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool (isnan)(const half& a) {
|
||||
#if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
|
||||
#if defined(EIGEN_HAS_CUDA_FP16) && defined(EIGEN_CUDA_ARCH) && EIGEN_CUDA_ARCH >= 530
|
||||
return __hisnan(a);
|
||||
#else
|
||||
return (a.x & 0x7fff) > 0x7c00;
|
||||
@ -443,7 +505,7 @@ EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half ceil(const half& a) {
|
||||
}
|
||||
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half (min)(const half& a, const half& b) {
|
||||
#if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
|
||||
#if defined(EIGEN_HAS_CUDA_FP16) && defined(EIGEN_CUDA_ARCH) && EIGEN_CUDA_ARCH >= 530
|
||||
return __hlt(b, a) ? b : a;
|
||||
#else
|
||||
const float f1 = static_cast<float>(a);
|
||||
@ -452,7 +514,7 @@ EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half (min)(const half& a, const half& b) {
|
||||
#endif
|
||||
}
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half (max)(const half& a, const half& b) {
|
||||
#if defined(EIGEN_HAS_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
|
||||
#if defined(EIGEN_HAS_CUDA_FP16) && defined(EIGEN_CUDA_ARCH) && EIGEN_CUDA_ARCH >= 530
|
||||
return __hlt(a, b) ? b : a;
|
||||
#else
|
||||
const float f1 = static_cast<float>(a);
|
||||
@ -490,49 +552,6 @@ template<> struct is_arithmetic<half> { enum { value = true }; };
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct numeric_limits<Eigen::half> {
|
||||
static const bool is_specialized = true;
|
||||
static const bool is_signed = true;
|
||||
static const bool is_integer = false;
|
||||
static const bool is_exact = false;
|
||||
static const bool has_infinity = true;
|
||||
static const bool has_quiet_NaN = true;
|
||||
static const bool has_signaling_NaN = true;
|
||||
static const float_denorm_style has_denorm = denorm_present;
|
||||
static const bool has_denorm_loss = false;
|
||||
static const std::float_round_style round_style = std::round_to_nearest;
|
||||
static const bool is_iec559 = false;
|
||||
static const bool is_bounded = false;
|
||||
static const bool is_modulo = false;
|
||||
static const int digits = 11;
|
||||
static const int digits10 = 3; // according to http://half.sourceforge.net/structstd_1_1numeric__limits_3_01half__float_1_1half_01_4.html
|
||||
static const int max_digits10 = 5; // according to http://half.sourceforge.net/structstd_1_1numeric__limits_3_01half__float_1_1half_01_4.html
|
||||
static const int radix = 2;
|
||||
static const int min_exponent = -13;
|
||||
static const int min_exponent10 = -4;
|
||||
static const int max_exponent = 16;
|
||||
static const int max_exponent10 = 4;
|
||||
static const bool traps = true;
|
||||
static const bool tinyness_before = false;
|
||||
|
||||
static Eigen::half (min)() { return Eigen::half_impl::raw_uint16_to_half(0x400); }
|
||||
static Eigen::half lowest() { return Eigen::half_impl::raw_uint16_to_half(0xfbff); }
|
||||
static Eigen::half (max)() { return Eigen::half_impl::raw_uint16_to_half(0x7bff); }
|
||||
static Eigen::half epsilon() { return Eigen::half_impl::raw_uint16_to_half(0x0800); }
|
||||
static Eigen::half round_error() { return Eigen::half(0.5); }
|
||||
static Eigen::half infinity() { return Eigen::half_impl::raw_uint16_to_half(0x7c00); }
|
||||
static Eigen::half quiet_NaN() { return Eigen::half_impl::raw_uint16_to_half(0x7e00); }
|
||||
static Eigen::half signaling_NaN() { return Eigen::half_impl::raw_uint16_to_half(0x7e00); }
|
||||
static Eigen::half denorm_min() { return Eigen::half_impl::raw_uint16_to_half(0x1); }
|
||||
};
|
||||
}
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
template<> struct NumTraits<Eigen::half>
|
||||
: GenericNumTraits<Eigen::half>
|
||||
{
|
||||
@ -607,14 +626,18 @@ struct hash<Eigen::half> {
|
||||
|
||||
|
||||
// Add the missing shfl_xor intrinsic
|
||||
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 300
|
||||
#if defined(EIGEN_CUDA_ARCH) && EIGEN_CUDA_ARCH >= 300
|
||||
__device__ EIGEN_STRONG_INLINE Eigen::half __shfl_xor(Eigen::half var, int laneMask, int width=warpSize) {
|
||||
#if EIGEN_CUDACC_VER < 90000
|
||||
return static_cast<Eigen::half>(__shfl_xor(static_cast<float>(var), laneMask, width));
|
||||
#else
|
||||
return static_cast<Eigen::half>(__shfl_xor_sync(0xFFFFFFFF, static_cast<float>(var), laneMask, width));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// ldg() has an overload for __half, but we also need one for Eigen::half.
|
||||
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 350
|
||||
// ldg() has an overload for __half_raw, but we also need one for Eigen::half.
|
||||
#if defined(EIGEN_CUDA_ARCH) && EIGEN_CUDA_ARCH >= 350
|
||||
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Eigen::half __ldg(const Eigen::half* ptr) {
|
||||
return Eigen::half_impl::raw_uint16_to_half(
|
||||
__ldg(reinterpret_cast<const unsigned short*>(ptr)));
|
||||
@ -622,7 +645,7 @@ EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Eigen::half __ldg(const Eigen::half* ptr)
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__CUDA_ARCH__)
|
||||
#if defined(EIGEN_CUDA_ARCH)
|
||||
namespace Eigen {
|
||||
namespace numext {
|
||||
|
||||
|
@ -99,7 +99,8 @@ template<> __device__ EIGEN_STRONG_INLINE Eigen::half pfirst<half2>(const half2&
|
||||
|
||||
template<> __device__ EIGEN_STRONG_INLINE half2 pabs<half2>(const half2& a) {
|
||||
half2 result;
|
||||
result.x = a.x & 0x7FFF7FFF;
|
||||
unsigned temp = *(reinterpret_cast<const unsigned*>(&(a)));
|
||||
*(reinterpret_cast<unsigned*>(&(result))) = temp & 0x7FFF7FFF;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ namespace internal {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (defined EIGEN_VECTORIZE_AVX) && (EIGEN_COMP_GNUC_STRICT || EIGEN_COMP_MINGW) && (__GXX_ABI_VERSION < 1004)
|
||||
#if ((defined EIGEN_VECTORIZE_AVX) && (EIGEN_COMP_GNUC_STRICT || EIGEN_COMP_MINGW) && (__GXX_ABI_VERSION < 1004)) || EIGEN_OS_QNX
|
||||
// With GCC's default ABI version, a __m128 or __m256 are the same types and therefore we cannot
|
||||
// have overloads for both types without linking error.
|
||||
// One solution is to increase ABI version using -fabi-version=4 (or greater).
|
||||
|
@ -1197,10 +1197,16 @@ void gebp_kernel<LhsScalar,RhsScalar,Index,DataMapper,mr,nr,ConjugateLhs,Conjuga
|
||||
EIGEN_ASM_COMMENT("begin gebp micro kernel 2pX4");
|
||||
RhsPacket B_0, B1, B2, B3, T0;
|
||||
|
||||
#define EIGEN_GEBGP_ONESTEP(K) \
|
||||
// NOTE: the begin/end asm comments below work around bug 935!
|
||||
// but they are not enough for gcc>=6 without FMA (bug 1637)
|
||||
#if EIGEN_GNUC_AT_LEAST(6,0) && defined(EIGEN_VECTORIZE_SSE)
|
||||
#define EIGEN_GEBP_2PX4_SPILLING_WORKAROUND __asm__ ("" : [a0] "+x,m" (A0),[a1] "+x,m" (A1));
|
||||
#else
|
||||
#define EIGEN_GEBP_2PX4_SPILLING_WORKAROUND
|
||||
#endif
|
||||
#define EIGEN_GEBGP_ONESTEP(K) \
|
||||
do { \
|
||||
EIGEN_ASM_COMMENT("begin step of gebp micro kernel 2pX4"); \
|
||||
EIGEN_ASM_COMMENT("Note: these asm comments work around bug 935!"); \
|
||||
traits.loadLhs(&blA[(0+2*K)*LhsProgress], A0); \
|
||||
traits.loadLhs(&blA[(1+2*K)*LhsProgress], A1); \
|
||||
traits.broadcastRhs(&blB[(0+4*K)*RhsProgress], B_0, B1, B2, B3); \
|
||||
@ -1212,6 +1218,7 @@ void gebp_kernel<LhsScalar,RhsScalar,Index,DataMapper,mr,nr,ConjugateLhs,Conjuga
|
||||
traits.madd(A1, B2, C6, B2); \
|
||||
traits.madd(A0, B3, C3, T0); \
|
||||
traits.madd(A1, B3, C7, B3); \
|
||||
EIGEN_GEBP_2PX4_SPILLING_WORKAROUND \
|
||||
EIGEN_ASM_COMMENT("end step of gebp micro kernel 2pX4"); \
|
||||
} while(false)
|
||||
|
||||
@ -1526,10 +1533,10 @@ void gebp_kernel<LhsScalar,RhsScalar,Index,DataMapper,mr,nr,ConjugateLhs,Conjuga
|
||||
// The following piece of code wont work for 512 bit registers
|
||||
// Moreover, if LhsProgress==8 it assumes that there is a half packet of the same size
|
||||
// as nr (which is currently 4) for the return type.
|
||||
typedef typename unpacket_traits<SResPacket>::half SResPacketHalf;
|
||||
const int SResPacketHalfSize = unpacket_traits<typename unpacket_traits<SResPacket>::half>::size;
|
||||
if ((SwappedTraits::LhsProgress % 4) == 0 &&
|
||||
(SwappedTraits::LhsProgress <= 8) &&
|
||||
(SwappedTraits::LhsProgress!=8 || unpacket_traits<SResPacketHalf>::size==nr))
|
||||
(SwappedTraits::LhsProgress!=8 || SResPacketHalfSize==nr))
|
||||
{
|
||||
SAccPacket C0, C1, C2, C3;
|
||||
straits.initAcc(C0);
|
||||
|
@ -52,7 +52,7 @@ struct general_matrix_matrix_triangular_product<Index,Scalar,LhsStorageOrder,Con
|
||||
static EIGEN_STRONG_INLINE void run(Index size, Index depth,const Scalar* lhs, Index lhsStride, \
|
||||
const Scalar* rhs, Index rhsStride, Scalar* res, Index resStride, Scalar alpha, level3_blocking<Scalar, Scalar>& blocking) \
|
||||
{ \
|
||||
if ( lhs==rhs && ((UpLo&(Lower|Upper)==UpLo)) ) { \
|
||||
if ( lhs==rhs && ((UpLo&(Lower|Upper))==UpLo) ) { \
|
||||
general_matrix_matrix_rankupdate<Index,Scalar,LhsStorageOrder,ConjugateLhs,ColMajor,UpLo> \
|
||||
::run(size,depth,lhs,lhsStride,rhs,rhsStride,res,resStride,alpha,blocking); \
|
||||
} else { \
|
||||
|
@ -43,12 +43,20 @@
|
||||
#endif
|
||||
#pragma clang diagnostic ignored "-Wconstant-logical-operand"
|
||||
|
||||
#elif defined __GNUC__ && __GNUC__>=6
|
||||
#elif defined __GNUC__
|
||||
|
||||
#ifndef EIGEN_PERMANENTLY_DISABLE_STUPID_WARNINGS
|
||||
#if (!defined(EIGEN_PERMANENTLY_DISABLE_STUPID_WARNINGS)) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||
#pragma GCC diagnostic push
|
||||
#endif
|
||||
#pragma GCC diagnostic ignored "-Wignored-attributes"
|
||||
// g++ warns about local variables shadowing member functions, which is too strict
|
||||
#pragma GCC diagnostic ignored "-Wshadow"
|
||||
#if __GNUC__ == 4 && __GNUC_MINOR__ < 8
|
||||
// Until g++-4.7 there are warnings when comparing unsigned int vs 0, even in templated functions:
|
||||
#pragma GCC diagnostic ignored "-Wtype-limits"
|
||||
#endif
|
||||
#if __GNUC__>=6
|
||||
#pragma GCC diagnostic ignored "-Wignored-attributes"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#define EIGEN_WORLD_VERSION 3
|
||||
#define EIGEN_MAJOR_VERSION 3
|
||||
#define EIGEN_MINOR_VERSION 5
|
||||
#define EIGEN_MINOR_VERSION 7
|
||||
|
||||
#define EIGEN_VERSION_AT_LEAST(x,y,z) (EIGEN_WORLD_VERSION>x || (EIGEN_WORLD_VERSION>=x && \
|
||||
(EIGEN_MAJOR_VERSION>y || (EIGEN_MAJOR_VERSION>=y && \
|
||||
|
@ -747,7 +747,15 @@ public:
|
||||
pointer allocate(size_type num, const void* /*hint*/ = 0)
|
||||
{
|
||||
internal::check_size_for_overflow<T>(num);
|
||||
return static_cast<pointer>( internal::aligned_malloc(num * sizeof(T)) );
|
||||
size_type size = num * sizeof(T);
|
||||
#if EIGEN_COMP_GNUC_STRICT && EIGEN_GNUC_AT_LEAST(7,0)
|
||||
// workaround gcc bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87544
|
||||
// It triggered eigen/Eigen/src/Core/util/Memory.h:189:12: warning: argument 1 value '18446744073709551612' exceeds maximum object size 9223372036854775807
|
||||
if(size>=std::size_t((std::numeric_limits<std::ptrdiff_t>::max)()))
|
||||
return 0;
|
||||
else
|
||||
#endif
|
||||
return static_cast<pointer>( internal::aligned_malloc(size) );
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type /*num*/)
|
||||
|
@ -109,6 +109,28 @@ template<> struct is_integral<unsigned int> { enum { value = true }; };
|
||||
template<> struct is_integral<signed long> { enum { value = true }; };
|
||||
template<> struct is_integral<unsigned long> { enum { value = true }; };
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
using std::make_unsigned;
|
||||
#else
|
||||
// TODO: Possibly improve this implementation of make_unsigned.
|
||||
// It is currently used only by
|
||||
// template<typename Scalar> struct random_default_impl<Scalar, false, true>.
|
||||
template<typename> struct make_unsigned;
|
||||
template<> struct make_unsigned<char> { typedef unsigned char type; };
|
||||
template<> struct make_unsigned<signed char> { typedef unsigned char type; };
|
||||
template<> struct make_unsigned<unsigned char> { typedef unsigned char type; };
|
||||
template<> struct make_unsigned<signed short> { typedef unsigned short type; };
|
||||
template<> struct make_unsigned<unsigned short> { typedef unsigned short type; };
|
||||
template<> struct make_unsigned<signed int> { typedef unsigned int type; };
|
||||
template<> struct make_unsigned<unsigned int> { typedef unsigned int type; };
|
||||
template<> struct make_unsigned<signed long> { typedef unsigned long type; };
|
||||
template<> struct make_unsigned<unsigned long> { typedef unsigned long type; };
|
||||
#if EIGEN_COMP_MSVC
|
||||
template<> struct make_unsigned<signed __int64> { typedef unsigned __int64 type; };
|
||||
template<> struct make_unsigned<unsigned __int64> { typedef unsigned __int64 type; };
|
||||
#endif
|
||||
#endif
|
||||
|
||||
template <typename T> struct add_const { typedef const T type; };
|
||||
template <typename T> struct add_const<T&> { typedef T& type; };
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#pragma warning pop
|
||||
#elif defined __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#elif defined __GNUC__ && __GNUC__>=6
|
||||
#elif defined __GNUC__ && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
|
@ -66,7 +66,6 @@ template<typename Derived>
|
||||
inline typename MatrixBase<Derived>::EigenvaluesReturnType
|
||||
MatrixBase<Derived>::eigenvalues() const
|
||||
{
|
||||
typedef typename internal::traits<Derived>::Scalar Scalar;
|
||||
return internal::eigenvalues_selector<Derived, NumTraits<Scalar>::IsComplex>::run(derived());
|
||||
}
|
||||
|
||||
@ -88,7 +87,6 @@ template<typename MatrixType, unsigned int UpLo>
|
||||
inline typename SelfAdjointView<MatrixType, UpLo>::EigenvaluesReturnType
|
||||
SelfAdjointView<MatrixType, UpLo>::eigenvalues() const
|
||||
{
|
||||
typedef typename SelfAdjointView<MatrixType, UpLo>::PlainObject PlainObject;
|
||||
PlainObject thisAsMatrix(*this);
|
||||
return SelfAdjointEigenSolver<PlainObject>(thisAsMatrix, false).eigenvalues();
|
||||
}
|
||||
|
@ -50,7 +50,8 @@ void conjugate_gradient(const MatrixType& mat, const Rhs& rhs, Dest& x,
|
||||
tol_error = 0;
|
||||
return;
|
||||
}
|
||||
RealScalar threshold = tol*tol*rhsNorm2;
|
||||
const RealScalar considerAsZero = (std::numeric_limits<RealScalar>::min)();
|
||||
RealScalar threshold = numext::maxi(tol*tol*rhsNorm2,considerAsZero);
|
||||
RealScalar residualNorm2 = residual.squaredNorm();
|
||||
if (residualNorm2 < threshold)
|
||||
{
|
||||
@ -58,7 +59,7 @@ void conjugate_gradient(const MatrixType& mat, const Rhs& rhs, Dest& x,
|
||||
tol_error = sqrt(residualNorm2 / rhsNorm2);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
VectorType p(n);
|
||||
p = precond.solve(residual); // initial search direction
|
||||
|
||||
|
@ -65,11 +65,11 @@ template<typename Scalar> class JacobiRotation
|
||||
bool makeJacobi(const MatrixBase<Derived>&, Index p, Index q);
|
||||
bool makeJacobi(const RealScalar& x, const Scalar& y, const RealScalar& z);
|
||||
|
||||
void makeGivens(const Scalar& p, const Scalar& q, Scalar* z=0);
|
||||
void makeGivens(const Scalar& p, const Scalar& q, Scalar* r=0);
|
||||
|
||||
protected:
|
||||
void makeGivens(const Scalar& p, const Scalar& q, Scalar* z, internal::true_type);
|
||||
void makeGivens(const Scalar& p, const Scalar& q, Scalar* z, internal::false_type);
|
||||
void makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::true_type);
|
||||
void makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::false_type);
|
||||
|
||||
Scalar m_c, m_s;
|
||||
};
|
||||
@ -84,7 +84,6 @@ bool JacobiRotation<Scalar>::makeJacobi(const RealScalar& x, const Scalar& y, co
|
||||
{
|
||||
using std::sqrt;
|
||||
using std::abs;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
RealScalar deno = RealScalar(2)*abs(y);
|
||||
if(deno < (std::numeric_limits<RealScalar>::min)())
|
||||
{
|
||||
@ -133,7 +132,7 @@ inline bool JacobiRotation<Scalar>::makeJacobi(const MatrixBase<Derived>& m, Ind
|
||||
* \f$ V = \left ( \begin{array}{c} p \\ q \end{array} \right )\f$ yields:
|
||||
* \f$ G^* V = \left ( \begin{array}{c} r \\ 0 \end{array} \right )\f$.
|
||||
*
|
||||
* The value of \a z is returned if \a z is not null (the default is null).
|
||||
* The value of \a r is returned if \a r is not null (the default is null).
|
||||
* Also note that G is built such that the cosine is always real.
|
||||
*
|
||||
* Example: \include Jacobi_makeGivens.cpp
|
||||
@ -146,9 +145,9 @@ inline bool JacobiRotation<Scalar>::makeJacobi(const MatrixBase<Derived>& m, Ind
|
||||
* \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight()
|
||||
*/
|
||||
template<typename Scalar>
|
||||
void JacobiRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* z)
|
||||
void JacobiRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* r)
|
||||
{
|
||||
makeGivens(p, q, z, typename internal::conditional<NumTraits<Scalar>::IsComplex, internal::true_type, internal::false_type>::type());
|
||||
makeGivens(p, q, r, typename internal::conditional<NumTraits<Scalar>::IsComplex, internal::true_type, internal::false_type>::type());
|
||||
}
|
||||
|
||||
|
||||
|
@ -180,8 +180,10 @@ public:
|
||||
RealScalar threshold() const
|
||||
{
|
||||
eigen_assert(m_isInitialized || m_usePrescribedThreshold);
|
||||
// this temporary is needed to workaround a MSVC issue
|
||||
Index diagSize = (std::max<Index>)(1,m_diagSize);
|
||||
return m_usePrescribedThreshold ? m_prescribedThreshold
|
||||
: (std::max<Index>)(1,m_diagSize)*NumTraits<Scalar>::epsilon();
|
||||
: diagSize*NumTraits<Scalar>::epsilon();
|
||||
}
|
||||
|
||||
/** \returns true if \a U (full or thin) is asked for in this SVD decomposition */
|
||||
|
@ -893,7 +893,7 @@ public:
|
||||
|
||||
Index p = m_outerIndex[outer] + m_innerNonZeros[outer]++;
|
||||
m_data.index(p) = convert_index(inner);
|
||||
return (m_data.value(p) = 0);
|
||||
return (m_data.value(p) = Scalar(0));
|
||||
}
|
||||
|
||||
private:
|
||||
@ -1274,7 +1274,7 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_StorageIndex>::Scalar&
|
||||
m_innerNonZeros[outer]++;
|
||||
|
||||
m_data.index(p) = inner;
|
||||
return (m_data.value(p) = 0);
|
||||
return (m_data.value(p) = Scalar(0));
|
||||
}
|
||||
|
||||
template<typename _Scalar, int _Options, typename _StorageIndex>
|
||||
@ -1381,7 +1381,7 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_StorageIndex>::Scalar&
|
||||
}
|
||||
|
||||
m_data.index(p) = inner;
|
||||
return (m_data.value(p) = 0);
|
||||
return (m_data.value(p) = Scalar(0));
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
@ -499,8 +499,6 @@ void SparseLU<MatrixType, OrderingType>::factorize(const MatrixType& matrix)
|
||||
eigen_assert(m_analysisIsOk && "analyzePattern() should be called first");
|
||||
eigen_assert((matrix.rows() == matrix.cols()) && "Only for squared matrices");
|
||||
|
||||
typedef typename IndexVector::Scalar StorageIndex;
|
||||
|
||||
m_isInitialized = true;
|
||||
|
||||
|
||||
|
@ -146,7 +146,7 @@ void SparseLUImpl<Scalar,StorageIndex>::panel_bmod(const Index m, const Index w,
|
||||
|
||||
Index ldl = internal::first_multiple<Index>(nrow, PacketSize);
|
||||
Index offset = (PacketSize-internal::first_default_aligned(B.data(), PacketSize)) % PacketSize;
|
||||
auto L = MappedMatrixBlock(tempv.data()+w*ldu+offset, nrow, u_cols, OuterStride<>(ldl));
|
||||
MappedMatrixBlock L(tempv.data()+w*ldu+offset, nrow, u_cols, OuterStride<>(ldl));
|
||||
|
||||
L.setZero();
|
||||
internal::sparselu_gemm<Scalar>(L.rows(), L.cols(), B.cols(), B.data(), B.outerStride(), U.data(), U.outerStride(), L.data(), L.outerStride());
|
||||
|
@ -297,8 +297,8 @@ SluMatrix asSluMatrix(MatrixType& mat)
|
||||
template<typename Scalar, int Flags, typename Index>
|
||||
MappedSparseMatrix<Scalar,Flags,Index> map_superlu(SluMatrix& sluMat)
|
||||
{
|
||||
eigen_assert((Flags&RowMajor)==RowMajor && sluMat.Stype == SLU_NR
|
||||
|| (Flags&ColMajor)==ColMajor && sluMat.Stype == SLU_NC);
|
||||
eigen_assert(((Flags&RowMajor)==RowMajor && sluMat.Stype == SLU_NR)
|
||||
|| ((Flags&ColMajor)==ColMajor && sluMat.Stype == SLU_NC));
|
||||
|
||||
Index outerSize = (Flags&RowMajor)==RowMajor ? sluMat.ncol : sluMat.nrow;
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
THIS IS NOT THE COMPLETE EIGEN DISTRIBUTION. ONLY FILES NEEDED FOR COMPILING EIGEN INTO SLIC3R WERE PUT INTO THE SLIC3R SOURCE DISTRIBUTION.
|
||||
THIS DIRECTORY CONTAINS PIECES OF THE EIGEN 3.3.5 b3f3d4950030 SOURCE DISTRIBUTION.
|
||||
|
||||
|
||||
**Eigen is a C++ template library for linear algebra: matrices, vectors, numerical solvers, and related algorithms.**
|
||||
|
||||
For more information go to http://eigen.tuxfamily.org/.
|
||||
|
||||
THIS IS NOT THE COMPLETE EIGEN DISTRIBUTION. ONLY FILES NEEDED FOR COMPILING EIGEN INTO SLIC3R WERE PUT INTO THE SLIC3R SOURCE DISTRIBUTION.
|
||||
THIS DIRECTORY CONTAINS PIECES OF THE EIGEN 3.3.7 323c052e1731 SOURCE DISTRIBUTION.
|
||||
|
@ -931,7 +931,7 @@ class BlockSparseMatrix : public SparseMatrixBase<BlockSparseMatrix<_Scalar,_Blo
|
||||
}
|
||||
|
||||
/**
|
||||
* \returns the starting position of the block <id> in the array of values
|
||||
* \returns the starting position of the block \p id in the array of values
|
||||
*/
|
||||
Index blockPtr(Index id) const
|
||||
{
|
||||
|
@ -228,6 +228,9 @@ template<typename _Scalar, int _Options, typename _StorageIndex>
|
||||
EIGEN_DEPRECATED inline DynamicSparseMatrix()
|
||||
: m_innerSize(0), m_data(0)
|
||||
{
|
||||
#ifdef EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN
|
||||
EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN
|
||||
#endif
|
||||
eigen_assert(innerSize()==0 && outerSize()==0);
|
||||
}
|
||||
|
||||
@ -235,6 +238,9 @@ template<typename _Scalar, int _Options, typename _StorageIndex>
|
||||
EIGEN_DEPRECATED inline DynamicSparseMatrix(Index rows, Index cols)
|
||||
: m_innerSize(0)
|
||||
{
|
||||
#ifdef EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN
|
||||
EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN
|
||||
#endif
|
||||
resize(rows, cols);
|
||||
}
|
||||
|
||||
@ -243,12 +249,18 @@ template<typename _Scalar, int _Options, typename _StorageIndex>
|
||||
EIGEN_DEPRECATED explicit inline DynamicSparseMatrix(const SparseMatrixBase<OtherDerived>& other)
|
||||
: m_innerSize(0)
|
||||
{
|
||||
Base::operator=(other.derived());
|
||||
#ifdef EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN
|
||||
EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN
|
||||
#endif
|
||||
Base::operator=(other.derived());
|
||||
}
|
||||
|
||||
inline DynamicSparseMatrix(const DynamicSparseMatrix& other)
|
||||
: Base(), m_innerSize(0)
|
||||
{
|
||||
#ifdef EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN
|
||||
EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN
|
||||
#endif
|
||||
*this = other.derived();
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,8 @@ namespace Eigen {
|
||||
|
||||
namespace internal
|
||||
{
|
||||
template <typename Scalar>
|
||||
inline bool GetMarketLine (std::stringstream& line, Index& M, Index& N, Index& i, Index& j, Scalar& value)
|
||||
template <typename Scalar,typename IndexType>
|
||||
inline bool GetMarketLine (std::stringstream& line, IndexType& M, IndexType& N, IndexType& i, IndexType& j, Scalar& value)
|
||||
{
|
||||
line >> i >> j >> value;
|
||||
i--;
|
||||
@ -30,8 +30,8 @@ namespace internal
|
||||
else
|
||||
return false;
|
||||
}
|
||||
template <typename Scalar>
|
||||
inline bool GetMarketLine (std::stringstream& line, Index& M, Index& N, Index& i, Index& j, std::complex<Scalar>& value)
|
||||
template <typename Scalar,typename IndexType>
|
||||
inline bool GetMarketLine (std::stringstream& line, IndexType& M, IndexType& N, IndexType& i, IndexType& j, std::complex<Scalar>& value)
|
||||
{
|
||||
Scalar valR, valI;
|
||||
line >> i >> j >> valR >> valI;
|
||||
@ -134,7 +134,7 @@ template<typename SparseMatrixType>
|
||||
bool loadMarket(SparseMatrixType& mat, const std::string& filename)
|
||||
{
|
||||
typedef typename SparseMatrixType::Scalar Scalar;
|
||||
typedef typename SparseMatrixType::Index Index;
|
||||
typedef typename SparseMatrixType::StorageIndex StorageIndex;
|
||||
std::ifstream input(filename.c_str(),std::ios::in);
|
||||
if(!input)
|
||||
return false;
|
||||
@ -144,11 +144,11 @@ bool loadMarket(SparseMatrixType& mat, const std::string& filename)
|
||||
|
||||
bool readsizes = false;
|
||||
|
||||
typedef Triplet<Scalar,Index> T;
|
||||
typedef Triplet<Scalar,StorageIndex> T;
|
||||
std::vector<T> elements;
|
||||
|
||||
Index M(-1), N(-1), NNZ(-1);
|
||||
Index count = 0;
|
||||
StorageIndex M(-1), N(-1), NNZ(-1);
|
||||
StorageIndex count = 0;
|
||||
while(input.getline(buffer, maxBuffersize))
|
||||
{
|
||||
// skip comments
|
||||
@ -171,7 +171,7 @@ bool loadMarket(SparseMatrixType& mat, const std::string& filename)
|
||||
}
|
||||
else
|
||||
{
|
||||
Index i(-1), j(-1);
|
||||
StorageIndex i(-1), j(-1);
|
||||
Scalar value;
|
||||
if( internal::GetMarketLine(line, M, N, i, j, value) )
|
||||
{
|
||||
|
@ -90,8 +90,8 @@ add_library(libslic3r STATIC
|
||||
GCode.hpp
|
||||
GCodeReader.cpp
|
||||
GCodeReader.hpp
|
||||
GCodeSender.cpp
|
||||
GCodeSender.hpp
|
||||
# GCodeSender.cpp
|
||||
# GCodeSender.hpp
|
||||
GCodeTimeEstimator.cpp
|
||||
GCodeTimeEstimator.hpp
|
||||
GCodeWriter.cpp
|
||||
@ -175,7 +175,7 @@ add_library(libslic3r STATIC
|
||||
SLA/SLASpatIndex.hpp
|
||||
)
|
||||
|
||||
if (NOT SLIC3R_SYNTAXONLY)
|
||||
if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY)
|
||||
add_precompiled_header(libslic3r pchheader.hpp FORCEINCLUDE)
|
||||
endif ()
|
||||
|
||||
|
@ -561,6 +561,12 @@ bool DynamicConfig::read_cli(int argc, char** argv, t_config_option_keys* extra)
|
||||
extra->push_back(token);
|
||||
continue;
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
if (boost::starts_with(token, "-psn_"))
|
||||
// OSX launcher may add a "process serial number", for example "-psn_0_989382" to the command line.
|
||||
// While it is supposed to be dropped since OSX 10.9, we will rather ignore it.
|
||||
continue;
|
||||
#endif /* __APPLE__ */
|
||||
// Stop parsing tokens as options when -- is supplied.
|
||||
if (token == "--") {
|
||||
parse_options = false;
|
||||
@ -604,23 +610,31 @@ bool DynamicConfig::read_cli(int argc, char** argv, t_config_option_keys* extra)
|
||||
value = argv[++ i];
|
||||
}
|
||||
// Store the option value.
|
||||
const bool existing = this->has(opt_key);
|
||||
if (ConfigOptionBool* opt = this->opt<ConfigOptionBool>(opt_key, true)) {
|
||||
opt->value = !no;
|
||||
} else if (ConfigOptionBools* opt = this->opt<ConfigOptionBools>(opt_key, true)) {
|
||||
if (!existing) opt->values.clear(); // remove the default values
|
||||
opt->values.push_back(!no);
|
||||
} else if (ConfigOptionStrings* opt = this->opt<ConfigOptionStrings>(opt_key, true)) {
|
||||
if (!existing) opt->values.clear(); // remove the default values
|
||||
opt->deserialize(value, true);
|
||||
} else if (ConfigOptionFloats* opt = this->opt<ConfigOptionFloats>(opt_key, true)) {
|
||||
if (!existing) opt->values.clear(); // remove the default values
|
||||
opt->deserialize(value, true);
|
||||
} else if (ConfigOptionPoints* opt = this->opt<ConfigOptionPoints>(opt_key, true)) {
|
||||
if (!existing) opt->values.clear(); // remove the default values
|
||||
opt->deserialize(value, true);
|
||||
const bool existing = this->has(opt_key);
|
||||
ConfigOption *opt_base = this->option(opt_key, true);
|
||||
ConfigOptionVectorBase *opt_vector = opt_base->is_vector() ? static_cast<ConfigOptionVectorBase*>(opt_base) : nullptr;
|
||||
if (opt_vector) {
|
||||
// Vector values will be chained. Repeated use of a parameter will append the parameter or parameters
|
||||
// to the end of the value.
|
||||
if (!existing)
|
||||
// remove the default values
|
||||
opt_vector->deserialize("", true);
|
||||
if (opt_base->type() == coBools)
|
||||
static_cast<ConfigOptionBools*>(opt_base)->values.push_back(!no);
|
||||
else
|
||||
// Deserialize any other vector value (ConfigOptionInts, Floats, Percents, Points) the same way
|
||||
// they get deserialized from an .ini file. For ConfigOptionStrings, that means that the C-style unescape
|
||||
// will be applied for values enclosed in quotes, while values non-enclosed in quotes are left to be
|
||||
// unescaped by the calling shell.
|
||||
opt_vector->deserialize(value, true);
|
||||
} else if (opt_base->type() == coBool) {
|
||||
static_cast<ConfigOptionBool*>(opt_base)->value = !no;
|
||||
} else if (opt_base->type() == coString) {
|
||||
// Do not unescape single string values, the unescaping is left to the calling shell.
|
||||
static_cast<ConfigOptionString*>(opt_base)->value = value;
|
||||
} else {
|
||||
this->set_deserialize(opt_key, value, true);
|
||||
// Any scalar value of a type different from Bool and String.
|
||||
this->set_deserialize(opt_key, value, false);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -63,7 +63,7 @@ enum ConfigOptionType {
|
||||
};
|
||||
|
||||
enum ConfigOptionMode {
|
||||
comSimple,
|
||||
comSimple = 0,
|
||||
comAdvanced,
|
||||
comExpert
|
||||
};
|
||||
@ -218,7 +218,7 @@ public:
|
||||
|
||||
const T& get_at(size_t i) const { return const_cast<ConfigOptionVector<T>*>(this)->get_at(i); }
|
||||
|
||||
// Resize this vector by duplicating the last value.
|
||||
// Resize this vector by duplicating the /*last*/first value.
|
||||
// If the current vector is empty, the default value is used instead.
|
||||
void resize(size_t n, const ConfigOption *opt_default = nullptr) override
|
||||
{
|
||||
@ -238,7 +238,7 @@ public:
|
||||
this->values.resize(n, static_cast<const ConfigOptionVector<T>*>(opt_default)->values.front());
|
||||
} else {
|
||||
// Resize by duplicating the last value.
|
||||
this->values.resize(n, this->values.back());
|
||||
this->values.resize(n, this->values./*back*/front());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -233,16 +233,15 @@ ExPolygon::medial_axis(double max_width, double min_width, Polylines* polylines)
|
||||
polylines->insert(polylines->end(), tp.begin(), tp.end());
|
||||
}
|
||||
|
||||
void
|
||||
ExPolygon::get_trapezoids(Polygons* polygons) const
|
||||
/*
|
||||
void ExPolygon::get_trapezoids(Polygons* polygons) const
|
||||
{
|
||||
ExPolygons expp;
|
||||
expp.push_back(*this);
|
||||
boost::polygon::get_trapezoids(*polygons, expp);
|
||||
}
|
||||
|
||||
void
|
||||
ExPolygon::get_trapezoids(Polygons* polygons, double angle) const
|
||||
void ExPolygon::get_trapezoids(Polygons* polygons, double angle) const
|
||||
{
|
||||
ExPolygon clone = *this;
|
||||
clone.rotate(PI/2 - angle, Point(0,0));
|
||||
@ -250,12 +249,12 @@ ExPolygon::get_trapezoids(Polygons* polygons, double angle) const
|
||||
for (Polygons::iterator polygon = polygons->begin(); polygon != polygons->end(); ++polygon)
|
||||
polygon->rotate(-(PI/2 - angle), Point(0,0));
|
||||
}
|
||||
*/
|
||||
|
||||
// This algorithm may return more trapezoids than necessary
|
||||
// (i.e. it may break a single trapezoid in several because
|
||||
// other parts of the object have x coordinates in the middle)
|
||||
void
|
||||
ExPolygon::get_trapezoids2(Polygons* polygons) const
|
||||
void ExPolygon::get_trapezoids2(Polygons* polygons) const
|
||||
{
|
||||
// get all points of this ExPolygon
|
||||
Points pp = *this;
|
||||
@ -293,8 +292,8 @@ ExPolygon::get_trapezoids2(Polygons* polygons) const
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ExPolygon::get_trapezoids2(Polygons* polygons, double angle) const {
|
||||
void ExPolygon::get_trapezoids2(Polygons* polygons, double angle) const
|
||||
{
|
||||
ExPolygon clone = *this;
|
||||
clone.rotate(PI / 2 - angle, Point(0, 0));
|
||||
clone.get_trapezoids2(polygons);
|
||||
@ -351,8 +350,7 @@ ExPolygon::get_trapezoids3_half(Polygons* polygons, float spacing) const {
|
||||
|
||||
// While this triangulates successfully, it's NOT a constrained triangulation
|
||||
// as it will create more vertices on the boundaries than the ones supplied.
|
||||
void
|
||||
ExPolygon::triangulate(Polygons* polygons) const
|
||||
void ExPolygon::triangulate(Polygons* polygons) const
|
||||
{
|
||||
// first make trapezoids
|
||||
Polygons trapezoids;
|
||||
@ -363,8 +361,8 @@ ExPolygon::triangulate(Polygons* polygons) const
|
||||
polygon->triangulate_convex(polygons);
|
||||
}
|
||||
|
||||
void
|
||||
ExPolygon::triangulate_pp(Polygons* polygons) const
|
||||
/*
|
||||
void ExPolygon::triangulate_pp(Polygons* polygons) const
|
||||
{
|
||||
// convert polygons
|
||||
std::list<TPPLPoly> input;
|
||||
@ -421,9 +419,113 @@ ExPolygon::triangulate_pp(Polygons* polygons) const
|
||||
polygons->push_back(p);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void
|
||||
ExPolygon::triangulate_p2t(Polygons* polygons) const
|
||||
std::list<TPPLPoly> expoly_to_polypartition_input(const ExPolygon &ex)
|
||||
{
|
||||
std::list<TPPLPoly> input;
|
||||
// contour
|
||||
{
|
||||
input.emplace_back();
|
||||
TPPLPoly &p = input.back();
|
||||
p.Init(int(ex.contour.points.size()));
|
||||
for (const Point &point : ex.contour.points) {
|
||||
size_t i = &point - &ex.contour.points.front();
|
||||
p[i].x = point(0);
|
||||
p[i].y = point(1);
|
||||
}
|
||||
p.SetHole(false);
|
||||
}
|
||||
// holes
|
||||
for (const Polygon &hole : ex.holes) {
|
||||
input.emplace_back();
|
||||
TPPLPoly &p = input.back();
|
||||
p.Init(hole.points.size());
|
||||
for (const Point &point : hole.points) {
|
||||
size_t i = &point - &hole.points.front();
|
||||
p[i].x = point(0);
|
||||
p[i].y = point(1);
|
||||
}
|
||||
p.SetHole(true);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
std::list<TPPLPoly> expoly_to_polypartition_input(const ExPolygons &expps)
|
||||
{
|
||||
std::list<TPPLPoly> input;
|
||||
for (const ExPolygon &ex : expps) {
|
||||
// contour
|
||||
{
|
||||
input.emplace_back();
|
||||
TPPLPoly &p = input.back();
|
||||
p.Init(int(ex.contour.points.size()));
|
||||
for (const Point &point : ex.contour.points) {
|
||||
size_t i = &point - &ex.contour.points.front();
|
||||
p[i].x = point(0);
|
||||
p[i].y = point(1);
|
||||
}
|
||||
p.SetHole(false);
|
||||
}
|
||||
// holes
|
||||
for (const Polygon &hole : ex.holes) {
|
||||
input.emplace_back();
|
||||
TPPLPoly &p = input.back();
|
||||
p.Init(hole.points.size());
|
||||
for (const Point &point : hole.points) {
|
||||
size_t i = &point - &hole.points.front();
|
||||
p[i].x = point(0);
|
||||
p[i].y = point(1);
|
||||
}
|
||||
p.SetHole(true);
|
||||
}
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
std::vector<Point> polypartition_output_to_triangles(const std::list<TPPLPoly> &output)
|
||||
{
|
||||
size_t num_triangles = 0;
|
||||
for (const TPPLPoly &poly : output)
|
||||
if (poly.GetNumPoints() >= 3)
|
||||
num_triangles += (size_t)poly.GetNumPoints() - 2;
|
||||
std::vector<Point> triangles;
|
||||
triangles.reserve(triangles.size() + num_triangles * 3);
|
||||
for (const TPPLPoly &poly : output) {
|
||||
long num_points = poly.GetNumPoints();
|
||||
if (num_points >= 3) {
|
||||
const TPPLPoint *pt0 = &poly[0];
|
||||
const TPPLPoint *pt1 = nullptr;
|
||||
const TPPLPoint *pt2 = &poly[1];
|
||||
for (long i = 2; i < num_points; ++ i) {
|
||||
pt1 = pt2;
|
||||
pt2 = &poly[i];
|
||||
triangles.emplace_back(coord_t(pt0->x), coord_t(pt0->y));
|
||||
triangles.emplace_back(coord_t(pt1->x), coord_t(pt1->y));
|
||||
triangles.emplace_back(coord_t(pt2->x), coord_t(pt2->y));
|
||||
}
|
||||
}
|
||||
}
|
||||
return triangles;
|
||||
}
|
||||
|
||||
void ExPolygon::triangulate_pp(Points *triangles) const
|
||||
{
|
||||
ExPolygons expp = union_ex(simplify_polygons(to_polygons(*this), true));
|
||||
std::list<TPPLPoly> input = expoly_to_polypartition_input(expp);
|
||||
// perform triangulation
|
||||
std::list<TPPLPoly> output;
|
||||
int res = TPPLPartition().Triangulate_MONO(&input, &output);
|
||||
// int TPPLPartition::Triangulate_EC(TPPLPolyList *inpolys, TPPLPolyList *triangles) {
|
||||
if (res != 1)
|
||||
throw std::runtime_error("Triangulation failed");
|
||||
*triangles = polypartition_output_to_triangles(output);
|
||||
}
|
||||
|
||||
// Uses the Poly2tri library maintained by Jan Niklas Hasse @jhasse // https://github.com/jhasse/poly2tri
|
||||
// See https://github.com/jhasse/poly2tri/blob/master/README.md for the limitations of the library!
|
||||
// No duplicate points are allowed, no very close points, holes must not touch outer contour etc.
|
||||
void ExPolygon::triangulate_p2t(Polygons* polygons) const
|
||||
{
|
||||
ExPolygons expp = simplify_polygons_ex(*this, true);
|
||||
|
||||
@ -447,6 +549,7 @@ ExPolygon::triangulate_p2t(Polygons* polygons) const
|
||||
}
|
||||
|
||||
// perform triangulation
|
||||
try {
|
||||
cdt.Triangulate();
|
||||
std::vector<p2t::Triangle*> triangles = cdt.GetTriangles();
|
||||
|
||||
@ -458,14 +561,17 @@ ExPolygon::triangulate_p2t(Polygons* polygons) const
|
||||
}
|
||||
polygons->push_back(p);
|
||||
}
|
||||
} catch (const std::runtime_error & /* err */) {
|
||||
assert(false);
|
||||
// just ignore, don't triangulate
|
||||
}
|
||||
|
||||
for (p2t::Point *ptr : ContourPoints)
|
||||
delete ptr;
|
||||
}
|
||||
}
|
||||
|
||||
Lines
|
||||
ExPolygon::lines() const
|
||||
Lines ExPolygon::lines() const
|
||||
{
|
||||
Lines lines = this->contour.lines();
|
||||
for (Polygons::const_iterator h = this->holes.begin(); h != this->holes.end(); ++h) {
|
||||
|
@ -6,6 +6,9 @@
|
||||
#include "Polyline.hpp"
|
||||
#include <vector>
|
||||
|
||||
// polygon class of the polypartition library
|
||||
class TPPLPoly;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class ExPolygon;
|
||||
@ -56,13 +59,14 @@ public:
|
||||
void remove_point_too_near(const coord_t tolerance);
|
||||
void medial_axis(const ExPolygon &bounds, double max_width, double min_width, ThickPolylines* polylines, double height) const;
|
||||
void medial_axis(double max_width, double min_width, Polylines* polylines) const;
|
||||
void get_trapezoids(Polygons* polygons) const;
|
||||
void get_trapezoids(Polygons* polygons, double angle) const;
|
||||
// void get_trapezoids(Polygons* polygons) const;
|
||||
// void get_trapezoids(Polygons* polygons, double angle) const;
|
||||
void get_trapezoids2(Polygons* polygons) const;
|
||||
void get_trapezoids2(Polygons* polygons, double angle) const;
|
||||
void get_trapezoids3_half(Polygons* polygons, float spacing) const;
|
||||
void triangulate(Polygons* polygons) const;
|
||||
void triangulate_pp(Polygons* polygons) const;
|
||||
// Triangulate into triples of points.
|
||||
void triangulate_pp(Points *triangles) const;
|
||||
void triangulate_p2t(Polygons* polygons) const;
|
||||
Lines lines() const;
|
||||
};
|
||||
@ -299,6 +303,10 @@ extern std::vector<BoundingBox> get_extents_vector(const ExPolygons &polygons);
|
||||
|
||||
extern bool remove_sticks(ExPolygon &poly);
|
||||
|
||||
extern std::list<TPPLPoly> expoly_to_polypartition_input(const ExPolygons &expp);
|
||||
extern std::list<TPPLPoly> expoly_to_polypartition_input(const ExPolygon &ex);
|
||||
extern std::vector<Point> polypartition_output_to_triangles(const std::list<TPPLPoly> &output);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
// start Boost
|
||||
|
@ -6,9 +6,12 @@
|
||||
#include <float.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "../libslic3r.h"
|
||||
#include "../BoundingBox.hpp"
|
||||
#include "../PrintConfig.hpp"
|
||||
#include "../Utils.hpp"
|
||||
#include "../Flow.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
@ -47,6 +50,7 @@ struct FillParams
|
||||
// in this case we don't try to make more continuous paths
|
||||
bool complete;
|
||||
};
|
||||
static_assert(IsTriviallyCopyable<FillParams>::value, "FillParams class is not POD (and it should be - see constructor).");
|
||||
|
||||
class Fill
|
||||
{
|
||||
|
@ -582,10 +582,7 @@ namespace Slic3r {
|
||||
|
||||
IdToLayerHeightsProfileMap::iterator obj_layer_heights_profile = m_layer_heights_profiles.find(object.first);
|
||||
if (obj_layer_heights_profile != m_layer_heights_profiles.end())
|
||||
{
|
||||
object.second->layer_height_profile = obj_layer_heights_profile->second;
|
||||
object.second->layer_height_profile_valid = true;
|
||||
}
|
||||
|
||||
IdToSlaSupportPointsMap::iterator obj_sla_support_points = m_sla_support_points.find(object.first);
|
||||
if (obj_sla_support_points != m_sla_support_points.end() && !obj_sla_support_points->second.empty())
|
||||
@ -1477,6 +1474,7 @@ namespace Slic3r {
|
||||
|
||||
stl_get_size(&stl);
|
||||
volume->mesh.repair();
|
||||
volume->center_geometry();
|
||||
volume->calculate_convex_hull();
|
||||
|
||||
// apply volume's name and config data
|
||||
@ -1925,7 +1923,7 @@ namespace Slic3r {
|
||||
for (const ModelObject* object : model.objects)
|
||||
{
|
||||
++count;
|
||||
std::vector<double> layer_height_profile = object->layer_height_profile_valid ? object->layer_height_profile : std::vector<double>();
|
||||
const std::vector<double> &layer_height_profile = object->layer_height_profile;
|
||||
if ((layer_height_profile.size() >= 4) && ((layer_height_profile.size() % 2) == 0))
|
||||
{
|
||||
sprintf(buffer, "object_id=%d|", count);
|
||||
|
@ -279,8 +279,8 @@ void AMFParserContext::startElement(const char *name, const char **atts)
|
||||
node_type_new = NODE_TYPE_VERTICES;
|
||||
else if (strcmp(name, "volume") == 0) {
|
||||
assert(! m_volume);
|
||||
m_volume = m_object->add_volume(TriangleMesh());
|
||||
node_type_new = NODE_TYPE_VOLUME;
|
||||
m_volume = m_object->add_volume(TriangleMesh());
|
||||
node_type_new = NODE_TYPE_VOLUME;
|
||||
}
|
||||
} else if (m_path[2] == NODE_TYPE_INSTANCE) {
|
||||
assert(m_instance);
|
||||
@ -528,6 +528,7 @@ void AMFParserContext::endElement(const char * /* name */)
|
||||
}
|
||||
stl_get_size(&stl);
|
||||
m_volume->mesh.repair();
|
||||
m_volume->center_geometry();
|
||||
m_volume->calculate_convex_hull();
|
||||
m_volume_facets.clear();
|
||||
m_volume = nullptr;
|
||||
@ -578,7 +579,6 @@ void AMFParserContext::endElement(const char * /* name */)
|
||||
break;
|
||||
p = end + 1;
|
||||
}
|
||||
m_object->layer_height_profile_valid = true;
|
||||
}
|
||||
else if (m_path.size() == 3 && m_path[1] == NODE_TYPE_OBJECT && m_object && strcmp(opt_key, "sla_support_points") == 0) {
|
||||
// Parse object's layer height profile, a semicolon separated list of floats.
|
||||
@ -642,13 +642,17 @@ void AMFParserContext::endDocument()
|
||||
continue;
|
||||
}
|
||||
for (const Instance &instance : object.second.instances)
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
{
|
||||
#else
|
||||
if (instance.deltax_set && instance.deltay_set) {
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
ModelInstance *mi = m_model.objects[object.second.idx]->add_instance();
|
||||
mi->set_offset(Vec3d(instance.deltax_set ? (double)instance.deltax : 0.0, instance.deltay_set ? (double)instance.deltay : 0.0, instance.deltaz_set ? (double)instance.deltaz : 0.0));
|
||||
mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0));
|
||||
mi->set_scaling_factor(Vec3d(instance.scalex_set ? (double)instance.scalex : 1.0, instance.scaley_set ? (double)instance.scaley : 1.0, instance.scalez_set ? (double)instance.scalez : 1.0));
|
||||
mi->set_mirror(Vec3d(instance.mirrorx_set ? (double)instance.mirrorx : 1.0, instance.mirrory_set ? (double)instance.mirrory : 1.0, instance.mirrorz_set ? (double)instance.mirrorz : 1.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -885,7 +889,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << object->config.serialize(key) << "</metadata>\n";
|
||||
if (!object->name.empty())
|
||||
stream << " <metadata type=\"name\">" << xml_escape(object->name) << "</metadata>\n";
|
||||
std::vector<double> layer_height_profile = object->layer_height_profile_valid ? object->layer_height_profile : std::vector<double>();
|
||||
const std::vector<double> &layer_height_profile = object->layer_height_profile;
|
||||
if (layer_height_profile.size() >= 4 && (layer_height_profile.size() % 2) == 0) {
|
||||
// Store the layer height profile as a single semicolon separated list.
|
||||
stream << " <metadata type=\"slic3r.layer_height_profile\">";
|
||||
@ -919,12 +923,14 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
||||
auto &stl = volume->mesh.stl;
|
||||
if (stl.v_shared == nullptr)
|
||||
stl_generate_shared_vertices(&stl);
|
||||
for (size_t i = 0; i < stl.stats.shared_vertices; ++ i) {
|
||||
const Transform3d& matrix = volume->get_matrix();
|
||||
for (size_t i = 0; i < stl.stats.shared_vertices; ++i) {
|
||||
stream << " <vertex>\n";
|
||||
stream << " <coordinates>\n";
|
||||
stream << " <x>" << stl.v_shared[i](0) << "</x>\n";
|
||||
stream << " <y>" << stl.v_shared[i](1) << "</y>\n";
|
||||
stream << " <z>" << stl.v_shared[i](2) << "</z>\n";
|
||||
Vec3d v = matrix * stl.v_shared[i].cast<double>();
|
||||
stream << " <x>" << v(0) << "</x>\n";
|
||||
stream << " <y>" << v(1) << "</y>\n";
|
||||
stream << " <z>" << v(2) << "</z>\n";
|
||||
stream << " </coordinates>\n";
|
||||
stream << " </vertex>\n";
|
||||
}
|
||||
|
@ -103,8 +103,7 @@ OozePrevention::_get_temp(GCode &gcodegen)
|
||||
: gcodegen.config().temperature.get_at(gcodegen.writer().extruder()->id());
|
||||
}
|
||||
|
||||
std::string
|
||||
Wipe::wipe(GCode &gcodegen, bool toolchange)
|
||||
std::string Wipe::wipe(GCode &gcodegen, bool toolchange)
|
||||
{
|
||||
std::string gcode;
|
||||
|
||||
@ -137,19 +136,22 @@ Wipe::wipe(GCode &gcodegen, bool toolchange)
|
||||
wipe_path.clip_end(wipe_path.length() - wipe_dist);
|
||||
|
||||
// subdivide the retraction in segments
|
||||
for (const Line &line : wipe_path.lines()) {
|
||||
double segment_length = line.length();
|
||||
/* Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
|
||||
due to rounding (TODO: test and/or better math for this) */
|
||||
double dE = length * (segment_length / wipe_dist) * 0.95;
|
||||
//FIXME one shall not generate the unnecessary G1 Fxxx commands, here wipe_speed is a constant inside this cycle.
|
||||
// Is it here for the cooling markers? Or should it be outside of the cycle?
|
||||
gcode += gcodegen.writer().set_speed(wipe_speed*60, "", gcodegen.enable_cooling_markers() ? ";_WIPE" : "");
|
||||
gcode += gcodegen.writer().extrude_to_xy(
|
||||
gcodegen.point_to_gcode(line.b),
|
||||
-dE,
|
||||
"wipe and retract"
|
||||
);
|
||||
if (! wipe_path.empty()) {
|
||||
for (const Line &line : wipe_path.lines()) {
|
||||
double segment_length = line.length();
|
||||
/* Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
|
||||
due to rounding (TODO: test and/or better math for this) */
|
||||
double dE = length * (segment_length / wipe_dist) * 0.95;
|
||||
//FIXME one shall not generate the unnecessary G1 Fxxx commands, here wipe_speed is a constant inside this cycle.
|
||||
// Is it here for the cooling markers? Or should it be outside of the cycle?
|
||||
gcode += gcodegen.writer().set_speed(wipe_speed*60, "", gcodegen.enable_cooling_markers() ? ";_WIPE" : "");
|
||||
gcode += gcodegen.writer().extrude_to_xy(
|
||||
gcodegen.point_to_gcode(line.b),
|
||||
-dE,
|
||||
"wipe and retract"
|
||||
);
|
||||
}
|
||||
gcodegen.set_last_pos(wipe_path.points.back());
|
||||
}
|
||||
|
||||
// prevent wiping again on same path
|
||||
@ -204,7 +206,9 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
|
||||
if (! start_filament_gcode.empty()) {
|
||||
// Process the start_filament_gcode for the active filament only.
|
||||
gcodegen.placeholder_parser().set("current_extruder", new_extruder_id);
|
||||
gcode += gcodegen.placeholder_parser_process("start_filament_gcode", start_filament_gcode, new_extruder_id);
|
||||
DynamicConfig config;
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(new_extruder_id));
|
||||
gcode += gcodegen.placeholder_parser_process("start_filament_gcode", start_filament_gcode, new_extruder_id, &config);
|
||||
check_add_eol(gcode);
|
||||
}
|
||||
// A phony move to the end position at the wipe tower.
|
||||
@ -787,11 +791,17 @@ void GCode::_do_export(Print &print, FILE *file)
|
||||
// Wipe tower will control the extruder switching, it will call the start_filament_gcode.
|
||||
} else {
|
||||
// Only initialize the initial extruder.
|
||||
_writeln(file, this->placeholder_parser_process("start_filament_gcode", print.config().start_filament_gcode.values[initial_extruder_id], initial_extruder_id));
|
||||
DynamicConfig config;
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(initial_extruder_id)));
|
||||
_writeln(file, this->placeholder_parser_process("start_filament_gcode", print.config().start_filament_gcode.values[initial_extruder_id], initial_extruder_id, &config));
|
||||
}
|
||||
} else {
|
||||
for (const std::string &start_gcode : print.config().start_filament_gcode.values)
|
||||
_writeln(file, this->placeholder_parser_process("start_filament_gcode", start_gcode, (unsigned int)(&start_gcode - &print.config().start_filament_gcode.values.front())));
|
||||
DynamicConfig config;
|
||||
for (const std::string &start_gcode : print.config().start_filament_gcode.values) {
|
||||
int extruder_id = (unsigned int)(&start_gcode - &print.config().start_filament_gcode.values.front());
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
|
||||
_writeln(file, this->placeholder_parser_process("start_filament_gcode", start_gcode, extruder_id, &config));
|
||||
}
|
||||
}
|
||||
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true);
|
||||
print.throw_if_canceled();
|
||||
@ -809,7 +819,7 @@ void GCode::_do_export(Print &print, FILE *file)
|
||||
for (const ExPolygon &expoly : layer->slices.expolygons)
|
||||
for (const Point © : object->copies()) {
|
||||
islands.emplace_back(expoly.contour);
|
||||
islands.back().translate(- copy);
|
||||
islands.back().translate(copy);
|
||||
}
|
||||
//FIXME Mege the islands in parallel.
|
||||
m_avoid_crossing_perimeters.init_external_mp(union_ex(islands));
|
||||
@ -991,10 +1001,15 @@ void GCode::_do_export(Print &print, FILE *file)
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(m_writer.get_position()(2) - m_config.z_offset.value));
|
||||
if (print.config().single_extruder_multi_material) {
|
||||
// Process the end_filament_gcode for the active filament only.
|
||||
_writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config().end_filament_gcode.get_at(m_writer.extruder()->id()), m_writer.extruder()->id(), &config));
|
||||
int extruder_id = m_writer.extruder()->id();
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
|
||||
_writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config().end_filament_gcode.get_at(extruder_id), extruder_id, &config));
|
||||
} else {
|
||||
for (const std::string &end_gcode : print.config().end_filament_gcode.values)
|
||||
_writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, (unsigned int)(&end_gcode - &print.config().end_filament_gcode.values.front()), &config));
|
||||
for (const std::string &end_gcode : print.config().end_filament_gcode.values) {
|
||||
int extruder_id = (unsigned int)(&end_gcode - &print.config().end_filament_gcode.values.front());
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
|
||||
_writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, extruder_id, &config));
|
||||
}
|
||||
}
|
||||
_writeln(file, this->placeholder_parser_process("end_gcode", print.config().end_gcode, m_writer.extruder()->id(), &config));
|
||||
}
|
||||
@ -1578,9 +1593,11 @@ void GCode::process_layer(
|
||||
auto objects_by_extruder_it = by_extruder.find(extruder_id);
|
||||
if (objects_by_extruder_it == by_extruder.end())
|
||||
continue;
|
||||
|
||||
// We are almost ready to print. However, we must go through all the objects twice to print the the overridden extrusions first (infill/perimeter wiping feature):
|
||||
for (int print_wipe_extrusions=const_cast<LayerTools&>(layer_tools).wiping_extrusions().is_anything_overridden(); print_wipe_extrusions>=0; --print_wipe_extrusions) {
|
||||
if (print_wipe_extrusions == 0)
|
||||
bool is_anything_overridden = const_cast<LayerTools&>(layer_tools).wiping_extrusions().is_anything_overridden();
|
||||
for (int print_wipe_extrusions = is_anything_overridden; print_wipe_extrusions>=0; --print_wipe_extrusions) {
|
||||
if (is_anything_overridden && print_wipe_extrusions == 0)
|
||||
gcode+="; PURGING FINISHED\n";
|
||||
|
||||
for (ObjectByExtruder &object_by_extruder : objects_by_extruder_it->second) {
|
||||
@ -1621,7 +1638,7 @@ void GCode::process_layer(
|
||||
m_layer = layers[layer_id].layer();
|
||||
}
|
||||
for (ObjectByExtruder::Island &island : object_by_extruder.islands) {
|
||||
const auto& by_region_specific = const_cast<LayerTools&>(layer_tools).wiping_extrusions().is_anything_overridden() ? island.by_region_per_copy(copy_id, extruder_id, print_wipe_extrusions) : island.by_region;
|
||||
const auto& by_region_specific = is_anything_overridden ? island.by_region_per_copy(copy_id, extruder_id, print_wipe_extrusions) : island.by_region;
|
||||
|
||||
gcode += this->extrude_infill(print, by_region_specific, true);
|
||||
gcode += this->extrude_perimeters(print, by_region_specific, lower_layer_edge_grids[layer_id]);
|
||||
@ -2610,9 +2627,11 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
|
||||
|
||||
// use G1 because we rely on paths being straight (G0 may make round paths)
|
||||
Lines lines = travel.lines();
|
||||
for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line)
|
||||
gcode += m_writer.travel_to_xy(this->point_to_gcode(line->b), comment);
|
||||
|
||||
if (! lines.empty()) {
|
||||
for (const Line &line : lines)
|
||||
gcode += m_writer.travel_to_xy(this->point_to_gcode(line.b), comment);
|
||||
this->set_last_pos(lines.back().b);
|
||||
}
|
||||
return gcode;
|
||||
}
|
||||
|
||||
|
@ -155,11 +155,11 @@ public:
|
||||
void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr);
|
||||
|
||||
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
|
||||
const Vec2d& origin() const { return m_origin; }
|
||||
const Vec2d& origin() const { return m_origin; }
|
||||
void set_origin(const Vec2d &pointf);
|
||||
void set_origin(const coordf_t x, const coordf_t y) { this->set_origin(Vec2d(x, y)); }
|
||||
const Point& last_pos() const { return m_last_pos; }
|
||||
Vec2d point_to_gcode(const Point &point) const;
|
||||
Vec2d point_to_gcode(const Point &point) const;
|
||||
Point gcode_to_point(const Vec2d &point) const;
|
||||
const FullPrintConfig &config() const { return m_config; }
|
||||
const Layer* layer() const { return m_layer; }
|
||||
@ -360,6 +360,7 @@ protected:
|
||||
size_t num_objects,
|
||||
size_t num_islands);
|
||||
|
||||
friend class Wipe;
|
||||
friend class WipeTowerIntegration;
|
||||
};
|
||||
|
||||
|
@ -1,24 +1,140 @@
|
||||
#include "PostProcessor.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
namespace Slic3r {
|
||||
// The standard Windows includes.
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
|
||||
//FIXME Ignore until we include boost::process
|
||||
void run_post_process_scripts(const std::string &path, const PrintConfig &config)
|
||||
// https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
|
||||
// This routine appends the given argument to a command line such that CommandLineToArgvW will return the argument string unchanged.
|
||||
// Arguments in a command line should be separated by spaces; this function does not add these spaces.
|
||||
// Argument - Supplies the argument to encode.
|
||||
// CommandLine - Supplies the command line to which we append the encoded argument string.
|
||||
static void quote_argv_winapi(const std::wstring &argument, std::wstring &commmand_line_out)
|
||||
{
|
||||
// Don't quote unless we actually need to do so --- hopefully avoid problems if programs won't parse quotes properly.
|
||||
if (argument.empty() == false && argument.find_first_of(L" \t\n\v\"") == argument.npos)
|
||||
commmand_line_out.append(argument);
|
||||
else {
|
||||
commmand_line_out.push_back(L'"');
|
||||
for (auto it = argument.begin(); ; ++ it) {
|
||||
unsigned number_backslashes = 0;
|
||||
while (it != argument.end() && *it == L'\\') {
|
||||
++ it;
|
||||
++ number_backslashes;
|
||||
}
|
||||
if (it == argument.end()) {
|
||||
// Escape all backslashes, but let the terminating double quotation mark we add below be interpreted as a metacharacter.
|
||||
commmand_line_out.append(number_backslashes * 2, L'\\');
|
||||
break;
|
||||
} else if (*it == L'"') {
|
||||
// Escape all backslashes and the following double quotation mark.
|
||||
commmand_line_out.append(number_backslashes * 2 + 1, L'\\');
|
||||
commmand_line_out.push_back(*it);
|
||||
} else {
|
||||
// Backslashes aren't special here.
|
||||
commmand_line_out.append(number_backslashes, L'\\');
|
||||
commmand_line_out.push_back(*it);
|
||||
}
|
||||
}
|
||||
commmand_line_out.push_back(L'"');
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
static DWORD execute_process_winapi(const std::wstring &command_line)
|
||||
{
|
||||
// Extract the current environment to be passed to the child process.
|
||||
std::wstring envstr;
|
||||
{
|
||||
wchar_t *env = GetEnvironmentStrings();
|
||||
assert(env != nullptr);
|
||||
const wchar_t* var = env;
|
||||
size_t totallen = 0;
|
||||
size_t len;
|
||||
while ((len = wcslen(var)) > 0) {
|
||||
totallen += len + 1;
|
||||
var += len + 1;
|
||||
}
|
||||
envstr = std::wstring(env, totallen);
|
||||
FreeEnvironmentStrings(env);
|
||||
}
|
||||
|
||||
STARTUPINFOW startup_info;
|
||||
memset(&startup_info, 0, sizeof(startup_info));
|
||||
startup_info.cb = sizeof(STARTUPINFO);
|
||||
#if 0
|
||||
startup_info.dwFlags = STARTF_USESHOWWINDOW;
|
||||
startup_info.wShowWindow = SW_HIDE;
|
||||
#endif
|
||||
PROCESS_INFORMATION process_info;
|
||||
if (! ::CreateProcessW(
|
||||
nullptr /* lpApplicationName */, (LPWSTR)command_line.c_str(), nullptr /* lpProcessAttributes */, nullptr /* lpThreadAttributes */, false /* bInheritHandles */,
|
||||
CREATE_UNICODE_ENVIRONMENT /* | CREATE_NEW_CONSOLE */ /* dwCreationFlags */, (LPVOID)envstr.c_str(), nullptr /* lpCurrentDirectory */, &startup_info, &process_info))
|
||||
throw std::runtime_error(std::string("Failed starting the script ") + boost::nowide::narrow(command_line) + ", Win32 error: " + std::to_string(int(::GetLastError())));
|
||||
::WaitForSingleObject(process_info.hProcess, INFINITE);
|
||||
ULONG rc = 0;
|
||||
::GetExitCodeProcess(process_info.hProcess, &rc);
|
||||
::CloseHandle(process_info.hThread);
|
||||
::CloseHandle(process_info.hProcess);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Run the script. If it is a perl script, run it through the bundled perl interpreter.
|
||||
// If it is a batch file, run it through the cmd.exe.
|
||||
// Otherwise run it directly.
|
||||
static int run_script_win32(const std::string &script, const std::string &gcode)
|
||||
{
|
||||
// Unpack the argument list provided by the user.
|
||||
int nArgs;
|
||||
LPWSTR *szArglist = CommandLineToArgvW(boost::nowide::widen(script).c_str(), &nArgs);
|
||||
if (szArglist == nullptr || nArgs <= 0) {
|
||||
// CommandLineToArgvW failed. Maybe the command line escapment is invalid?
|
||||
throw std::runtime_error(std::string("Post processing script ") + script + " on file " + gcode + " failed. CommandLineToArgvW() refused to parse the command line path.");
|
||||
}
|
||||
|
||||
std::wstring command_line;
|
||||
std::wstring command = szArglist[0];
|
||||
if (! boost::filesystem::exists(boost::filesystem::path(command)))
|
||||
throw std::runtime_error(std::string("The configured post-processing script does not exist: ") + boost::nowide::narrow(command));
|
||||
if (boost::iends_with(command, L".pl")) {
|
||||
// This is a perl script. Run it through the perl interpreter.
|
||||
// The current process may be slic3r.exe or slic3r-console.exe.
|
||||
// Find the path of the process:
|
||||
wchar_t wpath_exe[_MAX_PATH + 1];
|
||||
::GetModuleFileNameW(nullptr, wpath_exe, _MAX_PATH);
|
||||
boost::filesystem::path path_exe(wpath_exe);
|
||||
boost::filesystem::path path_perl = path_exe.parent_path() / "perl" / "perl.exe";
|
||||
if (! boost::filesystem::exists(path_perl)) {
|
||||
LocalFree(szArglist);
|
||||
throw std::runtime_error(std::string("Perl interpreter ") + path_perl.string() + " does not exist.");
|
||||
}
|
||||
// Replace it with the current perl interpreter.
|
||||
quote_argv_winapi(boost::nowide::widen(path_perl.string()), command_line);
|
||||
command_line += L" ";
|
||||
} else if (boost::iends_with(command, ".bat")) {
|
||||
// Run a batch file through the command line interpreter.
|
||||
command_line = L"cmd.exe /C ";
|
||||
}
|
||||
|
||||
for (int i = 0; i < nArgs; ++ i) {
|
||||
quote_argv_winapi(szArglist[i], command_line);
|
||||
command_line += L" ";
|
||||
}
|
||||
LocalFree(szArglist);
|
||||
quote_argv_winapi(boost::nowide::widen(gcode), command_line);
|
||||
return (int)execute_process_winapi(command_line);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <boost/process/system.hpp>
|
||||
#ifndef WIN32
|
||||
#include <sys/stat.h> //for getting filesystem UID/GID
|
||||
#include <unistd.h> //for getting current UID/GID
|
||||
#include <boost/process.hpp>
|
||||
#endif
|
||||
|
||||
namespace Slic3r {
|
||||
@ -33,44 +149,38 @@ void run_post_process_scripts(const std::string &path, const PrintConfig &config
|
||||
if (! boost::filesystem::exists(gcode_file))
|
||||
throw std::runtime_error(std::string("Post-processor can't find exported gcode file"));
|
||||
|
||||
for (std::string script: config.post_process.values) {
|
||||
// Ignore empty post processing script lines.
|
||||
boost::trim(script);
|
||||
if (script.empty())
|
||||
continue;
|
||||
BOOST_LOG_TRIVIAL(info) << "Executing script " << script << " on file " << path;
|
||||
if (! boost::filesystem::exists(boost::filesystem::path(script)))
|
||||
throw std::runtime_error(std::string("The configured post-processing script does not exist: ") + script);
|
||||
#ifndef WIN32
|
||||
struct stat info;
|
||||
if (stat(script.c_str(), &info))
|
||||
throw std::runtime_error(std::string("Cannot read information for post-processing script: ") + script);
|
||||
boost::filesystem::perms script_perms = boost::filesystem::status(script).permissions();
|
||||
//if UID matches, check UID perm. else if GID matches, check GID perm. Otherwise check other perm.
|
||||
if (!(script_perms & ((info.st_uid == geteuid()) ? boost::filesystem::perms::owner_exe
|
||||
: ((info.st_gid == getegid()) ? boost::filesystem::perms::group_exe
|
||||
: boost::filesystem::perms::others_exe))))
|
||||
throw std::runtime_error(std::string("The configured post-processing script is not executable: check permissions. ") + script);
|
||||
#endif
|
||||
int result = 0;
|
||||
for (const std::string &scripts : config.post_process.values) {
|
||||
std::vector<std::string> lines;
|
||||
boost::split(lines, scripts, boost::is_any_of("\r\n"));
|
||||
for (std::string script : lines) {
|
||||
// Ignore empty post processing script lines.
|
||||
boost::trim(script);
|
||||
if (script.empty())
|
||||
continue;
|
||||
BOOST_LOG_TRIVIAL(info) << "Executing script " << script << " on file " << path;
|
||||
#ifdef WIN32
|
||||
if (boost::iends_with(file, ".gcode")) {
|
||||
// The current process may be slic3r.exe or slic3r-console.exe.
|
||||
// Find the path of the process:
|
||||
wchar_t wpath_exe[_MAX_PATH + 1];
|
||||
::GetModuleFileNameW(nullptr, wpath_exe, _MAX_PATH);
|
||||
boost::filesystem::path path_exe(wpath_exe);
|
||||
// Replace it with the current perl interpreter.
|
||||
result = boost::process::system((path_exe.parent_path() / "perl5.24.0.exe").string(), script, gcode_file);
|
||||
} else
|
||||
int result = run_script_win32(script, gcode_file.string());
|
||||
#else
|
||||
result = boost::process::system(script, gcode_file);
|
||||
//FIXME testing existence of a script is risky, as the script line may contain the script and some additional command line parameters.
|
||||
// We would have to process the script line into parameters before testing for the existence of the command, the command may be looked up
|
||||
// in the PATH etc.
|
||||
if (! boost::filesystem::exists(boost::filesystem::path(script)))
|
||||
throw std::runtime_error(std::string("The configured post-processing script does not exist: ") + script);
|
||||
struct stat info;
|
||||
if (stat(script.c_str(), &info))
|
||||
throw std::runtime_error(std::string("Cannot read information for post-processing script: ") + script);
|
||||
boost::filesystem::perms script_perms = boost::filesystem::status(script).permissions();
|
||||
//if UID matches, check UID perm. else if GID matches, check GID perm. Otherwise check other perm.
|
||||
if (!(script_perms & ((info.st_uid == geteuid()) ? boost::filesystem::perms::owner_exe
|
||||
: ((info.st_gid == getegid()) ? boost::filesystem::perms::group_exe
|
||||
: boost::filesystem::perms::others_exe))))
|
||||
throw std::runtime_error(std::string("The configured post-processing script is not executable: check permissions. ") + script);
|
||||
int result = boost::process::system(script, gcode_file);
|
||||
if (result < 0)
|
||||
BOOST_LOG_TRIVIAL(error) << "Script " << script << " on file " << path << " failed. Negative error code returned.";
|
||||
#endif
|
||||
if (result < 0)
|
||||
BOOST_LOG_TRIVIAL(error) << "Script " << script << " on file " << path << " failed. Negative error code returned.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <Shiny/Shiny.h>
|
||||
|
||||
|
@ -914,24 +914,80 @@ Transform3d assemble_transform(const Vec3d& translation, const Vec3d& rotation,
|
||||
|
||||
Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>& rotation_matrix)
|
||||
{
|
||||
// see: https://www.learnopencv.com/rotation-matrix-to-euler-angles/
|
||||
double sy = ::sqrt(sqr(rotation_matrix(0, 0)) + sqr(rotation_matrix(1, 0)));
|
||||
#if ENABLE_NEW_EULER_ANGLES
|
||||
// reference: http://www.gregslabaugh.net/publications/euler.pdf
|
||||
auto is_approx = [](double value, double test_value) -> bool { return std::abs(value - test_value) < EPSILON; };
|
||||
|
||||
Vec3d angles = Vec3d::Zero();
|
||||
|
||||
if (sy >= 1e-6)
|
||||
Vec3d angles1 = Vec3d::Zero();
|
||||
Vec3d angles2 = Vec3d::Zero();
|
||||
if (is_approx(std::abs(rotation_matrix(2, 0)), 1.0))
|
||||
{
|
||||
angles(0) = ::atan2(rotation_matrix(2, 1), rotation_matrix(2, 2));
|
||||
angles(1) = ::atan2(-rotation_matrix(2, 0), sy);
|
||||
angles(2) = ::atan2(rotation_matrix(1, 0), rotation_matrix(0, 0));
|
||||
angles1(0) = 0.0;
|
||||
if (rotation_matrix(2, 0) > 0.0) // == +1.0
|
||||
{
|
||||
angles1(1) = 0.5 * (double)PI;
|
||||
angles1(2) = angles1(0) + ::atan2(rotation_matrix(0, 1), rotation_matrix(0, 2));
|
||||
}
|
||||
else // == -1.0
|
||||
{
|
||||
angles1(1) = 0.5 * (double)PI;
|
||||
angles1(2) = -angles1(0) - ::atan2(rotation_matrix(0, 1), rotation_matrix(0, 2));
|
||||
}
|
||||
angles2 = angles1;
|
||||
}
|
||||
else
|
||||
{
|
||||
angles(1) = 0.0;
|
||||
angles(1) = ::atan2(-rotation_matrix(2, 0), sy);
|
||||
angles(2) = (angles(1) >-0.0) ? ::atan2(rotation_matrix(1, 2), rotation_matrix(1, 1)) : ::atan2(-rotation_matrix(1, 2), rotation_matrix(1, 1));
|
||||
angles1(1) = -::asin(rotation_matrix(2, 0));
|
||||
double inv_cos1 = 1.0 / ::cos(angles1(1));
|
||||
angles1(0) = ::atan2(rotation_matrix(2, 1) * inv_cos1, rotation_matrix(2, 2) * inv_cos1);
|
||||
angles1(2) = ::atan2(rotation_matrix(1, 0) * inv_cos1, rotation_matrix(0, 0) * inv_cos1);
|
||||
|
||||
angles2(1) = (double)PI - angles1(1);
|
||||
double inv_cos2 = 1.0 / ::cos(angles2(1));
|
||||
angles2(0) = ::atan2(rotation_matrix(2, 1) * inv_cos2, rotation_matrix(2, 2) * inv_cos2);
|
||||
angles2(2) = ::atan2(rotation_matrix(1, 0) * inv_cos2, rotation_matrix(0, 0) * inv_cos2);
|
||||
}
|
||||
|
||||
// The following euristic is the best found up to now (in the sense that it works fine with the greatest number of edge use-cases)
|
||||
// but there are other use-cases were it does not
|
||||
// We need to improve it
|
||||
double min_1 = angles1.cwiseAbs().minCoeff();
|
||||
double min_2 = angles2.cwiseAbs().minCoeff();
|
||||
bool use_1 = (min_1 < min_2) || (is_approx(min_1, min_2) && (angles1.norm() <= angles2.norm()));
|
||||
|
||||
Vec3d angles = use_1 ? angles1 : angles2;
|
||||
#else
|
||||
auto y_only = [](const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>& matrix) -> bool {
|
||||
return (matrix(0, 1) == 0.0) && (matrix(1, 0) == 0.0) && (matrix(1, 1) == 1.0) && (matrix(1, 2) == 0.0) && (matrix(2, 1) == 0.0);
|
||||
};
|
||||
|
||||
// see: https://www.learnopencv.com/rotation-matrix-to-euler-angles/
|
||||
double cy_abs = ::sqrt(sqr(rotation_matrix(0, 0)) + sqr(rotation_matrix(1, 0)));
|
||||
|
||||
Vec3d angles = Vec3d::Zero();
|
||||
|
||||
if (cy_abs >= 1e-6)
|
||||
{
|
||||
angles(0) = ::atan2(rotation_matrix(2, 1), rotation_matrix(2, 2));
|
||||
angles(1) = ::atan2(-rotation_matrix(2, 0), cy_abs);
|
||||
angles(2) = ::atan2(rotation_matrix(1, 0), rotation_matrix(0, 0));
|
||||
|
||||
// this is an hack to try to avoid this function to return "strange" values due to gimbal lock
|
||||
if (y_only(rotation_matrix) && (angles(0) == (double)PI) && (angles(2) == (double)PI))
|
||||
{
|
||||
angles(0) = 0.0;
|
||||
angles(1) = ::atan2(rotation_matrix(2, 0), cy_abs) - (double)PI;
|
||||
angles(2) = 0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
angles(0) = 0.0;
|
||||
angles(1) = ::atan2(-rotation_matrix(2, 0), cy_abs);
|
||||
angles(2) = (angles(1) >= 0.0) ? ::atan2(rotation_matrix(1, 2), rotation_matrix(1, 1)) : ::atan2(-rotation_matrix(1, 2), rotation_matrix(1, 1));
|
||||
}
|
||||
#endif // ENABLE_NEW_EULER_ANGLES
|
||||
|
||||
return angles;
|
||||
}
|
||||
|
||||
@ -968,13 +1024,18 @@ void Transformation::Flags::set(bool dont_translate, bool dont_rotate, bool dont
|
||||
}
|
||||
|
||||
Transformation::Transformation()
|
||||
#if !ENABLE_VOLUMES_CENTERING_FIXES
|
||||
: m_offset(Vec3d::Zero())
|
||||
, m_rotation(Vec3d::Zero())
|
||||
, m_scaling_factor(Vec3d::Ones())
|
||||
, m_mirror(Vec3d::Ones())
|
||||
, m_matrix(Transform3d::Identity())
|
||||
, m_dirty(false)
|
||||
#endif // !ENABLE_VOLUMES_CENTERING_FIXES
|
||||
{
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
reset();
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
}
|
||||
|
||||
Transformation::Transformation(const Transform3d& transform)
|
||||
@ -1093,6 +1154,18 @@ void Transformation::set_from_transform(const Transform3d& transform)
|
||||
// std::cout << "something went wrong in extracting data from matrix" << std::endl;
|
||||
}
|
||||
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
void Transformation::reset()
|
||||
{
|
||||
m_offset = Vec3d::Zero();
|
||||
m_rotation = Vec3d::Zero();
|
||||
m_scaling_factor = Vec3d::Ones();
|
||||
m_mirror = Vec3d::Ones();
|
||||
m_matrix = Transform3d::Identity();
|
||||
m_dirty = false;
|
||||
}
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
|
||||
const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
|
||||
{
|
||||
if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror))
|
||||
|
@ -221,6 +221,10 @@ public:
|
||||
|
||||
void set_from_transform(const Transform3d& transform);
|
||||
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
void reset();
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
|
||||
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const;
|
||||
|
||||
Transformation operator * (const Transformation& other) const;
|
||||
|
@ -570,7 +570,6 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
|
||||
this->sla_support_points = rhs.sla_support_points;
|
||||
this->layer_height_ranges = rhs.layer_height_ranges;
|
||||
this->layer_height_profile = rhs.layer_height_profile;
|
||||
this->layer_height_profile_valid = rhs.layer_height_profile_valid;
|
||||
this->origin_translation = rhs.origin_translation;
|
||||
m_bounding_box = rhs.m_bounding_box;
|
||||
m_bounding_box_valid = rhs.m_bounding_box_valid;
|
||||
@ -602,7 +601,6 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
|
||||
this->sla_support_points = std::move(rhs.sla_support_points);
|
||||
this->layer_height_ranges = std::move(rhs.layer_height_ranges);
|
||||
this->layer_height_profile = std::move(rhs.layer_height_profile);
|
||||
this->layer_height_profile_valid = std::move(rhs.layer_height_profile_valid);
|
||||
this->origin_translation = std::move(rhs.origin_translation);
|
||||
m_bounding_box = std::move(rhs.m_bounding_box);
|
||||
m_bounding_box_valid = std::move(rhs.m_bounding_box_valid);
|
||||
@ -641,6 +639,9 @@ ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh)
|
||||
{
|
||||
ModelVolume* v = new ModelVolume(this, mesh);
|
||||
this->volumes.push_back(v);
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
v->center_geometry();
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
this->invalidate_bounding_box();
|
||||
return v;
|
||||
}
|
||||
@ -649,6 +650,9 @@ ModelVolume* ModelObject::add_volume(TriangleMesh &&mesh)
|
||||
{
|
||||
ModelVolume* v = new ModelVolume(this, std::move(mesh));
|
||||
this->volumes.push_back(v);
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
v->center_geometry();
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
this->invalidate_bounding_box();
|
||||
return v;
|
||||
}
|
||||
@ -657,6 +661,9 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other)
|
||||
{
|
||||
ModelVolume* v = new ModelVolume(this, other);
|
||||
this->volumes.push_back(v);
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
v->center_geometry();
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
this->invalidate_bounding_box();
|
||||
return v;
|
||||
}
|
||||
@ -665,6 +672,9 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other, TriangleMesh &&me
|
||||
{
|
||||
ModelVolume* v = new ModelVolume(this, other, std::move(mesh));
|
||||
this->volumes.push_back(v);
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
v->center_geometry();
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
this->invalidate_bounding_box();
|
||||
return v;
|
||||
}
|
||||
@ -675,6 +685,23 @@ void ModelObject::delete_volume(size_t idx)
|
||||
delete *i;
|
||||
this->volumes.erase(i);
|
||||
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
if (this->volumes.size() == 1)
|
||||
{
|
||||
// only one volume left
|
||||
// we need to collapse the volume transform into the instances transforms because now when selecting this volume
|
||||
// it will be seen as a single full instance ans so its volume transform may be ignored
|
||||
ModelVolume* v = this->volumes.front();
|
||||
Transform3d v_t = v->get_transformation().get_matrix();
|
||||
for (ModelInstance* inst : this->instances)
|
||||
{
|
||||
inst->set_transformation(Geometry::Transformation(inst->get_transformation().get_matrix() * v_t));
|
||||
}
|
||||
Geometry::Transformation t;
|
||||
v->set_transformation(t);
|
||||
v->set_new_unique_id();
|
||||
}
|
||||
#else
|
||||
if (this->volumes.size() == 1)
|
||||
{
|
||||
// only one volume left
|
||||
@ -691,6 +718,7 @@ void ModelObject::delete_volume(size_t idx)
|
||||
v->set_offset(Vec3d::Zero());
|
||||
v->set_new_unique_id();
|
||||
}
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
|
||||
this->invalidate_bounding_box();
|
||||
}
|
||||
@ -819,14 +847,27 @@ TriangleMesh ModelObject::full_raw_mesh() const
|
||||
BoundingBoxf3 ModelObject::raw_bounding_box() const
|
||||
{
|
||||
BoundingBoxf3 bb;
|
||||
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
if (this->instances.empty())
|
||||
throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
|
||||
|
||||
const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true);
|
||||
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
for (const ModelVolume *v : this->volumes)
|
||||
if (v->is_model_part()) {
|
||||
#if !ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
if (this->instances.empty())
|
||||
throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
|
||||
#endif // !ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
|
||||
TriangleMesh vol_mesh(v->mesh);
|
||||
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
vol_mesh.transform(inst_matrix * v->get_matrix());
|
||||
bb.merge(vol_mesh.bounding_box());
|
||||
#else
|
||||
vol_mesh.transform(v->get_matrix());
|
||||
bb.merge(this->instances.front()->transform_mesh_bounding_box(vol_mesh, true));
|
||||
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
@ -835,27 +876,53 @@ BoundingBoxf3 ModelObject::raw_bounding_box() const
|
||||
BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_translate) const
|
||||
{
|
||||
BoundingBoxf3 bb;
|
||||
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
const Transform3d& inst_matrix = this->instances[instance_idx]->get_transformation().get_matrix(dont_translate);
|
||||
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
for (ModelVolume *v : this->volumes)
|
||||
{
|
||||
if (v->is_model_part())
|
||||
{
|
||||
TriangleMesh mesh(v->mesh);
|
||||
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
mesh.transform(inst_matrix * v->get_matrix());
|
||||
bb.merge(mesh.bounding_box());
|
||||
#else
|
||||
mesh.transform(v->get_matrix());
|
||||
bb.merge(this->instances[instance_idx]->transform_mesh_bounding_box(mesh, dont_translate));
|
||||
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
}
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
BoundingBoxf3 ModelObject::full_raw_mesh_bounding_box() const
|
||||
{
|
||||
BoundingBoxf3 bb;
|
||||
for (const ModelVolume *v : this->volumes)
|
||||
{
|
||||
TriangleMesh vol_mesh(v->mesh);
|
||||
vol_mesh.transform(v->get_matrix());
|
||||
bb.merge(vol_mesh.bounding_box());
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
|
||||
void ModelObject::center_around_origin()
|
||||
{
|
||||
// calculate the displacements needed to
|
||||
// center this object around the origin
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
BoundingBoxf3 bb = full_raw_mesh_bounding_box();
|
||||
#else
|
||||
BoundingBoxf3 bb;
|
||||
for (ModelVolume *v : this->volumes)
|
||||
if (v->is_model_part())
|
||||
bb.merge(v->mesh.bounding_box());
|
||||
|
||||
bb.merge(v->mesh.bounding_box());
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
|
||||
// Shift is the vector from the center of the bounding box to the origin
|
||||
Vec3d shift = -bb.center();
|
||||
|
||||
@ -1021,7 +1088,8 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
||||
|
||||
if (keep_upper) { upper->add_volume(*volume); }
|
||||
if (keep_lower) { lower->add_volume(*volume); }
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
TriangleMesh upper_mesh, lower_mesh;
|
||||
|
||||
// Transform the mesh by the combined transformation matrix
|
||||
@ -1046,14 +1114,14 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
||||
}
|
||||
|
||||
if (keep_upper && upper_mesh.facets_count() > 0) {
|
||||
ModelVolume* vol = upper->add_volume(upper_mesh);
|
||||
vol->name = volume->name;
|
||||
ModelVolume* vol = upper->add_volume(upper_mesh);
|
||||
vol->name = volume->name;
|
||||
vol->config = volume->config;
|
||||
vol->set_material(volume->material_id(), *volume->material());
|
||||
}
|
||||
if (keep_lower && lower_mesh.facets_count() > 0) {
|
||||
ModelVolume* vol = lower->add_volume(lower_mesh);
|
||||
vol->name = volume->name;
|
||||
ModelVolume* vol = lower->add_volume(lower_mesh);
|
||||
vol->name = volume->name;
|
||||
vol->config = volume->config;
|
||||
vol->set_material(volume->material_id(), *volume->material());
|
||||
|
||||
@ -1132,7 +1200,9 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
||||
for (const ModelInstance *model_instance : this->instances)
|
||||
new_object->add_instance(*model_instance);
|
||||
ModelVolume* new_vol = new_object->add_volume(*volume, std::move(*mesh));
|
||||
#if !ENABLE_VOLUMES_CENTERING_FIXES
|
||||
new_vol->center_geometry();
|
||||
#endif // !ENABLE_VOLUMES_CENTERING_FIXES
|
||||
|
||||
for (ModelInstance* model_instance : new_object->instances)
|
||||
{
|
||||
@ -1300,10 +1370,20 @@ int ModelVolume::extruder_id() const
|
||||
|
||||
void ModelVolume::center_geometry()
|
||||
{
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
Vec3d shift = mesh.bounding_box().center();
|
||||
if (!shift.isApprox(Vec3d::Zero()))
|
||||
{
|
||||
mesh.translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
|
||||
m_convex_hull.translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
|
||||
translate(shift);
|
||||
}
|
||||
#else
|
||||
Vec3d shift = -mesh.bounding_box().center();
|
||||
mesh.translate((float)shift(0), (float)shift(1), (float)shift(2));
|
||||
m_convex_hull.translate((float)shift(0), (float)shift(1), (float)shift(2));
|
||||
translate(-shift);
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
}
|
||||
|
||||
void ModelVolume::calculate_convex_hull()
|
||||
|
@ -170,12 +170,8 @@ public:
|
||||
// Variation of a layer thickness for spans of Z coordinates.
|
||||
t_layer_height_ranges layer_height_ranges;
|
||||
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
|
||||
// The pairs of <z, layer_height> are packed into a 1D array to simplify handling by the Perl XS.
|
||||
// The pairs of <z, layer_height> are packed into a 1D array.
|
||||
std::vector<coordf_t> layer_height_profile;
|
||||
// layer_height_profile is initialized when the layer editing mode is entered.
|
||||
// Only if the user really modified the layer height, layer_height_profile_valid is set
|
||||
// and used subsequently by the PrintObject.
|
||||
bool layer_height_profile_valid;
|
||||
|
||||
// This vector holds position of selected support points for SLA. The data are
|
||||
// saved in mesh coordinates to allow using them for several instances.
|
||||
@ -223,6 +219,10 @@ public:
|
||||
BoundingBoxf3 raw_bounding_box() const;
|
||||
// A snug bounding box around the transformed non-modifier object volumes.
|
||||
BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate = false) const;
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
// Bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.
|
||||
BoundingBoxf3 full_raw_mesh_bounding_box() const;
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
void center_around_origin();
|
||||
void ensure_on_bed();
|
||||
void translate_instances(const Vec3d& vector);
|
||||
@ -261,7 +261,7 @@ protected:
|
||||
void set_model(Model *model) { m_model = model; }
|
||||
|
||||
private:
|
||||
ModelObject(Model *model) : layer_height_profile_valid(false), m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {}
|
||||
ModelObject(Model *model) : m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {}
|
||||
~ModelObject();
|
||||
|
||||
/* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */
|
||||
@ -319,6 +319,9 @@ public:
|
||||
// Extruder ID is only valid for FFF. Returns -1 for SLA or if the extruder ID is not applicable (support volumes).
|
||||
int extruder_id() const;
|
||||
|
||||
void set_splittable(const int val) { m_is_splittable = val; }
|
||||
int is_splittable() const { return m_is_splittable; }
|
||||
|
||||
// Split this volume, append the result to the object owning this volume.
|
||||
// Return the number of volumes created from this one.
|
||||
// This is useful to assign different materials to different volumes of an object.
|
||||
@ -391,6 +394,12 @@ private:
|
||||
TriangleMesh m_convex_hull;
|
||||
Geometry::Transformation m_transformation;
|
||||
|
||||
// flag to optimize the checking if the volume is splittable
|
||||
// -1 -> is unknown value (before first cheking)
|
||||
// 0 -> is not splittable
|
||||
// 1 -> is splittable
|
||||
int m_is_splittable {-1};
|
||||
|
||||
ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(MODEL_PART), object(object)
|
||||
{
|
||||
if (mesh.stl.stats.number_of_facets > 1)
|
||||
|
@ -15,6 +15,7 @@ namespace arr {
|
||||
|
||||
using namespace libnest2d;
|
||||
|
||||
// Only for debugging. Prints the model object vertices on stdout.
|
||||
std::string toString(const Model& model, bool holes = true) {
|
||||
std::stringstream ss;
|
||||
|
||||
@ -78,6 +79,7 @@ std::string toString(const Model& model, bool holes = true) {
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// Debugging: Save model to svg file.
|
||||
void toSVG(SVG& svg, const Model& model) {
|
||||
for(auto objptr : model.objects) {
|
||||
if(!objptr) continue;
|
||||
@ -121,6 +123,10 @@ Box boundingBox(const Box& pilebb, const Box& ibb ) {
|
||||
return Box(minc, maxc);
|
||||
}
|
||||
|
||||
// This is "the" object function which is evaluated many times for each vertex
|
||||
// (decimated with the accuracy parameter) of each object. Therefore it is
|
||||
// upmost crucial for this function to be as efficient as it possibly can be but
|
||||
// at the same time, it has to provide reasonable results.
|
||||
std::tuple<double /*score*/, Box /*farthest point from bin center*/>
|
||||
objfunc(const PointImpl& bincenter,
|
||||
const shapelike::Shapes<PolygonImpl>& merged_pile,
|
||||
@ -253,6 +259,8 @@ objfunc(const PointImpl& bincenter,
|
||||
return std::make_tuple(score, fullbb);
|
||||
}
|
||||
|
||||
// Fill in the placer algorithm configuration with values carefully chosen for
|
||||
// Slic3r.
|
||||
template<class PConf>
|
||||
void fillConfig(PConf& pcfg) {
|
||||
|
||||
@ -274,13 +282,19 @@ void fillConfig(PConf& pcfg) {
|
||||
pcfg.parallel = true;
|
||||
}
|
||||
|
||||
// Type trait for an arranger class for different bin types (box, circle,
|
||||
// polygon, etc...)
|
||||
template<class TBin>
|
||||
class AutoArranger {};
|
||||
|
||||
|
||||
// A class encapsulating the libnest2d Nester class and extending it with other
|
||||
// management and spatial index structures for acceleration.
|
||||
template<class TBin>
|
||||
class _ArrBase {
|
||||
protected:
|
||||
|
||||
// Useful type shortcuts...
|
||||
using Placer = TPacker<TBin>;
|
||||
using Selector = FirstFitSelection;
|
||||
using Packer = Nester<Placer, Selector>;
|
||||
@ -289,15 +303,15 @@ protected:
|
||||
using Pile = sl::Shapes<PolygonImpl>;
|
||||
|
||||
Packer m_pck;
|
||||
PConfig m_pconf; // Placement configuration
|
||||
PConfig m_pconf; // Placement configuration
|
||||
double m_bin_area;
|
||||
SpatIndex m_rtree;
|
||||
SpatIndex m_smallsrtree;
|
||||
double m_norm;
|
||||
Pile m_merged_pile;
|
||||
Box m_pilebb;
|
||||
ItemGroup m_remaining;
|
||||
ItemGroup m_items;
|
||||
SpatIndex m_rtree; // spatial index for the normal (bigger) objects
|
||||
SpatIndex m_smallsrtree; // spatial index for only the smaller items
|
||||
double m_norm; // A coefficient to scale distances
|
||||
Pile m_merged_pile; // The already merged pile (vector of items)
|
||||
Box m_pilebb; // The bounding box of the merged pile.
|
||||
ItemGroup m_remaining; // Remaining items (m_items at the beginning)
|
||||
ItemGroup m_items; // The items to be packed
|
||||
public:
|
||||
|
||||
_ArrBase(const TBin& bin, Distance dist,
|
||||
@ -308,6 +322,8 @@ public:
|
||||
{
|
||||
fillConfig(m_pconf);
|
||||
|
||||
// Set up a callback that is called just before arranging starts
|
||||
// This functionality is provided by the Nester class (m_pack).
|
||||
m_pconf.before_packing =
|
||||
[this](const Pile& merged_pile, // merged pile
|
||||
const ItemGroup& items, // packed items
|
||||
@ -344,8 +360,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class AutoArranger<Box>: public _ArrBase<Box> {
|
||||
// Arranger specialization for a Box shaped bin.
|
||||
template<> class AutoArranger<Box>: public _ArrBase<Box> {
|
||||
public:
|
||||
|
||||
AutoArranger(const Box& bin, Distance dist,
|
||||
@ -354,6 +370,9 @@ public:
|
||||
_ArrBase<Box>(bin, dist, progressind, stopcond)
|
||||
{
|
||||
|
||||
// Here we set up the actual object function that calls the common
|
||||
// object function for all bin shapes than does an additional inside
|
||||
// check for the arranged pile.
|
||||
m_pconf.object_function = [this, bin] (const Item &item) {
|
||||
|
||||
auto result = objfunc(bin.center(),
|
||||
@ -387,8 +406,8 @@ inline lnCircle to_lnCircle(const Circle& circ) {
|
||||
return lnCircle({circ.center()(0), circ.center()(1)}, circ.radius());
|
||||
}
|
||||
|
||||
template<>
|
||||
class AutoArranger<lnCircle>: public _ArrBase<lnCircle> {
|
||||
// Arranger specialization for circle shaped bin.
|
||||
template<> class AutoArranger<lnCircle>: public _ArrBase<lnCircle> {
|
||||
public:
|
||||
|
||||
AutoArranger(const lnCircle& bin, Distance dist,
|
||||
@ -396,6 +415,7 @@ public:
|
||||
std::function<bool(void)> stopcond):
|
||||
_ArrBase<lnCircle>(bin, dist, progressind, stopcond) {
|
||||
|
||||
// As with the box, only the inside check is different.
|
||||
m_pconf.object_function = [this, &bin] (const Item &item) {
|
||||
|
||||
auto result = objfunc(bin.center(),
|
||||
@ -431,8 +451,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class AutoArranger<PolygonImpl>: public _ArrBase<PolygonImpl> {
|
||||
// Arranger specialization for a generalized polygon.
|
||||
// Warning: this is unfinished business. It may or may not work.
|
||||
template<> class AutoArranger<PolygonImpl>: public _ArrBase<PolygonImpl> {
|
||||
public:
|
||||
AutoArranger(const PolygonImpl& bin, Distance dist,
|
||||
std::function<void(unsigned)> progressind,
|
||||
@ -461,8 +482,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<> // Specialization with no bin
|
||||
class AutoArranger<bool>: public _ArrBase<Box> {
|
||||
// Specialization with no bin. In this case the arranger should just arrange
|
||||
// all objects into a minimum sized pile but it is not limited by a bin. A
|
||||
// consequence is that only one pile should be created.
|
||||
template<> class AutoArranger<bool>: public _ArrBase<Box> {
|
||||
public:
|
||||
|
||||
AutoArranger(Distance dist, std::function<void(unsigned)> progressind,
|
||||
@ -490,14 +513,15 @@ public:
|
||||
|
||||
// A container which stores a pointer to the 3D object and its projected
|
||||
// 2D shape from top view.
|
||||
using ShapeData2D =
|
||||
std::vector<std::pair<Slic3r::ModelInstance*, Item>>;
|
||||
using ShapeData2D = std::vector<std::pair<Slic3r::ModelInstance*, Item>>;
|
||||
|
||||
ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
|
||||
ShapeData2D ret;
|
||||
|
||||
auto s = std::accumulate(model.objects.begin(), model.objects.end(), size_t(0),
|
||||
[](size_t s, ModelObject* o){
|
||||
// Count all the items on the bin (all the object's instances)
|
||||
auto s = std::accumulate(model.objects.begin(), model.objects.end(),
|
||||
size_t(0), [](size_t s, ModelObject* o)
|
||||
{
|
||||
return s + o->instances.size();
|
||||
});
|
||||
|
||||
@ -517,7 +541,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
|
||||
rmesh.rotate_x(float(finst->get_rotation()(X)));
|
||||
rmesh.rotate_y(float(finst->get_rotation()(Y)));
|
||||
|
||||
// TODO export the exact 2D projection
|
||||
// TODO export the exact 2D projection. Cannot do it as libnest2d
|
||||
// does not support concave shapes (yet).
|
||||
auto p = rmesh.convex_hull();
|
||||
|
||||
p.make_clockwise();
|
||||
@ -549,6 +574,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Apply the calculated translations and rotations (currently disabled) to the
|
||||
// Model object instances.
|
||||
void applyResult(
|
||||
IndexedPackGroup::value_type& group,
|
||||
Coord batch_offset,
|
||||
@ -576,6 +603,7 @@ void applyResult(
|
||||
}
|
||||
}
|
||||
|
||||
// Get the type of bed geometry from a simple vector of points.
|
||||
BedShapeHint bedShape(const Polyline &bed) {
|
||||
BedShapeHint ret;
|
||||
|
||||
@ -654,11 +682,15 @@ BedShapeHint bedShape(const Polyline &bed) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool arrange(Model &model,
|
||||
coord_t min_obj_distance,
|
||||
const Polyline &bed,
|
||||
BedShapeHint bedhint,
|
||||
bool first_bin_only,
|
||||
// The final client function to arrange the Model. A progress indicator and
|
||||
// a stop predicate can be also be passed to control the process.
|
||||
bool arrange(Model &model, // The model with the geometries
|
||||
coord_t min_obj_distance, // Has to be in scaled (clipper) measure
|
||||
const Polyline &bed, // The bed geometry.
|
||||
BedShapeHint bedhint, // Hint about the bed geometry type.
|
||||
bool first_bin_only, // What to do is not all items fit.
|
||||
|
||||
// Controlling callbacks.
|
||||
std::function<void (unsigned)> progressind,
|
||||
std::function<bool ()> stopcondition)
|
||||
{
|
||||
|
@ -243,6 +243,26 @@ std::vector<Point> MultiPoint::_douglas_peucker(const std::vector<Point>& pts, c
|
||||
floater = &pts[floater_idx];
|
||||
}
|
||||
}
|
||||
assert(result_pts.front() == pts.front());
|
||||
assert(result_pts.back() == pts.back());
|
||||
|
||||
#if 0
|
||||
{
|
||||
static int iRun = 0;
|
||||
BoundingBox bbox(pts);
|
||||
BoundingBox bbox2(result_pts);
|
||||
bbox.merge(bbox2);
|
||||
SVG svg(debug_out_path("douglas_peucker_%d.svg", iRun ++).c_str(), bbox);
|
||||
if (pts.front() == pts.back())
|
||||
svg.draw(Polygon(pts), "black");
|
||||
else
|
||||
svg.draw(Polyline(pts), "black");
|
||||
if (result_pts.front() == result_pts.back())
|
||||
svg.draw(Polygon(result_pts), "green", scale_(0.1));
|
||||
else
|
||||
svg.draw(Polyline(result_pts), "green", scale_(0.1));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return result_pts;
|
||||
}
|
||||
|
@ -270,9 +270,22 @@ namespace client
|
||||
{
|
||||
std::string out;
|
||||
switch (type) {
|
||||
case TYPE_BOOL: out = boost::to_string(data.b); break;
|
||||
case TYPE_INT: out = boost::to_string(data.i); break;
|
||||
case TYPE_DOUBLE: out = boost::to_string(data.d); break;
|
||||
case TYPE_BOOL: out = data.b ? "true" : "false"; break;
|
||||
case TYPE_INT: out = std::to_string(data.i); break;
|
||||
case TYPE_DOUBLE:
|
||||
#if 0
|
||||
// The default converter produces trailing zeros after the decimal point.
|
||||
out = std::to_string(data.d);
|
||||
#else
|
||||
// ostringstream default converter produces no trailing zeros after the decimal point.
|
||||
// It seems to be doing what the old boost::to_string() did.
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << data.d;
|
||||
out = ss.str();
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case TYPE_STRING: out = *data.s; break;
|
||||
default: break;
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ public:
|
||||
|
||||
Point& operator+=(const Point& rhs) { (*this)(0) += rhs(0); (*this)(1) += rhs(1); return *this; }
|
||||
Point& operator-=(const Point& rhs) { (*this)(0) -= rhs(0); (*this)(1) -= rhs(1); return *this; }
|
||||
Point& operator*=(const double &rhs) { (*this)(0) *= rhs; (*this)(1) *= rhs; return *this; }
|
||||
Point& operator*=(const double &rhs) { (*this)(0) = coord_t((*this)(0) * rhs); (*this)(1) = coord_t((*this)(1) * rhs); return *this; }
|
||||
|
||||
void rotate(double angle);
|
||||
void rotate(double angle, const Point ¢er);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "PrintExport.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <unordered_set>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
@ -292,18 +293,8 @@ std::vector<unsigned int> Print::object_extruders() const
|
||||
{
|
||||
std::vector<unsigned int> extruders;
|
||||
extruders.reserve(m_regions.size() * 3);
|
||||
|
||||
for (const PrintRegion *region : m_regions) {
|
||||
// these checks reflect the same logic used in the GUI for enabling/disabling
|
||||
// extruder selection fields
|
||||
if (region->config().perimeters.value > 0 || m_config.brim_width.value > 0)
|
||||
extruders.emplace_back(region->config().perimeter_extruder - 1);
|
||||
if (region->config().fill_density.value > 0)
|
||||
extruders.emplace_back(region->config().infill_extruder - 1);
|
||||
if (region->config().top_solid_layers.value > 0 || region->config().bottom_solid_layers.value > 0)
|
||||
extruders.emplace_back(region->config().solid_infill_extruder - 1);
|
||||
}
|
||||
|
||||
for (const PrintRegion *region : m_regions)
|
||||
region->collect_object_printing_extruders(extruders);
|
||||
sort_remove_duplicates(extruders);
|
||||
return extruders;
|
||||
}
|
||||
@ -371,37 +362,6 @@ double Print::max_allowed_layer_height() const
|
||||
return nozzle_diameter_max;
|
||||
}
|
||||
|
||||
static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders)
|
||||
{
|
||||
if (opt.value > (int)num_extruders)
|
||||
// assign the default extruder
|
||||
opt.value = 1;
|
||||
}
|
||||
|
||||
static PrintObjectConfig object_config_from_model(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders)
|
||||
{
|
||||
PrintObjectConfig config = default_object_config;
|
||||
normalize_and_apply_config(config, object.config);
|
||||
// Clamp invalid extruders to the default extruder (with index 1).
|
||||
clamp_exturder_to_default(config.support_material_extruder, num_extruders);
|
||||
clamp_exturder_to_default(config.support_material_interface_extruder, num_extruders);
|
||||
return config;
|
||||
}
|
||||
|
||||
static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders)
|
||||
{
|
||||
PrintRegionConfig config = default_region_config;
|
||||
normalize_and_apply_config(config, volume.get_object()->config);
|
||||
normalize_and_apply_config(config, volume.config);
|
||||
if (! volume.material_id().empty())
|
||||
normalize_and_apply_config(config, volume.material()->config);
|
||||
// Clamp invalid extruders to the default extruder (with index 1).
|
||||
clamp_exturder_to_default(config.infill_extruder, num_extruders);
|
||||
clamp_exturder_to_default(config.perimeter_extruder, num_extruders);
|
||||
clamp_exturder_to_default(config.solid_infill_extruder, num_extruders);
|
||||
return config;
|
||||
}
|
||||
|
||||
// Caller is responsible for supplying models whose objects don't collide
|
||||
// and have explicit instance positions.
|
||||
void Print::add_model_object(ModelObject* model_object, int idx)
|
||||
@ -438,7 +398,7 @@ void Print::add_model_object(ModelObject* model_object, int idx)
|
||||
if (! volume->is_model_part() && ! volume->is_modifier())
|
||||
continue;
|
||||
// Get the config applied to this volume.
|
||||
PrintRegionConfig config = region_config_from_model_volume(m_default_region_config, *volume, 99999);
|
||||
PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, *volume, 99999);
|
||||
// Find an existing print region with the same config.
|
||||
size_t region_id = size_t(-1);
|
||||
for (size_t i = 0; i < m_regions.size(); ++ i)
|
||||
@ -519,12 +479,12 @@ bool Print::apply_config(DynamicPrintConfig config)
|
||||
// If the new config for this volume differs from the other
|
||||
// volume configs currently associated to this region, it means
|
||||
// the region subdivision does not make sense anymore.
|
||||
if (! this_region_config.equals(region_config_from_model_volume(m_default_region_config, volume, 99999))) {
|
||||
if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, volume, 99999))) {
|
||||
rearrange_regions = true;
|
||||
goto exit_for_rearrange_regions;
|
||||
}
|
||||
} else {
|
||||
this_region_config = region_config_from_model_volume(m_default_region_config, volume, 99999);
|
||||
this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, volume, 99999);
|
||||
this_region_config_set = true;
|
||||
}
|
||||
for (const PrintRegionConfig &cfg : other_region_configs) {
|
||||
@ -568,10 +528,6 @@ exit_for_rearrange_regions:
|
||||
invalidated = true;
|
||||
}
|
||||
|
||||
// Always make sure that the layer_height_profiles are set, as they should not be modified from the worker threads.
|
||||
for (PrintObject *object : m_objects)
|
||||
object->update_layer_height_profile();
|
||||
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
@ -893,8 +849,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
||||
if (model_parts_differ || modifiers_differ ||
|
||||
model_object.origin_translation != model_object_new.origin_translation ||
|
||||
model_object.layer_height_ranges != model_object_new.layer_height_ranges ||
|
||||
model_object.layer_height_profile != model_object_new.layer_height_profile ||
|
||||
model_object.layer_height_profile_valid != model_object_new.layer_height_profile_valid) {
|
||||
model_object.layer_height_profile != model_object_new.layer_height_profile) {
|
||||
// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
|
||||
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
||||
for (auto it = range.first; it != range.second; ++ it) {
|
||||
@ -920,7 +875,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
||||
if (object_config_changed)
|
||||
model_object.config = model_object_new.config;
|
||||
if (! object_diff.empty() || object_config_changed) {
|
||||
PrintObjectConfig new_config = object_config_from_model(m_default_object_config, model_object, num_extruders);
|
||||
PrintObjectConfig new_config = PrintObject::object_config_from_model_object(m_default_object_config, model_object, num_extruders);
|
||||
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
||||
for (auto it = range.first; it != range.second; ++ it) {
|
||||
t_config_option_keys diff = it->print_object->config().diff(new_config);
|
||||
@ -962,7 +917,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
||||
old.emplace_back(&(*it));
|
||||
}
|
||||
// Generate a list of trafos and XY offsets for instances of a ModelObject
|
||||
PrintObjectConfig config = object_config_from_model(m_default_object_config, *model_object, num_extruders);
|
||||
PrintObjectConfig config = PrintObject::object_config_from_model_object(m_default_object_config, *model_object, num_extruders);
|
||||
std::vector<PrintInstances> new_print_instances = print_objects_from_model_object(*model_object);
|
||||
if (old.empty()) {
|
||||
// Simple case, just generate new instances.
|
||||
@ -1053,11 +1008,11 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
||||
// If the new config for this volume differs from the other
|
||||
// volume configs currently associated to this region, it means
|
||||
// the region subdivision does not make sense anymore.
|
||||
if (! this_region_config.equals(region_config_from_model_volume(m_default_region_config, volume, num_extruders)))
|
||||
if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, volume, num_extruders)))
|
||||
// Regions were split. Reset this print_object.
|
||||
goto print_object_end;
|
||||
} else {
|
||||
this_region_config = region_config_from_model_volume(m_default_region_config, volume, num_extruders);
|
||||
this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, volume, num_extruders);
|
||||
for (size_t i = 0; i < region_id; ++i) {
|
||||
const PrintRegion ®ion_other = *m_regions[i];
|
||||
if (region_other.m_refcnt != 0 && region_other.config().equals(this_region_config))
|
||||
@ -1108,7 +1063,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
||||
int region_id = -1;
|
||||
if (&print_object == &print_object0) {
|
||||
// Get the config applied to this volume.
|
||||
PrintRegionConfig config = region_config_from_model_volume(m_default_region_config, *volume, num_extruders);
|
||||
PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, *volume, num_extruders);
|
||||
// Find an existing print region with the same config.
|
||||
int idx_empty_slot = -1;
|
||||
for (int i = 0; i < (int)m_regions.size(); ++ i) {
|
||||
@ -1144,13 +1099,6 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
||||
}
|
||||
}
|
||||
|
||||
// Always make sure that the layer_height_profiles are set, as they should not be modified from the worker threads.
|
||||
for (PrintObject *object : m_objects)
|
||||
if (! object->layer_height_profile_valid)
|
||||
// No need to call the next line as the step should already be invalidated above.
|
||||
// update_apply_status(object->invalidate_step(posSlice));
|
||||
object->update_layer_height_profile();
|
||||
|
||||
//FIXME there may be a race condition with the G-code export running at the background thread.
|
||||
this->update_object_placeholders();
|
||||
|
||||
@ -1183,7 +1131,7 @@ std::string Print::validate() const
|
||||
// Check horizontal clearance.
|
||||
{
|
||||
Polygons convex_hulls_other;
|
||||
for (PrintObject *object : m_objects) {
|
||||
for (const PrintObject *object : m_objects) {
|
||||
// Get convex hull of all meshes assigned to this print object.
|
||||
Polygon convex_hull;
|
||||
{
|
||||
@ -1244,15 +1192,24 @@ std::string Print::validate() const
|
||||
return L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter and Repetier G-code flavors.");
|
||||
if (! m_config.use_relative_e_distances)
|
||||
return L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).");
|
||||
|
||||
if (m_objects.size() > 1) {
|
||||
bool has_custom_layering = false;
|
||||
std::vector<std::vector<coordf_t>> layer_height_profiles;
|
||||
for (const PrintObject *object : m_objects) {
|
||||
has_custom_layering = ! object->model_object()->layer_height_ranges.empty() || ! object->model_object()->layer_height_profile.empty();
|
||||
if (has_custom_layering) {
|
||||
layer_height_profiles.assign(m_objects.size(), std::vector<coordf_t>());
|
||||
break;
|
||||
}
|
||||
}
|
||||
SlicingParameters slicing_params0 = m_objects.front()->slicing_parameters();
|
||||
|
||||
const PrintObject* tallest_object = m_objects.front(); // let's find the tallest object
|
||||
for (const auto* object : m_objects)
|
||||
if (*(object->layer_height_profile.end()-2) > *(tallest_object->layer_height_profile.end()-2) )
|
||||
tallest_object = object;
|
||||
|
||||
for (PrintObject *object : m_objects) {
|
||||
SlicingParameters slicing_params = object->slicing_parameters();
|
||||
size_t tallest_object_idx = 0;
|
||||
if (has_custom_layering)
|
||||
PrintObject::update_layer_height_profile(*m_objects.front()->model_object(), slicing_params0, layer_height_profiles.front());
|
||||
for (size_t i = 1; i < m_objects.size(); ++ i) {
|
||||
const PrintObject *object = m_objects[i];
|
||||
const SlicingParameters slicing_params = object->slicing_parameters();
|
||||
if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON ||
|
||||
std::abs(slicing_params.layer_height - slicing_params0.layer_height ) > EPSILON)
|
||||
return L("The Wipe Tower is only supported for multiple objects if they have equal layer heigths");
|
||||
@ -1264,42 +1221,54 @@ std::string Print::validate() const
|
||||
return L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance");
|
||||
if (! equal_layering(slicing_params, slicing_params0))
|
||||
return L("The Wipe Tower is only supported for multiple objects if they are sliced equally.");
|
||||
if (has_custom_layering) {
|
||||
PrintObject::update_layer_height_profile(*object->model_object(), slicing_params, layer_height_profiles[i]);
|
||||
if (*(layer_height_profiles[i].end()-2) > *(layer_height_profiles[tallest_object_idx].end()-2))
|
||||
tallest_object_idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_config.variable_layer_height ) { // comparing layer height profiles
|
||||
if (has_custom_layering) {
|
||||
const std::vector<coordf_t> &layer_height_profile_tallest = layer_height_profiles[tallest_object_idx];
|
||||
for (size_t idx_object = 0; idx_object < m_objects.size(); ++ idx_object) {
|
||||
const PrintObject *object = m_objects[idx_object];
|
||||
const std::vector<coordf_t> &layer_height_profile = layer_height_profiles[idx_object];
|
||||
bool failed = false;
|
||||
// layer_height_profile should be set by Print::apply().
|
||||
if (tallest_object->layer_height_profile.size() >= object->layer_height_profile.size() ) {
|
||||
if (layer_height_profile_tallest.size() >= layer_height_profile.size()) {
|
||||
int i = 0;
|
||||
while ( i < object->layer_height_profile.size() && i < tallest_object->layer_height_profile.size()) {
|
||||
if (std::abs(tallest_object->layer_height_profile[i] - object->layer_height_profile[i])) {
|
||||
while (i < layer_height_profile.size() && i < layer_height_profile_tallest.size()) {
|
||||
if (std::abs(layer_height_profile_tallest[i] - layer_height_profile[i])) {
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
if (i == object->layer_height_profile.size()-2) // this element contains this objects max z
|
||||
if (tallest_object->layer_height_profile[i] > object->layer_height_profile[i]) // the difference does not matter in this case
|
||||
++i;
|
||||
++ i;
|
||||
if (i == layer_height_profile.size() - 2) // this element contains this objects max z
|
||||
if (layer_height_profile_tallest[i] > layer_height_profile[i]) // the difference does not matter in this case
|
||||
++ i;
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
failed = true;
|
||||
|
||||
if (failed)
|
||||
return L("The Wipe tower is only supported if all objects have the same layer height profile");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// find the smallest nozzle diameter
|
||||
std::vector<unsigned int> extruders = this->extruders();
|
||||
if (extruders.empty())
|
||||
return L("The supplied settings will cause an empty print.");
|
||||
|
||||
std::vector<double> nozzle_diameters;
|
||||
for (unsigned int extruder_id : extruders)
|
||||
nozzle_diameters.push_back(m_config.nozzle_diameter.get_at(extruder_id));
|
||||
double min_nozzle_diameter = *std::min_element(nozzle_diameters.begin(), nozzle_diameters.end());
|
||||
|
||||
// Find the smallest used nozzle diameter and the number of unique nozzle diameters.
|
||||
double min_nozzle_diameter = std::numeric_limits<double>::max();
|
||||
double max_nozzle_diameter = 0;
|
||||
for (unsigned int extruder_id : extruders) {
|
||||
double dmr = m_config.nozzle_diameter.get_at(extruder_id);
|
||||
min_nozzle_diameter = std::min(min_nozzle_diameter, dmr);
|
||||
max_nozzle_diameter = std::max(max_nozzle_diameter, dmr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// We currently allow one to assign extruders with a higher index than the number
|
||||
@ -1311,16 +1280,28 @@ std::string Print::validate() const
|
||||
#endif
|
||||
|
||||
for (PrintObject *object : m_objects) {
|
||||
if ((object->config().support_material_extruder == -1 || object->config().support_material_interface_extruder == -1) &&
|
||||
(object->config().raft_layers > 0 || object->config().support_material.value)) {
|
||||
if (object->config().raft_layers > 0 || object->config().support_material.value) {
|
||||
if ((object->config().support_material_extruder == 0 || object->config().support_material_interface_extruder == 0) && max_nozzle_diameter - min_nozzle_diameter > EPSILON) {
|
||||
// The object has some form of support and either support_material_extruder or support_material_interface_extruder
|
||||
// will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles
|
||||
// are of the same diameter.
|
||||
if (nozzle_diameters.size() > 1)
|
||||
return L("Printing with multiple extruders of differing nozzle diameters. "
|
||||
"If support is to be printed with the current extruder (support_material_extruder == 0 or support_material_interface_extruder == 0), "
|
||||
"all nozzles have to be of the same diameter.");
|
||||
}
|
||||
if (this->has_wipe_tower()) {
|
||||
if (object->config().support_material_contact_distance == 0) {
|
||||
// Soluble interface
|
||||
if (object->config().support_material_contact_distance == 0 && ! object->config().support_material_synchronize_layers)
|
||||
return L("For the Wipe Tower to work with the soluble supports, the support layers need to be synchronized with the object layers.");
|
||||
} else {
|
||||
// Non-soluble interface
|
||||
if (object->config().support_material_extruder != 0 || object->config().support_material_interface_extruder != 0)
|
||||
return L("The Wipe Tower currently supports the non-soluble supports only if they are printed with the current extruder without triggering a tool change. "
|
||||
"(both support_material_extruder and support_material_interface_extruder need to be set to 0).");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// validate first_layer_height
|
||||
double first_layer_height = object->config().get_abs_value(L("first_layer_height"));
|
||||
|
@ -45,6 +45,10 @@ public:
|
||||
// Average diameter of nozzles participating on extruding this region.
|
||||
coordf_t bridging_height_avg(const PrintConfig &print_config) const;
|
||||
|
||||
// Collect extruder indices used to print this region's object.
|
||||
void collect_object_printing_extruders(std::vector<unsigned int> &object_extruders) const;
|
||||
static void collect_object_printing_extruders(const PrintConfig &print_config, const PrintRegionConfig ®ion_config, std::vector<unsigned int> &object_extruders);
|
||||
|
||||
// Methods modifying the PrintRegion's state:
|
||||
public:
|
||||
Print* print() { return m_print; }
|
||||
@ -79,16 +83,6 @@ public:
|
||||
// vector of (vectors of volume ids), indexed by region_id
|
||||
std::vector<std::vector<int>> region_volumes;
|
||||
|
||||
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
|
||||
// The pairs of <z, layer_height> are packed into a 1D array to simplify handling by the Perl XS.
|
||||
// layer_height_profile must not be set by the background thread.
|
||||
std::vector<coordf_t> layer_height_profile;
|
||||
// There is a layer_height_profile at both PrintObject and ModelObject. The layer_height_profile at the ModelObject
|
||||
// is used for interactive editing and for loading / storing into a project file (AMF file as of today).
|
||||
// This flag indicates that the layer_height_profile at the UI has been updated, therefore the backend needs to get it.
|
||||
// This flag is necessary as we cannot safely clear the layer_height_profile if the background calculation is running.
|
||||
bool layer_height_profile_valid;
|
||||
|
||||
// this is set to true when LayerRegion->slices is split in top/internal/bottom
|
||||
// so that next call to make_perimeters() performs a union() before computing loops
|
||||
bool typed_slices;
|
||||
@ -129,23 +123,19 @@ public:
|
||||
SupportLayerPtrs::const_iterator insert_support_layer(SupportLayerPtrs::const_iterator pos, int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
|
||||
void delete_support_layer(int idx);
|
||||
|
||||
// To be used over the layer_height_profile of both the PrintObject and ModelObject
|
||||
// to initialize the height profile with the height ranges.
|
||||
bool update_layer_height_profile(std::vector<coordf_t> &layer_height_profile) const;
|
||||
|
||||
// Process layer_height_ranges, the raft layers and first layer thickness into layer_height_profile.
|
||||
// The layer_height_profile may be later modified interactively by the user to refine layers at sloping surfaces.
|
||||
bool update_layer_height_profile();
|
||||
|
||||
void reset_layer_height_profile();
|
||||
|
||||
void adjust_layer_height_profile(coordf_t z, coordf_t layer_thickness_delta, coordf_t band_width, int action);
|
||||
// Initialize the layer_height_profile from the model_object's layer_height_profile, from model_object's layer height table, or from slicing parameters.
|
||||
// Returns true, if the layer_height_profile was changed.
|
||||
static bool update_layer_height_profile(const ModelObject &model_object, const SlicingParameters &slicing_parameters, std::vector<coordf_t> &layer_height_profile);
|
||||
|
||||
// Collect the slicing parameters, to be used by variable layer thickness algorithm,
|
||||
// by the interactive layer height editor and by the printing process itself.
|
||||
// The slicing parameters are dependent on various configuration values
|
||||
// (layer height, first layer height, raft settings, print nozzle diameter etc).
|
||||
SlicingParameters slicing_parameters() const;
|
||||
static SlicingParameters slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object);
|
||||
|
||||
// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
|
||||
std::vector<unsigned int> object_extruders() const;
|
||||
|
||||
// Called when slicing to SVG (see Print.pm sub export_svg), and used by perimeters.t
|
||||
void slice();
|
||||
@ -172,13 +162,16 @@ protected:
|
||||
// Invalidate steps based on a set of parameters changed.
|
||||
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
||||
|
||||
static PrintObjectConfig object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders);
|
||||
static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders);
|
||||
|
||||
private:
|
||||
void make_perimeters();
|
||||
void prepare_infill();
|
||||
void infill();
|
||||
void generate_support_material();
|
||||
|
||||
void _slice();
|
||||
void _slice(const std::vector<coordf_t> &layer_height_profile);
|
||||
void _offsetHoles(float hole_delta, LayerRegion *layerm);
|
||||
std::string _fix_slicing_errors();
|
||||
void _simplify_slices(double distance);
|
||||
|
@ -75,7 +75,7 @@ void PrintConfigDef::init_fff_params()
|
||||
"This is mostly useful with Bowden extruders which suffer from oozing. "
|
||||
"This feature slows down both the print and the G-code generation.");
|
||||
def->cli = "avoid-crossing-perimeters!";
|
||||
def->mode = comAdvanced;
|
||||
def->mode = comExpert;
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("remove_small_gaps", coBool);
|
||||
@ -202,6 +202,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->cli = "bridge-speed=f";
|
||||
def->aliases = { "bridge_feed_rate" };
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloat(60);
|
||||
|
||||
def = this->add("brim_width", coFloat);
|
||||
@ -369,7 +370,7 @@ void PrintConfigDef::init_fff_params()
|
||||
"to compensate for the 1st layer squish aka an Elephant Foot effect. (should be negative = inwards)");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "elefant-foot-compensation=f";
|
||||
def->mode = comExpert;
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloat(0);
|
||||
|
||||
def = this->add("end_gcode", coString);
|
||||
@ -503,6 +504,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->cli = "external-perimeter-speed=s";
|
||||
def->ratio_over = "perimeter_speed";
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloatOrPercent(50, true);
|
||||
|
||||
def = this->add("external_perimeters_first", coBool);
|
||||
@ -836,12 +838,14 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_values.push_back("EDGE");
|
||||
def->enum_values.push_back("NGEN");
|
||||
def->enum_values.push_back("PVA");
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionStrings { "PLA" };
|
||||
|
||||
def = this->add("filament_soluble", coBools);
|
||||
def->label = L("Soluble material");
|
||||
def->tooltip = L("Soluble material is most likely used for a soluble support.");
|
||||
def->cli = "filament-soluble!";
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionBools { false };
|
||||
|
||||
def = this->add("filament_cost", coFloats);
|
||||
@ -1066,6 +1070,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->sidetext = L("mm/s");
|
||||
def->cli = "gap-fill-speed=f";
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloat(20);
|
||||
|
||||
def = this->add("gcode_comments", coBool);
|
||||
@ -1237,6 +1242,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->cli = "infill-speed=f";
|
||||
def->aliases = { "print_feed_rate", "infill_feed_rate" };
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloat(80);
|
||||
|
||||
def = this->add("inherits", coString);
|
||||
@ -1675,6 +1681,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->cli = "perimeter-speed=f";
|
||||
def->aliases = { "perimeter_feed_rate" };
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloat(60);
|
||||
|
||||
def = this->add("perimeters", coInt);
|
||||
@ -1900,8 +1907,8 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_labels.push_back(L("Aligned"));
|
||||
def->enum_labels.push_back(L("Rear"));
|
||||
def->enum_labels.push_back(L("Hidden"));
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionEnum<SeamPosition>(spAligned);
|
||||
def->mode = comSimple;
|
||||
def->default_value = new ConfigOptionEnum<SeamPosition>(spHidden);
|
||||
|
||||
def = this->add("seam_travel", coBool);
|
||||
def->label = L("Travel move reduced");
|
||||
@ -1954,6 +1961,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->max = 300000;
|
||||
def->enum_values.push_back("115200");
|
||||
def->enum_values.push_back("250000");
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionInt(250000);
|
||||
|
||||
def = this->add("skirt_distance", coFloat);
|
||||
@ -2007,6 +2015,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->cli = "small-perimeter-speed=s";
|
||||
def->ratio_over = "perimeter_speed";
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloatOrPercent(15, false);
|
||||
|
||||
def = this->add("solid_infill_below_area", coFloat);
|
||||
@ -2063,6 +2072,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->ratio_over = "infill_speed";
|
||||
def->aliases = { "solid_infill_feed_rate" };
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloatOrPercent(20, false);
|
||||
|
||||
def = this->add("solid_layers", coInt);
|
||||
@ -2154,7 +2164,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->tooltip = L("If checked, supports will be generated automatically based on the overhang threshold value."\
|
||||
" If unchecked, supports will be generated inside the \"Support Enforcer\" volumes only.");
|
||||
def->cli = "support-material-auto!";
|
||||
def->mode = comAdvanced;
|
||||
def->mode = comSimple;
|
||||
def->default_value = new ConfigOptionBool(true);
|
||||
|
||||
def = this->add("support_material_xy_spacing", coFloatOrPercent);
|
||||
@ -2186,7 +2196,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Support material");
|
||||
def->tooltip = L("Only create support if it lies on a build plate. Don't create support on a print.");
|
||||
def->cli = "support-material-buildplate-only!";
|
||||
def->mode = comAdvanced;
|
||||
def->mode = comSimple;
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("support_material_contact_distance_type", coEnum);
|
||||
@ -2323,6 +2333,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->cli = "support-material-interface-speed=s";
|
||||
def->ratio_over = "support_material_speed";
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloatOrPercent(100, true);
|
||||
|
||||
def = this->add("support_material_pattern", coEnum);
|
||||
@ -2357,6 +2368,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->sidetext = L("mm/s");
|
||||
def->cli = "support-material-speed=f";
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloat(60);
|
||||
|
||||
def = this->add("support_material_synchronize_layers", coBool);
|
||||
@ -2468,6 +2480,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->cli = "top-solid-infill-speed=s";
|
||||
def->ratio_over = "solid_infill_speed";
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloatOrPercent(15, false);
|
||||
|
||||
def = this->add("top_solid_layers", coInt);
|
||||
@ -2823,7 +2836,6 @@ void PrintConfigDef::init_sla_params()
|
||||
def->label = L("Generate supports");
|
||||
def->category = L("Supports");
|
||||
def->tooltip = L("Generate supports for the models");
|
||||
def->sidetext = L("");
|
||||
def->cli = "";
|
||||
def->default_value = new ConfigOptionBool(true);
|
||||
|
||||
@ -2863,13 +2875,28 @@ void PrintConfigDef::init_sla_params()
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(1.0);
|
||||
|
||||
def = this->add("support_pillar_connection_mode", coEnum);
|
||||
def->label = L("Support pillar connection mode");
|
||||
def->tooltip = L("Controls the bridge type between two neigboring pillars."
|
||||
" Can be zig-zag, cross (double zig-zag) or dynamic which"
|
||||
" will automatically switch between the first two depending"
|
||||
" on the distance of the two pillars.");
|
||||
def->cli = "";
|
||||
def->enum_keys_map = &ConfigOptionEnum<SLAPillarConnectionMode>::get_enum_values();
|
||||
def->enum_values.push_back("zigzag");
|
||||
def->enum_values.push_back("cross");
|
||||
def->enum_values.push_back("dynamic");
|
||||
def->enum_labels.push_back(L("Zig-Zag"));
|
||||
def->enum_labels.push_back(L("Cross"));
|
||||
def->enum_labels.push_back(L("Dynamic"));
|
||||
def->default_value = new ConfigOptionEnum<SLAPillarConnectionMode>(slapcmDynamic);
|
||||
|
||||
def = this->add("support_pillar_widening_factor", coFloat);
|
||||
def->label = L("Pillar widening factor");
|
||||
def->category = L("Supports");
|
||||
def->tooltip = L("Merging bridges or pillars into another pillars can "
|
||||
"increase the radius. Zero means no increase, one means "
|
||||
"full increase.");
|
||||
def->sidetext = L("");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
def->max = 1;
|
||||
@ -2951,14 +2978,13 @@ void PrintConfigDef::init_sla_params()
|
||||
def->label = L("Use pad");
|
||||
def->category = L("Pad");
|
||||
def->tooltip = L("Add a pad underneath the supported model");
|
||||
def->sidetext = L("");
|
||||
def->cli = "";
|
||||
def->default_value = new ConfigOptionBool(true);
|
||||
|
||||
def = this->add("pad_wall_thickness", coFloat);
|
||||
def->label = L("Pad wall thickness");
|
||||
def->category = L("Pad");
|
||||
def->tooltip = L("");
|
||||
// def->tooltip = L("");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
@ -2967,7 +2993,7 @@ void PrintConfigDef::init_sla_params()
|
||||
def = this->add("pad_wall_height", coFloat);
|
||||
def->label = L("Pad wall height");
|
||||
def->category = L("Pad");
|
||||
def->tooltip = L("");
|
||||
// def->tooltip = L("");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
@ -2976,7 +3002,7 @@ void PrintConfigDef::init_sla_params()
|
||||
def = this->add("pad_max_merge_distance", coFloat);
|
||||
def->label = L("Max merge distance");
|
||||
def->category = L("Pad");
|
||||
def->tooltip = L("");
|
||||
// def->tooltip = L("");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
@ -2985,7 +3011,7 @@ void PrintConfigDef::init_sla_params()
|
||||
def = this->add("pad_edge_radius", coFloat);
|
||||
def->label = L("Pad edge radius");
|
||||
def->category = L("Pad");
|
||||
def->tooltip = L("");
|
||||
// def->tooltip = L("");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
@ -3394,7 +3420,7 @@ CLIConfigDef::CLIConfigDef()
|
||||
def->tooltip = L("Forces the GUI launch instead of command line slicing "
|
||||
"(if you supply a model file, it will be loaded into the plater)");
|
||||
def->cli = "gui";
|
||||
def->default_value = new ConfigOptionBool(true);
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("info", coBool);
|
||||
def->label = L("Output Model Info");
|
||||
|
@ -70,6 +70,12 @@ enum SLADisplayOrientation {
|
||||
sladoPortrait
|
||||
};
|
||||
|
||||
enum SLAPillarConnectionMode {
|
||||
slapcmZigZag,
|
||||
slapcmCross,
|
||||
slapcmDynamic
|
||||
};
|
||||
|
||||
template<> inline const t_config_enum_values& ConfigOptionEnum<PrinterTechnology>::get_enum_values() {
|
||||
static t_config_enum_values keys_map;
|
||||
if (keys_map.empty()) {
|
||||
@ -196,6 +202,16 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<SLADisplayOrienta
|
||||
return keys_map;
|
||||
}
|
||||
|
||||
template<> inline const t_config_enum_values& ConfigOptionEnum<SLAPillarConnectionMode>::get_enum_values() {
|
||||
static const t_config_enum_values keys_map = {
|
||||
{"zigzag", slapcmZigZag},
|
||||
{"cross", slapcmCross},
|
||||
{"dynamic", slapcmDynamic}
|
||||
};
|
||||
|
||||
return keys_map;
|
||||
}
|
||||
|
||||
// Defines each and every confiuration option of Slic3r, including the properties of the GUI dialogs.
|
||||
// Does not store the actual values, but defines default values.
|
||||
class PrintConfigDef : public ConfigDef
|
||||
@ -1041,6 +1057,9 @@ public:
|
||||
// Radius in mm of the support pillars.
|
||||
ConfigOptionFloat support_pillar_diameter /*= 0.8*/;
|
||||
|
||||
// How the pillars are bridged together
|
||||
ConfigOptionEnum<SLAPillarConnectionMode> support_pillar_connection_mode;
|
||||
|
||||
// TODO: unimplemented at the moment. This coefficient will have an impact
|
||||
// when bridges and pillars are merged. The resulting pillar should be a bit
|
||||
// thicker than the ones merging into it. How much thicker? I don't know
|
||||
@ -1095,6 +1114,7 @@ protected:
|
||||
OPT_PTR(support_head_penetration);
|
||||
OPT_PTR(support_head_width);
|
||||
OPT_PTR(support_pillar_diameter);
|
||||
OPT_PTR(support_pillar_connection_mode);
|
||||
OPT_PTR(support_pillar_widening_factor);
|
||||
OPT_PTR(support_base_diameter);
|
||||
OPT_PTR(support_base_height);
|
||||
@ -1256,12 +1276,11 @@ public:
|
||||
class DynamicPrintAndCLIConfig : public DynamicPrintConfig
|
||||
{
|
||||
public:
|
||||
DynamicPrintAndCLIConfig() { this->apply(FullPrintConfig::defaults()); this->apply(CLIConfig()); }
|
||||
DynamicPrintAndCLIConfig(const DynamicPrintAndCLIConfig &other) : DynamicPrintConfig(other) {}
|
||||
DynamicPrintAndCLIConfig() {}
|
||||
DynamicPrintAndCLIConfig(const DynamicPrintAndCLIConfig &other) : DynamicPrintConfig(other) {}
|
||||
|
||||
// Overrides ConfigBase::def(). Static configuration definition. Any value stored into this ConfigBase shall have its definition here.
|
||||
const ConfigDef* def() const override { return &s_def; }
|
||||
t_config_option_keys keys() const override { return s_def.keys(); }
|
||||
|
||||
// Verify whether the opt_key has not been obsoleted or renamed.
|
||||
// Both opt_key and value may be modified by handle_legacy().
|
||||
|
@ -38,8 +38,7 @@ namespace Slic3r {
|
||||
PrintObject::PrintObject(Print* print, ModelObject* model_object, bool add_instances) :
|
||||
PrintObjectBaseWithState(print, model_object),
|
||||
typed_slices(false),
|
||||
size(Vec3crd::Zero()),
|
||||
layer_height_profile_valid(false)
|
||||
size(Vec3crd::Zero())
|
||||
{
|
||||
// Compute the translation to be applied to our meshes so that we work with smaller coordinates
|
||||
{
|
||||
@ -65,8 +64,6 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, bool add_insta
|
||||
}
|
||||
this->set_copies(copies);
|
||||
}
|
||||
|
||||
this->layer_height_profile = model_object->layer_height_profile;
|
||||
}
|
||||
|
||||
PrintBase::ApplyStatus PrintObject::set_copies(const Points &points)
|
||||
@ -106,7 +103,10 @@ void PrintObject::slice()
|
||||
if (! this->set_started(posSlice))
|
||||
return;
|
||||
m_print->set_status(10, "Processing triangulated mesh");
|
||||
this->_slice();
|
||||
std::vector<coordf_t> layer_height_profile;
|
||||
this->update_layer_height_profile(*this->model_object(), this->slicing_parameters(), layer_height_profile);
|
||||
m_print->throw_if_canceled();
|
||||
this->_slice(layer_height_profile);
|
||||
m_print->throw_if_canceled();
|
||||
// Fix the model.
|
||||
//FIXME is this the right place to do? It is done repeateadly at the UI and now here at the backend.
|
||||
@ -476,7 +476,6 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|
||||
|| opt_key == "exact_last_layer_height"
|
||||
|| opt_key == "raft_layers") {
|
||||
steps.emplace_back(posSlice);
|
||||
this->reset_layer_height_profile();
|
||||
}
|
||||
else if (
|
||||
opt_key == "clip_multipart_objects"
|
||||
@ -575,7 +574,6 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|
||||
} else {
|
||||
// for legacy, if we can't handle this option let's invalidate all steps
|
||||
this->invalidate_all_steps();
|
||||
this->reset_layer_height_profile();
|
||||
invalidated = true;
|
||||
}
|
||||
}
|
||||
@ -1615,7 +1613,6 @@ void PrintObject::bridge_over_infill()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* This method applies overextrude flow to the first internal solid layer above
|
||||
bridge (which is over sparse infill) note: it's almost complete copy/paste from the method behind,
|
||||
i think it should be merged before gitpull that.
|
||||
@ -1777,56 +1774,107 @@ void PrintObject::replaceSurfaceType(SurfaceType st_to_replace, SurfaceType st_r
|
||||
}
|
||||
}
|
||||
|
||||
static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders)
|
||||
{
|
||||
if (opt.value > (int)num_extruders)
|
||||
// assign the default extruder
|
||||
opt.value = 1;
|
||||
}
|
||||
|
||||
PrintObjectConfig PrintObject::object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders)
|
||||
{
|
||||
PrintObjectConfig config = default_object_config;
|
||||
normalize_and_apply_config(config, object.config);
|
||||
// Clamp invalid extruders to the default extruder (with index 1).
|
||||
clamp_exturder_to_default(config.support_material_extruder, num_extruders);
|
||||
clamp_exturder_to_default(config.support_material_interface_extruder, num_extruders);
|
||||
return config;
|
||||
}
|
||||
|
||||
PrintRegionConfig PrintObject::region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders)
|
||||
{
|
||||
PrintRegionConfig config = default_region_config;
|
||||
normalize_and_apply_config(config, volume.get_object()->config);
|
||||
normalize_and_apply_config(config, volume.config);
|
||||
if (! volume.material_id().empty())
|
||||
normalize_and_apply_config(config, volume.material()->config);
|
||||
// Clamp invalid extruders to the default extruder (with index 1).
|
||||
clamp_exturder_to_default(config.infill_extruder, num_extruders);
|
||||
clamp_exturder_to_default(config.perimeter_extruder, num_extruders);
|
||||
clamp_exturder_to_default(config.solid_infill_extruder, num_extruders);
|
||||
return config;
|
||||
}
|
||||
|
||||
SlicingParameters PrintObject::slicing_parameters() const
|
||||
{
|
||||
return SlicingParameters::create_from_config(
|
||||
this->print()->config(), m_config,
|
||||
unscale<double>(this->size(2)), this->print()->object_extruders());
|
||||
unscale<double>(this->size(2)), this->object_extruders());
|
||||
}
|
||||
|
||||
bool PrintObject::update_layer_height_profile(std::vector<coordf_t> &layer_height_profile) const
|
||||
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object)
|
||||
{
|
||||
PrintConfig print_config;
|
||||
PrintObjectConfig object_config;
|
||||
PrintRegionConfig default_region_config;
|
||||
print_config .apply(full_config, true);
|
||||
object_config.apply(full_config, true);
|
||||
default_region_config.apply(full_config, true);
|
||||
size_t num_extruders = print_config.nozzle_diameter.size();
|
||||
object_config = object_config_from_model_object(object_config, model_object, num_extruders);
|
||||
|
||||
std::vector<unsigned int> object_extruders;
|
||||
for (const ModelVolume *model_volume : model_object.volumes)
|
||||
if (model_volume->is_model_part())
|
||||
PrintRegion::collect_object_printing_extruders(
|
||||
print_config,
|
||||
region_config_from_model_volume(default_region_config, *model_volume, num_extruders),
|
||||
object_extruders);
|
||||
sort_remove_duplicates(object_extruders);
|
||||
|
||||
return SlicingParameters::create_from_config(print_config, object_config, model_object.bounding_box().max.z(), object_extruders);
|
||||
}
|
||||
|
||||
// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
|
||||
std::vector<unsigned int> PrintObject::object_extruders() const
|
||||
{
|
||||
std::vector<unsigned int> extruders;
|
||||
extruders.reserve(this->region_volumes.size() * 3);
|
||||
for (size_t idx_region = 0; idx_region < this->region_volumes.size(); ++ idx_region)
|
||||
if (! this->region_volumes[idx_region].empty())
|
||||
m_print->get_region(idx_region)->collect_object_printing_extruders(extruders);
|
||||
sort_remove_duplicates(extruders);
|
||||
return extruders;
|
||||
}
|
||||
|
||||
bool PrintObject::update_layer_height_profile(const ModelObject &model_object, const SlicingParameters &slicing_parameters, std::vector<coordf_t> &layer_height_profile)
|
||||
{
|
||||
bool updated = false;
|
||||
|
||||
// If the layer height profile is not set, try to use the one stored at the ModelObject.
|
||||
if (layer_height_profile.empty()) {
|
||||
layer_height_profile = this->model_object()->layer_height_profile;
|
||||
layer_height_profile = model_object.layer_height_profile;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
// Verify the layer_height_profile.
|
||||
SlicingParameters slicing_params = this->slicing_parameters();
|
||||
if (! layer_height_profile.empty() &&
|
||||
// Must not be of even length.
|
||||
((layer_height_profile.size() & 1) != 0 ||
|
||||
// Last entry must be at the top of the object.
|
||||
std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_params.object_print_z_height()) > 1e-3))
|
||||
std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_parameters.object_print_z_height()) > 1e-3))
|
||||
layer_height_profile.clear();
|
||||
|
||||
if (layer_height_profile.empty()) {
|
||||
if (0)
|
||||
// if (this->layer_height_profile.empty())
|
||||
layer_height_profile = layer_height_profile_adaptive(slicing_params, this->model_object()->layer_height_ranges, this->model_object()->volumes);
|
||||
layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_height_ranges, model_object.volumes);
|
||||
else
|
||||
layer_height_profile = layer_height_profile_from_ranges(slicing_params, this->model_object()->layer_height_ranges);
|
||||
layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_height_ranges);
|
||||
updated = true;
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
// This must be called from the main thread as it modifies the layer_height_profile.
|
||||
bool PrintObject::update_layer_height_profile()
|
||||
{
|
||||
// If the layer height profile has been marked as invalid for some reason (modified at the UI level
|
||||
// or invalidated due to the slicing parameters), clear it now.
|
||||
if (! this->layer_height_profile_valid) {
|
||||
this->layer_height_profile.clear();
|
||||
this->layer_height_profile_valid = true;
|
||||
}
|
||||
return this->update_layer_height_profile(this->layer_height_profile);
|
||||
}
|
||||
|
||||
// 1) Decides Z positions of the layers,
|
||||
// 2) Initializes layers and their regions
|
||||
// 3) Slices the object meshes
|
||||
@ -1836,7 +1884,7 @@ bool PrintObject::update_layer_height_profile()
|
||||
// Resulting expolygons of layer regions are marked as Internal.
|
||||
//
|
||||
// this should be idempotent
|
||||
void PrintObject::_slice()
|
||||
void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "Slicing objects..." << log_memory_info();
|
||||
|
||||
@ -1855,7 +1903,7 @@ void PrintObject::_slice()
|
||||
{
|
||||
this->clear_layers();
|
||||
// Object layers (pairs of bottom/top Z coordinate), without the raft.
|
||||
std::vector<coordf_t> object_layers = generate_object_layers(slicing_params, this->layer_height_profile);
|
||||
std::vector<coordf_t> object_layers = generate_object_layers(slicing_params, layer_height_profile);
|
||||
// Reserve object layers for the raft. Last layer of the raft is the contact layer.
|
||||
int id = int(slicing_params.raft_layers());
|
||||
slice_zs.reserve(object_layers.size());
|
||||
@ -2689,22 +2737,4 @@ void PrintObject::_generate_support_material()
|
||||
support_material.generate(*this);
|
||||
}
|
||||
|
||||
void PrintObject::reset_layer_height_profile()
|
||||
{
|
||||
// Reset the layer_heigth_profile.
|
||||
this->layer_height_profile.clear();
|
||||
this->layer_height_profile_valid = false;
|
||||
// Reset the source layer_height_profile if it exists at the ModelObject.
|
||||
this->model_object()->layer_height_profile.clear();
|
||||
this->model_object()->layer_height_profile_valid = false;
|
||||
}
|
||||
|
||||
void PrintObject::adjust_layer_height_profile(coordf_t z, coordf_t layer_thickness_delta, coordf_t band_width, int action)
|
||||
{
|
||||
update_layer_height_profile(m_model_object->layer_height_profile);
|
||||
Slic3r::adjust_layer_height_profile(slicing_parameters(), m_model_object->layer_height_profile, z, layer_thickness_delta, band_width, LayerHeightEditActionType(action));
|
||||
m_model_object->layer_height_profile_valid = true;
|
||||
layer_height_profile_valid = false;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -61,4 +61,20 @@ coordf_t PrintRegion::bridging_height_avg(const PrintConfig &print_config) const
|
||||
return this->nozzle_dmr_avg(print_config) * sqrt(m_config.bridge_flow_ratio.value);
|
||||
}
|
||||
|
||||
void PrintRegion::collect_object_printing_extruders(const PrintConfig &print_config, const PrintRegionConfig ®ion_config, std::vector<unsigned int> &object_extruders)
|
||||
{
|
||||
// These checks reflect the same logic used in the GUI for enabling/disabling extruder selection fields.
|
||||
if (region_config.perimeters.value > 0 || print_config.brim_width.value > 0)
|
||||
object_extruders.emplace_back(region_config.perimeter_extruder - 1);
|
||||
if (region_config.fill_density.value > 0)
|
||||
object_extruders.emplace_back(region_config.infill_extruder - 1);
|
||||
if (region_config.top_solid_layers.value > 0 || region_config.bottom_solid_layers.value > 0)
|
||||
object_extruders.emplace_back(region_config.solid_infill_extruder - 1);
|
||||
}
|
||||
|
||||
void PrintRegion::collect_object_printing_extruders(std::vector<unsigned int> &object_extruders) const
|
||||
{
|
||||
collect_object_printing_extruders(print()->config(), this->config(), object_extruders);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -215,41 +215,67 @@ inline Contour3D roofs(const ExPolygon& poly, coord_t z_distance) {
|
||||
return lower;
|
||||
}
|
||||
|
||||
template<class ExP, class D>
|
||||
Contour3D round_edges(const ExPolygon& base_plate,
|
||||
double radius_mm,
|
||||
double degrees,
|
||||
double ceilheight_mm,
|
||||
bool dir,
|
||||
ThrowOnCancel throw_on_cancel,
|
||||
ExP&& last_offset = ExP(), D&& last_height = D())
|
||||
ExPolygon& last_offset, double& last_height)
|
||||
{
|
||||
auto ob = base_plate;
|
||||
auto ob_prev = ob;
|
||||
double wh = ceilheight_mm, wh_prev = wh;
|
||||
Contour3D curvedwalls;
|
||||
|
||||
int steps = 15; // int(std::ceil(10*std::pow(radius_mm, 1.0/3)));
|
||||
int steps = 30;
|
||||
double stepx = radius_mm / steps;
|
||||
coord_t s = dir? 1 : -1;
|
||||
degrees = std::fmod(degrees, 180);
|
||||
|
||||
if(degrees >= 90) {
|
||||
for(int i = 1; i <= steps; ++i) {
|
||||
throw_on_cancel();
|
||||
// we use sin for x distance because we interpret the angle starting from
|
||||
// PI/2
|
||||
int tos = degrees < 90?
|
||||
int(radius_mm*std::cos(degrees * PI / 180 - PI/2) / stepx) : steps;
|
||||
|
||||
for(int i = 1; i <= tos; ++i) {
|
||||
throw_on_cancel();
|
||||
|
||||
ob = base_plate;
|
||||
|
||||
double r2 = radius_mm * radius_mm;
|
||||
double xx = i*stepx;
|
||||
double x2 = xx*xx;
|
||||
double stepy = std::sqrt(r2 - x2);
|
||||
|
||||
offset(ob, s*mm(xx));
|
||||
wh = ceilheight_mm - radius_mm + stepy;
|
||||
|
||||
Contour3D pwalls;
|
||||
pwalls = walls(ob, ob_prev, wh, wh_prev, throw_on_cancel);
|
||||
|
||||
curvedwalls.merge(pwalls);
|
||||
ob_prev = ob;
|
||||
wh_prev = wh;
|
||||
}
|
||||
|
||||
if(degrees > 90) {
|
||||
double tox = radius_mm - radius_mm*std::cos(degrees * PI / 180 - PI/2);
|
||||
int tos = int(tox / stepx);
|
||||
|
||||
for(int i = 1; i <= tos; ++i) {
|
||||
throw_on_cancel();
|
||||
ob = base_plate;
|
||||
|
||||
double r2 = radius_mm * radius_mm;
|
||||
double xx = i*stepx;
|
||||
double xx = radius_mm - i*stepx;
|
||||
double x2 = xx*xx;
|
||||
double stepy = std::sqrt(r2 - x2);
|
||||
|
||||
offset(ob, s*mm(xx));
|
||||
wh = ceilheight_mm - radius_mm + stepy;
|
||||
wh = ceilheight_mm - radius_mm - stepy;
|
||||
|
||||
Contour3D pwalls;
|
||||
pwalls = walls(ob, ob_prev, wh, wh_prev, throw_on_cancel);
|
||||
pwalls = walls(ob_prev, ob, wh_prev, wh, throw_on_cancel);
|
||||
|
||||
curvedwalls.merge(pwalls);
|
||||
ob_prev = ob;
|
||||
@ -257,28 +283,6 @@ Contour3D round_edges(const ExPolygon& base_plate,
|
||||
}
|
||||
}
|
||||
|
||||
double tox = radius_mm - radius_mm*std::sin(degrees * PI / 180);
|
||||
int tos = int(tox / stepx);
|
||||
|
||||
for(int i = 1; i <= tos; ++i) {
|
||||
throw_on_cancel();
|
||||
ob = base_plate;
|
||||
|
||||
double r2 = radius_mm * radius_mm;
|
||||
double xx = radius_mm - i*stepx;
|
||||
double x2 = xx*xx;
|
||||
double stepy = std::sqrt(r2 - x2);
|
||||
offset(ob, s*mm(xx));
|
||||
wh = ceilheight_mm - radius_mm - stepy;
|
||||
|
||||
Contour3D pwalls;
|
||||
pwalls = walls(ob_prev, ob, wh_prev, wh, throw_on_cancel);
|
||||
|
||||
curvedwalls.merge(pwalls);
|
||||
ob_prev = ob;
|
||||
wh_prev = wh;
|
||||
}
|
||||
|
||||
last_offset = std::move(ob);
|
||||
last_height = wh;
|
||||
|
||||
@ -457,32 +461,60 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
|
||||
void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
|
||||
const PoolConfig& cfg)
|
||||
{
|
||||
double mdist = 2*(1.8*cfg.min_wall_thickness_mm + 4*cfg.edge_radius_mm) +
|
||||
cfg.max_merge_distance_mm;
|
||||
|
||||
auto concavehs = concave_hull(ground_layer, mdist, cfg.throw_on_cancel);
|
||||
double mergedist = 2*(1.8*cfg.min_wall_thickness_mm + 4*cfg.edge_radius_mm)+
|
||||
cfg.max_merge_distance_mm;
|
||||
|
||||
// Here we get the base polygon from which the pad has to be generated.
|
||||
// We create an artificial concave hull from this polygon and that will
|
||||
// serve as the bottom plate of the pad. We will offset this concave hull
|
||||
// and then offset back the result with clipper with rounding edges ON. This
|
||||
// trick will create a nice rounded pad shape.
|
||||
auto concavehs = concave_hull(ground_layer, mergedist, cfg.throw_on_cancel);
|
||||
|
||||
const double thickness = cfg.min_wall_thickness_mm;
|
||||
const double wingheight = cfg.min_wall_height_mm;
|
||||
const double fullheight = wingheight + thickness;
|
||||
const double tilt = PI/4;
|
||||
const double wingdist = wingheight / std::tan(tilt);
|
||||
|
||||
// scaled values
|
||||
const coord_t s_thickness = mm(thickness);
|
||||
const coord_t s_eradius = mm(cfg.edge_radius_mm);
|
||||
const coord_t s_safety_dist = 2*s_eradius + coord_t(0.8*s_thickness);
|
||||
// const coord_t wheight = mm(cfg.min_wall_height_mm);
|
||||
coord_t s_wingdist = mm(wingdist);
|
||||
|
||||
auto& thrcl = cfg.throw_on_cancel;
|
||||
|
||||
for(ExPolygon& concaveh : concavehs) {
|
||||
if(concaveh.contour.points.empty()) return;
|
||||
|
||||
// Get rif of any holes in the concave hull output.
|
||||
concaveh.holes.clear();
|
||||
|
||||
const coord_t WALL_THICKNESS = mm(cfg.min_wall_thickness_mm);
|
||||
|
||||
const coord_t WALL_DISTANCE = mm(2*cfg.edge_radius_mm) +
|
||||
coord_t(0.8*WALL_THICKNESS);
|
||||
|
||||
const coord_t HEIGHT = mm(cfg.min_wall_height_mm);
|
||||
|
||||
// Here lies the trick that does the smooting only with clipper offset
|
||||
// calls. The offset is configured to round edges. Inner edges will
|
||||
// be rounded because we offset twice: ones to get the outer (top) plate
|
||||
// and again to get the inner (bottom) plate
|
||||
auto outer_base = concaveh;
|
||||
offset(outer_base, WALL_THICKNESS+WALL_DISTANCE);
|
||||
outer_base.holes.clear();
|
||||
offset(outer_base, s_safety_dist + s_wingdist + s_thickness);
|
||||
auto inner_base = outer_base;
|
||||
offset(inner_base, -WALL_THICKNESS);
|
||||
inner_base.holes.clear(); outer_base.holes.clear();
|
||||
offset(inner_base, -(s_thickness + s_wingdist));
|
||||
|
||||
// Punching a hole in the top plate for the cavity
|
||||
ExPolygon top_poly;
|
||||
ExPolygon middle_base;
|
||||
top_poly.contour = outer_base.contour;
|
||||
top_poly.holes.emplace_back(inner_base.contour);
|
||||
auto& tph = top_poly.holes.back().points;
|
||||
std::reverse(tph.begin(), tph.end());
|
||||
|
||||
if(wingheight > 0) {
|
||||
middle_base = outer_base;
|
||||
offset(middle_base, -s_thickness);
|
||||
top_poly.holes.emplace_back(middle_base.contour);
|
||||
auto& tph = top_poly.holes.back().points;
|
||||
std::reverse(tph.begin(), tph.end());
|
||||
}
|
||||
|
||||
Contour3D pool;
|
||||
|
||||
@ -497,13 +529,15 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
|
||||
// y = cy + (r^2*py - r*px*sqrt(px^2 + py^2 - r^2) / (px^2 + py^2)
|
||||
// where px and py are the coordinates of the point outside the circle
|
||||
// cx and cy are the circle center, r is the radius
|
||||
// We place the circle center to (0, 0) in the calculation the make
|
||||
// things easier.
|
||||
// to get the angle we use arcsin function and subtract 90 degrees then
|
||||
// flip the sign to get the right input to the round_edge function.
|
||||
double r = cfg.edge_radius_mm;
|
||||
double cy = 0;
|
||||
double cx = 0;
|
||||
double px = cfg.min_wall_thickness_mm;
|
||||
double py = r - cfg.min_wall_height_mm;
|
||||
double px = thickness + wingdist;
|
||||
double py = r - fullheight;
|
||||
|
||||
double pxcx = px - cx;
|
||||
double pycy = py - cy;
|
||||
@ -513,45 +547,59 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
|
||||
double vy = (r_2*pycy - r*pxcx*D) / b_2;
|
||||
double phi = -(std::asin(vy/r) * 180 / PI - 90);
|
||||
|
||||
auto curvedwalls = round_edges(ob,
|
||||
r,
|
||||
phi, // 170 degrees
|
||||
0, // z position of the input plane
|
||||
true,
|
||||
cfg.throw_on_cancel,
|
||||
ob, wh);
|
||||
|
||||
pool.merge(curvedwalls);
|
||||
// Generate the smoothed edge geometry
|
||||
auto walledges = round_edges(ob,
|
||||
r,
|
||||
phi,
|
||||
0, // z position of the input plane
|
||||
true,
|
||||
thrcl,
|
||||
ob, wh);
|
||||
pool.merge(walledges);
|
||||
|
||||
ExPolygon ob_contr = ob;
|
||||
ob_contr.holes.clear();
|
||||
|
||||
auto pwalls = walls(ob_contr, inner_base, wh, -cfg.min_wall_height_mm,
|
||||
cfg.throw_on_cancel);
|
||||
// Now that we have the rounded edge connencting the top plate with
|
||||
// the outer side walls, we can generate and merge the sidewall geometry
|
||||
auto pwalls = walls(ob, inner_base, wh, -fullheight, thrcl);
|
||||
pool.merge(pwalls);
|
||||
|
||||
if(wingheight > 0) {
|
||||
// Generate the smoothed edge geometry
|
||||
auto cavityedges = round_edges(middle_base,
|
||||
r,
|
||||
phi - 90, // from tangent lines
|
||||
0,
|
||||
false,
|
||||
thrcl,
|
||||
ob, wh);
|
||||
pool.merge(cavityedges);
|
||||
|
||||
// Next is the cavity walls connecting to the top plate's
|
||||
// artificially created hole.
|
||||
auto cavitywalls = walls(inner_base, ob, -wingheight, wh, thrcl);
|
||||
pool.merge(cavitywalls);
|
||||
}
|
||||
|
||||
// Now we need to triangulate the top and bottom plates as well as the
|
||||
// cavity bottom plate which is the same as the bottom plate but it is
|
||||
// eleveted by the thickness.
|
||||
Polygons top_triangles, bottom_triangles;
|
||||
|
||||
triangulate(top_poly, top_triangles);
|
||||
triangulate(inner_base, bottom_triangles);
|
||||
|
||||
auto top_plate = convert(top_triangles, 0, false);
|
||||
auto bottom_plate = convert(bottom_triangles, -HEIGHT, true);
|
||||
|
||||
ob = inner_base; wh = 0;
|
||||
// rounded edge generation for the inner bed
|
||||
curvedwalls = round_edges(ob,
|
||||
cfg.edge_radius_mm,
|
||||
90, // 90 degrees
|
||||
0, // z position of the input plane
|
||||
false,
|
||||
cfg.throw_on_cancel,
|
||||
ob, wh);
|
||||
pool.merge(curvedwalls);
|
||||
|
||||
auto innerbed = inner_bed(ob, cfg.min_wall_height_mm/2 + wh, wh);
|
||||
auto bottom_plate = convert(bottom_triangles, -mm(fullheight), true);
|
||||
|
||||
pool.merge(top_plate);
|
||||
pool.merge(bottom_plate);
|
||||
pool.merge(innerbed);
|
||||
|
||||
if(wingheight > 0) {
|
||||
Polygons middle_triangles;
|
||||
triangulate(inner_base, middle_triangles);
|
||||
auto middle_plate = convert(middle_triangles, -mm(wingheight), false);
|
||||
pool.merge(middle_plate);
|
||||
}
|
||||
|
||||
out.merge(mesh(pool));
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user