Merge branch 'master' into pm_support_spots_generator

This commit is contained in:
PavelMikus 2022-09-05 13:04:06 +02:00
commit b9659ce676
146 changed files with 8525 additions and 4751 deletions

View File

@ -27,7 +27,6 @@ option(SLIC3R_STATIC "Compile PrusaSlicer with static libraries (Boost, TBB,
option(SLIC3R_GUI "Compile PrusaSlicer with GUI components (OpenGL, wxWidgets)" 1)
option(SLIC3R_FHS "Assume PrusaSlicer 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 PrusaSlicer 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)
@ -328,25 +327,6 @@ add_definitions(-DwxUSE_UNICODE -D_UNICODE -DUNICODE -DWXINTL_NO_GETTEXT_MACRO)
# Disable unsafe implicit wxString to const char* / std::string and vice versa. This implicit conversion breaks the UTF-8 encoding quite often.
add_definitions(-DwxNO_UNSAFE_WXSTRING_CONV)
if (SLIC3R_PROFILE)
message("PrusaSlicer will be built with a Shiny invasive profiler")
add_definitions(-DSLIC3R_PROFILE)
endif ()
# Disable optimization even with debugging on.
if (0)
message(STATUS "Perl compiled without optimization. Disabling optimization for the PrusaSlicer build.")
message("Old CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}")
message("Old CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELEASE}")
message("Old CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS_RELEASE "/MD /Od /Zi /EHsc /DWIN32 /DTBB_USE_ASSERT")
set(CMAKE_C_FLAGS_RELEASE "/MD /Od /Zi /DWIN32 /DTBB_USE_ASSERT")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /EHsc /DWIN32 /DTBB_USE_ASSERT")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /DWIN32 /DTBB_USE_ASSERT")
set(CMAKE_CXX_FLAGS "/MD /Od /Zi /EHsc /DWIN32 /DTBB_USE_ASSERT")
set(CMAKE_C_FLAGS "/MD /Od /Zi /DWIN32 /DTBB_USE_ASSERT")
endif()
# Find and configure boost
if(SLIC3R_STATIC)
# Use static boost libraries.

View File

@ -3,6 +3,7 @@ prusaslicer_add_cmake_project(OCCT
URL https://github.com/Open-Cascade-SAS/OCCT/archive/refs/tags/V7_6_2.zip
URL_HASH SHA256=c696b923593e8c18d059709717dbf155b3e72fdd283c8522047a790ec3a432c5
PATCH_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_DIR}/occt_toolkit.cmake ./adm/cmake/
CMAKE_ARGS
-DINSTALL_DIR_LAYOUT=Unix # LMBBS
-DBUILD_LIBRARY_TYPE=Static
@ -20,3 +21,7 @@ prusaslicer_add_cmake_project(OCCT
-DBUILD_MODULE_ModelingData=OFF
-DBUILD_MODULE_Visualization=OFF
)
if (MSVC)
add_debug_dep(dep_OCCT)
endif ()

453
deps/OCCT/occt_toolkit.cmake vendored Normal file
View File

@ -0,0 +1,453 @@
# script for each OCCT toolkit
# filling some variables by default values(src) or using custom(tools, samples)
set (RELATIVE_SOURCES_DIR "${RELATIVE_DIR}")
if ("${RELATIVE_SOURCES_DIR}" STREQUAL "")
#if it is not defined, use default directory
set (RELATIVE_SOURCES_DIR "src")
endif()
set (OCC_MODULES_LIST "${MODULES_LIST}")
if ("${OCC_MODULES_LIST}" STREQUAL "")
set (OCC_MODULES_LIST ${OCCT_MODULES})
endif()
set (OCC_TARGET_FOLDER "${TARGET_FOLDER}")
if ("${OCC_TARGET_FOLDER}" STREQUAL "")
set (OCC_TARGET_FOLDER "Modules")
endif()
set (OCCT_TOOLKITS_NAME_SUFFIX "${TOOLKITS_NAME_SUFFIX}")
if ("${OCCT_TOOLKITS_NAME_SUFFIX}" STREQUAL "")
set (OCCT_TOOLKITS_NAME_SUFFIX "TOOLKITS")
endif()
# parse PACKAGES file
FILE_TO_LIST ("${RELATIVE_SOURCES_DIR}/${PROJECT_NAME}/PACKAGES" USED_PACKAGES)
if ("${USED_PACKAGES}" STREQUAL "")
set (USED_PACKAGES ${PROJECT_NAME})
endif()
if (USE_QT)
# Qt dependencies
OCCT_INCLUDE_CMAKE_FILE (adm/cmake/qt_macro)
FIND_QT_PACKAGE(PROJECT_LIBRARIES_DEBUG PROJECT_LIBRARIES_RELEASE PROJECT_INCLUDES)
include_directories("${PROJECT_INCLUDES}")
endif(USE_QT)
set (PRECOMPILED_DEFS)
if (NOT BUILD_SHARED_LIBS)
list (APPEND PRECOMPILED_DEFS "-DOCCT_NO_PLUGINS")
if (WIN32 AND NOT EXECUTABLE_PROJECT)
list (APPEND PRECOMPILED_DEFS "-DOCCT_STATIC_BUILD")
endif()
endif()
# Get all used packages from toolkit
UNSET(RESOURCE_FILES)
foreach (OCCT_PACKAGE ${USED_PACKAGES})
#remove part after "/" in the OCCT_PACKAGE variable if exists
string (FIND "${OCCT_PACKAGE}" "/" _index)
if (_index GREATER -1)
math (EXPR _index "${_index}")
string (SUBSTRING "${OCCT_PACKAGE}" 0 ${_index} OCCT_PACKAGE_NAME)
else()
set (OCCT_PACKAGE_NAME "${OCCT_PACKAGE}")
endif()
if (WIN32)
list (APPEND PRECOMPILED_DEFS "-D__${OCCT_PACKAGE_NAME}_DLL")
endif()
set (SOURCE_FILES)
set (HEADER_FILES)
# Generate Flex and Bison files
if (${BUILD_YACCLEX})
# flex files
OCCT_ORIGIN_AND_PATCHED_FILES ("${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}" "*[.]lex" SOURCE_FILES_FLEX)
list (LENGTH SOURCE_FILES_FLEX SOURCE_FILES_FLEX_LEN)
# bison files
OCCT_ORIGIN_AND_PATCHED_FILES ("${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}" "*[.]yacc" SOURCE_FILES_BISON)
list (LENGTH SOURCE_FILES_BISON SOURCE_FILES_BISON_LEN)
if (${SOURCE_FILES_FLEX_LEN} EQUAL ${SOURCE_FILES_BISON_LEN} AND NOT ${SOURCE_FILES_FLEX_LEN} EQUAL 0)
list (SORT SOURCE_FILES_FLEX)
list (SORT SOURCE_FILES_BISON)
math (EXPR SOURCE_FILES_FLEX_LEN "${SOURCE_FILES_FLEX_LEN} - 1")
foreach (FLEX_FILE_INDEX RANGE ${SOURCE_FILES_FLEX_LEN})
list (GET SOURCE_FILES_FLEX ${FLEX_FILE_INDEX} CURRENT_FLEX_FILE)
get_filename_component (CURRENT_FLEX_FILE_NAME ${CURRENT_FLEX_FILE} NAME_WE)
list (GET SOURCE_FILES_BISON ${FLEX_FILE_INDEX} CURRENT_BISON_FILE)
get_filename_component (CURRENT_BISON_FILE_NAME ${CURRENT_BISON_FILE} NAME_WE)
string (COMPARE EQUAL ${CURRENT_FLEX_FILE_NAME} ${CURRENT_BISON_FILE_NAME} ARE_FILES_EQUAL)
if (EXISTS "${CURRENT_FLEX_FILE}" AND EXISTS "${CURRENT_BISON_FILE}" AND ${ARE_FILES_EQUAL})
# Note: files are generated in original source directory (not in patch!)
set (FLEX_BISON_TARGET_DIR "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}")
# choose appropriate extension for generated files: "cxx" if source file contains
# instruction to generate C++ code, "c" otherwise
set (BISON_OUTPUT_FILE_EXT "c")
set (FLEX_OUTPUT_FILE_EXT "c")
file (STRINGS "${CURRENT_BISON_FILE}" FILE_BISON_CONTENT)
foreach (FILE_BISON_CONTENT_LINE ${FILE_BISON_CONTENT})
string (REGEX MATCH "%language \"C\\+\\+\"" CXX_BISON_LANGUAGE_FOUND ${FILE_BISON_CONTENT_LINE})
if (CXX_BISON_LANGUAGE_FOUND)
set (BISON_OUTPUT_FILE_EXT "cxx")
endif()
endforeach()
file (STRINGS "${CURRENT_FLEX_FILE}" FILE_FLEX_CONTENT)
foreach (FILE_FLEX_CONTENT_LINE ${FILE_FLEX_CONTENT})
string (REGEX MATCH "%option c\\+\\+" CXX_FLEX_LANGUAGE_FOUND ${FILE_FLEX_CONTENT_LINE})
if (CXX_FLEX_LANGUAGE_FOUND)
set (FLEX_OUTPUT_FILE_EXT "cxx")
# install copy of FlexLexer.h locally to allow further building without flex
if (FLEX_INCLUDE_DIR AND EXISTS "${FLEX_INCLUDE_DIR}/FlexLexer.h")
configure_file("${FLEX_INCLUDE_DIR}/FlexLexer.h" "${FLEX_BISON_TARGET_DIR}/FlexLexer.h" @ONLY NEWLINE_STYLE LF)
endif()
endif()
endforeach()
set (BISON_OUTPUT_FILE ${CURRENT_BISON_FILE_NAME}.tab.${BISON_OUTPUT_FILE_EXT})
set (FLEX_OUTPUT_FILE lex.${CURRENT_FLEX_FILE_NAME}.${FLEX_OUTPUT_FILE_EXT})
BISON_TARGET (Parser_${CURRENT_BISON_FILE_NAME} ${CURRENT_BISON_FILE} "${FLEX_BISON_TARGET_DIR}/${BISON_OUTPUT_FILE}"
COMPILE_FLAGS "-p ${CURRENT_BISON_FILE_NAME} -l -M ${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/=")
FLEX_TARGET (Scanner_${CURRENT_FLEX_FILE_NAME} ${CURRENT_FLEX_FILE} "${FLEX_BISON_TARGET_DIR}/${FLEX_OUTPUT_FILE}"
COMPILE_FLAGS "-P${CURRENT_FLEX_FILE_NAME} -L")
ADD_FLEX_BISON_DEPENDENCY (Scanner_${CURRENT_FLEX_FILE_NAME} Parser_${CURRENT_BISON_FILE_NAME})
list (APPEND SOURCE_FILES ${BISON_OUTPUT_FILE} ${FLEX_OUTPUT_FILE})
endif()
endforeach()
endif()
endif()
# header files
if (BUILD_PATCH AND EXISTS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES")
file (STRINGS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_M REGEX ".+[.]h")
file (STRINGS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_LXX REGEX ".+[.]lxx")
file (STRINGS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_GXX REGEX ".+[.]gxx")
file (STRINGS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" SOURCE_FILES_C REGEX ".+[.]c")
if(APPLE)
file (STRINGS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" SOURCE_FILES_M REGEX ".+[.]mm")
endif()
else()
file (STRINGS "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_M REGEX ".+[.]h")
file (STRINGS "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_LXX REGEX ".+[.]lxx")
file (STRINGS "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_GXX REGEX ".+[.]gxx")
file (STRINGS "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" SOURCE_FILES_C REGEX ".+[.]c")
if(APPLE)
file (STRINGS "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" SOURCE_FILES_M REGEX ".+[.]mm")
endif()
endif()
list (APPEND HEADER_FILES ${HEADER_FILES_M} ${HEADER_FILES_LXX} ${SOURCE_FILES_GXX})
list (APPEND SOURCE_FILES ${SOURCE_FILES_C})
if(APPLE)
list (APPEND SOURCE_FILES ${SOURCE_FILES_M})
endif()
foreach(HEADER_FILE ${HEADER_FILES})
if (BUILD_PATCH AND EXISTS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}")
message (STATUS "Info: consider patched file: ${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}")
list (APPEND USED_INCFILES "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}")
SOURCE_GROUP ("Header Files\\${OCCT_PACKAGE_NAME}" FILES "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}")
else()
list (APPEND USED_INCFILES "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}")
SOURCE_GROUP ("Header Files\\${OCCT_PACKAGE_NAME}" FILES "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}")
endif()
endforeach()
foreach(SOURCE_FILE ${SOURCE_FILES})
if (BUILD_PATCH AND EXISTS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}")
message (STATUS "Info: consider patched file: ${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}")
list (APPEND USED_SRCFILES "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}")
SOURCE_GROUP ("Source Files\\${OCCT_PACKAGE_NAME}" FILES "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}")
else()
list (APPEND USED_SRCFILES "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}")
SOURCE_GROUP ("Source Files\\${OCCT_PACKAGE_NAME}" FILES "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}")
endif()
endforeach()
if (USE_QT)
FIND_AND_INSTALL_QT_RESOURCES (${OCCT_PACKAGE} RESOURCE_FILES)
#message("Qt Resource files are: ${QT_RESOURCE_FILES} in ${OCCT_PACKAGE}")
endif(USE_QT)
#message("Resource files are: ${RESOURCE_FILES} in ${OCCT_PACKAGE}")
foreach(RESOURCE_FILE ${RESOURCE_FILES})
SOURCE_GROUP ("Resource Files\\${OCCT_PACKAGE_NAME}" FILES "${RESOURCE_FILE}")
endforeach()
endforeach()
string (REGEX REPLACE ";" " " PRECOMPILED_DEFS "${PRECOMPILED_DEFS}")
set (USED_RCFILE "")
if (MSVC)
set (USED_RCFILE "${CMAKE_BINARY_DIR}/resources/${PROJECT_NAME}.rc")
if (APPLY_OCCT_PATCH_DIR AND EXISTS "${APPLY_OCCT_PATCH_DIR}/adm/templates/occt_toolkit.rc.in")
configure_file("${APPLY_OCCT_PATCH_DIR}/adm/templates/occt_toolkit.rc.in" "${USED_RCFILE}" @ONLY)
else()
configure_file("${CMAKE_SOURCE_DIR}/adm/templates/occt_toolkit.rc.in" "${USED_RCFILE}" @ONLY)
endif()
endif()
set (CURRENT_MODULE)
foreach (OCCT_MODULE ${OCC_MODULES_LIST})
list (FIND ${OCCT_MODULE}_${OCCT_TOOLKITS_NAME_SUFFIX} ${PROJECT_NAME} CURRENT_PROJECT_IS_BUILT)
if (NOT ${CURRENT_PROJECT_IS_BUILT} EQUAL -1)
set (CURRENT_MODULE ${OCCT_MODULE})
endif()
endforeach()
if (MSVC)
OCCT_INSERT_CODE_FOR_TARGET ()
endif()
if (USE_QT)
FIND_AND_WRAP_MOC_FILES("${USED_INCFILES}" "${PROJECT_NAME}_MOC_FILES")
#message("MOC files: ${${PROJECT_NAME}_MOC_FILES}")
endif (USE_QT)
if (EXECUTABLE_PROJECT)
add_executable (${PROJECT_NAME} ${USED_SRCFILES} ${USED_INCFILES} ${USED_RCFILE} ${RESOURCE_FILES} ${${PROJECT_NAME}_MOC_FILES})
install (TARGETS ${PROJECT_NAME}
DESTINATION "${INSTALL_DIR_BIN}\${OCCT_INSTALL_BIN_LETTER}")
if (EMSCRIPTEN)
install(FILES ${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/bin\${OCCT_INSTALL_BIN_LETTER}/${PROJECT_NAME}.wasm DESTINATION "${INSTALL_DIR_BIN}/${OCCT_INSTALL_BIN_LETTER}")
endif()
else()
add_library (${PROJECT_NAME} ${USED_SRCFILES} ${USED_INCFILES} ${USED_RCFILE} ${RESOURCE_FILES} ${${PROJECT_NAME}_MOC_FILES})
if (MSVC)
if (BUILD_FORCE_RelWithDebInfo)
set (aReleasePdbConf "Release")
else()
set (aReleasePdbConf)
endif()
# install (FILES ${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/bin\${OCCT_INSTALL_BIN_LETTER}/${PROJECT_NAME}.pdb
# CONFIGURATIONS Debug ${aReleasePdbConf} RelWithDebInfo
# DESTINATION "${INSTALL_DIR_BIN}\${OCCT_INSTALL_BIN_LETTER}")
endif()
if (BUILD_SHARED_LIBS AND NOT "${BUILD_SHARED_LIBRARY_NAME_POSTFIX}" STREQUAL "")
set (CMAKE_SHARED_LIBRARY_SUFFIX_DEFAULT ${CMAKE_SHARED_LIBRARY_SUFFIX})
set (CMAKE_SHARED_LIBRARY_SUFFIX "${BUILD_SHARED_LIBRARY_NAME_POSTFIX}${CMAKE_SHARED_LIBRARY_SUFFIX}")
endif()
install (TARGETS ${PROJECT_NAME}
EXPORT OpenCASCADE${CURRENT_MODULE}Targets
RUNTIME DESTINATION "${INSTALL_DIR_BIN}\${OCCT_INSTALL_BIN_LETTER}"
ARCHIVE DESTINATION "${INSTALL_DIR_LIB}\${OCCT_INSTALL_BIN_LETTER}"
LIBRARY DESTINATION "${INSTALL_DIR_LIB}\${OCCT_INSTALL_BIN_LETTER}")
if (NOT WIN32)
if (BUILD_SHARED_LIBS AND NOT "${BUILD_SHARED_LIBRARY_NAME_POSTFIX}" STREQUAL "")
set (LINK_NAME "${INSTALL_DIR}/${INSTALL_DIR_LIB}\${OCCT_INSTALL_BIN_LETTER}/lib${PROJECT_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX_DEFAULT}")
set (LIBRARY_NAME "${INSTALL_DIR}/${INSTALL_DIR_LIB}\${OCCT_INSTALL_BIN_LETTER}/lib${PROJECT_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}")
OCCT_CREATE_SYMLINK_TO_FILE (${LIBRARY_NAME} ${LINK_NAME})
endif()
endif()
endif()
if (CURRENT_MODULE)
set_target_properties (${PROJECT_NAME} PROPERTIES FOLDER "${OCC_TARGET_FOLDER}/${CURRENT_MODULE}")
set_target_properties (${PROJECT_NAME} PROPERTIES MODULE "${CURRENT_MODULE}")
if (APPLE)
if (NOT "${INSTALL_NAME_DIR}" STREQUAL "")
set_target_properties (${PROJECT_NAME} PROPERTIES BUILD_WITH_INSTALL_RPATH 1 INSTALL_NAME_DIR "${INSTALL_NAME_DIR}")
endif()
endif()
endif()
get_property (OCC_VERSION_MAJOR GLOBAL PROPERTY OCC_VERSION_MAJOR)
get_property (OCC_VERSION_MINOR GLOBAL PROPERTY OCC_VERSION_MINOR)
get_property (OCC_VERSION_MAINTENANCE GLOBAL PROPERTY OCC_VERSION_MAINTENANCE)
if (ANDROID)
# do not append version to the filename
set_target_properties (${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "${PRECOMPILED_DEFS}")
else()
set_target_properties (${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "${PRECOMPILED_DEFS}"
SOVERSION "${OCC_VERSION_MAJOR}"
VERSION "${OCC_VERSION_MAJOR}.${OCC_VERSION_MINOR}.${OCC_VERSION_MAINTENANCE}")
endif()
set (USED_TOOLKITS_BY_CURRENT_PROJECT)
set (USED_EXTERNAL_LIBS_BY_CURRENT_PROJECT)
# parse EXTERNLIB file
if (CUSTOM_EXTERNLIB)
set (USED_EXTERNLIB_AND_TOOLKITS ${CUSTOM_EXTERNLIB})
else()
FILE_TO_LIST ("${RELATIVE_SOURCES_DIR}/${PROJECT_NAME}/EXTERNLIB" USED_EXTERNLIB_AND_TOOLKITS)
endif()
foreach (USED_ITEM ${USED_EXTERNLIB_AND_TOOLKITS})
string (REGEX MATCH "^ *#" COMMENT_FOUND ${USED_ITEM})
if (NOT COMMENT_FOUND)
string (REGEX MATCH "^TK" TK_FOUND ${USED_ITEM})
string (REGEX MATCH "^vtk" VTK_FOUND ${USED_ITEM})
if (NOT "${TK_FOUND}" STREQUAL "" OR NOT "${VTK_FOUND}" STREQUAL "")
list (APPEND USED_TOOLKITS_BY_CURRENT_PROJECT ${USED_ITEM})
if (NOT "${VTK_FOUND}" STREQUAL "" AND BUILD_SHARED_LIBS AND INSTALL_VTK AND COMMAND OCCT_INSTALL_VTK)
OCCT_INSTALL_VTK(${USED_ITEM})
endif()
else()
string (REGEX MATCH "^CSF_" CSF_FOUND ${USED_ITEM})
if ("${CSF_FOUND}" STREQUAL "")
message (STATUS "Info: ${USED_ITEM} from ${PROJECT_NAME} skipped due to it is empty")
else() # get CSF_ value
set (CURRENT_CSF ${${USED_ITEM}})
if (NOT "x${CURRENT_CSF}" STREQUAL "x")
if ("${CURRENT_CSF}" STREQUAL "CSF_OpenGlLibs")
add_definitions (-DHAVE_OPENGL)
endif()
if ("${CURRENT_CSF}" STREQUAL "CSF_OpenGlesLibs")
add_definitions (-DHAVE_GLES2)
endif()
set (LIBRARY_FROM_CACHE 0)
separate_arguments (CURRENT_CSF)
foreach (CSF_LIBRARY ${CURRENT_CSF})
string (TOLOWER "${CSF_LIBRARY}" CSF_LIBRARY)
string (REPLACE "+" "[+]" CSF_LIBRARY "${CSF_LIBRARY}")
string (REPLACE "." "" CSF_LIBRARY "${CSF_LIBRARY}")
get_cmake_property(ALL_CACHE_VARIABLES CACHE_VARIABLES)
string (REGEX MATCHALL "(^|;)3RDPARTY_[^;]+_LIBRARY[^;]*" ALL_CACHE_VARIABLES "${ALL_CACHE_VARIABLES}")
foreach (CACHE_VARIABLE ${ALL_CACHE_VARIABLES})
set (CURRENT_CACHE_LIBRARY ${${CACHE_VARIABLE}})
string (TOLOWER "${CACHE_VARIABLE}" CACHE_VARIABLE)
if (EXISTS "${CURRENT_CACHE_LIBRARY}" AND NOT IS_DIRECTORY "${CURRENT_CACHE_LIBRARY}")
string (REGEX MATCH "_${CSF_LIBRARY}$" IS_ENDING "${CACHE_VARIABLE}")
string (REGEX MATCH "^([a-z]+)" CSF_WO_VERSION "${CSF_LIBRARY}")
string (REGEX MATCH "_${CSF_WO_VERSION}$" IS_ENDING_WO_VERSION "${CACHE_VARIABLE}")
if ("3rdparty_${CSF_LIBRARY}_library" STREQUAL "${CACHE_VARIABLE}" OR
"3rdparty_${CSF_WO_VERSION}_library" STREQUAL "${CACHE_VARIABLE}" OR
NOT "x${IS_ENDING}" STREQUAL "x" OR
NOT "x${IS_ENDING_WO_VERSION}" STREQUAL "x")
list (APPEND USED_EXTERNAL_LIBS_BY_CURRENT_PROJECT "${CURRENT_CACHE_LIBRARY}")
set (LIBRARY_FROM_CACHE 1)
endif()
endif()
endforeach()
endforeach()
if (NOT ${LIBRARY_FROM_CACHE})
# prepare a list from a string with whitespaces
separate_arguments (CURRENT_CSF)
list (APPEND USED_EXTERNAL_LIBS_BY_CURRENT_PROJECT ${CURRENT_CSF})
endif()
endif()
endif()
endif()
endif()
endforeach()
if (APPLE)
list (FIND USED_EXTERNAL_LIBS_BY_CURRENT_PROJECT X11 IS_X11_FOUND)
if (NOT ${IS_X11_FOUND} EQUAL -1)
find_package (X11 COMPONENTS X11)
if (NOT X11_FOUND)
message (STATUS "Warning: X11 is not found. It's required to install The XQuartz project: http://www.xquartz.org")
endif()
endif()
endif()
# Update list of used VTK libraries if OpenGL2 Rendering BackEnd is used.
# Add VTK_OPENGL2_BACKEND definition.
if("${VTK_RENDERING_BACKEND}" STREQUAL "OpenGL2" OR IS_VTK_9XX)
add_definitions(-DVTK_OPENGL2_BACKEND)
foreach (VTK_EXCLUDE_LIBRARY vtkRenderingOpenGL vtkRenderingFreeTypeOpenGL)
list (FIND USED_TOOLKITS_BY_CURRENT_PROJECT "${VTK_EXCLUDE_LIBRARY}" IS_VTK_OPENGL_FOUND)
if (NOT ${IS_VTK_OPENGL_FOUND} EQUAL -1)
list (REMOVE_ITEM USED_TOOLKITS_BY_CURRENT_PROJECT ${VTK_EXCLUDE_LIBRARY})
if (${VTK_EXCLUDE_LIBRARY} STREQUAL vtkRenderingOpenGL)
list (APPEND USED_TOOLKITS_BY_CURRENT_PROJECT vtkRenderingOpenGL2)
if(VTK_MAJOR_VERSION GREATER 6)
list (APPEND USED_TOOLKITS_BY_CURRENT_PROJECT vtkRenderingGL2PSOpenGL2)
endif()
endif()
endif()
endforeach()
else()
if(VTK_MAJOR_VERSION EQUAL 6 AND VTK_MINOR_VERSION GREATER 2 OR VTK_MAJOR_VERSION GREATER 6)
list (FIND USED_TOOLKITS_BY_CURRENT_PROJECT "vtkRenderingFreeTypeOpenGL" IS_VTK_RENDER_FREETYPE_FOUND)
if (NOT ${IS_VTK_RENDER_FREETYPE_FOUND} EQUAL -1)
list (REMOVE_ITEM USED_TOOLKITS_BY_CURRENT_PROJECT "vtkRenderingFreeTypeOpenGL")
endif()
endif()
endif()
if (BUILD_SHARED_LIBS OR EXECUTABLE_PROJECT)
if(IS_VTK_9XX)
string (REGEX REPLACE "vtk" "VTK::" USED_TOOLKITS_BY_CURRENT_PROJECT "${USED_TOOLKITS_BY_CURRENT_PROJECT}")
endif()
target_link_libraries (${PROJECT_NAME} ${USED_TOOLKITS_BY_CURRENT_PROJECT} ${USED_EXTERNAL_LIBS_BY_CURRENT_PROJECT})
endif()
if (USE_QT)
foreach (PROJECT_LIBRARY_DEBUG ${PROJECT_LIBRARIES_DEBUG})
target_link_libraries (${PROJECT_NAME} debug ${PROJECT_LIBRARY_DEBUG})
endforeach()
foreach (PROJECT_LIBRARY_RELEASE ${PROJECT_LIBRARIES_RELEASE})
target_link_libraries (${PROJECT_NAME} optimized ${PROJECT_LIBRARY_RELEASE})
endforeach()
endif()
# suppress deprecation warnings inside OCCT itself for old gcc versions with unavailable Standard_DISABLE_DEPRECATION_WARNINGS
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6.0)
add_definitions("-DOCCT_NO_DEPRECATED")
message (STATUS "Warning: internal deprecation warnings by Standard_DEPRECATED have been disabled due to old gcc version being used")
endif()
endif()
# use Cotire to accelerate build via usage of precompiled headers
if (BUILD_USE_PCH)
if (WIN32)
# prevent definition of min and max macros through inclusion of Windows.h
# (for cotire builds)
add_definitions("-DNOMINMAX")
# avoid warnings on deprecated names from standard C library (see strsafe.h)
add_definitions("-DSTRSAFE_NO_DEPRECATE")
# avoid "std::Equal1" warning in QANCollection_Stl.cxx in debug mode
# suggesting using msvc "Checked Iterators"
add_definitions("-D_SCL_SECURE_NO_WARNINGS")
endif()
# Exclude system-provided glext.h.
# These macros are already defined within OpenGl_GlFunctions.hxx,
# however we have to duplicate them here for building TKOpenGl with PCH.
add_definitions("-DGL_GLEXT_LEGACY")
add_definitions("-DGLX_GLXEXT_LEGACY")
# workaround for old gcc
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
add_definitions("-D__STDC_CONSTANT_MACROS")
add_definitions("-D__STDC_FORMAT_MACROS")
endif()
# unity builds are not used since they do not add speed but cause conflicts
# in TKV3d
set_target_properties(${PROJECT_NAME} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
cotire(${PROJECT_NAME})
endif()

View File

@ -24,7 +24,6 @@
* miniz: No packages, author suggests using in the source tree
* qhull: libqhull-dev does not contain libqhullcpp => link errors. Until it is fixed, we will use the builtin version. https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=925540
* semver: One module C library, author expects to use clib for installation. No packages.
* Shiny: no packages
## Header only
* igl

4
resources/icons/edit.svg Normal file
View File

@ -0,0 +1,4 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M38.2923 1.34808L38.2441 1.30417C37.3235 0.463194 36.1301 0 34.8837 0C33.4864 0 32.1449 0.591489 31.2029 1.62267L13.3916 21.1224C13.2293 21.3002 13.1061 21.5099 13.03 21.7381L10.9357 28.0167C10.6935 28.7426 10.815 29.5453 11.2607 30.164C11.7099 30.7875 12.4336 31.1598 13.1967 31.1598H13.1968C13.5269 31.1598 13.8495 31.0919 14.1555 30.958L20.2195 28.3052C20.44 28.2087 20.6377 28.0671 20.8 27.8894L38.6114 8.38977C40.4648 6.36078 40.3219 3.20211 38.2923 1.34808ZM14.9484 26.8569L16.1773 23.1726L16.281 23.0591L18.6102 25.1866L18.5066 25.3001L14.9484 26.8569ZM36.0718 6.07002L20.93 22.6472L18.6007 20.5197L33.7426 3.94242C34.0387 3.61819 34.444 3.43956 34.8838 3.43956C35.2696 3.43956 35.6391 3.5831 35.9251 3.84428L35.9731 3.88819C36.6019 4.46248 36.6461 5.44127 36.0718 6.07002V6.07002Z" fill="#ED6B21"/>
<path d="M34.8369 15.8664C33.8871 15.8664 33.1171 16.6364 33.1171 17.5862V32.1868C33.1171 34.5984 31.155 36.5604 28.7435 36.5604H7.89985C5.48815 36.5604 3.52623 34.5984 3.52623 32.1868V11.5125C3.52623 9.10094 5.48826 7.1389 7.89985 7.1389H22.9865C23.9363 7.1389 24.7063 6.3689 24.7063 5.41912C24.7063 4.46934 23.9363 3.69934 22.9865 3.69934H7.89985C3.59158 3.69934 0.0866699 7.20437 0.0866699 11.5125V32.1867C0.0866699 36.4949 3.59169 39.9999 7.89985 39.9999H28.7433C33.0515 39.9999 36.5565 36.4949 36.5565 32.1867V17.5862C36.5566 16.6364 35.7866 15.8664 34.8369 15.8664V15.8664Z" fill="#808080"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-08-12 10:25+0200\n"
"PO-Revision-Date: 2022-07-22 21:49+0800\n"
"PO-Revision-Date: 2022-08-22 12:37+0800\n"
"Last-Translator: Bral@qq.com\n"
"Language-Team: \n"
"Language: zh_CN\n"
@ -3291,11 +3291,11 @@ msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:980
msgid "Import"
msgstr "进口"
msgstr "导入"
#: src/slic3r/GUI/GUI_App.cpp:981
msgid "Don't import"
msgstr "不要进口"
msgstr "不要导入"
#: src/slic3r/GUI/GUI_App.cpp:989
msgid "Continue and import newer configuration?"
@ -13639,6 +13639,8 @@ msgid ""
"perimeters with variable extrusion width. This setting also affects the "
"Concentric infill."
msgstr ""
"经典轮廓生成器产生具有恒定挤出宽度的轮廓,并且对于非常薄的区域使用间隙填充。 "
"Arachne 引擎产生具有可变挤出宽度的轮廓。这个设置也会影响回环填充。"
#: src/libslic3r/PrintConfig.cpp:3074
msgid "Classic"
@ -13659,6 +13661,8 @@ msgid ""
"perimeter segments. If expressed as a percentage (for example 100%), it will "
"be computed based on the nozzle diameter."
msgstr ""
"当随着零件变薄而在不同数量的轮廓之间过渡时,会分配出一定的空间来分割或连接轮"
"廓段。如果用百分比表示(例如 100%),它将根据喷嘴直径计算出来。"
#: src/libslic3r/PrintConfig.cpp:3091
msgid "Perimeter transitioning filter margin"
@ -13721,6 +13725,9 @@ msgid ""
"a percentage (for example 25%), it will be computed based on the nozzle "
"diameter."
msgstr ""
"薄型特征的最小厚度。比这个值薄的模型特征将不被打印,而比最小特征尺寸厚的特征"
"将被加宽到最小轮廓的宽度。如果以百分比表示(例如 25%),它将根据喷嘴直径计"
"算。"
#: src/libslic3r/PrintConfig.cpp:3140
msgid "Minimum perimeter width"

View File

@ -1,4 +1,5 @@
min_slic3r_version = 2.5.0-alpha0
0.2.1 Added Ender 3 Neo and Ender 3 S1 Plus. Various updates.
0.2.0 Added alternative nozzle support
0.1.5 Added Ender-3 S1 Pro
min_slic3r_version = 2.4.1

View File

@ -5,7 +5,7 @@
name = Creality
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 0.2.0
config_version = 0.2.1
# Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Creality/
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -41,6 +41,15 @@ bed_model = ender3_bed.stl
bed_texture = ender3.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER3NEO]
name = Creality Ender-3 Neo
variants = 0.4; 0.3; 0.5; 0.6
technology = FFF
family = ENDER
bed_model = ender3_bed.stl
bed_texture = ender3.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER3V2]
name = Creality Ender-3 V2
variants = 0.4; 0.3; 0.5; 0.6
@ -77,6 +86,15 @@ bed_model = ender3v2_bed.stl
bed_texture = ender3v2.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER3S1PLUS]
name = Creality Ender-3 S1 Plus
variants = 0.4; 0.3; 0.5; 0.6
technology = FFF
family = ENDER
bed_model = cr10v2_bed.stl
bed_texture = cr10spro.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER3MAX]
name = Creality Ender-3 Max
variants = 0.4; 0.3; 0.5; 0.6
@ -531,11 +549,11 @@ support_material_spacing = 1
first_layer_height = 0.2
extrusion_width = 0.33
external_perimeter_extrusion_width = 0.31
first_layer_extrusion_width = 0.33
first_layer_extrusion_width = 0.31
infill_extrusion_width = 0.33
perimeter_extrusion_width = 0.33
solid_infill_extrusion_width = 0.33
top_infill_extrusion_width = 0.33
top_infill_extrusion_width = 0.30
support_material_extrusion_width = 0.27
[print:*0.4nozzle*]
@ -545,11 +563,11 @@ support_material_spacing = 1
first_layer_height = 0.2
extrusion_width = 0.44
external_perimeter_extrusion_width = 0.42
first_layer_extrusion_width = 0.44
first_layer_extrusion_width = 0.42
infill_extrusion_width = 0.44
perimeter_extrusion_width = 0.44
solid_infill_extrusion_width = 0.44
top_infill_extrusion_width = 0.44
top_infill_extrusion_width = 0.40
support_material_extrusion_width = 0.36
[print:*0.5nozzle*]
@ -559,11 +577,11 @@ support_material_spacing = 1.1
first_layer_height = 0.2
extrusion_width = 0.55
external_perimeter_extrusion_width = 0.52
first_layer_extrusion_width = 0.55
first_layer_extrusion_width = 0.52
infill_extrusion_width = 0.55
perimeter_extrusion_width = 0.55
solid_infill_extrusion_width = 0.55
top_infill_extrusion_width = 0.55
top_infill_extrusion_width = 0.50
support_material_extrusion_width = 0.45
[print:*0.6nozzle*]
@ -573,11 +591,11 @@ support_material_spacing = 1.2
first_layer_height = 0.3
extrusion_width = 0.66
external_perimeter_extrusion_width = 0.63
first_layer_extrusion_width = 0.66
first_layer_extrusion_width = 0.63
infill_extrusion_width = 0.66
perimeter_extrusion_width = 0.66
solid_infill_extrusion_width = 0.66
top_infill_extrusion_width = 0.66
top_infill_extrusion_width = 0.60
support_material_extrusion_width = 0.54
@ -1268,6 +1286,25 @@ inherits = *ENDER3PRO*; *0.6nozzle*
[printer:*ENDER3NEO*]
inherits = *ENDER3*; *fastabl*
printer_model = ENDER3NEO
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER3NEO\nPRINTER_HAS_BOWDEN
[printer:Creality Ender-3 Neo (0.3 mm nozzle)]
inherits = *ENDER3NEO*; *0.3nozzle*
[printer:Creality Ender-3 Neo (0.4 mm nozzle)]
inherits = *ENDER3NEO*; *0.4nozzle*
[printer:Creality Ender-3 Neo (0.5 mm nozzle)]
inherits = *ENDER3NEO*; *0.5nozzle*
[printer:Creality Ender-3 Neo (0.6 mm nozzle)]
inherits = *ENDER3NEO*; *0.6nozzle*
[printer:*ENDER3V2*]
inherits = *common*; *bowden*; *pauseprint*
bed_shape = 5x0,215x0,215x220,5x220
@ -1312,7 +1349,7 @@ inherits = *ENDER3V2NEO*; *0.6nozzle*
[printer:*ENDER3S1*]
inherits = *common*; *bowden*; *spriteextruder*; *pauseprint*
inherits = *common*; *fastabl*; *spriteextruder*; *pauseprint*
bed_shape = 5x0,215x0,215x220,5x220
max_print_height = 270
printer_model = ENDER3S1
@ -1334,7 +1371,7 @@ inherits = *ENDER3S1*; *0.6nozzle*
[printer:*ENDER3S1PRO*]
inherits = *common*; *bowden*; *spriteextruder*; *pauseprint*
inherits = *common*; *fastabl*; *spriteextruder*; *pauseprint*
bed_shape = 5x0,215x0,215x220,5x220
max_print_height = 270
printer_model = ENDER3S1PRO
@ -1355,6 +1392,26 @@ inherits = *ENDER3S1PRO*; *0.6nozzle*
[printer:*ENDER3S1PLUS*]
inherits = *common*; *slowabl*; *spriteextruder*; *pauseprint*
bed_shape = 5x5,295x5,295x295,5x295
max_print_height = 300
printer_model = ENDER3S1PLUS
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER3S1PLUS
[printer:Creality Ender-3 S1 Plus (0.3 mm nozzle)]
inherits = *ENDER3S1PLUS*; *0.3nozzle*
[printer:Creality Ender-3 S1 Plus (0.4 mm nozzle)]
inherits = *ENDER3S1PLUS*; *0.4nozzle*
[printer:Creality Ender-3 S1 Plus (0.5 mm nozzle)]
inherits = *ENDER3S1PLUS*; *0.5nozzle*
[printer:Creality Ender-3 S1 Plus (0.6 mm nozzle)]
inherits = *ENDER3S1PLUS*; *0.6nozzle*
[printer:*ENDER3MAX*]
inherits = *common*; *bowdenlong*; *pauseprint*
@ -1669,7 +1726,7 @@ inherits = *CR10SMART*; *0.6nozzle*
[printer:*CR10SMARTPRO*]
inherits = *common*; *bowdenlong*; *slowabl*; *spriteextruder*
inherits = *common*; *slowabl*; *spriteextruder*
bed_shape = 5x5,295x5,295x295,5x295
max_print_height = 400
printer_model = CR10SMARTPRO

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -1,6 +1,10 @@
min_slic3r_version = 2.5.0-alpha0
1.5.1 Renamed filament type "NYLON" to "PA". Updated Adura X profile. Updated PETG fan settings for Prusa MINI (removed fan ramp up).
1.5.0 Updated arachne parameters. Added profiles for Jessie filaments.
1.5.0-alpha1 Added filament profile for Prusament PA11 Carbon Fiber. Added profiles for multiple 3D-Fuel filaments.
1.5.0-alpha0 Added parameters for Arachne perimeter generator. Changed default seam position. Updated output filename format.
min_slic3r_version = 2.4.0-rc
1.4.7 Added filament profile for Prusament PA11 Carbon Fiber. Added profiles for multiple 3D-Fuel filaments.
1.4.6 Added SLA materials. Updated filament profiles.
1.4.5 Added MMU2/S profiles for 0.25mm nozzle. Updated FW version. Enabled g-code thumbnails for MK3 family printers. Updated end g-code.
1.4.4 Added multiple Fiberlogy filament profiles. Updated Extrudr filament profiles.

View File

@ -5,7 +5,7 @@
name = Prusa Research
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 1.5.0-alpha0
config_version = 1.5.1
# Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/
changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -30,7 +30,7 @@ technology = FFF
family = MK3
bed_model = mk3_bed.stl
bed_texture = mk3.svg
default_materials = Generic PLA; Generic ABS; Generic PETG; Prusament PLA; Prusament PETG; Prusament ASA; Prusament PC Blend; Prusament PC Blend Carbon Fiber; Prusament PVB
default_materials = Generic PLA; Generic ABS; Generic PETG; Prusament PLA; Prusament PETG; Prusament ASA; Prusament PC Blend; Prusament PC Blend Carbon Fiber; Prusament PVB; Prusament PA11 Carbon Fiber
[printer_model:MK3]
name = Original Prusa i3 MK3
@ -39,7 +39,7 @@ technology = FFF
family = MK3
bed_model = mk3_bed.stl
bed_texture = mk3.svg
default_materials = Generic PLA; Generic ABS; Generic PETG; Prusament PLA; Prusament PETG; Prusament ASA; Prusament PC Blend; Prusament PC Blend Carbon Fiber; Prusament PVB
default_materials = Generic PLA; Generic ABS; Generic PETG; Prusament PLA; Prusament PETG; Prusament ASA; Prusament PC Blend; Prusament PC Blend Carbon Fiber; Prusament PVB; Prusament PA11 Carbon Fiber
[printer_model:MK3SMMU2S]
name = Original Prusa i3 MK3S && MK3S+ MMU2S
@ -66,7 +66,7 @@ technology = FFF
family = MK2.5
bed_model = mk3_bed.stl
bed_texture = mk3.svg
default_materials = Generic PLA; Generic ABS; Generic PETG; Prusament PLA; Prusament PETG; Prusament ASA; Prusament PC Blend; Prusament PC Blend Carbon Fiber; Prusament PVB
default_materials = Generic PLA; Generic ABS; Generic PETG; Prusament PLA; Prusament PETG; Prusament ASA; Prusament PC Blend; Prusament PC Blend Carbon Fiber; Prusament PVB; Prusament PA11 Carbon Fiber @MK2
[printer_model:MK2.5]
name = Original Prusa i3 MK2.5
@ -75,7 +75,7 @@ technology = FFF
family = MK2.5
bed_model = mk3_bed.stl
bed_texture = mk3.svg
default_materials = Generic PLA; Generic ABS; Generic PETG; Prusament PLA; Prusament PETG; Prusament ASA; Prusament PC Blend; Prusament PC Blend Carbon Fiber; Prusament PVB
default_materials = Generic PLA; Generic ABS; Generic PETG; Prusament PLA; Prusament PETG; Prusament ASA; Prusament PC Blend; Prusament PC Blend Carbon Fiber; Prusament PVB; Prusament PA11 Carbon Fiber @MK2
[printer_model:MK2.5SMMU2S]
name = Original Prusa i3 MK2.5S MMU2S
@ -102,7 +102,7 @@ technology = FFF
family = MK2
bed_model = mk2_bed.stl
bed_texture = mk2.svg
default_materials = Generic PLA; Generic ABS; Generic PETG; Prusament PLA; Prusament PETG; Prusament ASA; Prusament PC Blend; Prusament PC Blend Carbon Fiber; Prusament PVB
default_materials = Generic PLA; Generic ABS; Generic PETG; Prusament PLA; Prusament PETG; Prusament ASA; Prusament PC Blend; Prusament PC Blend Carbon Fiber; Prusament PVB; Prusament PA11 Carbon Fiber @MK2
[printer_model:MK2SMM]
name = Original Prusa i3 MK2S MMU1
@ -243,14 +243,11 @@ bottom_solid_min_thickness = 0.5
gcode_label_objects = 1
infill_anchor = 2.5
infill_anchor_max = 12
wall_add_middle_threshold = 75%
wall_split_middle_threshold = 50%
wall_transition_angle = 10
wall_transition_filter_deviation = 25%
wall_transition_length = 0.4
wall_distribution_count = 1
min_bead_width = 85%
min_feature_size = 0.1
[print:*MK3*]
fill_pattern = grid
@ -297,14 +294,11 @@ thick_bridges = 0
bridge_flow_ratio = 1
bridge_speed = 20
wipe_tower_bridging = 6
wall_add_middle_threshold = 85%
wall_split_middle_threshold = 70%
wall_transition_angle = 10
wall_transition_filter_deviation = 25%
wall_transition_length = 0.25
wall_distribution_count = 1
min_bead_width = 85%
min_feature_size = 0.0625
[print:*0.25nozzleMK3*]
inherits = *0.25nozzle*
@ -353,14 +347,11 @@ bottom_solid_min_thickness = 0.6
thick_bridges = 1
bridge_flow_ratio = 0.95
bridge_speed = 25
wall_add_middle_threshold = 85%
wall_split_middle_threshold = 70%
wall_transition_angle = 10
wall_transition_filter_deviation = 25%
wall_transition_length = 0.6
wall_distribution_count = 1
min_bead_width = 85%
min_feature_size = 0.15
[print:*0.6nozzleMK3*]
inherits = *0.6nozzle*
@ -422,14 +413,11 @@ bottom_solid_min_thickness = 0.8
single_extruder_multi_material_priming = 0
thick_bridges = 1
overhangs = 0
wall_add_middle_threshold = 85%
wall_split_middle_threshold = 70%
wall_transition_angle = 10
wall_transition_filter_deviation = 25%
wall_transition_length = 0.8
wall_distribution_count = 1
min_bead_width = 85%
min_feature_size = 0.2
[print:*soluble_support*]
overhangs = 1
@ -926,6 +914,7 @@ top_solid_infill_speed = 40
fill_pattern = gyroid
fill_density = 15%
perimeters = 3
wipe_tower_bridging = 5
[print:0.15mm QUALITY @MK3]
inherits = *0.15mm*; *MK3*
@ -1620,9 +1609,9 @@ filament_retract_lift = 0.2
compatible_printers_condition = printer_model=="MK2SMM"
[filament:*PETMINI*]
# inherits = *PET*
full_fan_speed_layer = 0
filament_retract_length = nil
filament_retract_speed = 40
filament_retract_speed = 45
filament_deretract_speed = 25
filament_retract_lift = nil
filament_retract_before_travel = 1
@ -1631,9 +1620,9 @@ compatible_printers_condition = printer_model=="MINI"
start_filament_gcode = "M900 K{if nozzle_diameter[0]==0.6}0.12{elsif nozzle_diameter[0]==0.8}0.06{else}0.2{endif} ; Filament gcode"
[filament:*PETMINI06*]
# inherits = *PET*
full_fan_speed_layer = 0
filament_retract_length = nil
filament_retract_speed = 40
filament_retract_speed = 45
filament_deretract_speed = 25
filament_retract_lift = nil
filament_retract_before_travel = 1
@ -1642,7 +1631,6 @@ start_filament_gcode = "M900 K0.12 ; Filament gcode"
filament_max_volumetric_speed = 13
[filament:*ABSMINI*]
# inherits = *ABS*
bed_temperature = 100
first_layer_bed_temperature = 100
filament_retract_length = 2.7
@ -2057,6 +2045,28 @@ disable_fan_first_layers = 6
compatible_printers_condition = nozzle_diameter[0]>=0.4 and nozzle_diameter[0]!=0.8 and printer_notes=~/.*PRINTER_MODEL_MK(2|2.5).*/ and ! (printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and single_extruder_multi_material)
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{else}0.07{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0"
[filament:Prusament PA11 Carbon Fiber]
inherits = Prusament PC Blend Carbon Fiber
filament_cost = 151.24
filament_density = 1.11
filament_type = PA
filament_max_volumetric_speed = 6.5
extrusion_multiplier = 1.05
first_layer_temperature = 275
temperature = 285
first_layer_bed_temperature = 90
bed_temperature = 115
fan_below_layer_time = 10
compatible_printers_condition = printer_notes!~/.*PRINTER_MODEL_MK(2|2.5).*/ and nozzle_diameter[0]>=0.4 and nozzle_diameter[0]!=0.8 and printer_model!="MINI" and ! single_extruder_multi_material
[filament:Prusament PA11 Carbon Fiber @MK2]
inherits = Prusament PA11 Carbon Fiber
first_layer_bed_temperature = 90
bed_temperature = 110
disable_fan_first_layers = 6
compatible_printers_condition = nozzle_diameter[0]>=0.4 and nozzle_diameter[0]!=0.8 and printer_notes=~/.*PRINTER_MODEL_MK(2|2.5).*/ and ! (printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and single_extruder_multi_material)
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{else}0.07{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0"
[filament:Fillamentum CPE]
inherits = *PET*
filament_vendor = Fillamentum
@ -2376,10 +2386,10 @@ inherits = *PET*
filament_vendor = addnorth
filament_cost = 29.99
filament_density = 1.27
filament_type = NYLON
filament_type = PA
extrusion_multiplier = 0.98
bed_temperature = 60
first_layer_bed_temperature = 60
bed_temperature = 115
first_layer_bed_temperature = 105
first_layer_temperature = 265
temperature = 270
fan_always_on = 0
@ -2396,7 +2406,7 @@ filament_retract_lift = 0.4
filament_max_volumetric_speed = 4
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{else}0.08{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0"
filament_spool_weight = 0
compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model!="MINI" and printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
compatible_printers_condition = printer_notes!~/.*PRINTER_MODEL_MK(2|2.5).*/ and nozzle_diameter[0]>=0.4 and printer_model!="MINI" and printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
[filament:addnorth Adura X @MINI]
inherits = addnorth Adura X
@ -2404,14 +2414,24 @@ filament_retract_length = nil
filament_retract_lift = nil
filament_retract_speed = 40
filament_deretract_speed = 25
bed_temperature = 60
first_layer_bed_temperature = 60
compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI"
[filament:addnorth Adura X @MMU1]
inherits = addnorth Adura X
filament_retract_length = nil
filament_retract_lift = nil
bed_temperature = 60
first_layer_bed_temperature = 60
compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MK2SMM"
[filament:addnorth Adura X @MK2]
inherits = addnorth Adura X
bed_temperature = 110
first_layer_bed_temperature = 105
compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_notes=~/.*PRINTER_MODEL_MK(2|2.5).*/ and ! (printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and single_extruder_multi_material)
[filament:addnorth E-PLA]
inherits = *PLA*
filament_vendor = addnorth
@ -2684,6 +2704,75 @@ filament_cost = 25.4
filament_density = 1.24
compatible_printers_condition = nozzle_diameter[0]!=0.8 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
[filament:3D-Fuel Standard PLA]
inherits = *PLA*
filament_vendor = 3D-Fuel
filament_cost = 22.14
filament_density = 1.24
filament_max_volumetric_speed = 10
first_layer_temperature = 210
temperature = 200
[filament:3D-Fuel EasiPrint PLA]
inherits = 3D-Fuel Standard PLA
filament_cost = 30.44
[filament:3D-Fuel Pro PLA]
inherits = *PLA*
filament_vendor = 3D-Fuel
filament_cost = 26.57
filament_density = 1.22
filament_max_volumetric_speed = 12
first_layer_temperature = 220
temperature = 215
filament_retract_lift = 0
[filament:3D-Fuel Buzzed]
inherits = 3D-Fuel Standard PLA
filament_cost = 44.27
filament_retract_lift = 0
first_layer_temperature = 210
temperature = 195
filament_max_volumetric_speed = 8
[filament:3D-Fuel Wound up]
inherits = 3D-Fuel Buzzed
filament_cost = 44.27
filament_retract_lift = nil
first_layer_temperature = 215
temperature = 210
filament_max_volumetric_speed = 8
[filament:3D-Fuel Workday ABS]
inherits = *ABSC*
filament_vendor = 3D-Fuel
filament_cost = 23.25
filament_density = 1.04
[filament:3D-Fuel Workday ABS @MINI]
inherits = 3D-Fuel Workday ABS; *ABSMINI*
[filament:Jessie PLA]
inherits = *PLA*
filament_vendor = Printed Solid
filament_cost = 21
filament_density = 1.24
filament_max_volumetric_speed = 12
[filament:Jessie PETG]
inherits = *PET*
filament_vendor = Printed Solid
filament_cost = 22
filament_density = 1.27
first_layer_temperature = 240
first_layer_bed_temperature = 85
temperature = 245
bed_temperature = 90
filament_max_volumetric_speed = 7
[filament:Jessie PETG @MINI]
inherits = Jessie PETG; *PETMINI*
[filament:Devil Design PLA]
inherits = *PLA*
filament_vendor = Devil Design
@ -2941,7 +3030,7 @@ bed_temperature = 115
fan_always_on = 0
cooling = 0
bridge_fan_speed = 25
filament_type = NYLON
filament_type = PA
filament_max_volumetric_speed = 8
compatible_printers_condition = printer_notes!~/.*PRINTER_MODEL_MK(2|2.5).*/ and printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
@ -4085,7 +4174,7 @@ filament_cost = 27.65
[filament:Fiberlogy Nylon PA12]
inherits = Fiberlogy ASA
filament_type = NYLON
filament_type = PA
filament_density = 1.01
filament_cost = 48
first_layer_bed_temperature = 105
@ -4318,7 +4407,7 @@ inherits = *common*
filament_vendor = Taulman
filament_cost = 40
filament_density = 1.13
bed_temperature = 90
bed_temperature = 110
bridge_fan_speed = 40
cooling = 0
disable_fan_first_layers = 3
@ -4327,13 +4416,22 @@ fan_below_layer_time = 20
filament_colour = #DEE0E6
filament_max_volumetric_speed = 7
filament_soluble = 0
filament_type = NYLON
first_layer_bed_temperature = 60
first_layer_temperature = 240
filament_type = PA
first_layer_bed_temperature = 90
first_layer_temperature = 260
temperature = 260
max_fan_speed = 0
min_fan_speed = 0
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{else}0.08{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0"
compatible_printers_condition = printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
[filament:Taulman Bridge @MINI]
inherits = Taulman Bridge
bed_temperature = 90
first_layer_bed_temperature = 60
first_layer_temperature = 240
temperature = 250
compatible_printers_condition = printer_model=="MINI"
[filament:Fillamentum Nylon FX256]
inherits = *common*
@ -4352,7 +4450,7 @@ slowdown_below_layer_time = 20
filament_colour = #DEE0E6
filament_max_volumetric_speed = 6
filament_soluble = 0
filament_type = NYLON
filament_type = PA
first_layer_bed_temperature = 90
first_layer_temperature = 250
max_fan_speed = 0
@ -4365,10 +4463,10 @@ inherits = *common*
filament_vendor = Fiberthree
filament_cost = 200.84
filament_density = 1.2
bed_temperature = 70
first_layer_bed_temperature = 75
first_layer_temperature = 270
temperature = 270
bed_temperature = 90
first_layer_bed_temperature = 90
first_layer_temperature = 285
temperature = 285
bridge_fan_speed = 30
cooling = 1
disable_fan_first_layers = 3
@ -4379,7 +4477,7 @@ slowdown_below_layer_time = 10
filament_colour = #DEE0E6
filament_max_volumetric_speed = 5
filament_soluble = 0
filament_type = NYLON
filament_type = PA
max_fan_speed = 20
min_fan_speed = 20
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.05{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0"
@ -4395,10 +4493,10 @@ inherits = *common*
filament_vendor = Fiberthree
filament_cost = 208.1
filament_density = 1.25
bed_temperature = 70
first_layer_bed_temperature = 75
first_layer_temperature = 275
temperature = 275
bed_temperature = 90
first_layer_bed_temperature = 90
first_layer_temperature = 285
temperature = 285
bridge_fan_speed = 30
cooling = 1
disable_fan_first_layers = 3
@ -4409,7 +4507,7 @@ slowdown_below_layer_time = 10
filament_colour = #DEE0E6
filament_max_volumetric_speed = 5
filament_soluble = 0
filament_type = NYLON
filament_type = PA
max_fan_speed = 0
min_fan_speed = 0
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.05{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0"
@ -4695,6 +4793,10 @@ compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.
[filament:Fiberthree F3 PA Pure Pro @MINI]
inherits = Fiberthree F3 PA Pure Pro
filament_max_volumetric_speed = 4
first_layer_temperature = 280
temperature = 280
first_layer_bed_temperature = 75
bed_temperature = 70
filament_retract_length = nil
filament_retract_speed = nil
filament_retract_lift = nil
@ -4704,6 +4806,10 @@ compatible_printers_condition = printer_model=="MINI"
[filament:Fiberthree F3 PA-CF Pro @MINI]
inherits = Fiberthree F3 PA-CF Pro
first_layer_temperature = 280
temperature = 280
first_layer_bed_temperature = 75
bed_temperature = 70
filament_max_volumetric_speed = 4
filament_retract_length = nil
filament_retract_speed = nil
@ -5083,6 +5189,16 @@ filament_max_volumetric_speed = 13
filament_retract_lift = 0.25
compatible_printers_condition = printer_notes!~/.*PRINTER_MODEL_MK(2|2.5).*/ and nozzle_diameter[0]==0.8 and printer_model!="MINI" and ! single_extruder_multi_material
[filament:Prusament PA11 Carbon Fiber @0.8 nozzle]
inherits = Prusament PA11 Carbon Fiber
filament_max_volumetric_speed = 11
compatible_printers_condition = printer_notes!~/.*PRINTER_MODEL_MK(2|2.5).*/ and nozzle_diameter[0]==0.8 and printer_model!="MINI" and ! single_extruder_multi_material
[filament:Prusament PA11 Carbon Fiber @0.8 nozzle MK2]
inherits = Prusament PA11 Carbon Fiber @MK2
filament_max_volumetric_speed = 11
compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_model!="MK2SMM" and printer_notes=~/.*PRINTER_MODEL_MK(2|2.5).*/ and ! (printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and single_extruder_multi_material)
[filament:Prusament PC Blend @0.8 nozzle MK2]
inherits = Prusament PC Blend @MK2
filament_max_volumetric_speed = 13
@ -8839,7 +8955,7 @@ inherits = Original Prusa i3 MK2S
printer_model = MK2.5
remaining_times = 1
machine_max_jerk_e = 4.5
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n{if filament_settings_id[initial_tool]=~/.*Prusament PA11.*/}\nG1 Z0.3 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E9 F1000 ; intro line\n{else}\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\n{endif}\nG92 E0
[printer:Original Prusa i3 MK2.5 0.25 nozzle]
inherits = Original Prusa i3 MK2S 0.25 nozzle
@ -8853,7 +8969,8 @@ inherits = Original Prusa i3 MK2S 0.6 nozzle
printer_model = MK2.5
remaining_times = 1
machine_max_jerk_e = 4.5
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
deretract_speed = 25
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n{if filament_settings_id[initial_tool]=~/.*Prusament PA11.*/}\nG1 Z0.3 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E9 F1000 ; intro line\n{else}\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\n{endif}\nG92 E0
[printer:Original Prusa i3 MK2.5 0.8 nozzle]
inherits = Original Prusa i3 MK2S 0.6 nozzle
@ -8862,10 +8979,13 @@ nozzle_diameter = 0.8
printer_variant = 0.8
max_layer_height = 0.6
min_layer_height = 0.2
retract_length = 1
retract_length = 0.7
retract_speed = 35
deretract_speed = 20
retract_lift = 0.25
remaining_times = 1
machine_max_jerk_e = 4.5
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n{if filament_settings_id[initial_tool]=~/.*Prusament PA11.*/}\nG1 Z0.3 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E9 F1000 ; intro line\n{else}\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\n{endif}\nG92 E0
default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle
color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
@ -8939,7 +9059,10 @@ max_layer_height = 0.6
min_layer_height = 0.2
nozzle_diameter = 0.8
printer_variant = 0.8
retract_length = 1
retract_length = 0.7
retract_speed = 35
deretract_speed = 20
retract_lift = 0.25
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n
default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle
@ -8952,6 +9075,7 @@ max_layer_height = 0.35
min_layer_height = 0.1
nozzle_diameter = 0.6
printer_variant = 0.6
deretract_speed = 25
default_print_profile = 0.20mm NORMAL @0.6 nozzle
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
@ -8985,6 +9109,7 @@ nozzle_diameter = 0.6,0.6,0.6,0.6,0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
deretract_speed = 25
default_print_profile = 0.20mm NORMAL @0.6 nozzle
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
@ -8994,6 +9119,7 @@ nozzle_diameter = 0.6,0.6,0.6,0.6,0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
deretract_speed = 25
default_print_profile = 0.20mm NORMAL @0.6 nozzle
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
@ -9067,7 +9193,7 @@ remaining_times = 1
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
retract_lift_below = 209
max_print_height = 210
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n{if filament_settings_id[initial_tool]=~/.*Prusament PA11.*/}\nG1 Z0.3 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E9 F1000 ; intro line\n{else}\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\n{endif}\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
printer_model = MK3
default_print_profile = 0.15mm QUALITY @MK3
thumbnails = 160x120
@ -9089,7 +9215,8 @@ nozzle_diameter = 0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}
deretract_speed = 25
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n{if filament_settings_id[initial_tool]=~/.*Prusament PA11.*/}\nG1 Z0.3 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E9 F1000 ; intro line\n{else}\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\n{endif}\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}
default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
@ -9099,8 +9226,11 @@ nozzle_diameter = 0.8
max_layer_height = 0.6
min_layer_height = 0.2
printer_variant = 0.8
retract_length = 1
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0\nM221 S95
retract_length = 0.7
retract_speed = 35
deretract_speed = 20
retract_lift = 0.25
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n{if filament_settings_id[initial_tool]=~/.*Prusament PA11.*/}\nG1 Z0.3 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E9 F1000 ; intro line\n{else}\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\n{endif}\nG92 E0\nM221 S95
default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle
color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
@ -9182,6 +9312,7 @@ nozzle_diameter = 0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
deretract_speed = 25
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
@ -9193,7 +9324,10 @@ nozzle_diameter = 0.8
max_layer_height = 0.6
min_layer_height = 0.2
printer_variant = 0.8
retract_length = 1
retract_length = 0.7
retract_speed = 35
deretract_speed = 20
retract_lift = 0.25
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle
@ -9235,6 +9369,7 @@ nozzle_diameter = 0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
deretract_speed = 25
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
@ -9246,7 +9381,10 @@ nozzle_diameter = 0.8
max_layer_height = 0.6
min_layer_height = 0.2
printer_variant = 0.8
retract_length = 1
retract_length = 0.7
retract_speed = 35
deretract_speed = 20
retract_lift = 0.25
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle
@ -9283,6 +9421,7 @@ nozzle_diameter = 0.6,0.6,0.6,0.6,0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
deretract_speed = 25
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
@ -9293,6 +9432,7 @@ nozzle_diameter = 0.6,0.6,0.6,0.6,0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
deretract_speed = 25
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
@ -9424,8 +9564,10 @@ max_layer_height = 0.55
min_layer_height = 0.2
default_print_profile = 0.40mm QUALITY @0.8 nozzle MINI
default_filament_profile = Prusament PLA @0.8 nozzle
retract_length = 3.5
retract_length = 3
retract_before_travel = 1.5
retract_speed = 45
deretract_speed = 20
[printer:Original Prusa SL1]
printer_technology = SLA

View File

@ -1,3 +1,4 @@
min_slic3r_version = 2.4.0-alpha0
1.0.1 Speed improvements, start gcode changes, added HIPS filament.
1.0.0 Initial version

View File

@ -1,14 +1,14 @@
# Print profiles for the gCreate printers.
#
# GTL Modified 210706 (at gCreate Shop)
#
# GTL Modified 220825 (at gCreate Shop)
# Speed improvements, start/end gCode changes
[vendor]
# Vendor name will be shown by the Config Wizard.
name = gCreate
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 1.0.0
config_version = 1.0.1
# Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/gCreate/
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -548,6 +548,7 @@ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_GCREATE.*/
# Common filament preset across all PLA filaments
[filament:*PLA*]
inherits = *common*
extrusion_multiplier = 0.94
bed_temperature = 60
fan_below_layer_time = 15
filament_colour = #FF3232
@ -749,11 +750,20 @@ filament_vendor = ProtoPasta
temperature = 250
bed_temperature = 70
[filament:Generic HIPS @GCREATE]
inherits = *PET*
filament_vendor = Generic
filament_density = 1.04
temperature = 230
first_layer_temperature = 235
bed_temperature = 100
first_layer_bed_temperature = 100
filament_type = HIPS
[filament:Generic TPU 90A @GCREATE]
inherits = *TPU90A*
filament_vendor = Generic
[filament:Generic CF PETG @GCREATE]
inherits = *CFPETG*
filament_vendor = Generic
@ -770,8 +780,6 @@ filament_vendor = Generic
inherits = *WOODFILLPLA*
filament_vendor = ColorFabb
[filament:Generic PVA @GCREATE - PLA and PVA Support]
bed_temperature = 0
bridge_fan_speed = 75
@ -830,8 +838,8 @@ machine_max_feedrate_x = 500
machine_max_feedrate_y = 500
machine_max_feedrate_z = 10
machine_max_jerk_e = 2.5
machine_max_jerk_x = 3
machine_max_jerk_y = 3
machine_max_jerk_x = 10
machine_max_jerk_y = 10
machine_max_jerk_z = 0.4
machine_min_extruding_rate = 0
machine_min_travel_rate = 0
@ -893,7 +901,7 @@ retract_speed = 70
deretract_speed = 40
retract_before_wipe = 70%
default_print_profile = 0.20mm - Standard Layers @GCREATE
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 ; home all\nG92 E0.0
start_gcode = M420 Z20\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 ; home all\nG92 E0.0
end_gcode = M104 S0 T0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+5, max_print_height)} F600{endif} ; Move print head up\nG1 X5 Y170 F3000 ; present print\n{if layer_z < max_print_height-10}G1 Z{z_offset+min(layer_z+70, max_print_height-10)} F600{endif} ; Move print head up\nM84 X Y E ; disable motors
#[printer:*abl*]
@ -906,6 +914,7 @@ printer_model = GMAX2PRO
max_layer_height = 0.7
min_layer_height = 0.08
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_GCREATE\nPRINTER_MODEL_GMAX2PRO
start_gcode = G90\nG28\nM420 Z20\nG1 Z5 F5000
bed_shape = 0x0,457x0,457x457,0x457
max_print_height = 610
@ -929,7 +938,7 @@ printer_model = GMAX2DUAL2IN1
max_layer_height = 0.7
min_layer_height = 0.08
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_GCREATE\nPRINTER_MODEL_GMAX2DUAL2IN1
start_gcode = G90 ;\n G28 ;\n G1 Z5 F5000
start_gcode = G90\nG28\nM420 Z20\nG1 Z5 F5000
bed_shape = 0x0,457x0,457x457,0x457
max_print_height = 610
default_print_profile = 0.20mm - Standard Layers @GCREATE
@ -951,7 +960,7 @@ printer_model = GMAX2DUAL
max_layer_height = 0.7
min_layer_height = 0.08
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_GCREATE\nPRINTER_MODEL_GMAX2DUAL
start_gcode = G90\nG28\nG1 Z5 F5000\nM218 T1 X20 Y0 ; Set second extruder offset
start_gcode = G90\nG28\nM420 Z20\nG1 Z5 F5000\nM218 T1 X20 Y0 ; Set second extruder offset
end_gcode = M104 S0 T0 ; turn off temperature\nM104 S0 T1 ; turn off 2nd extruder\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+5, max_print_height)} F600{endif} ; Move print head up\nG1 X5 Y170 F3000 ; present print\n{if layer_z < max_print_height-10}G1 Z{z_offset+min(layer_z+70, max_print_height-10)} F600{endif} ; Move print head up\nM84 X Y E ; disable motors
bed_shape = 0x0,457x0,457x457,0x457
max_print_height = 610

View File

@ -6,8 +6,6 @@
#include <libslic3r/AABBTreeIndirect.hpp>
#include <libslic3r/SLA/EigenMesh3D.hpp>
#include <Shiny/Shiny.h>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4244)
@ -42,53 +40,42 @@ void profile(const TriangleMesh &mesh)
Eigen::MatrixXd occlusion_output0;
{
AABBTreeIndirect::Tree3f tree;
{
PROFILE_BLOCK(AABBIndirect_Init);
tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(mesh.its.vertices, mesh.its.indices);
}
{
PROFILE_BLOCK(EigenMesh3D_AABBIndirectF_AmbientOcclusion);
occlusion_output0.resize(num_vertices, 1);
for (int ivertex = 0; ivertex < num_vertices; ++ ivertex) {
const Eigen::Vector3d origin = mesh.its.vertices[ivertex].template cast<double>();
const Eigen::Vector3d normal = vertex_normals.row(ivertex).template cast<double>();
int num_hits = 0;
for (int s = 0; s < num_samples; s++) {
Eigen::Vector3d d = dirs.row(s);
if(d.dot(normal) < 0) {
// reverse ray
d *= -1;
}
igl::Hit hit;
if (AABBTreeIndirect::intersect_ray_first_hit(mesh.its.vertices, mesh.its.indices, tree, (origin + 1e-4 * d).eval(), d, hit))
++ num_hits;
AABBTreeIndirect::Tree3f tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(mesh.its.vertices, mesh.its.indices);
occlusion_output0.resize(num_vertices, 1);
for (int ivertex = 0; ivertex < num_vertices; ++ ivertex) {
const Eigen::Vector3d origin = mesh.its.vertices[ivertex].template cast<double>();
const Eigen::Vector3d normal = vertex_normals.row(ivertex).template cast<double>();
int num_hits = 0;
for (int s = 0; s < num_samples; s++) {
Eigen::Vector3d d = dirs.row(s);
if(d.dot(normal) < 0) {
// reverse ray
d *= -1;
}
occlusion_output0(ivertex) = (double)num_hits/(double)num_samples;
igl::Hit hit;
if (AABBTreeIndirect::intersect_ray_first_hit(mesh.its.vertices, mesh.its.indices, tree, (origin + 1e-4 * d).eval(), d, hit))
++ num_hits;
}
occlusion_output0(ivertex) = (double)num_hits/(double)num_samples;
}
{
PROFILE_BLOCK(EigenMesh3D_AABBIndirectFF_AmbientOcclusion);
occlusion_output0.resize(num_vertices, 1);
for (int ivertex = 0; ivertex < num_vertices; ++ ivertex) {
const Eigen::Vector3d origin = mesh.its.vertices[ivertex].template cast<double>();
const Eigen::Vector3d normal = vertex_normals.row(ivertex).template cast<double>();
int num_hits = 0;
for (int s = 0; s < num_samples; s++) {
Eigen::Vector3d d = dirs.row(s);
if(d.dot(normal) < 0) {
// reverse ray
d *= -1;
}
igl::Hit hit;
if (AABBTreeIndirect::intersect_ray_first_hit(mesh.its.vertices, mesh.its.indices, tree,
Eigen::Vector3f((origin + 1e-4 * d).template cast<float>()),
Eigen::Vector3f(d.template cast<float>()), hit))
++ num_hits;
occlusion_output0.resize(num_vertices, 1);
for (int ivertex = 0; ivertex < num_vertices; ++ ivertex) {
const Eigen::Vector3d origin = mesh.its.vertices[ivertex].template cast<double>();
const Eigen::Vector3d normal = vertex_normals.row(ivertex).template cast<double>();
int num_hits = 0;
for (int s = 0; s < num_samples; s++) {
Eigen::Vector3d d = dirs.row(s);
if(d.dot(normal) < 0) {
// reverse ray
d *= -1;
}
occlusion_output0(ivertex) = (double)num_hits/(double)num_samples;
igl::Hit hit;
if (AABBTreeIndirect::intersect_ray_first_hit(mesh.its.vertices, mesh.its.indices, tree,
Eigen::Vector3f((origin + 1e-4 * d).template cast<float>()),
Eigen::Vector3f(d.template cast<float>()), hit))
++ num_hits;
}
occlusion_output0(ivertex) = (double)num_hits/(double)num_samples;
}
}
@ -100,31 +87,23 @@ void profile(const TriangleMesh &mesh)
vertices.emplace_back(V.row(i).transpose());
for (int i = 0; i < F.rows(); ++ i)
triangles.emplace_back(F.row(i).transpose());
AABBTreeIndirect::Tree3d tree;
{
PROFILE_BLOCK(AABBIndirectD_Init);
tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(vertices, triangles);
}
{
PROFILE_BLOCK(EigenMesh3D_AABBIndirectD_AmbientOcclusion);
occlusion_output1.resize(num_vertices, 1);
for (int ivertex = 0; ivertex < num_vertices; ++ ivertex) {
const Eigen::Vector3d origin = V.row(ivertex).template cast<double>();
const Eigen::Vector3d normal = vertex_normals.row(ivertex).template cast<double>();
int num_hits = 0;
for (int s = 0; s < num_samples; s++) {
Eigen::Vector3d d = dirs.row(s);
if(d.dot(normal) < 0) {
// reverse ray
d *= -1;
}
igl::Hit hit;
if (AABBTreeIndirect::intersect_ray_first_hit(vertices, triangles, tree, Eigen::Vector3d(origin + 1e-4 * d), d, hit))
++ num_hits;
AABBTreeIndirect::Tree3d tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(vertices, triangles);
occlusion_output1.resize(num_vertices, 1);
for (int ivertex = 0; ivertex < num_vertices; ++ ivertex) {
const Eigen::Vector3d origin = V.row(ivertex).template cast<double>();
const Eigen::Vector3d normal = vertex_normals.row(ivertex).template cast<double>();
int num_hits = 0;
for (int s = 0; s < num_samples; s++) {
Eigen::Vector3d d = dirs.row(s);
if(d.dot(normal) < 0) {
// reverse ray
d *= -1;
}
occlusion_output1(ivertex) = (double)num_hits/(double)num_samples;
igl::Hit hit;
if (AABBTreeIndirect::intersect_ray_first_hit(vertices, triangles, tree, Eigen::Vector3d(origin + 1e-4 * d), d, hit))
++ num_hits;
}
occlusion_output1(ivertex) = (double)num_hits/(double)num_samples;
}
}
@ -133,29 +112,23 @@ void profile(const TriangleMesh &mesh)
Eigen::MatrixXd occlusion_output2;
{
igl::AABB<Eigen::MatrixXd, 3> AABB;
{
PROFILE_BLOCK(EigenMesh3D_AABB_Init);
AABB.init(V, F);
}
{
PROFILE_BLOCK(EigenMesh3D_AABB_AmbientOcclusion);
occlusion_output2.resize(num_vertices, 1);
for (int ivertex = 0; ivertex < num_vertices; ++ ivertex) {
const Eigen::Vector3d origin = V.row(ivertex).template cast<double>();
const Eigen::Vector3d normal = vertex_normals.row(ivertex).template cast<double>();
int num_hits = 0;
for (int s = 0; s < num_samples; s++) {
Eigen::Vector3d d = dirs.row(s);
if(d.dot(normal) < 0) {
// reverse ray
d *= -1;
}
igl::Hit hit;
if (AABB.intersect_ray(V, F, origin + 1e-4 * d, d, hit))
++ num_hits;
AABB.init(V, F);
occlusion_output2.resize(num_vertices, 1);
for (int ivertex = 0; ivertex < num_vertices; ++ ivertex) {
const Eigen::Vector3d origin = V.row(ivertex).template cast<double>();
const Eigen::Vector3d normal = vertex_normals.row(ivertex).template cast<double>();
int num_hits = 0;
for (int s = 0; s < num_samples; s++) {
Eigen::Vector3d d = dirs.row(s);
if(d.dot(normal) < 0) {
// reverse ray
d *= -1;
}
occlusion_output2(ivertex) = (double)num_hits/(double)num_samples;
igl::Hit hit;
if (AABB.intersect_ray(V, F, origin + 1e-4 * d, d, hit))
++ num_hits;
}
occlusion_output2(ivertex) = (double)num_hits/(double)num_samples;
}
}
@ -166,37 +139,28 @@ void profile(const TriangleMesh &mesh)
igl::AABB<MapMatrixXfUnaligned, 3> AABB;
auto vertices = MapMatrixXfUnaligned(mesh.its.vertices.front().data(), mesh.its.vertices.size(), 3);
auto faces = MapMatrixXiUnaligned(mesh.its.indices.front().data(), mesh.its.indices.size(), 3);
{
PROFILE_BLOCK(EigenMesh3D_AABBf_Init);
AABB.init(
vertices,
faces);
}
AABB.init(
vertices,
faces);
{
PROFILE_BLOCK(EigenMesh3D_AABBf_AmbientOcclusion);
occlusion_output3.resize(num_vertices, 1);
for (int ivertex = 0; ivertex < num_vertices; ++ ivertex) {
const Eigen::Vector3d origin = mesh.its.vertices[ivertex].template cast<double>();
const Eigen::Vector3d normal = vertex_normals.row(ivertex).template cast<double>();
int num_hits = 0;
for (int s = 0; s < num_samples; s++) {
Eigen::Vector3d d = dirs.row(s);
if(d.dot(normal) < 0) {
// reverse ray
d *= -1;
}
igl::Hit hit;
if (AABB.intersect_ray(vertices, faces, (origin + 1e-4 * d).eval().template cast<float>(), d.template cast<float>(), hit))
++ num_hits;
occlusion_output3.resize(num_vertices, 1);
for (int ivertex = 0; ivertex < num_vertices; ++ ivertex) {
const Eigen::Vector3d origin = mesh.its.vertices[ivertex].template cast<double>();
const Eigen::Vector3d normal = vertex_normals.row(ivertex).template cast<double>();
int num_hits = 0;
for (int s = 0; s < num_samples; s++) {
Eigen::Vector3d d = dirs.row(s);
if(d.dot(normal) < 0) {
// reverse ray
d *= -1;
}
occlusion_output3(ivertex) = (double)num_hits/(double)num_samples;
igl::Hit hit;
if (AABB.intersect_ray(vertices, faces, (origin + 1e-4 * d).eval().template cast<float>(), d.template cast<float>(), hit))
++ num_hits;
}
occlusion_output3(ivertex) = (double)num_hits/(double)num_samples;
}
}
PROFILE_UPDATE();
PROFILE_OUTPUT(nullptr);
}
int main(const int argc, const char *argv[])

View File

@ -9,7 +9,6 @@ add_subdirectory(boost)
add_subdirectory(clipper)
add_subdirectory(miniz)
add_subdirectory(glu-libtess)
add_subdirectory(Shiny)
add_subdirectory(semver)
add_subdirectory(libigl)
add_subdirectory(hints)
@ -67,6 +66,7 @@ if (SLIC3R_GUI)
if (NOT wxWidgets_FOUND)
message(STATUS "Trying to find wxWidgets in CONFIG mode...")
find_package(wxWidgets 3.2 CONFIG REQUIRED COMPONENTS html adv gl core base)
slic3r_remap_configs(wx::wxhtml wx::wxadv wx::wxgl wx::wxcore wx::wxbase RelWithDebInfo Release)
else ()
include(${wxWidgets_USE_FILE})
endif ()

View File

@ -1,25 +0,0 @@
cmake_minimum_required(VERSION 2.8.12)
project(Shiny)
add_library(Shiny STATIC
Shiny.h
ShinyConfig.h
ShinyData.h
ShinyMacros.h
ShinyManager.c
ShinyManager.h
ShinyNode.c
ShinyNode.h
ShinyNodePool.c
ShinyNodePool.h
ShinyNodeState.c
ShinyNodeState.h
ShinyOutput.c
ShinyOutput.h
ShinyPrereqs.h
ShinyTools.c
ShinyTools.h
ShinyVersion.h
ShinyZone.c
ShinyZone.h
)

View File

@ -1,36 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef SHINY_H
#define SHINY_H
/*---------------------------------------------------------------------------*/
#include "ShinyMacros.h"
#ifdef SLIC3R_PROFILE
#include "ShinyManager.h"
#endif /* SLIC3R_PROFILE */
#endif /* SHINY_H */

View File

@ -1,61 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef SHINY_CONFIG_H
#define SHINY_CONFIG_H
/*---------------------------------------------------------------------------*/
/* if SHINY_LOOKUP_RATE is defined to TRUE then Shiny will record the success of its hash function. This is useful for debugging. Default is FALSE.
*/
#ifndef SHINY_LOOKUP_RATE
// #define SHINY_LOOKUP_RATE FALSE
#endif
/* if SHINY_HAS_ENABLED is defined to TRUE then Shiny can be enabled and disabled at runtime. TODO: bla bla...
*/
#ifndef SHINY_HAS_ENABLED
// #define SHINY_HAS_ENABLED FALSE
#endif
/* TODO:
*/
#define SHINY_OUTPUT_MODE_FLAT 0x1
/* TODO:
*/
#define SHINY_OUTPUT_MODE_TREE 0x2
/* TODO:
*/
#define SHINY_OUTPUT_MODE_BOTH 0x3
/* TODO:
*/
#ifndef SHINY_OUTPUT_MODE
#define SHINY_OUTPUT_MODE SHINY_OUTPUT_MODE_BOTH
#endif
#endif /* SHINY_CONFIG_H */

View File

@ -1,102 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef SHINY_DATA_H
#define SHINY_DATA_H
#include "ShinyPrereqs.h"
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------*/
typedef struct {
uint32_t entryCount;
shinytick_t selfTicks;
} ShinyLastData;
/*---------------------------------------------------------------------------*/
typedef struct {
shinytick_t cur;
float avg;
} ShinyTickData;
typedef struct {
uint32_t cur;
float avg;
} ShinyCountData;
typedef struct {
ShinyCountData entryCount;
ShinyTickData selfTicks;
ShinyTickData childTicks;
} ShinyData;
SHINY_INLINE shinytick_t ShinyData_totalTicksCur(const ShinyData *self) {
return self->selfTicks.cur + self->childTicks.cur;
}
SHINY_INLINE float ShinyData_totalTicksAvg(const ShinyData *self) {
return self->selfTicks.avg + self->childTicks.avg;
}
SHINY_INLINE void ShinyData_computeAverage(ShinyData *self, float a_damping) {
self->entryCount.avg = self->entryCount.cur +
a_damping * (self->entryCount.avg - self->entryCount.cur);
self->selfTicks.avg = self->selfTicks.cur +
a_damping * (self->selfTicks.avg - self->selfTicks.cur);
self->childTicks.avg = self->childTicks.cur +
a_damping * (self->childTicks.avg - self->childTicks.cur);
}
SHINY_INLINE void ShinyData_copyAverage(ShinyData *self) {
self->entryCount.avg = (float) self->entryCount.cur;
self->selfTicks.avg = (float) self->selfTicks.cur;
self->childTicks.avg = (float) self->childTicks.cur;
}
SHINY_INLINE void ShinyData_clearAll(ShinyData *self) {
self->entryCount.cur = 0;
self->entryCount.avg = 0;
self->selfTicks.cur = 0;
self->selfTicks.avg = 0;
self->childTicks.cur = 0;
self->childTicks.avg = 0;
}
SHINY_INLINE void ShinyData_clearCurrent(ShinyData *self) {
self->entryCount.cur = 0;
self->selfTicks.cur = 0;
self->childTicks.cur = 0;
}
#if __cplusplus
} /* end of extern "C" */
#endif
#endif /* SHINY_DATA_H */

View File

@ -1,281 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef SHINY_MACROS_H
#define SHINY_MACROS_H
#ifdef SLIC3R_PROFILE
#include "ShinyManager.h"
/*---------------------------------------------------------------------------*/
/* public preprocessors */
#define PROFILE_UPDATE() \
ShinyManager_update(&Shiny_instance)
#define PROFILE_SET_DAMPING(floatfrom0to1) \
Shiny_instance.damping = (floatfrom0to1);
#define PROFILE_GET_DAMPING() \
(Shiny_instance.damping)
#define PROFILE_OUTPUT(filename) \
ShinyManager_output(&Shiny_instance, (filename))
#define PROFILE_OUTPUT_STREAM(stream) \
ShinyManager_outputToStream(&Shiny_instance, (stream))
#ifdef __cplusplus
#define PROFILE_GET_TREE_STRING() \
ShinyManager_outputTreeToString(&Shiny_instance)
#define PROFILE_GET_FLAT_STRING() \
ShinyManager_outputFlatToString(&Shiny_instance)
#endif /* __cplusplus */
#define PROFILE_DESTROY() \
ShinyManager_destroy(&Shiny_instance)
#define PROFILE_CLEAR() \
ShinyManager_clear(&Shiny_instance)
#define PROFILE_SORT_ZONES() \
ShinyManager_sortZones(&Shiny_instance)
/*---------------------------------------------------------------------------*/
/* public preprocessors */
#define PROFILE_GET_TOTAL_TICKS_CUR() \
ShinyData_totalTicksCur(&Shiny_instance.rootZone.data)
#define PROFILE_GET_TOTAL_TICKS() \
ShinyData_totalTicksAvg(&Shiny_instance.rootZone.data)
#define PROFILE_GET_PROFILED_TICKS_CUR() \
(Shiny_instance.rootZone.data.selfTicks.cur)
#define PROFILE_GET_PROFILED_TICKS() \
(Shiny_instance.rootZone.data.selfTicks.avg)
#define PROFILE_GET_UNPROFILED_TICKS_CUR() \
(Shiny_instance.rootZone.data.childTicks.cur)
#define PROFILE_GET_UNPROFILED_TICKS() \
(Shiny_instance.rootZone.data.childTicks.avg)
#define PROFILE_GET_SHARED_TOTAL_TICKS_CUR(name) \
ShinyData_totalTicksCur(&(_PROFILE_ID_ZONE_SHARED(name).data))
#define PROFILE_GET_SHARED_TOTAL_TICKS(name) \
ShinyData_totalTicksAvg(&(_PROFILE_ID_ZONE_SHARED(name).data))
#define PROFILE_GET_SHARED_SELF_TICKS_CUR(name) \
(_PROFILE_ID_ZONE_SHARED(name).data.selfTicks.cur)
#define PROFILE_GET_SHARED_SELF_TICKS(name) \
(_PROFILE_ID_ZONE_SHARED(name).data.selfTicks.avg)
/*---------------------------------------------------------------------------*/
/* public preprocessors */
#define PROFILE_IS_SHARED_SELF_BELOW(name, floatfrom0to1) \
ShinyManager_isZoneSelfTimeBelow( \
&Shiny_instance, _PROFILE_ID_ZONE_SHARED(name), floatfrom0to1)
#define PROFILE_IS_SHARED_TOTAL_BELOW(name, floatfrom0to1) \
ShinyManager_isZoneTotalTimeBelow( \
&Shiny_instance, _PROFILE_ID_ZONE_SHARED(name), floatfrom0to1)
/*---------------------------------------------------------------------------*/
/* public preprocessors */
#define PROFILE_END() \
ShinyManager_endCurNode(&Shiny_instance)
/*---------------------------------------------------------------------------*/
/* public preprocessors */
#define PROFILE_BEGIN( name ) \
\
static _PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE(name), #name); \
_PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE(name))
/*---------------------------------------------------------------------------*/
/* public preprocessors */
#ifdef __cplusplus
#define PROFILE_BLOCK( name ) \
\
_PROFILE_BLOCK_DEFINE(_PROFILE_ID_BLOCK()); \
PROFILE_BEGIN(name)
#endif /* __cplusplus */
/*---------------------------------------------------------------------------*/
/* public preprocessors */
#ifdef __cplusplus
#define PROFILE_FUNC() \
\
_PROFILE_BLOCK_DEFINE(_PROFILE_ID_BLOCK()); \
static _PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE_FUNC(), __FUNCTION__); \
_PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_FUNC())
#endif /* __cplusplus */
/*---------------------------------------------------------------------------*/
/* public preprocessors */
#define PROFILE_CODE( code ) \
\
do { \
static _PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE_CODE(), #code); \
_PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_CODE()); \
{ code; } \
PROFILE_END(); \
} while(0)
/*---------------------------------------------------------------------------*/
/* public preprocessors */
#define PROFILE_SHARED_EXTERN( name ) \
\
_PROFILE_ZONE_DECLARE(extern, _PROFILE_ID_ZONE_SHARED(name))
/*---------------------------------------------------------------------------*/
/* public preprocessors */
#define PROFILE_SHARED_DEFINE( name ) \
\
_PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE_SHARED(name), #name)
/*---------------------------------------------------------------------------*/
/* public preprocessors */
#define PROFILE_SHARED_BEGIN( name ) \
\
_PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_SHARED(name))
/*---------------------------------------------------------------------------*/
/* public preprocessors */
#ifdef __cplusplus
#define PROFILE_SHARED_BLOCK( name ) \
\
_PROFILE_BLOCK_DEFINE(_PROFILE_ID_BLOCK()); \
_PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_SHARED(name))
#endif /* __cplusplus */
/*---------------------------------------------------------------------------*/
/* public preprocessors */
#ifdef SHINY_HAS_ENABLED
#define PROFILE_SET_ENABLED( boolean ) \
Shiny_instance.enabled = boolean
#endif
/*---------------------------------------------------------------------------*/
/* internal preprocessors */
#define _PROFILE_ID_ZONE( name ) __ShinyZone_##name
#define _PROFILE_ID_ZONE_FUNC() __ShinyZoneFunc
#define _PROFILE_ID_ZONE_CODE() __ShinyZoneCode
#define _PROFILE_ID_ZONE_SHARED( name ) name##__ShinyZoneShared
#define _PROFILE_ID_BLOCK() __ShinyBlock
/*---------------------------------------------------------------------------*/
/* internal preprocessor */
#define _PROFILE_ZONE_DEFINE( id, string ) \
\
ShinyZone id = { \
NULL, SHINY_ZONE_STATE_HIDDEN, string, \
{ { 0, 0 }, { 0, 0 }, { 0, 0 } } \
}
/*---------------------------------------------------------------------------*/
/* internal preprocessor */
#define _PROFILE_ZONE_DECLARE( prefix, id ) \
\
prefix ShinyZone id
/*---------------------------------------------------------------------------*/
/* internal preprocessor */
#define _PROFILE_BLOCK_DEFINE( id ) \
\
ShinyEndNodeOnDestruction SHINY_UNUSED id
/*---------------------------------------------------------------------------*/
/* internal preprocessor */
#define _PROFILE_ZONE_BEGIN( id ) \
\
do { \
static ShinyNodeCache cache = &_ShinyNode_dummy; \
ShinyManager_lookupAndBeginNode(&Shiny_instance, &cache, &id); \
} while(0)
/*---------------------------------------------------------------------------*/
#else /* SLIC3R_PROFILE */
#define PROFILE_UPDATE()
#define PROFILE_SET_DAMPING(x)
#define PROFILE_GET_DAMPING() 0.0f
#define PROFILE_OUTPUT(x)
#define PROFILE_OUTPUT_STREAM(x)
#define PROFILE_CLEAR()
#define PROFILE_GET_TREE_STRING() std::string()
#define PROFILE_GET_FLAT_STRING() std::string()
#define PROFILE_DESTROY()
#define PROFILE_BEGIN(name)
#define PROFILE_BLOCK(name)
#define PROFILE_FUNC()
#define PROFILE_CODE(code) do { code; } while (0)
#define PROFILE_SHARED_GLOBAL(name)
#define PROFILE_SHARED_MEMBER(name)
#define PROFILE_SHARED_DEFINE(name)
#define PROFILE_SHARED_BEGIN(name)
#define PROFILE_SHARED_BLOCK(name)
#define PROFILE_SET_ENABLED(boolean)
#endif /* SLIC3R_PROFILE */
#endif /* SHINY_MACROS_H */

View File

@ -1,445 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifdef SLIC3R_PROFILE
#include "ShinyManager.h"
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include <stdio.h>
/*---------------------------------------------------------------------------*/
#define TABLE_SIZE_INIT 256
/*---------------------------------------------------------------------------*/
ShinyManager Shiny_instance = {
#if SHINY_HAS_ENABLED == TRUE
/* enabled = */ false,
#endif
/* _lastTick = */ 0,
/* _curNode = */ &Shiny_instance.rootNode,
/* _tableMask = */ 0,
/* _nodeTable = */ _ShinyManager_dummyNodeTable,
#if SHINY_LOOKUP_RATE == TRUE
/* _lookupCount = */ 0,
/* _lookupSuccessCount = */ 0,
#endif
/* _tableSize = */ 1,
/* nodeCount = */ 1,
/* zoneCount = */ 1,
/* _lastZone = */ &Shiny_instance.rootZone,
/* _lastNodePool = */ NULL,
/* _firstNodePool = */ NULL,
/* rootNode = */ {
/* _last = */ { 0, 0 },
/* zone = */ &Shiny_instance.rootZone,
/* parent = */ &Shiny_instance.rootNode,
/* nextSibling = */ NULL,
/* firstChild = */ NULL,
/* lastChild = */ NULL,
/* childCount = */ 0,
/* entryLevel = */ 0,
/* _cache = */ NULL,
/* data = */ { { 0, 0 }, { 0, 0 }, { 0, 0 } }
},
/* rootZone = */ {
/* next = */ NULL,
/* _state = */ SHINY_ZONE_STATE_HIDDEN,
/* name = */ "<unprofiled>",
/* data = */ { { 0, 0 }, { 0, 0 }, { 0, 0 } }
},
/* damping = */ 0.f, // Damping disabled, every PROFILE_UPDATE will be performed from scratch. Original value: 0.9f
/* _initialized = */ FALSE,
/* _firstUpdate = */ TRUE
};
ShinyNode* _ShinyManager_dummyNodeTable[] = { NULL };
/*---------------------------------------------------------------------------*/
#if SHINY_COMPILER == SHINY_COMPILER_MSVC
# pragma warning (push)
# pragma warning (disable: 4311)
#endif
/* primary hash function */
SHINY_INLINE uint32_t hash_value(void* a_pParent, void* a_pZone) {
uint32_t a = (uint32_t) a_pParent + (uint32_t) a_pZone;
// uint32_t a = *reinterpret_cast<uint32_t*>(&a_pParent) + *reinterpret_cast<uint32_t*>(&a_pZone);
a = (a+0x7ed55d16) + (a<<12);
a = (a^0xc761c23c) ^ (a>>19);
return a;
}
/*
* secondary hash used as index offset: force it to be odd
* so it's relatively prime to the power-of-two table size
*/
SHINY_INLINE uint32_t hash_offset(uint32_t a) {
return ((a << 8) + (a >> 4)) | 1;
}
#if SHINY_COMPILER == SHINY_COMPILER_MSVC
# pragma warning (pop)
#endif
/*---------------------------------------------------------------------------*/
void ShinyManager_preLoad(ShinyManager *self) {
if (!self->_initialized) {
_ShinyManager_init(self);
_ShinyManager_createNodeTable(self, TABLE_SIZE_INIT);
_ShinyManager_createNodePool(self, TABLE_SIZE_INIT / 2);
}
}
/*---------------------------------------------------------------------------*/
void ShinyManager_update(ShinyManager *self) {
#if SHINY_HAS_ENABLED == TRUE
if (!enabled) return;
#endif
_ShinyManager_appendTicksToCurNode(self);
ShinyZone_preUpdateChain(&self->rootZone);
if (self->_firstUpdate || self->damping == 0) {
self->_firstUpdate = FALSE;
ShinyNode_updateTreeClean(&self->rootNode);
ShinyZone_updateChainClean(&self->rootZone);
} else {
ShinyNode_updateTree(&self->rootNode, self->damping);
ShinyZone_updateChain(&self->rootZone, self->damping);
}
}
/*---------------------------------------------------------------------------*/
void ShinyManager_updateClean(ShinyManager *self) {
#if SHINY_HAS_ENABLED == TRUE
if (!enabled) return;
#endif
_ShinyManager_appendTicksToCurNode(self);
ShinyZone_preUpdateChain(&self->rootZone);
self->_firstUpdate = FALSE;
ShinyNode_updateTreeClean(&self->rootNode);
ShinyZone_updateChainClean(&self->rootZone);
}
/*---------------------------------------------------------------------------*/
void ShinyManager_clear(ShinyManager *self) {
ShinyManager_destroy(self);
ShinyManager_preLoad(self);
}
/*---------------------------------------------------------------------------*/
void ShinyManager_destroy(ShinyManager *self) {
ShinyManager_destroyNodes(self);
ShinyManager_resetZones(self);
_ShinyManager_uninit(self);
}
/*---------------------------------------------------------------------------*/
ShinyNode* _ShinyManager_lookupNode(ShinyManager *self, ShinyNodeCache *a_cache, ShinyZone *a_zone) {
uint32_t nHash = hash_value(self->_curNode, a_zone);
uint32_t nIndex = nHash & self->_tableMask;
ShinyNode* pNode = self->_nodeTable[nIndex];
_ShinyManager_incLookup(self);
_ShinyManager_incLookupSuccess(self);
if (pNode) {
uint32_t nStep;
if (ShinyNode_isEqual(pNode, self->_curNode, a_zone)) return pNode; /* found it! */
/* hash collision: */
/* compute a secondary hash function for stepping */
nStep = hash_offset(nHash);
for (;;) {
_ShinyManager_incLookup(self);
nIndex = (nIndex + nStep) & self->_tableMask;
pNode = self->_nodeTable[nIndex];
if (!pNode) break; /* found empty slot */
else if (ShinyNode_isEqual(pNode, self->_curNode, a_zone)) return pNode; /* found it! */
}
/* loop is guaranteed to end because the hash table is never full */
}
if (a_zone->_state == SHINY_ZONE_STATE_HIDDEN) { /* zone is not initialized */
ShinyZone_init(a_zone, self->_lastZone);
self->_lastZone = a_zone;
self->zoneCount++;
if (self->_initialized == FALSE) { /* first time init */
_ShinyManager_init(self);
_ShinyManager_createNodeTable(self, TABLE_SIZE_INIT);
_ShinyManager_createNodePool(self, TABLE_SIZE_INIT / 2);
/* initialization has invalidated nIndex
* we must compute nIndex again
*/
return _ShinyManager_createNode(self, a_cache, a_zone);
}
}
/* Althouth nodeCount is not updated
* it includes rootNode so it adds up.
*
* check if we need to grow the table
* we keep it at most 1/2 full to be very fast
*/
if (self->_tableSize < 2 * self->nodeCount) {
_ShinyManager_resizeNodeTable(self, 2 * self->_tableSize);
_ShinyManager_resizeNodePool(self, self->nodeCount - 1);
/* resize has invalidated nIndex
* we must compute nIndex again
*/
return _ShinyManager_createNode(self, a_cache, a_zone);
}
self->nodeCount++;
{
ShinyNode* pNewNode = ShinyNodePool_newItem(self->_lastNodePool);
ShinyNode_init(pNewNode, self->_curNode, a_zone, a_cache);
self->_nodeTable[nIndex] = pNewNode;
return pNewNode;
}
}
/*---------------------------------------------------------------------------*/
void _ShinyManager_insertNode(ShinyManager *self, ShinyNode* a_pNode) {
uint32_t nHash = hash_value(a_pNode->parent, a_pNode->zone);
uint32_t nIndex = nHash & self->_tableMask;
if (self->_nodeTable[nIndex]) {
uint32_t nStep = hash_offset(nHash);
while (self->_nodeTable[nIndex])
nIndex = (nIndex + nStep) & self->_tableMask;
}
self->_nodeTable[nIndex] = a_pNode;
}
/*---------------------------------------------------------------------------*/
ShinyNode* _ShinyManager_createNode(ShinyManager *self, ShinyNodeCache* a_cache, ShinyZone* a_pZone) {
ShinyNode* pNewNode = ShinyNodePool_newItem(self->_lastNodePool);
ShinyNode_init(pNewNode, self->_curNode, a_pZone, a_cache);
self->nodeCount++;
_ShinyManager_insertNode(self, pNewNode);
return pNewNode;
}
/*---------------------------------------------------------------------------*/
void _ShinyManager_createNodePool(ShinyManager *self, uint32_t a_nCount) {
self->_firstNodePool = ShinyNodePool_create(a_nCount);
self->_lastNodePool = self->_firstNodePool;
}
/*---------------------------------------------------------------------------*/
void _ShinyManager_resizeNodePool(ShinyManager *self, uint32_t a_nCount) {
ShinyNodePool* pPool = ShinyNodePool_create(a_nCount);
self->_lastNodePool->nextPool = pPool;
self->_lastNodePool = pPool;
}
/*---------------------------------------------------------------------------*/
void _ShinyManager_createNodeTable(ShinyManager *self, uint32_t a_nCount) {
self->_tableSize = a_nCount;
self->_tableMask = a_nCount - 1;
self->_nodeTable = (ShinyNodeTable*)
malloc(sizeof(ShinyNode) * a_nCount);
memset(self->_nodeTable, 0, a_nCount * sizeof(ShinyNode*));
}
/*---------------------------------------------------------------------------*/
void _ShinyManager_resizeNodeTable(ShinyManager *self, uint32_t a_nCount) {
ShinyNodePool* pPool;
free(self->_nodeTable);
_ShinyManager_createNodeTable(self, a_nCount);
pPool = self->_firstNodePool;
while (pPool) {
ShinyNode *pIter = ShinyNodePool_firstItem(pPool);
while (pIter != pPool->_nextItem)
_ShinyManager_insertNode(self, pIter++);
pPool = pPool->nextPool;
}
}
/*---------------------------------------------------------------------------*/
void ShinyManager_resetZones(ShinyManager *self) {
ShinyZone_resetChain(&self->rootZone);
self->_lastZone = &self->rootZone;
self->zoneCount = 1;
}
/*---------------------------------------------------------------------------*/
void ShinyManager_destroyNodes(ShinyManager *self) {
if (self->_firstNodePool) {
ShinyNodePool_destroy(self->_firstNodePool);
self->_firstNodePool = NULL;
}
if (self->_nodeTable != _ShinyManager_dummyNodeTable) {
free(self->_nodeTable);
self->_nodeTable = _ShinyManager_dummyNodeTable;
self->_tableSize = 1;
self->_tableMask = 0;
}
self->_curNode = &self->rootNode;
self->nodeCount = 1;
_ShinyManager_init(self);
}
/*---------------------------------------------------------------------------*/
const char* ShinyManager_getOutputErrorString(ShinyManager *self) {
if (self->_firstUpdate) return "!!! Profile data must first be updated !!!";
else if (!self->_initialized) return "!!! No profiles where executed !!!";
else return NULL;
}
/*---------------------------------------------------------------------------*/
#if SHINY_COMPILER == SHINY_COMPILER_MSVC
# pragma warning (push)
# pragma warning (disable: 4996)
#endif
int ShinyManager_output(ShinyManager *self, const char *a_filename) {
if (!a_filename) {
ShinyManager_outputToStream(self, stdout);
} else {
FILE *file = fopen(a_filename, "w");
if (!file) return FALSE;
ShinyManager_outputToStream(self, file);
fclose(file);
}
return TRUE;
}
#if SHINY_COMPILER == SHINY_COMPILER_MSVC
# pragma warning (pop)
#endif
/*---------------------------------------------------------------------------*/
void ShinyManager_outputToStream(ShinyManager *self, FILE *a_stream) {
const char *error = ShinyManager_getOutputErrorString(self);
if (error) {
fwrite(error, 1, strlen(error), a_stream);
fwrite("\n\n", 1, 2, a_stream);
return;
}
#if SHINY_OUTPUT_MODE & SHINY_OUTPUT_MODE_FLAT
ShinyManager_sortZones(self);
{
int size = ShinyPrintZonesSize(self->zoneCount);
char *buffer = (char*) malloc(size);
ShinyPrintZones(buffer, &self->rootZone);
fwrite(buffer, 1, size - 1, a_stream);
fwrite("\n\n", 1, 2, a_stream);
free(buffer);
}
#endif
#if SHINY_OUTPUT_MODE & SHINY_OUTPUT_MODE_TREE
{
int size = ShinyPrintNodesSize(self->nodeCount);
char *buffer = (char*) malloc(size);
ShinyPrintNodes(buffer, &self->rootNode);
fwrite(buffer, 1, size - 1, a_stream);
fwrite("\n\n", 1, 2, a_stream);
free(buffer);
}
#endif
}
#endif /* SLIC3R_PROFILE */

View File

@ -1,263 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef SHINY_MANAGER_H
#define SHINY_MANAGER_H
#include "ShinyZone.h"
#include "ShinyNode.h"
#include "ShinyNodePool.h"
#include "ShinyTools.h"
#include "ShinyOutput.h"
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------*/
typedef struct {
#ifdef SHINY_HAS_ENABLED
bool enabled;
#endif
shinytick_t _lastTick;
ShinyNode* _curNode;
uint32_t _tableMask; /* = _tableSize - 1 */
ShinyNodeTable* _nodeTable;
#ifdef SHINY_LOOKUP_RATE
uint64_t _lookupCount;
uint64_t _lookupSuccessCount;
#endif
uint32_t _tableSize;
uint32_t nodeCount;
uint32_t zoneCount;
ShinyZone* _lastZone;
ShinyNodePool* _lastNodePool;
ShinyNodePool* _firstNodePool;
ShinyNode rootNode;
ShinyZone rootZone;
float damping;
int _initialized;
int _firstUpdate;
} ShinyManager;
/*---------------------------------------------------------------------------*/
extern ShinyNode* _ShinyManager_dummyNodeTable[];
extern ShinyManager Shiny_instance;
/*---------------------------------------------------------------------------*/
SHINY_INLINE void _ShinyManager_appendTicksToCurNode(ShinyManager *self) {
shinytick_t curTick;
ShinyGetTicks(&curTick);
ShinyNode_appendTicks(self->_curNode, curTick - self->_lastTick);
self->_lastTick = curTick;
}
SHINY_API ShinyNode* _ShinyManager_lookupNode(ShinyManager *self, ShinyNodeCache* a_cache, ShinyZone* a_zone);
SHINY_API void _ShinyManager_createNodeTable(ShinyManager *self, uint32_t a_count);
SHINY_API void _ShinyManager_resizeNodeTable(ShinyManager *self, uint32_t a_count);
SHINY_API void _ShinyManager_createNodePool(ShinyManager *self, uint32_t a_count);
SHINY_API void _ShinyManager_resizeNodePool(ShinyManager *self, uint32_t a_count);
SHINY_API ShinyNode* _ShinyManager_createNode(ShinyManager *self, ShinyNodeCache* a_cache, ShinyZone* a_pZone);
SHINY_API void _ShinyManager_insertNode(ShinyManager *self, ShinyNode* a_pNode);
SHINY_INLINE void _ShinyManager_init(ShinyManager *self) {
self->_initialized = TRUE;
self->rootNode._last.entryCount = 1;
self->rootNode._last.selfTicks = 0;
ShinyGetTicks(&self->_lastTick);
}
SHINY_INLINE void _ShinyManager_uninit(ShinyManager *self) {
self->_initialized = FALSE;
ShinyNode_clear(&self->rootNode);
self->rootNode.parent = &self->rootNode;
self->rootNode.zone = &self->rootZone;
}
#ifdef SHINY_LOOKUP_RATE
SHINY_INLINE void _ShinyManager_incLookup(ShinyManager *self) { self->_lookupCount++; }
SHINY_INLINE void _ShinyManager_incLookupSuccess(ShinyManager *self) { self->_lookupSuccessCount++; }
SHINY_INLINE float ShinyManager_lookupRate(const ShinyManager *self) { return ((float) self->_lookupSuccessCount) / ((float) self->_lookupCount); }
#else
SHINY_INLINE void _ShinyManager_incLookup(ShinyManager * self) { self = self; }
SHINY_INLINE void _ShinyManager_incLookupSuccess(ShinyManager * self) { self = self; }
SHINY_INLINE float ShinyManager_lookupRate(const ShinyManager * self) { self = self; return -1; }
#endif
SHINY_API void ShinyManager_resetZones(ShinyManager *self);
SHINY_API void ShinyManager_destroyNodes(ShinyManager *self);
SHINY_INLINE float ShinyManager_tableUsage(const ShinyManager *self) {
return ((float) self->nodeCount) / ((float) self->_tableSize);
}
SHINY_INLINE uint32_t ShinyManager_allocMemInBytes(const ShinyManager *self) {
return self->_tableSize * sizeof(ShinyNode*)
+ (self->_firstNodePool)? ShinyNodePool_memoryUsageChain(self->_firstNodePool) : 0;
}
SHINY_INLINE void ShinyManager_beginNode(ShinyManager *self, ShinyNode* a_node) {
ShinyNode_beginEntry(a_node);
_ShinyManager_appendTicksToCurNode(self);
self->_curNode = a_node;
}
SHINY_INLINE void ShinyManager_lookupAndBeginNode(ShinyManager *self, ShinyNodeCache* a_cache, ShinyZone* a_zone) {
#ifdef SHINY_HAS_ENABLED
if (!self->enabled) return;
#endif
if (self->_curNode != (*a_cache)->parent)
*a_cache = _ShinyManager_lookupNode(self, a_cache, a_zone);
ShinyManager_beginNode(self, *a_cache);
}
SHINY_INLINE void ShinyManager_endCurNode(ShinyManager *self) {
#ifdef SHINY_HAS_ENABLED
if (!self->enabled) return;
#endif
_ShinyManager_appendTicksToCurNode(self);
self->_curNode = self->_curNode->parent;
}
/**/
SHINY_API void ShinyManager_preLoad(ShinyManager *self);
SHINY_API void ShinyManager_updateClean(ShinyManager *self);
SHINY_API void ShinyManager_update(ShinyManager *self);
SHINY_API void ShinyManager_clear(ShinyManager *self);
SHINY_API void ShinyManager_destroy(ShinyManager *self);
SHINY_INLINE void ShinyManager_sortZones(ShinyManager *self) {
if (self->rootZone.next)
self->_lastZone = ShinyZone_sortChain(&self->rootZone.next);
}
SHINY_API const char* ShinyManager_getOutputErrorString(ShinyManager *self);
SHINY_API int ShinyManager_output(ShinyManager *self, const char *a_filename);
SHINY_API void ShinyManager_outputToStream(ShinyManager *self, FILE *stream);
#if __cplusplus
} /* end of extern "C" */
SHINY_INLINE std::string ShinyManager_outputTreeToString(ShinyManager *self) {
const char* error = ShinyManager_getOutputErrorString(self);
if (error) return error;
else return ShinyNodesToString(&self->rootNode, self->nodeCount);
}
SHINY_INLINE std::string ShinyManager_outputFlatToString(ShinyManager *self) {
const char* error = ShinyManager_getOutputErrorString(self);
if (error) return error;
ShinyManager_sortZones(self);
return ShinyZonesToString(&self->rootZone, self->zoneCount);
}
extern "C" { /* end of c++ */
#endif
SHINY_INLINE int ShinyManager_isZoneSelfTimeBelow(ShinyManager *self, ShinyZone* a_zone, float a_percentage) {
return a_percentage * (float) self->rootZone.data.childTicks.cur
<= (float) a_zone->data.selfTicks.cur;
}
SHINY_INLINE int ShinyManager_isZoneTotalTimeBelow(ShinyManager *self, ShinyZone* a_zone, float a_percentage) {
return a_percentage * (float) self->rootZone.data.childTicks.cur
<= (float) ShinyData_totalTicksCur(&a_zone->data);
}
/**/
SHINY_INLINE void ShinyManager_enumerateNodes(ShinyManager *self, void (*a_func)(const ShinyNode*)) {
ShinyNode_enumerateNodes(&self->rootNode, a_func);
}
SHINY_INLINE void ShinyManager_enumerateZones(ShinyManager *self, void (*a_func)(const ShinyZone*)) {
ShinyZone_enumerateZones(&self->rootZone, a_func);
}
#if __cplusplus
} /* end of extern "C" */
template <class T> void ShinyManager_enumerateNodes(ShinyManager *self, T* a_this, void (T::*a_func)(const ShinyNode*)) {
ShinyNode_enumerateNodes(&self->rootNode, a_this, a_func);
}
template <class T> void ShinyManager_enumerateZones(ShinyManager *self, T* a_this, void (T::*a_func)(const ShinyZone*)) {
ShinyZone_enumerateZones(&self->rootZone, a_this, a_func);
}
extern "C" { /* end of c++ */
#endif
/*---------------------------------------------------------------------------*/
#if __cplusplus
} /* end of extern "C" */
class ShinyEndNodeOnDestruction {
public:
SHINY_INLINE ~ShinyEndNodeOnDestruction() {
ShinyManager_endCurNode(&Shiny_instance);
}
};
#endif
#endif /* SHINY_MANAGER_H */

View File

@ -1,129 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifdef SLIC3R_PROFILE
#include "ShinyNode.h"
#include "ShinyZone.h"
#include "ShinyNodeState.h"
#include <memory.h>
/*---------------------------------------------------------------------------*/
ShinyNode _ShinyNode_dummy = {
/* _last = */ { 0, 0 },
/* zone = */ NULL,
/* parent = */ NULL,
/* nextSibling = */ NULL,
/* firstChild = */ NULL,
/* lastChild = */ NULL
};
/*---------------------------------------------------------------------------*/
void ShinyNode_updateTree(ShinyNode* first, float a_damping) {
ShinyNodeState *top = NULL;
ShinyNode *node = first;
for (;;) {
do {
top = ShinyNodeState_push(top, node);
node = node->firstChild;
} while (node);
for (;;) {
node = ShinyNodeState_finishAndGetNext(top, a_damping);
top = ShinyNodeState_pop(top);
if (node) break;
else if (!top) return;
}
}
}
/*---------------------------------------------------------------------------*/
void ShinyNode_updateTreeClean(ShinyNode* first) {
ShinyNodeState *top = NULL;
ShinyNode *node = first;
for (;;) {
do {
top = ShinyNodeState_push(top, node);
node = node->firstChild;
} while (node);
for (;;) {
node = ShinyNodeState_finishAndGetNextClean(top);
top = ShinyNodeState_pop(top);
if (node) break;
else if (!top) return;
}
}
}
/*---------------------------------------------------------------------------*/
const ShinyNode* ShinyNode_findNextInTree(const ShinyNode* self) {
if (self->firstChild) {
return self->firstChild;
} else if (self->nextSibling) {
return self->nextSibling;
} else {
ShinyNode* pParent = self->parent;
while (!ShinyNode_isRoot(pParent)) {
if (pParent->nextSibling) return pParent->nextSibling;
else pParent = pParent->parent;
}
return NULL;
}
}
/*---------------------------------------------------------------------------*/
void ShinyNode_clear(ShinyNode* self) {
memset(self, 0, sizeof(ShinyNode));
}
/*---------------------------------------------------------------------------*/
void ShinyNode_enumerateNodes(const ShinyNode* a_node, void (*a_func)(const ShinyNode*)) {
a_func(a_node);
if (a_node->firstChild) ShinyNode_enumerateNodes(a_node->firstChild, a_func);
if (a_node->nextSibling) ShinyNode_enumerateNodes(a_node->nextSibling, a_func);
}
#endif /* SLIC3R_PROFILE */

View File

@ -1,133 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef SHINY_NODE_H
#define SHINY_NODE_H
#include "ShinyData.h"
#include "ShinyTools.h"
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------*/
typedef struct _ShinyNode {
ShinyLastData _last;
struct _ShinyZone* zone;
struct _ShinyNode* parent;
struct _ShinyNode* nextSibling;
struct _ShinyNode* firstChild;
struct _ShinyNode* lastChild;
uint32_t childCount;
uint32_t entryLevel;
ShinyNodeCache* _cache;
ShinyData data;
} ShinyNode;
/*---------------------------------------------------------------------------*/
extern ShinyNode _ShinyNode_dummy;
/*---------------------------------------------------------------------------*/
SHINY_INLINE void ShinyNode_addChild(ShinyNode* self, ShinyNode* a_child) {
if (self->childCount++) {
self->lastChild->nextSibling = a_child;
self->lastChild = a_child;
} else {
self->lastChild = a_child;
self->firstChild = a_child;
}
}
SHINY_INLINE void ShinyNode_init(ShinyNode* self, ShinyNode* a_parent, struct _ShinyZone* a_zone, ShinyNodeCache* a_cache) {
/* NOTE: all member variables are assumed to be zero when allocated */
self->zone = a_zone;
self->parent = a_parent;
self->entryLevel = a_parent->entryLevel + 1;
ShinyNode_addChild(a_parent, self);
self->_cache = a_cache;
}
SHINY_API void ShinyNode_updateTree(ShinyNode* self, float a_damping);
SHINY_API void ShinyNode_updateTreeClean(ShinyNode* self);
SHINY_INLINE void ShinyNode_destroy(ShinyNode* self) {
*(self->_cache) = &_ShinyNode_dummy;
}
SHINY_INLINE void ShinyNode_appendTicks(ShinyNode* self, shinytick_t a_elapsedTicks) {
self->_last.selfTicks += a_elapsedTicks;
}
SHINY_INLINE void ShinyNode_beginEntry(ShinyNode* self) {
self->_last.entryCount++;
}
SHINY_INLINE int ShinyNode_isRoot(ShinyNode* self) {
return (self->entryLevel == 0);
}
SHINY_INLINE int ShinyNode_isDummy(ShinyNode* self) {
return (self == &_ShinyNode_dummy);
}
SHINY_INLINE int ShinyNode_isEqual(ShinyNode* self, const ShinyNode* a_parent, const struct _ShinyZone* a_zone) {
return (self->parent == a_parent && self->zone == a_zone);
}
SHINY_API const ShinyNode* ShinyNode_findNextInTree(const ShinyNode* self);
SHINY_API void ShinyNode_clear(ShinyNode* self);
SHINY_API void ShinyNode_enumerateNodes(const ShinyNode* a_node, void (*a_func)(const ShinyNode*));
#if __cplusplus
} /* end of extern "C" */
template <class T>
void ShinyNode_enumerateNodes(const ShinyNode* a_node, T* a_this, void (T::*a_func)(const ShinyNode*)) {
(a_this->*a_func)(a_node);
if (a_node->firstChild) ShinyNode_enumerateNodes(a_node->firstChild, a_this, a_func);
if (a_node->nextSibling) ShinyNode_enumerateNodes(a_node->nextSibling, a_this, a_func);
}
#endif /* __cplusplus */
#endif /* SHINY_NODE_H */

View File

@ -1,77 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifdef SLIC3R_PROFILE
#include "ShinyNodePool.h"
#include "ShinyTools.h"
#include <memory.h>
#include <malloc.h>
/*---------------------------------------------------------------------------*/
ShinyNodePool* ShinyNodePool_create(uint32_t a_items) {
ShinyNodePool* pPool = (ShinyNodePool*)
malloc(sizeof(ShinyNodePool) + sizeof(ShinyNode) * (a_items - 1));
pPool->nextPool = NULL;
pPool->_nextItem = &pPool->_items[0];
pPool->endOfItems = &pPool->_items[a_items];
memset(&pPool->_items[0], 0, a_items * sizeof(ShinyNode));
return pPool;
}
/*---------------------------------------------------------------------------*/
uint32_t ShinyNodePool_memoryUsageChain(ShinyNodePool *first) {
uint32_t bytes = (uint32_t) ((char*) first->endOfItems - (char*) first);
ShinyNodePool *pool = first->nextPool;
while (pool) {
bytes += (uint32_t) ((char*) pool->endOfItems - (char*) pool);
pool = pool->nextPool;
}
return bytes;
}
/*---------------------------------------------------------------------------*/
void ShinyNodePool_destroy(ShinyNodePool *self) {
ShinyNode* firstNode = ShinyNodePool_firstItem(self);
ShinyNode* lastNode = self->_nextItem;
while (firstNode != lastNode)
ShinyNode_destroy(firstNode++);
/* TODO: make this into a loop or a tail recursion */
if (self->nextPool) ShinyNodePool_destroy(self->nextPool);
free(self);
}
#endif /* SLIC3R_PROFILE */

View File

@ -1,67 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef SHINY_NODE_POOL_H
#define SHINY_NODE_POOL_H
#include "ShinyNode.h"
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------*/
typedef struct _ShinyNodePool {
struct _ShinyNodePool* nextPool;
ShinyNode *_nextItem;
ShinyNode *endOfItems;
ShinyNode _items[1];
} ShinyNodePool;
/*---------------------------------------------------------------------------*/
SHINY_INLINE ShinyNode* ShinyNodePool_firstItem(ShinyNodePool *self) {
return &(self->_items[0]);
}
SHINY_INLINE ShinyNode* ShinyNodePool_newItem(ShinyNodePool *self) {
return self->_nextItem++;
}
ShinyNodePool* ShinyNodePool_create(uint32_t a_items);
void ShinyNodePool_destroy(ShinyNodePool *self);
uint32_t ShinyNodePool_memoryUsageChain(ShinyNodePool *first);
#if __cplusplus
} /* end of extern "C" */
#endif
#endif /* SHINY_NODE_POOL_H */

View File

@ -1,108 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifdef SLIC3R_PROFILE
#include "ShinyNodeState.h"
#include "ShinyNode.h"
#include "ShinyZone.h"
#include <malloc.h>
/*---------------------------------------------------------------------------*/
ShinyNodeState* ShinyNodeState_push(ShinyNodeState *a_top, ShinyNode *a_node) {
ShinyZone *zone = a_node->zone;
ShinyNodeState *self = (ShinyNodeState*) malloc(sizeof(ShinyNodeState));
self->node = a_node;
self->_prev = a_top;
a_node->data.selfTicks.cur = a_node->_last.selfTicks;
a_node->data.entryCount.cur = a_node->_last.entryCount;
zone->data.selfTicks.cur += a_node->_last.selfTicks;
zone->data.entryCount.cur += a_node->_last.entryCount;
a_node->data.childTicks.cur = 0;
a_node->_last.selfTicks = 0;
a_node->_last.entryCount = 0;
self->zoneUpdating = zone->_state != SHINY_ZONE_STATE_UPDATING;
if (self->zoneUpdating) {
zone->_state = SHINY_ZONE_STATE_UPDATING;
} else {
zone->data.childTicks.cur -= a_node->data.selfTicks.cur;
}
return self;
}
/*---------------------------------------------------------------------------*/
ShinyNodeState* ShinyNodeState_pop(ShinyNodeState *a_top) {
ShinyNodeState *prev = a_top->_prev;
free(a_top);
return prev;
}
/*---------------------------------------------------------------------------*/
ShinyNode* ShinyNodeState_finishAndGetNext(ShinyNodeState *self, float a_damping) {
ShinyNode *node = self->node;
ShinyZone *zone = node->zone;
if (self->zoneUpdating) {
zone->data.childTicks.cur += node->data.childTicks.cur;
zone->_state = SHINY_ZONE_STATE_INITIALIZED;
}
ShinyData_computeAverage(&node->data, a_damping);
if (!ShinyNode_isRoot(node))
node->parent->data.childTicks.cur += node->data.selfTicks.cur + node->data.childTicks.cur;
return node->nextSibling;
}
/*---------------------------------------------------------------------------*/
ShinyNode* ShinyNodeState_finishAndGetNextClean(ShinyNodeState *self) {
ShinyNode *node = self->node;
ShinyZone *zone = node->zone;
if (self->zoneUpdating) {
zone->data.childTicks.cur += node->data.childTicks.cur;
zone->_state = SHINY_ZONE_STATE_INITIALIZED;
}
ShinyData_copyAverage(&node->data);
if (!ShinyNode_isRoot(node))
node->parent->data.childTicks.cur += node->data.selfTicks.cur + node->data.childTicks.cur;
return node->nextSibling;
}
#endif /* SLIC3R_PROFILE */

View File

@ -1,56 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef SHINY_NODE_STATE_H
#define SHINY_NODE_STATE_H
#include "ShinyNode.h"
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------*/
typedef struct _ShinyNodeState {
ShinyNode *node;
int zoneUpdating;
struct _ShinyNodeState *_prev;
} ShinyNodeState;
/*---------------------------------------------------------------------------*/
ShinyNodeState* ShinyNodeState_push(ShinyNodeState *a_top, ShinyNode *a_node);
ShinyNodeState* ShinyNodeState_pop(ShinyNodeState *a_top);
ShinyNode* ShinyNodeState_finishAndGetNext(ShinyNodeState *self, float a_damping);
ShinyNode* ShinyNodeState_finishAndGetNextClean(ShinyNodeState *self);
#if __cplusplus
} /* end of extern "C" */
#endif
#endif /* SHINY_NODE_STATE_H */

View File

@ -1,189 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifdef SLIC3R_PROFILE
#include "ShinyOutput.h"
#include <stdio.h>
#if SHINY_COMPILER == SHINY_COMPILER_MSVC
# pragma warning(disable: 4996)
# define snprintf _snprintf
# define TRAILING 0
#else
# define TRAILING 1
#endif
/*---------------------------------------------------------------------------*/
#define OUTPUT_WIDTH_CALL 6
#define OUTPUT_WIDTH_TIME (6+3)
#define OUTPUT_WIDTH_PERC (4+3)
#define OUTPUT_WIDTH_SUM 120
#define OUTPUT_WIDTH_DATA (1+OUTPUT_WIDTH_CALL + 1 + 2*(OUTPUT_WIDTH_TIME+4+OUTPUT_WIDTH_PERC+1) + 1)
#define OUTPUT_WIDTH_NAME (OUTPUT_WIDTH_SUM - OUTPUT_WIDTH_DATA)
/*---------------------------------------------------------------------------*/
SHINY_INLINE char* printHeader(char *output, const char *a_title) {
snprintf(output, OUTPUT_WIDTH_SUM + TRAILING,
"%-*s %*s %*s %*s",
OUTPUT_WIDTH_NAME, a_title,
OUTPUT_WIDTH_CALL, "calls",
OUTPUT_WIDTH_TIME+4+OUTPUT_WIDTH_PERC+1, "self time",
OUTPUT_WIDTH_TIME+4+OUTPUT_WIDTH_PERC+1, "total time");
return output + OUTPUT_WIDTH_SUM;
}
/*---------------------------------------------------------------------------*/
SHINY_INLINE char* printData(char *output, const ShinyData *a_data, float a_topercent) {
float totalTicksAvg = ShinyData_totalTicksAvg(a_data);
const ShinyTimeUnit *selfUnit = ShinyGetTimeUnit(a_data->selfTicks.avg);
const ShinyTimeUnit *totalUnit = ShinyGetTimeUnit(totalTicksAvg);
snprintf(output, OUTPUT_WIDTH_DATA + TRAILING,
" %*.1f %*.2f %-2s %*.2f%% %*.2f %-2s %*.2f%%",
OUTPUT_WIDTH_CALL, a_data->entryCount.avg,
OUTPUT_WIDTH_TIME, a_data->selfTicks.avg * selfUnit->invTickFreq, selfUnit->suffix,
OUTPUT_WIDTH_PERC, a_data->selfTicks.avg * a_topercent,
OUTPUT_WIDTH_TIME, totalTicksAvg * totalUnit->invTickFreq, totalUnit->suffix,
OUTPUT_WIDTH_PERC, totalTicksAvg * a_topercent);
return output + OUTPUT_WIDTH_DATA;
}
/*---------------------------------------------------------------------------*/
SHINY_INLINE char* printNode(char* output, const ShinyNode *a_node, float a_topercent) {
int offset = a_node->entryLevel * 2;
snprintf(output, OUTPUT_WIDTH_NAME + TRAILING, "%*s%-*s",
offset, "", OUTPUT_WIDTH_NAME - offset, a_node->zone->name);
output += OUTPUT_WIDTH_NAME;
output = printData(output, &a_node->data, a_topercent);
return output;
}
/*---------------------------------------------------------------------------*/
SHINY_INLINE char* printZone(char* output, const ShinyZone *a_zone, float a_topercent) {
snprintf(output, OUTPUT_WIDTH_NAME + TRAILING, "%-*s",
OUTPUT_WIDTH_NAME, a_zone->name);
output += OUTPUT_WIDTH_NAME;
output = printData(output, &a_zone->data, a_topercent);
return output;
}
/*---------------------------------------------------------------------------*/
int ShinyPrintNodesSize(uint32_t a_count) {
return (1 + a_count) * (OUTPUT_WIDTH_SUM + 1);
}
/*---------------------------------------------------------------------------*/
int ShinyPrintZonesSize(uint32_t a_count) {
return (1 + a_count) * (OUTPUT_WIDTH_SUM + 1);
}
/*---------------------------------------------------------------------------*/
void ShinyPrintANode(char* output, const ShinyNode *a_node, const ShinyNode *a_root) {
float fTicksToPc = 100.0f / a_root->data.childTicks.avg;
output = printNode(output, a_node, fTicksToPc);
(*output++) = '\0';
}
/*---------------------------------------------------------------------------*/
void ShinyPrintAZone(char* output, const ShinyZone *a_zone, const ShinyZone *a_root) {
float fTicksToPc = 100.0f / a_root->data.childTicks.avg;
output = printZone(output, a_zone, fTicksToPc);
(*output++) = '\0';
}
/*---------------------------------------------------------------------------*/
void ShinyPrintNodes(char* output, const ShinyNode *a_root) {
float fTicksToPc = 100.0f / a_root->data.childTicks.avg;
const ShinyNode *node = a_root;
output = printHeader(output, "call tree");
(*output++) = '\n';
for (;;) {
output = printNode(output, node, fTicksToPc);
node = ShinyNode_findNextInTree(node);
if (node) {
(*output++) = '\n';
} else {
(*output++) = '\0';
return;
}
}
}
/*---------------------------------------------------------------------------*/
void ShinyPrintZones(char* output, const ShinyZone *a_root) {
float fTicksToPc = 100.0f / a_root->data.childTicks.avg;
const ShinyZone *zone = a_root;
output = printHeader(output, "sorted list");
(*output++) = '\n';
for (;;) {
output = printZone(output, zone, fTicksToPc);
zone = zone->next;
if (zone) {
(*output++) = '\n';
} else {
(*output++) = '\0';
return;
}
}
}
#endif /* SLIC3R_PROFILE */

View File

@ -1,68 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef SHINY_OUTPUT_H
#define SHINY_OUTPUT_H
#include "ShinyNode.h"
#include "ShinyZone.h"
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------*/
SHINY_API int ShinyPrintNodesSize(uint32_t a_count);
SHINY_API int ShinyPrintZonesSize(uint32_t a_count);
SHINY_API void ShinyPrintANode(char* output, const ShinyNode *a_node, const ShinyNode *a_root);
SHINY_API void ShinyPrintAZone(char* output, const ShinyZone *a_zone, const ShinyZone *a_root);
SHINY_API void ShinyPrintNodes(char* output, const ShinyNode *a_root);
SHINY_API void ShinyPrintZones(char* output, const ShinyZone *a_root);
/*---------------------------------------------------------------------------*/
#if __cplusplus
} /* end of extern "C" */
#include <string>
SHINY_INLINE std::string ShinyNodesToString(const ShinyNode *a_root, uint32_t a_count) {
std::string str;
str.resize(ShinyPrintNodesSize(a_count) - 1);
ShinyPrintNodes(&str[0], a_root);
return str;
}
SHINY_INLINE std::string ShinyZonesToString(const ShinyZone *a_root, uint32_t a_count) {
std::string str;
str.resize(ShinyPrintZonesSize(a_count) - 1);
ShinyPrintZones(&str[0], a_root);
return str;
}
#endif /* __cplusplus */
#endif /* SHINY_OUTPUT_H */

View File

@ -1,138 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef SHINY_PREREQS_H
#define SHINY_PREREQS_H
#include <stdint.h>
/*---------------------------------------------------------------------------*/
#ifndef FALSE
#define FALSE 0x0
#endif
#ifndef TRUE
#define TRUE 0x1
#endif
#ifndef NULL
#define NULL 0
#endif
#include "ShinyConfig.h"
#include "ShinyVersion.h"
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------*/
#define SHINY_PLATFORM_WIN32 0x1
#define SHINY_PLATFORM_POSIX 0x2
#if defined (_WIN32)
# define SHINY_PLATFORM SHINY_PLATFORM_WIN32
#else /* ASSUME: POSIX-compliant OS */
# define SHINY_PLATFORM SHINY_PLATFORM_POSIX
#endif
/*---------------------------------------------------------------------------*/
#define SHINY_COMPILER_MSVC 0x1
#define SHINY_COMPILER_GNUC 0x2
#define SHINY_COMPILER_OTHER 0x3
#if defined (_MSC_VER)
# define SHINY_COMPILER SHINY_COMPILER_MSVC
#elif defined (__GNUG__)
# define SHINY_COMPILER SHINY_COMPILER_GNUC
#else
# define SHINY_COMPILER SHINY_COMPILER_OTHER
#endif
/*---------------------------------------------------------------------------*/
#if SHINY_COMPILER == SHINY_COMPILER_GNUC
#include <sys/types.h>
#include <stdint.h>
#endif
/*---------------------------------------------------------------------------*/
struct _ShinyNode;
struct _ShinyZone;
typedef struct _ShinyNode* ShinyNodeCache;
typedef struct _ShinyNode* ShinyNodeTable;
/*---------------------------------------------------------------------------*/
#define SHINY_API
/*---------------------------------------------------------------------------*/
#if SHINY_COMPILER == SHINY_COMPILER_MSVC
# define SHINY_INLINE __inline
# define SHINY_UNUSED
#elif SHINY_COMPILER == SHINY_COMPILER_GNUC
# define SHINY_INLINE inline
# define SHINY_UNUSED __attribute__((unused))
#elif SHINY_COMPILER == SHINY_COMPILER_OTHER
# define SHINY_INLINE inline
# define SHINY_UNUSED
#endif
/*---------------------------------------------------------------------------*/
#if SHINY_COMPILER == SHINY_COMPILER_MSVC
typedef int int32_t;
typedef unsigned int uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
/*
#elif defined(__CYGWIN__)
typedef u_int32_t uint32_t;
typedef u_int64_t uint64_t;
*/
#endif
typedef uint64_t shinytick_t;
#if __cplusplus
} /* end of extern "C" */
#endif
#endif /* SHINY_PREREQS_H */

View File

@ -1,116 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifdef SLIC3R_PROFILE
#include "ShinyTools.h"
#if SHINY_PLATFORM == SHINY_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#ifndef NOMINMAX
#define NOMINMAX
#endif /* NOMINMAX */
#include <windows.h>
#elif SHINY_PLATFORM == SHINY_PLATFORM_POSIX
#include <sys/time.h>
#endif
/*---------------------------------------------------------------------------*/
const ShinyTimeUnit* ShinyGetTimeUnit(float ticks) {
static ShinyTimeUnit units[4] = { 0 };
if (units[0].tickFreq == 0) { /* auto initialize first time */
units[0].tickFreq = ShinyGetTickFreq() / 1.0f;
units[0].invTickFreq = ShinyGetTickInvFreq() * 1.0f;
units[0].suffix = "s";
units[1].tickFreq = ShinyGetTickFreq() / 1000.0f;
units[1].invTickFreq = ShinyGetTickInvFreq() * 1000.0f;
units[1].suffix = "ms";
units[2].tickFreq = ShinyGetTickFreq() / 1000000.0f;
units[2].invTickFreq = ShinyGetTickInvFreq() * 1000000.0f;
units[2].suffix = "us";
units[3].tickFreq = ShinyGetTickFreq() / 1000000000.0f;
units[3].invTickFreq = ShinyGetTickInvFreq() * 1000000000.0f;
units[3].suffix = "ns";
}
if (units[0].tickFreq < ticks) return &units[0];
else if (units[1].tickFreq < ticks) return &units[1];
else if (units[2].tickFreq < ticks) return &units[2];
else return &units[3];
}
/*---------------------------------------------------------------------------*/
#if SHINY_PLATFORM == SHINY_PLATFORM_WIN32
void ShinyGetTicks(shinytick_t *p) {
QueryPerformanceCounter((LARGE_INTEGER*)(p));
}
shinytick_t ShinyGetTickFreq(void) {
static shinytick_t freq = 0;
if (freq == 0) QueryPerformanceFrequency((LARGE_INTEGER*)(&freq));
return freq;
}
float ShinyGetTickInvFreq(void) {
static float invfreq = 0;
if (invfreq == 0) invfreq = 1.0f / ShinyGetTickFreq();
return invfreq;
}
/*---------------------------------------------------------------------------*/
#elif SHINY_PLATFORM == SHINY_PLATFORM_POSIX
//#include <time.h>
//#include <sys/time.h>
void ShinyGetTicks(shinytick_t *p) {
struct timeval time;
gettimeofday(&time, NULL);
*p = time.tv_sec * 1000000 + time.tv_usec;
}
shinytick_t ShinyGetTickFreq(void) {
return 1000000;
}
float ShinyGetTickInvFreq(void) {
return 1.0f / 1000000.0f;
}
#endif
#endif /* SLIC3R_PROFILE */

View File

@ -1,57 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef SHINY_TOOLS_H
#define SHINY_TOOLS_H
#include "ShinyPrereqs.h"
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------*/
typedef struct {
float tickFreq;
float invTickFreq;
const char* suffix;
} ShinyTimeUnit;
/*---------------------------------------------------------------------------*/
SHINY_API const ShinyTimeUnit* ShinyGetTimeUnit(float ticks);
SHINY_API void ShinyGetTicks(shinytick_t *p);
SHINY_API shinytick_t ShinyGetTickFreq(void);
SHINY_API float ShinyGetTickInvFreq(void);
#if __cplusplus
} /* end of extern "C" */
#endif
#endif /* SHINY_TOOLS_H */

View File

@ -1,37 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef SHINY_VERSION_H
#define SHINY_VERSION_H
/*---------------------------------------------------------------------------*/
#define SHINY_VERSION "2.6 RC1"
#define SHINY_SHORTNAME "Shiny"
#define SHINY_FULLNAME "Shiny Profiler"
#define SHINY_COPYRIGHT "Copyright (C) 2007-2010 Aidin Abedi"
#define SHINY_DESCRIPTION "Shiny is a state of the art profiler designed to help finding bottlenecks in your project."
#endif /* SHINY_VERSION_H */

View File

@ -1,201 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifdef SLIC3R_PROFILE
#include "ShinyZone.h"
#include <memory.h>
/*---------------------------------------------------------------------------*/
void ShinyZone_preUpdateChain(ShinyZone *first) {
ShinyZone* zone = first;
while (zone) {
ShinyData_clearCurrent(&(zone->data));
zone = zone->next;
}
}
/*---------------------------------------------------------------------------*/
void ShinyZone_updateChain(ShinyZone *first, float a_damping) {
ShinyZone* zone = first;
do {
ShinyData_computeAverage(&(zone->data), a_damping);
zone = zone->next;
} while (zone);
}
/*---------------------------------------------------------------------------*/
void ShinyZone_updateChainClean(ShinyZone *first) {
ShinyZone* zone = first;
do {
ShinyData_copyAverage(&(zone->data));
zone = zone->next;
} while (zone);
}
/*---------------------------------------------------------------------------*/
void ShinyZone_resetChain(ShinyZone *first) {
ShinyZone* zone = first, *temp;
do {
zone->_state = SHINY_ZONE_STATE_HIDDEN;
temp = zone->next;
zone->next = NULL;
zone = temp;
} while (zone);
}
/*---------------------------------------------------------------------------*/
/* A Linked-List Memory Sort
by Philip J. Erdelsky
pje@efgh.com
http://www.alumni.caltech.edu/~pje/
Modified by Aidin Abedi
*/
ShinyZone* ShinyZone_sortChain(ShinyZone **first) /* return ptr to last zone */
{
ShinyZone *p = *first;
unsigned base;
unsigned long block_size;
struct tape
{
ShinyZone *first, *last;
unsigned long count;
} tape[4];
/* Distribute the records alternately to tape[0] and tape[1]. */
tape[0].count = tape[1].count = 0L;
tape[0].first = NULL;
base = 0;
while (p != NULL)
{
ShinyZone *next = p->next;
p->next = tape[base].first;
tape[base].first = p;
tape[base].count++;
p = next;
base ^= 1;
}
/* If the list is empty or contains only a single record, then */
/* tape[1].count == 0L and this part is vacuous. */
for (base = 0, block_size = 1L; tape[base+1].count != 0L;
base ^= 2, block_size <<= 1)
{
int dest;
struct tape *tape0, *tape1;
tape0 = tape + base;
tape1 = tape + base + 1;
dest = base ^ 2;
tape[dest].count = tape[dest+1].count = 0;
for (; tape0->count != 0; dest ^= 1)
{
unsigned long n0, n1;
struct tape *output_tape = tape + dest;
n0 = n1 = block_size;
while (1)
{
ShinyZone *chosen_record;
struct tape *chosen_tape;
if (n0 == 0 || tape0->count == 0)
{
if (n1 == 0 || tape1->count == 0)
break;
chosen_tape = tape1;
n1--;
}
else if (n1 == 0 || tape1->count == 0)
{
chosen_tape = tape0;
n0--;
}
else if (ShinyZone_compare(tape1->first, tape0->first) > 0)
{
chosen_tape = tape1;
n1--;
}
else
{
chosen_tape = tape0;
n0--;
}
chosen_tape->count--;
chosen_record = chosen_tape->first;
chosen_tape->first = chosen_record->next;
if (output_tape->count == 0)
output_tape->first = chosen_record;
else
output_tape->last->next = chosen_record;
output_tape->last = chosen_record;
output_tape->count++;
}
}
}
if (tape[base].count > 1L) {
ShinyZone* last = tape[base].last;
*first = tape[base].first;
last->next = NULL;
return last;
} else {
return NULL;
}
}
/*---------------------------------------------------------------------------*/
void ShinyZone_clear(ShinyZone* self) {
memset(self, 0, sizeof(ShinyZone));
}
/*---------------------------------------------------------------------------*/
void ShinyZone_enumerateZones(const ShinyZone* a_zone, void (*a_func)(const ShinyZone*)) {
a_func(a_zone);
if (a_zone->next) ShinyZone_enumerateZones(a_zone->next, a_func);
}
#endif /* SLIC3R_PROFILE */

View File

@ -1,91 +0,0 @@
/*
The MIT License
Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef SHINY_ZONE_H
#define SHINY_ZONE_H
#include "ShinyData.h"
#include <memory.h>
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------*/
#define SHINY_ZONE_STATE_HIDDEN 0
#define SHINY_ZONE_STATE_INITIALIZED 1
#define SHINY_ZONE_STATE_UPDATING 2
/*---------------------------------------------------------------------------*/
typedef struct _ShinyZone {
struct _ShinyZone* next;
int _state;
const char* name;
ShinyData data;
} ShinyZone;
/*---------------------------------------------------------------------------*/
SHINY_INLINE void ShinyZone_init(ShinyZone *self, ShinyZone* a_prev) {
self->_state = SHINY_ZONE_STATE_INITIALIZED;
a_prev->next = self;
}
SHINY_INLINE void ShinyZone_uninit(ShinyZone *self) {
self->_state = SHINY_ZONE_STATE_HIDDEN;
self->next = NULL;
}
SHINY_API void ShinyZone_preUpdateChain(ShinyZone *first);
SHINY_API void ShinyZone_updateChain(ShinyZone *first, float a_damping);
SHINY_API void ShinyZone_updateChainClean(ShinyZone *first);
SHINY_API void ShinyZone_resetChain(ShinyZone *first);
SHINY_API ShinyZone* ShinyZone_sortChain(ShinyZone **first);
SHINY_INLINE float ShinyZone_compare(ShinyZone *a, ShinyZone *b) {
return a->data.selfTicks.avg - b->data.selfTicks.avg;
}
SHINY_API void ShinyZone_clear(ShinyZone* self);
SHINY_API void ShinyZone_enumerateZones(const ShinyZone* a_zone, void (*a_func)(const ShinyZone*));
#if __cplusplus
} /* end of extern "C" */
template <class T>
void ShinyZone_enumerateZones(const ShinyZone* a_zone, T* a_this, void (T::*a_func)(const ShinyZone*)) {
(a_this->*a_func)(a_zone);
if (a_zone->next) ShinyZone_enumerateZones(a_zone->next, a_this, a_func);
}
#endif /* __cplusplus */
#endif /* SHINY_ZONE_H */

View File

@ -8,7 +8,3 @@ add_library(clipper STATIC
clipper_z.cpp
clipper_z.hpp
)
if(SLIC3R_PROFILE)
target_link_libraries(clipper Shiny)
endif()

View File

@ -50,17 +50,6 @@
#include <assert.h>
#include <libslic3r/Int128.hpp>
// Profiling support using the Shiny intrusive profiler
//#define CLIPPERLIB_PROFILE
#if defined(SLIC3R_PROFILE) && defined(CLIPPERLIB_PROFILE)
#include <Shiny/Shiny.h>
#define CLIPPERLIB_PROFILE_FUNC() PROFILE_FUNC()
#define CLIPPERLIB_PROFILE_BLOCK(name) PROFILE_BLOCK(name)
#else
#define CLIPPERLIB_PROFILE_FUNC()
#define CLIPPERLIB_PROFILE_BLOCK(name)
#endif
#ifdef CLIPPERLIB_NAMESPACE_PREFIX
namespace CLIPPERLIB_NAMESPACE_PREFIX {
#endif // CLIPPERLIB_NAMESPACE_PREFIX
@ -299,7 +288,6 @@ int PointInPolygon (const IntPoint &pt, OutPt *op)
// This is potentially very expensive! O(n^2)!
bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2)
{
CLIPPERLIB_PROFILE_FUNC();
OutPt* op = OutPt1;
do
{
@ -602,9 +590,18 @@ bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b)
// ClipperBase class methods ...
//------------------------------------------------------------------------------
#ifndef CLIPPERLIB_INT32
#ifdef CLIPPERLIB_INT32
static inline void RangeTest(const IntPoint &pt)
{
#ifndef NDEBUG
static constexpr const int32_t hi = 65536 * 16383;
if (pt.x() > hi || pt.y() > hi || -pt.x() > hi || -pt.y() > hi)
throw clipperException("Coordinate outside allowed range");
#endif // NDEBUG
}
#else // CLIPPERLIB_INT32
// Called from ClipperBase::AddPath() to verify the scale of the input polygon coordinates.
inline void RangeTest(const IntPoint& Pt, bool& useFullRange)
static inline void RangeTest(const IntPoint& Pt, bool& useFullRange)
{
if (useFullRange)
{
@ -759,7 +756,6 @@ TEdge* ClipperBase::ProcessBound(TEdge* E, bool NextIsForward)
bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
{
CLIPPERLIB_PROFILE_FUNC();
// Remove duplicate end point from a closed input path.
// Remove duplicate points from the end of the input path.
int highI = (int)pg.size() -1;
@ -783,7 +779,6 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
bool ClipperBase::AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, bool Closed, TEdge* edges)
{
CLIPPERLIB_PROFILE_FUNC();
#ifdef use_lines
if (!Closed && PolyTyp == ptClip)
throw clipperException("AddPath: Open paths must be subject.");
@ -798,7 +793,10 @@ bool ClipperBase::AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, b
try
{
edges[1].Curr = pg[1];
#ifndef CLIPPERLIB_INT32
#ifdef CLIPPERLIB_INT32
RangeTest(pg[0]);
RangeTest(pg[highI]);
#else
RangeTest(pg[0], m_UseFullRange);
RangeTest(pg[highI], m_UseFullRange);
#endif // CLIPPERLIB_INT32
@ -806,7 +804,9 @@ bool ClipperBase::AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, b
InitEdge(&edges[highI], &edges[0], &edges[highI-1], pg[highI]);
for (int i = highI - 1; i >= 1; --i)
{
#ifndef CLIPPERLIB_INT32
#ifdef CLIPPERLIB_INT32
RangeTest(pg[i]);
#else
RangeTest(pg[i], m_UseFullRange);
#endif // CLIPPERLIB_INT32
InitEdge(&edges[i], &edges[i+1], &edges[i-1], pg[i]);
@ -961,7 +961,6 @@ bool ClipperBase::AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, b
void ClipperBase::Clear()
{
CLIPPERLIB_PROFILE_FUNC();
m_MinimaList.clear();
m_edges.clear();
#ifndef CLIPPERLIB_INT32
@ -975,7 +974,6 @@ void ClipperBase::Clear()
// Sort the LML entries, initialize the left / right bound edges of each Local Minima.
void ClipperBase::Reset()
{
CLIPPERLIB_PROFILE_FUNC();
if (m_MinimaList.empty()) return; //ie nothing to process
std::sort(m_MinimaList.begin(), m_MinimaList.end(), [](const LocalMinimum& lm1, const LocalMinimum& lm2){ return lm1.Y < lm2.Y; });
@ -1004,7 +1002,6 @@ void ClipperBase::Reset()
// Returns (0,0,0,0) for an empty rectangle.
IntRect ClipperBase::GetBounds()
{
CLIPPERLIB_PROFILE_FUNC();
IntRect result;
auto lm = m_MinimaList.begin();
if (lm == m_MinimaList.end())
@ -1065,7 +1062,6 @@ Clipper::Clipper(int initOptions) :
void Clipper::Reset()
{
CLIPPERLIB_PROFILE_FUNC();
ClipperBase::Reset();
m_Scanbeam = std::priority_queue<cInt>();
m_Maxima.clear();
@ -1080,7 +1076,6 @@ void Clipper::Reset()
bool Clipper::Execute(ClipType clipType, Paths &solution,
PolyFillType subjFillType, PolyFillType clipFillType)
{
CLIPPERLIB_PROFILE_FUNC();
if (m_HasOpenPaths)
throw clipperException("Error: PolyTree struct is needed for open path clipping.");
solution.clear();
@ -1098,7 +1093,6 @@ bool Clipper::Execute(ClipType clipType, Paths &solution,
bool Clipper::Execute(ClipType clipType, PolyTree& polytree,
PolyFillType subjFillType, PolyFillType clipFillType)
{
CLIPPERLIB_PROFILE_FUNC();
m_SubjFillType = subjFillType;
m_ClipFillType = clipFillType;
m_ClipType = clipType;
@ -1112,10 +1106,8 @@ bool Clipper::Execute(ClipType clipType, PolyTree& polytree,
bool Clipper::ExecuteInternal()
{
CLIPPERLIB_PROFILE_FUNC();
bool succeeded = true;
try {
CLIPPERLIB_PROFILE_BLOCK(Clipper_ExecuteInternal_Process);
Reset();
if (m_MinimaList.empty()) return true;
cInt botY = m_Scanbeam.top();
@ -1140,13 +1132,11 @@ bool Clipper::ExecuteInternal()
if (succeeded)
{
CLIPPERLIB_PROFILE_BLOCK(Clipper_ExecuteInternal_Fix);
//fix orientations ...
//FIXME Vojtech: Does it not invalidate the loop hierarchy maintained as OutRec::FirstLeft pointers?
//FIXME Vojtech: The area is calculated with floats, it may not be numerically stable!
{
CLIPPERLIB_PROFILE_BLOCK(Clipper_ExecuteInternal_Fix_orientations);
for (OutRec *outRec : m_PolyOuts)
if (outRec->Pts && !outRec->IsOpen && (outRec->IsHole ^ m_ReverseOutput) == (Area(*outRec) > 0))
ReversePolyPtLinks(outRec->Pts);
@ -1156,7 +1146,6 @@ bool Clipper::ExecuteInternal()
//unfortunately FixupOutPolygon() must be done after JoinCommonEdges()
{
CLIPPERLIB_PROFILE_BLOCK(Clipper_ExecuteInternal_Fix_fixup);
for (OutRec *outRec : m_PolyOuts)
if (outRec->Pts) {
if (outRec->IsOpen)
@ -1410,7 +1399,6 @@ bool Clipper::IsContributing(const TEdge& edge) const
// Called from Clipper::InsertLocalMinimaIntoAEL() and Clipper::IntersectEdges().
OutPt* Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt)
{
CLIPPERLIB_PROFILE_FUNC();
OutPt* result;
TEdge *e, *prevE;
if (IsHorizontal(*e2) || ( e1->Dx > e2->Dx ))
@ -1502,7 +1490,6 @@ void Clipper::CopyAELToSEL()
// Called from Clipper::ExecuteInternal()
void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
{
CLIPPERLIB_PROFILE_FUNC();
while (!m_MinimaList.empty() && m_MinimaList.back().Y == botY)
{
TEdge* lb = m_MinimaList.back().LeftBound;
@ -2052,7 +2039,6 @@ OutPt* Clipper::GetLastOutPt(TEdge *e)
void Clipper::ProcessHorizontals()
{
CLIPPERLIB_PROFILE_FUNC();
TEdge* horzEdge = m_SortedEdges;
while(horzEdge)
{
@ -2429,7 +2415,6 @@ void Clipper::UpdateEdgeIntoAEL(TEdge *&e)
bool Clipper::ProcessIntersections(const cInt topY)
{
CLIPPERLIB_PROFILE_FUNC();
if( !m_ActiveEdges ) return true;
try {
BuildIntersectList(topY);
@ -2584,7 +2569,6 @@ void Clipper::DoMaxima(TEdge *e)
void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
{
CLIPPERLIB_PROFILE_FUNC();
TEdge* e = m_ActiveEdges;
while( e )
{
@ -3195,7 +3179,6 @@ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
// This is potentially very expensive! O(n^3)!
void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec) const
{
CLIPPERLIB_PROFILE_FUNC();
//tests if NewOutRec contains the polygon before reassigning FirstLeft
for (OutRec *outRec : m_PolyOuts)
{
@ -3219,7 +3202,6 @@ void Clipper::FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec) const
void Clipper::JoinCommonEdges()
{
CLIPPERLIB_PROFILE_FUNC();
for (Join &join : m_Joins)
{
OutRec *outRec1 = GetOutRec(join.OutPt1->Idx);
@ -3770,7 +3752,6 @@ void ClipperOffset::DoRound(int j, int k)
// http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/Clipper/Properties/StrictlySimple.htm
void Clipper::DoSimplePolygons()
{
CLIPPERLIB_PROFILE_FUNC();
size_t i = 0;
while (i < m_PolyOuts.size())
{

View File

@ -184,6 +184,9 @@ void AppConfig::set_defaults()
if (get("show_hints").empty())
set("show_hints", "1");
if (get("allow_auto_color_change").empty())
set("allow_auto_color_change", "1");
if (get("allow_ip_resolve").empty())
set("allow_ip_resolve", "1");

View File

@ -451,8 +451,23 @@ SkeletalTrapezoidation::SkeletalTrapezoidation(const Polygons& polys, const Bead
constructFromPolygons(polys);
}
static bool has_finite_edge_with_non_finite_vertex(const Geometry::VoronoiDiagram &voronoi_diagram)
{
for (const VoronoiUtils::vd_t::edge_type &edge : voronoi_diagram.edges()) {
if (edge.is_finite()) {
assert(edge.vertex0() != nullptr && edge.vertex1() != nullptr);
if (edge.vertex0() == nullptr || edge.vertex1() == nullptr || !VoronoiUtils::is_finite(*edge.vertex0()) ||
!VoronoiUtils::is_finite(*edge.vertex1()))
return true;
}
}
return false;
}
static bool detect_missing_voronoi_vertex(const Geometry::VoronoiDiagram &voronoi_diagram, const std::vector<SkeletalTrapezoidation::Segment> &segments) {
if (has_finite_edge_with_non_finite_vertex(voronoi_diagram))
return true;
for (VoronoiUtils::vd_t::cell_type cell : voronoi_diagram.cells()) {
if (!cell.incident_edge())
continue; // There is no spoon
@ -471,7 +486,8 @@ static bool detect_missing_voronoi_vertex(const Geometry::VoronoiDiagram &vorono
VoronoiUtils::vd_t::edge_type *ending_vd_edge = nullptr;
VoronoiUtils::vd_t::edge_type *edge = cell.incident_edge();
do {
if (edge->is_infinite()) continue;
if (edge->is_infinite() || edge->vertex0() == nullptr || edge->vertex1() == nullptr || !VoronoiUtils::is_finite(*edge->vertex0()) || !VoronoiUtils::is_finite(*edge->vertex1()))
continue;
Vec2i64 v0 = VoronoiUtils::p(edge->vertex0());
Vec2i64 v1 = VoronoiUtils::p(edge->vertex1());
@ -509,29 +525,36 @@ static bool has_missing_twin_edge(const SkeletalTrapezoidationGraph &graph)
inline static std::unordered_map<Point, Point, PointHash> try_to_fix_degenerated_voronoi_diagram_by_rotation(
Geometry::VoronoiDiagram &voronoi_diagram,
const Polygons &polys,
Polygons &polys_copy,
Polygons &polys_rotated,
std::vector<SkeletalTrapezoidation::Segment> &segments,
const double fix_angle)
{
std::unordered_map<Point, Point, PointHash> vertex_mapping;
for (Polygon &poly : polys_copy)
for (Polygon &poly : polys_rotated)
poly.rotate(fix_angle);
assert(polys_copy.size() == polys.size());
assert(polys_rotated.size() == polys.size());
for (size_t poly_idx = 0; poly_idx < polys.size(); ++poly_idx) {
assert(polys_copy[poly_idx].size() == polys[poly_idx].size());
assert(polys_rotated[poly_idx].size() == polys[poly_idx].size());
for (size_t point_idx = 0; point_idx < polys[poly_idx].size(); ++point_idx)
vertex_mapping.insert({polys[poly_idx][point_idx], polys_copy[poly_idx][point_idx]});
vertex_mapping.insert({polys_rotated[poly_idx][point_idx], polys[poly_idx][point_idx]});
}
segments.clear();
for (size_t poly_idx = 0; poly_idx < polys_copy.size(); poly_idx++)
for (size_t point_idx = 0; point_idx < polys_copy[poly_idx].size(); point_idx++)
segments.emplace_back(&polys_copy, poly_idx, point_idx);
for (size_t poly_idx = 0; poly_idx < polys_rotated.size(); poly_idx++)
for (size_t point_idx = 0; point_idx < polys_rotated[poly_idx].size(); point_idx++)
segments.emplace_back(&polys_rotated, poly_idx, point_idx);
voronoi_diagram.clear();
construct_voronoi(segments.begin(), segments.end(), &voronoi_diagram);
#ifdef ARACHNE_DEBUG_VORONOI
{
static int iRun = 0;
dump_voronoi_to_svg(debug_out_path("arachne_voronoi-diagram-rotated-%d.svg", iRun++).c_str(), voronoi_diagram, to_points(polys), to_lines(polys));
}
#endif
assert(Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(voronoi_diagram));
return vertex_mapping;
@ -591,10 +614,6 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
}
#endif
#ifdef ARACHNE_DEBUG
assert(Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(voronoi_diagram));
#endif
// Try to detect cases when some Voronoi vertex is missing and when
// the Voronoi diagram is not planar.
// When any Voronoi vertex is missing, or the Voronoi diagram is not
@ -715,6 +734,10 @@ process_voronoi_diagram:
if (degenerated_voronoi_diagram)
rotate_back_skeletal_trapezoidation_graph_after_fix(this->graph, fix_angle, vertex_mapping);
#ifdef ARACHNE_DEBUG
assert(Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(voronoi_diagram));
#endif
separatePointyQuadEndNodes();
graph.collapseSmallEdges();

View File

@ -268,13 +268,13 @@ void extrusion_paths_append(ExtrusionPaths &dst, const ClipperLib_Z::Paths &extr
{
for (const ClipperLib_Z::Path &extrusion_path : extrusion_paths) {
ThickPolyline thick_polyline = Arachne::to_thick_polyline(extrusion_path);
Slic3r::append(dst, thick_polyline_to_extrusion_paths(thick_polyline, role, flow, scaled<float>(0.05), float(SCALED_EPSILON)));
Slic3r::append(dst, thick_polyline_to_multi_path(thick_polyline, role, flow, scaled<float>(0.05), float(SCALED_EPSILON)).paths);
}
}
void extrusion_paths_append(ExtrusionPaths &dst, const Arachne::ExtrusionLine &extrusion, const ExtrusionRole role, const Flow &flow)
{
ThickPolyline thick_polyline = Arachne::to_thick_polyline(extrusion);
Slic3r::append(dst, thick_polyline_to_extrusion_paths(thick_polyline, role, flow, scaled<float>(0.05), float(SCALED_EPSILON)));
Slic3r::append(dst, thick_polyline_to_multi_path(thick_polyline, role, flow, scaled<float>(0.05), float(SCALED_EPSILON)).paths);
}
} // namespace Slic3r

View File

@ -15,6 +15,7 @@ Vec2i64 VoronoiUtils::p(const vd_t::vertex_type *node)
{
const double x = node->x();
const double y = node->y();
assert(std::isfinite(x) && std::isfinite(y));
assert(x <= double(std::numeric_limits<int64_t>::max()) && x >= std::numeric_limits<int64_t>::lowest());
assert(y <= double(std::numeric_limits<int64_t>::max()) && y >= std::numeric_limits<int64_t>::lowest());
return {int64_t(x + 0.5 - (x < 0)), int64_t(y + 0.5 - (y < 0))}; // Round to the nearest integer coordinates.

View File

@ -35,6 +35,11 @@ public:
* The \p approximate_step_size is measured parallel to the \p source_segment, not along the parabola.
*/
static std::vector<Point> discretizeParabola(const Point &source_point, const Segment &source_segment, Point start, Point end, coord_t approximate_step_size, float transitioning_angle);
static inline bool is_finite(const VoronoiUtils::vd_t::vertex_type &vertex)
{
return std::isfinite(vertex.x()) && std::isfinite(vertex.y());
}
};
} // namespace Slic3r::Arachne

View File

@ -18,7 +18,7 @@ public:
BoundingBoxBase() : min(PointClass::Zero()), max(PointClass::Zero()), defined(false) {}
BoundingBoxBase(const PointClass &pmin, const PointClass &pmax) :
min(pmin), max(pmax), defined(pmin(0) < pmax(0) && pmin(1) < pmax(1)) {}
min(pmin), max(pmax), defined(pmin.x() < pmax.x() && pmin.y() < pmax.y()) {}
BoundingBoxBase(const PointClass &p1, const PointClass &p2, const PointClass &p3) :
min(p1), max(p1), defined(false) { merge(p2); merge(p3); }
@ -37,7 +37,7 @@ public:
this->min = this->min.cwiseMin(vec);
this->max = this->max.cwiseMax(vec);
}
this->defined = (this->min(0) < this->max(0)) && (this->min(1) < this->max(1));
this->defined = (this->min.x() < this->max.x()) && (this->min.y() < this->max.y());
}
}
@ -58,15 +58,15 @@ public:
BoundingBoxBase<PointClass> inflated(coordf_t delta) const throw() { BoundingBoxBase<PointClass> out(*this); out.offset(delta); return out; }
PointClass center() const;
bool contains(const PointClass &point) const {
return point(0) >= this->min(0) && point(0) <= this->max(0)
&& point(1) >= this->min(1) && point(1) <= this->max(1);
return point.x() >= this->min.x() && point.x() <= this->max.x()
&& point.y() >= this->min.y() && point.y() <= this->max.y();
}
bool contains(const BoundingBoxBase<PointClass> &other) const {
return contains(other.min) && contains(other.max);
}
bool overlap(const BoundingBoxBase<PointClass> &other) const {
return ! (this->max(0) < other.min(0) || this->min(0) > other.max(0) ||
this->max(1) < other.min(1) || this->min(1) > other.max(1));
return ! (this->max.x() < other.min.x() || this->min.x() > other.max.x() ||
this->max.y() < other.min.y() || this->min.y() > other.max.y());
}
bool operator==(const BoundingBoxBase<PointClass> &rhs) { return this->min == rhs.min && this->max == rhs.max; }
bool operator!=(const BoundingBoxBase<PointClass> &rhs) { return ! (*this == rhs); }
@ -79,7 +79,7 @@ public:
BoundingBox3Base() : BoundingBoxBase<PointClass>() {}
BoundingBox3Base(const PointClass &pmin, const PointClass &pmax) :
BoundingBoxBase<PointClass>(pmin, pmax)
{ if (pmin(2) >= pmax(2)) BoundingBoxBase<PointClass>::defined = false; }
{ if (pmin.z() >= pmax.z()) BoundingBoxBase<PointClass>::defined = false; }
BoundingBox3Base(const PointClass &p1, const PointClass &p2, const PointClass &p3) :
BoundingBoxBase<PointClass>(p1, p1) { merge(p2); merge(p3); }
@ -96,7 +96,7 @@ public:
this->min = this->min.cwiseMin(vec);
this->max = this->max.cwiseMax(vec);
}
this->defined = (this->min(0) < this->max(0)) && (this->min(1) < this->max(1)) && (this->min(2) < this->max(2));
this->defined = (this->min.x() < this->max.x()) && (this->min.y() < this->max.y()) && (this->min.z() < this->max.z());
}
BoundingBox3Base(const std::vector<PointClass> &points)
@ -116,15 +116,17 @@ public:
coordf_t max_size() const;
bool contains(const PointClass &point) const {
return BoundingBoxBase<PointClass>::contains(point) && point(2) >= this->min(2) && point(2) <= this->max(2);
return BoundingBoxBase<PointClass>::contains(point) && point.z() >= this->min.z() && point.z() <= this->max.z();
}
bool contains(const BoundingBox3Base<PointClass>& other) const {
return contains(other.min) && contains(other.max);
}
// Intersects without boundaries.
bool intersects(const BoundingBox3Base<PointClass>& other) const {
return (this->min(0) < other.max(0)) && (this->max(0) > other.min(0)) && (this->min(1) < other.max(1)) && (this->max(1) > other.min(1)) && (this->min(2) < other.max(2)) && (this->max(2) > other.min(2));
return this->min.x() < other.max.x() && this->max.x() > other.min.x() && this->min.y() < other.max.y() && this->max.y() > other.min.y() &&
this->min.z() < other.max.z() && this->max.z() > other.min.z();
}
};
@ -212,13 +214,13 @@ public:
template<typename VT>
inline bool empty(const BoundingBoxBase<VT> &bb)
{
return ! bb.defined || bb.min(0) >= bb.max(0) || bb.min(1) >= bb.max(1);
return ! bb.defined || bb.min.x() >= bb.max.x() || bb.min.y() >= bb.max.y();
}
template<typename VT>
inline bool empty(const BoundingBox3Base<VT> &bb)
{
return ! bb.defined || bb.min(0) >= bb.max(0) || bb.min(1) >= bb.max(1) || bb.min(2) >= bb.max(2);
return ! bb.defined || bb.min.x() >= bb.max.x() || bb.min.y() >= bb.max.y() || bb.min.z() >= bb.max.z();
}
inline BoundingBox scaled(const BoundingBoxf &bb) { return {scaled(bb.min), scaled(bb.max)}; }

View File

@ -332,7 +332,7 @@ static std::vector<InnerBrimExPolygons> inner_brim_area(const Print
append(no_brim_area_object, diff_ex(offset(ex_poly.contour, no_brim_offset, ClipperLib::jtSquare), ex_poly_holes_reversed));
if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim)
append(no_brim_area_object, diff_ex(ExPolygon(ex_poly.contour), shrink_ex(ex_poly_holes_reversed, no_brim_offset, ClipperLib::jtSquare)));
append(no_brim_area_object, diff_ex(ex_poly.contour, shrink_ex(ex_poly_holes_reversed, no_brim_offset, ClipperLib::jtSquare)));
append(holes_reversed_object, ex_poly_holes_reversed);
}

View File

@ -258,6 +258,10 @@ set(SLIC3R_SOURCES
Technologies.hpp
Tesselate.cpp
Tesselate.hpp
TreeSupport.cpp
TreeSupport.hpp
TreeModelVolumes.cpp
TreeModelVolumes.hpp
TriangleMesh.cpp
TriangleMesh.hpp
TriangleMeshSlicer.cpp
@ -461,10 +465,6 @@ if(WIN32)
target_link_libraries(libslic3r Psapi.lib)
endif()
if(SLIC3R_PROFILE)
target_link_libraries(libslic3r Shiny)
endif()
if (APPLE)
# This flag prevents the need for minimum SDK version 10.14
# currently, PS targets v10.12

View File

@ -8,17 +8,6 @@
#include "SVG.hpp"
#endif /* CLIPPER_UTILS_DEBUG */
// Profiling support using the Shiny intrusive profiler
//#define CLIPPER_UTILS_PROFILE
#if defined(SLIC3R_PROFILE) && defined(CLIPPER_UTILS_PROFILE)
#include <Shiny/Shiny.h>
#define CLIPPERUTILS_PROFILE_FUNC() PROFILE_FUNC()
#define CLIPPERUTILS_PROFILE_BLOCK(name) PROFILE_BLOCK(name)
#else
#define CLIPPERUTILS_PROFILE_FUNC()
#define CLIPPERUTILS_PROFILE_BLOCK(name)
#endif
#define CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR (0.005f)
namespace Slic3r {
@ -556,6 +545,8 @@ Slic3r::Polygons diff(const Slic3r::Surfaces &subject, const Slic3r::Polygons &c
{ return _clipper(ClipperLib::ctDifference, ClipperUtils::SurfacesProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
{ return _clipper(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::SinglePathProvider(clip.points), do_safety_offset); }
Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset)
{ return _clipper(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonProvider(clip), do_safety_offset); }
Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
{ return _clipper(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
Slic3r::Polygons intersection(const Slic3r::ExPolygon &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset)
@ -576,6 +567,8 @@ Slic3r::Polygons union_(const Slic3r::ExPolygons &subject)
{ return _clipper(ClipperLib::ctUnion, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ApplySafetyOffset::No); }
Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::Polygons &subject2)
{ return _clipper(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(subject2), ApplySafetyOffset::No); }
Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::ExPolygon &subject2)
{ return _clipper(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonProvider(subject2), ApplySafetyOffset::No); }
template <typename TSubject, typename TClip>
static ExPolygons _clipper_ex(ClipperLib::ClipType clipType, TSubject &&subject, TClip &&clip, ApplySafetyOffset do_safety_offset, ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero)
@ -585,6 +578,8 @@ Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygo
{ return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset)
{ return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); }
Slic3r::ExPolygons diff_ex(const Slic3r::Polygon &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset)
{ return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); }
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset)
{ return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); }
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
@ -715,6 +710,8 @@ Slic3r::Polylines diff_pl(const Slic3r::Polygons &subject, const Slic3r::Polygon
{ return _clipper_pl_closed(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip)); }
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip)
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::SinglePathProvider(clip.points)); }
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip)
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonProvider(clip)); }
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip)
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::PolygonsProvider(clip)); }
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygons &clip)

View File

@ -420,6 +420,7 @@ inline Slic3r::Lines diff_ln(const Slic3r::Lines &subject, const Slic3r::Polygon
// Safety offset is applied to the clipping polygons only.
Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::Polygons intersection(const Slic3r::ExPolygon &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::Polygons intersection(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
@ -436,6 +437,7 @@ Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r
Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::ExPolygons intersection_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygons &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip);
@ -458,6 +460,7 @@ Slic3r::Polygons union_(const Slic3r::Polygons &subject);
Slic3r::Polygons union_(const Slic3r::ExPolygons &subject);
Slic3r::Polygons union_(const Slic3r::Polygons &subject, const ClipperLib::PolyFillType fillType);
Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::Polygons &subject2);
Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::ExPolygon &subject2);
// May be used to "heal" unusual models (3DLabPrints etc.) by providing fill_type (pftEvenOdd, pftNonZero, pftPositive, pftNegative).
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero);
Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons &subject);

View File

@ -12,6 +12,7 @@
#include <string>
#include <string_view>
#include <vector>
#include <float.h>
#include "libslic3r.h"
#include "clonable_ptr.hpp"
#include "Exception.hpp"
@ -1766,8 +1767,8 @@ public:
// <min, max> limit of a numeric input.
// If not set, the <min, max> is set to <INT_MIN, INT_MAX>
// By setting min=0, only nonnegative input is allowed.
int min = INT_MIN;
int max = INT_MAX;
float min = -FLT_MAX;
float max = FLT_MAX;
// To check if it's not a typo and a % is missing
double max_literal = 1;
ConfigOptionMode mode = comSimple;

View File

@ -66,6 +66,8 @@ struct Info
bool operator==(const Info& rhs) const
{
if (rhs.gcodes.empty() && this->gcodes.empty())
return true; // don't respect to the comparison of the mode, when g_codes are empty
return (rhs.mode == this->mode ) &&
(rhs.gcodes == this->gcodes );
}

View File

@ -12,27 +12,6 @@
namespace Slic3r {
ExPolygon::operator Points() const
{
Points points;
Polygons pp = *this;
for (Polygons::const_iterator poly = pp.begin(); poly != pp.end(); ++poly) {
for (Points::const_iterator point = poly->points.begin(); point != poly->points.end(); ++point)
points.push_back(*point);
}
return points;
}
ExPolygon::operator Polygons() const
{
return to_polygons(*this);
}
ExPolygon::operator Polylines() const
{
return to_polylines(*this);
}
void ExPolygon::scale(double factor)
{
contour.scale(factor);
@ -149,7 +128,7 @@ bool ExPolygon::overlaps(const ExPolygon &other) const
svg.draw_outline(*this);
svg.draw_outline(other, "blue");
#endif
Polylines pl_out = intersection_pl((Polylines)other, *this);
Polylines pl_out = intersection_pl(to_polylines(other), *this);
#if 0
svg.draw(pl_out, "red");
#endif

View File

@ -34,9 +34,6 @@ public:
Polygon contour;
Polygons holes;
operator Points() const;
operator Polygons() const;
operator Polylines() const;
void clear() { contour.points.clear(); holes.clear(); }
void scale(double factor);
void translate(double x, double y) { this->translate(Point(coord_t(x), coord_t(y))); }
@ -281,6 +278,19 @@ inline ExPolygons to_expolygons(Polygons &&polys)
return ex_polys;
}
inline Points to_points(const ExPolygon &expoly)
{
size_t cnt = expoly.contour.size();
for (const Polygon &hole : expoly.holes)
cnt += hole.size();
Points out;
out.reserve(cnt);
append(out, expoly.contour.points);
for (const Polygon &hole : expoly.holes)
append(out, hole.points);
return out;
}
inline void polygons_append(Polygons &dst, const ExPolygon &src)
{
dst.reserve(dst.size() + src.holes.size() + 1);

View File

@ -179,6 +179,16 @@ private:
ExtrusionRole m_role;
};
class ExtrusionPathOriented : public ExtrusionPath
{
public:
ExtrusionPathOriented(ExtrusionRole role, double mm3_per_mm, float width, float height) : ExtrusionPath(role, mm3_per_mm, width, height) {}
ExtrusionEntity* clone() const override { return new ExtrusionPathOriented(*this); }
// Create a new object, initialize it with this object using the move semantics.
ExtrusionEntity* clone_move() override { return new ExtrusionPathOriented(std::move(*this)); }
virtual bool can_reverse() const { return false; }
};
typedef std::vector<ExtrusionPath> ExtrusionPaths;
// Single continuous extrusion path, possibly with varying extrusion thickness, extrusion height or bridging / non bridging.
@ -330,12 +340,12 @@ inline void extrusion_paths_append(ExtrusionPaths &dst, Polylines &&polylines, E
polylines.clear();
}
inline void extrusion_entities_append_paths(ExtrusionEntitiesPtr &dst, const Polylines &polylines, ExtrusionRole role, double mm3_per_mm, float width, float height)
inline void extrusion_entities_append_paths(ExtrusionEntitiesPtr &dst, const Polylines &polylines, ExtrusionRole role, double mm3_per_mm, float width, float height, bool can_reverse = true)
{
dst.reserve(dst.size() + polylines.size());
for (const Polyline &polyline : polylines)
if (polyline.is_valid()) {
ExtrusionPath *extrusion_path = new ExtrusionPath(role, mm3_per_mm, width, height);
ExtrusionPath* extrusion_path = can_reverse ? new ExtrusionPath(role, mm3_per_mm, width, height) : new ExtrusionPathOriented(role, mm3_per_mm, width, height);
dst.push_back(extrusion_path);
extrusion_path->polyline = polyline;
}

View File

@ -427,14 +427,13 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
for (const ThickPolyline &thick_polyline : thick_polylines) {
Flow new_flow = surface_fill.params.flow.with_spacing(float(f->spacing));
ExtrusionPaths paths = thick_polyline_to_extrusion_paths(thick_polyline, surface_fill.params.extrusion_role, new_flow, scaled<float>(0.05), 0);
ExtrusionMultiPath multi_path = thick_polyline_to_multi_path(thick_polyline, surface_fill.params.extrusion_role, new_flow, scaled<float>(0.05), float(SCALED_EPSILON));
// Append paths to collection.
if (!paths.empty()) {
if (paths.front().first_point() == paths.back().last_point())
eec->entities.emplace_back(new ExtrusionLoop(std::move(paths)));
if (!multi_path.empty()) {
if (multi_path.paths.front().first_point() == multi_path.paths.back().last_point())
eec->entities.emplace_back(new ExtrusionLoop(std::move(multi_path.paths)));
else
for (ExtrusionPath &path : paths)
eec->entities.emplace_back(new ExtrusionPath(std::move(path)));
eec->entities.emplace_back(new ExtrusionMultiPath(std::move(multi_path)));
}
}

View File

@ -21,6 +21,8 @@
#include "FillAdaptive.hpp"
#include "FillLightning.hpp"
#include <boost/log/trivial.hpp>
// #define INFILL_DEBUG_OUTPUT
namespace Slic3r {
@ -129,8 +131,8 @@ std::pair<float, Point> Fill::_infill_direction(const Surface *surface) const
float out_angle = this->angle;
if (out_angle == FLT_MAX) {
//FIXME Vojtech: Add a warning?
printf("Using undefined infill angle\n");
assert(false);
BOOST_LOG_TRIVIAL(error) << "Using undefined infill angle";
out_angle = 0.f;
}

View File

@ -106,6 +106,7 @@ void FillConcentric::_fill_surface_single(const FillParams &params,
thick_polyline.points.emplace_back(thick_polyline.points.front());
}
thick_polylines_out.emplace_back(std::move(thick_polyline));
last_pos = thick_polylines_out.back().last_point();
}
// clip the paths to prevent the extruder from getting exactly on the first point of the loop

View File

@ -414,7 +414,7 @@ public:
// bool sticks_removed =
remove_sticks(polygons_src);
// if (sticks_removed) BOOST_LOG_TRIVIAL(error) << "Sticks removed!";
polygons_outer = aoffset1 == 0 ? polygons_src : offset(polygons_src, float(aoffset1), ClipperLib::jtMiter, miterLimit);
polygons_outer = aoffset1 == 0 ? to_polygons(polygons_src) : offset(polygons_src, float(aoffset1), ClipperLib::jtMiter, miterLimit);
if (aoffset2 < 0)
polygons_inner = shrink(polygons_outer, float(aoffset1 - aoffset2), ClipperLib::jtMiter, miterLimit);
// Filter out contours with zero area or small area, contours with 2 points only.

View File

@ -141,18 +141,6 @@ NodeSPtr Node::closestNode(const Point& loc)
return result;
}
bool inside(const Polygons &polygons, const Point &p)
{
int poly_count_inside = 0;
for (const Polygon &poly : polygons) {
const int is_inside_this_poly = ClipperLib::PointInPolygon(p, poly.points);
if (is_inside_this_poly == -1)
return true;
poly_count_inside += is_inside_this_poly;
}
return (poly_count_inside % 2) == 1;
}
bool lineSegmentPolygonsIntersection(const Point& a, const Point& b, const EdgeGrid::Grid& outline_locator, Point& result, const coord_t within_max_dist)
{
struct Visitor {
@ -192,7 +180,7 @@ bool Node::realign(const Polygons& outlines, const EdgeGrid::Grid& outline_locat
if (outlines.empty())
return false;
if (inside(outlines, m_p)) {
if (contains(outlines, m_p)) {
// Only keep children that have an unbroken connection to here, realign will put the rest in rerooted parts due to recursion:
Point coll;
bool reground_me = false;

View File

@ -64,11 +64,11 @@ LoadStepFn get_load_step_fn()
load_step_fn = reinterpret_cast<LoadStepFn>(dlsym(plugin_ptr, fn_name));
if (!load_step_fn) {
dlclose(plugin_ptr);
throw Slic3r::RuntimeError(std::string("Cannot load function from OCCTWrapper.dll: ") + fn_name
throw Slic3r::RuntimeError(std::string("Cannot load function from OCCTWrapper.so: ") + fn_name
+ "\n\n" + dlerror());
}
} else {
throw Slic3r::RuntimeError(std::string("Cannot load OCCTWrapper.dll:\n\n") + dlerror());
throw Slic3r::RuntimeError(std::string("Cannot load OCCTWrapper.so:\n\n") + dlerror());
}
#endif
}

View File

@ -53,8 +53,6 @@
using slic3r_tbb_filtermode = tbb::filter;
#endif
#include <Shiny/Shiny.h>
using namespace std::literals::string_view_literals;
#if 0
@ -735,8 +733,6 @@ namespace DoExport {
void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* result, ThumbnailsGeneratorCallback thumbnail_cb)
{
PROFILE_CLEAR();
CNumericLocalesSetter locales_setter;
// Does the file exist? If so, we hope that it is still valid.
@ -828,10 +824,6 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
BOOST_LOG_TRIVIAL(info) << "Exporting G-code finished" << log_memory_info();
print->set_done(psGCodeExport);
// Write the profiler measurements to file
PROFILE_UPDATE();
PROFILE_OUTPUT(debug_out_path("gcode-export-profile.txt").c_str());
}
// free functions called by GCode::_do_export()
@ -1048,8 +1040,6 @@ std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Pri
void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb)
{
PROFILE_FUNC();
// modifies m_silent_time_estimator_enabled
DoExport::init_gcode_processor(print.config(), m_processor, m_silent_time_estimator_enabled);
@ -2639,6 +2629,12 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, const std::string_view descr
// thus empty path segments will not be produced by G-code export.
loop.split_at(last_pos, false, scaled<double>(0.0015));
for (auto it = std::next(loop.paths.begin()); it != loop.paths.end(); ++it) {
assert(it->polyline.points.size() >= 2);
assert(std::prev(it)->polyline.last_point() == it->polyline.first_point());
}
assert(loop.paths.front().first_point() == loop.paths.back().last_point());
// clip the path to avoid the extruder to get exactly on the first point of the loop;
// if polyline was shorter than the clipping distance we'd get a null polyline, so
// we discard it in that case
@ -2665,8 +2661,21 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, const std::string_view descr
// reset acceleration
gcode += m_writer.set_acceleration((unsigned int)(m_config.default_acceleration.value + 0.5));
if (m_wipe.enable)
m_wipe.path = paths.front().polyline; // TODO: don't limit wipe to last path
if (m_wipe.enable) {
m_wipe.path = paths.front().polyline;
for (auto it = std::next(paths.begin()); it != paths.end(); ++it) {
if (is_bridge(it->role()))
break; // Don't perform a wipe on bridges.
assert(it->polyline.points.size() >= 2);
assert(m_wipe.path.points.back() == it->polyline.first_point());
if (m_wipe.path.points.back() != it->polyline.first_point())
break; // ExtrusionLoop is interrupted in some place.
m_wipe.path.points.insert(m_wipe.path.points.end(), it->polyline.points.begin() + 1, it->polyline.points.end());
}
}
// make a little move inwards before leaving loop
if (paths.back().role() == erExternalPerimeter && m_layer != NULL && m_config.perimeters.value > 1 && paths.front().size() >= 2 && paths.back().polyline.points.size() >= 3) {
@ -2709,6 +2718,10 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, const std::string_view descr
std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, const std::string_view description, double speed)
{
for (auto it = std::next(multipath.paths.begin()); it != multipath.paths.end(); ++it) {
assert(it->polyline.points.size() >= 2);
assert(std::prev(it)->polyline.last_point() == it->polyline.first_point());
}
// extrude along the path
std::string gcode;
for (ExtrusionPath path : multipath.paths) {
@ -2716,8 +2729,20 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, const std::s
gcode += this->_extrude(path, description, speed);
}
if (m_wipe.enable) {
m_wipe.path = std::move(multipath.paths.back().polyline); // TODO: don't limit wipe to last path
m_wipe.path = std::move(multipath.paths.back().polyline);
m_wipe.path.reverse();
for (auto it = std::next(multipath.paths.rbegin()); it != multipath.paths.rend(); ++it) {
if (is_bridge(it->role()))
break; // Do not perform a wipe on bridges.
assert(it->polyline.points.size() >= 2);
assert(m_wipe.path.points.back() == it->polyline.last_point());
if (m_wipe.path.points.back() != it->polyline.last_point())
break; // ExtrusionMultiPath is interrupted in some place.
m_wipe.path.points.insert(m_wipe.path.points.end(), it->polyline.points.rbegin() + 1, it->polyline.points.rend());
}
}
// reset acceleration
gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5));
@ -3134,15 +3159,26 @@ bool GCode::needs_retraction(const Polyline &travel, ExtrusionRole role)
return false;
}
if (role == erSupportMaterial) {
const SupportLayer* support_layer = dynamic_cast<const SupportLayer*>(m_layer);
//FIXME support_layer->support_islands.contains should use some search structure!
if (support_layer != NULL && diff_pl(travel, support_layer->support_islands).empty())
// skip retraction if this is a travel move inside a support material island
//FIXME not retracting over a long path may cause oozing, which in turn may result in missing material
// at the end of the extrusion path!
return false;
}
if (role == erSupportMaterial)
if (const SupportLayer *support_layer = dynamic_cast<const SupportLayer*>(m_layer);
support_layer != nullptr && ! support_layer->support_islands_bboxes.empty()) {
BoundingBox bbox_travel = get_extents(travel);
Polylines trimmed;
bool trimmed_initialized = false;
for (const BoundingBox &bbox : support_layer->support_islands_bboxes)
if (bbox.overlap(bbox_travel)) {
const auto &island = support_layer->support_islands[&bbox - support_layer->support_islands_bboxes.data()];
trimmed = trimmed_initialized ? diff_pl(trimmed, island) : diff_pl(travel, island);
trimmed_initialized = true;
if (trimmed.empty())
// skip retraction if this is a travel move inside a support material island
//FIXME not retracting over a long path may cause oozing, which in turn may result in missing material
// at the end of the extrusion path!
return false;
// Not sure whether updating the boudning box isn't too expensive.
//bbox_travel = get_extents(trimmed);
}
}
if (m_config.only_retract_when_crossing_perimeters && m_layer != nullptr &&
m_config.fill_density.value > 0 && m_layer->any_internal_region_slice_contains(travel))

View File

@ -2683,7 +2683,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
if (m_height == 0.0f)
m_height = DEFAULT_TOOLPATH_HEIGHT;
if (m_end_position[Z] == 0.0f)
if (m_end_position[Z] == 0.0f || (m_extrusion_role == erCustom && m_layer_id == 0))
m_end_position[Z] = m_height;
#if ENABLE_PROCESS_G2_G3_LINES
@ -2913,7 +2913,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
}
if (m_spiral_vase_active && !m_result.spiral_vase_layers.empty()) {
if (m_result.spiral_vase_layers.back().first == FLT_MAX && delta_pos[Z] > 0.0)
if (m_result.spiral_vase_layers.back().first == FLT_MAX && delta_pos[Z] >= 0.0)
// replace layer height placeholder with correct value
m_result.spiral_vase_layers.back().first = static_cast<float>(m_end_position[Z]);
if (!m_result.moves.empty())

View File

@ -153,7 +153,7 @@ static int run_script(const std::string &script, const std::string &gcode, std::
{
// Try to obtain user's default shell
const char *shell = ::getenv("SHELL");
if (shell == nullptr) { shell = "sh"; }
if (shell == nullptr) { shell = "/bin/sh"; }
// Quote and escape the gcode path argument
std::string command { script };

View File

@ -669,17 +669,32 @@ inline void PressureEqualizer::push_to_output(const char *text, const size_t len
output_buffer[output_buffer_length] = 0;
}
inline bool PressureEqualizer::is_just_feedrate_provided(const GCodeLine &line)
inline bool is_just_line_with_extrude_set_speed_tag(const std::string &line)
{
return line.pos_provided[4] && !line.pos_provided[0] && !line.pos_provided[1] && !line.pos_provided[2] && !line.pos_provided[3];
if (line.empty() && !boost::starts_with(line, "G1 ") && !boost::ends_with(line, EXTRUDE_SET_SPEED_TAG))
return false;
const char *p_line = line.data() + 3;
const char *const line_end = line.data() + line.length() - 1;
while (!is_eol(*p_line)) {
if (toupper(*p_line++) == 'F')
break;
else
return false;
}
parse_float(p_line, line_end - p_line);
eatws(p_line);
p_line += EXTRUDE_SET_SPEED_TAG.length();
return p_line <= line_end && is_eol(*p_line);
}
void PressureEqualizer::push_line_to_output(const size_t line_idx, const float new_feedrate, const char *comment)
{
const GCodeLine &line = this->m_gcode_lines[line_idx];
if (line_idx > 0) {
const GCodeLine &prev_line = this->m_gcode_lines[line_idx - 1];
if (prev_line.extrude_set_speed_tag && this->is_just_feedrate_provided(prev_line))
if (line_idx > 0 && output_buffer_length > 0) {
const std::string prev_line_str = std::string(output_buffer.begin() + int(this->output_buffer_prev_length),
output_buffer.begin() + int(this->output_buffer_length) + 1);
if (is_just_line_with_extrude_set_speed_tag(prev_line_str))
this->output_buffer_length = this->output_buffer_prev_length; // Remove the last line because it only sets the speed for an empty block of g-code lines, so it is useless.
else
push_to_output(EXTRUDE_END_TAG.data(), EXTRUDE_END_TAG.length(), true);

View File

@ -193,8 +193,6 @@ private:
// Push a G-code line to the output.
void push_line_to_output(size_t line_idx, float new_feedrate, const char *comment);
inline bool is_just_feedrate_provided(const GCodeLine &line);
public:
std::queue<LayerResult*> m_layer_results;

View File

@ -455,6 +455,7 @@ void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const
}
Polygon polygon = orig_polygon;
bool was_clockwise = polygon.make_counter_clockwise();
float angle_arm_len = region != nullptr ? region->flow(FlowRole::frExternalPerimeter).nozzle_diameter() : 0.5f;
std::vector<float> lengths { };
for (size_t point_idx = 0; point_idx < polygon.size() - 1; ++point_idx) {
@ -462,7 +463,7 @@ void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const
}
lengths.push_back(std::max((unscale(polygon[0]) - unscale(polygon[polygon.size() - 1])).norm(), 0.1));
std::vector<float> polygon_angles = calculate_polygon_angles_at_vertices(polygon, lengths,
SeamPlacer::polygon_local_angles_arm_distance);
angle_arm_len);
result.perimeters.push_back( { });
Perimeter &perimeter = result.perimeters.back();
@ -949,6 +950,10 @@ void pick_random_seam_point(const std::vector<SeamCandidate> &perimeter_points,
};
std::vector<Viable> viables;
const Vec3f pseudornd_seed = perimeter_points[viable_example_index].position;
float rand = std::abs(sin(pseudornd_seed.dot(Vec3f(12.9898f,78.233f, 133.3333f))) * 43758.5453f);
rand = rand - (int) rand;
for (size_t index = start_index; index < end_index; ++index) {
if (comparator.are_similar(perimeter_points[index], perimeter_points[viable_example_index])) {
// index ok, push info into viables
@ -976,7 +981,7 @@ void pick_random_seam_point(const std::vector<SeamCandidate> &perimeter_points,
float len_sum = std::accumulate(viables.begin(), viables.end(), 0.0f, [](const float acc, const Viable &v) {
return acc + v.edge_length;
});
float picked_len = len_sum * (rand() / (float(RAND_MAX) + 1));
float picked_len = len_sum * rand;
size_t point_idx = 0;
while (picked_len - viables[point_idx].edge_length > 0) {
@ -997,11 +1002,7 @@ class PerimeterDistancer {
public:
PerimeterDistancer(const Layer *layer) {
static const float eps = float(scale_(layer->object()->config().slice_closing_radius.value));
// merge with offset
ExPolygons merged = layer->merged(eps);
// ofsset back
ExPolygons layer_outline = offset_ex(merged, -eps);
ExPolygons layer_outline = layer->lslices;
for (const ExPolygon &island : layer_outline) {
assert(island.contour.is_counter_clockwise());
for (const auto &line : island.contour.lines()) {
@ -1017,8 +1018,8 @@ public:
tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(lines);
}
float distance_from_perimeter(const Point &point) const {
Vec2d p = unscale(point);
float distance_from_perimeter(const Vec2f &point) const {
Vec2d p = point.cast<double>();
size_t hit_idx_out { };
Vec2d hit_point_out = Vec2d::Zero();
auto distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, p, hit_idx_out, hit_point_out);
@ -1110,20 +1111,19 @@ void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po)
std::unique_ptr<PerimeterDistancer> current_layer_distancer = std::make_unique<PerimeterDistancer>(po->layers()[layer_idx]);
for (SeamCandidate &perimeter_point : layers[layer_idx].points) {
Point point = Point::new_scale(Vec2f { perimeter_point.position.head<2>() });
Vec2f point = Vec2f { perimeter_point.position.head<2>() };
if (prev_layer_distancer.get() != nullptr) {
perimeter_point.overhang = (prev_layer_distancer->distance_from_perimeter(point)
+ 0.5f * perimeter_point.perimeter.flow_width
perimeter_point.overhang = prev_layer_distancer->distance_from_perimeter(point)
+ 0.6f * perimeter_point.perimeter.flow_width
- tan(SeamPlacer::overhang_angle_threshold)
* po->layers()[layer_idx]->height)
/ (3.0f * perimeter_point.perimeter.flow_width);
//NOTE disables the feature to place seams on slowly decreasing areas. Remove the following line to enable.
perimeter_point.overhang = perimeter_point.overhang < 0.0f ? 0.0f : perimeter_point.overhang;
* po->layers()[layer_idx]->height;
perimeter_point.overhang =
perimeter_point.overhang < 0.0f ? 0.0f : perimeter_point.overhang;
}
if (should_compute_layer_embedding) { // search for embedded perimeter points (points hidden inside the print ,e.g. multimaterial join, best position for seam)
perimeter_point.embedded_distance = current_layer_distancer->distance_from_perimeter(point)
+ 0.5f * perimeter_point.perimeter.flow_width;
+ 0.6f * perimeter_point.perimeter.flow_width;
}
}
@ -1381,7 +1381,7 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl::
observations[index] = current.position.head<2>();
observation_points[index] = current.position.z();
weights[index] = angle_weight(current.local_ccw_angle);
float sign = layer_angle > 2.0 * std::abs(current.local_ccw_angle) ? -1.0f : 1.0f;
float sign = layer_angle > 2.0 * std::abs(current.local_ccw_angle) ? -0.8f : 1.0f;
if (current.type == EnforcedBlockedSeamPoint::Enforced) {
sign = 1.0f;
weights[index] += 3.0f;
@ -1399,10 +1399,10 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl::
// Perimeter structure of the point; also set flag aligned to true
for (size_t index = 0; index < seam_string.size(); ++index) {
const auto &pair = seam_string[index];
float t = std::min(1.0f, std::abs(layers[pair.first].points[pair.second].local_ccw_angle)
/ SeamPlacer::sharp_angle_snapping_threshold);
float t = std::min(1.0f, std::pow(std::abs(layers[pair.first].points[pair.second].local_ccw_angle)
/ SeamPlacer::sharp_angle_snapping_threshold, 3.0f));
if (layers[pair.first].points[pair.second].type == EnforcedBlockedSeamPoint::Enforced){
t = std::max(0.7f, t);
t = std::max(0.4f, t);
}
Vec3f current_pos = layers[pair.first].points[pair.second].position;
@ -1533,16 +1533,40 @@ void SeamPlacer::place_seam(const Layer *layer, ExtrusionLoop &loop, bool extern
const size_t layer_index = layer->id() - po->slicing_parameters().raft_layers();
const double unscaled_z = layer->slice_z;
auto get_next_loop_point = [&loop](ExtrusionLoop::ClosestPathPoint current) {
current.segment_idx += 1;
if (current.segment_idx >= loop.paths[current.path_idx].polyline.points.size()) {
current.path_idx = next_idx_modulo(current.path_idx, loop.paths.size());
current.segment_idx = 0;
}
current.foot_pt = loop.paths[current.path_idx].polyline.points[current.segment_idx];
return current;
};
const PrintObjectSeamData::LayerSeams &layer_perimeters =
m_seam_per_object.find(layer->object())->second.layers[layer_index];
// Find the closest perimeter in the SeamPlacer to the first point of this loop.
size_t closest_perimeter_point_index;
{
const Point &fp = loop.first_point();
Vec2f unscaled_p = unscaled<float>(fp);
closest_perimeter_point_index = find_closest_point(*layer_perimeters.points_tree.get(),
to_3d(unscaled_p, float(unscaled_z)));
// Find the closest perimeter in the SeamPlacer to this loop.
// Repeat search until two consecutive points of the loop are found, that result in the same closest_perimeter
// This is beacuse with arachne, T-Junctions may exist and sometimes the wrong perimeter was chosen
size_t closest_perimeter_point_index = 0;
{ // local space for the closest_perimeter_point_index
Perimeter *closest_perimeter = nullptr;
ExtrusionLoop::ClosestPathPoint closest_point{0,0,loop.paths[0].polyline.points[0]};
size_t points_count = std::accumulate(loop.paths.begin(), loop.paths.end(), 0, [](size_t acc,const ExtrusionPath& p) {
return acc + p.polyline.points.size();
});
for (size_t _ = 0; _ < points_count; ++_) {
Vec2f unscaled_p = unscaled<float>(closest_point.foot_pt);
closest_perimeter_point_index = find_closest_point(*layer_perimeters.points_tree.get(),
to_3d(unscaled_p, float(unscaled_z)));
if (closest_perimeter != &layer_perimeters.points[closest_perimeter_point_index].perimeter) {
closest_perimeter = &layer_perimeters.points[closest_perimeter_point_index].perimeter;
closest_point = get_next_loop_point(closest_point);
} else {
break;
}
}
}
Vec3f seam_position;

View File

@ -113,12 +113,10 @@ public:
//square of number of rays per sample point
static constexpr size_t sqr_rays_per_sample_point = 5;
// arm length used during angles computation
static constexpr float polygon_local_angles_arm_distance = 0.3f;
// snapping angle - angles larger than this value will be snapped to during seam painting
static constexpr float sharp_angle_snapping_threshold = 55.0f * float(PI) / 180.0f;
// overhang angle for seam placement that still yields good results, in degrees, measured from vertical direction
static constexpr float overhang_angle_threshold = 45.0f * float(PI) / 180.0f;
static constexpr float overhang_angle_threshold = 50.0f * float(PI) / 180.0f;
// determines angle importance compared to visibility ( neutral value is 1.0f. )
static constexpr float angle_importance_aligned = 0.6f;

View File

@ -10,7 +10,6 @@
#include "LocalesUtils.hpp"
#include <Shiny/Shiny.h>
#include <fast_float/fast_float.h>
namespace Slic3r {
@ -37,14 +36,11 @@ void GCodeReader::apply_config(const DynamicPrintConfig &config)
const char* GCodeReader::parse_line_internal(const char *ptr, const char *end, GCodeLine &gline, std::pair<const char*, const char*> &command)
{
PROFILE_FUNC();
assert(is_decimal_separator_point());
// command and args
const char *c = ptr;
{
PROFILE_BLOCK(command_and_args);
// Skip the whitespaces.
command.first = skip_whitespaces(c);
// Skip the command.
@ -98,10 +94,8 @@ const char* GCodeReader::parse_line_internal(const char *ptr, const char *end, G
for (; ! is_end_of_line(*c); ++ c);
// Copy the raw string including the comment, without the trailing newlines.
if (c > ptr) {
PROFILE_BLOCK(copy_raw_string);
if (c > ptr)
gline.m_raw.assign(ptr, c);
}
// Skip the trailing newlines.
if (*c == '\r')
@ -117,7 +111,6 @@ const char* GCodeReader::parse_line_internal(const char *ptr, const char *end, G
void GCodeReader::update_coordinates(GCodeLine &gline, std::pair<const char*, const char*> &command)
{
PROFILE_FUNC();
if (*command.first == 'G') {
int cmd_len = int(command.second - command.first);
if ((cmd_len == 2 && (command.first[1] == '0' || command.first[1] == '1')) ||

View File

@ -23,8 +23,8 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
bool use_mach_limits = print_config.gcode_flavor.value == gcfMarlinLegacy
|| print_config.gcode_flavor.value == gcfMarlinFirmware
|| print_config.gcode_flavor.value == gcfRepRapFirmware;
m_max_acceleration = std::lrint((use_mach_limits && print_config.machine_limits_usage.value == MachineLimitsUsage::EmitToGCode) ?
print_config.machine_max_acceleration_extruding.values.front() : 0);
m_max_acceleration = static_cast<unsigned int>(std::round((use_mach_limits && print_config.machine_limits_usage.value == MachineLimitsUsage::EmitToGCode) ?
print_config.machine_max_acceleration_extruding.values.front() : 0));
}
void GCodeWriter::set_extruders(std::vector<unsigned int> extruder_ids)

View File

@ -577,7 +577,6 @@ void Transformation::set_scaling_factor(const Vec3d& scaling_factor)
void Transformation::set_scaling_factor(Axis axis, double scaling_factor)
{
#if ENABLE_WORLD_COORDINATE
assert(scaling_factor > 0.0);
auto [rotation, scale] = extract_rotation_scale(m_matrix);
scale(axis, axis) = scaling_factor;

View File

@ -3,6 +3,7 @@
#include <CGAL/Surface_sweep_2_algorithms.h>
#include "libslic3r/Geometry/Voronoi.hpp"
#include "libslic3r/Arachne/utils/VoronoiUtils.hpp"
#include "VoronoiUtilsCgal.hpp"
@ -28,7 +29,8 @@ bool VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(const VD &voronoi_
if (edge.color() != 0)
continue;
if (edge.is_finite() && edge.is_linear()) {
if (edge.is_finite() && edge.is_linear() && edge.vertex0() != nullptr && edge.vertex1() != nullptr &&
Arachne::VoronoiUtils::is_finite(*edge.vertex0()) && Arachne::VoronoiUtils::is_finite(*edge.vertex1())) {
segments.emplace_back(to_cgal_point(*edge.vertex0()), to_cgal_point(*edge.vertex1()));
edge.color(1);
assert(edge.twin() != nullptr);
@ -73,7 +75,8 @@ bool VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(const VoronoiDiagram &vor
do {
// FIXME Lukas H.: Also process parabolic segments.
if (edge->is_finite() && edge->is_linear())
if (edge->is_finite() && edge->is_linear() && edge->vertex0() != nullptr && edge->vertex1() != nullptr &&
Arachne::VoronoiUtils::is_finite(*edge->vertex0()) && Arachne::VoronoiUtils::is_finite(*edge->vertex1()))
edges.emplace_back(edge);
edge = edge->rot_next();

View File

@ -197,6 +197,8 @@ public:
// Polygons covered by the supports: base, interface and contact areas.
// Used to suppress retraction if moving for a support extrusion over these support_islands.
ExPolygons support_islands;
// Slightly inflated bounding boxes of the above, for faster intersection query.
std::vector<BoundingBox> support_islands_bboxes;
// Extrusion paths for the support base and for the support interface and contacts.
ExtrusionEntityCollection support_fills;

View File

@ -101,7 +101,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
g.overhang_flow = this->bridging_flow(frPerimeter);
g.solid_infill_flow = this->flow(frSolidInfill);
if (this->layer()->object()->config().perimeter_generator.value == PerimeterGeneratorType::Arachne)
if (this->layer()->object()->config().perimeter_generator.value == PerimeterGeneratorType::Arachne && !spiral_vase)
g.process_arachne();
else
g.process_classic();
@ -386,10 +386,12 @@ void LayerRegion::prepare_fill_surfaces()
bool spiral_vase = this->layer()->object()->print()->config().spiral_vase;
// if no solid layers are requested, turn top/bottom surfaces to internal
// For Lightning infill, infill_only_where_needed is ignored because both
// do a similar thing, and their combination doesn't make much sense.
if (! spiral_vase && this->region().config().top_solid_layers == 0) {
for (Surface &surface : this->fill_surfaces.surfaces)
if (surface.is_top())
surface.surface_type = this->layer()->object()->config().infill_only_where_needed ? stInternalVoid : stInternal;
surface.surface_type = this->layer()->object()->config().infill_only_where_needed && this->region().config().fill_pattern != ipLightning ? stInternalVoid : stInternal;
}
if (this->region().config().bottom_solid_layers == 0) {
for (Surface &surface : this->fill_surfaces.surfaces)

View File

@ -21,12 +21,12 @@
namespace Slic3r {
ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, const float tolerance, const float merge_tolerance)
ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, const float tolerance, const float merge_tolerance)
{
ExtrusionPaths paths;
ExtrusionPath path(role);
ThickLines lines = thick_polyline.thicklines();
ExtrusionMultiPath multi_path;
ExtrusionPath path(role);
ThickLines lines = thick_polyline.thicklines();
for (int i = 0; i < (int)lines.size(); ++i) {
const ThickLine& line = lines[i];
assert(line.a_width >= SCALED_EPSILON && line.b_width >= SCALED_EPSILON);
@ -38,8 +38,8 @@ ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thick_poly
path.polyline.points.back() = line.b; // If the variable path is non-empty, connect this tiny line to it.
else if (i + 1 < (int)lines.size()) // If there is at least one following line, connect this tiny line to it.
lines[i + 1].a = line.a;
else if (!paths.empty())
paths.back().polyline.points.back() = line.b; // Connect this tiny line to the last finished path.
else if (!multi_path.paths.empty())
multi_path.paths.back().polyline.points.back() = line.b; // Connect this tiny line to the last finished path.
// If any of the above isn't satisfied, then remove this tiny line.
continue;
@ -103,40 +103,38 @@ ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thick_poly
path.polyline.append(line.b);
} else {
// we need to initialize a new line
paths.emplace_back(std::move(path));
multi_path.paths.emplace_back(std::move(path));
path = ExtrusionPath(role);
-- i;
}
}
}
if (path.polyline.is_valid())
paths.emplace_back(std::move(path));
return paths;
multi_path.paths.emplace_back(std::move(path));
return multi_path;
}
static void variable_width(const ThickPolylines& polylines, ExtrusionRole role, const Flow &flow, std::vector<ExtrusionEntity*> &out)
static void variable_width(const ThickPolylines &polylines, ExtrusionRole role, const Flow &flow, std::vector<ExtrusionEntity *> &out)
{
// This value determines granularity of adaptive width, as G-code does not allow
// variable extrusion within a single move; this value shall only affect the amount
// of segments, and any pruning shall be performed before we apply this tolerance.
const auto tolerance = float(scale_(0.05));
for (const ThickPolyline &p : polylines) {
ExtrusionPaths paths = thick_polyline_to_extrusion_paths(p, role, flow, tolerance, tolerance);
// Append paths to collection.
if (!paths.empty()) {
for (auto it = std::next(paths.begin()); it != paths.end(); ++it) {
// This value determines granularity of adaptive width, as G-code does not allow
// variable extrusion within a single move; this value shall only affect the amount
// of segments, and any pruning shall be performed before we apply this tolerance.
const auto tolerance = float(scale_(0.05));
for (const ThickPolyline &p : polylines) {
ExtrusionMultiPath multi_path = thick_polyline_to_multi_path(p, role, flow, tolerance, tolerance);
// Append paths to collection.
if (!multi_path.paths.empty()) {
for (auto it = std::next(multi_path.paths.begin()); it != multi_path.paths.end(); ++it) {
assert(it->polyline.points.size() >= 2);
assert(std::prev(it)->polyline.last_point() == it->polyline.first_point());
}
if (paths.front().first_point() == paths.back().last_point()) {
out.emplace_back(new ExtrusionLoop(std::move(paths)));
} else {
for (ExtrusionPath &path : paths)
out.emplace_back(new ExtrusionPath(std::move(path)));
}
}
}
if (multi_path.paths.front().first_point() == multi_path.paths.back().last_point())
out.emplace_back(new ExtrusionLoop(std::move(multi_path.paths)));
else
out.emplace_back(new ExtrusionMultiPath(std::move(multi_path)));
}
}
}
// Hierarchy of perimeters.
@ -534,10 +532,35 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator &p
else
extrusion_loop.make_clockwise();
for (auto it = std::next(extrusion_loop.paths.begin()); it != extrusion_loop.paths.end(); ++it) {
assert(it->polyline.points.size() >= 2);
assert(std::prev(it)->polyline.last_point() == it->polyline.first_point());
}
assert(extrusion_loop.paths.front().first_point() == extrusion_loop.paths.back().last_point());
extrusion_coll.append(std::move(extrusion_loop));
} else
for (ExtrusionPath &path : paths)
extrusion_coll.append(ExtrusionPath(std::move(path)));
} else {
// Because we are processing one ExtrusionLine all ExtrusionPaths should form one connected path.
// But there is possibility that due to numerical issue there is poss
assert([&paths = std::as_const(paths)]() -> bool {
for (auto it = std::next(paths.begin()); it != paths.end(); ++it)
if (std::prev(it)->polyline.last_point() != it->polyline.first_point())
return false;
return true;
}());
ExtrusionMultiPath multi_path;
multi_path.paths.emplace_back(std::move(paths.front()));
for (auto it_path = std::next(paths.begin()); it_path != paths.end(); ++it_path) {
if (multi_path.paths.back().last_point() != it_path->first_point()) {
extrusion_coll.append(ExtrusionMultiPath(std::move(multi_path)));
multi_path = ExtrusionMultiPath();
}
multi_path.paths.emplace_back(std::move(*it_path));
}
extrusion_coll.append(ExtrusionMultiPath(std::move(multi_path)));
}
}
}

View File

@ -72,7 +72,7 @@ private:
Polygons m_lower_slices_polygons;
};
ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, float tolerance, float merge_tolerance);
ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, float tolerance, float merge_tolerance);
}

View File

@ -40,11 +40,11 @@
#include <boost/lexical_cast.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_lit.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/phoenix/fusion.hpp>
#include <boost/phoenix/stl.hpp>
#include <boost/phoenix/object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/repository/include/qi_distinct.hpp>
#include <boost/spirit/repository/include/qi_iter_pos.hpp>

View File

@ -142,9 +142,9 @@ public:
Point() : Vec2crd(0, 0) {}
Point(int32_t x, int32_t y) : Vec2crd(coord_t(x), coord_t(y)) {}
Point(int64_t x, int64_t y) : Vec2crd(coord_t(x), coord_t(y)) {}
Point(double x, double y) : Vec2crd(coord_t(lrint(x)), coord_t(lrint(y))) {}
Point(double x, double y) : Vec2crd(coord_t(std::round(x)), coord_t(std::round(y))) {}
Point(const Point &rhs) { *this = rhs; }
explicit Point(const Vec2d& rhs) : Vec2crd(coord_t(lrint(rhs.x())), coord_t(lrint(rhs.y()))) {}
explicit Point(const Vec2d& rhs) : Vec2crd(coord_t(std::round(rhs.x())), coord_t(std::round(rhs.y()))) {}
// This constructor allows you to construct Point from Eigen expressions
template<typename OtherDerived>
Point(const Eigen::MatrixBase<OtherDerived> &other) : Vec2crd(other) {}
@ -282,7 +282,7 @@ namespace int128 {
// To be used by std::unordered_map, std::unordered_multimap and friends.
struct PointHash {
size_t operator()(const Vec2crd &pt) const {
size_t operator()(const Vec2crd &pt) const noexcept {
return coord_t((89 * 31 + int64_t(pt.x())) * 31 + pt.y());
}
};

View File

@ -90,28 +90,24 @@ void Polygon::douglas_peucker(double tolerance)
// Does an unoriented polygon contain a point?
// Tested by counting intersections along a horizontal line.
bool Polygon::contains(const Point &point) const
bool Polygon::contains(const Point &p) const
{
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
bool result = false;
Points::const_iterator i = this->points.begin();
Points::const_iterator j = this->points.end() - 1;
for (; i != this->points.end(); j = i++) {
//FIXME this test is not numerically robust. Particularly, it does not handle horizontal segments at y == point(1) well.
// Does the ray with y == point(1) intersect this line segment?
for (; i != this->points.end(); j = i ++)
if (i->y() > p.y() != j->y() > p.y())
#if 1
if ( (((*i)(1) > point(1)) != ((*j)(1) > point(1)))
&& ((double)point(0) < (double)((*j)(0) - (*i)(0)) * (double)(point(1) - (*i)(1)) / (double)((*j)(1) - (*i)(1)) + (double)(*i)(0)) )
result = !result;
if (Vec2d v = (*j - *i).cast<double>();
// p.x() is below the line
p.x() - i->x() < double(p.y() - i->y()) * v.x() / v.y())
#else
if (((*i)(1) > point(1)) != ((*j)(1) > point(1))) {
// Orientation predicated relative to i-th point.
double orient = (double)(point(0) - (*i)(0)) * (double)((*j)(1) - (*i)(1)) - (double)(point(1) - (*i)(1)) * (double)((*j)(0) - (*i)(0));
if (((*i)(1) > (*j)(1)) ? (orient > 0.) : (orient < 0.))
result = !result;
}
if (double orient = (double)(p.x() - i->x()) * (double)(j->y() - i->y()) - (double)(p.y() - i->y()) * (double)(j->x() - i->x());
(i->y() > j->y()) ? (orient > 0.) : (orient < 0.))
#endif
}
result = !result;
return result;
}
@ -520,4 +516,35 @@ void remove_collinear(Polygons &polys)
remove_collinear(poly);
}
bool contains(const Polygons &polygons, const Point &p, bool border_result)
{
int poly_count_inside = 0;
for (const Polygon &poly : polygons) {
const int is_inside_this_poly = ClipperLib::PointInPolygon(p, poly.points);
if (is_inside_this_poly == -1)
return border_result;
poly_count_inside += is_inside_this_poly;
}
return (poly_count_inside % 2) == 1;
}
Polygon make_circle(double radius, double error)
{
double angle = 2. * acos(1. - error / radius);
size_t num_segments = size_t(ceil(2. * M_PI / angle));
return make_circle_num_segments(radius, num_segments);
}
Polygon make_circle_num_segments(double radius, size_t num_segments)
{
Polygon out;
out.points.reserve(num_segments);
double angle_inc = 2.0 * M_PI / num_segments;
for (size_t i = 0; i < num_segments; ++ i) {
const double angle = angle_inc * i;
out.points.emplace_back(coord_t(cos(angle) * radius), coord_t(sin(angle) * radius));
}
return out;
}
}

View File

@ -250,6 +250,12 @@ inline Polygons to_polygons(std::vector<Points> &&paths)
return out;
}
// Returns true if inside. Returns border_result if on boundary.
bool contains(const Polygons& polygons, const Point& p, bool border_result = true);
Polygon make_circle(double radius, double error);
Polygon make_circle_num_segments(double radius, size_t num_segments);
} // Slic3r
// start Boost

View File

@ -61,6 +61,9 @@ public:
}
}
Point& operator[](Points::size_type idx) { return this->points[idx]; }
const Point& operator[](Points::size_type idx) const { return this->points[idx]; }
const Point& last_point() const override { return this->points.back(); }
const Point& leftmost_point() const;
Lines lines() const override;

View File

@ -748,7 +748,7 @@ std::pair<Preset*, bool> PresetCollection::load_external_preset(
{
// Load the preset over a default preset, so that the missing fields are filled in from the default preset.
DynamicPrintConfig cfg(this->default_preset_for(combined_config).config);
const auto &keys = cfg.keys();
t_config_option_keys keys = std::move(cfg.keys());
cfg.apply_only(combined_config, keys, true);
std::string &inherits = Preset::inherits(cfg);
if (select == LoadAndSelect::Never) {
@ -792,6 +792,13 @@ std::pair<Preset*, bool> PresetCollection::load_external_preset(
// the differences will be shown in the preset editor against the referenced profile.
this->select_preset(it - m_presets.begin());
// The source config may contain keys from many possible preset types. Just copy those that relate to this preset.
// Following keys are not used neither by the UI nor by the slicing core, therefore they are not important
// Erase them from config appl to avoid redundant "dirty" parameter in loaded preset.
for (const char* key : { "print_settings_id", "filament_settings_id", "sla_print_settings_id", "sla_material_settings_id", "printer_settings_id",
"printer_model", "printer_variant", "default_print_profile", "default_filament_profile", "default_sla_print_profile", "default_sla_material_profile" })
keys.erase(std::remove(keys.begin(), keys.end(), key), keys.end());
this->get_edited_preset().config.apply_only(combined_config, keys, true);
this->update_dirty();
// Don't save the newly loaded project as a "saved into project" state.
@ -1869,13 +1876,23 @@ bool PhysicalPrinterCollection::delete_preset_from_printers( const std::string&
return true;
}
void PhysicalPrinterCollection::rename_preset_in_printers(const std::string& old_preset_name, const std::string& new_preset_name)
{
for (PhysicalPrinter& printer : m_printers)
if (printer.delete_preset(old_preset_name)) {
printer.add_preset(new_preset_name);
printer.update_preset_names_in_config();
printer.save();
}
}
// Get list of printers which have more than one preset and "preset_names" preset is one of them
std::vector<std::string> PhysicalPrinterCollection::get_printers_with_preset(const std::string& preset_name)
std::vector<std::string> PhysicalPrinterCollection::get_printers_with_preset(const std::string& preset_name, bool respect_only_preset /*= true*/)
{
std::vector<std::string> printers;
for (auto printer : m_printers) {
if (printer.preset_names.size() == 1)
if (!respect_only_preset && printer.preset_names.size() == 1)
continue;
if (printer.preset_names.find(preset_name) != printer.preset_names.end())
printers.emplace_back(printer.name);

View File

@ -734,9 +734,9 @@ public:
// If there is last preset for the printer and first_check== false, then delete this printer
// returns true if all presets were deleted successfully.
bool delete_preset_from_printers(const std::string& preset_name);
void rename_preset_in_printers(const std::string& old_name, const std::string& new_name);
// Get list of printers which have more than one preset and "preset_names" preset is one of them
std::vector<std::string> get_printers_with_preset( const std::string &preset_name);
std::vector<std::string> get_printers_with_preset( const std::string &preset_name, bool respect_only_preset = true);
// Get list of printers which has only "preset_names" preset
std::vector<std::string> get_printers_with_only_preset( const std::string &preset_name);

View File

@ -626,7 +626,8 @@ PrintObjectRegions::BoundingBox find_modifier_volume_extents(const PrintObjectRe
const PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[parent_region_id];
const PrintObjectRegions::BoundingBox *parent_extents = find_volume_extents(layer_range, *parent_region.model_volume);
assert(parent_extents);
out.extend(*parent_extents);
out.clamp(*parent_extents);
assert(! out.isEmpty());
if (parent_region.model_volume->is_model_part())
break;
parent_region_id = parent_region.parent;

View File

@ -137,7 +137,8 @@ CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SupportMaterialPattern)
static const t_config_enum_values s_keys_map_SupportMaterialStyle {
{ "grid", smsGrid },
{ "snug", smsSnug }
{ "snug", smsSnug },
{ "tree", smsTree }
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SupportMaterialStyle)
@ -1050,6 +1051,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("HIPS");
def->enum_values.push_back("EDGE");
def->enum_values.push_back("NGEN");
def->enum_values.push_back("PA");
def->enum_values.push_back("NYLON");
def->enum_values.push_back("PVA");
def->enum_values.push_back("PC");
@ -2776,8 +2778,10 @@ void PrintConfigDef::init_fff_params()
def->enum_keys_map = &ConfigOptionEnum<SupportMaterialStyle>::get_enum_values();
def->enum_values.push_back("grid");
def->enum_values.push_back("snug");
def->enum_values.push_back("tree");
def->enum_labels.push_back(L("Grid"));
def->enum_labels.push_back(L("Snug"));
def->enum_labels.push_back(L("Tree"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<SupportMaterialStyle>(smsGrid));

View File

@ -60,7 +60,7 @@ enum InfillPattern : int {
ipRectilinear, ipMonotonic, ipAlignedRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipAdaptiveCubic, ipSupportCubic, ipSupportBase,
ipLightning,
ipCount,
ipCount,
};
enum class IroningType {
@ -85,7 +85,7 @@ enum SupportMaterialPattern {
};
enum SupportMaterialStyle {
smsGrid, smsSnug,
smsGrid, smsSnug, smsTree,
};
enum SupportMaterialInterfacePattern {

View File

@ -8,6 +8,7 @@
#include "Layer.hpp"
#include "MutablePolygon.hpp"
#include "SupportMaterial.hpp"
#include "TreeSupport.hpp"
#include "Surface.hpp"
#include "Slicing.hpp"
#include "Tesselate.hpp"
@ -28,8 +29,6 @@
#include <tbb/parallel_for.h>
#include <Shiny/Shiny.h>
using namespace std::literals;
//! macro used to mark string used at localization,
@ -689,12 +688,21 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "bottom_fill_pattern"
|| opt_key == "external_fill_link_max_length"
|| opt_key == "fill_angle"
|| opt_key == "fill_pattern"
|| opt_key == "infill_anchor"
|| opt_key == "infill_anchor_max"
|| opt_key == "top_infill_extrusion_width"
|| opt_key == "first_layer_extrusion_width") {
steps.emplace_back(posInfill);
} else if (opt_key == "fill_pattern") {
steps.emplace_back(posInfill);
const auto *old_fill_pattern = old_config.option<ConfigOptionEnum<InfillPattern>>(opt_key);
const auto *new_fill_pattern = new_config.option<ConfigOptionEnum<InfillPattern>>(opt_key);
assert(old_fill_pattern && new_fill_pattern);
// We need to recalculate infill surfaces when infill_only_where_needed is enabled, and we are switching from
// the Lightning infill to another infill or vice versa.
if (m_config.infill_only_where_needed && (new_fill_pattern->value == ipLightning || old_fill_pattern->value == ipLightning))
steps.emplace_back(posPrepareInfill);
} else if (opt_key == "fill_density") {
// One likely wants to reslice only when switching between zero infill to simulate boolean difference (subtracting volumes),
// normal infill and 100% (solid) infill.
@ -1098,8 +1106,6 @@ void PrintObject::process_external_surfaces()
void PrintObject::discover_vertical_shells()
{
PROFILE_FUNC();
BOOST_LOG_TRIVIAL(info) << "Discovering vertical shells..." << log_memory_info();
struct DiscoverVerticalShellsCacheEntry
@ -1210,8 +1216,6 @@ void PrintObject::discover_vertical_shells()
}
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
PROFILE_BLOCK(discover_vertical_shells_region);
const PrintRegion &region = this->printing_region(region_id);
if (! region.config().ensure_vertical_shell_thickness.value)
// This region will be handled by discover_horizontal_shells().
@ -1261,7 +1265,6 @@ void PrintObject::discover_vertical_shells()
(const tbb::blocked_range<size_t>& range) {
// printf("discover_vertical_shells from %d to %d\n", range.begin(), range.end());
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
PROFILE_BLOCK(discover_vertical_shells_region_layer);
m_print->throw_if_canceled();
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
static size_t debug_idx = 0;
@ -1286,88 +1289,82 @@ void PrintObject::discover_vertical_shells()
ExPolygons shell_ex;
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
float min_perimeter_infill_spacing = float(infill_line_spacing) * 1.05f;
{
PROFILE_BLOCK(discover_vertical_shells_region_layer_collect);
#if 0
// #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
{
Slic3r::SVG svg_cummulative(debug_out_path("discover_vertical_shells-perimeters-before-union-run%d.svg", debug_idx), this->bounding_box());
for (int n = (int)idx_layer - n_extra_bottom_layers; n <= (int)idx_layer + n_extra_top_layers; ++ n) {
if (n < 0 || n >= (int)m_layers.size())
continue;
ExPolygons &expolys = m_layers[n]->perimeter_expolygons;
for (size_t i = 0; i < expolys.size(); ++ i) {
Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-run%d-layer%d-expoly%d.svg", debug_idx, n, i), get_extents(expolys[i]));
svg.draw(expolys[i]);
svg.draw_outline(expolys[i].contour, "black", scale_(0.05));
svg.draw_outline(expolys[i].holes, "blue", scale_(0.05));
svg.Close();
{
Slic3r::SVG svg_cummulative(debug_out_path("discover_vertical_shells-perimeters-before-union-run%d.svg", debug_idx), this->bounding_box());
for (int n = (int)idx_layer - n_extra_bottom_layers; n <= (int)idx_layer + n_extra_top_layers; ++ n) {
if (n < 0 || n >= (int)m_layers.size())
continue;
ExPolygons &expolys = m_layers[n]->perimeter_expolygons;
for (size_t i = 0; i < expolys.size(); ++ i) {
Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-run%d-layer%d-expoly%d.svg", debug_idx, n, i), get_extents(expolys[i]));
svg.draw(expolys[i]);
svg.draw_outline(expolys[i].contour, "black", scale_(0.05));
svg.draw_outline(expolys[i].holes, "blue", scale_(0.05));
svg.Close();
svg_cummulative.draw(expolys[i]);
svg_cummulative.draw_outline(expolys[i].contour, "black", scale_(0.05));
svg_cummulative.draw_outline(expolys[i].holes, "blue", scale_(0.05));
}
svg_cummulative.draw(expolys[i]);
svg_cummulative.draw_outline(expolys[i].contour, "black", scale_(0.05));
svg_cummulative.draw_outline(expolys[i].holes, "blue", scale_(0.05));
}
}
}
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
polygons_append(holes, cache_top_botom_regions[idx_layer].holes);
if (int n_top_layers = region_config.top_solid_layers.value; n_top_layers > 0) {
// Gather top regions projected to this layer.
coordf_t print_z = layer->print_z;
for (int i = int(idx_layer) + 1;
i < int(cache_top_botom_regions.size()) &&
(i < int(idx_layer) + n_top_layers ||
m_layers[i]->print_z - print_z < region_config.top_solid_min_thickness - EPSILON);
++ i) {
const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[i];
if (! holes.empty())
holes = intersection(holes, cache.holes);
if (! cache.top_surfaces.empty()) {
polygons_append(shell, cache.top_surfaces);
// Running the union_ using the Clipper library piece by piece is cheaper
// than running the union_ all at once.
shell = union_(shell);
}
polygons_append(holes, cache_top_botom_regions[idx_layer].holes);
if (int n_top_layers = region_config.top_solid_layers.value; n_top_layers > 0) {
// Gather top regions projected to this layer.
coordf_t print_z = layer->print_z;
for (int i = int(idx_layer) + 1;
i < int(cache_top_botom_regions.size()) &&
(i < int(idx_layer) + n_top_layers ||
m_layers[i]->print_z - print_z < region_config.top_solid_min_thickness - EPSILON);
++ i) {
const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[i];
if (! holes.empty())
holes = intersection(holes, cache.holes);
if (! cache.top_surfaces.empty()) {
polygons_append(shell, cache.top_surfaces);
// Running the union_ using the Clipper library piece by piece is cheaper
// than running the union_ all at once.
shell = union_(shell);
}
}
if (int n_bottom_layers = region_config.bottom_solid_layers.value; n_bottom_layers > 0) {
// Gather bottom regions projected to this layer.
coordf_t bottom_z = layer->bottom_z();
for (int i = int(idx_layer) - 1;
i >= 0 &&
(i > int(idx_layer) - n_bottom_layers ||
bottom_z - m_layers[i]->bottom_z() < region_config.bottom_solid_min_thickness - EPSILON);
-- i) {
const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[i];
if (! holes.empty())
holes = intersection(holes, cache.holes);
if (! cache.bottom_surfaces.empty()) {
polygons_append(shell, cache.bottom_surfaces);
// Running the union_ using the Clipper library piece by piece is cheaper
// than running the union_ all at once.
shell = union_(shell);
}
}
}
if (int n_bottom_layers = region_config.bottom_solid_layers.value; n_bottom_layers > 0) {
// Gather bottom regions projected to this layer.
coordf_t bottom_z = layer->bottom_z();
for (int i = int(idx_layer) - 1;
i >= 0 &&
(i > int(idx_layer) - n_bottom_layers ||
bottom_z - m_layers[i]->bottom_z() < region_config.bottom_solid_min_thickness - EPSILON);
-- i) {
const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[i];
if (! holes.empty())
holes = intersection(holes, cache.holes);
if (! cache.bottom_surfaces.empty()) {
polygons_append(shell, cache.bottom_surfaces);
// Running the union_ using the Clipper library piece by piece is cheaper
// than running the union_ all at once.
shell = union_(shell);
}
}
}
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
{
Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-%d.svg", debug_idx), get_extents(shell));
svg.draw(shell);
svg.draw_outline(shell, "black", scale_(0.05));
svg.Close();
}
{
Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-%d.svg", debug_idx), get_extents(shell));
svg.draw(shell);
svg.draw_outline(shell, "black", scale_(0.05));
svg.Close();
}
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
#if 0
{
PROFILE_BLOCK(discover_vertical_shells_region_layer_shell_);
// shell = union_(shell, true);
shell = union_(shell, false);
}
// shell = union_(shell, true);
shell = union_(shell, false);
#endif
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
shell_ex = union_safety_offset_ex(shell);
shell_ex = union_safety_offset_ex(shell);
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
}
//if (shell.empty())
// continue;
@ -1494,62 +1491,66 @@ void PrintObject::discover_vertical_shells()
}
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
} // for each region
// Write the profiler measurements to file
// PROFILE_UPDATE();
// PROFILE_OUTPUT(debug_out_path("discover_vertical_shells-profile.txt").c_str());
}
/* This method applies bridge flow to the first internal solid layer above
sparse infill */
// This method applies bridge flow to the first internal solid layer above sparse infill.
void PrintObject::bridge_over_infill()
{
BOOST_LOG_TRIVIAL(info) << "Bridge over infill..." << log_memory_info();
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
const PrintRegion &region = this->printing_region(region_id);
// skip bridging in case there are no voids
if (region.config().fill_density.value == 100)
continue;
std::vector<int> sparse_infill_regions;
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id)
if (const PrintRegion &region = this->printing_region(region_id); region.config().fill_density.value < 100)
sparse_infill_regions.emplace_back(region_id);
if (this->layer_count() < 2 || sparse_infill_regions.empty())
return;
for (LayerPtrs::iterator layer_it = m_layers.begin(); layer_it != m_layers.end(); ++ layer_it) {
// skip first layer
if (layer_it == m_layers.begin())
continue;
Layer *layer = *layer_it;
// Collect sum of all internal (sparse infill) regions, because
// 1) layerm->fill_surfaces.will be modified in parallel.
// 2) the parallel loop works on a sum of surfaces over regions anyways, thus collecting the sparse infill surfaces
// up front is an optimization.
std::vector<Polygons> internals;
internals.reserve(this->layer_count());
for (Layer *layer : m_layers) {
Polygons sum;
for (const LayerRegion *layerm : layer->m_regions)
layerm->fill_surfaces.filter_by_type(stInternal, &sum);
internals.emplace_back(std::move(sum));
}
// Process all regions and layers in parallel.
tbb::parallel_for(tbb::blocked_range<size_t>(0, sparse_infill_regions.size() * (this->layer_count() - 1), sparse_infill_regions.size()),
[this, &sparse_infill_regions, &internals]
(const tbb::blocked_range<size_t> &range) {
for (size_t task_id = range.begin(); task_id != range.end(); ++ task_id) {
const size_t layer_id = (task_id / sparse_infill_regions.size()) + 1;
const size_t region_id = sparse_infill_regions[task_id % sparse_infill_regions.size()];
Layer *layer = this->get_layer(layer_id);
LayerRegion *layerm = layer->m_regions[region_id];
Flow bridge_flow = layerm->bridging_flow(frSolidInfill);
// extract the stInternalSolid surfaces that might be transformed into bridges
Polygons internal_solid;
layerm->fill_surfaces.filter_by_type(stInternalSolid, &internal_solid);
// Extract the stInternalSolid surfaces that might be transformed into bridges.
ExPolygons internal_solid;
layerm->fill_surfaces.remove_type(stInternalSolid, &internal_solid);
if (internal_solid.empty())
// No internal solid -> no new bridges for this layer region.
continue;
// check whether the lower area is deep enough for absorbing the extra flow
// (for obvious physical reasons but also for preventing the bridge extrudates
// from overflowing in 3D preview)
ExPolygons to_bridge;
{
Polygons to_bridge_pp = internal_solid;
// iterate through lower layers spanned by bridge_flow
Polygons to_bridge_pp = to_polygons(internal_solid);
// Iterate through lower layers spanned by bridge_flow.
double bottom_z = layer->print_z - bridge_flow.height() - EPSILON;
for (int i = int(layer_it - m_layers.begin()) - 1; i >= 0; --i) {
const Layer* lower_layer = m_layers[i];
// stop iterating if layer is lower than bottom_z
if (lower_layer->print_z < bottom_z) break;
// iterate through regions and collect internal surfaces
Polygons lower_internal;
for (LayerRegion *lower_layerm : lower_layer->m_regions)
lower_layerm->fill_surfaces.filter_by_type(stInternal, &lower_internal);
// intersect such lower internal surfaces with the candidate solid surfaces
to_bridge_pp = intersection(to_bridge_pp, lower_internal);
for (auto i = int(layer_id) - 1; i >= 0; -- i) {
// Stop iterating if layer is lower than bottom_z.
if (m_layers[i]->print_z < bottom_z)
break;
// Intersect lower sparse infills with the candidate solid surfaces.
to_bridge_pp = intersection(to_bridge_pp, internals[i]);
}
// there's no point in bridging too thin/short regions
//FIXME Vojtech: The offset2 function is not a geometric offset,
// therefore it may create 1) gaps, and 2) sharp corners, which are outside the original contour.
@ -1559,12 +1560,16 @@ void PrintObject::bridge_over_infill()
to_bridge_pp = opening(to_bridge_pp, min_width);
}
if (to_bridge_pp.empty()) continue;
if (to_bridge_pp.empty()) {
// Restore internal_solid surfaces.
for (ExPolygon &ex : internal_solid)
layerm->fill_surfaces.surfaces.push_back(Surface(stInternalSolid, std::move(ex)));
continue;
}
// convert into ExPolygons
to_bridge = union_ex(to_bridge_pp);
}
#ifdef SLIC3R_DEBUG
printf("Bridging %zu internal areas at layer %zu\n", to_bridge.size(), layer->id());
#endif
@ -1573,11 +1578,10 @@ void PrintObject::bridge_over_infill()
ExPolygons not_to_bridge = diff_ex(internal_solid, to_bridge, ApplySafetyOffset::Yes);
to_bridge = intersection_ex(to_bridge, internal_solid, ApplySafetyOffset::Yes);
// build the new collection of fill_surfaces
layerm->fill_surfaces.remove_type(stInternalSolid);
for (ExPolygon &ex : to_bridge)
layerm->fill_surfaces.surfaces.push_back(Surface(stInternalBridge, ex));
layerm->fill_surfaces.surfaces.push_back(Surface(stInternalBridge, std::move(ex)));
for (ExPolygon &ex : not_to_bridge)
layerm->fill_surfaces.surfaces.push_back(Surface(stInternalSolid, ex));
layerm->fill_surfaces.surfaces.push_back(Surface(stInternalSolid, std::move(ex)));
/*
# exclude infill from the layers below if needed
# see discussion at https://github.com/alexrj/Slic3r/issues/240
@ -1611,14 +1615,13 @@ void PrintObject::bridge_over_infill()
}
}
*/
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
layerm->export_region_slices_to_svg_debug("7_bridge_over_infill");
layerm->export_region_fill_surfaces_to_svg_debug("7_bridge_over_infill");
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
m_print->throw_if_canceled();
}
}
});
}
static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders)
@ -1795,7 +1798,14 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
// fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries.
void PrintObject::clip_fill_surfaces()
{
if (! m_config.infill_only_where_needed.value)
bool has_lightning_infill = false;
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id)
if (const PrintRegionConfig &config = this->printing_region(region_id).config(); config.fill_density > 0 && config.fill_pattern == ipLightning)
has_lightning_infill = true;
// For Lightning infill, infill_only_where_needed is ignored because both
// do a similar thing, and their combination doesn't make much sense.
if (! m_config.infill_only_where_needed.value || has_lightning_infill)
return;
bool has_infill = false;
for (size_t i = 0; i < this->num_printing_regions(); ++ i)
@ -2187,8 +2197,13 @@ void PrintObject::combine_infill()
void PrintObject::_generate_support_material()
{
PrintObjectSupportMaterial support_material(this, m_slicing_params);
support_material.generate(*this);
if (m_config.support_material_style == smsTree) {
TreeSupport tree_support;
tree_support.generateSupportAreas(*this);
} else {
PrintObjectSupportMaterial support_material(this, m_slicing_params);
support_material.generate(*this);
}
}
static void project_triangles_to_slabs(ConstLayerPtrsAdaptor layers, const indexed_triangle_set &custom_facets, const Transform3f &tr, bool seam, std::vector<Polygons> &out)

View File

@ -204,7 +204,7 @@ public:
void add(const ExPolygon &ep)
{
m_polys.emplace_back(ep);
m_index.insert(BoundingBox{ep}, unsigned(m_index.size()));
m_index.insert(get_extents(ep), unsigned(m_index.size()));
}
// Check an arbitrary polygon for intersection with the indexed polygons

View File

@ -88,10 +88,8 @@ void SVG::draw(const ExPolygon &expolygon, std::string fill, const float fill_op
this->fill = fill;
std::string d;
Polygons pp = expolygon;
for (Polygons::const_iterator p = pp.begin(); p != pp.end(); ++p) {
d += this->get_path_d(*p, true) + " ";
}
for (const Polygon &p : to_polygons(expolygon))
d += this->get_path_d(p, true) + " ";
this->path(d, true, 0, fill_opacity);
}
@ -359,7 +357,7 @@ void SVG::export_expolygons(const char *path, const std::vector<std::pair<Slic3r
for (const auto &exp_with_attr : expolygons_with_attributes)
if (exp_with_attr.second.radius_points > 0)
for (const ExPolygon &expoly : exp_with_attr.first)
svg.draw((Points)expoly, exp_with_attr.second.color_points, exp_with_attr.second.radius_points);
svg.draw(to_points(expoly), exp_with_attr.second.color_points, exp_with_attr.second.radius_points);
// Export legend.
// 1st row

File diff suppressed because it is too large Load Diff

View File

@ -11,147 +11,187 @@ class PrintObject;
class PrintConfig;
class PrintObjectConfig;
// Support layer type to be used by SupportGeneratorLayer. This type carries a much more detailed information
// about the support layer type than the final support layers stored in a PrintObject.
enum SupporLayerType {
Unknown = 0,
// Ratft base layer, to be printed with the support material.
RaftBase,
// Raft interface layer, to be printed with the support interface material.
RaftInterface,
// Bottom contact layer placed over a top surface of an object. To be printed with a support interface material.
BottomContact,
// Dense interface layer, to be printed with the support interface material.
// This layer is separated from an object by an BottomContact layer.
BottomInterface,
// Sparse base support layer, to be printed with a support material.
Base,
// Dense interface layer, to be printed with the support interface material.
// This layer is separated from an object with TopContact layer.
TopInterface,
// Top contact layer directly supporting an overhang. To be printed with a support interface material.
TopContact,
// Some undecided type yet. It will turn into Base first, then it may turn into BottomInterface or TopInterface.
Intermediate,
};
// A support layer type used internally by the SupportMaterial class. This class carries a much more detailed
// information about the support layer than the layers stored in the PrintObject, mainly
// the SupportGeneratorLayer is aware of the bridging flow and the interface gaps between the object and the support.
class SupportGeneratorLayer
{
public:
void reset() {
*this = SupportGeneratorLayer();
}
bool operator==(const SupportGeneratorLayer &layer2) const {
return print_z == layer2.print_z && height == layer2.height && bridging == layer2.bridging;
}
// Order the layers by lexicographically by an increasing print_z and a decreasing layer height.
bool operator<(const SupportGeneratorLayer &layer2) const {
if (print_z < layer2.print_z) {
return true;
} else if (print_z == layer2.print_z) {
if (height > layer2.height)
return true;
else if (height == layer2.height) {
// Bridging layers first.
return bridging && ! layer2.bridging;
} else
return false;
} else
return false;
}
void merge(SupportGeneratorLayer &&rhs) {
// The union_() does not support move semantic yet, but maybe one day it will.
this->polygons = union_(this->polygons, std::move(rhs.polygons));
auto merge = [](std::unique_ptr<Polygons> &dst, std::unique_ptr<Polygons> &src) {
if (! dst || dst->empty())
dst = std::move(src);
else if (src && ! src->empty())
*dst = union_(*dst, std::move(*src));
};
merge(this->contact_polygons, rhs.contact_polygons);
merge(this->overhang_polygons, rhs.overhang_polygons);
merge(this->enforcer_polygons, rhs.enforcer_polygons);
rhs.reset();
}
// For the bridging flow, bottom_print_z will be above bottom_z to account for the vertical separation.
// For the non-bridging flow, bottom_print_z will be equal to bottom_z.
coordf_t bottom_print_z() const { return print_z - height; }
// To sort the extremes of top / bottom interface layers.
coordf_t extreme_z() const { return (this->layer_type == SupporLayerType::TopContact) ? this->bottom_z : this->print_z; }
SupporLayerType layer_type { SupporLayerType::Unknown };
// Z used for printing, in unscaled coordinates.
coordf_t print_z { 0 };
// Bottom Z of this layer. For soluble layers, bottom_z + height = print_z,
// otherwise bottom_z + gap + height = print_z.
coordf_t bottom_z { 0 };
// Layer height in unscaled coordinates.
coordf_t height { 0 };
// Index of a PrintObject layer_id supported by this layer. This will be set for top contact layers.
// If this is not a contact layer, it will be set to size_t(-1).
size_t idx_object_layer_above { size_t(-1) };
// Index of a PrintObject layer_id, which supports this layer. This will be set for bottom contact layers.
// If this is not a contact layer, it will be set to size_t(-1).
size_t idx_object_layer_below { size_t(-1) };
// Use a bridging flow when printing this support layer.
bool bridging { false };
// Polygons to be filled by the support pattern.
Polygons polygons;
// Currently for the contact layers only.
std::unique_ptr<Polygons> contact_polygons;
std::unique_ptr<Polygons> overhang_polygons;
// Enforcers need to be propagated independently in case the "support on build plate only" option is enabled.
std::unique_ptr<Polygons> enforcer_polygons;
};
// Layers are allocated and owned by a deque. Once a layer is allocated, it is maintained
// up to the end of a generate() method. The layer storage may be replaced by an allocator class in the future,
// which would allocate layers by multiple chunks.
using SupportGeneratorLayerStorage = std::deque<SupportGeneratorLayer>;
using SupportGeneratorLayersPtr = std::vector<SupportGeneratorLayer*>;
struct SupportParameters {
SupportParameters(const PrintObject &object);
Flow first_layer_flow;
Flow support_material_flow;
Flow support_material_interface_flow;
Flow support_material_bottom_interface_flow;
// Is merging of regions allowed? Could the interface & base support regions be printed with the same extruder?
bool can_merge_support_regions;
coordf_t support_layer_height_min;
// coordf_t support_layer_height_max;
coordf_t gap_xy;
float base_angle;
float interface_angle;
coordf_t interface_spacing;
coordf_t interface_density;
coordf_t support_spacing;
coordf_t support_density;
InfillPattern base_fill_pattern;
InfillPattern interface_fill_pattern;
InfillPattern contact_fill_pattern;
bool with_sheath;
};
// Generate raft layers, also expand the 1st support layer
// in case there is no raft layer to improve support adhesion.
SupportGeneratorLayersPtr generate_raft_base(
const PrintObject &object,
const SupportParameters &support_params,
const SlicingParameters &slicing_params,
const SupportGeneratorLayersPtr &top_contacts,
const SupportGeneratorLayersPtr &interface_layers,
const SupportGeneratorLayersPtr &base_interface_layers,
const SupportGeneratorLayersPtr &base_layers,
SupportGeneratorLayerStorage &layer_storage);
// returns sorted layers
SupportGeneratorLayersPtr generate_support_layers(
PrintObject &object,
const SupportGeneratorLayersPtr &raft_layers,
const SupportGeneratorLayersPtr &bottom_contacts,
const SupportGeneratorLayersPtr &top_contacts,
const SupportGeneratorLayersPtr &intermediate_layers,
const SupportGeneratorLayersPtr &interface_layers,
const SupportGeneratorLayersPtr &base_interface_layers);
// Produce the support G-code.
// Used by both classic and tree supports.
void generate_support_toolpaths(
SupportLayerPtrs &support_layers,
const PrintObjectConfig &config,
const SupportParameters &support_params,
const SlicingParameters &slicing_params,
const SupportGeneratorLayersPtr &raft_layers,
const SupportGeneratorLayersPtr &bottom_contacts,
const SupportGeneratorLayersPtr &top_contacts,
const SupportGeneratorLayersPtr &intermediate_layers,
const SupportGeneratorLayersPtr &interface_layers,
const SupportGeneratorLayersPtr &base_interface_layers);
void export_print_z_polygons_to_svg(const char *path, SupportGeneratorLayer ** const layers, size_t n_layers);
void export_print_z_polygons_and_extrusions_to_svg(const char *path, SupportGeneratorLayer ** const layers, size_t n_layers, SupportLayer& support_layer);
// This class manages raft and supports for a single PrintObject.
// Instantiated by Slic3r::Print::Object->_support_material()
// This class is instantiated before the slicing starts as Object.pm will query
// the parameters of the raft to determine the 1st layer height and thickness.
class PrintObjectSupportMaterial
{
public:
// Support layer type to be used by MyLayer. This type carries a much more detailed information
// about the support layer type than the final support layers stored in a PrintObject.
enum SupporLayerType {
sltUnknown = 0,
// Ratft base layer, to be printed with the support material.
sltRaftBase,
// Raft interface layer, to be printed with the support interface material.
sltRaftInterface,
// Bottom contact layer placed over a top surface of an object. To be printed with a support interface material.
sltBottomContact,
// Dense interface layer, to be printed with the support interface material.
// This layer is separated from an object by an sltBottomContact layer.
sltBottomInterface,
// Sparse base support layer, to be printed with a support material.
sltBase,
// Dense interface layer, to be printed with the support interface material.
// This layer is separated from an object with sltTopContact layer.
sltTopInterface,
// Top contact layer directly supporting an overhang. To be printed with a support interface material.
sltTopContact,
// Some undecided type yet. It will turn into sltBase first, then it may turn into sltBottomInterface or sltTopInterface.
sltIntermediate,
};
// A support layer type used internally by the SupportMaterial class. This class carries a much more detailed
// information about the support layer than the layers stored in the PrintObject, mainly
// the MyLayer is aware of the bridging flow and the interface gaps between the object and the support.
class MyLayer
{
public:
void reset() {
*this = MyLayer();
}
bool operator==(const MyLayer &layer2) const {
return print_z == layer2.print_z && height == layer2.height && bridging == layer2.bridging;
}
// Order the layers by lexicographically by an increasing print_z and a decreasing layer height.
bool operator<(const MyLayer &layer2) const {
if (print_z < layer2.print_z) {
return true;
} else if (print_z == layer2.print_z) {
if (height > layer2.height)
return true;
else if (height == layer2.height) {
// Bridging layers first.
return bridging && ! layer2.bridging;
} else
return false;
} else
return false;
}
void merge(MyLayer &&rhs) {
// The union_() does not support move semantic yet, but maybe one day it will.
this->polygons = union_(this->polygons, std::move(rhs.polygons));
auto merge = [](std::unique_ptr<Polygons> &dst, std::unique_ptr<Polygons> &src) {
if (! dst || dst->empty())
dst = std::move(src);
else if (src && ! src->empty())
*dst = union_(*dst, std::move(*src));
};
merge(this->contact_polygons, rhs.contact_polygons);
merge(this->overhang_polygons, rhs.overhang_polygons);
merge(this->enforcer_polygons, rhs.enforcer_polygons);
rhs.reset();
}
// For the bridging flow, bottom_print_z will be above bottom_z to account for the vertical separation.
// For the non-bridging flow, bottom_print_z will be equal to bottom_z.
coordf_t bottom_print_z() const { return print_z - height; }
// To sort the extremes of top / bottom interface layers.
coordf_t extreme_z() const { return (this->layer_type == sltTopContact) ? this->bottom_z : this->print_z; }
SupporLayerType layer_type { sltUnknown };
// Z used for printing, in unscaled coordinates.
coordf_t print_z { 0 };
// Bottom Z of this layer. For soluble layers, bottom_z + height = print_z,
// otherwise bottom_z + gap + height = print_z.
coordf_t bottom_z { 0 };
// Layer height in unscaled coordinates.
coordf_t height { 0 };
// Index of a PrintObject layer_id supported by this layer. This will be set for top contact layers.
// If this is not a contact layer, it will be set to size_t(-1).
size_t idx_object_layer_above { size_t(-1) };
// Index of a PrintObject layer_id, which supports this layer. This will be set for bottom contact layers.
// If this is not a contact layer, it will be set to size_t(-1).
size_t idx_object_layer_below { size_t(-1) };
// Use a bridging flow when printing this support layer.
bool bridging { false };
// Polygons to be filled by the support pattern.
Polygons polygons;
// Currently for the contact layers only.
std::unique_ptr<Polygons> contact_polygons;
std::unique_ptr<Polygons> overhang_polygons;
// Enforcers need to be propagated independently in case the "support on build plate only" option is enabled.
std::unique_ptr<Polygons> enforcer_polygons;
};
struct SupportParams {
Flow first_layer_flow;
Flow support_material_flow;
Flow support_material_interface_flow;
Flow support_material_bottom_interface_flow;
// Is merging of regions allowed? Could the interface & base support regions be printed with the same extruder?
bool can_merge_support_regions;
coordf_t support_layer_height_min;
// coordf_t support_layer_height_max;
coordf_t gap_xy;
float base_angle;
float interface_angle;
coordf_t interface_spacing;
coordf_t interface_density;
coordf_t support_spacing;
coordf_t support_density;
InfillPattern base_fill_pattern;
InfillPattern interface_fill_pattern;
InfillPattern contact_fill_pattern;
bool with_sheath;
};
// Layers are allocated and owned by a deque. Once a layer is allocated, it is maintained
// up to the end of a generate() method. The layer storage may be replaced by an allocator class in the future,
// which would allocate layers by multiple chunks.
typedef std::deque<MyLayer> MyLayerStorage;
typedef std::vector<MyLayer*> MyLayersPtr;
public:
PrintObjectSupportMaterial(const PrintObject *object, const SlicingParameters &slicing_params);
@ -175,58 +215,48 @@ private:
// Generate top contact layers supporting overhangs.
// For a soluble interface material synchronize the layer heights with the object, otherwise leave the layer height undefined.
// If supports over bed surface only are requested, don't generate contact layers over an object.
MyLayersPtr top_contact_layers(const PrintObject &object, const std::vector<Polygons> &buildplate_covered, MyLayerStorage &layer_storage) const;
SupportGeneratorLayersPtr top_contact_layers(const PrintObject &object, const std::vector<Polygons> &buildplate_covered, SupportGeneratorLayerStorage &layer_storage) const;
// Generate bottom contact layers supporting the top contact layers.
// For a soluble interface material synchronize the layer heights with the object,
// otherwise set the layer height to a bridging flow of a support interface nozzle.
MyLayersPtr bottom_contact_layers_and_layer_support_areas(
const PrintObject &object, const MyLayersPtr &top_contacts, std::vector<Polygons> &buildplate_covered,
MyLayerStorage &layer_storage, std::vector<Polygons> &layer_support_areas) const;
SupportGeneratorLayersPtr bottom_contact_layers_and_layer_support_areas(
const PrintObject &object, const SupportGeneratorLayersPtr &top_contacts, std::vector<Polygons> &buildplate_covered,
SupportGeneratorLayerStorage &layer_storage, std::vector<Polygons> &layer_support_areas) const;
// Trim the top_contacts layers with the bottom_contacts layers if they overlap, so there would not be enough vertical space for both of them.
void trim_top_contacts_by_bottom_contacts(const PrintObject &object, const MyLayersPtr &bottom_contacts, MyLayersPtr &top_contacts) const;
void trim_top_contacts_by_bottom_contacts(const PrintObject &object, const SupportGeneratorLayersPtr &bottom_contacts, SupportGeneratorLayersPtr &top_contacts) const;
// Generate raft layers and the intermediate support layers between the bottom contact and top contact surfaces.
MyLayersPtr raft_and_intermediate_support_layers(
SupportGeneratorLayersPtr raft_and_intermediate_support_layers(
const PrintObject &object,
const MyLayersPtr &bottom_contacts,
const MyLayersPtr &top_contacts,
MyLayerStorage &layer_storage) const;
const SupportGeneratorLayersPtr &bottom_contacts,
const SupportGeneratorLayersPtr &top_contacts,
SupportGeneratorLayerStorage &layer_storage) const;
// Fill in the base layers with polygons.
void generate_base_layers(
const PrintObject &object,
const MyLayersPtr &bottom_contacts,
const MyLayersPtr &top_contacts,
MyLayersPtr &intermediate_layers,
const SupportGeneratorLayersPtr &bottom_contacts,
const SupportGeneratorLayersPtr &top_contacts,
SupportGeneratorLayersPtr &intermediate_layers,
const std::vector<Polygons> &layer_support_areas) const;
// Generate raft layers, also expand the 1st support layer
// in case there is no raft layer to improve support adhesion.
MyLayersPtr generate_raft_base(
const PrintObject &object,
const MyLayersPtr &top_contacts,
const MyLayersPtr &interface_layers,
const MyLayersPtr &base_interface_layers,
const MyLayersPtr &base_layers,
MyLayerStorage &layer_storage) const;
// Turn some of the base layers into base interface layers.
// For soluble interfaces with non-soluble bases, print maximum two first interface layers with the base
// extruder to improve adhesion of the soluble filament to the base.
std::pair<MyLayersPtr, MyLayersPtr> generate_interface_layers(
const MyLayersPtr &bottom_contacts,
const MyLayersPtr &top_contacts,
MyLayersPtr &intermediate_layers,
MyLayerStorage &layer_storage) const;
std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interface_layers(
const SupportGeneratorLayersPtr &bottom_contacts,
const SupportGeneratorLayersPtr &top_contacts,
SupportGeneratorLayersPtr &intermediate_layers,
SupportGeneratorLayerStorage &layer_storage) const;
// Trim support layers by an object to leave a defined gap between
// the support volume and the object.
void trim_support_layers_by_object(
const PrintObject &object,
MyLayersPtr &support_layers,
SupportGeneratorLayersPtr &support_layers,
const coordf_t gap_extra_above,
const coordf_t gap_extra_below,
const coordf_t gap_xy) const;
@ -236,25 +266,14 @@ private:
void clip_with_shape();
*/
// Produce the actual G-code.
void generate_toolpaths(
SupportLayerPtrs &support_layers,
const MyLayersPtr &raft_layers,
const MyLayersPtr &bottom_contacts,
const MyLayersPtr &top_contacts,
const MyLayersPtr &intermediate_layers,
const MyLayersPtr &interface_layers,
const MyLayersPtr &base_interface_layers) const;
// Following objects are not owned by SupportMaterial class.
const PrintObject *m_object;
const PrintConfig *m_print_config;
const PrintObjectConfig *m_object_config;
// Pre-calculated parameters shared between the object slicer and the support generator,
// carrying information on a raft, 1st layer height, 1st object layer height, gap between the raft and object etc.
SlicingParameters m_slicing_params;
// Various precomputed support parameters to be shared with external functions.
SupportParams m_support_params;
SupportParameters m_support_params;
};
} // namespace Slic3r

View File

@ -65,14 +65,11 @@ SurfacesPtr SurfaceCollection::filter_by_types(const SurfaceType *types, int nty
return ss;
}
void SurfaceCollection::filter_by_type(SurfaceType type, Polygons* polygons)
void SurfaceCollection::filter_by_type(SurfaceType type, Polygons *polygons) const
{
for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
if (surface->surface_type == type) {
Polygons pp = surface->expolygon;
polygons->insert(polygons->end(), pp.begin(), pp.end());
}
}
for (const Surface &surface : this->surfaces)
if (surface.surface_type == type)
polygons_append(*polygons, to_polygons(surface.expolygon));
}
void SurfaceCollection::keep_type(const SurfaceType type)
@ -124,6 +121,22 @@ void SurfaceCollection::remove_type(const SurfaceType type)
surfaces.erase(surfaces.begin() + j, surfaces.end());
}
void SurfaceCollection::remove_type(const SurfaceType type, ExPolygons *polygons)
{
size_t j = 0;
for (size_t i = 0; i < surfaces.size(); ++ i) {
if (Surface &surface = surfaces[i]; surface.surface_type == type) {
polygons->emplace_back(std::move(surface.expolygon));
} else {
if (j < i)
std::swap(surfaces[i], surfaces[j]);
++ j;
}
}
if (j < surfaces.size())
surfaces.erase(surfaces.begin() + j, surfaces.end());
}
void SurfaceCollection::remove_types(const SurfaceType *types, int ntypes)
{
size_t j = 0;

View File

@ -32,7 +32,8 @@ public:
void keep_types(const SurfaceType *types, int ntypes);
void remove_type(const SurfaceType type);
void remove_types(const SurfaceType *types, int ntypes);
void filter_by_type(SurfaceType type, Polygons* polygons);
void filter_by_type(SurfaceType type, Polygons *polygons) const;
void remove_type(const SurfaceType type, ExPolygons *polygons);
void set_type(SurfaceType type) {
for (Surface &surface : this->surfaces)
surface.surface_type = type;

View File

@ -47,8 +47,6 @@
#define ENABLE_PREVIEW_LAYER_TIME (1 && ENABLE_2_5_0_ALPHA1)
// Enable showing time estimate for travel moves in legend
#define ENABLE_TRAVEL_TIME (1 && ENABLE_2_5_0_ALPHA1)
// Enable not killing focus in object manipulator fields when hovering over 3D scene
#define ENABLE_OBJECT_MANIPULATOR_FOCUS (0 && ENABLE_2_5_0_ALPHA1)
// Enable removal of wipe tower magic object_id equal to 1000
#define ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL (1 && ENABLE_2_5_0_ALPHA1)
// Enable removal of legacy OpenGL calls

View File

@ -203,7 +203,7 @@ void name_tbb_thread_pool_threads_set_locale()
const size_t nthreads_hw = tbb::this_task_arena::max_concurrency();
size_t nthreads = nthreads_hw;
#ifdef SLIC3R_PROFILE
#if 0
// Shiny profiler is not thread safe, thus disable parallelization.
disable_multi_threading();
nthreads = 1;

View File

@ -0,0 +1,777 @@
// Tree supports by Thomas Rahm, losely based on Tree Supports by CuraEngine.
// Original source of Thomas Rahm's tree supports:
// https://github.com/ThomasRahm/CuraEngine
//
// Original CuraEngine copyright:
// Copyright (c) 2021 Ultimaker B.V.
// CuraEngine is released under the terms of the AGPLv3 or higher.
#include "TreeModelVolumes.hpp"
#include "TreeSupport.hpp"
#include "BuildVolume.hpp"
#include "ClipperUtils.hpp"
#include "Flow.hpp"
#include "Layer.hpp"
#include "Point.hpp"
#include "Print.hpp"
#include "PrintConfig.hpp"
#include "Utils.hpp"
#include <boost/log/trivial.hpp>
#include <tbb/parallel_for.h>
#include <tbb/task_group.h>
namespace Slic3r
{
// or warning
// had to use a define beacuse the macro processing inside macro BOOST_LOG_TRIVIAL()
#define error_level_not_in_cache error
TreeSupportMeshGroupSettings::TreeSupportMeshGroupSettings(const PrintObject &print_object)
{
const PrintConfig &print_config = print_object.print()->config();
const PrintObjectConfig &config = print_object.config();
const SlicingParameters &slicing_params = print_object.slicing_parameters();
// const std::vector<unsigned int> printing_extruders = print_object.object_extruders();
// Support must be enabled and set to Tree style.
assert(config.support_material);
assert(config.support_material_style == smsTree);
// Calculate maximum external perimeter width over all printing regions, taking into account the default layer height.
coordf_t external_perimeter_width = 0.;
for (size_t region_id = 0; region_id < print_object.num_printing_regions(); ++ region_id) {
const PrintRegion &region = print_object.printing_region(region_id);
external_perimeter_width = std::max<coordf_t>(external_perimeter_width, region.flow(print_object, frExternalPerimeter, config.layer_height).width());
}
this->layer_height = scaled<coord_t>(config.layer_height.value);
this->resolution = scaled<coord_t>(print_config.gcode_resolution.value);
this->min_feature_size = scaled<coord_t>(config.min_feature_size.value);
// +1 makes the threshold inclusive
this->support_angle = 0.5 * M_PI - std::clamp<double>((config.support_material_threshold + 1) * M_PI / 180., 0., 0.5 * M_PI);
this->support_line_width = support_material_flow(&print_object, config.layer_height).scaled_width();
this->support_roof_line_width = support_material_interface_flow(&print_object, config.layer_height).scaled_width();
//FIXME add it to SlicingParameters and reuse in both tree and normal supports?
this->support_bottom_enable = config.support_material_interface_layers.value > 0 && config.support_material_bottom_interface_layers.value != 0;
this->support_bottom_height = this->support_bottom_enable ?
(config.support_material_bottom_interface_layers.value > 0 ?
config.support_material_bottom_interface_layers.value :
config.support_material_interface_layers.value) * this->layer_height :
0;
this->support_material_buildplate_only = config.support_material_buildplate_only;
this->support_xy_distance = scaled<coord_t>(config.support_material_xy_spacing.get_abs_value(external_perimeter_width));
// Separation of interfaces, it is likely smaller than support_xy_distance.
this->support_xy_distance_overhang = std::min(this->support_xy_distance, scaled<coord_t>(0.5 * external_perimeter_width));
this->support_top_distance = scaled<coord_t>(slicing_params.gap_support_object);
this->support_bottom_distance = scaled<coord_t>(slicing_params.gap_object_support);
// this->support_interface_skip_height =
// this->support_infill_angles =
this->support_roof_enable = config.support_material_interface_layers.value > 0;
this->support_roof_height = config.support_material_interface_layers.value * this->layer_height;
// this->minimum_roof_area =
// this->support_roof_angles =
this->support_roof_pattern = config.support_material_interface_pattern;
this->support_pattern = config.support_material_pattern;
this->support_line_spacing = scaled<coord_t>(config.support_material_spacing.value);
// this->support_bottom_offset =
// this->support_wall_count = config.support_material_with_sheath ? 1 : 0;
this->support_wall_count = 1;
this->support_roof_line_distance = scaled<coord_t>(config.support_material_interface_spacing.value) + this->support_roof_line_width;
// this->minimum_support_area =
// this->minimum_bottom_area =
// this->support_offset =
}
//FIXME Machine border is currently ignored.
static Polygons calculateMachineBorderCollision(Polygon machine_border)
{
// Put a border of 1m around the print volume so that we don't collide.
#if 1
//FIXME just returning no border will let tree support legs collide with print bed boundary
return {};
#else
//FIXME offsetting by 1000mm easily overflows int32_tr coordinate.
Polygons out = offset(machine_border, scaled<float>(1000.), jtMiter, 1.2);
machine_border.reverse(); // Makes the polygon negative so that we subtract the actual volume from the collision area.
out.emplace_back(std::move(machine_border));
return out;
#endif
}
TreeModelVolumes::TreeModelVolumes(
const PrintObject &print_object,
const BuildVolume &build_volume,
const coord_t max_move, const coord_t max_move_slow, size_t current_mesh_idx,
double progress_multiplier, double progress_offset, const std::vector<Polygons>& additional_excluded_areas) :
// -2 to avoid rounding errors
m_max_move{ std::max<coord_t>(max_move - 2, 0) }, m_max_move_slow{ std::max<coord_t>(max_move_slow - 2, 0) },
#ifdef SLIC3R_TREESUPPORTS_PROGRESS
m_progress_multiplier{ progress_multiplier }, m_progress_offset{ progress_offset },
#endif // SLIC3R_TREESUPPORTS_PROGRESS
m_machine_border{ calculateMachineBorderCollision(build_volume.polygon()) }
{
#if 0
std::unordered_map<size_t, size_t> mesh_to_layeroutline_idx;
for (size_t mesh_idx = 0; mesh_idx < storage.meshes.size(); ++ mesh_idx) {
SliceMeshStorage mesh = storage.meshes[mesh_idx];
bool added = false;
for (size_t idx = 0; idx < m_layer_outlines.size(); ++ idx)
if (TreeSupport::TreeSupportSettings(m_layer_outlines[idx].first) == TreeSupport::TreeSupportSettings(mesh.settings)) {
added = true;
mesh_to_layeroutline_idx[mesh_idx] = idx;
}
if (! added) {
mesh_to_layeroutline_idx[mesh_idx] = m_layer_outlines.size();
m_layer_outlines.emplace_back(mesh.settings, std::vector<Polygons>(storage.support.supportLayers.size(), Polygons()));
}
}
for (size_t idx = 0; idx < m_layer_outlines.size(); ++ idx) {
tbb::parallel_for(tbb::blocked_range<size_t>(0, m_layer_outlines[idx].second.size()),
[&](const tbb::blocked_range<size_t> &range) {
for (const size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx)
m_layer_outlines[idx].second[layer_idx] = union_(m_layer_outlines[idx].second[layer_idx]);
});
}
m_current_outline_idx = mesh_to_layeroutline_idx[current_mesh_idx];
#else
{
m_anti_overhang = print_object.slice_support_blockers();
TreeSupportMeshGroupSettings mesh_settings(print_object);
m_layer_outlines.emplace_back(mesh_settings, std::vector<Polygons>{});
m_current_outline_idx = 0;
std::vector<Polygons> &outlines = m_layer_outlines.front().second;
outlines.assign(print_object.layer_count(), Polygons{});
tbb::parallel_for(tbb::blocked_range<size_t>(0, print_object.layer_count(), std::min<size_t>(1, std::max<size_t>(16, print_object.layer_count() / (8 * tbb::this_task_arena::max_concurrency())))),
[&](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx)
outlines[layer_idx] = to_polygons(expolygons_simplify(print_object.get_layer(layer_idx)->lslices, mesh_settings.resolution));
});
}
#endif
m_support_rests_on_model = false;
m_min_resolution = std::numeric_limits<coord_t>::max();
for (auto data_pair : m_layer_outlines) {
m_support_rests_on_model |= ! data_pair.first.support_material_buildplate_only;
m_min_resolution = std::min(m_min_resolution, data_pair.first.resolution);
}
const TreeSupport::TreeSupportSettings config{ m_layer_outlines[m_current_outline_idx].first };
m_current_min_xy_dist = config.xy_min_distance;
m_current_min_xy_dist_delta = config.xy_distance - m_current_min_xy_dist;
assert(m_current_min_xy_dist_delta >= 0);
m_increase_until_radius = config.increase_radius_until_radius;
m_radius_0 = config.getRadius(0);
#if 0
for (size_t mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++) {
SliceMeshStorage mesh = storage.meshes[mesh_idx];
tbb::parallel_for(tbb::blocked_range<size_t>(0, m_layer_outlines[mesh_to_layeroutline_idx[mesh_idx]].second.size()),
[&](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx)
if (layer_idx < mesh.layer_nr_max_filled_layer) {
Polygons outline = extractOutlineFromMesh(mesh, layer_idx);
append(m_layer_outlines[mesh_to_layeroutline_idx[mesh_idx]].second[layer_idx], outline);
}
});
}
if (! additional_excluded_areas.empty()) {
tbb::parallel_for(tbb::blocked_range<size_t>(0, m_anti_overhang.size()),
[&](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
if (layer_idx < coord_t(additional_excluded_areas.size()))
append(m_anti_overhang[layer_idx], additional_excluded_areas[layer_idx]);
// if (SUPPORT_TREE_AVOID_SUPPORT_BLOCKER)
// append(m_anti_overhang[layer_idx], storage.support.supportLayers[layer_idx].anti_overhang);
//FIXME block wipe tower
// if (storage.primeTower.enabled)
// append(m_anti_overhang[layer_idx], layer_idx == 0 ? storage.primeTower.outer_poly_first_layer : storage.primeTower.outer_poly);
m_anti_overhang[layer_idx] = union_(m_anti_overhang[layer_idx]);
}
});
}
#endif
}
void TreeModelVolumes::precalculate(const coord_t max_layer)
{
auto t_start = std::chrono::high_resolution_clock::now();
m_precalculated = true;
// Get the config corresponding to one mesh that is in the current group. Which one has to be irrelevant.
// Not the prettiest way to do this, but it ensures some calculations that may be a bit more complex
// like inital layer diameter are only done in once.
TreeSupport::TreeSupportSettings config(m_layer_outlines[m_current_outline_idx].first);
{
// calculate which radius each layer in the tip may have.
std::vector<coord_t> possible_tip_radiis;
for (size_t distance_to_top = 0; distance_to_top <= config.tip_layers; ++ distance_to_top) {
possible_tip_radiis.emplace_back(ceilRadius(config.getRadius(distance_to_top)));
possible_tip_radiis.emplace_back(ceilRadius(config.getRadius(distance_to_top) + m_current_min_xy_dist_delta));
}
sort_remove_duplicates(possible_tip_radiis);
// It theoretically may happen in the tip, that the radius can change so much in-between 2 layers,
// that a ceil step is skipped (as in there is a radius r so that ceilRadius(radius(dtt))<ceilRadius(r)<ceilRadius(radius(dtt+1))).
// As such a radius will not reasonable happen in the tree and it will most likely not be requested,
// there is no need to calculate them. So just skip these.
for (coord_t radius_eval = m_radius_0; radius_eval <= config.branch_radius; radius_eval = ceilRadius(radius_eval + 1))
if (! std::binary_search(possible_tip_radiis.begin(), possible_tip_radiis.end(), radius_eval))
m_ignorable_radii.emplace_back(radius_eval);
}
// it may seem that the required avoidance can be of a smaller radius when going to model (no initial layer diameter for to model branches)
// but as for every branch going towards the bp, the to model avoidance is required to check for possible merges with to model branches, this assumption is in-fact wrong.
std::unordered_map<coord_t, LayerIndex> radius_until_layer;
// while it is possible to calculate, up to which layer the avoidance should be calculated, this simulation is easier to understand, and does not need to be adjusted if something of the radius calculation is changed.
// Overhead with an assumed worst case of 6600 layers was about 2ms
for (LayerIndex distance_to_top = 0; distance_to_top <= max_layer; ++ distance_to_top) {
const LayerIndex current_layer = max_layer - distance_to_top;
auto update_radius_until_layer = [&radius_until_layer, current_layer](coord_t r) {
auto it = radius_until_layer.find(r);
if (it == radius_until_layer.end())
radius_until_layer.emplace_hint(it, r, current_layer);
};
// regular radius
update_radius_until_layer(ceilRadius(config.getRadius(distance_to_top, 0) + m_current_min_xy_dist_delta));
// the maximum radius that the radius with the min_xy_dist can achieve
update_radius_until_layer(ceilRadius(config.getRadius(distance_to_top, 0)));
update_radius_until_layer(ceilRadius(config.recommendedMinRadius(current_layer) + m_current_min_xy_dist_delta));
}
// Copy to deque to use in parallel for later.
std::vector<RadiusLayerPair> relevant_avoidance_radiis{ radius_until_layer.begin(), radius_until_layer.end() };
// Append additional radiis needed for collision.
// To calculate collision holefree for every radius, the collision of radius m_increase_until_radius will be required.
radius_until_layer[ceilRadius(m_increase_until_radius + m_current_min_xy_dist_delta)] = max_layer;
// Collision for radius 0 needs to be calculated everywhere, as it will be used to ensure valid xy_distance in drawAreas.
radius_until_layer[0] = max_layer;
if (m_current_min_xy_dist_delta != 0)
radius_until_layer[m_current_min_xy_dist_delta] = max_layer;
// Now that required_avoidance_limit contains the maximum of ild and regular required radius just copy.
std::vector<RadiusLayerPair> relevant_collision_radiis{ radius_until_layer.begin(), radius_until_layer.end() };
// Calculate the relevant collisions
calculateCollision(relevant_collision_radiis);
// calculate a separate Collisions with all holes removed. These are relevant for some avoidances that try to avoid holes (called safe)
std::vector<RadiusLayerPair> relevant_hole_collision_radiis;
for (RadiusLayerPair key : relevant_avoidance_radiis)
if (key.first < m_increase_until_radius + m_current_min_xy_dist_delta)
relevant_hole_collision_radiis.emplace_back(key);
// Calculate collisions without holes, built from regular collision
calculateCollisionHolefree(relevant_hole_collision_radiis);
// Let placables be calculated from calculateAvoidance() for better parallelization.
if (m_support_rests_on_model)
calculatePlaceables(relevant_avoidance_radiis);
auto t_coll = std::chrono::high_resolution_clock::now();
// Calculate the relevant avoidances in parallel as far as possible
{
tbb::task_group task_group;
task_group.run([this, relevant_avoidance_radiis]{ calculateAvoidance(relevant_avoidance_radiis, true, m_support_rests_on_model); });
task_group.run([this, relevant_avoidance_radiis]{ calculateWallRestrictions(relevant_avoidance_radiis); });
task_group.wait();
}
auto t_end = std::chrono::high_resolution_clock::now();
auto dur_col = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_coll - t_start).count();
auto dur_avo = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_end - t_coll).count();
// m_precalculated = true;
BOOST_LOG_TRIVIAL(info) << "Precalculating collision took" << dur_col << " ms. Precalculating avoidance took " << dur_avo << " ms.";
}
const Polygons& TreeModelVolumes::getCollision(const coord_t orig_radius, LayerIndex layer_idx, bool min_xy_dist) const
{
const coord_t radius = this->ceilRadius(orig_radius, min_xy_dist);
if (std::optional<std::reference_wrapper<const Polygons>> result = m_collision_cache.getArea({ radius, layer_idx }); result)
return (*result).get();
if (m_precalculated) {
BOOST_LOG_TRIVIAL(error_level_not_in_cache) << "Had to calculate collision at radius " << radius << " and layer " << layer_idx << ", but precalculate was called. Performance may suffer!";
TreeSupport::showError("Not precalculated Collision requested.", false);
}
const_cast<TreeModelVolumes*>(this)->calculateCollision(radius, layer_idx);
return getCollision(orig_radius, layer_idx, min_xy_dist);
}
// Private. Only called internally by calculateAvoidance() and calculateAvoidanceToModel(), radius is already snapped to grid.
const Polygons& TreeModelVolumes::getCollisionHolefree(coord_t radius, LayerIndex layer_idx) const
{
assert(radius == this->ceilRadius(radius));
assert(radius < m_increase_until_radius + m_current_min_xy_dist_delta);
if (std::optional<std::reference_wrapper<const Polygons>> result = m_collision_cache_holefree.getArea({ radius, layer_idx }); result)
return (*result).get();
if (m_precalculated) {
BOOST_LOG_TRIVIAL(error_level_not_in_cache) << "Had to calculate collision holefree at radius " << radius << " and layer " << layer_idx << ", but precalculate was called. Performance may suffer!";
TreeSupport::showError("Not precalculated Holefree Collision requested.", false);
}
const_cast<TreeModelVolumes*>(this)->calculateCollisionHolefree({ radius, layer_idx });
return getCollisionHolefree(radius, layer_idx);
}
const Polygons& TreeModelVolumes::getAvoidance(const coord_t orig_radius, LayerIndex layer_idx, AvoidanceType type, bool to_model, bool min_xy_dist) const
{
if (layer_idx == 0) // What on the layer directly above buildplate do i have to avoid to reach the buildplate ...
return getCollision(orig_radius, layer_idx, min_xy_dist);
const coord_t radius = this->ceilRadius(orig_radius, min_xy_dist);
if (type == AvoidanceType::FastSafe && radius >= m_increase_until_radius + m_current_min_xy_dist_delta)
// no holes anymore by definition at this request
type = AvoidanceType::Fast;
if (std::optional<std::reference_wrapper<const Polygons>> result =
this->avoidance_cache(type, to_model).getArea({ radius, layer_idx });
result)
return (*result).get();
if (m_precalculated) {
if (to_model) {
BOOST_LOG_TRIVIAL(error_level_not_in_cache) << "Had to calculate Avoidance to model at radius " << radius << " and layer " << layer_idx << ", but precalculate was called. Performance may suffer!";
TreeSupport::showError("Not precalculated Avoidance(to model) requested.", false);
} else {
BOOST_LOG_TRIVIAL(error_level_not_in_cache) << "Had to calculate Avoidance at radius " << radius << " and layer " << layer_idx << ", but precalculate was called. Performance may suffer!";
TreeSupport::showError("Not precalculated Avoidance(to buildplate) requested.", false);
}
}
const_cast<TreeModelVolumes*>(this)->calculateAvoidance({ radius, layer_idx }, ! to_model, to_model);
// Retrive failed and correct result was calculated. Now it has to be retrived.
return getAvoidance(orig_radius, layer_idx, type, to_model, min_xy_dist);
}
const Polygons& TreeModelVolumes::getPlaceableAreas(const coord_t orig_radius, LayerIndex layer_idx) const
{
if (orig_radius == 0)
return this->getCollision(0, layer_idx, true);
const coord_t radius = ceilRadius(orig_radius);
if (std::optional<std::reference_wrapper<const Polygons>> result = m_placeable_areas_cache.getArea({ radius, layer_idx }); result)
return (*result).get();
if (m_precalculated) {
BOOST_LOG_TRIVIAL(error_level_not_in_cache) << "Had to calculate Placeable Areas at radius " << radius << " and layer " << layer_idx << ", but precalculate was called. Performance may suffer!";
TreeSupport::showError("Not precalculated Placeable areas requested.", false);
}
const_cast<TreeModelVolumes*>(this)->calculatePlaceables(radius, layer_idx);
return getPlaceableAreas(orig_radius, layer_idx);
}
const Polygons& TreeModelVolumes::getWallRestriction(const coord_t orig_radius, LayerIndex layer_idx, bool min_xy_dist) const
{
assert(layer_idx > 0);
if (layer_idx == 0)
// Should never be requested as there will be no going below layer 0 ...,
// but just to be sure some semi-sane catch. Alternative would be empty Polygon.
return getCollision(orig_radius, layer_idx, min_xy_dist);
min_xy_dist &= m_current_min_xy_dist_delta > 0;
const coord_t radius = ceilRadius(orig_radius);
if (std::optional<std::reference_wrapper<const Polygons>> result =
(min_xy_dist ? m_wall_restrictions_cache_min : m_wall_restrictions_cache).getArea({ radius, layer_idx });
result)
return (*result).get();
if (m_precalculated) {
BOOST_LOG_TRIVIAL(error_level_not_in_cache) << "Had to calculate Wall restricions at radius " << radius << " and layer " << layer_idx << ", but precalculate was called. Performance may suffer!";
TreeSupport::showError(
min_xy_dist ?
"Not precalculated Wall restriction of minimum xy distance requested )." :
"Not precalculated Wall restriction requested )."
, false);
}
const_cast<TreeModelVolumes*>(this)->calculateWallRestrictions({ radius, layer_idx });
return getWallRestriction(orig_radius, layer_idx, min_xy_dist); // Retrieve failed and correct result was calculated. Now it has to be retrieved.
}
void TreeModelVolumes::calculateCollision(const std::vector<RadiusLayerPair> &keys)
{
tbb::parallel_for(tbb::blocked_range<size_t>(0, keys.size()),
[&](const tbb::blocked_range<size_t> &range) {
for (size_t ikey = range.begin(); ikey != range.end(); ++ ikey) {
const LayerIndex radius = keys[ikey].first;
const size_t max_layer_idx = keys[ikey].second;
// recursive call to parallel_for.
calculateCollision(radius, max_layer_idx);
}
});
}
void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex max_layer_idx)
{
// assert(radius == this->ceilRadius(radius));
// Process the outlines from least layers to most layers so that the final union will run over the longest vector.
std::vector<size_t> layer_outline_indices(m_layer_outlines.size(), 0);
std::iota(layer_outline_indices.begin(), layer_outline_indices.end(), 0);
std::sort(layer_outline_indices.begin(), layer_outline_indices.end(),
[this](size_t i, size_t j) { return m_layer_outlines[i].second.size() < m_layer_outlines[j].second.size(); });
const LayerIndex min_layer_last = m_collision_cache.getMaxCalculatedLayer(radius);
std::vector<Polygons> data(max_layer_idx + 1 - min_layer_last, Polygons{});
const bool calculate_placable = m_support_rests_on_model && radius == 0;
std::vector<Polygons> data_placeable;
if (calculate_placable)
data_placeable = std::vector<Polygons>(max_layer_idx + 1 - min_layer_last, Polygons{});
for (size_t outline_idx : layer_outline_indices)
if (const std::vector<Polygons> &outlines = m_layer_outlines[outline_idx].second; ! outlines.empty()) {
const TreeSupportMeshGroupSettings &settings = m_layer_outlines[outline_idx].first;
const coord_t layer_height = settings.layer_height;
const coord_t z_distance_bottom = settings.support_bottom_distance;
const int z_distance_bottom_layers = round_up_divide<int>(z_distance_bottom, layer_height);
const int z_distance_top_layers = round_up_divide<int>(settings.support_top_distance, layer_height);
const LayerIndex max_required_layer = std::min<LayerIndex>(outlines.size(), max_layer_idx + std::max(coord_t(1), z_distance_top_layers));
const LayerIndex min_layer_bottom = std::max<LayerIndex>(0, min_layer_last - int(z_distance_bottom_layers));
const coord_t xy_distance = outline_idx == m_current_outline_idx ? m_current_min_xy_dist :
// technically this causes collision for the normal xy_distance to be larger by m_current_min_xy_dist_delta for all
// not currently processing meshes as this delta will be added at request time.
// avoiding this would require saving each collision for each outline_idx separately.
// and later for each avoidance... But avoidance calculation has to be for the whole scene and can NOT be done for each outline_idx separately and combined later.
// so avoiding this inaccuracy seems infeasible as it would require 2x the avoidance calculations => 0.5x the performance.
//FIXME support_xy_distance is not corrected for "soluble" flag, see TreeSupportSettings constructor.
settings.support_xy_distance;
// 1) Calculate offsets of collision areas in parallel.
std::vector<Polygons> collision_areas_offsetted(max_required_layer + 1 - min_layer_bottom);
tbb::parallel_for(tbb::blocked_range<LayerIndex>(min_layer_bottom, max_required_layer + 1),
[&outlines, &machine_border = m_machine_border, offset_value = radius + xy_distance, min_layer_bottom, &collision_areas_offsetted]
(const tbb::blocked_range<LayerIndex> &range) {
for (LayerIndex layer_idx = range.begin(); layer_idx != range.end(); ++ layer_idx) {
Polygons collision_areas = machine_border;
append(collision_areas, outlines[layer_idx]);
// jtRound is not needed here, as the overshoot can not cause errors in the algorithm, because no assumptions are made about the model.
// if a key does not exist when it is accessed it is added!
collision_areas_offsetted[layer_idx - min_layer_bottom] = offset_value == 0 ? union_(collision_areas) : offset(union_ex(collision_areas), offset_value, ClipperLib::jtMiter, 1.2);
}
});
// 2) Sum over top / bottom ranges.
const bool last = outline_idx == layer_outline_indices.size();
tbb::parallel_for(tbb::blocked_range<LayerIndex>(min_layer_last + 1, max_layer_idx + 1),
[&collision_areas_offsetted, &anti_overhang = m_anti_overhang, min_layer_bottom, radius, z_distance_bottom_layers, z_distance_top_layers, min_resolution = m_min_resolution, &data, min_layer_last, last]
(const tbb::blocked_range<LayerIndex>& range) {
for (LayerIndex layer_idx = range.begin(); layer_idx != range.end(); ++layer_idx) {
Polygons collisions;
for (int i = -z_distance_bottom_layers; i <= z_distance_top_layers; ++ i) {
int j = layer_idx + i - min_layer_bottom;
if (j >= 0 && j < int(collision_areas_offsetted.size()))
append(collisions, collision_areas_offsetted[j]);
}
collisions = last && layer_idx < int(anti_overhang.size()) ? union_(collisions, offset(union_ex(anti_overhang[layer_idx]), radius, ClipperLib::jtMiter, 1.2)) : union_(collisions);
auto &dst = data[layer_idx - (min_layer_last + 1)];
if (last) {
if (! dst.empty())
collisions = union_(collisions, dst);
dst = polygons_simplify(collisions, min_resolution);
} else
append(dst, collisions);
}
});
// 3) Optionally calculate placables.
if (calculate_placable) {
// Calculating both the collision areas and placable areas.
tbb::parallel_for(tbb::blocked_range<LayerIndex>(std::max(min_layer_last + 1, z_distance_bottom_layers + 1), max_layer_idx + 1),
[&collision_areas_offsetted, &anti_overhang = m_anti_overhang, min_layer_bottom, z_distance_bottom_layers, last, min_resolution = m_min_resolution, &data_placeable, min_layer_last]
(const tbb::blocked_range<LayerIndex>& range) {
for (LayerIndex layer_idx = range.begin(); layer_idx != range.end(); ++ layer_idx) {
LayerIndex layer_idx_below = layer_idx - (z_distance_bottom_layers + 1) - min_layer_bottom;
assert(layer_idx_below >= 0);
auto &current = collision_areas_offsetted[layer_idx - min_layer_bottom];
auto &below = collision_areas_offsetted[layer_idx_below];
auto placable = diff(below, layer_idx < int(anti_overhang.size()) ? union_(current, anti_overhang[layer_idx - (z_distance_bottom_layers + 1)]) : current);
auto &dst = data_placeable[layer_idx - (min_layer_last + 1)];
if (last) {
if (! dst.empty())
placable = union_(placable, dst);
dst = polygons_simplify(placable, min_resolution);
} else
append(dst, placable);
}
});
} else {
// Calculating just the collision areas.
}
}
#ifdef SLIC3R_TREESUPPORTS_PROGRESS
{
std::lock_guard<std::mutex> critical_section(*m_critical_progress);
if (m_precalculated && m_precalculation_progress < TREE_PROGRESS_PRECALC_COLL) {
m_precalculation_progress += TREE_PROGRESS_PRECALC_COLL / keys.size();
Progress::messageProgress(Progress::Stage::SUPPORT, m_precalculation_progress * m_progress_multiplier + m_progress_offset, TREE_PROGRESS_TOTAL);
}
}
#endif
m_collision_cache.insert(std::move(data), min_layer_last + 1, radius);
if (calculate_placable)
m_placeable_areas_cache.insert(std::move(data_placeable), min_layer_last + 1, radius);
}
void TreeModelVolumes::calculateCollisionHolefree(const std::vector<RadiusLayerPair> &keys)
{
LayerIndex max_layer = 0;
for (long long unsigned int i = 0; i < keys.size(); i++)
max_layer = std::max(max_layer, keys[i].second);
tbb::parallel_for(tbb::blocked_range<LayerIndex>(0, max_layer + 1, keys.size()),
[&](const tbb::blocked_range<LayerIndex> &range) {
RadiusLayerPolygonCacheData data;
for (LayerIndex layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
for (RadiusLayerPair key : keys)
if (layer_idx <= key.second) {
// Logically increase the collision by m_increase_until_radius
coord_t radius = key.first;
assert(radius == this->ceilRadius(radius));
assert(radius < m_increase_until_radius + m_current_min_xy_dist_delta);
coord_t increase_radius_ceil = ceilRadius(m_increase_until_radius, false) - radius;
assert(increase_radius_ceil > 0);
// this union is important as otherwise holes(in form of lines that will increase to holes in a later step) can get unioned onto the area.
data[RadiusLayerPair(radius, layer_idx)] = polygons_simplify(
offset(union_ex(getCollision(m_increase_until_radius, layer_idx, false)),
5 - increase_radius_ceil, ClipperLib::jtRound, m_min_resolution),
m_min_resolution);
}
}
m_collision_cache_holefree.insert(std::move(data));
});
}
void TreeModelVolumes::calculateAvoidance(const std::vector<RadiusLayerPair> &keys, bool to_build_plate, bool to_model)
{
// For every RadiusLayer pair there are 3 avoidances that have to be calculated.
// Prepare tasks for parallelization.
struct AvoidanceTask {
AvoidanceType type;
coord_t radius;
LayerIndex max_required_layer;
bool to_model;
LayerIndex start_layer;
bool slow() const { return this->type == AvoidanceType::Slow; }
bool holefree() const { return this->type == AvoidanceType::FastSafe; }
};
std::vector<AvoidanceTask> avoidance_tasks;
avoidance_tasks.reserve((int(to_build_plate) + int(to_model)) * keys.size() * size_t(AvoidanceType::Count));
for (int iter_idx = 0; iter_idx < 2 * int(keys.size()) * int(AvoidanceType::Count); ++ iter_idx) {
AvoidanceTask task{
AvoidanceType(iter_idx % int(AvoidanceType::Count)),
keys[iter_idx / 6].first, // radius
keys[iter_idx / 6].second, // max_layer
((iter_idx / 3) & 1) != 0 // to_model
};
// Ensure start_layer is at least 1 as if no avoidance was calculated yet getMaxCalculatedLayer() returns -1.
task.start_layer = std::max<LayerIndex>(1, 1 + avoidance_cache(task.type, task.to_model).getMaxCalculatedLayer(task.radius));
if (task.start_layer > task.max_required_layer) {
BOOST_LOG_TRIVIAL(debug) << "Calculation requested for value already calculated?";
continue;
}
if (! task.holefree() || task.radius < m_increase_until_radius + m_current_min_xy_dist_delta)
avoidance_tasks.emplace_back(task);
}
tbb::parallel_for(tbb::blocked_range<size_t>(0, avoidance_tasks.size(), 1),
[this, &avoidance_tasks](const tbb::blocked_range<size_t> &range) {
for (size_t task_idx = range.begin(); task_idx < range.end(); ++ task_idx) {
const AvoidanceTask &task = avoidance_tasks[task_idx];
assert(! task.holefree() || task.radius < m_increase_until_radius + m_current_min_xy_dist_delta);
if (task.to_model)
// ensuring Placeableareas are calculated
getPlaceableAreas(task.radius, task.max_required_layer);
// The following loop propagating avoidance regions bottom up is inherently serial.
const bool collision_holefree = (task.slow() || task.holefree()) && task.radius < m_increase_until_radius + m_current_min_xy_dist_delta;
const float max_move = task.slow() ? m_max_move_slow : m_max_move;
// Limiting the offset step so that unioning the shrunk latest_avoidance with the current layer collisions
// will not create gaps in the resulting avoidance region letting a tree support branch tunneling through an object wall.
float move_step = 1.9 * std::max(task.radius, m_current_min_xy_dist);
int move_steps = round_up_divide<int>(max_move, move_step);
assert(move_steps > 0);
float last_move_step = max_move - (move_steps - 1) * move_step;
if (last_move_step < scaled<float>(0.05)) {
assert(move_steps > 1);
if (move_steps > 1) {
// Avoid taking a very short last step, stretch the other steps a bit instead.
move_step = max_move / (-- move_steps);
last_move_step = move_step;
}
}
// minDist as the delta was already added, also avoidance for layer 0 will return the collision.
Polygons latest_avoidance = getAvoidance(task.radius, task.start_layer - 1, task.type, task.to_model, true);
std::vector<std::pair<RadiusLayerPair, Polygons>> data;
data.reserve(task.max_required_layer + 1 - task.start_layer);
for (LayerIndex layer_idx = task.start_layer; layer_idx <= task.max_required_layer; ++ layer_idx) {
// Merge current layer collisions with shrunk last_avoidance.
const Polygons &current_layer_collisions = collision_holefree ? getCollisionHolefree(task.radius, layer_idx) : getCollision(task.radius, layer_idx, true);
// For mildly steep branch angles only one step will be taken.
for (int istep = 0; istep < move_steps; ++ istep)
latest_avoidance = union_(current_layer_collisions,
offset(latest_avoidance,
istep + 1 == move_steps ? - last_move_step : - move_step,
ClipperLib::jtRound, m_min_resolution));
if (task.to_model)
latest_avoidance = diff(latest_avoidance, getPlaceableAreas(task.radius, layer_idx));
latest_avoidance = polygons_simplify(latest_avoidance, m_min_resolution);
data.emplace_back(RadiusLayerPair{task.radius, layer_idx}, latest_avoidance);
}
#ifdef SLIC3R_TREESUPPORTS_PROGRESS
{
std::lock_guard<std::mutex> critical_section(*m_critical_progress);
if (m_precalculated && m_precalculation_progress < TREE_PROGRESS_PRECALC_COLL + TREE_PROGRESS_PRECALC_AVO) {
m_precalculation_progress += to_model ?
0.4 * TREE_PROGRESS_PRECALC_AVO / (keys.size() * 3) :
m_support_rests_on_model ? 0.4 : 1 * TREE_PROGRESS_PRECALC_AVO / (keys.size() * 3);
Progress::messageProgress(Progress::Stage::SUPPORT, m_precalculation_progress * m_progress_multiplier + m_progress_offset, TREE_PROGRESS_TOTAL);
}
}
#endif
avoidance_cache(task.type, task.to_model).insert(std::move(data));
}
});
}
void TreeModelVolumes::calculatePlaceables(const std::vector<RadiusLayerPair> &keys)
{
tbb::parallel_for(tbb::blocked_range<size_t>(0, keys.size()),
[&, keys](const tbb::blocked_range<size_t>& range) {
for (size_t key_idx = range.begin(); key_idx < range.end(); ++ key_idx)
this->calculatePlaceables(keys[key_idx].first, keys[key_idx].second);
});
}
void TreeModelVolumes::calculatePlaceables(const coord_t radius, const LayerIndex max_required_layer)
{
LayerIndex start_layer = 1 + m_placeable_areas_cache.getMaxCalculatedLayer(radius);
if (start_layer > max_required_layer) {
BOOST_LOG_TRIVIAL(debug) << "Requested calculation for value already calculated ?";
return;
}
std::vector<Polygons> data(max_required_layer + 1 - start_layer, Polygons{});
if (start_layer == 0)
data[0] = diff(m_machine_border, getCollision(radius, 0, true));
tbb::parallel_for(tbb::blocked_range<LayerIndex>(std::max(1, start_layer), max_required_layer + 1),
[this, &data, radius, start_layer](const tbb::blocked_range<LayerIndex>& range) {
for (LayerIndex layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx)
data[layer_idx - start_layer] = offset(union_ex(getPlaceableAreas(0, layer_idx)), - radius, jtMiter, 1.2);
});
#ifdef SLIC3R_TREESUPPORTS_PROGRESS
{
std::lock_guard<std::mutex> critical_section(*m_critical_progress);
if (m_precalculated && m_precalculation_progress < TREE_PROGRESS_PRECALC_COLL + TREE_PROGRESS_PRECALC_AVO) {
m_precalculation_progress += 0.2 * TREE_PROGRESS_PRECALC_AVO / (keys.size());
Progress::messageProgress(Progress::Stage::SUPPORT, m_precalculation_progress * m_progress_multiplier + m_progress_offset, TREE_PROGRESS_TOTAL);
}
}
#endif
m_placeable_areas_cache.insert(std::move(data), start_layer, radius);
}
void TreeModelVolumes::calculateWallRestrictions(const std::vector<RadiusLayerPair> &keys)
{
// Wall restrictions are mainly important when they represent actual walls that are printed, and not "just" the configured z_distance, because technically valid placement is no excuse for moving through a wall.
// As they exist to prevent accidentially moving though a wall at high speed between layers like thie (x = wall,i = influence area,o= empty space,d = blocked area because of z distance) Assume maximum movement distance is two characters and maximum safe movement distance of one character
/* Potential issue addressed by the wall restrictions: Influence area may lag through a wall
* layer z+1:iiiiiiiiiiioooo
* layer z+0:xxxxxiiiiiiiooo
* layer z-1:ooooixxxxxxxxxx
*/
// The radius for the upper collission has to be 0 as otherwise one may not enter areas that may be forbidden on layer_idx but not one below (c = not an influence area even though it should ):
/*
* layer z+1:xxxxxiiiiiioo
* layer z+0:dddddiiiiiiio
* layer z-1:dddocdddddddd
*/
// Also there can not just the collision of the lower layer be used because if it were:
/*
* layer z+1:dddddiiiiiiiiiio
* layer z+0:xxxxxddddddddddc
* layer z-1:dddddxxxxxxxxxxc
*/
// Or of the upper layer be used because if it were:
/*
* layer z+1:dddddiiiiiiiiiio
* layer z+0:xxxxcddddddddddc
* layer z-1:ddddcxxxxxxxxxxc
*/
// And just offseting with maximum movement distance (and not in multiple steps) could cause:
/*
* layer z: oxiiiiiiiiioo
* layer z-1: ixiiiiiiiiiii
*/
tbb::parallel_for(tbb::blocked_range<size_t>(0, keys.size()),
[&, keys](const tbb::blocked_range<size_t> &range) {
for (size_t key_idx = range.begin(); key_idx < range.end(); ++ key_idx) {
const coord_t radius = keys[key_idx].first;
const LayerIndex max_required_layer = keys[key_idx].second;
const coord_t min_layer_bottom = std::max(1, m_wall_restrictions_cache.getMaxCalculatedLayer(radius));
const size_t buffer_size = max_required_layer + 1 - min_layer_bottom;
std::vector<Polygons> data(buffer_size, Polygons{});
std::vector<Polygons> data_min;
if (m_current_min_xy_dist_delta > 0)
data_min.assign(buffer_size, Polygons{});
tbb::parallel_for(tbb::blocked_range<LayerIndex>(min_layer_bottom, max_required_layer + 1),
[this, &data, &data_min, radius, min_layer_bottom](const tbb::blocked_range<LayerIndex> &range) {
for (LayerIndex layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
data[layer_idx - min_layer_bottom] = polygons_simplify(
// radius contains m_current_min_xy_dist_delta already if required
intersection(getCollision(0, layer_idx, false), getCollision(radius, layer_idx - 1, true)),
m_min_resolution);
if (! data_min.empty())
data_min[layer_idx - min_layer_bottom] =
polygons_simplify(
intersection(getCollision(0, layer_idx, true), getCollision(radius, layer_idx - 1, true)),
m_min_resolution);
}
});
m_wall_restrictions_cache.insert(std::move(data), min_layer_bottom, radius);
if (! data_min.empty())
m_wall_restrictions_cache_min.insert(std::move(data_min), min_layer_bottom, radius);
}
});
}
coord_t TreeModelVolumes::ceilRadius(const coord_t radius) const
{
if (radius == 0)
return 0;
coord_t out = m_radius_0;
if (radius > m_radius_0) {
// generate SUPPORT_TREE_PRE_EXPONENTIAL_STEPS of radiis before starting to exponentially increase them.
coord_t initial_radius_delta = SUPPORT_TREE_EXPONENTIAL_THRESHOLD - m_radius_0;
auto ignore = [this](coord_t r) { return std::binary_search(m_ignorable_radii.begin(), m_ignorable_radii.end(), r); };
if (initial_radius_delta > SUPPORT_TREE_COLLISION_RESOLUTION) {
const int num_steps = round_up_divide(initial_radius_delta, SUPPORT_TREE_EXPONENTIAL_THRESHOLD);
const int stepsize = initial_radius_delta / num_steps;
out += stepsize;
for (auto step = 0; step < num_steps; ++ step) {
if (out >= radius && ! ignore(out))
return out;
out += stepsize;
}
} else
out += SUPPORT_TREE_COLLISION_RESOLUTION;
while (out < radius || ignore(out)) {
assert(out * SUPPORT_TREE_EXPONENTIAL_FACTOR > out + SUPPORT_TREE_COLLISION_RESOLUTION);
out = out * SUPPORT_TREE_EXPONENTIAL_FACTOR;
}
}
return out;
}
}

View File

@ -0,0 +1,610 @@
// Tree supports by Thomas Rahm, losely based on Tree Supports by CuraEngine.
// Original source of Thomas Rahm's tree supports:
// https://github.com/ThomasRahm/CuraEngine
//
// Original CuraEngine copyright:
// Copyright (c) 2021 Ultimaker B.V.
// CuraEngine is released under the terms of the AGPLv3 or higher.
#ifndef slic3r_TreeModelVolumes_hpp
#define slic3r_TreeModelVolumes_hpp
#include <mutex>
#include <unordered_map>
#include <unordered_set>
#include <boost/functional/hash.hpp>
#include "Point.hpp"
#include "Polygon.hpp"
#include "PrintConfig.hpp"
namespace Slic3r
{
using LayerIndex = int;
class BuildVolume;
class PrintObject;
struct TreeSupportMeshGroupSettings {
TreeSupportMeshGroupSettings() = default;
explicit TreeSupportMeshGroupSettings(const PrintObject &print_object);
/*********************************************************************/
/* Print parameters, not support specific: */
/*********************************************************************/
coord_t layer_height { scaled<coord_t>(0.15) };
// Maximum Deviation (meshfix_maximum_deviation)
// The maximum deviation allowed when reducing the resolution for the Maximum Resolution setting. If you increase this,
// the print will be less accurate, but the g-code will be smaller. Maximum Deviation is a limit for Maximum Resolution,
// so if the two conflict the Maximum Deviation will always be held true.
coord_t resolution { scaled<coord_t>(0.025) };
// Minimum Feature Size (aka minimum line width)
// Minimum thickness of thin features. Model features that are thinner than this value will not be printed, while features thicker
// than the Minimum Feature Size will be widened to the Minimum Wall Line Width.
coord_t min_feature_size { scaled<coord_t>(0.1) };
/*********************************************************************/
/* General support parameters: */
/*********************************************************************/
// Support Overhang Angle
// The minimum angle of overhangs for which support is added. At a value of 0° all overhangs are supported, 90° will not provide any support.
double support_angle { 50. * M_PI / 180. };
// Support Line Width
// Width of a single support structure line.
coord_t support_line_width { scaled<coord_t>(0.4) };
// Support Roof Line Width: Width of a single support roof line.
coord_t support_roof_line_width { scaled<coord_t>(0.4) };
// Enable Support Floor (aka bottom interfaces)
// Generate a dense slab of material between the bottom of the support and the model. This will create a skin between the model and support.
bool support_bottom_enable { false };
// Support Floor Thickness
// The thickness of the support floors. This controls the number of dense layers that are printed on top of places of a model on which support rests.
coord_t support_bottom_height { scaled<coord_t>(1.) };
bool support_material_buildplate_only { false };
// Support X/Y Distance
// Distance of the support structure from the print in the X/Y directions.
// minimum: 0, maximum warning: 1.5 * machine_nozzle_tip_outer_diameter
coord_t support_xy_distance { scaled<coord_t>(0.7) };
// Minimum Support X/Y Distance
// Distance of the support structure from the overhang in the X/Y directions.
// minimum_value: 0, minimum warning": support_xy_distance - support_line_width * 2, maximum warning: support_xy_distance
coord_t support_xy_distance_overhang { scaled<coord_t>(0.2) };
// Support Top Distance
// Distance from the top of the support to the print.
coord_t support_top_distance { scaled<coord_t>(0.1) };
// Support Bottom Distance
// Distance from the print to the bottom of the support.
coord_t support_bottom_distance { scaled<coord_t>(0.1) };
//FIXME likely not needed, optimization for clipping of interface layers
// When checking where there's model above and below the support, take steps of the given height. Lower values will slice slower, while higher values
// may cause normal support to be printed in some places where there should have been support interface.
coord_t support_interface_skip_height { scaled<coord_t>(0.3) };
// Support Infill Line Directions
// A list of integer line directions to use. Elements from the list are used sequentially as the layers progress and when the end
// of the list is reached, it starts at the beginning again. The list items are separated by commas and the whole list is contained
// in square brackets. Default is an empty list which means use the default angle 0 degrees.
// std::vector<double> support_infill_angles {};
// Enable Support Roof
// Generate a dense slab of material between the top of support and the model. This will create a skin between the model and support.
bool support_roof_enable { false };
// Support Roof Thickness
// The thickness of the support roofs. This controls the amount of dense layers at the top of the support on which the model rests.
coord_t support_roof_height { scaled<coord_t>(1.) };
// Minimum Support Roof Area
// Minimum area size for the roofs of the support. Polygons which have an area smaller than this value will be printed as normal support.
double minimum_roof_area { scaled<double>(scaled<double>(1.)) };
// A list of integer line directions to use. Elements from the list are used sequentially as the layers progress
// and when the end of the list is reached, it starts at the beginning again. The list items are separated
// by commas and the whole list is contained in square brackets. Default is an empty list which means
// use the default angles (alternates between 45 and 135 degrees if interfaces are quite thick or 90 degrees).
std::vector<double> support_roof_angles {};
// Support Roof Pattern (aka top interface)
// The pattern with which the roofs of the support are printed.
SupportMaterialInterfacePattern support_roof_pattern { smipAuto };
// Support Pattern
// The pattern of the support structures of the print. The different options available result in sturdy or easy to remove support.
SupportMaterialPattern support_pattern { smpRectilinear };
// Support Line Distance
// Distance between the printed support structure lines. This setting is calculated by the support density.
coord_t support_line_spacing { scaled<coord_t>(2.66 - 0.4) };
// Support Floor Horizontal Expansion
// Amount of offset applied to the floors of the support.
coord_t support_bottom_offset { scaled<coord_t>(0.) };
// Support Wall Line Count
// The number of walls with which to surround support infill. Adding a wall can make support print more reliably
// and can support overhangs better, but increases print time and material used.
// tree: 1, zig-zag: 0, concentric: 1
int support_wall_count { 1 };
// Support Roof Line Distance
// Distance between the printed support roof lines. This setting is calculated by the Support Roof Density, but can be adjusted separately.
coord_t support_roof_line_distance { scaled<coord_t>(0.4) };
// Minimum Support Area
// Minimum area size for support polygons. Polygons which have an area smaller than this value will not be generated.
coord_t minimum_support_area { scaled<coord_t>(0.) };
// Minimum Support Floor Area
// Minimum area size for the floors of the support. Polygons which have an area smaller than this value will be printed as normal support.
coord_t minimum_bottom_area { scaled<coord_t>(1.0) };
// Support Horizontal Expansion
// Amount of offset applied to all support polygons in each layer. Positive values can smooth out the support areas and result in more sturdy support.
coord_t support_offset { scaled<coord_t>(0.) };
/*********************************************************************/
/* Parameters for the Cura tree supports implementation: */
/*********************************************************************/
// Tree Support Maximum Branch Angle
// The maximum angle of the branches, when the branches have to avoid the model. Use a lower angle to make them more vertical and more stable. Use a higher angle to be able to have more reach.
// minimum: 0, minimum warning: 20, maximum: 89, maximum warning": 85
double support_tree_angle { 60. * M_PI / 180. };
// Tree Support Branch Diameter Angle
// The angle of the branches' diameter as they gradually become thicker towards the bottom. An angle of 0 will cause the branches to have uniform thickness over their length.
// A bit of an angle can increase stability of the tree support.
// minimum: 0, maximum: 89.9999, maximum warning: 15
double support_tree_branch_diameter_angle { 5. * M_PI / 180. };
// Tree Support Branch Distance
// How far apart the branches need to be when they touch the model. Making this distance small will cause
// the tree support to touch the model at more points, causing better overhang but making support harder to remove.
coord_t support_tree_branch_distance { scaled<coord_t>(1.) };
// Tree Support Branch Diameter
// The diameter of the thinnest branches of tree support. Thicker branches are more sturdy. Branches towards the base will be thicker than this.
// minimum: 0.001, minimum warning: support_line_width * 2
coord_t support_tree_branch_diameter { scaled<coord_t>(2.) };
/*********************************************************************/
/* Parameters new to the Thomas Rahm's tree supports implementation: */
/*********************************************************************/
// Tree Support Preferred Branch Angle
// The preferred angle of the branches, when they do not have to avoid the model. Use a lower angle to make them more vertical and more stable. Use a higher angle for branches to merge faster.
// minimum: 0, minimum warning: 10, maximum: support_tree_angle, maximum warning: support_tree_angle-1
double support_tree_angle_slow { 50. * M_PI / 180. };
// Tree Support Diameter Increase To Model
// The most the diameter of a branch that has to connect to the model may increase by merging with branches that could reach the buildplate.
// Increasing this reduces print time, but increases the area of support that rests on model
// minimum: 0
coord_t support_tree_max_diameter_increase_by_merges_when_support_to_model { scaled<coord_t>(1.0) };
// Tree Support Minimum Height To Model
// How tall a branch has to be if it is placed on the model. Prevents small blobs of support. This setting is ignored when a branch is supporting a support roof.
// minimum: 0, maximum warning: 5
coord_t support_tree_min_height_to_model { scaled<coord_t>(1.0) };
// Tree Support Inital Layer Diameter
// Diameter every branch tries to achieve when reaching the buildplate. Improves bed adhesion.
// minimum: 0, maximum warning: 20
coord_t support_tree_bp_diameter { scaled<coord_t>(7.5) };
// Tree Support Branch Density
// Adjusts the density of the support structure used to generate the tips of the branches. A higher value results in better overhangs,
// but the supports are harder to remove. Use Support Roof for very high values or ensure support density is similarly high at the top.
// 5%-35%
double support_tree_top_rate { 15. };
// Tree Support Tip Diameter
// The diameter of the top of the tip of the branches of tree support."
// minimum: min_wall_line_width, minimum warning: min_wall_line_width+0.05, maximum_value: support_tree_branch_diameter, value: support_line_width
coord_t support_tree_tip_diameter { scaled<coord_t>(0.4) };
// Support Interface Priority
// How support interface and support will interact when they overlap. Currently only implemented for support roof.
//enum support_interface_priority { support_lines_overwrite_interface_area };
};
class TreeModelVolumes
{
public:
TreeModelVolumes() = default;
explicit TreeModelVolumes(const PrintObject &print_object, const BuildVolume &build_volume,
coord_t max_move, coord_t max_move_slow, size_t current_mesh_idx, double progress_multiplier,
double progress_offset, const std::vector<Polygons> &additional_excluded_areas = {});
TreeModelVolumes(TreeModelVolumes&&) = default;
TreeModelVolumes& operator=(TreeModelVolumes&&) = default;
TreeModelVolumes(const TreeModelVolumes&) = delete;
TreeModelVolumes& operator=(const TreeModelVolumes&) = delete;
enum class AvoidanceType
{
Slow,
FastSafe,
Fast,
Count
};
/*!
* \brief Precalculate avoidances and collisions up to max_layer.
*
* Knowledge about branch angle is used to only calculate avoidances and collisions that may actually be needed.
* Not calling precalculate() will cause the class to lazily calculate avoidances and collisions as needed, which will be a lot slower on systems with more then one or two cores!
*/
void precalculate(const coord_t max_layer);
/*!
* \brief Provides the areas that have to be avoided by the tree's branches to prevent collision with the model on this layer.
*
* The result is a 2D area that would cause nodes of radius \p radius to
* collide with the model.
*
* \param radius The radius of the node of interest
* \param layer_idx The layer of interest
* \param min_xy_dist Is the minimum xy distance used.
* \return Polygons object
*/
const Polygons& getCollision(const coord_t radius, LayerIndex layer_idx, bool min_xy_dist) const;
/*!
* \brief Provides the areas that have to be avoided by the tree's branches
* in order to reach the build plate.
*
* The result is a 2D area that would cause nodes of radius \p radius to
* collide with the model or be unable to reach the build platform.
*
* The input collision areas are inset by the maximum move distance and
* propagated upwards.
*
* \param radius The radius of the node of interest
* \param layer_idx The layer of interest
* \param type Is the propagation with the maximum move distance slow required.
* \param to_model Does the avoidance allow good connections with the model.
* \param min_xy_dist is the minimum xy distance used.
* \return Polygons object
*/
const Polygons& getAvoidance(coord_t radius, LayerIndex layer_idx, AvoidanceType type, bool to_model, bool min_xy_dist) const;
/*!
* \brief Provides the area represents all areas on the model where the branch does completely fit on the given layer.
* \param radius The radius of the node of interest
* \param layer_idx The layer of interest
* \return Polygons object
*/
const Polygons& getPlaceableAreas(coord_t radius, LayerIndex layer_idx) const;
/*!
* \brief Provides the area that represents the walls, as in the printed area, of the model. This is an abstract representation not equal with the outline. See calculateWallRestrictions for better description.
* \param radius The radius of the node of interest.
* \param layer_idx The layer of interest.
* \param min_xy_dist is the minimum xy distance used.
* \return Polygons object
*/
const Polygons& getWallRestriction(coord_t radius, LayerIndex layer_idx, bool min_xy_dist) const;
/*!
* \brief Round \p radius upwards to either a multiple of m_radius_sample_resolution or a exponentially increasing value
*
* It also adds the difference between the minimum xy distance and the regular one.
*
* \param radius The radius of the node of interest
* \param min_xy_dist is the minimum xy distance used.
* \return The rounded radius
*/
coord_t ceilRadius(const coord_t radius, const bool min_xy_dist) const {
assert(radius >= 0);
return min_xy_dist ?
this->ceilRadius(radius) :
// special case as if a radius 0 is requested it could be to ensure correct xy distance. As such it is beneficial if the collision is as close to the configured values as possible.
radius > 0 ? this->ceilRadius(radius + m_current_min_xy_dist_delta) : m_current_min_xy_dist_delta;
}
/*!
* \brief Round \p radius upwards to the maximum that would still round up to the same value as the provided one.
*
* \param radius The radius of the node of interest
* \param min_xy_dist is the minimum xy distance used.
* \return The maximum radius, resulting in the same rounding.
*/
coord_t getRadiusNextCeil(coord_t radius, bool min_xy_dist) const {
assert(radius > 0);
return min_xy_dist ?
this->ceilRadius(radius) :
this->ceilRadius(radius + m_current_min_xy_dist_delta) - m_current_min_xy_dist_delta;
}
private:
/*!
* \brief Convenience typedef for the keys to the caches
*/
using RadiusLayerPair = std::pair<coord_t, LayerIndex>;
using RadiusLayerPolygonCacheData = std::unordered_map<RadiusLayerPair, Polygons, boost::hash<RadiusLayerPair>>;
class RadiusLayerPolygonCache {
public:
RadiusLayerPolygonCache() = default;
RadiusLayerPolygonCache(RadiusLayerPolygonCache &&rhs) : data(std::move(rhs.data)) {}
RadiusLayerPolygonCache& operator=(RadiusLayerPolygonCache &&rhs) { data = std::move(rhs.data); return *this; }
RadiusLayerPolygonCache(const RadiusLayerPolygonCache&) = delete;
RadiusLayerPolygonCache& operator=(const RadiusLayerPolygonCache&) = delete;
void insert(RadiusLayerPolygonCacheData &&in) {
std::lock_guard<std::mutex> guard(this->mutex);
for (auto& d : in)
this->data.emplace(d.first, std::move(d.second));
}
void insert(std::vector<std::pair<RadiusLayerPair, Polygons>> &&in) {
std::lock_guard<std::mutex> guard(this->mutex);
for (auto& d : in)
this->data.emplace(d.first, std::move(d.second));
}
// by layer
void insert(std::vector<std::pair<coord_t, Polygons>> &&in, coord_t radius) {
std::lock_guard<std::mutex> guard(this->mutex);
for (auto &d : in)
this->data.emplace(RadiusLayerPair{ radius, d.first }, std::move(d.second));
}
void insert(std::vector<Polygons> &&in, coord_t first_layer_idx, coord_t radius) {
std::lock_guard<std::mutex> guard(this->mutex);
for (auto &d : in)
this->data.emplace(RadiusLayerPair{ radius, first_layer_idx ++ }, std::move(d));
}
/*!
* \brief Checks a cache for a given RadiusLayerPair and returns it if it is found
* \param key RadiusLayerPair of the requested areas. The radius will be calculated up to the provided layer.
* \return A wrapped optional reference of the requested area (if it was found, an empty optional if nothing was found)
*/
std::optional<std::reference_wrapper<const Polygons>> getArea(const TreeModelVolumes::RadiusLayerPair &key) const {
std::lock_guard<std::mutex> guard(this->mutex);
const auto it = this->data.find(key);
return it == this->data.end() ?
std::optional<std::reference_wrapper<const Polygons>>{} : std::optional<std::reference_wrapper<const Polygons>>{ it->second };
}
/*!
* \brief Get the highest already calculated layer in the cache.
* \param radius The radius for which the highest already calculated layer has to be found.
* \param map The cache in which the lookup is performed.
*
* \return A wrapped optional reference of the requested area (if it was found, an empty optional if nothing was found)
*/
LayerIndex getMaxCalculatedLayer(coord_t radius) const {
std::lock_guard<std::mutex> guard(this->mutex);
int max_layer = -1;
// the placeable on model areas do not exist on layer 0, as there can not be model below it. As such it may be possible that layer 1 is available, but layer 0 does not exist.
if (this->data.find({ radius, 1 }) != this->data.end())
max_layer = 1;
while (this->data.count(TreeModelVolumes::RadiusLayerPair(radius, max_layer + 1)) > 0)
++ max_layer;
return max_layer;
}
private:
RadiusLayerPolygonCacheData data;
mutable std::mutex mutex;
};
/*!
* \brief Provides the areas that have to be avoided by the tree's branches to prevent collision with the model on this layer. Holes are removed.
*
* The result is a 2D area that would cause nodes of given radius to
* collide with the model or be inside a hole.
* A Hole is defined as an area, in which a branch with m_increase_until_radius radius would collide with the wall.
* minimum xy distance is always used.
* \param radius The radius of the node of interest
* \param layer_idx The layer of interest
* \param min_xy_dist Is the minimum xy distance used.
* \return Polygons object
*/
const Polygons& getCollisionHolefree(coord_t radius, LayerIndex layer_idx) const;
/*!
* \brief Round \p radius upwards to either a multiple of m_radius_sample_resolution or a exponentially increasing value
*
* \param radius The radius of the node of interest
*/
coord_t ceilRadius(const coord_t radius) const;
/*!
* \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model on this layer.
*
* The result is a 2D area that would cause nodes of given radius to
* collide with the model. Result is saved in the cache.
* \param keys RadiusLayerPairs of all requested areas. Every radius will be calculated up to the provided layer.
*/
void calculateCollision(const std::vector<RadiusLayerPair> &keys);
void calculateCollision(const coord_t radius, const LayerIndex max_layer_idx);
/*!
* \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model on this layer. Holes are removed.
*
* The result is a 2D area that would cause nodes of given radius to
* collide with the model or be inside a hole. Result is saved in the cache.
* A Hole is defined as an area, in which a branch with m_increase_until_radius radius would collide with the wall.
* \param keys RadiusLayerPairs of all requested areas. Every radius will be calculated up to the provided layer.
*/
void calculateCollisionHolefree(const std::vector<RadiusLayerPair> &keys);
/*!
* \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model on this layer. Holes are removed.
*
* The result is a 2D area that would cause nodes of given radius to
* collide with the model or be inside a hole. Result is saved in the cache.
* A Hole is defined as an area, in which a branch with m_increase_until_radius radius would collide with the wall.
* \param key RadiusLayerPairs the requested areas. The radius will be calculated up to the provided layer.
*/
void calculateCollisionHolefree(RadiusLayerPair key)
{
calculateCollisionHolefree(std::vector<RadiusLayerPair>{ RadiusLayerPair(key) });
}
/*!
* \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model.
*
* The result is a 2D area that would cause nodes of radius \p radius to
* collide with the model. Result is saved in the cache.
* \param keys RadiusLayerPairs of all requested areas. Every radius will be calculated up to the provided layer.
*/
void calculateAvoidance(const std::vector<RadiusLayerPair> &keys, bool to_build_plate, bool to_model);
/*!
* \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model.
*
* The result is a 2D area that would cause nodes of radius \p radius to
* collide with the model. Result is saved in the cache.
* \param key RadiusLayerPair of the requested areas. It will be calculated up to the provided layer.
*/
void calculateAvoidance(RadiusLayerPair key, bool to_build_plate, bool to_model)
{
calculateAvoidance(std::vector<RadiusLayerPair>{ RadiusLayerPair(key) }, to_build_plate, to_model);
}
/*!
* \brief Creates the areas where a branch of a given radius can be place on the model.
* Result is saved in the cache.
* \param key RadiusLayerPair of the requested areas. It will be calculated up to the provided layer.
*/
void calculatePlaceables(const coord_t radius, const LayerIndex max_required_layer);
/*!
* \brief Creates the areas where a branch of a given radius can be placed on the model.
* Result is saved in the cache.
* \param keys RadiusLayerPair of the requested areas. The radius will be calculated up to the provided layer.
*/
void calculatePlaceables(const std::vector<RadiusLayerPair> &keys);
/*!
* \brief Creates the areas that can not be passed when expanding an area downwards. As such these areas are an somewhat abstract representation of a wall (as in a printed object).
*
* These areas are at least xy_min_dist wide. When calculating it is always assumed that every wall is printed on top of another (as in has an overlap with the wall a layer below). Result is saved in the corresponding cache.
*
* \param keys RadiusLayerPairs of all requested areas. Every radius will be calculated up to the provided layer.
*/
void calculateWallRestrictions(const std::vector<RadiusLayerPair> &keys);
/*!
* \brief Creates the areas that can not be passed when expanding an area downwards. As such these areas are an somewhat abstract representation of a wall (as in a printed object).
* These areas are at least xy_min_dist wide. When calculating it is always assumed that every wall is printed on top of another (as in has an overlap with the wall a layer below). Result is saved in the corresponding cache.
* \param key RadiusLayerPair of the requested area. It well be will be calculated up to the provided layer.
*/
void calculateWallRestrictions(RadiusLayerPair key)
{
calculateWallRestrictions(std::vector<RadiusLayerPair>{ RadiusLayerPair(key) });
}
/*!
* \brief The maximum distance that the center point of a tree branch may move in consecutive layers if it has to avoid the model.
*/
coord_t m_max_move;
/*!
* \brief The maximum distance that the centre-point of a tree branch may
* move in consecutive layers if it does not have to avoid the model
*/
coord_t m_max_move_slow;
/*!
* \brief The smallest maximum resolution for simplify
*/
coord_t m_min_resolution;
bool m_precalculated = false;
/*!
* \brief The index to access the outline corresponding with the currently processing mesh
*/
size_t m_current_outline_idx;
/*!
* \brief The minimum required clearance between the model and the tree branches
*/
coord_t m_current_min_xy_dist;
/*!
* \brief The difference between the minimum required clearance between the model and the tree branches and the regular one.
*/
coord_t m_current_min_xy_dist_delta;
/*!
* \brief Does at least one mesh allow support to rest on a model.
*/
bool m_support_rests_on_model;
#ifdef SLIC3R_TREESUPPORTS_PROGRESS
/*!
* \brief The progress of the precalculate function for communicating it to the progress bar.
*/
coord_t m_precalculation_progress = 0;
/*!
* \brief The progress multiplier of all values added progress bar.
* Required for the progress bar the behave as expected when areas have to be calculated multiple times
*/
double m_progress_multiplier;
/*!
* \brief The progress offset added to all values communicated to the progress bar.
* Required for the progress bar the behave as expected when areas have to be calculated multiple times
*/
double m_progress_offset;
#endif // SLIC3R_TREESUPPORTS_PROGRESS
/*!
* \brief Increase radius in the resulting drawn branches, even if the avoidance does not allow it. Will be cut later to still fit.
*/
coord_t m_increase_until_radius;
/*!
* \brief Polygons representing the limits of the printable area of the
* machine
*/
Polygons m_machine_border;
/*!
* \brief Storage for layer outlines and the corresponding settings of the meshes grouped by meshes with identical setting.
*/
std::vector<std::pair<TreeSupportMeshGroupSettings, std::vector<Polygons>>> m_layer_outlines;
/*!
* \brief Storage for areas that should be avoided, like support blocker or previous generated trees.
*/
std::vector<Polygons> m_anti_overhang;
/*!
* \brief Radii that can be ignored by ceilRadius as they will never be requested, sorted.
*/
std::vector<coord_t> m_ignorable_radii;
/*!
* \brief Smallest radius a branch can have. This is the radius of a SupportElement with DTT=0.
*/
coord_t m_radius_0;
/*!
* \brief Caches for the collision, avoidance and areas on the model where support can be placed safely
* at given radius and layer indices.
*/
RadiusLayerPolygonCache m_collision_cache;
RadiusLayerPolygonCache m_collision_cache_holefree;
RadiusLayerPolygonCache m_avoidance_cache;
RadiusLayerPolygonCache m_avoidance_cache_slow;
RadiusLayerPolygonCache m_avoidance_cache_to_model;
RadiusLayerPolygonCache m_avoidance_cache_to_model_slow;
RadiusLayerPolygonCache m_placeable_areas_cache;
/*!
* \brief Caches to avoid holes smaller than the radius until which the radius is always increased, as they are free of holes.
* Also called safe avoidances, as they are safe regarding not running into holes.
*/
RadiusLayerPolygonCache m_avoidance_cache_holefree;
RadiusLayerPolygonCache m_avoidance_cache_holefree_to_model;
RadiusLayerPolygonCache& avoidance_cache(const AvoidanceType type, const bool to_model) {
if (to_model) {
switch (type) {
case AvoidanceType::Fast: return m_avoidance_cache_to_model;
case AvoidanceType::Slow: return m_avoidance_cache_to_model_slow;
case AvoidanceType::Count: assert(false);
case AvoidanceType::FastSafe: return m_avoidance_cache_holefree_to_model;
}
} else {
switch (type) {
case AvoidanceType::Fast: return m_avoidance_cache;
case AvoidanceType::Slow: return m_avoidance_cache_slow;
case AvoidanceType::Count: assert(false);
case AvoidanceType::FastSafe: return m_avoidance_cache_holefree;
}
}
assert(false);
return m_avoidance_cache;
}
const RadiusLayerPolygonCache& avoidance_cache(const AvoidanceType type, const bool to_model) const {
return const_cast<TreeModelVolumes*>(this)->avoidance_cache(type, to_model);
}
/*!
* \brief Caches to represent walls not allowed to be passed over.
*/
RadiusLayerPolygonCache m_wall_restrictions_cache;
// A different cache for min_xy_dist as the maximal safe distance an influence area can be increased(guaranteed overlap of two walls in consecutive layer)
// is much smaller when min_xy_dist is used. This causes the area of the wall restriction to be thinner and as such just using the min_xy_dist wall
// restriction would be slower.
RadiusLayerPolygonCache m_wall_restrictions_cache_min;
#ifdef SLIC3R_TREESUPPORTS_PROGRESS
std::unique_ptr<std::mutex> m_critical_progress { std::make_unique<std::mutex>() };
#endif // SLIC3R_TREESUPPORTS_PROGRESS
};
}
#endif //slic3r_TreeModelVolumes_hpp

File diff suppressed because it is too large Load Diff

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