mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-11 00:37:51 -06:00
Merge remote-tracking branch 'origin/master' into ys_search
This commit is contained in:
commit
99d49a74d0
151 changed files with 21552 additions and 3527 deletions
|
@ -160,6 +160,9 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
# Boost on Raspberry-Pi does not link to pthreads.
|
# Boost on Raspberry-Pi does not link to pthreads.
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
|
find_package(DBus REQUIRED)
|
||||||
|
include_directories(${DBUS_INCLUDE_DIRS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX)
|
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX)
|
||||||
|
@ -369,9 +372,9 @@ include_directories(BEFORE SYSTEM ${EIGEN3_INCLUDE_DIR})
|
||||||
|
|
||||||
# Find expat or use bundled version
|
# Find expat or use bundled version
|
||||||
# Always use the system libexpat on Linux.
|
# Always use the system libexpat on Linux.
|
||||||
if (NOT SLIC3R_STATIC OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
|
||||||
find_package(EXPAT)
|
find_package(EXPAT)
|
||||||
endif ()
|
|
||||||
if (NOT EXPAT_FOUND)
|
if (NOT EXPAT_FOUND)
|
||||||
add_library(expat STATIC
|
add_library(expat STATIC
|
||||||
${LIBDIR}/expat/xmlparse.c
|
${LIBDIR}/expat/xmlparse.c
|
||||||
|
@ -382,7 +385,8 @@ if (NOT EXPAT_FOUND)
|
||||||
set(EXPAT_INCLUDE_DIRS ${LIBDIR}/expat/)
|
set(EXPAT_INCLUDE_DIRS ${LIBDIR}/expat/)
|
||||||
set(EXPAT_LIBRARIES expat)
|
set(EXPAT_LIBRARIES expat)
|
||||||
endif ()
|
endif ()
|
||||||
include_directories(${EXPAT_INCLUDE_DIRS})
|
|
||||||
|
find_package(PNG)
|
||||||
|
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
|
|
||||||
|
|
59
cmake/modules/FindDBus.cmake
Normal file
59
cmake/modules/FindDBus.cmake
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
# - Try to find DBus
|
||||||
|
# Once done, this will define
|
||||||
|
#
|
||||||
|
# DBUS_FOUND - system has DBus
|
||||||
|
# DBUS_INCLUDE_DIRS - the DBus include directories
|
||||||
|
# DBUS_LIBRARIES - link these to use DBus
|
||||||
|
#
|
||||||
|
# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
# 1. Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
|
||||||
|
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
|
||||||
|
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
FIND_PACKAGE(PkgConfig)
|
||||||
|
PKG_CHECK_MODULES(PC_DBUS QUIET dbus-1)
|
||||||
|
|
||||||
|
FIND_LIBRARY(DBUS_LIBRARIES
|
||||||
|
NAMES dbus-1
|
||||||
|
HINTS ${PC_DBUS_LIBDIR}
|
||||||
|
${PC_DBUS_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_PATH(DBUS_INCLUDE_DIR
|
||||||
|
NAMES dbus/dbus.h
|
||||||
|
HINTS ${PC_DBUS_INCLUDEDIR}
|
||||||
|
${PC_DBUS_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
GET_FILENAME_COMPONENT(_DBUS_LIBRARY_DIR ${DBUS_LIBRARIES} PATH)
|
||||||
|
FIND_PATH(DBUS_ARCH_INCLUDE_DIR
|
||||||
|
NAMES dbus/dbus-arch-deps.h
|
||||||
|
HINTS ${PC_DBUS_INCLUDEDIR}
|
||||||
|
${PC_DBUS_INCLUDE_DIRS}
|
||||||
|
${_DBUS_LIBRARY_DIR}
|
||||||
|
${DBUS_INCLUDE_DIR}
|
||||||
|
PATH_SUFFIXES include
|
||||||
|
)
|
||||||
|
|
||||||
|
SET(DBUS_INCLUDE_DIRS ${DBUS_INCLUDE_DIR} ${DBUS_ARCH_INCLUDE_DIR})
|
||||||
|
|
||||||
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(DBUS REQUIRED_VARS DBUS_INCLUDE_DIRS DBUS_LIBRARIES)
|
33
deps/CMakeLists.txt
vendored
33
deps/CMakeLists.txt
vendored
|
@ -34,8 +34,10 @@ endif ()
|
||||||
set(DESTDIR "${CMAKE_CURRENT_BINARY_DIR}/destdir" CACHE PATH "Destination directory")
|
set(DESTDIR "${CMAKE_CURRENT_BINARY_DIR}/destdir" CACHE PATH "Destination directory")
|
||||||
|
|
||||||
option(DEP_DEBUG "Build debug variants (only applicable on Windows)" ON)
|
option(DEP_DEBUG "Build debug variants (only applicable on Windows)" ON)
|
||||||
option(DEP_WX_STABLE "Build against wxWidgets stable 3.0 as opposed to default 3.1 (Linux only)" OFF)
|
|
||||||
|
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
option(DEP_WX_GTK3 "Build wxWidgets against GTK3" OFF)
|
option(DEP_WX_GTK3 "Build wxWidgets against GTK3" OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
# On developer machines, it can be enabled to speed up compilation and suppress warnings coming from IGL.
|
# On developer machines, it can be enabled to speed up compilation and suppress warnings coming from IGL.
|
||||||
# FIXME:
|
# FIXME:
|
||||||
|
@ -127,12 +129,28 @@ else()
|
||||||
include("deps-linux.cmake")
|
include("deps-linux.cmake")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(ZLIB_PKG "")
|
||||||
|
if (NOT ZLIB_FOUND)
|
||||||
|
include(ZLIB/ZLIB.cmake)
|
||||||
|
set(ZLIB_PKG dep_ZLIB)
|
||||||
|
endif ()
|
||||||
|
set(PNG_PKG "")
|
||||||
|
if (NOT PNG_FOUND)
|
||||||
|
include(PNG/PNG.cmake)
|
||||||
|
set(PNG_PKG dep_PNG)
|
||||||
|
endif ()
|
||||||
|
set(EXPAT_PKG "")
|
||||||
|
if (NOT EXPAT_FOUND)
|
||||||
|
include(EXPAT/EXPAT.cmake)
|
||||||
|
set(EXPAT_PKG dep_EXPAT)
|
||||||
|
endif ()
|
||||||
|
|
||||||
include(GLEW/GLEW.cmake)
|
include(GLEW/GLEW.cmake)
|
||||||
include(OpenCSG/OpenCSG.cmake)
|
include(OpenCSG/OpenCSG.cmake)
|
||||||
|
|
||||||
include(GMP/GMP.cmake)
|
include(GMP/GMP.cmake)
|
||||||
include(MPFR/MPFR.cmake)
|
include(MPFR/MPFR.cmake)
|
||||||
include(CGAL/CGAL.cmake)
|
include(CGAL/CGAL.cmake)
|
||||||
|
include(wxWidgets/wxWidgets.cmake)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
|
|
||||||
|
@ -141,15 +159,17 @@ if (MSVC)
|
||||||
dep_boost
|
dep_boost
|
||||||
dep_tbb
|
dep_tbb
|
||||||
dep_libcurl
|
dep_libcurl
|
||||||
dep_wxwidgets
|
dep_wxWidgets
|
||||||
dep_gtest
|
dep_gtest
|
||||||
dep_cereal
|
dep_cereal
|
||||||
dep_nlopt
|
dep_nlopt
|
||||||
# dep_qhull # Experimental
|
# dep_qhull # Experimental
|
||||||
dep_ZLIB # on Windows we still need zlib
|
|
||||||
dep_openvdb
|
dep_openvdb
|
||||||
dep_OpenCSG
|
dep_OpenCSG
|
||||||
dep_CGAL
|
dep_CGAL
|
||||||
|
${PNG_PKG}
|
||||||
|
${ZLIB_PKG}
|
||||||
|
${EXPAT_PKG}
|
||||||
)
|
)
|
||||||
|
|
||||||
else()
|
else()
|
||||||
|
@ -159,7 +179,7 @@ else()
|
||||||
dep_boost
|
dep_boost
|
||||||
dep_tbb
|
dep_tbb
|
||||||
dep_libcurl
|
dep_libcurl
|
||||||
dep_wxwidgets
|
dep_wxWidgets
|
||||||
dep_gtest
|
dep_gtest
|
||||||
dep_cereal
|
dep_cereal
|
||||||
dep_nlopt
|
dep_nlopt
|
||||||
|
@ -167,6 +187,9 @@ else()
|
||||||
dep_openvdb
|
dep_openvdb
|
||||||
dep_OpenCSG
|
dep_OpenCSG
|
||||||
dep_CGAL
|
dep_CGAL
|
||||||
|
${PNG_PKG}
|
||||||
|
${ZLIB_PKG}
|
||||||
|
${EXPAT_PKG}
|
||||||
# dep_libigl # Not working, static build has different Eigen
|
# dep_libigl # Not working, static build has different Eigen
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
9
deps/EXPAT/EXPAT.cmake
vendored
Normal file
9
deps/EXPAT/EXPAT.cmake
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
prusaslicer_add_cmake_project(EXPAT
|
||||||
|
# GIT_REPOSITORY https://github.com/nigels-com/glew.git
|
||||||
|
# GIT_TAG 3a8eff7 # 2.1.0
|
||||||
|
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/expat
|
||||||
|
)
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
add_debug_dep(dep_EXPAT)
|
||||||
|
endif ()
|
71
deps/EXPAT/expat/CMakeLists.txt
vendored
Normal file
71
deps/EXPAT/expat/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
|
||||||
|
project(EXPAT)
|
||||||
|
|
||||||
|
if (BUILD_SHARED_LIBS AND MSVC)
|
||||||
|
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(expat
|
||||||
|
xmlparse.c
|
||||||
|
xmlrole.c
|
||||||
|
xmltok.c
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(expat PRIVATE ${PROJECT_SOURCE_DIR})
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
${PROJECT_SOURCE_DIR}/expat.h
|
||||||
|
${PROJECT_SOURCE_DIR}/expat_config.h
|
||||||
|
${PROJECT_SOURCE_DIR}/expat_external.h
|
||||||
|
DESTINATION
|
||||||
|
${CMAKE_INSTALL_INCLUDEDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(EXPAT INTERFACE)
|
||||||
|
target_link_libraries(EXPAT INTERFACE expat)
|
||||||
|
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
|
write_basic_package_version_file(
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||||
|
VERSION 1.95
|
||||||
|
COMPATIBILITY AnyNewerVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS expat EXPAT
|
||||||
|
EXPORT ${PROJECT_NAME}Targets
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
export(EXPORT ${PROJECT_NAME}Targets
|
||||||
|
FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake"
|
||||||
|
NAMESPACE ${PROJECT_NAME}:: )
|
||||||
|
|
||||||
|
set(ConfigPackageLocation ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
||||||
|
|
||||||
|
install(EXPORT ${PROJECT_NAME}Targets
|
||||||
|
FILE
|
||||||
|
"${PROJECT_NAME}Targets.cmake"
|
||||||
|
NAMESPACE
|
||||||
|
${PROJECT_NAME}::
|
||||||
|
DESTINATION
|
||||||
|
${ConfigPackageLocation}
|
||||||
|
)
|
||||||
|
|
||||||
|
configure_file(config.cmake.in ${PROJECT_NAME}Config.cmake @ONLY)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||||
|
DESTINATION
|
||||||
|
${ConfigPackageLocation}
|
||||||
|
)
|
||||||
|
|
21
deps/EXPAT/expat/COPYING
vendored
Normal file
21
deps/EXPAT/expat/COPYING
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper
|
||||||
|
Copyright (c) 2001-2016 Expat maintainers
|
||||||
|
|
||||||
|
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.
|
146
deps/EXPAT/expat/README
vendored
Normal file
146
deps/EXPAT/expat/README
vendored
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
Expat, Release 2.2.0, stripped and modified for inclusion into Slic3r.
|
||||||
|
Only the library sources needed for static linking were left.
|
||||||
|
|
||||||
|
The original README follows:
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Expat, Release 2.2.0
|
||||||
|
|
||||||
|
This is Expat, a C library for parsing XML, written by James Clark.
|
||||||
|
Expat is a stream-oriented XML parser. This means that you register
|
||||||
|
handlers with the parser before starting the parse. These handlers
|
||||||
|
are called when the parser discovers the associated structures in the
|
||||||
|
document being parsed. A start tag is an example of the kind of
|
||||||
|
structures for which you may register handlers.
|
||||||
|
|
||||||
|
Windows users should use the expat_win32bin package, which includes
|
||||||
|
both precompiled libraries and executables, and source code for
|
||||||
|
developers.
|
||||||
|
|
||||||
|
Expat is free software. You may copy, distribute, and modify it under
|
||||||
|
the terms of the License contained in the file COPYING distributed
|
||||||
|
with this package. This license is the same as the MIT/X Consortium
|
||||||
|
license.
|
||||||
|
|
||||||
|
Versions of Expat that have an odd minor version (the middle number in
|
||||||
|
the release above), are development releases and should be considered
|
||||||
|
as beta software. Releases with even minor version numbers are
|
||||||
|
intended to be production grade software.
|
||||||
|
|
||||||
|
If you are building Expat from a check-out from the CVS repository,
|
||||||
|
you need to run a script that generates the configure script using the
|
||||||
|
GNU autoconf and libtool tools. To do this, you need to have
|
||||||
|
autoconf 2.58 or newer. Run the script like this:
|
||||||
|
|
||||||
|
./buildconf.sh
|
||||||
|
|
||||||
|
Once this has been done, follow the same instructions as for building
|
||||||
|
from a source distribution.
|
||||||
|
|
||||||
|
To build Expat from a source distribution, you first run the
|
||||||
|
configuration shell script in the top level distribution directory:
|
||||||
|
|
||||||
|
./configure
|
||||||
|
|
||||||
|
There are many options which you may provide to configure (which you
|
||||||
|
can discover by running configure with the --help option). But the
|
||||||
|
one of most interest is the one that sets the installation directory.
|
||||||
|
By default, the configure script will set things up to install
|
||||||
|
libexpat into /usr/local/lib, expat.h into /usr/local/include, and
|
||||||
|
xmlwf into /usr/local/bin. If, for example, you'd prefer to install
|
||||||
|
into /home/me/mystuff/lib, /home/me/mystuff/include, and
|
||||||
|
/home/me/mystuff/bin, you can tell configure about that with:
|
||||||
|
|
||||||
|
./configure --prefix=/home/me/mystuff
|
||||||
|
|
||||||
|
Another interesting option is to enable 64-bit integer support for
|
||||||
|
line and column numbers and the over-all byte index:
|
||||||
|
|
||||||
|
./configure CPPFLAGS=-DXML_LARGE_SIZE
|
||||||
|
|
||||||
|
However, such a modification would be a breaking change to the ABI
|
||||||
|
and is therefore not recommended for general use - e.g. as part of
|
||||||
|
a Linux distribution - but rather for builds with special requirements.
|
||||||
|
|
||||||
|
After running the configure script, the "make" command will build
|
||||||
|
things and "make install" will install things into their proper
|
||||||
|
location. Have a look at the "Makefile" to learn about additional
|
||||||
|
"make" options. Note that you need to have write permission into
|
||||||
|
the directories into which things will be installed.
|
||||||
|
|
||||||
|
If you are interested in building Expat to provide document
|
||||||
|
information in UTF-16 encoding rather than the default UTF-8, follow
|
||||||
|
these instructions (after having run "make distclean"):
|
||||||
|
|
||||||
|
1. For UTF-16 output as unsigned short (and version/error
|
||||||
|
strings as char), run:
|
||||||
|
|
||||||
|
./configure CPPFLAGS=-DXML_UNICODE
|
||||||
|
|
||||||
|
For UTF-16 output as wchar_t (incl. version/error strings),
|
||||||
|
run:
|
||||||
|
|
||||||
|
./configure CFLAGS="-g -O2 -fshort-wchar" \
|
||||||
|
CPPFLAGS=-DXML_UNICODE_WCHAR_T
|
||||||
|
|
||||||
|
2. Edit the MakeFile, changing:
|
||||||
|
|
||||||
|
LIBRARY = libexpat.la
|
||||||
|
|
||||||
|
to:
|
||||||
|
|
||||||
|
LIBRARY = libexpatw.la
|
||||||
|
|
||||||
|
(Note the additional "w" in the library name.)
|
||||||
|
|
||||||
|
3. Run "make buildlib" (which builds the library only).
|
||||||
|
Or, to save step 2, run "make buildlib LIBRARY=libexpatw.la".
|
||||||
|
|
||||||
|
4. Run "make installlib" (which installs the library only).
|
||||||
|
Or, if step 2 was omitted, run "make installlib LIBRARY=libexpatw.la".
|
||||||
|
|
||||||
|
Using DESTDIR or INSTALL_ROOT is enabled, with INSTALL_ROOT being the default
|
||||||
|
value for DESTDIR, and the rest of the make file using only DESTDIR.
|
||||||
|
It works as follows:
|
||||||
|
$ make install DESTDIR=/path/to/image
|
||||||
|
overrides the in-makefile set DESTDIR, while both
|
||||||
|
$ INSTALL_ROOT=/path/to/image make install
|
||||||
|
$ make install INSTALL_ROOT=/path/to/image
|
||||||
|
use DESTDIR=$(INSTALL_ROOT), even if DESTDIR eventually is defined in the
|
||||||
|
environment, because variable-setting priority is
|
||||||
|
1) commandline
|
||||||
|
2) in-makefile
|
||||||
|
3) environment
|
||||||
|
|
||||||
|
Note: This only applies to the Expat library itself, building UTF-16 versions
|
||||||
|
of xmlwf and the tests is currently not supported.
|
||||||
|
|
||||||
|
Note for Solaris users: The "ar" command is usually located in
|
||||||
|
"/usr/ccs/bin", which is not in the default PATH. You will need to
|
||||||
|
add this to your path for the "make" command, and probably also switch
|
||||||
|
to GNU make (the "make" found in /usr/ccs/bin does not seem to work
|
||||||
|
properly -- apparently it does not understand .PHONY directives). If
|
||||||
|
you're using ksh or bash, use this command to build:
|
||||||
|
|
||||||
|
PATH=/usr/ccs/bin:$PATH make
|
||||||
|
|
||||||
|
When using Expat with a project using autoconf for configuration, you
|
||||||
|
can use the probing macro in conftools/expat.m4 to determine how to
|
||||||
|
include Expat. See the comments at the top of that file for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
A reference manual is available in the file doc/reference.html in this
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
The homepage for this project is http://www.libexpat.org/. There
|
||||||
|
are links there to connect you to the bug reports page. If you need
|
||||||
|
to report a bug when you don't have access to a browser, you may also
|
||||||
|
send a bug report by email to expat-bugs@mail.libexpat.org.
|
||||||
|
|
||||||
|
Discussion related to the direction of future expat development takes
|
||||||
|
place on expat-discuss@mail.libexpat.org. Archives of this list and
|
||||||
|
other Expat-related lists may be found at:
|
||||||
|
|
||||||
|
http://mail.libexpat.org/mailman/listinfo/
|
92
deps/EXPAT/expat/ascii.h
vendored
Normal file
92
deps/EXPAT/expat/ascii.h
vendored
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||||
|
See the file COPYING for copying permission.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ASCII_A 0x41
|
||||||
|
#define ASCII_B 0x42
|
||||||
|
#define ASCII_C 0x43
|
||||||
|
#define ASCII_D 0x44
|
||||||
|
#define ASCII_E 0x45
|
||||||
|
#define ASCII_F 0x46
|
||||||
|
#define ASCII_G 0x47
|
||||||
|
#define ASCII_H 0x48
|
||||||
|
#define ASCII_I 0x49
|
||||||
|
#define ASCII_J 0x4A
|
||||||
|
#define ASCII_K 0x4B
|
||||||
|
#define ASCII_L 0x4C
|
||||||
|
#define ASCII_M 0x4D
|
||||||
|
#define ASCII_N 0x4E
|
||||||
|
#define ASCII_O 0x4F
|
||||||
|
#define ASCII_P 0x50
|
||||||
|
#define ASCII_Q 0x51
|
||||||
|
#define ASCII_R 0x52
|
||||||
|
#define ASCII_S 0x53
|
||||||
|
#define ASCII_T 0x54
|
||||||
|
#define ASCII_U 0x55
|
||||||
|
#define ASCII_V 0x56
|
||||||
|
#define ASCII_W 0x57
|
||||||
|
#define ASCII_X 0x58
|
||||||
|
#define ASCII_Y 0x59
|
||||||
|
#define ASCII_Z 0x5A
|
||||||
|
|
||||||
|
#define ASCII_a 0x61
|
||||||
|
#define ASCII_b 0x62
|
||||||
|
#define ASCII_c 0x63
|
||||||
|
#define ASCII_d 0x64
|
||||||
|
#define ASCII_e 0x65
|
||||||
|
#define ASCII_f 0x66
|
||||||
|
#define ASCII_g 0x67
|
||||||
|
#define ASCII_h 0x68
|
||||||
|
#define ASCII_i 0x69
|
||||||
|
#define ASCII_j 0x6A
|
||||||
|
#define ASCII_k 0x6B
|
||||||
|
#define ASCII_l 0x6C
|
||||||
|
#define ASCII_m 0x6D
|
||||||
|
#define ASCII_n 0x6E
|
||||||
|
#define ASCII_o 0x6F
|
||||||
|
#define ASCII_p 0x70
|
||||||
|
#define ASCII_q 0x71
|
||||||
|
#define ASCII_r 0x72
|
||||||
|
#define ASCII_s 0x73
|
||||||
|
#define ASCII_t 0x74
|
||||||
|
#define ASCII_u 0x75
|
||||||
|
#define ASCII_v 0x76
|
||||||
|
#define ASCII_w 0x77
|
||||||
|
#define ASCII_x 0x78
|
||||||
|
#define ASCII_y 0x79
|
||||||
|
#define ASCII_z 0x7A
|
||||||
|
|
||||||
|
#define ASCII_0 0x30
|
||||||
|
#define ASCII_1 0x31
|
||||||
|
#define ASCII_2 0x32
|
||||||
|
#define ASCII_3 0x33
|
||||||
|
#define ASCII_4 0x34
|
||||||
|
#define ASCII_5 0x35
|
||||||
|
#define ASCII_6 0x36
|
||||||
|
#define ASCII_7 0x37
|
||||||
|
#define ASCII_8 0x38
|
||||||
|
#define ASCII_9 0x39
|
||||||
|
|
||||||
|
#define ASCII_TAB 0x09
|
||||||
|
#define ASCII_SPACE 0x20
|
||||||
|
#define ASCII_EXCL 0x21
|
||||||
|
#define ASCII_QUOT 0x22
|
||||||
|
#define ASCII_AMP 0x26
|
||||||
|
#define ASCII_APOS 0x27
|
||||||
|
#define ASCII_MINUS 0x2D
|
||||||
|
#define ASCII_PERIOD 0x2E
|
||||||
|
#define ASCII_COLON 0x3A
|
||||||
|
#define ASCII_SEMI 0x3B
|
||||||
|
#define ASCII_LT 0x3C
|
||||||
|
#define ASCII_EQUALS 0x3D
|
||||||
|
#define ASCII_GT 0x3E
|
||||||
|
#define ASCII_LSQB 0x5B
|
||||||
|
#define ASCII_RSQB 0x5D
|
||||||
|
#define ASCII_UNDERSCORE 0x5F
|
||||||
|
#define ASCII_LPAREN 0x28
|
||||||
|
#define ASCII_RPAREN 0x29
|
||||||
|
#define ASCII_FF 0x0C
|
||||||
|
#define ASCII_SLASH 0x2F
|
||||||
|
#define ASCII_HASH 0x23
|
||||||
|
#define ASCII_PIPE 0x7C
|
||||||
|
#define ASCII_COMMA 0x2C
|
36
deps/EXPAT/expat/asciitab.h
vendored
Normal file
36
deps/EXPAT/expat/asciitab.h
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||||
|
See the file COPYING for copying permission.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
|
||||||
|
/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
|
||||||
|
/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
|
||||||
|
/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
|
||||||
|
/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
|
||||||
|
/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
|
||||||
|
/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
|
||||||
|
/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
|
||||||
|
/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
|
||||||
|
/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
|
||||||
|
/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
|
||||||
|
/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
|
||||||
|
/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
|
||||||
|
/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
|
||||||
|
/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
|
||||||
|
/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
|
||||||
|
/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
|
4
deps/EXPAT/expat/config.cmake.in
vendored
Normal file
4
deps/EXPAT/expat/config.cmake.in
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
include(${CMAKE_CURRENT_LIST_DIR}/EXPATTargets.cmake)
|
||||||
|
set(EXPAT_LIBRARIES EXPAT::expat)
|
||||||
|
set(EXPAT_INCLUDE_DIRS ${_IMPORT_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
|
|
1048
deps/EXPAT/expat/expat.h
vendored
Normal file
1048
deps/EXPAT/expat/expat.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
33
deps/EXPAT/expat/expat_config.h
vendored
Normal file
33
deps/EXPAT/expat/expat_config.h
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*================================================================
|
||||||
|
** Copyright 2000, Clark Cooper
|
||||||
|
** All rights reserved.
|
||||||
|
**
|
||||||
|
** This is free software. You are permitted to copy, distribute, or modify
|
||||||
|
** it under the terms of the MIT/X license (contained in the COPYING file
|
||||||
|
** with this distribution.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EXPATCONFIG_H
|
||||||
|
#define EXPATCONFIG_H
|
||||||
|
|
||||||
|
#include <memory.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define XML_NS 1
|
||||||
|
#define XML_DTD 1
|
||||||
|
#define XML_CONTEXT_BYTES 1024
|
||||||
|
|
||||||
|
/* we will assume all Windows platforms are little endian */
|
||||||
|
#define BYTEORDER 1234
|
||||||
|
|
||||||
|
/* Windows has memmove() available. */
|
||||||
|
#define HAVE_MEMMOVE
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#undef WIN32_LEAN_AND_MEAN
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ifndef EXPATCONFIG_H */
|
129
deps/EXPAT/expat/expat_external.h
vendored
Normal file
129
deps/EXPAT/expat/expat_external.h
vendored
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
|
||||||
|
See the file COPYING for copying permission.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef Expat_External_INCLUDED
|
||||||
|
#define Expat_External_INCLUDED 1
|
||||||
|
|
||||||
|
/* External API definitions */
|
||||||
|
|
||||||
|
#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__)
|
||||||
|
#define XML_USE_MSC_EXTENSIONS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Expat tries very hard to make the API boundary very specifically
|
||||||
|
defined. There are two macros defined to control this boundary;
|
||||||
|
each of these can be defined before including this header to
|
||||||
|
achieve some different behavior, but doing so it not recommended or
|
||||||
|
tested frequently.
|
||||||
|
|
||||||
|
XMLCALL - The calling convention to use for all calls across the
|
||||||
|
"library boundary." This will default to cdecl, and
|
||||||
|
try really hard to tell the compiler that's what we
|
||||||
|
want.
|
||||||
|
|
||||||
|
XMLIMPORT - Whatever magic is needed to note that a function is
|
||||||
|
to be imported from a dynamically loaded library
|
||||||
|
(.dll, .so, or .sl, depending on your platform).
|
||||||
|
|
||||||
|
The XMLCALL macro was added in Expat 1.95.7. The only one which is
|
||||||
|
expected to be directly useful in client code is XMLCALL.
|
||||||
|
|
||||||
|
Note that on at least some Unix versions, the Expat library must be
|
||||||
|
compiled with the cdecl calling convention as the default since
|
||||||
|
system headers may assume the cdecl convention.
|
||||||
|
*/
|
||||||
|
#ifndef XMLCALL
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define XMLCALL __cdecl
|
||||||
|
#elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER)
|
||||||
|
#define XMLCALL __attribute__((cdecl))
|
||||||
|
#else
|
||||||
|
/* For any platform which uses this definition and supports more than
|
||||||
|
one calling convention, we need to extend this definition to
|
||||||
|
declare the convention used on that platform, if it's possible to
|
||||||
|
do so.
|
||||||
|
|
||||||
|
If this is the case for your platform, please file a bug report
|
||||||
|
with information on how to identify your platform via the C
|
||||||
|
pre-processor and how to specify the same calling convention as the
|
||||||
|
platform's malloc() implementation.
|
||||||
|
*/
|
||||||
|
#define XMLCALL
|
||||||
|
#endif
|
||||||
|
#endif /* not defined XMLCALL */
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(XML_STATIC) && !defined(XMLIMPORT)
|
||||||
|
#ifndef XML_BUILDING_EXPAT
|
||||||
|
/* using Expat from an application */
|
||||||
|
|
||||||
|
#ifdef XML_USE_MSC_EXTENSIONS
|
||||||
|
// #define XMLIMPORT __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif /* not defined XML_STATIC */
|
||||||
|
|
||||||
|
#if !defined(XMLIMPORT) && defined(__GNUC__) && (__GNUC__ >= 4)
|
||||||
|
#define XMLIMPORT __attribute__ ((visibility ("default")))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If we didn't define it above, define it away: */
|
||||||
|
#ifndef XMLIMPORT
|
||||||
|
#define XMLIMPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
|
||||||
|
#define XML_ATTR_MALLOC __attribute__((__malloc__))
|
||||||
|
#else
|
||||||
|
#define XML_ATTR_MALLOC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
|
||||||
|
#define XML_ATTR_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
|
||||||
|
#else
|
||||||
|
#define XML_ATTR_ALLOC_SIZE(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XML_UNICODE_WCHAR_T
|
||||||
|
#define XML_UNICODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XML_UNICODE /* Information is UTF-16 encoded. */
|
||||||
|
#ifdef XML_UNICODE_WCHAR_T
|
||||||
|
typedef wchar_t XML_Char;
|
||||||
|
typedef wchar_t XML_LChar;
|
||||||
|
#else
|
||||||
|
typedef unsigned short XML_Char;
|
||||||
|
typedef char XML_LChar;
|
||||||
|
#endif /* XML_UNICODE_WCHAR_T */
|
||||||
|
#else /* Information is UTF-8 encoded. */
|
||||||
|
typedef char XML_Char;
|
||||||
|
typedef char XML_LChar;
|
||||||
|
#endif /* XML_UNICODE */
|
||||||
|
|
||||||
|
#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */
|
||||||
|
#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
|
||||||
|
typedef __int64 XML_Index;
|
||||||
|
typedef unsigned __int64 XML_Size;
|
||||||
|
#else
|
||||||
|
typedef long long XML_Index;
|
||||||
|
typedef unsigned long long XML_Size;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
typedef long XML_Index;
|
||||||
|
typedef unsigned long XML_Size;
|
||||||
|
#endif /* XML_LARGE_SIZE */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* not Expat_External_INCLUDED */
|
37
deps/EXPAT/expat/iasciitab.h
vendored
Normal file
37
deps/EXPAT/expat/iasciitab.h
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||||
|
See the file COPYING for copying permission.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */
|
||||||
|
/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
|
||||||
|
/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
|
||||||
|
/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
|
||||||
|
/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
|
||||||
|
/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
|
||||||
|
/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
|
||||||
|
/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
|
||||||
|
/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
|
||||||
|
/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
|
||||||
|
/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
|
||||||
|
/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
|
||||||
|
/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
|
||||||
|
/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
|
||||||
|
/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
|
||||||
|
/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
|
||||||
|
/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
|
||||||
|
/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
|
95
deps/EXPAT/expat/internal.h
vendored
Normal file
95
deps/EXPAT/expat/internal.h
vendored
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
/* internal.h
|
||||||
|
|
||||||
|
Internal definitions used by Expat. This is not needed to compile
|
||||||
|
client code.
|
||||||
|
|
||||||
|
The following calling convention macros are defined for frequently
|
||||||
|
called functions:
|
||||||
|
|
||||||
|
FASTCALL - Used for those internal functions that have a simple
|
||||||
|
body and a low number of arguments and local variables.
|
||||||
|
|
||||||
|
PTRCALL - Used for functions called though function pointers.
|
||||||
|
|
||||||
|
PTRFASTCALL - Like PTRCALL, but for low number of arguments.
|
||||||
|
|
||||||
|
inline - Used for selected internal functions for which inlining
|
||||||
|
may improve performance on some platforms.
|
||||||
|
|
||||||
|
Note: Use of these macros is based on judgement, not hard rules,
|
||||||
|
and therefore subject to change.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && defined(__i386__) && !defined(__MINGW32__)
|
||||||
|
/* We'll use this version by default only where we know it helps.
|
||||||
|
|
||||||
|
regparm() generates warnings on Solaris boxes. See SF bug #692878.
|
||||||
|
|
||||||
|
Instability reported with egcs on a RedHat Linux 7.3.
|
||||||
|
Let's comment out:
|
||||||
|
#define FASTCALL __attribute__((stdcall, regparm(3)))
|
||||||
|
and let's try this:
|
||||||
|
*/
|
||||||
|
#define FASTCALL __attribute__((regparm(3)))
|
||||||
|
#define PTRFASTCALL __attribute__((regparm(3)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Using __fastcall seems to have an unexpected negative effect under
|
||||||
|
MS VC++, especially for function pointers, so we won't use it for
|
||||||
|
now on that platform. It may be reconsidered for a future release
|
||||||
|
if it can be made more effective.
|
||||||
|
Likely reason: __fastcall on Windows is like stdcall, therefore
|
||||||
|
the compiler cannot perform stack optimizations for call clusters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Make sure all of these are defined if they aren't already. */
|
||||||
|
|
||||||
|
#ifndef FASTCALL
|
||||||
|
#define FASTCALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PTRCALL
|
||||||
|
#define PTRCALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PTRFASTCALL
|
||||||
|
#define PTRFASTCALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef XML_MIN_SIZE
|
||||||
|
#if !defined(__cplusplus) && !defined(inline)
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define inline __inline
|
||||||
|
#endif /* __GNUC__ */
|
||||||
|
#endif
|
||||||
|
#endif /* XML_MIN_SIZE */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define inline inline
|
||||||
|
#else
|
||||||
|
#ifndef inline
|
||||||
|
#define inline
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef UNUSED_P
|
||||||
|
# ifdef __GNUC__
|
||||||
|
# define UNUSED_P(p) UNUSED_ ## p __attribute__((__unused__))
|
||||||
|
# else
|
||||||
|
# define UNUSED_P(p) UNUSED_ ## p
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
align_limit_to_full_utf8_characters(const char * from, const char ** fromLimRef);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
36
deps/EXPAT/expat/latin1tab.h
vendored
Normal file
36
deps/EXPAT/expat/latin1tab.h
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||||
|
See the file COPYING for copying permission.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||||
|
/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||||
|
/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||||
|
/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||||
|
/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||||
|
/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||||
|
/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||||
|
/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||||
|
/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||||
|
/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||||
|
/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
|
||||||
|
/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||||
|
/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||||
|
/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME,
|
||||||
|
/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
|
||||||
|
/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||||
|
/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
|
||||||
|
/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
|
||||||
|
/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||||
|
/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
150
deps/EXPAT/expat/nametab.h
vendored
Normal file
150
deps/EXPAT/expat/nametab.h
vendored
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
static const unsigned namingBitmap[] = {
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||||
|
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||||
|
0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE,
|
||||||
|
0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF,
|
||||||
|
0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF,
|
||||||
|
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF,
|
||||||
|
0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
|
||||||
|
0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
|
||||||
|
0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
|
||||||
|
0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
|
||||||
|
0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
|
||||||
|
0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF,
|
||||||
|
0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000,
|
||||||
|
0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060,
|
||||||
|
0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003,
|
||||||
|
0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003,
|
||||||
|
0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000,
|
||||||
|
0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001,
|
||||||
|
0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003,
|
||||||
|
0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000,
|
||||||
|
0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003,
|
||||||
|
0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003,
|
||||||
|
0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000,
|
||||||
|
0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF,
|
||||||
|
0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB,
|
||||||
|
0x40000000, 0xF580C900, 0x00000007, 0x02010800,
|
||||||
|
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||||
|
0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF,
|
||||||
|
0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF,
|
||||||
|
0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF,
|
||||||
|
0x00000000, 0x00004C40, 0x00000000, 0x00000000,
|
||||||
|
0x00000007, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF,
|
||||||
|
0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF,
|
||||||
|
0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||||
|
0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000,
|
||||||
|
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||||
|
0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE,
|
||||||
|
0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF,
|
||||||
|
0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
|
||||||
|
0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000,
|
||||||
|
0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003,
|
||||||
|
0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
|
||||||
|
0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
|
||||||
|
0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
|
||||||
|
0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
|
||||||
|
0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF,
|
||||||
|
0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF,
|
||||||
|
0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF,
|
||||||
|
0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF,
|
||||||
|
0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF,
|
||||||
|
0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0,
|
||||||
|
0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1,
|
||||||
|
0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3,
|
||||||
|
0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80,
|
||||||
|
0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3,
|
||||||
|
0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3,
|
||||||
|
0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000,
|
||||||
|
0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000,
|
||||||
|
0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF,
|
||||||
|
0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x1FFF0000, 0x00000002,
|
||||||
|
0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF,
|
||||||
|
0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF,
|
||||||
|
};
|
||||||
|
static const unsigned char nmstrtPages[] = {
|
||||||
|
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00,
|
||||||
|
0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||||
|
0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
|
||||||
|
0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
static const unsigned char namePages[] = {
|
||||||
|
0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00,
|
||||||
|
0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
|
||||||
|
0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
|
||||||
|
0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
};
|
37
deps/EXPAT/expat/utf8tab.h
vendored
Normal file
37
deps/EXPAT/expat/utf8tab.h
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||||
|
See the file COPYING for copying permission.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||||
|
/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||||
|
/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||||
|
/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||||
|
/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||||
|
/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||||
|
/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||||
|
/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||||
|
/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||||
|
/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
|
||||||
|
/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
|
||||||
|
/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
|
||||||
|
/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
|
||||||
|
/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4,
|
||||||
|
/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||||
|
/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM,
|
6458
deps/EXPAT/expat/xmlparse.c
vendored
Normal file
6458
deps/EXPAT/expat/xmlparse.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
1322
deps/EXPAT/expat/xmlrole.c
vendored
Normal file
1322
deps/EXPAT/expat/xmlrole.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
114
deps/EXPAT/expat/xmlrole.h
vendored
Normal file
114
deps/EXPAT/expat/xmlrole.h
vendored
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||||
|
See the file COPYING for copying permission.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XmlRole_INCLUDED
|
||||||
|
#define XmlRole_INCLUDED 1
|
||||||
|
|
||||||
|
#ifdef __VMS
|
||||||
|
/* 0 1 2 3 0 1 2 3
|
||||||
|
1234567890123456789012345678901 1234567890123456789012345678901 */
|
||||||
|
#define XmlPrologStateInitExternalEntity XmlPrologStateInitExternalEnt
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "xmltok.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum {
|
||||||
|
XML_ROLE_ERROR = -1,
|
||||||
|
XML_ROLE_NONE = 0,
|
||||||
|
XML_ROLE_XML_DECL,
|
||||||
|
XML_ROLE_INSTANCE_START,
|
||||||
|
XML_ROLE_DOCTYPE_NONE,
|
||||||
|
XML_ROLE_DOCTYPE_NAME,
|
||||||
|
XML_ROLE_DOCTYPE_SYSTEM_ID,
|
||||||
|
XML_ROLE_DOCTYPE_PUBLIC_ID,
|
||||||
|
XML_ROLE_DOCTYPE_INTERNAL_SUBSET,
|
||||||
|
XML_ROLE_DOCTYPE_CLOSE,
|
||||||
|
XML_ROLE_GENERAL_ENTITY_NAME,
|
||||||
|
XML_ROLE_PARAM_ENTITY_NAME,
|
||||||
|
XML_ROLE_ENTITY_NONE,
|
||||||
|
XML_ROLE_ENTITY_VALUE,
|
||||||
|
XML_ROLE_ENTITY_SYSTEM_ID,
|
||||||
|
XML_ROLE_ENTITY_PUBLIC_ID,
|
||||||
|
XML_ROLE_ENTITY_COMPLETE,
|
||||||
|
XML_ROLE_ENTITY_NOTATION_NAME,
|
||||||
|
XML_ROLE_NOTATION_NONE,
|
||||||
|
XML_ROLE_NOTATION_NAME,
|
||||||
|
XML_ROLE_NOTATION_SYSTEM_ID,
|
||||||
|
XML_ROLE_NOTATION_NO_SYSTEM_ID,
|
||||||
|
XML_ROLE_NOTATION_PUBLIC_ID,
|
||||||
|
XML_ROLE_ATTRIBUTE_NAME,
|
||||||
|
XML_ROLE_ATTRIBUTE_TYPE_CDATA,
|
||||||
|
XML_ROLE_ATTRIBUTE_TYPE_ID,
|
||||||
|
XML_ROLE_ATTRIBUTE_TYPE_IDREF,
|
||||||
|
XML_ROLE_ATTRIBUTE_TYPE_IDREFS,
|
||||||
|
XML_ROLE_ATTRIBUTE_TYPE_ENTITY,
|
||||||
|
XML_ROLE_ATTRIBUTE_TYPE_ENTITIES,
|
||||||
|
XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN,
|
||||||
|
XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS,
|
||||||
|
XML_ROLE_ATTRIBUTE_ENUM_VALUE,
|
||||||
|
XML_ROLE_ATTRIBUTE_NOTATION_VALUE,
|
||||||
|
XML_ROLE_ATTLIST_NONE,
|
||||||
|
XML_ROLE_ATTLIST_ELEMENT_NAME,
|
||||||
|
XML_ROLE_IMPLIED_ATTRIBUTE_VALUE,
|
||||||
|
XML_ROLE_REQUIRED_ATTRIBUTE_VALUE,
|
||||||
|
XML_ROLE_DEFAULT_ATTRIBUTE_VALUE,
|
||||||
|
XML_ROLE_FIXED_ATTRIBUTE_VALUE,
|
||||||
|
XML_ROLE_ELEMENT_NONE,
|
||||||
|
XML_ROLE_ELEMENT_NAME,
|
||||||
|
XML_ROLE_CONTENT_ANY,
|
||||||
|
XML_ROLE_CONTENT_EMPTY,
|
||||||
|
XML_ROLE_CONTENT_PCDATA,
|
||||||
|
XML_ROLE_GROUP_OPEN,
|
||||||
|
XML_ROLE_GROUP_CLOSE,
|
||||||
|
XML_ROLE_GROUP_CLOSE_REP,
|
||||||
|
XML_ROLE_GROUP_CLOSE_OPT,
|
||||||
|
XML_ROLE_GROUP_CLOSE_PLUS,
|
||||||
|
XML_ROLE_GROUP_CHOICE,
|
||||||
|
XML_ROLE_GROUP_SEQUENCE,
|
||||||
|
XML_ROLE_CONTENT_ELEMENT,
|
||||||
|
XML_ROLE_CONTENT_ELEMENT_REP,
|
||||||
|
XML_ROLE_CONTENT_ELEMENT_OPT,
|
||||||
|
XML_ROLE_CONTENT_ELEMENT_PLUS,
|
||||||
|
XML_ROLE_PI,
|
||||||
|
XML_ROLE_COMMENT,
|
||||||
|
#ifdef XML_DTD
|
||||||
|
XML_ROLE_TEXT_DECL,
|
||||||
|
XML_ROLE_IGNORE_SECT,
|
||||||
|
XML_ROLE_INNER_PARAM_ENTITY_REF,
|
||||||
|
#endif /* XML_DTD */
|
||||||
|
XML_ROLE_PARAM_ENTITY_REF
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct prolog_state {
|
||||||
|
int (PTRCALL *handler) (struct prolog_state *state,
|
||||||
|
int tok,
|
||||||
|
const char *ptr,
|
||||||
|
const char *end,
|
||||||
|
const ENCODING *enc);
|
||||||
|
unsigned level;
|
||||||
|
int role_none;
|
||||||
|
#ifdef XML_DTD
|
||||||
|
unsigned includeLevel;
|
||||||
|
int documentEntity;
|
||||||
|
int inEntityValue;
|
||||||
|
#endif /* XML_DTD */
|
||||||
|
} PROLOG_STATE;
|
||||||
|
|
||||||
|
void XmlPrologStateInit(PROLOG_STATE *);
|
||||||
|
#ifdef XML_DTD
|
||||||
|
void XmlPrologStateInitExternalEntity(PROLOG_STATE *);
|
||||||
|
#endif /* XML_DTD */
|
||||||
|
|
||||||
|
#define XmlTokenRole(state, tok, ptr, end, enc) \
|
||||||
|
(((state)->handler)(state, tok, ptr, end, enc))
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* not XmlRole_INCLUDED */
|
1737
deps/EXPAT/expat/xmltok.c
vendored
Normal file
1737
deps/EXPAT/expat/xmltok.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
322
deps/EXPAT/expat/xmltok.h
vendored
Normal file
322
deps/EXPAT/expat/xmltok.h
vendored
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||||
|
See the file COPYING for copying permission.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XmlTok_INCLUDED
|
||||||
|
#define XmlTok_INCLUDED 1
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The following token may be returned by XmlContentTok */
|
||||||
|
#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be
|
||||||
|
start of illegal ]]> sequence */
|
||||||
|
/* The following tokens may be returned by both XmlPrologTok and
|
||||||
|
XmlContentTok.
|
||||||
|
*/
|
||||||
|
#define XML_TOK_NONE -4 /* The string to be scanned is empty */
|
||||||
|
#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan;
|
||||||
|
might be part of CRLF sequence */
|
||||||
|
#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */
|
||||||
|
#define XML_TOK_PARTIAL -1 /* only part of a token */
|
||||||
|
#define XML_TOK_INVALID 0
|
||||||
|
|
||||||
|
/* The following tokens are returned by XmlContentTok; some are also
|
||||||
|
returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok.
|
||||||
|
*/
|
||||||
|
#define XML_TOK_START_TAG_WITH_ATTS 1
|
||||||
|
#define XML_TOK_START_TAG_NO_ATTS 2
|
||||||
|
#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag <e/> */
|
||||||
|
#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4
|
||||||
|
#define XML_TOK_END_TAG 5
|
||||||
|
#define XML_TOK_DATA_CHARS 6
|
||||||
|
#define XML_TOK_DATA_NEWLINE 7
|
||||||
|
#define XML_TOK_CDATA_SECT_OPEN 8
|
||||||
|
#define XML_TOK_ENTITY_REF 9
|
||||||
|
#define XML_TOK_CHAR_REF 10 /* numeric character reference */
|
||||||
|
|
||||||
|
/* The following tokens may be returned by both XmlPrologTok and
|
||||||
|
XmlContentTok.
|
||||||
|
*/
|
||||||
|
#define XML_TOK_PI 11 /* processing instruction */
|
||||||
|
#define XML_TOK_XML_DECL 12 /* XML decl or text decl */
|
||||||
|
#define XML_TOK_COMMENT 13
|
||||||
|
#define XML_TOK_BOM 14 /* Byte order mark */
|
||||||
|
|
||||||
|
/* The following tokens are returned only by XmlPrologTok */
|
||||||
|
#define XML_TOK_PROLOG_S 15
|
||||||
|
#define XML_TOK_DECL_OPEN 16 /* <!foo */
|
||||||
|
#define XML_TOK_DECL_CLOSE 17 /* > */
|
||||||
|
#define XML_TOK_NAME 18
|
||||||
|
#define XML_TOK_NMTOKEN 19
|
||||||
|
#define XML_TOK_POUND_NAME 20 /* #name */
|
||||||
|
#define XML_TOK_OR 21 /* | */
|
||||||
|
#define XML_TOK_PERCENT 22
|
||||||
|
#define XML_TOK_OPEN_PAREN 23
|
||||||
|
#define XML_TOK_CLOSE_PAREN 24
|
||||||
|
#define XML_TOK_OPEN_BRACKET 25
|
||||||
|
#define XML_TOK_CLOSE_BRACKET 26
|
||||||
|
#define XML_TOK_LITERAL 27
|
||||||
|
#define XML_TOK_PARAM_ENTITY_REF 28
|
||||||
|
#define XML_TOK_INSTANCE_START 29
|
||||||
|
|
||||||
|
/* The following occur only in element type declarations */
|
||||||
|
#define XML_TOK_NAME_QUESTION 30 /* name? */
|
||||||
|
#define XML_TOK_NAME_ASTERISK 31 /* name* */
|
||||||
|
#define XML_TOK_NAME_PLUS 32 /* name+ */
|
||||||
|
#define XML_TOK_COND_SECT_OPEN 33 /* <![ */
|
||||||
|
#define XML_TOK_COND_SECT_CLOSE 34 /* ]]> */
|
||||||
|
#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */
|
||||||
|
#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */
|
||||||
|
#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */
|
||||||
|
#define XML_TOK_COMMA 38
|
||||||
|
|
||||||
|
/* The following token is returned only by XmlAttributeValueTok */
|
||||||
|
#define XML_TOK_ATTRIBUTE_VALUE_S 39
|
||||||
|
|
||||||
|
/* The following token is returned only by XmlCdataSectionTok */
|
||||||
|
#define XML_TOK_CDATA_SECT_CLOSE 40
|
||||||
|
|
||||||
|
/* With namespace processing this is returned by XmlPrologTok for a
|
||||||
|
name with a colon.
|
||||||
|
*/
|
||||||
|
#define XML_TOK_PREFIXED_NAME 41
|
||||||
|
|
||||||
|
#ifdef XML_DTD
|
||||||
|
#define XML_TOK_IGNORE_SECT 42
|
||||||
|
#endif /* XML_DTD */
|
||||||
|
|
||||||
|
#ifdef XML_DTD
|
||||||
|
#define XML_N_STATES 4
|
||||||
|
#else /* not XML_DTD */
|
||||||
|
#define XML_N_STATES 3
|
||||||
|
#endif /* not XML_DTD */
|
||||||
|
|
||||||
|
#define XML_PROLOG_STATE 0
|
||||||
|
#define XML_CONTENT_STATE 1
|
||||||
|
#define XML_CDATA_SECTION_STATE 2
|
||||||
|
#ifdef XML_DTD
|
||||||
|
#define XML_IGNORE_SECTION_STATE 3
|
||||||
|
#endif /* XML_DTD */
|
||||||
|
|
||||||
|
#define XML_N_LITERAL_TYPES 2
|
||||||
|
#define XML_ATTRIBUTE_VALUE_LITERAL 0
|
||||||
|
#define XML_ENTITY_VALUE_LITERAL 1
|
||||||
|
|
||||||
|
/* The size of the buffer passed to XmlUtf8Encode must be at least this. */
|
||||||
|
#define XML_UTF8_ENCODE_MAX 4
|
||||||
|
/* The size of the buffer passed to XmlUtf16Encode must be at least this. */
|
||||||
|
#define XML_UTF16_ENCODE_MAX 2
|
||||||
|
|
||||||
|
typedef struct position {
|
||||||
|
/* first line and first column are 0 not 1 */
|
||||||
|
XML_Size lineNumber;
|
||||||
|
XML_Size columnNumber;
|
||||||
|
} POSITION;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
const char *valuePtr;
|
||||||
|
const char *valueEnd;
|
||||||
|
char normalized;
|
||||||
|
} ATTRIBUTE;
|
||||||
|
|
||||||
|
struct encoding;
|
||||||
|
typedef struct encoding ENCODING;
|
||||||
|
|
||||||
|
typedef int (PTRCALL *SCANNER)(const ENCODING *,
|
||||||
|
const char *,
|
||||||
|
const char *,
|
||||||
|
const char **);
|
||||||
|
|
||||||
|
enum XML_Convert_Result {
|
||||||
|
XML_CONVERT_COMPLETED = 0,
|
||||||
|
XML_CONVERT_INPUT_INCOMPLETE = 1,
|
||||||
|
XML_CONVERT_OUTPUT_EXHAUSTED = 2 /* and therefore potentially input remaining as well */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct encoding {
|
||||||
|
SCANNER scanners[XML_N_STATES];
|
||||||
|
SCANNER literalScanners[XML_N_LITERAL_TYPES];
|
||||||
|
int (PTRCALL *sameName)(const ENCODING *,
|
||||||
|
const char *,
|
||||||
|
const char *);
|
||||||
|
int (PTRCALL *nameMatchesAscii)(const ENCODING *,
|
||||||
|
const char *,
|
||||||
|
const char *,
|
||||||
|
const char *);
|
||||||
|
int (PTRFASTCALL *nameLength)(const ENCODING *, const char *);
|
||||||
|
const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *);
|
||||||
|
int (PTRCALL *getAtts)(const ENCODING *enc,
|
||||||
|
const char *ptr,
|
||||||
|
int attsMax,
|
||||||
|
ATTRIBUTE *atts);
|
||||||
|
int (PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr);
|
||||||
|
int (PTRCALL *predefinedEntityName)(const ENCODING *,
|
||||||
|
const char *,
|
||||||
|
const char *);
|
||||||
|
void (PTRCALL *updatePosition)(const ENCODING *,
|
||||||
|
const char *ptr,
|
||||||
|
const char *end,
|
||||||
|
POSITION *);
|
||||||
|
int (PTRCALL *isPublicId)(const ENCODING *enc,
|
||||||
|
const char *ptr,
|
||||||
|
const char *end,
|
||||||
|
const char **badPtr);
|
||||||
|
enum XML_Convert_Result (PTRCALL *utf8Convert)(const ENCODING *enc,
|
||||||
|
const char **fromP,
|
||||||
|
const char *fromLim,
|
||||||
|
char **toP,
|
||||||
|
const char *toLim);
|
||||||
|
enum XML_Convert_Result (PTRCALL *utf16Convert)(const ENCODING *enc,
|
||||||
|
const char **fromP,
|
||||||
|
const char *fromLim,
|
||||||
|
unsigned short **toP,
|
||||||
|
const unsigned short *toLim);
|
||||||
|
int minBytesPerChar;
|
||||||
|
char isUtf8;
|
||||||
|
char isUtf16;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Scan the string starting at ptr until the end of the next complete
|
||||||
|
token, but do not scan past eptr. Return an integer giving the
|
||||||
|
type of token.
|
||||||
|
|
||||||
|
Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set.
|
||||||
|
|
||||||
|
Return XML_TOK_PARTIAL when the string does not contain a complete
|
||||||
|
token; nextTokPtr will not be set.
|
||||||
|
|
||||||
|
Return XML_TOK_INVALID when the string does not start a valid
|
||||||
|
token; nextTokPtr will be set to point to the character which made
|
||||||
|
the token invalid.
|
||||||
|
|
||||||
|
Otherwise the string starts with a valid token; nextTokPtr will be
|
||||||
|
set to point to the character following the end of that token.
|
||||||
|
|
||||||
|
Each data character counts as a single token, but adjacent data
|
||||||
|
characters may be returned together. Similarly for characters in
|
||||||
|
the prolog outside literals, comments and processing instructions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define XmlTok(enc, state, ptr, end, nextTokPtr) \
|
||||||
|
(((enc)->scanners[state])(enc, ptr, end, nextTokPtr))
|
||||||
|
|
||||||
|
#define XmlPrologTok(enc, ptr, end, nextTokPtr) \
|
||||||
|
XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr)
|
||||||
|
|
||||||
|
#define XmlContentTok(enc, ptr, end, nextTokPtr) \
|
||||||
|
XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr)
|
||||||
|
|
||||||
|
#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \
|
||||||
|
XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr)
|
||||||
|
|
||||||
|
#ifdef XML_DTD
|
||||||
|
|
||||||
|
#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \
|
||||||
|
XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr)
|
||||||
|
|
||||||
|
#endif /* XML_DTD */
|
||||||
|
|
||||||
|
/* This is used for performing a 2nd-level tokenization on the content
|
||||||
|
of a literal that has already been returned by XmlTok.
|
||||||
|
*/
|
||||||
|
#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \
|
||||||
|
(((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr))
|
||||||
|
|
||||||
|
#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \
|
||||||
|
XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr)
|
||||||
|
|
||||||
|
#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \
|
||||||
|
XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr)
|
||||||
|
|
||||||
|
#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2))
|
||||||
|
|
||||||
|
#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \
|
||||||
|
(((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2))
|
||||||
|
|
||||||
|
#define XmlNameLength(enc, ptr) \
|
||||||
|
(((enc)->nameLength)(enc, ptr))
|
||||||
|
|
||||||
|
#define XmlSkipS(enc, ptr) \
|
||||||
|
(((enc)->skipS)(enc, ptr))
|
||||||
|
|
||||||
|
#define XmlGetAttributes(enc, ptr, attsMax, atts) \
|
||||||
|
(((enc)->getAtts)(enc, ptr, attsMax, atts))
|
||||||
|
|
||||||
|
#define XmlCharRefNumber(enc, ptr) \
|
||||||
|
(((enc)->charRefNumber)(enc, ptr))
|
||||||
|
|
||||||
|
#define XmlPredefinedEntityName(enc, ptr, end) \
|
||||||
|
(((enc)->predefinedEntityName)(enc, ptr, end))
|
||||||
|
|
||||||
|
#define XmlUpdatePosition(enc, ptr, end, pos) \
|
||||||
|
(((enc)->updatePosition)(enc, ptr, end, pos))
|
||||||
|
|
||||||
|
#define XmlIsPublicId(enc, ptr, end, badPtr) \
|
||||||
|
(((enc)->isPublicId)(enc, ptr, end, badPtr))
|
||||||
|
|
||||||
|
#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \
|
||||||
|
(((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim))
|
||||||
|
|
||||||
|
#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \
|
||||||
|
(((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim))
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ENCODING initEnc;
|
||||||
|
const ENCODING **encPtr;
|
||||||
|
} INIT_ENCODING;
|
||||||
|
|
||||||
|
int XmlParseXmlDecl(int isGeneralTextEntity,
|
||||||
|
const ENCODING *enc,
|
||||||
|
const char *ptr,
|
||||||
|
const char *end,
|
||||||
|
const char **badPtr,
|
||||||
|
const char **versionPtr,
|
||||||
|
const char **versionEndPtr,
|
||||||
|
const char **encodingNamePtr,
|
||||||
|
const ENCODING **namedEncodingPtr,
|
||||||
|
int *standalonePtr);
|
||||||
|
|
||||||
|
int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name);
|
||||||
|
const ENCODING *XmlGetUtf8InternalEncoding(void);
|
||||||
|
const ENCODING *XmlGetUtf16InternalEncoding(void);
|
||||||
|
int FASTCALL XmlUtf8Encode(int charNumber, char *buf);
|
||||||
|
int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf);
|
||||||
|
int XmlSizeOfUnknownEncoding(void);
|
||||||
|
|
||||||
|
|
||||||
|
typedef int (XMLCALL *CONVERTER) (void *userData, const char *p);
|
||||||
|
|
||||||
|
ENCODING *
|
||||||
|
XmlInitUnknownEncoding(void *mem,
|
||||||
|
int *table,
|
||||||
|
CONVERTER convert,
|
||||||
|
void *userData);
|
||||||
|
|
||||||
|
int XmlParseXmlDeclNS(int isGeneralTextEntity,
|
||||||
|
const ENCODING *enc,
|
||||||
|
const char *ptr,
|
||||||
|
const char *end,
|
||||||
|
const char **badPtr,
|
||||||
|
const char **versionPtr,
|
||||||
|
const char **versionEndPtr,
|
||||||
|
const char **encodingNamePtr,
|
||||||
|
const ENCODING **namedEncodingPtr,
|
||||||
|
int *standalonePtr);
|
||||||
|
|
||||||
|
int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name);
|
||||||
|
const ENCODING *XmlGetUtf8InternalEncodingNS(void);
|
||||||
|
const ENCODING *XmlGetUtf16InternalEncodingNS(void);
|
||||||
|
ENCODING *
|
||||||
|
XmlInitUnknownEncodingNS(void *mem,
|
||||||
|
int *table,
|
||||||
|
CONVERTER convert,
|
||||||
|
void *userData);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* not XmlTok_INCLUDED */
|
46
deps/EXPAT/expat/xmltok_impl.h
vendored
Normal file
46
deps/EXPAT/expat/xmltok_impl.h
vendored
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||||
|
See the file COPYING for copying permission.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BT_NONXML,
|
||||||
|
BT_MALFORM,
|
||||||
|
BT_LT,
|
||||||
|
BT_AMP,
|
||||||
|
BT_RSQB,
|
||||||
|
BT_LEAD2,
|
||||||
|
BT_LEAD3,
|
||||||
|
BT_LEAD4,
|
||||||
|
BT_TRAIL,
|
||||||
|
BT_CR,
|
||||||
|
BT_LF,
|
||||||
|
BT_GT,
|
||||||
|
BT_QUOT,
|
||||||
|
BT_APOS,
|
||||||
|
BT_EQUALS,
|
||||||
|
BT_QUEST,
|
||||||
|
BT_EXCL,
|
||||||
|
BT_SOL,
|
||||||
|
BT_SEMI,
|
||||||
|
BT_NUM,
|
||||||
|
BT_LSQB,
|
||||||
|
BT_S,
|
||||||
|
BT_NMSTRT,
|
||||||
|
BT_COLON,
|
||||||
|
BT_HEX,
|
||||||
|
BT_DIGIT,
|
||||||
|
BT_NAME,
|
||||||
|
BT_MINUS,
|
||||||
|
BT_OTHER, /* known not to be a name or name start character */
|
||||||
|
BT_NONASCII, /* might be a name or name start character */
|
||||||
|
BT_PERCNT,
|
||||||
|
BT_LPAR,
|
||||||
|
BT_RPAR,
|
||||||
|
BT_AST,
|
||||||
|
BT_PLUS,
|
||||||
|
BT_COMMA,
|
||||||
|
BT_VERBAR
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <stddef.h>
|
1779
deps/EXPAT/expat/xmltok_impl.inc
vendored
Normal file
1779
deps/EXPAT/expat/xmltok_impl.inc
vendored
Normal file
File diff suppressed because it is too large
Load diff
115
deps/EXPAT/expat/xmltok_ns.inc
vendored
Normal file
115
deps/EXPAT/expat/xmltok_ns.inc
vendored
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||||
|
See the file COPYING for copying permission.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This file is included! */
|
||||||
|
#ifdef XML_TOK_NS_C
|
||||||
|
|
||||||
|
const ENCODING *
|
||||||
|
NS(XmlGetUtf8InternalEncoding)(void)
|
||||||
|
{
|
||||||
|
return &ns(internal_utf8_encoding).enc;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ENCODING *
|
||||||
|
NS(XmlGetUtf16InternalEncoding)(void)
|
||||||
|
{
|
||||||
|
#if BYTEORDER == 1234
|
||||||
|
return &ns(internal_little2_encoding).enc;
|
||||||
|
#elif BYTEORDER == 4321
|
||||||
|
return &ns(internal_big2_encoding).enc;
|
||||||
|
#else
|
||||||
|
const short n = 1;
|
||||||
|
return (*(const char *)&n
|
||||||
|
? &ns(internal_little2_encoding).enc
|
||||||
|
: &ns(internal_big2_encoding).enc);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static const ENCODING * const NS(encodings)[] = {
|
||||||
|
&ns(latin1_encoding).enc,
|
||||||
|
&ns(ascii_encoding).enc,
|
||||||
|
&ns(utf8_encoding).enc,
|
||||||
|
&ns(big2_encoding).enc,
|
||||||
|
&ns(big2_encoding).enc,
|
||||||
|
&ns(little2_encoding).enc,
|
||||||
|
&ns(utf8_encoding).enc /* NO_ENC */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int PTRCALL
|
||||||
|
NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end,
|
||||||
|
const char **nextTokPtr)
|
||||||
|
{
|
||||||
|
return initScan(NS(encodings), (const INIT_ENCODING *)enc,
|
||||||
|
XML_PROLOG_STATE, ptr, end, nextTokPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int PTRCALL
|
||||||
|
NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end,
|
||||||
|
const char **nextTokPtr)
|
||||||
|
{
|
||||||
|
return initScan(NS(encodings), (const INIT_ENCODING *)enc,
|
||||||
|
XML_CONTENT_STATE, ptr, end, nextTokPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
int i = getEncodingIndex(name);
|
||||||
|
if (i == UNKNOWN_ENC)
|
||||||
|
return 0;
|
||||||
|
SET_INIT_ENC_INDEX(p, i);
|
||||||
|
p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog);
|
||||||
|
p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent);
|
||||||
|
p->initEnc.updatePosition = initUpdatePosition;
|
||||||
|
p->encPtr = encPtr;
|
||||||
|
*encPtr = &(p->initEnc);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const ENCODING *
|
||||||
|
NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end)
|
||||||
|
{
|
||||||
|
#define ENCODING_MAX 128
|
||||||
|
char buf[ENCODING_MAX];
|
||||||
|
char *p = buf;
|
||||||
|
int i;
|
||||||
|
XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1);
|
||||||
|
if (ptr != end)
|
||||||
|
return 0;
|
||||||
|
*p = 0;
|
||||||
|
if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2)
|
||||||
|
return enc;
|
||||||
|
i = getEncodingIndex(buf);
|
||||||
|
if (i == UNKNOWN_ENC)
|
||||||
|
return 0;
|
||||||
|
return NS(encodings)[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
NS(XmlParseXmlDecl)(int isGeneralTextEntity,
|
||||||
|
const ENCODING *enc,
|
||||||
|
const char *ptr,
|
||||||
|
const char *end,
|
||||||
|
const char **badPtr,
|
||||||
|
const char **versionPtr,
|
||||||
|
const char **versionEndPtr,
|
||||||
|
const char **encodingName,
|
||||||
|
const ENCODING **encoding,
|
||||||
|
int *standalone)
|
||||||
|
{
|
||||||
|
return doParseXmlDecl(NS(findEncoding),
|
||||||
|
isGeneralTextEntity,
|
||||||
|
enc,
|
||||||
|
ptr,
|
||||||
|
end,
|
||||||
|
badPtr,
|
||||||
|
versionPtr,
|
||||||
|
versionEndPtr,
|
||||||
|
encodingName,
|
||||||
|
encoding,
|
||||||
|
standalone);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* XML_TOK_NS_C */
|
1
deps/GLEW/GLEW.cmake
vendored
1
deps/GLEW/GLEW.cmake
vendored
|
@ -1,4 +1,5 @@
|
||||||
# We have to check for OpenGL to compile GLEW
|
# We have to check for OpenGL to compile GLEW
|
||||||
|
set(OpenGL_GL_PREFERENCE "LEGACY") # to prevent a nasty warning by cmake
|
||||||
find_package(OpenGL QUIET REQUIRED)
|
find_package(OpenGL QUIET REQUIRED)
|
||||||
|
|
||||||
prusaslicer_add_cmake_project(
|
prusaslicer_add_cmake_project(
|
||||||
|
|
4
deps/OpenCSG/OpenCSG.cmake
vendored
4
deps/OpenCSG/OpenCSG.cmake
vendored
|
@ -6,8 +6,8 @@ prusaslicer_add_cmake_project(OpenCSG
|
||||||
DEPENDS dep_GLEW
|
DEPENDS dep_GLEW
|
||||||
)
|
)
|
||||||
|
|
||||||
if (TARGET dep_ZLIB)
|
if (TARGET ${ZLIB_PKG})
|
||||||
add_dependencies(dep_OpenCSG dep_ZLIB)
|
add_dependencies(dep_OpenCSG ${ZLIB_PKG})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
|
|
13
deps/PNG/PNG.cmake
vendored
Normal file
13
deps/PNG/PNG.cmake
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
prusaslicer_add_cmake_project(PNG
|
||||||
|
GIT_REPOSITORY https://github.com/glennrp/libpng.git
|
||||||
|
GIT_TAG v1.6.35
|
||||||
|
DEPENDS ${ZLIB_PKG}
|
||||||
|
CMAKE_ARGS
|
||||||
|
-DPNG_SHARED=OFF
|
||||||
|
-DPNG_STATIC=ON
|
||||||
|
-DPNG_TESTS=OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
add_debug_dep(dep_PNG)
|
||||||
|
endif ()
|
48
deps/deps-linux.cmake
vendored
48
deps/deps-linux.cmake
vendored
|
@ -3,6 +3,13 @@ set(DEP_CMAKE_OPTS "-DCMAKE_POSITION_INDEPENDENT_CODE=ON")
|
||||||
|
|
||||||
include("deps-unix-common.cmake")
|
include("deps-unix-common.cmake")
|
||||||
|
|
||||||
|
find_package(PNG QUIET)
|
||||||
|
if (NOT PNG_FOUND)
|
||||||
|
message(WARNING "No PNG dev package found in system, building static library. You should install the system package.")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
#TODO UDEV
|
||||||
|
|
||||||
ExternalProject_Add(dep_boost
|
ExternalProject_Add(dep_boost
|
||||||
EXCLUDE_FROM_ALL 1
|
EXCLUDE_FROM_ALL 1
|
||||||
URL "https://dl.bintray.com/boostorg/release/1.70.0/source/boost_1_70_0.tar.gz"
|
URL "https://dl.bintray.com/boostorg/release/1.70.0/source/boost_1_70_0.tar.gz"
|
||||||
|
@ -93,45 +100,4 @@ ExternalProject_Add(dep_libcurl
|
||||||
INSTALL_COMMAND make install "DESTDIR=${DESTDIR}"
|
INSTALL_COMMAND make install "DESTDIR=${DESTDIR}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if (DEP_WX_STABLE)
|
|
||||||
set(DEP_WX_TAG "v3.0.4")
|
|
||||||
else ()
|
|
||||||
set(DEP_WX_TAG "v3.1.1-patched")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (DEP_WX_GTK3)
|
|
||||||
set(WX_GTK_VERSION "3")
|
|
||||||
else ()
|
|
||||||
set(WX_GTK_VERSION "2")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
ExternalProject_Add(dep_wxwidgets
|
|
||||||
EXCLUDE_FROM_ALL 1
|
|
||||||
GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets"
|
|
||||||
GIT_TAG "${DEP_WX_TAG}"
|
|
||||||
BUILD_IN_SOURCE 1
|
|
||||||
# PATCH_COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/wxwidgets-pngprefix.h" src/png/pngprefix.h
|
|
||||||
CONFIGURE_COMMAND ./configure
|
|
||||||
"--prefix=${DESTDIR}/usr/local"
|
|
||||||
--disable-shared
|
|
||||||
--with-gtk=${WX_GTK_VERSION}
|
|
||||||
--with-opengl
|
|
||||||
--enable-unicode
|
|
||||||
--enable-graphics_ctx
|
|
||||||
--with-regex=builtin
|
|
||||||
--with-libpng=builtin
|
|
||||||
--with-libxpm=builtin
|
|
||||||
--with-libjpeg=builtin
|
|
||||||
--with-libtiff=builtin
|
|
||||||
--with-zlib
|
|
||||||
--with-expat=builtin
|
|
||||||
--disable-precomp-headers
|
|
||||||
--enable-debug_info
|
|
||||||
--enable-debug_gdb
|
|
||||||
--disable-debug
|
|
||||||
--disable-debug_flag
|
|
||||||
BUILD_COMMAND make "-j${NPROC}" && make -C locale allmo
|
|
||||||
INSTALL_COMMAND make install
|
|
||||||
)
|
|
||||||
|
|
||||||
add_dependencies(dep_openvdb dep_boost)
|
add_dependencies(dep_openvdb dep_boost)
|
||||||
|
|
26
deps/deps-macos.cmake
vendored
26
deps/deps-macos.cmake
vendored
|
@ -86,30 +86,4 @@ ExternalProject_Add(dep_libcurl
|
||||||
INSTALL_COMMAND make install "DESTDIR=${DESTDIR}"
|
INSTALL_COMMAND make install "DESTDIR=${DESTDIR}"
|
||||||
)
|
)
|
||||||
|
|
||||||
ExternalProject_Add(dep_wxwidgets
|
|
||||||
EXCLUDE_FROM_ALL 1
|
|
||||||
GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets"
|
|
||||||
GIT_TAG v3.1.3-patched
|
|
||||||
BUILD_IN_SOURCE 1
|
|
||||||
# PATCH_COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/wxwidgets-pngprefix.h" src/png/pngprefix.h
|
|
||||||
CONFIGURE_COMMAND env "CXXFLAGS=${DEP_WERRORS_SDK}" "CFLAGS=${DEP_WERRORS_SDK}" ./configure
|
|
||||||
"--prefix=${DESTDIR}/usr/local"
|
|
||||||
--disable-shared
|
|
||||||
--with-osx_cocoa
|
|
||||||
--with-macosx-sdk=${CMAKE_OSX_SYSROOT}
|
|
||||||
"--with-macosx-version-min=${DEP_OSX_TARGET}"
|
|
||||||
--with-opengl
|
|
||||||
--with-regex=builtin
|
|
||||||
--with-libpng=builtin
|
|
||||||
--with-libxpm=builtin
|
|
||||||
--with-libjpeg=builtin
|
|
||||||
--with-libtiff=builtin
|
|
||||||
--with-zlib
|
|
||||||
--with-expat=builtin
|
|
||||||
--disable-debug
|
|
||||||
--disable-debug_flag
|
|
||||||
BUILD_COMMAND make "-j${NPROC}" && PATH=/usr/local/opt/gettext/bin/:$ENV{PATH} make -C locale allmo
|
|
||||||
INSTALL_COMMAND make install
|
|
||||||
)
|
|
||||||
|
|
||||||
add_dependencies(dep_openvdb dep_boost)
|
add_dependencies(dep_openvdb dep_boost)
|
16
deps/deps-mingw.cmake
vendored
16
deps/deps-mingw.cmake
vendored
|
@ -58,19 +58,3 @@ ExternalProject_Add(dep_libcurl
|
||||||
-DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local
|
-DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local
|
||||||
${DEP_CMAKE_OPTS}
|
${DEP_CMAKE_OPTS}
|
||||||
)
|
)
|
||||||
|
|
||||||
ExternalProject_Add(dep_wxwidgets
|
|
||||||
EXCLUDE_FROM_ALL 1
|
|
||||||
GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets"
|
|
||||||
GIT_TAG v3.1.1-patched
|
|
||||||
# URL "https://github.com/wxWidgets/wxWidgets/releases/download/v3.1.1/wxWidgets-3.1.1.tar.bz2"
|
|
||||||
# URL_HASH SHA256=c925dfe17e8f8b09eb7ea9bfdcfcc13696a3e14e92750effd839f5e10726159e
|
|
||||||
# PATCH_COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}\\wxwidgets-pngprefix.h" src\\png\\pngprefix.h
|
|
||||||
CMAKE_ARGS
|
|
||||||
-DBUILD_SHARED_LIBS=OFF
|
|
||||||
-DwxUSE_LIBPNG=builtin
|
|
||||||
-DwxUSE_ZLIB=builtin
|
|
||||||
-DwxUSE_OPENGL=ON
|
|
||||||
-DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local
|
|
||||||
${DEP_CMAKE_OPTS}
|
|
||||||
)
|
|
8
deps/deps-unix-common.cmake
vendored
8
deps/deps-unix-common.cmake
vendored
|
@ -9,9 +9,15 @@ endif ()
|
||||||
|
|
||||||
find_package(ZLIB QUIET)
|
find_package(ZLIB QUIET)
|
||||||
if (NOT ZLIB_FOUND)
|
if (NOT ZLIB_FOUND)
|
||||||
include(ZLIB/ZLIB.cmake)
|
message(WARNING "No ZLIB dev package found in system, building static library. You should install the system package.")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
# TODO Evaluate expat modifications in the bundled version and test with system versions in various distros and OSX SDKs
|
||||||
|
# find_package(EXPAT QUIET)
|
||||||
|
# if (NOT EXPAT_FOUND)
|
||||||
|
# message(WARNING "No EXPAT dev package found in system, building static library. Consider installing the system package.")
|
||||||
|
# endif ()
|
||||||
|
|
||||||
ExternalProject_Add(dep_tbb
|
ExternalProject_Add(dep_tbb
|
||||||
EXCLUDE_FROM_ALL 1
|
EXCLUDE_FROM_ALL 1
|
||||||
URL "https://github.com/wjakob/tbb/archive/a0dc9bf76d0120f917b641ed095360448cabc85b.tar.gz"
|
URL "https://github.com/wjakob/tbb/archive/a0dc9bf76d0120f917b641ed095360448cabc85b.tar.gz"
|
||||||
|
|
59
deps/deps-windows.cmake
vendored
59
deps/deps-windows.cmake
vendored
|
@ -149,38 +149,6 @@ ExternalProject_Add(dep_nlopt
|
||||||
|
|
||||||
add_debug_dep(dep_nlopt)
|
add_debug_dep(dep_nlopt)
|
||||||
|
|
||||||
include(ZLIB/ZLIB.cmake)
|
|
||||||
# ExternalProject_Add(dep_zlib
|
|
||||||
# EXCLUDE_FROM_ALL 1
|
|
||||||
# URL "https://zlib.net/zlib-1.2.11.tar.xz"
|
|
||||||
# URL_HASH SHA256=4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066
|
|
||||||
# CMAKE_GENERATOR "${DEP_MSVC_GEN}"
|
|
||||||
# CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}"
|
|
||||||
# CMAKE_ARGS
|
|
||||||
# -DSKIP_INSTALL_FILES=ON # Prevent installation of man pages et al.
|
|
||||||
# "-DINSTALL_BIN_DIR=${CMAKE_CURRENT_BINARY_DIR}\\fallout" # I found no better way of preventing zlib from creating & installing DLLs :-/
|
|
||||||
# -DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
|
||||||
# "-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR}\\usr\\local"
|
|
||||||
# BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj
|
|
||||||
# INSTALL_COMMAND ""
|
|
||||||
# )
|
|
||||||
|
|
||||||
add_debug_dep(dep_ZLIB)
|
|
||||||
|
|
||||||
# The following steps are unfortunately needed to remove the _static suffix on libraries
|
|
||||||
# ExternalProject_Add_Step(dep_zlib fix_static
|
|
||||||
# DEPENDEES install
|
|
||||||
# COMMAND "${CMAKE_COMMAND}" -E rename zlibstatic.lib zlib.lib
|
|
||||||
# WORKING_DIRECTORY "${DESTDIR}\\usr\\local\\lib\\"
|
|
||||||
# )
|
|
||||||
# if (${DEP_DEBUG})
|
|
||||||
# ExternalProject_Add_Step(dep_zlib fix_static_debug
|
|
||||||
# DEPENDEES install
|
|
||||||
# COMMAND "${CMAKE_COMMAND}" -E rename zlibstaticd.lib zlibd.lib
|
|
||||||
# WORKING_DIRECTORY "${DESTDIR}\\usr\\local\\lib\\"
|
|
||||||
# )
|
|
||||||
# endif ()
|
|
||||||
|
|
||||||
if (${DEPS_BITS} EQUAL 32)
|
if (${DEPS_BITS} EQUAL 32)
|
||||||
set(DEP_LIBCURL_TARGET "x86")
|
set(DEP_LIBCURL_TARGET "x86")
|
||||||
else ()
|
else ()
|
||||||
|
@ -243,36 +211,13 @@ endif ()
|
||||||
|
|
||||||
find_package(Git REQUIRED)
|
find_package(Git REQUIRED)
|
||||||
|
|
||||||
ExternalProject_Add(dep_wxwidgets
|
|
||||||
EXCLUDE_FROM_ALL 1
|
|
||||||
GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets"
|
|
||||||
GIT_TAG v3.1.1-patched
|
|
||||||
# URL "https://github.com/wxWidgets/wxWidgets/releases/download/v3.1.1/wxWidgets-3.1.1.tar.bz2"
|
|
||||||
# URL_HASH SHA256=c925dfe17e8f8b09eb7ea9bfdcfcc13696a3e14e92750effd839f5e10726159e
|
|
||||||
BUILD_IN_SOURCE 1
|
|
||||||
# PATCH_COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}\\wxwidgets-pngprefix.h" src\\png\\pngprefix.h
|
|
||||||
CONFIGURE_COMMAND ""
|
|
||||||
BUILD_COMMAND cd build\\msw && nmake /f makefile.vc BUILD=release SHARED=0 UNICODE=1 USE_GUI=1 "${DEP_WXWIDGETS_TARGET}"
|
|
||||||
INSTALL_COMMAND "${CMAKE_COMMAND}" -E copy_directory include "${DESTDIR}\\usr\\local\\include"
|
|
||||||
&& "${CMAKE_COMMAND}" -E copy_directory "lib\\${DEP_WXWIDGETS_LIBDIR}" "${DESTDIR}\\usr\\local\\lib\\${DEP_WXWIDGETS_LIBDIR}"
|
|
||||||
)
|
|
||||||
if (${DEP_DEBUG})
|
|
||||||
ExternalProject_Get_Property(dep_wxwidgets SOURCE_DIR)
|
|
||||||
ExternalProject_Add_Step(dep_wxwidgets build_debug
|
|
||||||
DEPENDEES build
|
|
||||||
DEPENDERS install
|
|
||||||
COMMAND cd build\\msw && nmake /f makefile.vc BUILD=debug SHARED=0 UNICODE=1 USE_GUI=1 "${DEP_WXWIDGETS_TARGET}"
|
|
||||||
WORKING_DIRECTORY "${SOURCE_DIR}"
|
|
||||||
)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
ExternalProject_Add(dep_blosc
|
ExternalProject_Add(dep_blosc
|
||||||
EXCLUDE_FROM_ALL 1
|
EXCLUDE_FROM_ALL 1
|
||||||
#URL https://github.com/Blosc/c-blosc/archive/v1.17.0.zip
|
#URL https://github.com/Blosc/c-blosc/archive/v1.17.0.zip
|
||||||
#URL_HASH SHA256=7463a1df566704f212263312717ab2c36b45d45cba6cd0dccebf91b2cc4b4da9
|
#URL_HASH SHA256=7463a1df566704f212263312717ab2c36b45d45cba6cd0dccebf91b2cc4b4da9
|
||||||
GIT_REPOSITORY https://github.com/Blosc/c-blosc.git
|
GIT_REPOSITORY https://github.com/Blosc/c-blosc.git
|
||||||
GIT_TAG e63775855294b50820ef44d1b157f4de1cc38d3e #v1.17.0
|
GIT_TAG e63775855294b50820ef44d1b157f4de1cc38d3e #v1.17.0
|
||||||
DEPENDS dep_ZLIB
|
DEPENDS ${ZLIB_PKG}
|
||||||
CMAKE_GENERATOR "${DEP_MSVC_GEN}"
|
CMAKE_GENERATOR "${DEP_MSVC_GEN}"
|
||||||
CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}"
|
CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}"
|
||||||
CMAKE_ARGS
|
CMAKE_ARGS
|
||||||
|
@ -299,7 +244,7 @@ ExternalProject_Add(dep_openexr
|
||||||
EXCLUDE_FROM_ALL 1
|
EXCLUDE_FROM_ALL 1
|
||||||
GIT_REPOSITORY https://github.com/openexr/openexr.git
|
GIT_REPOSITORY https://github.com/openexr/openexr.git
|
||||||
GIT_TAG eae0e337c9f5117e78114fd05f7a415819df413a #v2.4.0
|
GIT_TAG eae0e337c9f5117e78114fd05f7a415819df413a #v2.4.0
|
||||||
DEPENDS dep_ZLIB
|
DEPENDS ${ZLIB_PKG}
|
||||||
CMAKE_GENERATOR "${DEP_MSVC_GEN}"
|
CMAKE_GENERATOR "${DEP_MSVC_GEN}"
|
||||||
CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}"
|
CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}"
|
||||||
CMAKE_ARGS
|
CMAKE_ARGS
|
||||||
|
|
36
deps/wxWidgets/wxWidgets.cmake
vendored
Normal file
36
deps/wxWidgets/wxWidgets.cmake
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
set(_wx_git_tag v3.1.3-patched)
|
||||||
|
|
||||||
|
# set(_patch_command "")
|
||||||
|
set(_wx_toolkit "")
|
||||||
|
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
set(_gtk_ver 2)
|
||||||
|
if (DEP_WX_GTK3)
|
||||||
|
set(_gtk_ver 3)
|
||||||
|
endif ()
|
||||||
|
set(_wx_toolkit "-DwxBUILD_TOOLKIT=gtk${_gtk_ver}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
prusaslicer_add_cmake_project(wxWidgets
|
||||||
|
GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets"
|
||||||
|
GIT_TAG ${_wx_git_tag}
|
||||||
|
# PATCH_COMMAND "${_patch_command}"
|
||||||
|
DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG}
|
||||||
|
CMAKE_ARGS
|
||||||
|
-DwxBUILD_PRECOMP=ON
|
||||||
|
${_wx_toolkit}
|
||||||
|
"-DCMAKE_DEBUG_POSTFIX:STRING="
|
||||||
|
-DwxUSE_DETECT_SM=OFF
|
||||||
|
-DwxUSE_UNICODE=ON
|
||||||
|
-DwxUSE_OPENGL=ON
|
||||||
|
-DwxUSE_LIBPNG=sys
|
||||||
|
-DwxUSE_ZLIB=sys
|
||||||
|
-DwxUSE_REGEX=builtin
|
||||||
|
-DwxUSE_LIBXPM=builtin
|
||||||
|
-DwxUSE_LIBJPEG=builtin
|
||||||
|
-DwxUSE_LIBTIFF=builtin
|
||||||
|
-DwxUSE_EXPAT=sys
|
||||||
|
)
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
add_debug_dep(dep_wxWidgets)
|
||||||
|
endif ()
|
|
@ -59,6 +59,29 @@ if (SLIC3R_GUI)
|
||||||
|
|
||||||
include(${wxWidgets_USE_FILE})
|
include(${wxWidgets_USE_FILE})
|
||||||
|
|
||||||
|
string(REGEX MATCH "wxpng" WX_PNG_BUILTIN ${wxWidgets_LIBRARIES})
|
||||||
|
if (PNG_FOUND AND NOT WX_PNG_BUILTIN)
|
||||||
|
list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX png)
|
||||||
|
list(APPEND wxWidgets_LIBRARIES ${PNG_LIBRARIES})
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
string(REGEX MATCH "wxexpat" WX_EXPAT_BUILTIN ${wxWidgets_LIBRARIES})
|
||||||
|
if (EXPAT_FOUND AND NOT WX_EXPAT_BUILTIN)
|
||||||
|
list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX expat)
|
||||||
|
list(APPEND wxWidgets_LIBRARIES ${EXPAT_LIBRARIES})
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
# This is an issue in the new wxWidgets cmake build, doesn't deal with librt
|
||||||
|
find_library(LIBRT rt)
|
||||||
|
if(LIBRT)
|
||||||
|
list(APPEND wxWidgets_LIBRARIES ${LIBRT})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# This fixes a OpenGL linking issue on OSX. wxWidgets cmake build includes
|
||||||
|
# wrong libs for opengl in the link line and it does not link to it by himself.
|
||||||
|
# libslic3r_gui will link to opengl anyway, so lets override wx
|
||||||
|
list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX OpenGL)
|
||||||
|
|
||||||
# list(REMOVE_ITEM wxWidgets_LIBRARIES oleacc)
|
# list(REMOVE_ITEM wxWidgets_LIBRARIES oleacc)
|
||||||
message(STATUS "wx libs: ${wxWidgets_LIBRARIES}")
|
message(STATUS "wx libs: ${wxWidgets_LIBRARIES}")
|
||||||
|
|
||||||
|
@ -178,13 +201,13 @@ if (WIN32)
|
||||||
elseif (XCODE)
|
elseif (XCODE)
|
||||||
# Because of Debug/Release/etc. configurations (similar to MSVC) the slic3r binary is located in an extra level
|
# Because of Debug/Release/etc. configurations (similar to MSVC) the slic3r binary is located in an extra level
|
||||||
add_custom_command(TARGET PrusaSlicer POST_BUILD
|
add_custom_command(TARGET PrusaSlicer POST_BUILD
|
||||||
COMMAND ln -sf "${SLIC3R_RESOURCES_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/resources"
|
COMMAND ln -sfn "${SLIC3R_RESOURCES_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/resources"
|
||||||
COMMENT "Symlinking the resources directory into the build tree"
|
COMMENT "Symlinking the resources directory into the build tree"
|
||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
else ()
|
else ()
|
||||||
add_custom_command(TARGET PrusaSlicer POST_BUILD
|
add_custom_command(TARGET PrusaSlicer POST_BUILD
|
||||||
COMMAND ln -sf "${SLIC3R_RESOURCES_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/../resources"
|
COMMAND ln -sfn "${SLIC3R_RESOURCES_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/../resources"
|
||||||
COMMENT "Symlinking the resources directory into the build tree"
|
COMMENT "Symlinking the resources directory into the build tree"
|
||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "libslic3r/Config.hpp"
|
#include "libslic3r/Config.hpp"
|
||||||
#include "libslic3r/Geometry.hpp"
|
#include "libslic3r/Geometry.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
|
#include "libslic3r/ModelArrange.hpp"
|
||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
#include "libslic3r/SLAPrint.hpp"
|
#include "libslic3r/SLAPrint.hpp"
|
||||||
#include "libslic3r/TriangleMesh.hpp"
|
#include "libslic3r/TriangleMesh.hpp"
|
||||||
|
@ -41,6 +42,7 @@
|
||||||
#include "libslic3r/Format/3mf.hpp"
|
#include "libslic3r/Format/3mf.hpp"
|
||||||
#include "libslic3r/Format/STL.hpp"
|
#include "libslic3r/Format/STL.hpp"
|
||||||
#include "libslic3r/Format/OBJ.hpp"
|
#include "libslic3r/Format/OBJ.hpp"
|
||||||
|
#include "libslic3r/Format/SL1.hpp"
|
||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
|
|
||||||
#include "PrusaSlicer.hpp"
|
#include "PrusaSlicer.hpp"
|
||||||
|
@ -49,18 +51,21 @@
|
||||||
#include "slic3r/GUI/GUI.hpp"
|
#include "slic3r/GUI/GUI.hpp"
|
||||||
#include "slic3r/GUI/GUI_App.hpp"
|
#include "slic3r/GUI/GUI_App.hpp"
|
||||||
#include "slic3r/GUI/3DScene.hpp"
|
#include "slic3r/GUI/3DScene.hpp"
|
||||||
|
#include "slic3r/GUI/InstanceCheck.hpp"
|
||||||
|
#include "slic3r/GUI/AppConfig.hpp"
|
||||||
#endif /* SLIC3R_GUI */
|
#endif /* SLIC3R_GUI */
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
|
|
||||||
PrinterTechnology get_printer_technology(const DynamicConfig &config)
|
|
||||||
{
|
|
||||||
const ConfigOptionEnum<PrinterTechnology> *opt = config.option<ConfigOptionEnum<PrinterTechnology>>("printer_technology");
|
|
||||||
return (opt == nullptr) ? ptUnknown : opt->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CLI::run(int argc, char **argv)
|
int CLI::run(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
#ifdef __WXGTK__
|
||||||
|
// On Linux, wxGTK has no support for Wayland, and the app crashes on
|
||||||
|
// startup if gtk3 is used. This env var has to be set explicitly to
|
||||||
|
// instruct the window manager to fall back to X server mode.
|
||||||
|
::setenv("GDK_BACKEND", "x11", /* replace */ true);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Switch boost::filesystem to utf8.
|
// Switch boost::filesystem to utf8.
|
||||||
try {
|
try {
|
||||||
boost::nowide::nowide_filesystem();
|
boost::nowide::nowide_filesystem();
|
||||||
|
@ -87,12 +92,14 @@ int CLI::run(int argc, char **argv)
|
||||||
m_extra_config.apply(m_config, true);
|
m_extra_config.apply(m_config, true);
|
||||||
m_extra_config.normalize();
|
m_extra_config.normalize();
|
||||||
|
|
||||||
|
PrinterTechnology printer_technology = Slic3r::printer_technology(m_config);
|
||||||
|
|
||||||
bool start_gui = m_actions.empty() &&
|
bool start_gui = m_actions.empty() &&
|
||||||
// cutting transformations are setting an "export" action.
|
// cutting transformations are setting an "export" action.
|
||||||
std::find(m_transforms.begin(), m_transforms.end(), "cut") == m_transforms.end() &&
|
std::find(m_transforms.begin(), m_transforms.end(), "cut") == m_transforms.end() &&
|
||||||
std::find(m_transforms.begin(), m_transforms.end(), "cut_x") == m_transforms.end() &&
|
std::find(m_transforms.begin(), m_transforms.end(), "cut_x") == m_transforms.end() &&
|
||||||
std::find(m_transforms.begin(), m_transforms.end(), "cut_y") == m_transforms.end();
|
std::find(m_transforms.begin(), m_transforms.end(), "cut_y") == m_transforms.end();
|
||||||
PrinterTechnology printer_technology = get_printer_technology(m_extra_config);
|
|
||||||
const std::vector<std::string> &load_configs = m_config.option<ConfigOptionStrings>("load", true)->values;
|
const std::vector<std::string> &load_configs = m_config.option<ConfigOptionStrings>("load", true)->values;
|
||||||
|
|
||||||
// load config files supplied via --load
|
// load config files supplied via --load
|
||||||
|
@ -113,7 +120,7 @@ int CLI::run(int argc, char **argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
config.normalize();
|
config.normalize();
|
||||||
PrinterTechnology other_printer_technology = get_printer_technology(config);
|
PrinterTechnology other_printer_technology = Slic3r::printer_technology(config);
|
||||||
if (printer_technology == ptUnknown) {
|
if (printer_technology == ptUnknown) {
|
||||||
printer_technology = other_printer_technology;
|
printer_technology = other_printer_technology;
|
||||||
} else if (printer_technology != other_printer_technology && other_printer_technology != ptUnknown) {
|
} else if (printer_technology != other_printer_technology && other_printer_technology != ptUnknown) {
|
||||||
|
@ -134,7 +141,7 @@ int CLI::run(int argc, char **argv)
|
||||||
// When loading an AMF or 3MF, config is imported as well, including the printer technology.
|
// When loading an AMF or 3MF, config is imported as well, including the printer technology.
|
||||||
DynamicPrintConfig config;
|
DynamicPrintConfig config;
|
||||||
model = Model::read_from_file(file, &config, true);
|
model = Model::read_from_file(file, &config, true);
|
||||||
PrinterTechnology other_printer_technology = get_printer_technology(config);
|
PrinterTechnology other_printer_technology = Slic3r::printer_technology(config);
|
||||||
if (printer_technology == ptUnknown) {
|
if (printer_technology == ptUnknown) {
|
||||||
printer_technology = other_printer_technology;
|
printer_technology = other_printer_technology;
|
||||||
} else if (printer_technology != other_printer_technology && other_printer_technology != ptUnknown) {
|
} else if (printer_technology != other_printer_technology && other_printer_technology != ptUnknown) {
|
||||||
|
@ -161,9 +168,6 @@ int CLI::run(int argc, char **argv)
|
||||||
// Normalizing after importing the 3MFs / AMFs
|
// Normalizing after importing the 3MFs / AMFs
|
||||||
m_print_config.normalize();
|
m_print_config.normalize();
|
||||||
|
|
||||||
if (printer_technology == ptUnknown)
|
|
||||||
printer_technology = std::find(m_actions.begin(), m_actions.end(), "export_sla") == m_actions.end() ? ptFFF : ptSLA;
|
|
||||||
|
|
||||||
// Initialize full print configs for both the FFF and SLA technologies.
|
// Initialize full print configs for both the FFF and SLA technologies.
|
||||||
FullPrintConfig fff_print_config;
|
FullPrintConfig fff_print_config;
|
||||||
SLAFullPrintConfig sla_print_config;
|
SLAFullPrintConfig sla_print_config;
|
||||||
|
@ -174,6 +178,7 @@ int CLI::run(int argc, char **argv)
|
||||||
m_print_config.apply(fff_print_config, true);
|
m_print_config.apply(fff_print_config, true);
|
||||||
} else if (printer_technology == ptSLA) {
|
} else if (printer_technology == ptSLA) {
|
||||||
// The default value has to be different from the one in fff mode.
|
// The default value has to be different from the one in fff mode.
|
||||||
|
sla_print_config.printer_technology.value = ptSLA;
|
||||||
sla_print_config.output_filename_format.value = "[input_filename_base].sl1";
|
sla_print_config.output_filename_format.value = "[input_filename_base].sl1";
|
||||||
|
|
||||||
// The default bed shape should reflect the default display parameters
|
// The default bed shape should reflect the default display parameters
|
||||||
|
@ -186,8 +191,18 @@ int CLI::run(int argc, char **argv)
|
||||||
m_print_config.apply(sla_print_config, true);
|
m_print_config.apply(sla_print_config, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string validity = m_print_config.validate();
|
||||||
|
if (!validity.empty()) {
|
||||||
|
boost::nowide::cerr << "error: " << validity << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Loop through transform options.
|
// Loop through transform options.
|
||||||
bool user_center_specified = false;
|
bool user_center_specified = false;
|
||||||
|
Points bed = get_bed_shape(m_print_config);
|
||||||
|
ArrangeParams arrange_cfg;
|
||||||
|
arrange_cfg.min_obj_distance = scaled(min_object_distance(m_print_config));
|
||||||
|
|
||||||
for (auto const &opt_key : m_transforms) {
|
for (auto const &opt_key : m_transforms) {
|
||||||
if (opt_key == "merge") {
|
if (opt_key == "merge") {
|
||||||
Model m;
|
Model m;
|
||||||
|
@ -197,29 +212,33 @@ int CLI::run(int argc, char **argv)
|
||||||
// Rearrange instances unless --dont-arrange is supplied
|
// Rearrange instances unless --dont-arrange is supplied
|
||||||
if (! m_config.opt_bool("dont_arrange")) {
|
if (! m_config.opt_bool("dont_arrange")) {
|
||||||
m.add_default_instances();
|
m.add_default_instances();
|
||||||
const BoundingBoxf &bb = fff_print_config.bed_shape.values;
|
if (this->has_print_action())
|
||||||
m.arrange_objects(
|
arrange_objects(m, bed, arrange_cfg);
|
||||||
fff_print_config.min_object_distance(),
|
else
|
||||||
// If we are going to use the merged model for printing, honor
|
arrange_objects(m, InfiniteBed{}, arrange_cfg);
|
||||||
// the configured print bed for arranging, otherwise do it freely.
|
|
||||||
this->has_print_action() ? &bb : nullptr
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
m_models.clear();
|
m_models.clear();
|
||||||
m_models.emplace_back(std::move(m));
|
m_models.emplace_back(std::move(m));
|
||||||
} else if (opt_key == "duplicate") {
|
} else if (opt_key == "duplicate") {
|
||||||
const BoundingBoxf &bb = fff_print_config.bed_shape.values;
|
|
||||||
for (auto &model : m_models) {
|
for (auto &model : m_models) {
|
||||||
const bool all_objects_have_instances = std::none_of(
|
const bool all_objects_have_instances = std::none_of(
|
||||||
model.objects.begin(), model.objects.end(),
|
model.objects.begin(), model.objects.end(),
|
||||||
[](ModelObject* o){ return o->instances.empty(); }
|
[](ModelObject* o){ return o->instances.empty(); }
|
||||||
);
|
);
|
||||||
if (all_objects_have_instances) {
|
|
||||||
|
int dups = m_config.opt_int("duplicate");
|
||||||
|
if (!all_objects_have_instances) model.add_default_instances();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (dups > 1) {
|
||||||
// if all input objects have defined position(s) apply duplication to the whole model
|
// if all input objects have defined position(s) apply duplication to the whole model
|
||||||
model.duplicate(m_config.opt_int("duplicate"), fff_print_config.min_object_distance(), &bb);
|
duplicate(model, size_t(dups), bed, arrange_cfg);
|
||||||
} else {
|
} else {
|
||||||
model.add_default_instances();
|
arrange_objects(model, bed, arrange_cfg);
|
||||||
model.duplicate_objects(m_config.opt_int("duplicate"), fff_print_config.min_object_distance(), &bb);
|
}
|
||||||
|
} catch (std::exception &ex) {
|
||||||
|
boost::nowide::cerr << "error: " << ex.what() << std::endl;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (opt_key == "duplicate_grid") {
|
} else if (opt_key == "duplicate_grid") {
|
||||||
|
@ -413,7 +432,8 @@ int CLI::run(int argc, char **argv)
|
||||||
std::string outfile = m_config.opt_string("output");
|
std::string outfile = m_config.opt_string("output");
|
||||||
Print fff_print;
|
Print fff_print;
|
||||||
SLAPrint sla_print;
|
SLAPrint sla_print;
|
||||||
|
SL1Archive sla_archive(sla_print.printer_config());
|
||||||
|
sla_print.set_printer(&sla_archive);
|
||||||
sla_print.set_status_callback(
|
sla_print.set_status_callback(
|
||||||
[](const PrintBase::SlicingStatus& s)
|
[](const PrintBase::SlicingStatus& s)
|
||||||
{
|
{
|
||||||
|
@ -423,11 +443,11 @@ int CLI::run(int argc, char **argv)
|
||||||
|
|
||||||
PrintBase *print = (printer_technology == ptFFF) ? static_cast<PrintBase*>(&fff_print) : static_cast<PrintBase*>(&sla_print);
|
PrintBase *print = (printer_technology == ptFFF) ? static_cast<PrintBase*>(&fff_print) : static_cast<PrintBase*>(&sla_print);
|
||||||
if (! m_config.opt_bool("dont_arrange")) {
|
if (! m_config.opt_bool("dont_arrange")) {
|
||||||
//FIXME make the min_object_distance configurable.
|
if (user_center_specified) {
|
||||||
model.arrange_objects(fff_print.config().min_object_distance());
|
Vec2d c = m_config.option<ConfigOptionPoint>("center")->value;
|
||||||
model.center_instances_around_point((! user_center_specified && m_print_config.has("bed_shape")) ?
|
arrange_objects(model, InfiniteBed{scaled(c)}, arrange_cfg);
|
||||||
BoundingBoxf(m_print_config.opt<ConfigOptionPoints>("bed_shape")->values).center() :
|
} else
|
||||||
m_config.option<ConfigOptionPoint>("center")->value);
|
arrange_objects(model, bed, arrange_cfg);
|
||||||
}
|
}
|
||||||
if (printer_technology == ptFFF) {
|
if (printer_technology == ptFFF) {
|
||||||
for (auto* mo : model.objects)
|
for (auto* mo : model.objects)
|
||||||
|
@ -453,7 +473,7 @@ int CLI::run(int argc, char **argv)
|
||||||
outfile = sla_print.output_filepath(outfile);
|
outfile = sla_print.output_filepath(outfile);
|
||||||
// We need to finalize the filename beforehand because the export function sets the filename inside the zip metadata
|
// We need to finalize the filename beforehand because the export function sets the filename inside the zip metadata
|
||||||
outfile_final = sla_print.print_statistics().finalize_output_path(outfile);
|
outfile_final = sla_print.print_statistics().finalize_output_path(outfile);
|
||||||
sla_print.export_raster(outfile_final);
|
sla_archive.export_print(outfile_final, sla_print);
|
||||||
}
|
}
|
||||||
if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final)) {
|
if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final)) {
|
||||||
boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl;
|
boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl;
|
||||||
|
@ -505,6 +525,16 @@ int CLI::run(int argc, char **argv)
|
||||||
#ifdef SLIC3R_GUI
|
#ifdef SLIC3R_GUI
|
||||||
// #ifdef USE_WX
|
// #ifdef USE_WX
|
||||||
GUI::GUI_App *gui = new GUI::GUI_App();
|
GUI::GUI_App *gui = new GUI::GUI_App();
|
||||||
|
|
||||||
|
bool gui_single_instance_setting = gui->app_config->get("single_instance") == "1";
|
||||||
|
if (Slic3r::instance_check(argc, argv, gui_single_instance_setting)) {
|
||||||
|
//TODO: do we have delete gui and other stuff?
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//gui->app_config = app_config;
|
||||||
|
//app_config = nullptr;
|
||||||
|
|
||||||
// gui->autosave = m_config.opt_string("autosave");
|
// gui->autosave = m_config.opt_string("autosave");
|
||||||
GUI::GUI_App::SetInstance(gui);
|
GUI::GUI_App::SetInstance(gui);
|
||||||
gui->CallAfter([gui, this, &load_configs] {
|
gui->CallAfter([gui, this, &load_configs] {
|
||||||
|
@ -610,6 +640,8 @@ bool CLI::setup(int argc, char **argv)
|
||||||
set_logging_level(opt_loglevel->value);
|
set_logging_level(opt_loglevel->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string validity = m_config.validate();
|
||||||
|
|
||||||
// Initialize with defaults.
|
// Initialize with defaults.
|
||||||
for (const t_optiondef_map *options : { &cli_actions_config_def.options, &cli_transform_config_def.options, &cli_misc_config_def.options })
|
for (const t_optiondef_map *options : { &cli_actions_config_def.options, &cli_transform_config_def.options, &cli_misc_config_def.options })
|
||||||
for (const std::pair<t_config_option_key, ConfigOptionDef> &optdef : *options)
|
for (const std::pair<t_config_option_key, ConfigOptionDef> &optdef : *options)
|
||||||
|
@ -617,6 +649,11 @@ bool CLI::setup(int argc, char **argv)
|
||||||
|
|
||||||
set_data_dir(m_config.opt_string("datadir"));
|
set_data_dir(m_config.opt_string("datadir"));
|
||||||
|
|
||||||
|
if (!validity.empty()) {
|
||||||
|
boost::nowide::cerr << "error: " << validity << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SLIC3R_GUI
|
#ifdef SLIC3R_GUI
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
|
@ -216,7 +218,6 @@ int APIENTRY wWinMain(HINSTANCE /* hInstance */, HINSTANCE /* hPrevInstance */,
|
||||||
int wmain(int argc, wchar_t **argv)
|
int wmain(int argc, wchar_t **argv)
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<wchar_t*> argv_extended;
|
std::vector<wchar_t*> argv_extended;
|
||||||
argv_extended.emplace_back(argv[0]);
|
argv_extended.emplace_back(argv[0]);
|
||||||
|
|
||||||
|
|
|
@ -982,6 +982,9 @@ template<class S> inline double area(const S& poly, const PolygonTag& )
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class RawShapes>
|
||||||
|
inline double area(const RawShapes& shapes, const MultiPolygonTag&);
|
||||||
|
|
||||||
template<class S> // Dispatching function
|
template<class S> // Dispatching function
|
||||||
inline double area(const S& sh)
|
inline double area(const S& sh)
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,6 +27,7 @@ using Coord = TCoord<PointImpl>;
|
||||||
using Box = _Box<PointImpl>;
|
using Box = _Box<PointImpl>;
|
||||||
using Segment = _Segment<PointImpl>;
|
using Segment = _Segment<PointImpl>;
|
||||||
using Circle = _Circle<PointImpl>;
|
using Circle = _Circle<PointImpl>;
|
||||||
|
using MultiPolygon = TMultiShape<PolygonImpl>;
|
||||||
|
|
||||||
using Item = _Item<PolygonImpl>;
|
using Item = _Item<PolygonImpl>;
|
||||||
using Rectangle = _Rectangle<PolygonImpl>;
|
using Rectangle = _Rectangle<PolygonImpl>;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <libnest2d/libnest2d.hpp>
|
#include <libnest2d/nester.hpp>
|
||||||
|
|
||||||
namespace libnest2d { namespace svg {
|
namespace libnest2d { namespace svg {
|
||||||
|
|
||||||
|
@ -49,9 +49,8 @@ public:
|
||||||
conf_.mm_in_coord_units;
|
conf_.mm_in_coord_units;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeItem(const Item& item) {
|
void writeShape(RawShape tsh) {
|
||||||
if(svg_layers_.empty()) addLayer();
|
if(svg_layers_.empty()) addLayer();
|
||||||
auto tsh = item.transformedShape();
|
|
||||||
if(conf_.origo_location == BOTTOMLEFT) {
|
if(conf_.origo_location == BOTTOMLEFT) {
|
||||||
auto d = static_cast<Coord>(
|
auto d = static_cast<Coord>(
|
||||||
std::round(conf_.height*conf_.mm_in_coord_units) );
|
std::round(conf_.height*conf_.mm_in_coord_units) );
|
||||||
|
@ -63,8 +62,14 @@ public:
|
||||||
for(auto& h : holes) for(auto& v : h) setY(v, -getY(v) + d);
|
for(auto& h : holes) for(auto& v : h) setY(v, -getY(v) + d);
|
||||||
|
|
||||||
}
|
}
|
||||||
currentLayer() += shapelike::serialize<Formats::SVG>(tsh,
|
currentLayer() +=
|
||||||
1.0/conf_.mm_in_coord_units) + "\n";
|
shapelike::serialize<Formats::SVG>(tsh,
|
||||||
|
1.0 / conf_.mm_in_coord_units) +
|
||||||
|
"\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeItem(const Item& item) {
|
||||||
|
writeShape(item.transformedShape());
|
||||||
}
|
}
|
||||||
|
|
||||||
void writePackGroup(const PackGroup& result) {
|
void writePackGroup(const PackGroup& result) {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include "Arrange.hpp"
|
#include "Arrange.hpp"
|
||||||
#include "Geometry.hpp"
|
//#include "Geometry.hpp"
|
||||||
#include "SVG.hpp"
|
#include "SVG.hpp"
|
||||||
#include "MTUtils.hpp"
|
|
||||||
|
|
||||||
#include <libnest2d/backends/clipper/geometries.hpp>
|
#include <libnest2d/backends/clipper/geometries.hpp>
|
||||||
#include <libnest2d/optimizers/nlopt/subplex.hpp>
|
#include <libnest2d/optimizers/nlopt/subplex.hpp>
|
||||||
|
@ -83,7 +82,7 @@ const double BIG_ITEM_TRESHOLD = 0.02;
|
||||||
// Fill in the placer algorithm configuration with values carefully chosen for
|
// Fill in the placer algorithm configuration with values carefully chosen for
|
||||||
// Slic3r.
|
// Slic3r.
|
||||||
template<class PConf>
|
template<class PConf>
|
||||||
void fillConfig(PConf& pcfg) {
|
void fill_config(PConf& pcfg) {
|
||||||
|
|
||||||
// Align the arranged pile into the center of the bin
|
// Align the arranged pile into the center of the bin
|
||||||
pcfg.alignment = PConf::Alignment::CENTER;
|
pcfg.alignment = PConf::Alignment::CENTER;
|
||||||
|
@ -105,7 +104,7 @@ void fillConfig(PConf& pcfg) {
|
||||||
|
|
||||||
// Apply penalty to object function result. This is used only when alignment
|
// Apply penalty to object function result. This is used only when alignment
|
||||||
// after arrange is explicitly disabled (PConfig::Alignment::DONT_ALIGN)
|
// after arrange is explicitly disabled (PConfig::Alignment::DONT_ALIGN)
|
||||||
double fixed_overfit(const std::tuple<double, Box>& result, const Box &binbb)
|
static double fixed_overfit(const std::tuple<double, Box>& result, const Box &binbb)
|
||||||
{
|
{
|
||||||
double score = std::get<0>(result);
|
double score = std::get<0>(result);
|
||||||
Box pilebb = std::get<1>(result);
|
Box pilebb = std::get<1>(result);
|
||||||
|
@ -312,7 +311,7 @@ public:
|
||||||
, m_bin_area(sl::area(bin))
|
, m_bin_area(sl::area(bin))
|
||||||
, m_norm(std::sqrt(m_bin_area))
|
, m_norm(std::sqrt(m_bin_area))
|
||||||
{
|
{
|
||||||
fillConfig(m_pconf);
|
fill_config(m_pconf);
|
||||||
|
|
||||||
// Set up a callback that is called just before arranging starts
|
// Set up a callback that is called just before arranging starts
|
||||||
// This functionality is provided by the Nester class (m_pack).
|
// This functionality is provided by the Nester class (m_pack).
|
||||||
|
@ -363,6 +362,9 @@ public:
|
||||||
m_item_count = 0;
|
m_item_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PConfig& config() { return m_pconf; }
|
||||||
|
const PConfig& config() const { return m_pconf; }
|
||||||
|
|
||||||
inline void preload(std::vector<Item>& fixeditems) {
|
inline void preload(std::vector<Item>& fixeditems) {
|
||||||
m_pconf.alignment = PConfig::Alignment::DONT_ALIGN;
|
m_pconf.alignment = PConfig::Alignment::DONT_ALIGN;
|
||||||
auto bb = sl::boundingBox(m_bin);
|
auto bb = sl::boundingBox(m_bin);
|
||||||
|
@ -438,127 +440,6 @@ std::function<double(const Item &)> AutoArranger<clppr::Polygon>::get_objfn()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Circle to_lnCircle(const CircleBed& circ) {
|
|
||||||
return Circle({circ.center()(0), circ.center()(1)}, circ.radius());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the type of bed geometry from a simple vector of points.
|
|
||||||
void BedShapeHint::reset(BedShapes type)
|
|
||||||
{
|
|
||||||
if (m_type != type) {
|
|
||||||
if (m_type == bsIrregular)
|
|
||||||
m_bed.polygon.Slic3r::Polyline::~Polyline();
|
|
||||||
else if (type == bsIrregular)
|
|
||||||
::new (&m_bed.polygon) Polyline();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
BedShapeHint::BedShapeHint(const Polyline &bed) {
|
|
||||||
auto x = [](const Point& p) { return p(X); };
|
|
||||||
auto y = [](const Point& p) { return p(Y); };
|
|
||||||
|
|
||||||
auto width = [x](const BoundingBox& box) {
|
|
||||||
return x(box.max) - x(box.min);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto height = [y](const BoundingBox& box) {
|
|
||||||
return y(box.max) - y(box.min);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto area = [&width, &height](const BoundingBox& box) {
|
|
||||||
double w = width(box);
|
|
||||||
double h = height(box);
|
|
||||||
return w * h;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto poly_area = [](Polyline p) {
|
|
||||||
Polygon pp; pp.points.reserve(p.points.size() + 1);
|
|
||||||
pp.points = std::move(p.points);
|
|
||||||
pp.points.emplace_back(pp.points.front());
|
|
||||||
return std::abs(pp.area());
|
|
||||||
};
|
|
||||||
|
|
||||||
auto distance_to = [x, y](const Point& p1, const Point& p2) {
|
|
||||||
double dx = x(p2) - x(p1);
|
|
||||||
double dy = y(p2) - y(p1);
|
|
||||||
return std::sqrt(dx*dx + dy*dy);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto bb = bed.bounding_box();
|
|
||||||
|
|
||||||
auto isCircle = [bb, distance_to](const Polyline& polygon) {
|
|
||||||
auto center = bb.center();
|
|
||||||
std::vector<double> vertex_distances;
|
|
||||||
double avg_dist = 0;
|
|
||||||
for (auto pt: polygon.points)
|
|
||||||
{
|
|
||||||
double distance = distance_to(center, pt);
|
|
||||||
vertex_distances.push_back(distance);
|
|
||||||
avg_dist += distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
avg_dist /= vertex_distances.size();
|
|
||||||
|
|
||||||
CircleBed ret(center, avg_dist);
|
|
||||||
for(auto el : vertex_distances)
|
|
||||||
{
|
|
||||||
if (std::abs(el - avg_dist) > 10 * SCALED_EPSILON) {
|
|
||||||
ret = CircleBed();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto parea = poly_area(bed);
|
|
||||||
|
|
||||||
if( (1.0 - parea/area(bb)) < 1e-3 ) {
|
|
||||||
m_type = BedShapes::bsBox;
|
|
||||||
m_bed.box = bb;
|
|
||||||
}
|
|
||||||
else if(auto c = isCircle(bed)) {
|
|
||||||
m_type = BedShapes::bsCircle;
|
|
||||||
m_bed.circ = c;
|
|
||||||
} else {
|
|
||||||
assert(m_type != BedShapes::bsIrregular);
|
|
||||||
m_type = BedShapes::bsIrregular;
|
|
||||||
::new (&m_bed.polygon) Polyline(bed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BedShapeHint &BedShapeHint::operator=(BedShapeHint &&cpy)
|
|
||||||
{
|
|
||||||
reset(cpy.m_type);
|
|
||||||
|
|
||||||
switch(m_type) {
|
|
||||||
case bsBox: m_bed.box = std::move(cpy.m_bed.box); break;
|
|
||||||
case bsCircle: m_bed.circ = std::move(cpy.m_bed.circ); break;
|
|
||||||
case bsIrregular: m_bed.polygon = std::move(cpy.m_bed.polygon); break;
|
|
||||||
case bsInfinite: m_bed.infbed = std::move(cpy.m_bed.infbed); break;
|
|
||||||
case bsUnknown: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
BedShapeHint &BedShapeHint::operator=(const BedShapeHint &cpy)
|
|
||||||
{
|
|
||||||
reset(cpy.m_type);
|
|
||||||
|
|
||||||
switch(m_type) {
|
|
||||||
case bsBox: m_bed.box = cpy.m_bed.box; break;
|
|
||||||
case bsCircle: m_bed.circ = cpy.m_bed.circ; break;
|
|
||||||
case bsIrregular: m_bed.polygon = cpy.m_bed.polygon; break;
|
|
||||||
case bsInfinite: m_bed.infbed = cpy.m_bed.infbed; break;
|
|
||||||
case bsUnknown: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Bin> void remove_large_items(std::vector<Item> &items, Bin &&bin)
|
template<class Bin> void remove_large_items(std::vector<Item> &items, Bin &&bin)
|
||||||
{
|
{
|
||||||
auto it = items.begin();
|
auto it = items.begin();
|
||||||
|
@ -572,12 +453,12 @@ void _arrange(
|
||||||
std::vector<Item> & shapes,
|
std::vector<Item> & shapes,
|
||||||
std::vector<Item> & excludes,
|
std::vector<Item> & excludes,
|
||||||
const BinT & bin,
|
const BinT & bin,
|
||||||
coord_t minobjd,
|
const ArrangeParams & params,
|
||||||
std::function<void(unsigned)> progressfn,
|
std::function<void(unsigned)> progressfn,
|
||||||
std::function<bool()> stopfn)
|
std::function<bool()> stopfn)
|
||||||
{
|
{
|
||||||
// Integer ceiling the min distance from the bed perimeters
|
// Integer ceiling the min distance from the bed perimeters
|
||||||
coord_t md = minobjd;
|
coord_t md = params.min_obj_distance;
|
||||||
md = (md % 2) ? md / 2 + 1 : md / 2;
|
md = (md % 2) ? md / 2 + 1 : md / 2;
|
||||||
|
|
||||||
auto corrected_bin = bin;
|
auto corrected_bin = bin;
|
||||||
|
@ -585,7 +466,10 @@ void _arrange(
|
||||||
|
|
||||||
AutoArranger<BinT> arranger{corrected_bin, progressfn, stopfn};
|
AutoArranger<BinT> arranger{corrected_bin, progressfn, stopfn};
|
||||||
|
|
||||||
auto infl = coord_t(std::ceil(minobjd / 2.0));
|
arranger.config().accuracy = params.accuracy;
|
||||||
|
arranger.config().parallel = params.parallel;
|
||||||
|
|
||||||
|
auto infl = coord_t(std::ceil(params.min_obj_distance / 2.0));
|
||||||
for (Item& itm : shapes) itm.inflate(infl);
|
for (Item& itm : shapes) itm.inflate(infl);
|
||||||
for (Item& itm : excludes) itm.inflate(infl);
|
for (Item& itm : excludes) itm.inflate(infl);
|
||||||
|
|
||||||
|
@ -603,22 +487,49 @@ void _arrange(
|
||||||
for (Item &itm : inp) itm.inflate(-infl);
|
for (Item &itm : inp) itm.inflate(-infl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The final client function for arrangement. A progress indicator and
|
inline Box to_nestbin(const BoundingBox &bb) { return Box{{bb.min(X), bb.min(Y)}, {bb.max(X), bb.max(Y)}};}
|
||||||
// a stop predicate can be also be passed to control the process.
|
inline Circle to_nestbin(const CircleBed &c) { return Circle({c.center()(0), c.center()(1)}, c.radius()); }
|
||||||
void arrange(ArrangePolygons & arrangables,
|
inline clppr::Polygon to_nestbin(const Polygon &p) { return sl::create<clppr::Polygon>(Slic3rMultiPoint_to_ClipperPath(p)); }
|
||||||
const ArrangePolygons & excludes,
|
inline Box to_nestbin(const InfiniteBed &bed) { return Box::infinite({bed.center.x(), bed.center.y()}); }
|
||||||
coord_t min_obj_dist,
|
|
||||||
const BedShapeHint & bedhint,
|
|
||||||
std::function<void(unsigned)> progressind,
|
|
||||||
std::function<bool()> stopcondition)
|
|
||||||
{
|
|
||||||
namespace clppr = ClipperLib;
|
|
||||||
|
|
||||||
std::vector<Item> items, fixeditems;
|
inline coord_t width(const BoundingBox& box) { return box.max.x() - box.min.x(); }
|
||||||
items.reserve(arrangables.size());
|
inline coord_t height(const BoundingBox& box) { return box.max.y() - box.min.y(); }
|
||||||
|
inline double area(const BoundingBox& box) { return double(width(box)) * height(box); }
|
||||||
|
inline double poly_area(const Points &pts) { return std::abs(Polygon::area(pts)); }
|
||||||
|
inline double distance_to(const Point& p1, const Point& p2)
|
||||||
|
{
|
||||||
|
double dx = p2.x() - p1.x();
|
||||||
|
double dy = p2.y() - p1.y();
|
||||||
|
return std::sqrt(dx*dx + dy*dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CircleBed to_circle(const Point ¢er, const Points& points) {
|
||||||
|
std::vector<double> vertex_distances;
|
||||||
|
double avg_dist = 0;
|
||||||
|
|
||||||
|
for (auto pt : points)
|
||||||
|
{
|
||||||
|
double distance = distance_to(center, pt);
|
||||||
|
vertex_distances.push_back(distance);
|
||||||
|
avg_dist += distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
avg_dist /= vertex_distances.size();
|
||||||
|
|
||||||
|
CircleBed ret(center, avg_dist);
|
||||||
|
for(auto el : vertex_distances)
|
||||||
|
{
|
||||||
|
if (std::abs(el - avg_dist) > 10 * SCALED_EPSILON) {
|
||||||
|
ret = {};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// Create Item from Arrangeable
|
// Create Item from Arrangeable
|
||||||
auto process_arrangeable = [](const ArrangePolygon &arrpoly,
|
static void process_arrangeable(const ArrangePolygon &arrpoly,
|
||||||
std::vector<Item> & outp)
|
std::vector<Item> & outp)
|
||||||
{
|
{
|
||||||
Polygon p = arrpoly.poly.contour;
|
Polygon p = arrpoly.poly.contour;
|
||||||
|
@ -639,7 +550,42 @@ void arrange(ArrangePolygons & arrangables,
|
||||||
outp.back().translation({offs.x(), offs.y()});
|
outp.back().translation({offs.x(), offs.y()});
|
||||||
outp.back().binId(arrpoly.bed_idx);
|
outp.back().binId(arrpoly.bed_idx);
|
||||||
outp.back().priority(arrpoly.priority);
|
outp.back().priority(arrpoly.priority);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void arrange(ArrangePolygons & items,
|
||||||
|
const ArrangePolygons &excludes,
|
||||||
|
const Points & bed,
|
||||||
|
const ArrangeParams & params)
|
||||||
|
{
|
||||||
|
if (bed.empty())
|
||||||
|
arrange(items, excludes, InfiniteBed{}, params);
|
||||||
|
else if (bed.size() == 1)
|
||||||
|
arrange(items, excludes, InfiniteBed{bed.front()}, params);
|
||||||
|
else {
|
||||||
|
auto bb = BoundingBox(bed);
|
||||||
|
CircleBed circ = to_circle(bb.center(), bed);
|
||||||
|
auto parea = poly_area(bed);
|
||||||
|
|
||||||
|
if ((1.0 - parea / area(bb)) < 1e-3)
|
||||||
|
arrange(items, excludes, bb, params);
|
||||||
|
else if (!std::isnan(circ.radius()))
|
||||||
|
arrange(items, excludes, circ, params);
|
||||||
|
else
|
||||||
|
arrange(items, excludes, Polygon(bed), params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class BedT>
|
||||||
|
void arrange(ArrangePolygons & arrangables,
|
||||||
|
const ArrangePolygons &excludes,
|
||||||
|
const BedT & bed,
|
||||||
|
const ArrangeParams & params)
|
||||||
|
{
|
||||||
|
namespace clppr = ClipperLib;
|
||||||
|
|
||||||
|
std::vector<Item> items, fixeditems;
|
||||||
|
items.reserve(arrangables.size());
|
||||||
|
|
||||||
for (ArrangePolygon &arrangeable : arrangables)
|
for (ArrangePolygon &arrangeable : arrangables)
|
||||||
process_arrangeable(arrangeable, items);
|
process_arrangeable(arrangeable, items);
|
||||||
|
@ -649,45 +595,10 @@ void arrange(ArrangePolygons & arrangables,
|
||||||
|
|
||||||
for (Item &itm : fixeditems) itm.inflate(scaled(-2. * EPSILON));
|
for (Item &itm : fixeditems) itm.inflate(scaled(-2. * EPSILON));
|
||||||
|
|
||||||
auto &cfn = stopcondition;
|
auto &cfn = params.stopcondition;
|
||||||
auto &pri = progressind;
|
auto &pri = params.progressind;
|
||||||
|
|
||||||
switch (bedhint.get_type()) {
|
_arrange(items, fixeditems, to_nestbin(bed), params, pri, cfn);
|
||||||
case bsBox: {
|
|
||||||
// Create the arranger for the box shaped bed
|
|
||||||
BoundingBox bbb = bedhint.get_box();
|
|
||||||
Box binbb{{bbb.min(X), bbb.min(Y)}, {bbb.max(X), bbb.max(Y)}};
|
|
||||||
|
|
||||||
_arrange(items, fixeditems, binbb, min_obj_dist, pri, cfn);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case bsCircle: {
|
|
||||||
auto cc = to_lnCircle(bedhint.get_circle());
|
|
||||||
|
|
||||||
_arrange(items, fixeditems, cc, min_obj_dist, pri, cfn);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case bsIrregular: {
|
|
||||||
auto ctour = Slic3rMultiPoint_to_ClipperPath(bedhint.get_irregular());
|
|
||||||
auto irrbed = sl::create<clppr::Polygon>(std::move(ctour));
|
|
||||||
BoundingBox polybb(bedhint.get_irregular());
|
|
||||||
|
|
||||||
_arrange(items, fixeditems, irrbed, min_obj_dist, pri, cfn);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case bsInfinite: {
|
|
||||||
const InfiniteBed& nobin = bedhint.get_infinite();
|
|
||||||
auto infbb = Box::infinite({nobin.center.x(), nobin.center.y()});
|
|
||||||
|
|
||||||
_arrange(items, fixeditems, infbb, min_obj_dist, pri, cfn);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case bsUnknown: {
|
|
||||||
// We know nothing about the bed, let it be infinite and zero centered
|
|
||||||
_arrange(items, fixeditems, Box::infinite(), min_obj_dist, pri, cfn);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(size_t i = 0; i < items.size(); ++i) {
|
for(size_t i = 0; i < items.size(); ++i) {
|
||||||
clppr::IntPoint tr = items[i].translation();
|
clppr::IntPoint tr = items[i].translation();
|
||||||
|
@ -697,15 +608,10 @@ void arrange(ArrangePolygons & arrangables,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arrange, without the fixed items (excludes)
|
template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const BoundingBox &bed, const ArrangeParams ¶ms);
|
||||||
void arrange(ArrangePolygons & inp,
|
template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const CircleBed &bed, const ArrangeParams ¶ms);
|
||||||
coord_t min_d,
|
template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const Polygon &bed, const ArrangeParams ¶ms);
|
||||||
const BedShapeHint & bedhint,
|
template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const InfiniteBed &bed, const ArrangeParams ¶ms);
|
||||||
std::function<void(unsigned)> prfn,
|
|
||||||
std::function<bool()> stopfn)
|
|
||||||
{
|
|
||||||
arrange(inp, {}, min_d, bedhint, prfn, stopfn);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace arr
|
} // namespace arr
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
#ifndef MODELARRANGE_HPP
|
#ifndef ARRANGE_HPP
|
||||||
#define MODELARRANGE_HPP
|
#define ARRANGE_HPP
|
||||||
|
|
||||||
#include "ExPolygon.hpp"
|
#include "ExPolygon.hpp"
|
||||||
#include "BoundingBox.hpp"
|
#include "BoundingBox.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r { namespace arrangement {
|
||||||
|
|
||||||
namespace arrangement {
|
|
||||||
|
|
||||||
/// A geometry abstraction for a circular print bed. Similarly to BoundingBox.
|
/// A geometry abstraction for a circular print bed. Similarly to BoundingBox.
|
||||||
class CircleBed {
|
class CircleBed {
|
||||||
|
@ -15,96 +13,16 @@ class CircleBed {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
inline CircleBed(): center_(0, 0), radius_(std::nan("")) {}
|
inline CircleBed(): center_(0, 0), radius_(std::nan("")) {}
|
||||||
inline CircleBed(const Point& c, double r): center_(c), radius_(r) {}
|
explicit inline CircleBed(const Point& c, double r): center_(c), radius_(r) {}
|
||||||
|
|
||||||
inline double radius() const { return radius_; }
|
inline double radius() const { return radius_; }
|
||||||
inline const Point& center() const { return center_; }
|
inline const Point& center() const { return center_; }
|
||||||
inline operator bool() { return !std::isnan(radius_); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Representing an unbounded bed.
|
/// Representing an unbounded bed.
|
||||||
struct InfiniteBed { Point center; };
|
struct InfiniteBed {
|
||||||
|
Point center;
|
||||||
/// Types of print bed shapes.
|
explicit InfiniteBed(const Point &p = {0, 0}): center{p} {}
|
||||||
enum BedShapes {
|
|
||||||
bsBox,
|
|
||||||
bsCircle,
|
|
||||||
bsIrregular,
|
|
||||||
bsInfinite,
|
|
||||||
bsUnknown
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Info about the print bed for the arrange() function. This is a variant
|
|
||||||
/// holding one of the four shapes a bed can be.
|
|
||||||
class BedShapeHint {
|
|
||||||
BedShapes m_type = BedShapes::bsInfinite;
|
|
||||||
|
|
||||||
// The union neither calls constructors nor destructors of its members.
|
|
||||||
// The only member with non-trivial constructor / destructor is the polygon,
|
|
||||||
// a placement new / delete needs to be called over it.
|
|
||||||
union BedShape_u { // TODO: use variant from cpp17?
|
|
||||||
CircleBed circ;
|
|
||||||
BoundingBox box;
|
|
||||||
Polyline polygon;
|
|
||||||
InfiniteBed infbed{};
|
|
||||||
~BedShape_u() {}
|
|
||||||
BedShape_u() {}
|
|
||||||
} m_bed;
|
|
||||||
|
|
||||||
// Reset the type, allocate m_bed properly
|
|
||||||
void reset(BedShapes type);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
BedShapeHint(){}
|
|
||||||
|
|
||||||
/// Get a bed shape hint for arrange() from a naked Polyline.
|
|
||||||
explicit BedShapeHint(const Polyline &polyl);
|
|
||||||
explicit BedShapeHint(const BoundingBox &bb)
|
|
||||||
{
|
|
||||||
m_type = bsBox; m_bed.box = bb;
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit BedShapeHint(const CircleBed &c)
|
|
||||||
{
|
|
||||||
m_type = bsCircle; m_bed.circ = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit BedShapeHint(const InfiniteBed &ibed)
|
|
||||||
{
|
|
||||||
m_type = bsInfinite; m_bed.infbed = ibed;
|
|
||||||
}
|
|
||||||
|
|
||||||
~BedShapeHint()
|
|
||||||
{
|
|
||||||
if (m_type == BedShapes::bsIrregular)
|
|
||||||
m_bed.polygon.Slic3r::Polyline::~Polyline();
|
|
||||||
}
|
|
||||||
|
|
||||||
BedShapeHint(const BedShapeHint &cpy) { *this = cpy; }
|
|
||||||
BedShapeHint(BedShapeHint &&cpy) { *this = std::move(cpy); }
|
|
||||||
|
|
||||||
BedShapeHint &operator=(const BedShapeHint &cpy);
|
|
||||||
BedShapeHint& operator=(BedShapeHint &&cpy);
|
|
||||||
|
|
||||||
BedShapes get_type() const { return m_type; }
|
|
||||||
|
|
||||||
const BoundingBox &get_box() const
|
|
||||||
{
|
|
||||||
assert(m_type == bsBox); return m_bed.box;
|
|
||||||
}
|
|
||||||
const CircleBed &get_circle() const
|
|
||||||
{
|
|
||||||
assert(m_type == bsCircle); return m_bed.circ;
|
|
||||||
}
|
|
||||||
const Polyline &get_irregular() const
|
|
||||||
{
|
|
||||||
assert(m_type == bsIrregular); return m_bed.polygon;
|
|
||||||
}
|
|
||||||
const InfiniteBed &get_infinite() const
|
|
||||||
{
|
|
||||||
assert(m_type == bsInfinite); return m_bed.infbed;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A logical bed representing an object not being arranged. Either the arrange
|
/// A logical bed representing an object not being arranged. Either the arrange
|
||||||
|
@ -125,9 +43,14 @@ struct ArrangePolygon {
|
||||||
ExPolygon poly; /// The 2D silhouette to be arranged
|
ExPolygon poly; /// The 2D silhouette to be arranged
|
||||||
Vec2crd translation{0, 0}; /// The translation of the poly
|
Vec2crd translation{0, 0}; /// The translation of the poly
|
||||||
double rotation{0.0}; /// The rotation of the poly in radians
|
double rotation{0.0}; /// The rotation of the poly in radians
|
||||||
|
coord_t inflation = 0; /// Arrange with inflated polygon
|
||||||
int bed_idx{UNARRANGED}; /// To which logical bed does poly belong...
|
int bed_idx{UNARRANGED}; /// To which logical bed does poly belong...
|
||||||
int priority{0};
|
int priority{0};
|
||||||
|
|
||||||
|
// If empty, any rotation is allowed (currently unsupported)
|
||||||
|
// If only a zero is there, no rotation is allowed
|
||||||
|
std::vector<double> allowed_rotations = {0.};
|
||||||
|
|
||||||
/// Optional setter function which can store arbitrary data in its closure
|
/// Optional setter function which can store arbitrary data in its closure
|
||||||
std::function<void(const ArrangePolygon&)> setter = nullptr;
|
std::function<void(const ArrangePolygon&)> setter = nullptr;
|
||||||
|
|
||||||
|
@ -140,6 +63,30 @@ struct ArrangePolygon {
|
||||||
|
|
||||||
using ArrangePolygons = std::vector<ArrangePolygon>;
|
using ArrangePolygons = std::vector<ArrangePolygon>;
|
||||||
|
|
||||||
|
struct ArrangeParams {
|
||||||
|
|
||||||
|
/// The minimum distance which is allowed for any
|
||||||
|
/// pair of items on the print bed in any direction.
|
||||||
|
coord_t min_obj_distance = 0.;
|
||||||
|
|
||||||
|
/// The accuracy of optimization.
|
||||||
|
/// Goes from 0.0 to 1.0 and scales performance as well
|
||||||
|
float accuracy = 0.65f;
|
||||||
|
|
||||||
|
/// Allow parallel execution.
|
||||||
|
bool parallel = true;
|
||||||
|
|
||||||
|
/// Progress indicator callback called when an object gets packed.
|
||||||
|
/// The unsigned argument is the number of items remaining to pack.
|
||||||
|
std::function<void(unsigned)> progressind;
|
||||||
|
|
||||||
|
/// A predicate returning true if abort is needed.
|
||||||
|
std::function<bool(void)> stopcondition;
|
||||||
|
|
||||||
|
ArrangeParams() = default;
|
||||||
|
explicit ArrangeParams(coord_t md) : min_obj_distance(md) {}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Arranges the input polygons.
|
* \brief Arranges the input polygons.
|
||||||
*
|
*
|
||||||
|
@ -150,33 +97,23 @@ using ArrangePolygons = std::vector<ArrangePolygon>;
|
||||||
* \param items Input vector of ArrangePolygons. The transformation, rotation
|
* \param items Input vector of ArrangePolygons. The transformation, rotation
|
||||||
* and bin_idx fields will be changed after the call finished and can be used
|
* and bin_idx fields will be changed after the call finished and can be used
|
||||||
* to apply the result on the input polygon.
|
* to apply the result on the input polygon.
|
||||||
*
|
|
||||||
* \param min_obj_distance The minimum distance which is allowed for any
|
|
||||||
* pair of items on the print bed in any direction.
|
|
||||||
*
|
|
||||||
* \param bedhint Info about the shape and type of the bed.
|
|
||||||
*
|
|
||||||
* \param progressind Progress indicator callback called when
|
|
||||||
* an object gets packed. The unsigned argument is the number of items
|
|
||||||
* remaining to pack.
|
|
||||||
*
|
|
||||||
* \param stopcondition A predicate returning true if abort is needed.
|
|
||||||
*/
|
*/
|
||||||
void arrange(ArrangePolygons & items,
|
template<class TBed> void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const TBed &bed, const ArrangeParams ¶ms = {});
|
||||||
coord_t min_obj_distance,
|
|
||||||
const BedShapeHint & bedhint,
|
|
||||||
std::function<void(unsigned)> progressind = nullptr,
|
|
||||||
std::function<bool(void)> stopcondition = nullptr);
|
|
||||||
|
|
||||||
/// Same as the previous, only that it takes unmovable items as an
|
// A dispatch function that determines the bed shape from a set of points.
|
||||||
/// additional argument. Those will be considered as already arranged objects.
|
template<> void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const Points &bed, const ArrangeParams ¶ms);
|
||||||
void arrange(ArrangePolygons & items,
|
|
||||||
const ArrangePolygons & excludes,
|
extern template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const BoundingBox &bed, const ArrangeParams ¶ms);
|
||||||
coord_t min_obj_distance,
|
extern template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const CircleBed &bed, const ArrangeParams ¶ms);
|
||||||
const BedShapeHint & bedhint,
|
extern template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const Polygon &bed, const ArrangeParams ¶ms);
|
||||||
std::function<void(unsigned)> progressind = nullptr,
|
extern template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const InfiniteBed &bed, const ArrangeParams ¶ms);
|
||||||
std::function<bool(void)> stopcondition = nullptr);
|
|
||||||
|
inline void arrange(ArrangePolygons &items, const Points &bed, const ArrangeParams ¶ms = {}) { arrange(items, {}, bed, params); }
|
||||||
|
inline void arrange(ArrangePolygons &items, const BoundingBox &bed, const ArrangeParams ¶ms = {}) { arrange(items, {}, bed, params); }
|
||||||
|
inline void arrange(ArrangePolygons &items, const CircleBed &bed, const ArrangeParams ¶ms = {}) { arrange(items, {}, bed, params); }
|
||||||
|
inline void arrange(ArrangePolygons &items, const Polygon &bed, const ArrangeParams ¶ms = {}) { arrange(items, {}, bed, params); }
|
||||||
|
inline void arrange(ArrangePolygons &items, const InfiniteBed &bed, const ArrangeParams ¶ms = {}) { arrange(items, {}, bed, params); }
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arrangement
|
||||||
|
|
||||||
} // arr
|
|
||||||
} // Slic3r
|
|
||||||
#endif // MODELARRANGE_HPP
|
#endif // MODELARRANGE_HPP
|
||||||
|
|
|
@ -186,6 +186,11 @@ 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(0) >= bb.max(0) || bb.min(1) >= bb.max(1) || bb.min(2) >= bb.max(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline BoundingBox scaled(const BoundingBoxf &bb) { return {scaled(bb.min), scaled(bb.max)}; }
|
||||||
|
inline BoundingBox3 scaled(const BoundingBoxf3 &bb) { return {scaled(bb.min), scaled(bb.max)}; }
|
||||||
|
inline BoundingBoxf unscaled(const BoundingBox &bb) { return {unscaled(bb.min), unscaled(bb.max)}; }
|
||||||
|
inline BoundingBoxf3 unscaled(const BoundingBox3 &bb) { return {unscaled(bb.min), unscaled(bb.max)}; }
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
// Serialization through the Cereal library
|
// Serialization through the Cereal library
|
||||||
|
|
|
@ -77,6 +77,8 @@ add_library(libslic3r STATIC
|
||||||
Format/PRUS.hpp
|
Format/PRUS.hpp
|
||||||
Format/STL.cpp
|
Format/STL.cpp
|
||||||
Format/STL.hpp
|
Format/STL.hpp
|
||||||
|
Format/SL1.hpp
|
||||||
|
Format/SL1.cpp
|
||||||
GCode/Analyzer.cpp
|
GCode/Analyzer.cpp
|
||||||
GCode/Analyzer.hpp
|
GCode/Analyzer.hpp
|
||||||
GCode/ThumbnailData.cpp
|
GCode/ThumbnailData.cpp
|
||||||
|
@ -120,6 +122,8 @@ add_library(libslic3r STATIC
|
||||||
Line.hpp
|
Line.hpp
|
||||||
Model.cpp
|
Model.cpp
|
||||||
Model.hpp
|
Model.hpp
|
||||||
|
ModelArrange.hpp
|
||||||
|
ModelArrange.cpp
|
||||||
CustomGCode.cpp
|
CustomGCode.cpp
|
||||||
CustomGCode.hpp
|
CustomGCode.hpp
|
||||||
Arrange.hpp
|
Arrange.hpp
|
||||||
|
@ -160,6 +164,8 @@ add_library(libslic3r STATIC
|
||||||
SLAPrint.hpp
|
SLAPrint.hpp
|
||||||
Slicing.cpp
|
Slicing.cpp
|
||||||
Slicing.hpp
|
Slicing.hpp
|
||||||
|
SlicesToTriangleMesh.hpp
|
||||||
|
SlicesToTriangleMesh.cpp
|
||||||
SlicingAdaptive.cpp
|
SlicingAdaptive.cpp
|
||||||
SlicingAdaptive.hpp
|
SlicingAdaptive.hpp
|
||||||
SupportMaterial.cpp
|
SupportMaterial.cpp
|
||||||
|
@ -175,6 +181,8 @@ add_library(libslic3r STATIC
|
||||||
Tesselate.hpp
|
Tesselate.hpp
|
||||||
TriangleMesh.cpp
|
TriangleMesh.cpp
|
||||||
TriangleMesh.hpp
|
TriangleMesh.hpp
|
||||||
|
TriangulateWall.hpp
|
||||||
|
TriangulateWall.cpp
|
||||||
utils.cpp
|
utils.cpp
|
||||||
Utils.hpp
|
Utils.hpp
|
||||||
Time.cpp
|
Time.cpp
|
||||||
|
@ -189,6 +197,7 @@ add_library(libslic3r STATIC
|
||||||
SimplifyMesh.hpp
|
SimplifyMesh.hpp
|
||||||
SimplifyMeshImpl.hpp
|
SimplifyMeshImpl.hpp
|
||||||
SimplifyMesh.cpp
|
SimplifyMesh.cpp
|
||||||
|
MarchingSquares.hpp
|
||||||
${OpenVDBUtils_SOURCES}
|
${OpenVDBUtils_SOURCES}
|
||||||
SLA/Common.hpp
|
SLA/Common.hpp
|
||||||
SLA/Common.cpp
|
SLA/Common.cpp
|
||||||
|
@ -206,10 +215,11 @@ add_library(libslic3r STATIC
|
||||||
SLA/Rotfinder.cpp
|
SLA/Rotfinder.cpp
|
||||||
SLA/BoostAdapter.hpp
|
SLA/BoostAdapter.hpp
|
||||||
SLA/SpatIndex.hpp
|
SLA/SpatIndex.hpp
|
||||||
SLA/Raster.hpp
|
SLA/RasterBase.hpp
|
||||||
SLA/Raster.cpp
|
SLA/RasterBase.cpp
|
||||||
SLA/RasterWriter.hpp
|
SLA/AGGRaster.hpp
|
||||||
SLA/RasterWriter.cpp
|
SLA/RasterToPolygons.hpp
|
||||||
|
SLA/RasterToPolygons.cpp
|
||||||
SLA/ConcaveHull.hpp
|
SLA/ConcaveHull.hpp
|
||||||
SLA/ConcaveHull.cpp
|
SLA/ConcaveHull.cpp
|
||||||
SLA/Hollowing.hpp
|
SLA/Hollowing.hpp
|
||||||
|
@ -262,7 +272,8 @@ endif ()
|
||||||
encoding_check(libslic3r)
|
encoding_check(libslic3r)
|
||||||
|
|
||||||
target_compile_definitions(libslic3r PUBLIC -DUSE_TBB -DTBB_USE_CAPTURED_EXCEPTION=0)
|
target_compile_definitions(libslic3r PUBLIC -DUSE_TBB -DTBB_USE_CAPTURED_EXCEPTION=0)
|
||||||
target_include_directories(libslic3r PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${LIBNEST2D_INCLUDES} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
|
target_include_directories(libslic3r PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
target_include_directories(libslic3r PUBLIC ${EXPAT_INCLUDE_DIRS})
|
||||||
target_link_libraries(libslic3r
|
target_link_libraries(libslic3r
|
||||||
libnest2d
|
libnest2d
|
||||||
admesh
|
admesh
|
||||||
|
|
|
@ -312,6 +312,7 @@ std::string ExtrusionEntity::role_to_string(ExtrusionRole role)
|
||||||
case erOverhangPerimeter : return L("Overhang perimeter");
|
case erOverhangPerimeter : return L("Overhang perimeter");
|
||||||
case erInternalInfill : return L("Internal infill");
|
case erInternalInfill : return L("Internal infill");
|
||||||
case erSolidInfill : return L("Solid infill");
|
case erSolidInfill : return L("Solid infill");
|
||||||
|
case erIroning : return L("Ironing");
|
||||||
case erTopSolidInfill : return L("Top solid infill");
|
case erTopSolidInfill : return L("Top solid infill");
|
||||||
case erBridgeInfill : return L("Bridge infill");
|
case erBridgeInfill : return L("Bridge infill");
|
||||||
case erGapFill : return L("Gap fill");
|
case erGapFill : return L("Gap fill");
|
||||||
|
|
|
@ -22,6 +22,7 @@ enum ExtrusionRole : uint8_t {
|
||||||
erInternalInfill,
|
erInternalInfill,
|
||||||
erSolidInfill,
|
erSolidInfill,
|
||||||
erTopSolidInfill,
|
erTopSolidInfill,
|
||||||
|
erIroning,
|
||||||
erBridgeInfill,
|
erBridgeInfill,
|
||||||
erGapFill,
|
erGapFill,
|
||||||
erSkirt,
|
erSkirt,
|
||||||
|
@ -54,14 +55,16 @@ inline bool is_infill(ExtrusionRole role)
|
||||||
return role == erBridgeInfill
|
return role == erBridgeInfill
|
||||||
|| role == erInternalInfill
|
|| role == erInternalInfill
|
||||||
|| role == erSolidInfill
|
|| role == erSolidInfill
|
||||||
|| role == erTopSolidInfill;
|
|| role == erTopSolidInfill
|
||||||
|
|| role == erIroning;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_solid_infill(ExtrusionRole role)
|
inline bool is_solid_infill(ExtrusionRole role)
|
||||||
{
|
{
|
||||||
return role == erBridgeInfill
|
return role == erBridgeInfill
|
||||||
|| role == erSolidInfill
|
|| role == erSolidInfill
|
||||||
|| role == erTopSolidInfill;
|
|| role == erTopSolidInfill
|
||||||
|
|| role == erIroning;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_bridge(ExtrusionRole role) {
|
inline bool is_bridge(ExtrusionRole role) {
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "../Surface.hpp"
|
#include "../Surface.hpp"
|
||||||
|
|
||||||
#include "FillBase.hpp"
|
#include "FillBase.hpp"
|
||||||
|
#include "FillRectilinear2.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
@ -372,7 +373,11 @@ void Layer::make_fills()
|
||||||
// Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon.
|
// Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon.
|
||||||
f->spacing = surface_fill.params.spacing;
|
f->spacing = surface_fill.params.spacing;
|
||||||
surface_fill.surface.expolygon = std::move(expoly);
|
surface_fill.surface.expolygon = std::move(expoly);
|
||||||
Polylines polylines = f->fill_surface(&surface_fill.surface, params);
|
Polylines polylines;
|
||||||
|
try {
|
||||||
|
polylines = f->fill_surface(&surface_fill.surface, params);
|
||||||
|
} catch (InfillFailedException &) {
|
||||||
|
}
|
||||||
if (! polylines.empty()) {
|
if (! polylines.empty()) {
|
||||||
// calculate actual flow from spacing (which might have been adjusted by the infill
|
// calculate actual flow from spacing (which might have been adjusted by the infill
|
||||||
// pattern generator)
|
// pattern generator)
|
||||||
|
@ -388,8 +393,8 @@ void Layer::make_fills()
|
||||||
flow_width = new_flow.width;
|
flow_width = new_flow.width;
|
||||||
}
|
}
|
||||||
// Save into layer.
|
// Save into layer.
|
||||||
auto *eec = new ExtrusionEntityCollection();
|
ExtrusionEntityCollection* eec = nullptr;
|
||||||
m_regions[surface_fill.region_id]->fills.entities.push_back(eec);
|
m_regions[surface_fill.region_id]->fills.entities.push_back(eec = new ExtrusionEntityCollection());
|
||||||
// Only concentric fills are not sorted.
|
// Only concentric fills are not sorted.
|
||||||
eec->no_sort = f->no_sort();
|
eec->no_sort = f->no_sort();
|
||||||
extrusion_entities_append_paths(
|
extrusion_entities_append_paths(
|
||||||
|
@ -418,4 +423,170 @@ void Layer::make_fills()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create ironing extrusions over top surfaces.
|
||||||
|
void Layer::make_ironing()
|
||||||
|
{
|
||||||
|
// LayerRegion::slices contains surfaces marked with SurfaceType.
|
||||||
|
// Here we want to collect top surfaces extruded with the same extruder.
|
||||||
|
// A surface will be ironed with the same extruder to not contaminate the print with another material leaking from the nozzle.
|
||||||
|
|
||||||
|
// First classify regions based on the extruder used.
|
||||||
|
struct IroningParams {
|
||||||
|
int extruder = -1;
|
||||||
|
bool just_infill = false;
|
||||||
|
// Spacing of the ironing lines, also to calculate the extrusion flow from.
|
||||||
|
double line_spacing;
|
||||||
|
// Height of the extrusion, to calculate the extrusion flow from.
|
||||||
|
double height;
|
||||||
|
double speed;
|
||||||
|
double angle;
|
||||||
|
|
||||||
|
bool operator<(const IroningParams &rhs) const {
|
||||||
|
if (this->extruder < rhs.extruder)
|
||||||
|
return true;
|
||||||
|
if (this->extruder > rhs.extruder)
|
||||||
|
return false;
|
||||||
|
if (int(this->just_infill) < int(rhs.just_infill))
|
||||||
|
return true;
|
||||||
|
if (int(this->just_infill) > int(rhs.just_infill))
|
||||||
|
return false;
|
||||||
|
if (this->line_spacing < rhs.line_spacing)
|
||||||
|
return true;
|
||||||
|
if (this->line_spacing > rhs.line_spacing)
|
||||||
|
return false;
|
||||||
|
if (this->height < rhs.height)
|
||||||
|
return true;
|
||||||
|
if (this->height > rhs.height)
|
||||||
|
return false;
|
||||||
|
if (this->speed < rhs.speed)
|
||||||
|
return true;
|
||||||
|
if (this->speed > rhs.speed)
|
||||||
|
return false;
|
||||||
|
if (this->angle < rhs.angle)
|
||||||
|
return true;
|
||||||
|
if (this->angle > rhs.angle)
|
||||||
|
return false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const IroningParams &rhs) const {
|
||||||
|
return this->extruder == rhs.extruder && this->just_infill == rhs.just_infill &&
|
||||||
|
this->line_spacing == rhs.line_spacing && this->height == rhs.height && this->speed == rhs.speed &&
|
||||||
|
this->angle == rhs.angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
LayerRegion *layerm = nullptr;
|
||||||
|
|
||||||
|
// IdeaMaker: ironing
|
||||||
|
// ironing flowrate (5% percent)
|
||||||
|
// ironing speed (10 mm/sec)
|
||||||
|
|
||||||
|
// Kisslicer:
|
||||||
|
// iron off, Sweep, Group
|
||||||
|
// ironing speed: 15 mm/sec
|
||||||
|
|
||||||
|
// Cura:
|
||||||
|
// Pattern (zig-zag / concentric)
|
||||||
|
// line spacing (0.1mm)
|
||||||
|
// flow: from normal layer height. 10%
|
||||||
|
// speed: 20 mm/sec
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<IroningParams> by_extruder;
|
||||||
|
bool extruder_dont_care = this->object()->config().wipe_into_objects;
|
||||||
|
double default_layer_height = this->object()->config().layer_height;
|
||||||
|
|
||||||
|
for (LayerRegion *layerm : m_regions)
|
||||||
|
if (! layerm->slices.empty()) {
|
||||||
|
IroningParams ironing_params;
|
||||||
|
const PrintRegionConfig &config = layerm->region()->config();
|
||||||
|
if (config.ironing &&
|
||||||
|
(config.ironing_type == IroningType::AllSolid ||
|
||||||
|
(config.top_solid_layers > 0 &&
|
||||||
|
(config.ironing_type == IroningType::TopSurfaces ||
|
||||||
|
(config.ironing_type == IroningType::TopmostOnly && layerm->layer()->upper_layer == nullptr))))) {
|
||||||
|
if (config.perimeter_extruder == config.solid_infill_extruder || config.perimeters == 0) {
|
||||||
|
// Iron the whole face.
|
||||||
|
ironing_params.extruder = config.solid_infill_extruder;
|
||||||
|
} else {
|
||||||
|
// Iron just the infill.
|
||||||
|
ironing_params.extruder = config.solid_infill_extruder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ironing_params.extruder != -1) {
|
||||||
|
ironing_params.just_infill = false;
|
||||||
|
ironing_params.line_spacing = config.ironing_spacing;
|
||||||
|
ironing_params.height = default_layer_height * 0.01 * config.ironing_flowrate;
|
||||||
|
ironing_params.speed = config.ironing_speed;
|
||||||
|
ironing_params.angle = config.fill_angle * M_PI / 180.;
|
||||||
|
ironing_params.layerm = layerm;
|
||||||
|
by_extruder.emplace_back(ironing_params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::sort(by_extruder.begin(), by_extruder.end());
|
||||||
|
|
||||||
|
FillRectilinear2 fill;
|
||||||
|
FillParams fill_params;
|
||||||
|
fill.set_bounding_box(this->object()->bounding_box());
|
||||||
|
fill.layer_id = this->id();
|
||||||
|
fill.z = this->print_z;
|
||||||
|
fill.overlap = 0;
|
||||||
|
fill_params.density = 1.;
|
||||||
|
// fill_params.dont_connect = true;
|
||||||
|
fill_params.dont_connect = false;
|
||||||
|
fill_params.monotonous = true;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < by_extruder.size(); ++ i) {
|
||||||
|
// Find span of regions equivalent to the ironing operation.
|
||||||
|
IroningParams &ironing_params = by_extruder[i];
|
||||||
|
size_t j = i;
|
||||||
|
for (++ j; j < by_extruder.size() && ironing_params == by_extruder[j]; ++ j) ;
|
||||||
|
|
||||||
|
// Create the ironing extrusions for regions <i, j)
|
||||||
|
ExPolygons ironing_areas;
|
||||||
|
double nozzle_dmr = this->object()->print()->config().nozzle_diameter.values[ironing_params.extruder - 1];
|
||||||
|
if (ironing_params.just_infill) {
|
||||||
|
// Just infill.
|
||||||
|
} else {
|
||||||
|
// Infill and perimeter.
|
||||||
|
// Merge top surfaces with the same ironing parameters.
|
||||||
|
Polygons polys;
|
||||||
|
for (size_t k = i; k < j; ++ k)
|
||||||
|
for (const Surface &surface : by_extruder[k].layerm->slices.surfaces)
|
||||||
|
if (surface.surface_type == stTop)
|
||||||
|
polygons_append(polys, surface.expolygon);
|
||||||
|
// Trim the top surfaces with half the nozzle diameter.
|
||||||
|
ironing_areas = intersection_ex(polys, offset(this->lslices, - float(scale_(0.5 * nozzle_dmr))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the filler object.
|
||||||
|
fill.spacing = ironing_params.line_spacing;
|
||||||
|
fill.angle = float(ironing_params.angle + 0.25 * M_PI);
|
||||||
|
fill.link_max_length = (coord_t)scale_(3. * fill.spacing);
|
||||||
|
double height = ironing_params.height * fill.spacing / nozzle_dmr;
|
||||||
|
Flow flow = Flow::new_from_spacing(float(nozzle_dmr), 0., float(height), false);
|
||||||
|
double flow_mm3_per_mm = flow.mm3_per_mm();
|
||||||
|
Surface surface_fill(stTop, ExPolygon());
|
||||||
|
for (ExPolygon &expoly : ironing_areas) {
|
||||||
|
surface_fill.expolygon = std::move(expoly);
|
||||||
|
Polylines polylines;
|
||||||
|
try {
|
||||||
|
polylines = fill.fill_surface(&surface_fill, fill_params);
|
||||||
|
} catch (InfillFailedException &) {
|
||||||
|
}
|
||||||
|
if (! polylines.empty()) {
|
||||||
|
// Save into layer.
|
||||||
|
ExtrusionEntityCollection *eec = nullptr;
|
||||||
|
ironing_params.layerm->fills.entities.push_back(eec = new ExtrusionEntityCollection());
|
||||||
|
// Don't sort the ironing infill lines as they are monotonously ordered.
|
||||||
|
eec->no_sort = true;
|
||||||
|
extrusion_entities_append_paths(
|
||||||
|
eec->entities, std::move(polylines),
|
||||||
|
erIroning,
|
||||||
|
flow_mm3_per_mm, float(flow.width), float(height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -27,7 +27,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
|
||||||
case ip3DHoneycomb: return new Fill3DHoneycomb();
|
case ip3DHoneycomb: return new Fill3DHoneycomb();
|
||||||
case ipGyroid: return new FillGyroid();
|
case ipGyroid: return new FillGyroid();
|
||||||
case ipRectilinear: return new FillRectilinear2();
|
case ipRectilinear: return new FillRectilinear2();
|
||||||
// case ipRectilinear: return new FillRectilinear();
|
case ipMonotonous: return new FillMonotonous();
|
||||||
case ipLine: return new FillLine();
|
case ipLine: return new FillLine();
|
||||||
case ipGrid: return new FillGrid2();
|
case ipGrid: return new FillGrid2();
|
||||||
case ipTriangles: return new FillTriangles();
|
case ipTriangles: return new FillTriangles();
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
@ -18,29 +19,31 @@ namespace Slic3r {
|
||||||
class ExPolygon;
|
class ExPolygon;
|
||||||
class Surface;
|
class Surface;
|
||||||
|
|
||||||
|
class InfillFailedException : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
InfillFailedException() : std::runtime_error("Infill failed") {}
|
||||||
|
};
|
||||||
|
|
||||||
struct FillParams
|
struct FillParams
|
||||||
{
|
{
|
||||||
FillParams() {
|
|
||||||
memset(this, 0, sizeof(FillParams));
|
|
||||||
// Adjustment does not work.
|
|
||||||
dont_adjust = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool full_infill() const { return density > 0.9999f; }
|
bool full_infill() const { return density > 0.9999f; }
|
||||||
|
|
||||||
// Fill density, fraction in <0, 1>
|
// Fill density, fraction in <0, 1>
|
||||||
float density;
|
float density { 0.f };
|
||||||
|
|
||||||
// Don't connect the fill lines around the inner perimeter.
|
// Don't connect the fill lines around the inner perimeter.
|
||||||
bool dont_connect;
|
bool dont_connect { false };
|
||||||
|
|
||||||
// Don't adjust spacing to fill the space evenly.
|
// Don't adjust spacing to fill the space evenly.
|
||||||
bool dont_adjust;
|
bool dont_adjust { true };
|
||||||
|
|
||||||
|
// Monotonous infill - strictly left to right for better surface quality of top infills.
|
||||||
|
bool monotonous { false };
|
||||||
|
|
||||||
// For Honeycomb.
|
// For Honeycomb.
|
||||||
// we were requested to complete each loop;
|
// we were requested to complete each loop;
|
||||||
// in this case we don't try to make more continuous paths
|
// in this case we don't try to make more continuous paths
|
||||||
bool complete;
|
bool complete { false };
|
||||||
};
|
};
|
||||||
static_assert(IsTriviallyCopyable<FillParams>::value, "FillParams class is not POD (and it should be - see constructor).");
|
static_assert(IsTriviallyCopyable<FillParams>::value, "FillParams class is not POD (and it should be - see constructor).");
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,18 +13,27 @@ class FillRectilinear2 : public Fill
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual Fill* clone() const { return new FillRectilinear2(*this); };
|
virtual Fill* clone() const { return new FillRectilinear2(*this); };
|
||||||
virtual ~FillRectilinear2() {}
|
virtual ~FillRectilinear2() = default;
|
||||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool fill_surface_by_lines(const Surface *surface, const FillParams ¶ms, float angleBase, float pattern_shift, Polylines &polylines_out);
|
bool fill_surface_by_lines(const Surface *surface, const FillParams ¶ms, float angleBase, float pattern_shift, Polylines &polylines_out);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FillMonotonous : public FillRectilinear2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual Fill* clone() const { return new FillMonotonous(*this); };
|
||||||
|
virtual ~FillMonotonous() = default;
|
||||||
|
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
||||||
|
virtual bool no_sort() const { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
class FillGrid2 : public FillRectilinear2
|
class FillGrid2 : public FillRectilinear2
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual Fill* clone() const { return new FillGrid2(*this); };
|
virtual Fill* clone() const { return new FillGrid2(*this); };
|
||||||
virtual ~FillGrid2() {}
|
virtual ~FillGrid2() = default;
|
||||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -36,7 +45,7 @@ class FillTriangles : public FillRectilinear2
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual Fill* clone() const { return new FillTriangles(*this); };
|
virtual Fill* clone() const { return new FillTriangles(*this); };
|
||||||
virtual ~FillTriangles() {}
|
virtual ~FillTriangles() = default;
|
||||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -48,7 +57,7 @@ class FillStars : public FillRectilinear2
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual Fill* clone() const { return new FillStars(*this); };
|
virtual Fill* clone() const { return new FillStars(*this); };
|
||||||
virtual ~FillStars() {}
|
virtual ~FillStars() = default;
|
||||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -60,7 +69,7 @@ class FillCubic : public FillRectilinear2
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual Fill* clone() const { return new FillCubic(*this); };
|
virtual Fill* clone() const { return new FillCubic(*this); };
|
||||||
virtual ~FillCubic() {}
|
virtual ~FillCubic() = default;
|
||||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
171
src/libslic3r/Format/SL1.cpp
Normal file
171
src/libslic3r/Format/SL1.cpp
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
#include "SL1.hpp"
|
||||||
|
#include "GCode/ThumbnailData.hpp"
|
||||||
|
#include "libslic3r/Time.hpp"
|
||||||
|
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
#include "libslic3r/Zipper.hpp"
|
||||||
|
#include "libslic3r/SLAPrint.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
using ConfMap = std::map<std::string, std::string>;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::string to_ini(const ConfMap &m)
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
for (auto ¶m : m) ret += param.first + " = " + param.second + "\n";
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_cfg_value(const DynamicPrintConfig &cfg, const std::string &key)
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
|
||||||
|
if (cfg.has(key)) {
|
||||||
|
auto opt = cfg.option(key);
|
||||||
|
if (opt) ret = opt->serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill_iniconf(ConfMap &m, const SLAPrint &print)
|
||||||
|
{
|
||||||
|
auto &cfg = print.full_print_config();
|
||||||
|
m["layerHeight"] = get_cfg_value(cfg, "layer_height");
|
||||||
|
m["expTime"] = get_cfg_value(cfg, "exposure_time");
|
||||||
|
m["expTimeFirst"] = get_cfg_value(cfg, "initial_exposure_time");
|
||||||
|
m["materialName"] = get_cfg_value(cfg, "sla_material_settings_id");
|
||||||
|
m["printerModel"] = get_cfg_value(cfg, "printer_model");
|
||||||
|
m["printerVariant"] = get_cfg_value(cfg, "printer_variant");
|
||||||
|
m["printerProfile"] = get_cfg_value(cfg, "printer_settings_id");
|
||||||
|
m["printProfile"] = get_cfg_value(cfg, "sla_print_settings_id");
|
||||||
|
m["fileCreationTimestamp"] = Utils::utc_timestamp();
|
||||||
|
m["prusaSlicerVersion"] = SLIC3R_BUILD_ID;
|
||||||
|
|
||||||
|
SLAPrintStatistics stats = print.print_statistics();
|
||||||
|
// Set statistics values to the printer
|
||||||
|
|
||||||
|
double used_material = (stats.objects_used_material +
|
||||||
|
stats.support_used_material) / 1000;
|
||||||
|
|
||||||
|
int num_fade = print.default_object_config().faded_layers.getInt();
|
||||||
|
num_fade = num_fade >= 0 ? num_fade : 0;
|
||||||
|
|
||||||
|
m["usedMaterial"] = std::to_string(used_material);
|
||||||
|
m["numFade"] = std::to_string(num_fade);
|
||||||
|
m["numSlow"] = std::to_string(stats.slow_layers_count);
|
||||||
|
m["numFast"] = std::to_string(stats.fast_layers_count);
|
||||||
|
m["printTime"] = std::to_string(stats.estimated_print_time);
|
||||||
|
|
||||||
|
m["action"] = "print";
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill_slicerconf(ConfMap &m, const SLAPrint &print)
|
||||||
|
{
|
||||||
|
using namespace std::literals::string_view_literals;
|
||||||
|
|
||||||
|
// Sorted list of config keys, which shall not be stored into the ini.
|
||||||
|
static constexpr auto banned_keys = {
|
||||||
|
"compatible_printers"sv,
|
||||||
|
"compatible_prints"sv,
|
||||||
|
"print_host"sv,
|
||||||
|
"printhost_apikey"sv,
|
||||||
|
"printhost_cafile"sv
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(std::is_sorted(banned_keys.begin(), banned_keys.end()));
|
||||||
|
auto is_banned = [](const std::string &key) {
|
||||||
|
return std::binary_search(banned_keys.begin(), banned_keys.end(), key);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto &cfg = print.full_print_config();
|
||||||
|
for (const std::string &key : cfg.keys())
|
||||||
|
if (! is_banned(key) && ! cfg.option(key)->is_nil())
|
||||||
|
m[key] = cfg.opt_serialize(key);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
uqptr<sla::RasterBase> SL1Archive::create_raster() const
|
||||||
|
{
|
||||||
|
sla::RasterBase::Resolution res;
|
||||||
|
sla::RasterBase::PixelDim pxdim;
|
||||||
|
std::array<bool, 2> mirror;
|
||||||
|
|
||||||
|
double w = m_cfg.display_width.getFloat();
|
||||||
|
double h = m_cfg.display_height.getFloat();
|
||||||
|
auto pw = size_t(m_cfg.display_pixels_x.getInt());
|
||||||
|
auto ph = size_t(m_cfg.display_pixels_y.getInt());
|
||||||
|
|
||||||
|
mirror[X] = m_cfg.display_mirror_x.getBool();
|
||||||
|
mirror[Y] = m_cfg.display_mirror_y.getBool();
|
||||||
|
|
||||||
|
auto ro = m_cfg.display_orientation.getInt();
|
||||||
|
sla::RasterBase::Orientation orientation =
|
||||||
|
ro == sla::RasterBase::roPortrait ? sla::RasterBase::roPortrait :
|
||||||
|
sla::RasterBase::roLandscape;
|
||||||
|
|
||||||
|
if (orientation == sla::RasterBase::roPortrait) {
|
||||||
|
std::swap(w, h);
|
||||||
|
std::swap(pw, ph);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = sla::RasterBase::Resolution{pw, ph};
|
||||||
|
pxdim = sla::RasterBase::PixelDim{w / pw, h / ph};
|
||||||
|
sla::RasterBase::Trafo tr{orientation, mirror};
|
||||||
|
|
||||||
|
double gamma = m_cfg.gamma_correction.getFloat();
|
||||||
|
|
||||||
|
return sla::create_raster_grayscale_aa(res, pxdim, gamma, tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
sla::EncodedRaster SL1Archive::encode_raster(const sla::RasterBase &rst) const
|
||||||
|
{
|
||||||
|
return rst.encode(sla::PNGRasterEncoder());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SL1Archive::export_print(Zipper& zipper,
|
||||||
|
const SLAPrint &print,
|
||||||
|
const std::string &prjname)
|
||||||
|
{
|
||||||
|
std::string project =
|
||||||
|
prjname.empty() ?
|
||||||
|
boost::filesystem::path(zipper.get_filename()).stem().string() :
|
||||||
|
prjname;
|
||||||
|
|
||||||
|
ConfMap iniconf, slicerconf;
|
||||||
|
fill_iniconf(iniconf, print);
|
||||||
|
|
||||||
|
iniconf["jobDir"] = project;
|
||||||
|
|
||||||
|
fill_slicerconf(slicerconf, print);
|
||||||
|
|
||||||
|
try {
|
||||||
|
zipper.add_entry("config.ini");
|
||||||
|
zipper << to_ini(iniconf);
|
||||||
|
zipper.add_entry("prusaslicer.ini");
|
||||||
|
zipper << to_ini(slicerconf);
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
for (const sla::EncodedRaster &rst : m_layers) {
|
||||||
|
|
||||||
|
std::string imgname = project + string_printf("%.5d", i++) + "." +
|
||||||
|
rst.extension();
|
||||||
|
|
||||||
|
zipper.add_entry(imgname.c_str(), rst.data(), rst.size());
|
||||||
|
}
|
||||||
|
} catch(std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << e.what();
|
||||||
|
// Rethrow the exception
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
44
src/libslic3r/Format/SL1.hpp
Normal file
44
src/libslic3r/Format/SL1.hpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef ARCHIVETRAITS_HPP
|
||||||
|
#define ARCHIVETRAITS_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "libslic3r/Zipper.hpp"
|
||||||
|
#include "libslic3r/SLAPrint.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class SL1Archive: public SLAPrinter {
|
||||||
|
SLAPrinterConfig m_cfg;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uqptr<sla::RasterBase> create_raster() const override;
|
||||||
|
sla::EncodedRaster encode_raster(const sla::RasterBase &rst) const override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
SL1Archive() = default;
|
||||||
|
explicit SL1Archive(const SLAPrinterConfig &cfg): m_cfg(cfg) {}
|
||||||
|
explicit SL1Archive(SLAPrinterConfig &&cfg): m_cfg(std::move(cfg)) {}
|
||||||
|
|
||||||
|
void export_print(Zipper &zipper, const SLAPrint &print, const std::string &projectname = "");
|
||||||
|
void export_print(const std::string &fname, const SLAPrint &print, const std::string &projectname = "")
|
||||||
|
{
|
||||||
|
Zipper zipper(fname);
|
||||||
|
export_print(zipper, print, projectname);
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply(const SLAPrinterConfig &cfg) override
|
||||||
|
{
|
||||||
|
auto diff = m_cfg.diff(cfg);
|
||||||
|
if (!diff.empty()) {
|
||||||
|
m_cfg.apply_only(cfg, diff);
|
||||||
|
m_layers = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Slic3r::sla
|
||||||
|
|
||||||
|
#endif // ARCHIVETRAITS_HPP
|
|
@ -2246,12 +2246,14 @@ void GCode::process_layer(
|
||||||
const auto& by_region_specific = is_anything_overridden ? island.by_region_per_copy(by_region_per_copy_cache, static_cast<unsigned int>(instance_to_print.instance_id), extruder_id, print_wipe_extrusions != 0) : island.by_region;
|
const auto& by_region_specific = is_anything_overridden ? island.by_region_per_copy(by_region_per_copy_cache, static_cast<unsigned int>(instance_to_print.instance_id), extruder_id, print_wipe_extrusions != 0) : island.by_region;
|
||||||
//FIXME the following code prints regions in the order they are defined, the path is not optimized in any way.
|
//FIXME the following code prints regions in the order they are defined, the path is not optimized in any way.
|
||||||
if (print.config().infill_first) {
|
if (print.config().infill_first) {
|
||||||
gcode += this->extrude_infill(print, by_region_specific);
|
gcode += this->extrude_infill(print, by_region_specific, false);
|
||||||
gcode += this->extrude_perimeters(print, by_region_specific, lower_layer_edge_grids[instance_to_print.layer_id]);
|
gcode += this->extrude_perimeters(print, by_region_specific, lower_layer_edge_grids[instance_to_print.layer_id]);
|
||||||
} else {
|
} else {
|
||||||
gcode += this->extrude_perimeters(print, by_region_specific, lower_layer_edge_grids[instance_to_print.layer_id]);
|
gcode += this->extrude_perimeters(print, by_region_specific, lower_layer_edge_grids[instance_to_print.layer_id]);
|
||||||
gcode += this->extrude_infill(print,by_region_specific);
|
gcode += this->extrude_infill(print,by_region_specific, false);
|
||||||
}
|
}
|
||||||
|
// ironing
|
||||||
|
gcode += this->extrude_infill(print,by_region_specific, true);
|
||||||
}
|
}
|
||||||
if (this->config().gcode_label_objects)
|
if (this->config().gcode_label_objects)
|
||||||
gcode += std::string("; stop printing object ") + instance_to_print.print_object.model_object()->name + " id:" + std::to_string(instance_to_print.layer_id) + " copy " + std::to_string(instance_to_print.instance_id) + "\n";
|
gcode += std::string("; stop printing object ") + instance_to_print.print_object.model_object()->name + " id:" + std::to_string(instance_to_print.layer_id) + " copy " + std::to_string(instance_to_print.instance_id) + "\n";
|
||||||
|
@ -2873,21 +2875,29 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vector<Obje
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chain the paths hierarchically by a greedy algorithm to minimize a travel distance.
|
// Chain the paths hierarchically by a greedy algorithm to minimize a travel distance.
|
||||||
std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region)
|
std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region, bool ironing)
|
||||||
{
|
{
|
||||||
std::string gcode;
|
std::string gcode;
|
||||||
|
ExtrusionEntitiesPtr extrusions;
|
||||||
|
const char* extrusion_name = ironing ? "ironing" : "infill";
|
||||||
for (const ObjectByExtruder::Island::Region ®ion : by_region)
|
for (const ObjectByExtruder::Island::Region ®ion : by_region)
|
||||||
if (! region.infills.empty()) {
|
if (! region.infills.empty()) {
|
||||||
|
extrusions.clear();
|
||||||
|
extrusions.reserve(region.infills.size());
|
||||||
|
for (ExtrusionEntity *ee : region.infills)
|
||||||
|
if ((ee->role() == erIroning) == ironing)
|
||||||
|
extrusions.emplace_back(ee);
|
||||||
|
if (! extrusions.empty()) {
|
||||||
m_config.apply(print.regions()[®ion - &by_region.front()]->config());
|
m_config.apply(print.regions()[®ion - &by_region.front()]->config());
|
||||||
ExtrusionEntitiesPtr extrusions { region.infills };
|
|
||||||
chain_and_reorder_extrusion_entities(extrusions, &m_last_pos);
|
chain_and_reorder_extrusion_entities(extrusions, &m_last_pos);
|
||||||
for (const ExtrusionEntity *fill : extrusions) {
|
for (const ExtrusionEntity *fill : extrusions) {
|
||||||
auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(fill);
|
auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(fill);
|
||||||
if (eec) {
|
if (eec) {
|
||||||
for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities)
|
for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities)
|
||||||
gcode += this->extrude_entity(*ee, "infill");
|
gcode += this->extrude_entity(*ee, extrusion_name);
|
||||||
} else
|
} else
|
||||||
gcode += this->extrude_entity(*fill, "infill");
|
gcode += this->extrude_entity(*fill, extrusion_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return gcode;
|
return gcode;
|
||||||
|
@ -3027,6 +3037,8 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
speed = m_config.get_abs_value("solid_infill_speed");
|
speed = m_config.get_abs_value("solid_infill_speed");
|
||||||
} else if (path.role() == erTopSolidInfill) {
|
} else if (path.role() == erTopSolidInfill) {
|
||||||
speed = m_config.get_abs_value("top_solid_infill_speed");
|
speed = m_config.get_abs_value("top_solid_infill_speed");
|
||||||
|
} else if (path.role() == erIroning) {
|
||||||
|
speed = m_config.get_abs_value("ironing_speed");
|
||||||
} else if (path.role() == erGapFill) {
|
} else if (path.role() == erGapFill) {
|
||||||
speed = m_config.get_abs_value("gap_fill_speed");
|
speed = m_config.get_abs_value("gap_fill_speed");
|
||||||
} else {
|
} else {
|
||||||
|
@ -3427,10 +3439,13 @@ void GCode::ObjectByExtruder::Island::Region::append(const Type type, const Extr
|
||||||
|
|
||||||
// First we append the entities, there are eec->entities.size() of them:
|
// First we append the entities, there are eec->entities.size() of them:
|
||||||
size_t old_size = perimeters_or_infills->size();
|
size_t old_size = perimeters_or_infills->size();
|
||||||
size_t new_size = old_size + eec->entities.size();
|
size_t new_size = old_size + (eec->can_reverse() ? eec->entities.size() : 1);
|
||||||
perimeters_or_infills->reserve(new_size);
|
perimeters_or_infills->reserve(new_size);
|
||||||
|
if (eec->can_reverse()) {
|
||||||
for (auto* ee : eec->entities)
|
for (auto* ee : eec->entities)
|
||||||
perimeters_or_infills->emplace_back(ee);
|
perimeters_or_infills->emplace_back(ee);
|
||||||
|
} else
|
||||||
|
perimeters_or_infills->emplace_back(const_cast<ExtrusionEntityCollection*>(eec));
|
||||||
|
|
||||||
if (copies_extruder != nullptr) {
|
if (copies_extruder != nullptr) {
|
||||||
// Don't reallocate overrides if not needed.
|
// Don't reallocate overrides if not needed.
|
||||||
|
|
|
@ -295,7 +295,7 @@ private:
|
||||||
const size_t single_object_instance_idx);
|
const size_t single_object_instance_idx);
|
||||||
|
|
||||||
std::string extrude_perimeters(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region, std::unique_ptr<EdgeGrid::Grid> &lower_layer_edge_grid);
|
std::string extrude_perimeters(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region, std::unique_ptr<EdgeGrid::Grid> &lower_layer_edge_grid);
|
||||||
std::string extrude_infill(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region);
|
std::string extrude_infill(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region, bool ironing);
|
||||||
std::string extrude_support(const ExtrusionEntityCollection &support_fills);
|
std::string extrude_support(const ExtrusionEntityCollection &support_fills);
|
||||||
|
|
||||||
std::string travel_to(const Point &point, ExtrusionRole role, std::string comment);
|
std::string travel_to(const Point &point, ExtrusionRole role, std::string comment);
|
||||||
|
|
|
@ -117,6 +117,7 @@ const Color GCodePreviewData::Extrusion::Default_Extrusion_Role_Colors[erCount]
|
||||||
Color(1.0f, 1.0f, 0.0f, 1.0f), // erInternalInfill
|
Color(1.0f, 1.0f, 0.0f, 1.0f), // erInternalInfill
|
||||||
Color(1.0f, 0.0f, 1.0f, 1.0f), // erSolidInfill
|
Color(1.0f, 0.0f, 1.0f, 1.0f), // erSolidInfill
|
||||||
Color(0.0f, 1.0f, 1.0f, 1.0f), // erTopSolidInfill
|
Color(0.0f, 1.0f, 1.0f, 1.0f), // erTopSolidInfill
|
||||||
|
Color(0.0f, 1.0f, 1.0f, 1.0f), // erIroning
|
||||||
Color(0.5f, 0.5f, 0.5f, 1.0f), // erBridgeInfill
|
Color(0.5f, 0.5f, 0.5f, 1.0f), // erBridgeInfill
|
||||||
Color(1.0f, 1.0f, 1.0f, 1.0f), // erGapFill
|
Color(1.0f, 1.0f, 1.0f, 1.0f), // erGapFill
|
||||||
Color(0.5f, 0.0f, 0.0f, 1.0f), // erSkirt
|
Color(0.5f, 0.0f, 0.0f, 1.0f), // erSkirt
|
||||||
|
|
|
@ -36,11 +36,6 @@ public:
|
||||||
// collection of surfaces for infill generation
|
// collection of surfaces for infill generation
|
||||||
SurfaceCollection fill_surfaces;
|
SurfaceCollection fill_surfaces;
|
||||||
|
|
||||||
// Collection of perimeter surfaces. This is a cached result of diff(slices, fill_surfaces).
|
|
||||||
// While not necessary, the memory consumption is meager and it speeds up calculation.
|
|
||||||
// The perimeter_surfaces keep the IDs of the slices (top/bottom/)
|
|
||||||
SurfaceCollection perimeter_surfaces;
|
|
||||||
|
|
||||||
// collection of expolygons representing the bridged areas (thus not
|
// collection of expolygons representing the bridged areas (thus not
|
||||||
// needing support material)
|
// needing support material)
|
||||||
Polygons bridged;
|
Polygons bridged;
|
||||||
|
@ -140,6 +135,7 @@ public:
|
||||||
}
|
}
|
||||||
void make_perimeters();
|
void make_perimeters();
|
||||||
void make_fills();
|
void make_fills();
|
||||||
|
void make_ironing();
|
||||||
|
|
||||||
void export_region_slices_to_svg(const char *path) const;
|
void export_region_slices_to_svg(const char *path) const;
|
||||||
void export_region_fill_surfaces_to_svg(const char *path) const;
|
void export_region_fill_surfaces_to_svg(const char *path) const;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
#include "Point.hpp"
|
#include "Point.hpp"
|
||||||
|
#include "BoundingBox.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
@ -75,143 +76,6 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An std compatible random access iterator which uses indices to the
|
|
||||||
/// source vector thus resistant to invalidation caused by relocations. It
|
|
||||||
/// also "knows" its container. No comparison is neccesary to the container
|
|
||||||
/// "end()" iterator. The template can be instantiated with a different
|
|
||||||
/// value type than that of the container's but the types must be
|
|
||||||
/// compatible. E.g. a base class of the contained objects is compatible.
|
|
||||||
///
|
|
||||||
/// For a constant iterator, one can instantiate this template with a value
|
|
||||||
/// type preceded with 'const'.
|
|
||||||
template<class Vector, // The container type, must be random access...
|
|
||||||
class Value = typename Vector::value_type // The value type
|
|
||||||
>
|
|
||||||
class IndexBasedIterator
|
|
||||||
{
|
|
||||||
static const size_t NONE = size_t(-1);
|
|
||||||
|
|
||||||
std::reference_wrapper<Vector> m_index_ref;
|
|
||||||
size_t m_idx = NONE;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using value_type = Value;
|
|
||||||
using pointer = Value *;
|
|
||||||
using reference = Value &;
|
|
||||||
using difference_type = long;
|
|
||||||
using iterator_category = std::random_access_iterator_tag;
|
|
||||||
|
|
||||||
inline explicit IndexBasedIterator(Vector &index, size_t idx)
|
|
||||||
: m_index_ref(index), m_idx(idx)
|
|
||||||
{}
|
|
||||||
|
|
||||||
// Post increment
|
|
||||||
inline IndexBasedIterator operator++(int)
|
|
||||||
{
|
|
||||||
IndexBasedIterator cpy(*this);
|
|
||||||
++m_idx;
|
|
||||||
return cpy;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline IndexBasedIterator operator--(int)
|
|
||||||
{
|
|
||||||
IndexBasedIterator cpy(*this);
|
|
||||||
--m_idx;
|
|
||||||
return cpy;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline IndexBasedIterator &operator++()
|
|
||||||
{
|
|
||||||
++m_idx;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline IndexBasedIterator &operator--()
|
|
||||||
{
|
|
||||||
--m_idx;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline IndexBasedIterator &operator+=(difference_type l)
|
|
||||||
{
|
|
||||||
m_idx += size_t(l);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline IndexBasedIterator operator+(difference_type l)
|
|
||||||
{
|
|
||||||
auto cpy = *this;
|
|
||||||
cpy += l;
|
|
||||||
return cpy;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline IndexBasedIterator &operator-=(difference_type l)
|
|
||||||
{
|
|
||||||
m_idx -= size_t(l);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline IndexBasedIterator operator-(difference_type l)
|
|
||||||
{
|
|
||||||
auto cpy = *this;
|
|
||||||
cpy -= l;
|
|
||||||
return cpy;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator difference_type() { return difference_type(m_idx); }
|
|
||||||
|
|
||||||
/// Tesing the end of the container... this is not possible with std
|
|
||||||
/// iterators.
|
|
||||||
inline bool is_end() const
|
|
||||||
{
|
|
||||||
return m_idx >= m_index_ref.get().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Value &operator*() const
|
|
||||||
{
|
|
||||||
assert(m_idx < m_index_ref.get().size());
|
|
||||||
return m_index_ref.get().operator[](m_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Value *operator->() const
|
|
||||||
{
|
|
||||||
assert(m_idx < m_index_ref.get().size());
|
|
||||||
return &m_index_ref.get().operator[](m_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If both iterators point past the container, they are equal...
|
|
||||||
inline bool operator==(const IndexBasedIterator &other)
|
|
||||||
{
|
|
||||||
size_t e = m_index_ref.get().size();
|
|
||||||
return m_idx == other.m_idx || (m_idx >= e && other.m_idx >= e);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator!=(const IndexBasedIterator &other)
|
|
||||||
{
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator<=(const IndexBasedIterator &other)
|
|
||||||
{
|
|
||||||
return (m_idx < other.m_idx) || (*this == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator<(const IndexBasedIterator &other)
|
|
||||||
{
|
|
||||||
return m_idx < other.m_idx && (*this != other);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator>=(const IndexBasedIterator &other)
|
|
||||||
{
|
|
||||||
return m_idx > other.m_idx || *this == other;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator>(const IndexBasedIterator &other)
|
|
||||||
{
|
|
||||||
return m_idx > other.m_idx && *this != other;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A very simple range concept implementation with iterator-like objects.
|
/// A very simple range concept implementation with iterator-like objects.
|
||||||
template<class It> class Range
|
template<class It> class Range
|
||||||
{
|
{
|
||||||
|
@ -252,97 +116,6 @@ template<class T> struct remove_cvref
|
||||||
|
|
||||||
template<class T> using remove_cvref_t = typename remove_cvref<T>::type;
|
template<class T> using remove_cvref_t = typename remove_cvref<T>::type;
|
||||||
|
|
||||||
// A shorter C++14 style form of the enable_if metafunction
|
|
||||||
template<bool B, class T>
|
|
||||||
using enable_if_t = typename std::enable_if<B, T>::type;
|
|
||||||
|
|
||||||
// /////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Type safe conversions to and from scaled and unscaled coordinates
|
|
||||||
// /////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// A meta-predicate which is true for integers wider than or equal to coord_t
|
|
||||||
template<class I> struct is_scaled_coord
|
|
||||||
{
|
|
||||||
static const SLIC3R_CONSTEXPR bool value =
|
|
||||||
std::is_integral<I>::value &&
|
|
||||||
std::numeric_limits<I>::digits >=
|
|
||||||
std::numeric_limits<coord_t>::digits;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Meta predicates for floating, 'scaled coord' and generic arithmetic types
|
|
||||||
template<class T, class O = T>
|
|
||||||
using FloatingOnly = enable_if_t<std::is_floating_point<T>::value, O>;
|
|
||||||
|
|
||||||
template<class T, class O = T>
|
|
||||||
using ScaledCoordOnly = enable_if_t<is_scaled_coord<T>::value, O>;
|
|
||||||
|
|
||||||
template<class T, class O = T>
|
|
||||||
using IntegerOnly = enable_if_t<std::is_integral<T>::value, O>;
|
|
||||||
|
|
||||||
template<class T, class O = T>
|
|
||||||
using ArithmeticOnly = enable_if_t<std::is_arithmetic<T>::value, O>;
|
|
||||||
|
|
||||||
// Semantics are the following:
|
|
||||||
// Upscaling (scaled()): only from floating point types (or Vec) to either
|
|
||||||
// floating point or integer 'scaled coord' coordinates.
|
|
||||||
// Downscaling (unscaled()): from arithmetic (or Vec) to floating point only
|
|
||||||
|
|
||||||
// Conversion definition from unscaled to floating point scaled
|
|
||||||
template<class Tout,
|
|
||||||
class Tin,
|
|
||||||
class = FloatingOnly<Tin>>
|
|
||||||
inline constexpr FloatingOnly<Tout> scaled(const Tin &v) noexcept
|
|
||||||
{
|
|
||||||
return Tout(v / Tin(SCALING_FACTOR));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conversion definition from unscaled to integer 'scaled coord'.
|
|
||||||
// TODO: is the rounding necessary? Here it is commented out to show that
|
|
||||||
// it can be different for integers but it does not have to be. Using
|
|
||||||
// std::round means loosing noexcept and constexpr modifiers
|
|
||||||
template<class Tout = coord_t, class Tin, class = FloatingOnly<Tin>>
|
|
||||||
inline constexpr ScaledCoordOnly<Tout> scaled(const Tin &v) noexcept
|
|
||||||
{
|
|
||||||
//return static_cast<Tout>(std::round(v / SCALING_FACTOR));
|
|
||||||
return Tout(v / Tin(SCALING_FACTOR));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conversion for Eigen vectors (N dimensional points)
|
|
||||||
template<class Tout = coord_t,
|
|
||||||
class Tin,
|
|
||||||
int N,
|
|
||||||
class = FloatingOnly<Tin>,
|
|
||||||
int...EigenArgs>
|
|
||||||
inline Eigen::Matrix<ArithmeticOnly<Tout>, N, EigenArgs...>
|
|
||||||
scaled(const Eigen::Matrix<Tin, N, EigenArgs...> &v)
|
|
||||||
{
|
|
||||||
return (v / SCALING_FACTOR).template cast<Tout>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conversion from arithmetic scaled type to floating point unscaled
|
|
||||||
template<class Tout = double,
|
|
||||||
class Tin,
|
|
||||||
class = ArithmeticOnly<Tin>,
|
|
||||||
class = FloatingOnly<Tout>>
|
|
||||||
inline constexpr Tout unscaled(const Tin &v) noexcept
|
|
||||||
{
|
|
||||||
return Tout(v * Tout(SCALING_FACTOR));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unscaling for Eigen vectors. Input base type can be arithmetic, output base
|
|
||||||
// type can only be floating point.
|
|
||||||
template<class Tout = double,
|
|
||||||
class Tin,
|
|
||||||
int N,
|
|
||||||
class = ArithmeticOnly<Tin>,
|
|
||||||
class = FloatingOnly<Tout>,
|
|
||||||
int...EigenArgs>
|
|
||||||
inline constexpr Eigen::Matrix<Tout, N, EigenArgs...>
|
|
||||||
unscaled(const Eigen::Matrix<Tin, N, EigenArgs...> &v) noexcept
|
|
||||||
{
|
|
||||||
return v.template cast<Tout>() * SCALING_FACTOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T, class I, class... Args> // Arbitrary allocator can be used
|
template<class T, class I, class... Args> // Arbitrary allocator can be used
|
||||||
inline IntegerOnly<I, std::vector<T, Args...>> reserve_vector(I capacity)
|
inline IntegerOnly<I, std::vector<T, Args...>> reserve_vector(I capacity)
|
||||||
{
|
{
|
||||||
|
@ -353,10 +126,10 @@ inline IntegerOnly<I, std::vector<T, Args...>> reserve_vector(I capacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exactly like Matlab https://www.mathworks.com/help/matlab/ref/linspace.html
|
/// Exactly like Matlab https://www.mathworks.com/help/matlab/ref/linspace.html
|
||||||
template<class T, class I>
|
template<class T, class I, class = IntegerOnly<I>>
|
||||||
inline std::vector<T> linspace_vector(const ArithmeticOnly<T> &start,
|
inline std::vector<T> linspace_vector(const ArithmeticOnly<T> &start,
|
||||||
const T &stop,
|
const T &stop,
|
||||||
const IntegerOnly<I> &n)
|
const I &n)
|
||||||
{
|
{
|
||||||
std::vector<T> vals(n, T());
|
std::vector<T> vals(n, T());
|
||||||
|
|
||||||
|
|
448
src/libslic3r/MarchingSquares.hpp
Normal file
448
src/libslic3r/MarchingSquares.hpp
Normal file
|
@ -0,0 +1,448 @@
|
||||||
|
#ifndef MARCHINGSQUARES_HPP
|
||||||
|
#define MARCHINGSQUARES_HPP
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace marchsq {
|
||||||
|
|
||||||
|
// Marks a square in the grid
|
||||||
|
struct Coord {
|
||||||
|
long r = 0, c = 0;
|
||||||
|
|
||||||
|
Coord() = default;
|
||||||
|
explicit Coord(long s) : r(s), c(s) {}
|
||||||
|
Coord(long _r, long _c): r(_r), c(_c) {}
|
||||||
|
|
||||||
|
size_t seq(const Coord &res) const { return r * res.c + c; }
|
||||||
|
Coord& operator+=(const Coord& b) { r += b.r; c += b.c; return *this; }
|
||||||
|
Coord operator+(const Coord& b) const { Coord a = *this; a += b; return a; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Closed ring of cell coordinates
|
||||||
|
using Ring = std::vector<Coord>;
|
||||||
|
|
||||||
|
// Specialize this struct to register a raster type for the Marching squares alg
|
||||||
|
template<class T, class Enable = void> struct _RasterTraits {
|
||||||
|
|
||||||
|
// The type of pixel cell in the raster
|
||||||
|
using ValueType = typename T::ValueType;
|
||||||
|
|
||||||
|
// Value at a given position
|
||||||
|
static ValueType get(const T &raster, size_t row, size_t col);
|
||||||
|
|
||||||
|
// Number of rows and cols of the raster
|
||||||
|
static size_t rows(const T &raster);
|
||||||
|
static size_t cols(const T &raster);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialize this to use parellel loops within the algorithm
|
||||||
|
template<class ExecutionPolicy, class Enable = void> struct _Loop {
|
||||||
|
template<class It, class Fn> static void for_each(It from, It to, Fn &&fn)
|
||||||
|
{
|
||||||
|
for (auto it = from; it < to; ++it) fn(*it, size_t(it - from));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace __impl {
|
||||||
|
|
||||||
|
template<class T> using RasterTraits = _RasterTraits<std::decay_t<T>>;
|
||||||
|
template<class T> using TRasterValue = typename RasterTraits<T>::ValueType;
|
||||||
|
|
||||||
|
template<class T> size_t rows(const T &raster)
|
||||||
|
{
|
||||||
|
return RasterTraits<T>::rows(raster);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> size_t cols(const T &raster)
|
||||||
|
{
|
||||||
|
return RasterTraits<T>::cols(raster);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> TRasterValue<T> isoval(const T &rst, const Coord &crd)
|
||||||
|
{
|
||||||
|
return RasterTraits<T>::get(rst, crd.r, crd.c);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ExecutionPolicy, class It, class Fn>
|
||||||
|
void for_each(ExecutionPolicy&& policy, It from, It to, Fn &&fn)
|
||||||
|
{
|
||||||
|
_Loop<ExecutionPolicy>::for_each(from, to, fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type of squares (tiles) depending on which vertices are inside an ROI
|
||||||
|
// The vertices would be marked a, b, c, d in counter clockwise order from the
|
||||||
|
// bottom left vertex of a square.
|
||||||
|
// d --- c
|
||||||
|
// | |
|
||||||
|
// | |
|
||||||
|
// a --- b
|
||||||
|
enum class SquareTag : uint8_t {
|
||||||
|
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
||||||
|
none, a, b, ab, c, ac, bc, abc, d, ad, bd, abd, cd, acd, bcd, full
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class E> constexpr std::underlying_type_t<E> _t(E e) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<std::underlying_type_t<E>>(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Dir: uint8_t { left, down, right, up, none};
|
||||||
|
|
||||||
|
static const constexpr Dir NEXT_CCW[] = {
|
||||||
|
/* 00 */ Dir::none, // SquareTag::none (empty square, nowhere to go)
|
||||||
|
/* 01 */ Dir::left, // SquareTag::a
|
||||||
|
/* 02 */ Dir::down, // SquareTag::b
|
||||||
|
/* 03 */ Dir::left, // SquareTag::ab
|
||||||
|
/* 04 */ Dir::right, // SquareTag::c
|
||||||
|
/* 05 */ Dir::none, // SquareTag::ac (ambiguous case)
|
||||||
|
/* 06 */ Dir::down, // SquareTag::bc
|
||||||
|
/* 07 */ Dir::left, // SquareTag::abc
|
||||||
|
/* 08 */ Dir::up, // SquareTag::d
|
||||||
|
/* 09 */ Dir::up, // SquareTag::ad
|
||||||
|
/* 10 */ Dir::none, // SquareTag::bd (ambiguous case)
|
||||||
|
/* 11 */ Dir::up, // SquareTag::abd
|
||||||
|
/* 12 */ Dir::right, // SquareTag::cd
|
||||||
|
/* 13 */ Dir::right, // SquareTag::acd
|
||||||
|
/* 14 */ Dir::down, // SquareTag::bcd
|
||||||
|
/* 15 */ Dir::none // SquareTag::full (full covered, nowhere to go)
|
||||||
|
};
|
||||||
|
|
||||||
|
static const constexpr uint8_t PREV_CCW[] = {
|
||||||
|
/* 00 */ 1 << _t(Dir::none),
|
||||||
|
/* 01 */ 1 << _t(Dir::up),
|
||||||
|
/* 02 */ 1 << _t(Dir::left),
|
||||||
|
/* 03 */ 1 << _t(Dir::left),
|
||||||
|
/* 04 */ 1 << _t(Dir::down),
|
||||||
|
/* 05 */ 1 << _t(Dir::up) | 1 << _t(Dir::down),
|
||||||
|
/* 06 */ 1 << _t(Dir::down),
|
||||||
|
/* 07 */ 1 << _t(Dir::down),
|
||||||
|
/* 08 */ 1 << _t(Dir::right),
|
||||||
|
/* 09 */ 1 << _t(Dir::up),
|
||||||
|
/* 10 */ 1 << _t(Dir::left) | 1 << _t(Dir::right),
|
||||||
|
/* 11 */ 1 << _t(Dir::left),
|
||||||
|
/* 12 */ 1 << _t(Dir::right),
|
||||||
|
/* 13 */ 1 << _t(Dir::up),
|
||||||
|
/* 14 */ 1 << _t(Dir::right),
|
||||||
|
/* 15 */ 1 << _t(Dir::none)
|
||||||
|
};
|
||||||
|
|
||||||
|
const constexpr uint8_t DIRMASKS[] = {
|
||||||
|
/*left: */ 0x01, /*down*/ 0x12, /*right */0x21, /*up*/ 0x10, /*none*/ 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
inline Coord step(const Coord &crd, Dir d)
|
||||||
|
{
|
||||||
|
uint8_t dd = DIRMASKS[uint8_t(d)];
|
||||||
|
return {crd.r - 1 + (dd & 0x0f), crd.c - 1 + (dd >> 4)};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Rst> class Grid {
|
||||||
|
const Rst * m_rst = nullptr;
|
||||||
|
Coord m_cellsize, m_res_1, m_window, m_gridsize, m_grid_1;
|
||||||
|
std::vector<uint8_t> m_tags; // Assign tags to each square
|
||||||
|
|
||||||
|
Coord rastercoord(const Coord &crd) const
|
||||||
|
{
|
||||||
|
return {(crd.r - 1) * m_window.r, (crd.c - 1) * m_window.c};
|
||||||
|
}
|
||||||
|
|
||||||
|
Coord bl(const Coord &crd) const { return tl(crd) + Coord{m_res_1.r, 0}; }
|
||||||
|
Coord br(const Coord &crd) const { return tl(crd) + Coord{m_res_1.r, m_res_1.c}; }
|
||||||
|
Coord tr(const Coord &crd) const { return tl(crd) + Coord{0, m_res_1.c}; }
|
||||||
|
Coord tl(const Coord &crd) const { return rastercoord(crd); }
|
||||||
|
|
||||||
|
bool is_within(const Coord &crd)
|
||||||
|
{
|
||||||
|
long R = rows(*m_rst), C = cols(*m_rst);
|
||||||
|
return crd.r >= 0 && crd.r < R && crd.c >= 0 && crd.c < C;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate the tag for a cell (or square). The cell coordinates mark the
|
||||||
|
// top left vertex of a square in the raster. v is the isovalue
|
||||||
|
uint8_t get_tag_for_cell(const Coord &cell, TRasterValue<Rst> v)
|
||||||
|
{
|
||||||
|
Coord sqr[] = {bl(cell), br(cell), tr(cell), tl(cell)};
|
||||||
|
|
||||||
|
uint8_t t = ((is_within(sqr[0]) && isoval(*m_rst, sqr[0]) >= v)) +
|
||||||
|
((is_within(sqr[1]) && isoval(*m_rst, sqr[1]) >= v) << 1) +
|
||||||
|
((is_within(sqr[2]) && isoval(*m_rst, sqr[2]) >= v) << 2) +
|
||||||
|
((is_within(sqr[3]) && isoval(*m_rst, sqr[3]) >= v) << 3);
|
||||||
|
|
||||||
|
assert(t < 16);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a cell coordinate from a sequential index
|
||||||
|
Coord coord(size_t i) const
|
||||||
|
{
|
||||||
|
return {long(i) / m_gridsize.c, long(i) % m_gridsize.c};
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t seq(const Coord &crd) const { return crd.seq(m_gridsize); }
|
||||||
|
|
||||||
|
bool is_visited(size_t idx, Dir d = Dir::none) const
|
||||||
|
{
|
||||||
|
SquareTag t = get_tag(idx);
|
||||||
|
uint8_t ref = d == Dir::none ? PREV_CCW[_t(t)] : uint8_t(1 << _t(d));
|
||||||
|
return t == SquareTag::full || t == SquareTag::none ||
|
||||||
|
((m_tags[idx] & 0xf0) >> 4) == ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_visited(size_t idx, Dir d = Dir::none)
|
||||||
|
{
|
||||||
|
m_tags[idx] |= (1 << (_t(d)) << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_ambiguous(size_t idx) const
|
||||||
|
{
|
||||||
|
SquareTag t = get_tag(idx);
|
||||||
|
return t == SquareTag::ac || t == SquareTag::bd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for a new starting square
|
||||||
|
size_t search_start_cell(size_t i = 0) const
|
||||||
|
{
|
||||||
|
// Skip ambiguous tags as starting tags due to unknown previous
|
||||||
|
// direction.
|
||||||
|
while ((i < m_tags.size()) && (is_visited(i) || is_ambiguous(i))) ++i;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
SquareTag get_tag(size_t idx) const { return SquareTag(m_tags[idx] & 0x0f); }
|
||||||
|
|
||||||
|
Dir next_dir(Dir prev, SquareTag tag) const
|
||||||
|
{
|
||||||
|
// Treat ambiguous cases as two separate regions in one square.
|
||||||
|
switch (tag) {
|
||||||
|
case SquareTag::ac:
|
||||||
|
switch (prev) {
|
||||||
|
case Dir::down: return Dir::right;
|
||||||
|
case Dir::up: return Dir::left;
|
||||||
|
default: assert(false); return Dir::none;
|
||||||
|
}
|
||||||
|
case SquareTag::bd:
|
||||||
|
switch (prev) {
|
||||||
|
case Dir::right: return Dir::up;
|
||||||
|
case Dir::left: return Dir::down;
|
||||||
|
default: assert(false); return Dir::none;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return NEXT_CCW[uint8_t(tag)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Dir::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CellIt {
|
||||||
|
Coord crd; Dir dir= Dir::none; const Rst *grid = nullptr;
|
||||||
|
|
||||||
|
TRasterValue<Rst> operator*() const { return isoval(*grid, crd); }
|
||||||
|
CellIt& operator++() { crd = step(crd, dir); return *this; }
|
||||||
|
CellIt operator++(int) { CellIt it = *this; ++(*this); return it; }
|
||||||
|
bool operator!=(const CellIt &it) { return crd.r != it.crd.r || crd.c != it.crd.c; }
|
||||||
|
|
||||||
|
using value_type = TRasterValue<Rst>;
|
||||||
|
using pointer = TRasterValue<Rst> *;
|
||||||
|
using reference = TRasterValue<Rst> &;
|
||||||
|
using difference_type = long;
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Two cell iterators representing an edge of a square. This is then
|
||||||
|
// used for binary search for the first active pixel on the edge.
|
||||||
|
struct Edge { CellIt from, to; };
|
||||||
|
|
||||||
|
Edge _edge(const Coord &ringvertex) const
|
||||||
|
{
|
||||||
|
size_t idx = ringvertex.r;
|
||||||
|
Coord cell = coord(idx);
|
||||||
|
uint8_t tg = m_tags[ringvertex.r];
|
||||||
|
SquareTag t = SquareTag(tg & 0x0f);
|
||||||
|
|
||||||
|
switch (t) {
|
||||||
|
case SquareTag::a:
|
||||||
|
case SquareTag::ab:
|
||||||
|
case SquareTag::abc:
|
||||||
|
return {{tl(cell), Dir::down, m_rst}, {bl(cell)}};
|
||||||
|
case SquareTag::b:
|
||||||
|
case SquareTag::bc:
|
||||||
|
case SquareTag::bcd:
|
||||||
|
return {{bl(cell), Dir::right, m_rst}, {br(cell)}};
|
||||||
|
case SquareTag::c:
|
||||||
|
return {{br(cell), Dir::up, m_rst}, {tr(cell)}};
|
||||||
|
case SquareTag::ac:
|
||||||
|
switch (Dir(ringvertex.c)) {
|
||||||
|
case Dir::left: return {{tl(cell), Dir::down, m_rst}, {bl(cell)}};
|
||||||
|
case Dir::right: return {{br(cell), Dir::up, m_rst}, {tr(cell)}};
|
||||||
|
default: assert(false);
|
||||||
|
}
|
||||||
|
case SquareTag::d:
|
||||||
|
case SquareTag::ad:
|
||||||
|
case SquareTag::abd:
|
||||||
|
return {{tr(cell), Dir::left, m_rst}, {tl(cell)}};
|
||||||
|
case SquareTag::bd:
|
||||||
|
switch (Dir(ringvertex.c)) {
|
||||||
|
case Dir::down: return {{bl(cell), Dir::right, m_rst}, {br(cell)}};
|
||||||
|
case Dir::up: return {{tr(cell), Dir::left, m_rst}, {tl(cell)}};
|
||||||
|
default: assert(false);
|
||||||
|
}
|
||||||
|
case SquareTag::cd:
|
||||||
|
case SquareTag::acd:
|
||||||
|
return {{br(cell), Dir::up, m_rst}, {tr(cell)}};
|
||||||
|
case SquareTag::full:
|
||||||
|
case SquareTag::none: {
|
||||||
|
Coord crd{tl(cell) + Coord{m_cellsize.r / 2, m_cellsize.c / 2}};
|
||||||
|
return {{crd, Dir::none, m_rst}, crd};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Edge edge(const Coord &ringvertex) const
|
||||||
|
{
|
||||||
|
const long R = rows(*m_rst), C = cols(*m_rst);
|
||||||
|
const long R_1 = R - 1, C_1 = C - 1;
|
||||||
|
|
||||||
|
Edge e = _edge(ringvertex);
|
||||||
|
e.to.dir = e.from.dir;
|
||||||
|
++e.to;
|
||||||
|
|
||||||
|
e.from.crd.r = std::min(e.from.crd.r, R_1);
|
||||||
|
e.from.crd.r = std::max(e.from.crd.r, 0l);
|
||||||
|
e.from.crd.c = std::min(e.from.crd.c, C_1);
|
||||||
|
e.from.crd.c = std::max(e.from.crd.c, 0l);
|
||||||
|
|
||||||
|
e.to.crd.r = std::min(e.to.crd.r, R);
|
||||||
|
e.to.crd.r = std::max(e.to.crd.r, 0l);
|
||||||
|
e.to.crd.c = std::min(e.to.crd.c, C);
|
||||||
|
e.to.crd.c = std::max(e.to.crd.c, 0l);
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Grid(const Rst &rst, const Coord &cellsz, const Coord &overlap)
|
||||||
|
: m_rst{&rst}
|
||||||
|
, m_cellsize{cellsz}
|
||||||
|
, m_res_1{m_cellsize.r - 1, m_cellsize.c - 1}
|
||||||
|
, m_window{overlap.r < cellsz.r ? cellsz.r - overlap.r : cellsz.r,
|
||||||
|
overlap.c < cellsz.c ? cellsz.c - overlap.c : cellsz.c}
|
||||||
|
, m_gridsize{2 + (long(rows(rst)) - overlap.r) / m_window.r,
|
||||||
|
2 + (long(cols(rst)) - overlap.c) / m_window.c}
|
||||||
|
, m_tags(m_gridsize.r * m_gridsize.c, 0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Go through the cells and mark them with the appropriate tag.
|
||||||
|
template<class ExecutionPolicy>
|
||||||
|
void tag_grid(ExecutionPolicy &&policy, TRasterValue<Rst> isoval)
|
||||||
|
{
|
||||||
|
// parallel for r
|
||||||
|
for_each (std::forward<ExecutionPolicy>(policy),
|
||||||
|
m_tags.begin(), m_tags.end(),
|
||||||
|
[this, isoval](uint8_t& tag, size_t idx) {
|
||||||
|
tag = get_tag_for_cell(coord(idx), isoval);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan for the rings on the tagged grid. Each ring vertex stores the
|
||||||
|
// sequential index of the cell and the next direction (Dir).
|
||||||
|
// This info can be used later to calculate the exact raster coordinate.
|
||||||
|
std::vector<Ring> scan_rings()
|
||||||
|
{
|
||||||
|
std::vector<Ring> rings;
|
||||||
|
size_t startidx = 0;
|
||||||
|
while ((startidx = search_start_cell(startidx)) < m_tags.size()) {
|
||||||
|
Ring ring;
|
||||||
|
|
||||||
|
size_t idx = startidx;
|
||||||
|
Dir prev = Dir::none, next = next_dir(prev, get_tag(idx));
|
||||||
|
|
||||||
|
while (next != Dir::none && !is_visited(idx, prev)) {
|
||||||
|
Coord ringvertex{long(idx), long(next)};
|
||||||
|
ring.emplace_back(ringvertex);
|
||||||
|
set_visited(idx, prev);
|
||||||
|
|
||||||
|
idx = seq(step(coord(idx), next));
|
||||||
|
prev = next;
|
||||||
|
next = next_dir(next, get_tag(idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
// To prevent infinite loops in case of degenerate input
|
||||||
|
if (next == Dir::none) m_tags[startidx] = _t(SquareTag::none);
|
||||||
|
|
||||||
|
if (ring.size() > 1) {
|
||||||
|
ring.pop_back();
|
||||||
|
rings.emplace_back(ring);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rings;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the exact raster position from the cells which store the
|
||||||
|
// sequantial index of the square and the next direction
|
||||||
|
template<class ExecutionPolicy>
|
||||||
|
void interpolate_rings(ExecutionPolicy && policy,
|
||||||
|
std::vector<Ring> &rings,
|
||||||
|
TRasterValue<Rst> isov)
|
||||||
|
{
|
||||||
|
for_each(std::forward<ExecutionPolicy>(policy),
|
||||||
|
rings.begin(), rings.end(), [this, isov] (Ring &ring, size_t)
|
||||||
|
{
|
||||||
|
for (Coord &ringvertex : ring) {
|
||||||
|
Edge e = edge(ringvertex);
|
||||||
|
|
||||||
|
CellIt found = std::lower_bound(e.from, e.to, isov);
|
||||||
|
ringvertex = found.crd;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Raster, class ExecutionPolicy>
|
||||||
|
std::vector<marchsq::Ring> execute_with_policy(ExecutionPolicy && policy,
|
||||||
|
const Raster & raster,
|
||||||
|
TRasterValue<Raster> isoval,
|
||||||
|
Coord windowsize = {})
|
||||||
|
{
|
||||||
|
if (!rows(raster) || !cols(raster)) return {};
|
||||||
|
|
||||||
|
size_t ratio = cols(raster) / rows(raster);
|
||||||
|
|
||||||
|
if (!windowsize.r) windowsize.r = 2;
|
||||||
|
if (!windowsize.c)
|
||||||
|
windowsize.c = std::max(2l, long(windowsize.r * ratio));
|
||||||
|
|
||||||
|
Coord overlap{1};
|
||||||
|
|
||||||
|
Grid<Raster> grid{raster, windowsize, overlap};
|
||||||
|
|
||||||
|
grid.tag_grid(std::forward<ExecutionPolicy>(policy), isoval);
|
||||||
|
std::vector<marchsq::Ring> rings = grid.scan_rings();
|
||||||
|
grid.interpolate_rings(std::forward<ExecutionPolicy>(policy), rings, isoval);
|
||||||
|
|
||||||
|
return rings;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Raster>
|
||||||
|
std::vector<marchsq::Ring> execute(const Raster &raster,
|
||||||
|
TRasterValue<Raster> isoval,
|
||||||
|
Coord windowsize = {})
|
||||||
|
{
|
||||||
|
return execute_with_policy(nullptr, raster, isoval, windowsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __impl
|
||||||
|
|
||||||
|
using __impl::execute_with_policy;
|
||||||
|
using __impl::execute;
|
||||||
|
|
||||||
|
} // namespace marchsq
|
||||||
|
|
||||||
|
#endif // MARCHINGSQUARES_HPP
|
|
@ -1,4 +1,5 @@
|
||||||
#include "Model.hpp"
|
#include "Model.hpp"
|
||||||
|
#include "ModelArrange.hpp"
|
||||||
#include "Geometry.hpp"
|
#include "Geometry.hpp"
|
||||||
#include "MTUtils.hpp"
|
#include "MTUtils.hpp"
|
||||||
|
|
||||||
|
@ -355,116 +356,6 @@ TriangleMesh Model::mesh() const
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _arrange(const Pointfs &sizes, coordf_t dist, const BoundingBoxf* bb, Pointfs &out)
|
|
||||||
{
|
|
||||||
if (sizes.empty())
|
|
||||||
// return if the list is empty or the following call to BoundingBoxf constructor will lead to a crash
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// we supply unscaled data to arrange()
|
|
||||||
bool result = Slic3r::Geometry::arrange(
|
|
||||||
sizes.size(), // number of parts
|
|
||||||
BoundingBoxf(sizes).max, // width and height of a single cell
|
|
||||||
dist, // distance between cells
|
|
||||||
bb, // bounding box of the area to fill
|
|
||||||
out // output positions
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!result && bb != nullptr) {
|
|
||||||
// Try to arrange again ignoring bb
|
|
||||||
result = Slic3r::Geometry::arrange(
|
|
||||||
sizes.size(), // number of parts
|
|
||||||
BoundingBoxf(sizes).max, // width and height of a single cell
|
|
||||||
dist, // distance between cells
|
|
||||||
nullptr, // bounding box of the area to fill
|
|
||||||
out // output positions
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* arrange objects preserving their instance count
|
|
||||||
but altering their instance positions */
|
|
||||||
bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb)
|
|
||||||
{
|
|
||||||
size_t count = 0;
|
|
||||||
for (auto obj : objects) count += obj->instances.size();
|
|
||||||
|
|
||||||
arrangement::ArrangePolygons input;
|
|
||||||
ModelInstancePtrs instances;
|
|
||||||
input.reserve(count);
|
|
||||||
instances.reserve(count);
|
|
||||||
for (ModelObject *mo : objects)
|
|
||||||
for (ModelInstance *minst : mo->instances) {
|
|
||||||
input.emplace_back(minst->get_arrange_polygon());
|
|
||||||
instances.emplace_back(minst);
|
|
||||||
}
|
|
||||||
|
|
||||||
arrangement::BedShapeHint bedhint;
|
|
||||||
coord_t bedwidth = 0;
|
|
||||||
|
|
||||||
if (bb) {
|
|
||||||
bedwidth = scaled(bb->size().x());
|
|
||||||
bedhint = arrangement::BedShapeHint(
|
|
||||||
BoundingBox(scaled(bb->min), scaled(bb->max)));
|
|
||||||
}
|
|
||||||
|
|
||||||
arrangement::arrange(input, scaled(dist), bedhint);
|
|
||||||
|
|
||||||
bool ret = true;
|
|
||||||
coord_t stride = bedwidth + bedwidth / 5;
|
|
||||||
|
|
||||||
for(size_t i = 0; i < input.size(); ++i) {
|
|
||||||
if (input[i].bed_idx != 0) ret = false;
|
|
||||||
if (input[i].bed_idx >= 0) {
|
|
||||||
input[i].translation += Vec2crd{input[i].bed_idx * stride, 0};
|
|
||||||
instances[i]->apply_arrange_result(input[i].translation.cast<double>(),
|
|
||||||
input[i].rotation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Duplicate the entire model preserving instance relative positions.
|
|
||||||
void Model::duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb)
|
|
||||||
{
|
|
||||||
Pointfs model_sizes(copies_num-1, to_2d(this->bounding_box().size()));
|
|
||||||
Pointfs positions;
|
|
||||||
if (! _arrange(model_sizes, dist, bb, positions))
|
|
||||||
throw std::invalid_argument("Cannot duplicate part as the resulting objects would not fit on the print bed.\n");
|
|
||||||
|
|
||||||
// note that this will leave the object count unaltered
|
|
||||||
|
|
||||||
for (ModelObject *o : this->objects) {
|
|
||||||
// make a copy of the pointers in order to avoid recursion when appending their copies
|
|
||||||
ModelInstancePtrs instances = o->instances;
|
|
||||||
for (const ModelInstance *i : instances) {
|
|
||||||
for (const Vec2d &pos : positions) {
|
|
||||||
ModelInstance *instance = o->add_instance(*i);
|
|
||||||
instance->set_offset(instance->get_offset() + Vec3d(pos(0), pos(1), 0.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
o->invalidate_bounding_box();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this will append more instances to each object
|
|
||||||
and then automatically rearrange everything */
|
|
||||||
void Model::duplicate_objects(size_t copies_num, coordf_t dist, const BoundingBoxf* bb)
|
|
||||||
{
|
|
||||||
for (ModelObject *o : this->objects) {
|
|
||||||
// make a copy of the pointers in order to avoid recursion when appending their copies
|
|
||||||
ModelInstancePtrs instances = o->instances;
|
|
||||||
for (const ModelInstance *i : instances)
|
|
||||||
for (size_t k = 2; k <= copies_num; ++ k)
|
|
||||||
o->add_instance(*i);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->arrange_objects(dist, bb);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Model::duplicate_objects_grid(size_t x, size_t y, coordf_t dist)
|
void Model::duplicate_objects_grid(size_t x, size_t y, coordf_t dist)
|
||||||
{
|
{
|
||||||
if (this->objects.size() > 1) throw "Grid duplication is not supported with multiple objects";
|
if (this->objects.size() > 1) throw "Grid duplication is not supported with multiple objects";
|
||||||
|
@ -1149,6 +1040,8 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
||||||
for (ModelVolume *volume : volumes) {
|
for (ModelVolume *volume : volumes) {
|
||||||
const auto volume_matrix = volume->get_matrix();
|
const auto volume_matrix = volume->get_matrix();
|
||||||
|
|
||||||
|
volume->m_supported_facets.clear();
|
||||||
|
|
||||||
if (! volume->is_model_part()) {
|
if (! volume->is_model_part()) {
|
||||||
// Modifiers are not cut, but we still need to add the instance transformation
|
// Modifiers are not cut, but we still need to add the instance transformation
|
||||||
// to the modifier volume transformation to preserve their shape properly.
|
// to the modifier volume transformation to preserve their shape properly.
|
||||||
|
@ -1848,6 +1741,41 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<int> FacetsAnnotation::get_facets(FacetSupportType type) const
|
||||||
|
{
|
||||||
|
std::vector<int> out;
|
||||||
|
for (auto& [facet_idx, this_type] : m_data)
|
||||||
|
if (this_type == type)
|
||||||
|
out.push_back(facet_idx);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void FacetsAnnotation::set_facet(int idx, FacetSupportType type)
|
||||||
|
{
|
||||||
|
bool changed = true;
|
||||||
|
|
||||||
|
if (type == FacetSupportType::NONE)
|
||||||
|
changed = m_data.erase(idx) != 0;
|
||||||
|
else
|
||||||
|
m_data[idx] = type;
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
update_timestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void FacetsAnnotation::clear()
|
||||||
|
{
|
||||||
|
m_data.clear();
|
||||||
|
update_timestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Test whether the two models contain the same number of ModelObjects with the same set of IDs
|
// Test whether the two models contain the same number of ModelObjects with the same set of IDs
|
||||||
// ordered in the same order. In that case it is not necessary to kill the background processing.
|
// ordered in the same order. In that case it is not necessary to kill the background processing.
|
||||||
bool model_object_list_equal(const Model &model_old, const Model &model_new)
|
bool model_object_list_equal(const Model &model_old, const Model &model_new)
|
||||||
|
@ -1911,6 +1839,16 @@ bool model_volume_list_changed(const ModelObject &model_object_old, const ModelO
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool model_custom_supports_data_changed(const ModelObject& mo, const ModelObject& mo_new) {
|
||||||
|
assert(! model_volume_list_changed(mo, mo_new, ModelVolumeType::MODEL_PART));
|
||||||
|
assert(mo.volumes.size() == mo_new.volumes.size());
|
||||||
|
for (size_t i=0; i<mo.volumes.size(); ++i) {
|
||||||
|
if (! mo_new.volumes[i]->m_supported_facets.is_same_as(mo.volumes[i]->m_supported_facets))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
extern bool model_has_multi_part_objects(const Model &model)
|
extern bool model_has_multi_part_objects(const Model &model)
|
||||||
{
|
{
|
||||||
for (const ModelObject *model_object : model.objects)
|
for (const ModelObject *model_object : model.objects)
|
||||||
|
@ -1991,6 +1929,7 @@ void check_model_ids_equal(const Model &model1, const Model &model2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* NDEBUG */
|
#endif /* NDEBUG */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
namespace cereal {
|
namespace cereal {
|
||||||
class BinaryInputArchive;
|
class BinaryInputArchive;
|
||||||
|
@ -214,8 +215,8 @@ public:
|
||||||
when user expects that. */
|
when user expects that. */
|
||||||
Vec3d origin_translation;
|
Vec3d origin_translation;
|
||||||
|
|
||||||
Model* get_model() { return m_model; };
|
Model* get_model() { return m_model; }
|
||||||
const Model* get_model() const { return m_model; };
|
const Model* get_model() const { return m_model; }
|
||||||
|
|
||||||
ModelVolume* add_volume(const TriangleMesh &mesh);
|
ModelVolume* add_volume(const TriangleMesh &mesh);
|
||||||
ModelVolume* add_volume(TriangleMesh &&mesh);
|
ModelVolume* add_volume(TriangleMesh &&mesh);
|
||||||
|
@ -391,6 +392,34 @@ enum class ModelVolumeType : int {
|
||||||
SUPPORT_BLOCKER,
|
SUPPORT_BLOCKER,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class FacetSupportType : int8_t {
|
||||||
|
NONE = 0,
|
||||||
|
ENFORCER = 1,
|
||||||
|
BLOCKER = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
class FacetsAnnotation {
|
||||||
|
public:
|
||||||
|
using ClockType = std::chrono::steady_clock;
|
||||||
|
|
||||||
|
std::vector<int> get_facets(FacetSupportType type) const;
|
||||||
|
void set_facet(int idx, FacetSupportType type);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
ClockType::time_point get_timestamp() const { return timestamp; }
|
||||||
|
bool is_same_as(const FacetsAnnotation& other) const {
|
||||||
|
return timestamp == other.get_timestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<int, FacetSupportType> m_data;
|
||||||
|
|
||||||
|
ClockType::time_point timestamp;
|
||||||
|
void update_timestamp() {
|
||||||
|
timestamp = ClockType::now();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// An object STL, or a modifier volume, over which a different set of parameters shall be applied.
|
// An object STL, or a modifier volume, over which a different set of parameters shall be applied.
|
||||||
// ModelVolume instances are owned by a ModelObject.
|
// ModelVolume instances are owned by a ModelObject.
|
||||||
class ModelVolume final : public ObjectBase
|
class ModelVolume final : public ObjectBase
|
||||||
|
@ -421,8 +450,11 @@ public:
|
||||||
// overriding the global Slic3r settings and the ModelObject settings.
|
// overriding the global Slic3r settings and the ModelObject settings.
|
||||||
ModelConfig config;
|
ModelConfig config;
|
||||||
|
|
||||||
|
// List of mesh facets to be supported/unsupported.
|
||||||
|
FacetsAnnotation m_supported_facets;
|
||||||
|
|
||||||
// A parent object owning this modifier volume.
|
// A parent object owning this modifier volume.
|
||||||
ModelObject* get_object() const { return this->object; };
|
ModelObject* get_object() const { return this->object; }
|
||||||
ModelVolumeType type() const { return m_type; }
|
ModelVolumeType type() const { return m_type; }
|
||||||
void set_type(const ModelVolumeType t) { m_type = t; }
|
void set_type(const ModelVolumeType t) { m_type = t; }
|
||||||
bool is_model_part() const { return m_type == ModelVolumeType::MODEL_PART; }
|
bool is_model_part() const { return m_type == ModelVolumeType::MODEL_PART; }
|
||||||
|
@ -548,7 +580,9 @@ private:
|
||||||
// Copying an existing volume, therefore this volume will get a copy of the ID assigned.
|
// Copying an existing volume, therefore this volume will get a copy of the ID assigned.
|
||||||
ModelVolume(ModelObject *object, const ModelVolume &other) :
|
ModelVolume(ModelObject *object, const ModelVolume &other) :
|
||||||
ObjectBase(other),
|
ObjectBase(other),
|
||||||
name(other.name), source(other.source), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation)
|
name(other.name), source(other.source), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull),
|
||||||
|
config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation),
|
||||||
|
m_supported_facets(other.m_supported_facets)
|
||||||
{
|
{
|
||||||
assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id());
|
assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id());
|
||||||
assert(this->id() == other.id() && this->config.id() == other.config.id());
|
assert(this->id() == other.id() && this->config.id() == other.config.id());
|
||||||
|
@ -565,6 +599,8 @@ private:
|
||||||
if (mesh.stl.stats.number_of_facets > 1)
|
if (mesh.stl.stats.number_of_facets > 1)
|
||||||
calculate_convex_hull();
|
calculate_convex_hull();
|
||||||
assert(this->config.id().valid()); assert(this->config.id() != other.config.id()); assert(this->id() != this->config.id());
|
assert(this->config.id().valid()); assert(this->config.id() != other.config.id()); assert(this->id() != this->config.id());
|
||||||
|
|
||||||
|
m_supported_facets.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelVolume& operator=(ModelVolume &rhs) = delete;
|
ModelVolume& operator=(ModelVolume &rhs) = delete;
|
||||||
|
@ -802,10 +838,8 @@ public:
|
||||||
bool center_instances_around_point(const Vec2d &point);
|
bool center_instances_around_point(const Vec2d &point);
|
||||||
void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); }
|
void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); }
|
||||||
TriangleMesh mesh() const;
|
TriangleMesh mesh() const;
|
||||||
bool arrange_objects(coordf_t dist, const BoundingBoxf* bb = NULL);
|
|
||||||
// Croaks if the duplicated objects do not fit the print bed.
|
// Croaks if the duplicated objects do not fit the print bed.
|
||||||
void duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb = NULL);
|
|
||||||
void duplicate_objects(size_t copies_num, coordf_t dist, const BoundingBoxf* bb = NULL);
|
|
||||||
void duplicate_objects_grid(size_t x, size_t y, coordf_t dist);
|
void duplicate_objects_grid(size_t x, size_t y, coordf_t dist);
|
||||||
|
|
||||||
bool looks_like_multipart_object() const;
|
bool looks_like_multipart_object() const;
|
||||||
|
@ -822,7 +856,7 @@ public:
|
||||||
std::string propose_export_file_name_and_path(const std::string &new_extension) const;
|
std::string propose_export_file_name_and_path(const std::string &new_extension) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Model(int) : ObjectBase(-1) { assert(this->id().invalid()); };
|
explicit Model(int) : ObjectBase(-1) { assert(this->id().invalid()); }
|
||||||
void assign_new_unique_ids_recursive();
|
void assign_new_unique_ids_recursive();
|
||||||
void update_links_bottom_up_recursive();
|
void update_links_bottom_up_recursive();
|
||||||
|
|
||||||
|
@ -849,6 +883,10 @@ extern bool model_object_list_extended(const Model &model_old, const Model &mode
|
||||||
// than the old ModelObject.
|
// than the old ModelObject.
|
||||||
extern bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolumeType type);
|
extern bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolumeType type);
|
||||||
|
|
||||||
|
// Test whether the now ModelObject has newer custom supports data than the old one.
|
||||||
|
// The function assumes that volumes list is synchronized.
|
||||||
|
extern bool model_custom_supports_data_changed(const ModelObject& mo, const ModelObject& mo_new);
|
||||||
|
|
||||||
// If the model has multi-part objects, then it is currently not supported by the SLA mode.
|
// If the model has multi-part objects, then it is currently not supported by the SLA mode.
|
||||||
// Either the model cannot be loaded, or a SLA printer has to be activated.
|
// Either the model cannot be loaded, or a SLA printer has to be activated.
|
||||||
extern bool model_has_multi_part_objects(const Model &model);
|
extern bool model_has_multi_part_objects(const Model &model);
|
||||||
|
|
83
src/libslic3r/ModelArrange.cpp
Normal file
83
src/libslic3r/ModelArrange.cpp
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
#include "ModelArrange.hpp"
|
||||||
|
#include "MTUtils.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
arrangement::ArrangePolygons get_arrange_polys(const Model &model, ModelInstancePtrs &instances)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
for (auto obj : model.objects) count += obj->instances.size();
|
||||||
|
|
||||||
|
ArrangePolygons input;
|
||||||
|
input.reserve(count);
|
||||||
|
instances.clear(); instances.reserve(count);
|
||||||
|
for (ModelObject *mo : model.objects)
|
||||||
|
for (ModelInstance *minst : mo->instances) {
|
||||||
|
input.emplace_back(minst->get_arrange_polygon());
|
||||||
|
instances.emplace_back(minst);
|
||||||
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool apply_arrange_polys(ArrangePolygons &input, ModelInstancePtrs &instances, VirtualBedFn vfn)
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < input.size(); ++i) {
|
||||||
|
if (input[i].bed_idx != 0) { ret = false; if (vfn) vfn(input[i]); }
|
||||||
|
if (input[i].bed_idx >= 0)
|
||||||
|
instances[i]->apply_arrange_result(input[i].translation.cast<double>(),
|
||||||
|
input[i].rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Slic3r::arrangement::ArrangePolygon get_arrange_poly(const Model &model)
|
||||||
|
{
|
||||||
|
ArrangePolygon ap;
|
||||||
|
Points &apts = ap.poly.contour.points;
|
||||||
|
for (const ModelObject *mo : model.objects)
|
||||||
|
for (const ModelInstance *minst : mo->instances) {
|
||||||
|
ArrangePolygon obj_ap = minst->get_arrange_polygon();
|
||||||
|
ap.poly.contour.rotate(obj_ap.rotation);
|
||||||
|
ap.poly.contour.translate(obj_ap.translation.x(), obj_ap.translation.y());
|
||||||
|
const Points &pts = obj_ap.poly.contour.points;
|
||||||
|
std::copy(pts.begin(), pts.end(), std::back_inserter(apts));
|
||||||
|
}
|
||||||
|
|
||||||
|
apts = Geometry::convex_hull(apts);
|
||||||
|
return ap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void duplicate(Model &model, Slic3r::arrangement::ArrangePolygons &copies, VirtualBedFn vfn)
|
||||||
|
{
|
||||||
|
for (ModelObject *o : model.objects) {
|
||||||
|
// make a copy of the pointers in order to avoid recursion when appending their copies
|
||||||
|
ModelInstancePtrs instances = o->instances;
|
||||||
|
o->instances.clear();
|
||||||
|
for (const ModelInstance *i : instances) {
|
||||||
|
for (arrangement::ArrangePolygon &ap : copies) {
|
||||||
|
if (ap.bed_idx != 0) vfn(ap);
|
||||||
|
ModelInstance *instance = o->add_instance(*i);
|
||||||
|
Vec2d pos = unscale(ap.translation);
|
||||||
|
instance->set_offset(instance->get_offset() + to_3d(pos, 0.));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o->invalidate_bounding_box();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void duplicate_objects(Model &model, size_t copies_num)
|
||||||
|
{
|
||||||
|
for (ModelObject *o : model.objects) {
|
||||||
|
// make a copy of the pointers in order to avoid recursion when appending their copies
|
||||||
|
ModelInstancePtrs instances = o->instances;
|
||||||
|
for (const ModelInstance *i : instances)
|
||||||
|
for (size_t k = 2; k <= copies_num; ++ k)
|
||||||
|
o->add_instance(*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
68
src/libslic3r/ModelArrange.hpp
Normal file
68
src/libslic3r/ModelArrange.hpp
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#ifndef MODELARRANGE_HPP
|
||||||
|
#define MODELARRANGE_HPP
|
||||||
|
|
||||||
|
#include <libslic3r/Model.hpp>
|
||||||
|
#include <libslic3r/Arrange.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
using arrangement::ArrangePolygon;
|
||||||
|
using arrangement::ArrangePolygons;
|
||||||
|
using arrangement::ArrangeParams;
|
||||||
|
using arrangement::InfiniteBed;
|
||||||
|
using arrangement::CircleBed;
|
||||||
|
|
||||||
|
// Do something with ArrangePolygons in virtual beds
|
||||||
|
using VirtualBedFn = std::function<void(arrangement::ArrangePolygon&)>;
|
||||||
|
|
||||||
|
[[noreturn]] inline void throw_if_out_of_bed(arrangement::ArrangePolygon&)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Objects could not fit on the bed");
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrangePolygons get_arrange_polys(const Model &model, ModelInstancePtrs &instances);
|
||||||
|
ArrangePolygon get_arrange_poly(const Model &model);
|
||||||
|
bool apply_arrange_polys(ArrangePolygons &polys, ModelInstancePtrs &instances, VirtualBedFn);
|
||||||
|
|
||||||
|
void duplicate(Model &model, ArrangePolygons &copies, VirtualBedFn);
|
||||||
|
void duplicate_objects(Model &model, size_t copies_num);
|
||||||
|
|
||||||
|
template<class TBed>
|
||||||
|
bool arrange_objects(Model & model,
|
||||||
|
const TBed & bed,
|
||||||
|
const ArrangeParams ¶ms,
|
||||||
|
VirtualBedFn vfn = throw_if_out_of_bed)
|
||||||
|
{
|
||||||
|
ModelInstancePtrs instances;
|
||||||
|
auto&& input = get_arrange_polys(model, instances);
|
||||||
|
arrangement::arrange(input, bed, params);
|
||||||
|
|
||||||
|
return apply_arrange_polys(input, instances, vfn);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class TBed>
|
||||||
|
void duplicate(Model & model,
|
||||||
|
size_t copies_num,
|
||||||
|
const TBed & bed,
|
||||||
|
const ArrangeParams ¶ms,
|
||||||
|
VirtualBedFn vfn = throw_if_out_of_bed)
|
||||||
|
{
|
||||||
|
ArrangePolygons copies(copies_num, get_arrange_poly(model));
|
||||||
|
arrangement::arrange(copies, bed, params);
|
||||||
|
duplicate(model, copies, vfn);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class TBed>
|
||||||
|
void duplicate_objects(Model & model,
|
||||||
|
size_t copies_num,
|
||||||
|
const TBed & bed,
|
||||||
|
const ArrangeParams ¶ms,
|
||||||
|
VirtualBedFn vfn = throw_if_out_of_bed)
|
||||||
|
{
|
||||||
|
duplicate_objects(model, copies_num);
|
||||||
|
arrange_objects(model, bed, params, vfn);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MODELARRANGE_HPP
|
|
@ -114,6 +114,7 @@ public:
|
||||||
Point& operator+=(const Point& rhs) { (*this)(0) += rhs(0); (*this)(1) += rhs(1); return *this; }
|
Point& operator+=(const Point& rhs) { (*this)(0) += rhs(0); (*this)(1) += rhs(1); return *this; }
|
||||||
Point& operator-=(const Point& rhs) { (*this)(0) -= rhs(0); (*this)(1) -= rhs(1); return *this; }
|
Point& operator-=(const Point& rhs) { (*this)(0) -= rhs(0); (*this)(1) -= rhs(1); return *this; }
|
||||||
Point& operator*=(const double &rhs) { (*this)(0) = coord_t((*this)(0) * rhs); (*this)(1) = coord_t((*this)(1) * rhs); return *this; }
|
Point& operator*=(const double &rhs) { (*this)(0) = coord_t((*this)(0) * rhs); (*this)(1) = coord_t((*this)(1) * rhs); return *this; }
|
||||||
|
Point operator*(const double &rhs) { return Point((*this)(0) * rhs, (*this)(1) * rhs); }
|
||||||
|
|
||||||
void rotate(double angle);
|
void rotate(double angle);
|
||||||
void rotate(double angle, const Point ¢er);
|
void rotate(double angle, const Point ¢er);
|
||||||
|
@ -288,6 +289,72 @@ private:
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream &stm, const Vec2d &pointf);
|
std::ostream& operator<<(std::ostream &stm, const Vec2d &pointf);
|
||||||
|
|
||||||
|
|
||||||
|
// /////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Type safe conversions to and from scaled and unscaled coordinates
|
||||||
|
// /////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Semantics are the following:
|
||||||
|
// Upscaling (scaled()): only from floating point types (or Vec) to either
|
||||||
|
// floating point or integer 'scaled coord' coordinates.
|
||||||
|
// Downscaling (unscaled()): from arithmetic (or Vec) to floating point only
|
||||||
|
|
||||||
|
// Conversion definition from unscaled to floating point scaled
|
||||||
|
template<class Tout,
|
||||||
|
class Tin,
|
||||||
|
class = FloatingOnly<Tin>>
|
||||||
|
inline constexpr FloatingOnly<Tout> scaled(const Tin &v) noexcept
|
||||||
|
{
|
||||||
|
return Tout(v / Tin(SCALING_FACTOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversion definition from unscaled to integer 'scaled coord'.
|
||||||
|
// TODO: is the rounding necessary? Here it is commented out to show that
|
||||||
|
// it can be different for integers but it does not have to be. Using
|
||||||
|
// std::round means loosing noexcept and constexpr modifiers
|
||||||
|
template<class Tout = coord_t, class Tin, class = FloatingOnly<Tin>>
|
||||||
|
inline constexpr ScaledCoordOnly<Tout> scaled(const Tin &v) noexcept
|
||||||
|
{
|
||||||
|
//return static_cast<Tout>(std::round(v / SCALING_FACTOR));
|
||||||
|
return Tout(v / Tin(SCALING_FACTOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversion for Eigen vectors (N dimensional points)
|
||||||
|
template<class Tout = coord_t,
|
||||||
|
class Tin,
|
||||||
|
int N,
|
||||||
|
class = FloatingOnly<Tin>,
|
||||||
|
int...EigenArgs>
|
||||||
|
inline Eigen::Matrix<ArithmeticOnly<Tout>, N, EigenArgs...>
|
||||||
|
scaled(const Eigen::Matrix<Tin, N, EigenArgs...> &v)
|
||||||
|
{
|
||||||
|
return (v / SCALING_FACTOR).template cast<Tout>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversion from arithmetic scaled type to floating point unscaled
|
||||||
|
template<class Tout = double,
|
||||||
|
class Tin,
|
||||||
|
class = ArithmeticOnly<Tin>,
|
||||||
|
class = FloatingOnly<Tout>>
|
||||||
|
inline constexpr Tout unscaled(const Tin &v) noexcept
|
||||||
|
{
|
||||||
|
return Tout(v * Tout(SCALING_FACTOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unscaling for Eigen vectors. Input base type can be arithmetic, output base
|
||||||
|
// type can only be floating point.
|
||||||
|
template<class Tout = double,
|
||||||
|
class Tin,
|
||||||
|
int N,
|
||||||
|
class = ArithmeticOnly<Tin>,
|
||||||
|
class = FloatingOnly<Tout>,
|
||||||
|
int...EigenArgs>
|
||||||
|
inline constexpr Eigen::Matrix<Tout, N, EigenArgs...>
|
||||||
|
unscaled(const Eigen::Matrix<Tin, N, EigenArgs...> &v) noexcept
|
||||||
|
{
|
||||||
|
return v.template cast<Tout>() * SCALING_FACTOR;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
// start Boost
|
// start Boost
|
||||||
|
|
|
@ -48,7 +48,7 @@ int64_t Polygon::area2x() const
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
double Polygon::area() const
|
double Polygon::area(const Points &points)
|
||||||
{
|
{
|
||||||
size_t n = points.size();
|
size_t n = points.size();
|
||||||
if (n < 3)
|
if (n < 3)
|
||||||
|
@ -62,6 +62,11 @@ double Polygon::area() const
|
||||||
return 0.5 * a;
|
return 0.5 * a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double Polygon::area() const
|
||||||
|
{
|
||||||
|
return Polygon::area(points);
|
||||||
|
}
|
||||||
|
|
||||||
bool Polygon::is_counter_clockwise() const
|
bool Polygon::is_counter_clockwise() const
|
||||||
{
|
{
|
||||||
return ClipperLib::Orientation(Slic3rMultiPoint_to_ClipperPath(*this));
|
return ClipperLib::Orientation(Slic3rMultiPoint_to_ClipperPath(*this));
|
||||||
|
|
|
@ -22,6 +22,7 @@ public:
|
||||||
const Point& operator[](Points::size_type idx) const { return this->points[idx]; }
|
const Point& operator[](Points::size_type idx) const { return this->points[idx]; }
|
||||||
|
|
||||||
Polygon() {}
|
Polygon() {}
|
||||||
|
virtual ~Polygon() = default;
|
||||||
explicit Polygon(const Points &points) : MultiPoint(points) {}
|
explicit Polygon(const Points &points) : MultiPoint(points) {}
|
||||||
Polygon(std::initializer_list<Point> points) : MultiPoint(points) {}
|
Polygon(std::initializer_list<Point> points) : MultiPoint(points) {}
|
||||||
Polygon(const Polygon &other) : MultiPoint(other.points) {}
|
Polygon(const Polygon &other) : MultiPoint(other.points) {}
|
||||||
|
@ -47,6 +48,7 @@ public:
|
||||||
Polyline split_at_first_point() const { return this->split_at_index(0); }
|
Polyline split_at_first_point() const { return this->split_at_index(0); }
|
||||||
Points equally_spaced_points(double distance) const { return this->split_at_first_point().equally_spaced_points(distance); }
|
Points equally_spaced_points(double distance) const { return this->split_at_first_point().equally_spaced_points(distance); }
|
||||||
|
|
||||||
|
static double area(const Points &pts);
|
||||||
double area() const;
|
double area() const;
|
||||||
bool is_counter_clockwise() const;
|
bool is_counter_clockwise() const;
|
||||||
bool is_clockwise() const;
|
bool is_clockwise() const;
|
||||||
|
|
|
@ -404,6 +404,7 @@ static inline void model_volume_list_copy_configs(ModelObject &model_object_dst,
|
||||||
// Copy the ModelVolume data.
|
// Copy the ModelVolume data.
|
||||||
mv_dst.name = mv_src.name;
|
mv_dst.name = mv_src.name;
|
||||||
static_cast<DynamicPrintConfig&>(mv_dst.config) = static_cast<const DynamicPrintConfig&>(mv_src.config);
|
static_cast<DynamicPrintConfig&>(mv_dst.config) = static_cast<const DynamicPrintConfig&>(mv_src.config);
|
||||||
|
mv_dst.m_supported_facets = mv_src.m_supported_facets;
|
||||||
//FIXME what to do with the materials?
|
//FIXME what to do with the materials?
|
||||||
// mv_dst.m_material_id = mv_src.m_material_id;
|
// mv_dst.m_material_id = mv_src.m_material_id;
|
||||||
++ i_src;
|
++ i_src;
|
||||||
|
@ -854,7 +855,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||||
}
|
}
|
||||||
// Copy content of the ModelObject including its ID, do not change the parent.
|
// Copy content of the ModelObject including its ID, do not change the parent.
|
||||||
model_object.assign_copy(model_object_new);
|
model_object.assign_copy(model_object_new);
|
||||||
} else if (support_blockers_differ || support_enforcers_differ) {
|
} else if (support_blockers_differ || support_enforcers_differ || model_custom_supports_data_changed(model_object, model_object_new)) {
|
||||||
// First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list.
|
// First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list.
|
||||||
this->call_cancel_callback();
|
this->call_cancel_callback();
|
||||||
update_apply_status(false);
|
update_apply_status(false);
|
||||||
|
@ -862,9 +863,11 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||||
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
||||||
for (auto it = range.first; it != range.second; ++ it)
|
for (auto it = range.first; it != range.second; ++ it)
|
||||||
update_apply_status(it->print_object->invalidate_step(posSupportMaterial));
|
update_apply_status(it->print_object->invalidate_step(posSupportMaterial));
|
||||||
|
if (support_enforcers_differ || support_blockers_differ) {
|
||||||
// Copy just the support volumes.
|
// Copy just the support volumes.
|
||||||
model_volume_list_update_supports(model_object, model_object_new);
|
model_volume_list_update_supports(model_object, model_object_new);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (! model_parts_differ && ! modifiers_differ) {
|
if (! model_parts_differ && ! modifiers_differ) {
|
||||||
// Synchronize Object's config.
|
// Synchronize Object's config.
|
||||||
bool object_config_changed = model_object.config != model_object_new.config;
|
bool object_config_changed = model_object.config != model_object_new.config;
|
||||||
|
@ -881,7 +884,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Synchronize (just copy) the remaining data of ModelVolumes (name, config).
|
// Synchronize (just copy) the remaining data of ModelVolumes (name, config, custom supports data).
|
||||||
//FIXME What to do with m_material_id?
|
//FIXME What to do with m_material_id?
|
||||||
model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::MODEL_PART);
|
model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::MODEL_PART);
|
||||||
model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::PARAMETER_MODIFIER);
|
model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::PARAMETER_MODIFIER);
|
||||||
|
@ -1583,6 +1586,8 @@ void Print::process()
|
||||||
this->set_status(70, L("Infilling layers"));
|
this->set_status(70, L("Infilling layers"));
|
||||||
for (PrintObject *obj : m_objects)
|
for (PrintObject *obj : m_objects)
|
||||||
obj->infill();
|
obj->infill();
|
||||||
|
for (PrintObject *obj : m_objects)
|
||||||
|
obj->ironing();
|
||||||
for (PrintObject *obj : m_objects)
|
for (PrintObject *obj : m_objects)
|
||||||
obj->generate_support_material();
|
obj->generate_support_material();
|
||||||
if (this->set_started(psWipeTower)) {
|
if (this->set_started(psWipeTower)) {
|
||||||
|
|
|
@ -41,7 +41,7 @@ enum PrintStep {
|
||||||
|
|
||||||
enum PrintObjectStep {
|
enum PrintObjectStep {
|
||||||
posSlice, posPerimeters, posPrepareInfill,
|
posSlice, posPerimeters, posPrepareInfill,
|
||||||
posInfill, posSupportMaterial, posCount,
|
posInfill, posIroning, posSupportMaterial, posCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
// A PrintRegion object represents a group of volumes to print
|
// A PrintRegion object represents a group of volumes to print
|
||||||
|
@ -192,6 +192,11 @@ public:
|
||||||
std::vector<ExPolygons> slice_support_blockers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_BLOCKER); }
|
std::vector<ExPolygons> slice_support_blockers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_BLOCKER); }
|
||||||
std::vector<ExPolygons> slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); }
|
std::vector<ExPolygons> slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); }
|
||||||
|
|
||||||
|
// Helpers to project custom supports on slices
|
||||||
|
void project_and_append_custom_supports(FacetSupportType type, std::vector<ExPolygons>& expolys) const;
|
||||||
|
void project_and_append_custom_enforcers(std::vector<ExPolygons>& enforcers) const { project_and_append_custom_supports(FacetSupportType::ENFORCER, enforcers); }
|
||||||
|
void project_and_append_custom_blockers(std::vector<ExPolygons>& blockers) const { project_and_append_custom_supports(FacetSupportType::BLOCKER, blockers); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// to be called from Print only.
|
// to be called from Print only.
|
||||||
friend class Print;
|
friend class Print;
|
||||||
|
@ -218,6 +223,7 @@ private:
|
||||||
void make_perimeters();
|
void make_perimeters();
|
||||||
void prepare_infill();
|
void prepare_infill();
|
||||||
void infill();
|
void infill();
|
||||||
|
void ironing();
|
||||||
void generate_support_material();
|
void generate_support_material();
|
||||||
|
|
||||||
void _slice(const std::vector<coordf_t> &layer_height_profile);
|
void _slice(const std::vector<coordf_t> &layer_height_profile);
|
||||||
|
|
|
@ -39,6 +39,11 @@ void PrintConfigDef::init_common_params()
|
||||||
{
|
{
|
||||||
ConfigOptionDef* def;
|
ConfigOptionDef* def;
|
||||||
|
|
||||||
|
def = this->add("single_instance", coBool);
|
||||||
|
def->label = L("Single Instance");
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionBool(false));
|
||||||
|
|
||||||
def = this->add("printer_technology", coEnum);
|
def = this->add("printer_technology", coEnum);
|
||||||
def->label = L("Printer technology");
|
def->label = L("Printer technology");
|
||||||
def->tooltip = L("Printer technology");
|
def->tooltip = L("Printer technology");
|
||||||
|
@ -419,18 +424,20 @@ void PrintConfigDef::init_fff_params()
|
||||||
def->cli = "top-fill-pattern|external-fill-pattern|solid-fill-pattern";
|
def->cli = "top-fill-pattern|external-fill-pattern|solid-fill-pattern";
|
||||||
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
|
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
|
||||||
def->enum_values.push_back("rectilinear");
|
def->enum_values.push_back("rectilinear");
|
||||||
|
def->enum_values.push_back("monotonous");
|
||||||
def->enum_values.push_back("concentric");
|
def->enum_values.push_back("concentric");
|
||||||
def->enum_values.push_back("hilbertcurve");
|
def->enum_values.push_back("hilbertcurve");
|
||||||
def->enum_values.push_back("archimedeanchords");
|
def->enum_values.push_back("archimedeanchords");
|
||||||
def->enum_values.push_back("octagramspiral");
|
def->enum_values.push_back("octagramspiral");
|
||||||
def->enum_labels.push_back(L("Rectilinear"));
|
def->enum_labels.push_back(L("Rectilinear"));
|
||||||
|
def->enum_labels.push_back(L("Monotonous"));
|
||||||
def->enum_labels.push_back(L("Concentric"));
|
def->enum_labels.push_back(L("Concentric"));
|
||||||
def->enum_labels.push_back(L("Hilbert Curve"));
|
def->enum_labels.push_back(L("Hilbert Curve"));
|
||||||
def->enum_labels.push_back(L("Archimedean Chords"));
|
def->enum_labels.push_back(L("Archimedean Chords"));
|
||||||
def->enum_labels.push_back(L("Octagram Spiral"));
|
def->enum_labels.push_back(L("Octagram Spiral"));
|
||||||
// solid_fill_pattern is an obsolete equivalent to top_fill_pattern/bottom_fill_pattern.
|
// solid_fill_pattern is an obsolete equivalent to top_fill_pattern/bottom_fill_pattern.
|
||||||
def->aliases = { "solid_fill_pattern", "external_fill_pattern" };
|
def->aliases = { "solid_fill_pattern", "external_fill_pattern" };
|
||||||
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipRectilinear));
|
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipMonotonous));
|
||||||
|
|
||||||
def = this->add("bottom_fill_pattern", coEnum);
|
def = this->add("bottom_fill_pattern", coEnum);
|
||||||
def->label = L("Bottom fill pattern");
|
def->label = L("Bottom fill pattern");
|
||||||
|
@ -1081,6 +1088,53 @@ void PrintConfigDef::init_fff_params()
|
||||||
def->mode = comExpert;
|
def->mode = comExpert;
|
||||||
def->set_default_value(new ConfigOptionBool(false));
|
def->set_default_value(new ConfigOptionBool(false));
|
||||||
|
|
||||||
|
def = this->add("ironing", coBool);
|
||||||
|
def->label = L("Enable ironing");
|
||||||
|
def->tooltip = L("Enable ironing of the top layers with the hot print head for smooth surface");
|
||||||
|
def->category = L("Ironing");
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionBool(false));
|
||||||
|
|
||||||
|
def = this->add("ironing_type", coEnum);
|
||||||
|
def->label = L("Ironingy Type");
|
||||||
|
def->tooltip = L("Ironingy Type");
|
||||||
|
def->enum_keys_map = &ConfigOptionEnum<IroningType>::get_enum_values();
|
||||||
|
def->enum_values.push_back("top");
|
||||||
|
def->enum_values.push_back("topmost");
|
||||||
|
def->enum_values.push_back("solid");
|
||||||
|
def->enum_labels.push_back("All top surfaces");
|
||||||
|
def->enum_labels.push_back("Topmost surface only");
|
||||||
|
def->enum_labels.push_back("All solid surfaces");
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionEnum<IroningType>(IroningType::TopSurfaces));
|
||||||
|
|
||||||
|
def = this->add("ironing_flowrate", coPercent);
|
||||||
|
def->label = L("Flow rate");
|
||||||
|
def->category = L("Ironing");
|
||||||
|
def->tooltip = L("Percent of a flow rate relative to object's normal layer height.");
|
||||||
|
def->sidetext = L("%");
|
||||||
|
def->ratio_over = "layer_height";
|
||||||
|
def->min = 0;
|
||||||
|
def->mode = comExpert;
|
||||||
|
def->set_default_value(new ConfigOptionPercent(15));
|
||||||
|
|
||||||
|
def = this->add("ironing_spacing", coFloat);
|
||||||
|
def->label = L("Spacing between ironing passes");
|
||||||
|
def->tooltip = L("Distance between ironing lins");
|
||||||
|
def->sidetext = L("mm");
|
||||||
|
def->min = 0;
|
||||||
|
def->mode = comExpert;
|
||||||
|
def->set_default_value(new ConfigOptionFloat(0.1));
|
||||||
|
|
||||||
|
def = this->add("ironing_speed", coFloat);
|
||||||
|
def->label = L("Ironing speed");
|
||||||
|
def->category = L("Speed");
|
||||||
|
def->tooltip = L("Ironing speed");
|
||||||
|
def->sidetext = L("mm/s");
|
||||||
|
def->min = 0;
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionFloat(15));
|
||||||
|
|
||||||
def = this->add("layer_gcode", coString);
|
def = this->add("layer_gcode", coString);
|
||||||
def->label = L("After layer change G-code");
|
def->label = L("After layer change G-code");
|
||||||
def->tooltip = L("This custom code is inserted at every layer change, right after the Z move "
|
def->tooltip = L("This custom code is inserted at every layer change, right after the Z move "
|
||||||
|
@ -3066,6 +3120,42 @@ DynamicPrintConfig* DynamicPrintConfig::new_from_defaults_keys(const std::vector
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double min_object_distance(const ConfigBase &cfg)
|
||||||
|
{
|
||||||
|
double ret = 0.;
|
||||||
|
|
||||||
|
if (printer_technology(cfg) == ptSLA) ret = 6.;
|
||||||
|
else {
|
||||||
|
auto ecr_opt = cfg.option<ConfigOptionFloat>("extruder_clearance_radius");
|
||||||
|
auto dd_opt = cfg.option<ConfigOptionFloat>("duplicate_distance");
|
||||||
|
auto co_opt = cfg.option<ConfigOptionBool>("complete_objects");
|
||||||
|
|
||||||
|
if (!ecr_opt || !dd_opt || !co_opt) ret = 0.;
|
||||||
|
else {
|
||||||
|
// min object distance is max(duplicate_distance, clearance_radius)
|
||||||
|
ret = (co_opt->value && ecr_opt->value > dd_opt->value) ?
|
||||||
|
ecr_opt->value : dd_opt->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrinterTechnology printer_technology(const ConfigBase &cfg)
|
||||||
|
{
|
||||||
|
const ConfigOptionEnum<PrinterTechnology> *opt = cfg.option<ConfigOptionEnum<PrinterTechnology>>("printer_technology");
|
||||||
|
|
||||||
|
if (opt) return opt->value;
|
||||||
|
|
||||||
|
const ConfigOptionBool *export_opt = cfg.option<ConfigOptionBool>("export_sla");
|
||||||
|
if (export_opt && export_opt->getBool()) return ptSLA;
|
||||||
|
|
||||||
|
export_opt = cfg.option<ConfigOptionBool>("export_gcode");
|
||||||
|
if (export_opt && export_opt->getBool()) return ptFFF;
|
||||||
|
|
||||||
|
return ptUnknown;
|
||||||
|
}
|
||||||
|
|
||||||
void DynamicPrintConfig::normalize()
|
void DynamicPrintConfig::normalize()
|
||||||
{
|
{
|
||||||
if (this->has("extruder")) {
|
if (this->has("extruder")) {
|
||||||
|
@ -3136,22 +3226,6 @@ std::string DynamicPrintConfig::validate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double PrintConfig::min_object_distance() const
|
|
||||||
{
|
|
||||||
return PrintConfig::min_object_distance(static_cast<const ConfigBase*>(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
double PrintConfig::min_object_distance(const ConfigBase *config)
|
|
||||||
{
|
|
||||||
double extruder_clearance_radius = config->option("extruder_clearance_radius")->getFloat();
|
|
||||||
double duplicate_distance = config->option("duplicate_distance")->getFloat();
|
|
||||||
|
|
||||||
// min object distance is max(duplicate_distance, clearance_radius)
|
|
||||||
return (config->option("complete_objects")->getBool() && extruder_clearance_radius > duplicate_distance)
|
|
||||||
? extruder_clearance_radius
|
|
||||||
: duplicate_distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
//FIXME localize this function.
|
//FIXME localize this function.
|
||||||
std::string FullPrintConfig::validate()
|
std::string FullPrintConfig::validate()
|
||||||
{
|
{
|
||||||
|
@ -3561,8 +3635,39 @@ void DynamicPrintAndCLIConfig::handle_legacy(t_config_option_key &opt_key, std::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Points to_points(const std::vector<Vec2d> &dpts)
|
||||||
|
{
|
||||||
|
Points pts; pts.reserve(dpts.size());
|
||||||
|
for (auto &v : dpts)
|
||||||
|
pts.emplace_back( coord_t(scale_(v.x())), coord_t(scale_(v.y())) );
|
||||||
|
return pts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Points get_bed_shape(const DynamicPrintConfig &config)
|
||||||
|
{
|
||||||
|
const auto *bed_shape_opt = config.opt<ConfigOptionPoints>("bed_shape");
|
||||||
|
if (!bed_shape_opt) {
|
||||||
|
|
||||||
|
// Here, it is certain that the bed shape is missing, so an infinite one
|
||||||
|
// has to be used, but still, the center of bed can be queried
|
||||||
|
if (auto center_opt = config.opt<ConfigOptionPoint>("center"))
|
||||||
|
return { scaled(center_opt->value) };
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return to_points(bed_shape_opt->values);
|
||||||
|
}
|
||||||
|
|
||||||
|
Points get_bed_shape(const PrintConfig &cfg)
|
||||||
|
{
|
||||||
|
return to_points(cfg.bed_shape.values);
|
||||||
|
}
|
||||||
|
|
||||||
|
Points get_bed_shape(const SLAPrinterConfig &cfg) { return to_points(cfg.bed_shape.values); }
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
#include <cereal/types/polymorphic.hpp>
|
#include <cereal/types/polymorphic.hpp>
|
||||||
CEREAL_REGISTER_TYPE(Slic3r::DynamicPrintConfig)
|
CEREAL_REGISTER_TYPE(Slic3r::DynamicPrintConfig)
|
||||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::DynamicConfig, Slic3r::DynamicPrintConfig)
|
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::DynamicConfig, Slic3r::DynamicPrintConfig)
|
||||||
|
|
|
@ -34,10 +34,17 @@ enum PrintHostType {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum InfillPattern {
|
enum InfillPattern {
|
||||||
ipRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
ipRectilinear, ipMonotonous, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
||||||
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipCount,
|
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class IroningType {
|
||||||
|
TopSurfaces,
|
||||||
|
TopmostOnly,
|
||||||
|
AllSolid,
|
||||||
|
Count,
|
||||||
|
};
|
||||||
|
|
||||||
enum SupportMaterialPattern {
|
enum SupportMaterialPattern {
|
||||||
smpRectilinear, smpRectilinearGrid, smpHoneycomb,
|
smpRectilinear, smpRectilinearGrid, smpHoneycomb,
|
||||||
};
|
};
|
||||||
|
@ -106,6 +113,7 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<InfillPattern>::g
|
||||||
static t_config_enum_values keys_map;
|
static t_config_enum_values keys_map;
|
||||||
if (keys_map.empty()) {
|
if (keys_map.empty()) {
|
||||||
keys_map["rectilinear"] = ipRectilinear;
|
keys_map["rectilinear"] = ipRectilinear;
|
||||||
|
keys_map["monotonous"] = ipMonotonous;
|
||||||
keys_map["grid"] = ipGrid;
|
keys_map["grid"] = ipGrid;
|
||||||
keys_map["triangles"] = ipTriangles;
|
keys_map["triangles"] = ipTriangles;
|
||||||
keys_map["stars"] = ipStars;
|
keys_map["stars"] = ipStars;
|
||||||
|
@ -122,6 +130,16 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<InfillPattern>::g
|
||||||
return keys_map;
|
return keys_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<> inline const t_config_enum_values& ConfigOptionEnum<IroningType>::get_enum_values() {
|
||||||
|
static t_config_enum_values keys_map;
|
||||||
|
if (keys_map.empty()) {
|
||||||
|
keys_map["top"] = int(IroningType::TopSurfaces);
|
||||||
|
keys_map["topmost"] = int(IroningType::TopmostOnly);
|
||||||
|
keys_map["solid"] = int(IroningType::AllSolid);
|
||||||
|
}
|
||||||
|
return keys_map;
|
||||||
|
}
|
||||||
|
|
||||||
template<> inline const t_config_enum_values& ConfigOptionEnum<SupportMaterialPattern>::get_enum_values() {
|
template<> inline const t_config_enum_values& ConfigOptionEnum<SupportMaterialPattern>::get_enum_values() {
|
||||||
static t_config_enum_values keys_map;
|
static t_config_enum_values keys_map;
|
||||||
if (keys_map.empty()) {
|
if (keys_map.empty()) {
|
||||||
|
@ -194,6 +212,9 @@ extern const PrintConfigDef print_config_def;
|
||||||
|
|
||||||
class StaticPrintConfig;
|
class StaticPrintConfig;
|
||||||
|
|
||||||
|
PrinterTechnology printer_technology(const ConfigBase &cfg);
|
||||||
|
double min_object_distance(const ConfigBase &cfg);
|
||||||
|
|
||||||
// Slic3r dynamic configuration, used to override the configuration
|
// Slic3r dynamic configuration, used to override the configuration
|
||||||
// per object, per modification volume or per printing material.
|
// per object, per modification volume or per printing material.
|
||||||
// The dynamic configuration is also used to store user modifications of the print global parameters,
|
// The dynamic configuration is also used to store user modifications of the print global parameters,
|
||||||
|
@ -485,6 +506,12 @@ public:
|
||||||
ConfigOptionInt infill_every_layers;
|
ConfigOptionInt infill_every_layers;
|
||||||
ConfigOptionFloatOrPercent infill_overlap;
|
ConfigOptionFloatOrPercent infill_overlap;
|
||||||
ConfigOptionFloat infill_speed;
|
ConfigOptionFloat infill_speed;
|
||||||
|
// Ironing options
|
||||||
|
ConfigOptionBool ironing;
|
||||||
|
ConfigOptionEnum<IroningType> ironing_type;
|
||||||
|
ConfigOptionPercent ironing_flowrate;
|
||||||
|
ConfigOptionFloat ironing_spacing;
|
||||||
|
ConfigOptionFloat ironing_speed;
|
||||||
// Detect bridging perimeters
|
// Detect bridging perimeters
|
||||||
ConfigOptionBool overhangs;
|
ConfigOptionBool overhangs;
|
||||||
ConfigOptionInt perimeter_extruder;
|
ConfigOptionInt perimeter_extruder;
|
||||||
|
@ -530,6 +557,11 @@ protected:
|
||||||
OPT_PTR(infill_every_layers);
|
OPT_PTR(infill_every_layers);
|
||||||
OPT_PTR(infill_overlap);
|
OPT_PTR(infill_overlap);
|
||||||
OPT_PTR(infill_speed);
|
OPT_PTR(infill_speed);
|
||||||
|
OPT_PTR(ironing);
|
||||||
|
OPT_PTR(ironing_type);
|
||||||
|
OPT_PTR(ironing_flowrate);
|
||||||
|
OPT_PTR(ironing_spacing);
|
||||||
|
OPT_PTR(ironing_speed);
|
||||||
OPT_PTR(overhangs);
|
OPT_PTR(overhangs);
|
||||||
OPT_PTR(perimeter_extruder);
|
OPT_PTR(perimeter_extruder);
|
||||||
OPT_PTR(perimeter_extrusion_width);
|
OPT_PTR(perimeter_extrusion_width);
|
||||||
|
@ -749,8 +781,6 @@ class PrintConfig : public MachineEnvelopeConfig, public GCodeConfig
|
||||||
STATIC_PRINT_CONFIG_CACHE_DERIVED(PrintConfig)
|
STATIC_PRINT_CONFIG_CACHE_DERIVED(PrintConfig)
|
||||||
PrintConfig() : MachineEnvelopeConfig(0), GCodeConfig(0) { initialize_cache(); *this = s_cache_PrintConfig.defaults(); }
|
PrintConfig() : MachineEnvelopeConfig(0), GCodeConfig(0) { initialize_cache(); *this = s_cache_PrintConfig.defaults(); }
|
||||||
public:
|
public:
|
||||||
double min_object_distance() const;
|
|
||||||
static double min_object_distance(const ConfigBase *config);
|
|
||||||
|
|
||||||
ConfigOptionBool avoid_crossing_perimeters;
|
ConfigOptionBool avoid_crossing_perimeters;
|
||||||
ConfigOptionPoints bed_shape;
|
ConfigOptionPoints bed_shape;
|
||||||
|
@ -1305,6 +1335,10 @@ private:
|
||||||
static PrintAndCLIConfigDef s_def;
|
static PrintAndCLIConfigDef s_def;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Points get_bed_shape(const DynamicPrintConfig &cfg);
|
||||||
|
Points get_bed_shape(const PrintConfig &cfg);
|
||||||
|
Points get_bed_shape(const SLAPrinterConfig &cfg);
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
// Serialization through the Cereal library
|
// Serialization through the Cereal library
|
||||||
|
|
|
@ -387,6 +387,25 @@ void PrintObject::infill()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PrintObject::ironing()
|
||||||
|
{
|
||||||
|
if (this->set_started(posIroning)) {
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "Ironing in parallel - start";
|
||||||
|
tbb::parallel_for(
|
||||||
|
tbb::blocked_range<size_t>(1, m_layers.size()),
|
||||||
|
[this](const tbb::blocked_range<size_t>& range) {
|
||||||
|
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
|
||||||
|
m_print->throw_if_canceled();
|
||||||
|
m_layers[layer_idx]->make_ironing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
m_print->throw_if_canceled();
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "Ironing in parallel - end";
|
||||||
|
this->set_done(posIroning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PrintObject::generate_support_material()
|
void PrintObject::generate_support_material()
|
||||||
{
|
{
|
||||||
if (this->set_started(posSupportMaterial)) {
|
if (this->set_started(posSupportMaterial)) {
|
||||||
|
@ -2610,6 +2629,7 @@ void PrintObject::combine_infill()
|
||||||
// Because fill areas for rectilinear and honeycomb are grown
|
// Because fill areas for rectilinear and honeycomb are grown
|
||||||
// later to overlap perimeters, we need to counteract that too.
|
// later to overlap perimeters, we need to counteract that too.
|
||||||
((region->config().fill_pattern == ipRectilinear ||
|
((region->config().fill_pattern == ipRectilinear ||
|
||||||
|
region->config().fill_pattern == ipMonotonous ||
|
||||||
region->config().fill_pattern == ipGrid ||
|
region->config().fill_pattern == ipGrid ||
|
||||||
region->config().fill_pattern == ipLine ||
|
region->config().fill_pattern == ipLine ||
|
||||||
region->config().fill_pattern == ipHoneycomb) ? 1.5f : 0.5f) *
|
region->config().fill_pattern == ipHoneycomb) ? 1.5f : 0.5f) *
|
||||||
|
@ -2645,4 +2665,168 @@ void PrintObject::_generate_support_material()
|
||||||
support_material.generate(*this);
|
support_material.generate(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PrintObject::project_and_append_custom_supports(
|
||||||
|
FacetSupportType type, std::vector<ExPolygons>& expolys) const
|
||||||
|
{
|
||||||
|
for (const ModelVolume* mv : this->model_object()->volumes) {
|
||||||
|
const std::vector<int> custom_facets = mv->m_supported_facets.get_facets(type);
|
||||||
|
if (custom_facets.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const TriangleMesh& mesh = mv->mesh();
|
||||||
|
const Transform3f& tr1 = mv->get_matrix().cast<float>();
|
||||||
|
const Transform3f& tr2 = this->trafo().cast<float>();
|
||||||
|
const Transform3f tr = tr2 * tr1;
|
||||||
|
|
||||||
|
|
||||||
|
// The projection will be at most a pentagon. Let's minimize heap
|
||||||
|
// reallocations by saving in in the following struct.
|
||||||
|
// Points are used so that scaling can be done in parallel
|
||||||
|
// and they can be moved from to create an ExPolygon later.
|
||||||
|
struct LightPolygon {
|
||||||
|
LightPolygon() { pts.reserve(5); }
|
||||||
|
Points pts;
|
||||||
|
|
||||||
|
void add(const Vec2f& pt) {
|
||||||
|
pts.emplace_back(scale_(pt.x()), scale_(pt.y()));
|
||||||
|
assert(pts.size() <= 5);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Structure to collect projected polygons. One element for each triangle.
|
||||||
|
// Saves vector of polygons and layer_id of the first one.
|
||||||
|
struct TriangleProjections {
|
||||||
|
size_t first_layer_id;
|
||||||
|
std::vector<LightPolygon> polygons;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Vector to collect resulting projections from each triangle.
|
||||||
|
std::vector<TriangleProjections> projections_of_triangles(custom_facets.size());
|
||||||
|
|
||||||
|
// Iterate over all triangles.
|
||||||
|
tbb::parallel_for(
|
||||||
|
tbb::blocked_range<size_t>(0, custom_facets.size()),
|
||||||
|
[&](const tbb::blocked_range<size_t>& range) {
|
||||||
|
for (size_t idx = range.begin(); idx < range.end(); ++ idx) {
|
||||||
|
|
||||||
|
std::array<Vec3f, 3> facet;
|
||||||
|
|
||||||
|
// Transform the triangle into worlds coords.
|
||||||
|
for (int i=0; i<3; ++i)
|
||||||
|
facet[i] = tr * mesh.its.vertices[mesh.its.indices[custom_facets[idx]](i)];
|
||||||
|
|
||||||
|
// Ignore triangles with upward-pointing normal.
|
||||||
|
if ((facet[1]-facet[0]).cross(facet[2]-facet[0]).z() > 0.)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Sort the three vertices according to z-coordinate.
|
||||||
|
std::sort(facet.begin(), facet.end(),
|
||||||
|
[](const Vec3f& pt1, const Vec3f&pt2) {
|
||||||
|
return pt1.z() < pt2.z();
|
||||||
|
});
|
||||||
|
|
||||||
|
std::array<Vec2f, 3> trianglef;
|
||||||
|
for (int i=0; i<3; ++i) {
|
||||||
|
trianglef[i] = Vec2f(facet[i].x(), facet[i].y());
|
||||||
|
trianglef[i] += Vec2f(unscale<float>(this->center_offset().x()),
|
||||||
|
unscale<float>(this->center_offset().y()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find lowest slice not below the triangle.
|
||||||
|
auto it = std::lower_bound(layers().begin(), layers().end(), facet[0].z()+EPSILON,
|
||||||
|
[](const Layer* l1, float z) {
|
||||||
|
return l1->slice_z < z;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Count how many projections will be generated for this triangle
|
||||||
|
// and allocate respective amount in projections_of_triangles.
|
||||||
|
projections_of_triangles[idx].first_layer_id = it-layers().begin();
|
||||||
|
size_t last_layer_id = projections_of_triangles[idx].first_layer_id;
|
||||||
|
// The cast in the condition below is important. The comparison must
|
||||||
|
// be an exact opposite of the one lower in the code where
|
||||||
|
// the polygons are appended. And that one is on floats.
|
||||||
|
while (last_layer_id + 1 < layers().size()
|
||||||
|
&& float(layers()[last_layer_id]->slice_z) <= facet[2].z())
|
||||||
|
++last_layer_id;
|
||||||
|
projections_of_triangles[idx].polygons.resize(
|
||||||
|
last_layer_id - projections_of_triangles[idx].first_layer_id + 1);
|
||||||
|
|
||||||
|
// Calculate how to move points on triangle sides per unit z increment.
|
||||||
|
Vec2f ta(trianglef[1] - trianglef[0]);
|
||||||
|
Vec2f tb(trianglef[2] - trianglef[0]);
|
||||||
|
ta *= 1./(facet[1].z() - facet[0].z());
|
||||||
|
tb *= 1./(facet[2].z() - facet[0].z());
|
||||||
|
|
||||||
|
// Projection on current slice will be build directly in place.
|
||||||
|
LightPolygon* proj = &projections_of_triangles[idx].polygons[0];
|
||||||
|
proj->add(trianglef[0]);
|
||||||
|
|
||||||
|
bool passed_first = false;
|
||||||
|
bool stop = false;
|
||||||
|
|
||||||
|
// Project a sub-polygon on all slices intersecting the triangle.
|
||||||
|
while (it != layers().end()) {
|
||||||
|
const float z = (*it)->slice_z;
|
||||||
|
|
||||||
|
// Projections of triangle sides intersections with slices.
|
||||||
|
// a moves along one side, b tracks the other.
|
||||||
|
Vec2f a;
|
||||||
|
Vec2f b;
|
||||||
|
|
||||||
|
// If the middle vertex was already passed, append the vertex
|
||||||
|
// and use ta for tracking the remaining side.
|
||||||
|
if (z > facet[1].z() && ! passed_first) {
|
||||||
|
proj->add(trianglef[1]);
|
||||||
|
ta = trianglef[2]-trianglef[1];
|
||||||
|
ta *= 1./(facet[2].z() - facet[1].z());
|
||||||
|
passed_first = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This slice is above the triangle already.
|
||||||
|
if (z > facet[2].z() || it+1 == layers().end()) {
|
||||||
|
proj->add(trianglef[2]);
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Move a, b along the side it currently tracks to get
|
||||||
|
// projected intersection with current slice.
|
||||||
|
a = passed_first ? (trianglef[1]+ta*(z-facet[1].z()))
|
||||||
|
: (trianglef[0]+ta*(z-facet[0].z()));
|
||||||
|
b = trianglef[0]+tb*(z-facet[0].z());
|
||||||
|
proj->add(a);
|
||||||
|
proj->add(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stop)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Advance to the next layer.
|
||||||
|
++it;
|
||||||
|
++proj;
|
||||||
|
assert(proj <= &projections_of_triangles[idx].polygons.back() );
|
||||||
|
|
||||||
|
// a, b are first two points of the polygon for the next layer.
|
||||||
|
proj->add(b);
|
||||||
|
proj->add(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}); // end of parallel_for
|
||||||
|
|
||||||
|
// Make sure that the output vector can be used.
|
||||||
|
expolys.resize(layers().size());
|
||||||
|
|
||||||
|
// Now append the collected polygons to respective layers.
|
||||||
|
for (auto& trg : projections_of_triangles) {
|
||||||
|
int layer_id = trg.first_layer_id;
|
||||||
|
|
||||||
|
for (const LightPolygon& poly : trg.polygons) {
|
||||||
|
expolys[layer_id].emplace_back(std::move(poly.pts));
|
||||||
|
++layer_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // loop over ModelVolumes
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
222
src/libslic3r/SLA/AGGRaster.hpp
Normal file
222
src/libslic3r/SLA/AGGRaster.hpp
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
#ifndef AGGRASTER_HPP
|
||||||
|
#define AGGRASTER_HPP
|
||||||
|
|
||||||
|
#include <libslic3r/SLA/RasterBase.hpp>
|
||||||
|
#include "libslic3r/ExPolygon.hpp"
|
||||||
|
#include "libslic3r/MTUtils.hpp"
|
||||||
|
#include <libnest2d/backends/clipper/clipper_polygon.hpp>
|
||||||
|
|
||||||
|
// For rasterizing
|
||||||
|
#include <agg/agg_basics.h>
|
||||||
|
#include <agg/agg_rendering_buffer.h>
|
||||||
|
#include <agg/agg_pixfmt_gray.h>
|
||||||
|
#include <agg/agg_pixfmt_rgb.h>
|
||||||
|
#include <agg/agg_renderer_base.h>
|
||||||
|
#include <agg/agg_renderer_scanline.h>
|
||||||
|
|
||||||
|
#include <agg/agg_scanline_p.h>
|
||||||
|
#include <agg/agg_rasterizer_scanline_aa.h>
|
||||||
|
#include <agg/agg_path_storage.h>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
inline const Polygon& contour(const ExPolygon& p) { return p.contour; }
|
||||||
|
inline const ClipperLib::Path& contour(const ClipperLib::Polygon& p) { return p.Contour; }
|
||||||
|
|
||||||
|
inline const Polygons& holes(const ExPolygon& p) { return p.holes; }
|
||||||
|
inline const ClipperLib::Paths& holes(const ClipperLib::Polygon& p) { return p.Holes; }
|
||||||
|
|
||||||
|
namespace sla {
|
||||||
|
|
||||||
|
template<class Color> struct Colors {
|
||||||
|
static const Color White;
|
||||||
|
static const Color Black;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Color> const Color Colors<Color>::White = Color{255};
|
||||||
|
template<class Color> const Color Colors<Color>::Black = Color{0};
|
||||||
|
|
||||||
|
template<class PixelRenderer,
|
||||||
|
template<class /*agg::renderer_base<PixelRenderer>*/> class Renderer,
|
||||||
|
class Rasterizer = agg::rasterizer_scanline_aa<>,
|
||||||
|
class Scanline = agg::scanline_p8>
|
||||||
|
class AGGRaster: public RasterBase {
|
||||||
|
public:
|
||||||
|
using TColor = typename PixelRenderer::color_type;
|
||||||
|
using TValue = typename TColor::value_type;
|
||||||
|
using TPixel = typename PixelRenderer::pixel_type;
|
||||||
|
using TRawBuffer = agg::rendering_buffer;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Resolution m_resolution;
|
||||||
|
PixelDim m_pxdim_scaled; // used for scaled coordinate polygons
|
||||||
|
|
||||||
|
std::vector<TPixel> m_buf;
|
||||||
|
agg::rendering_buffer m_rbuf;
|
||||||
|
|
||||||
|
PixelRenderer m_pixrenderer;
|
||||||
|
|
||||||
|
agg::renderer_base<PixelRenderer> m_raw_renderer;
|
||||||
|
Renderer<agg::renderer_base<PixelRenderer>> m_renderer;
|
||||||
|
|
||||||
|
Trafo m_trafo;
|
||||||
|
Scanline m_scanlines;
|
||||||
|
Rasterizer m_rasterizer;
|
||||||
|
|
||||||
|
void flipy(agg::path_storage &path) const
|
||||||
|
{
|
||||||
|
path.flip_y(0, double(m_resolution.height_px));
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipx(agg::path_storage &path) const
|
||||||
|
{
|
||||||
|
path.flip_x(0, double(m_resolution.width_px));
|
||||||
|
}
|
||||||
|
|
||||||
|
double getPx(const Point &p) { return p(0) * m_pxdim_scaled.w_mm; }
|
||||||
|
double getPy(const Point &p) { return p(1) * m_pxdim_scaled.h_mm; }
|
||||||
|
agg::path_storage to_path(const Polygon &poly) { return to_path(poly.points); }
|
||||||
|
double getPx(const ClipperLib::IntPoint &p) { return p.X * m_pxdim_scaled.w_mm; }
|
||||||
|
double getPy(const ClipperLib::IntPoint& p) { return p.Y * m_pxdim_scaled.h_mm; }
|
||||||
|
|
||||||
|
template<class PointVec> agg::path_storage _to_path(const PointVec& v)
|
||||||
|
{
|
||||||
|
agg::path_storage path;
|
||||||
|
|
||||||
|
auto it = v.begin();
|
||||||
|
path.move_to(getPx(*it), getPy(*it));
|
||||||
|
while(++it != v.end()) path.line_to(getPx(*it), getPy(*it));
|
||||||
|
path.line_to(getPx(v.front()), getPy(v.front()));
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class PointVec> agg::path_storage _to_path_flpxy(const PointVec& v)
|
||||||
|
{
|
||||||
|
agg::path_storage path;
|
||||||
|
|
||||||
|
auto it = v.begin();
|
||||||
|
path.move_to(getPy(*it), getPx(*it));
|
||||||
|
while(++it != v.end()) path.line_to(getPy(*it), getPx(*it));
|
||||||
|
path.line_to(getPy(v.front()), getPx(v.front()));
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class PointVec> agg::path_storage to_path(const PointVec &v)
|
||||||
|
{
|
||||||
|
auto path = m_trafo.flipXY ? _to_path_flpxy(v) : _to_path(v);
|
||||||
|
|
||||||
|
path.translate_all_paths(m_trafo.center_x * m_pxdim_scaled.w_mm,
|
||||||
|
m_trafo.center_y * m_pxdim_scaled.h_mm);
|
||||||
|
|
||||||
|
if(m_trafo.mirror_x) flipx(path);
|
||||||
|
if(m_trafo.mirror_y) flipy(path);
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class P> void _draw(const P &poly)
|
||||||
|
{
|
||||||
|
m_rasterizer.reset();
|
||||||
|
|
||||||
|
m_rasterizer.add_path(to_path(contour(poly)));
|
||||||
|
for(auto& h : holes(poly)) m_rasterizer.add_path(to_path(h));
|
||||||
|
|
||||||
|
agg::render_scanlines(m_rasterizer, m_scanlines, m_renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<class GammaFn> AGGRaster(const Resolution &res,
|
||||||
|
const PixelDim & pd,
|
||||||
|
const Trafo & trafo,
|
||||||
|
const TColor & foreground,
|
||||||
|
const TColor & background,
|
||||||
|
GammaFn && gammafn)
|
||||||
|
: m_resolution(res)
|
||||||
|
, m_pxdim_scaled(SCALING_FACTOR / pd.w_mm, SCALING_FACTOR / pd.h_mm)
|
||||||
|
, m_buf(res.pixels())
|
||||||
|
, m_rbuf(reinterpret_cast<TValue *>(m_buf.data()),
|
||||||
|
unsigned(res.width_px),
|
||||||
|
unsigned(res.height_px),
|
||||||
|
int(res.width_px *PixelRenderer::num_components))
|
||||||
|
, m_pixrenderer(m_rbuf)
|
||||||
|
, m_raw_renderer(m_pixrenderer)
|
||||||
|
, m_renderer(m_raw_renderer)
|
||||||
|
, m_trafo(trafo)
|
||||||
|
{
|
||||||
|
m_renderer.color(foreground);
|
||||||
|
clear(background);
|
||||||
|
|
||||||
|
m_rasterizer.gamma(gammafn);
|
||||||
|
}
|
||||||
|
|
||||||
|
Trafo trafo() const override { return m_trafo; }
|
||||||
|
Resolution resolution() const override { return m_resolution; }
|
||||||
|
PixelDim pixel_dimensions() const override
|
||||||
|
{
|
||||||
|
return {SCALING_FACTOR / m_pxdim_scaled.w_mm,
|
||||||
|
SCALING_FACTOR / m_pxdim_scaled.h_mm};
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(const ExPolygon &poly) override { _draw(poly); }
|
||||||
|
void draw(const ClipperLib::Polygon &poly) override { _draw(poly); }
|
||||||
|
|
||||||
|
EncodedRaster encode(RasterEncoder encoder) const override
|
||||||
|
{
|
||||||
|
return encoder(m_buf.data(), m_resolution.width_px, m_resolution.height_px, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear(const TColor color) { m_raw_renderer.clear(color); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Captures an anti-aliased monochrome canvas where vectorial
|
||||||
|
* polygons can be rasterized. Fill color is always white and the background is
|
||||||
|
* black. Contours are anti-aliased.
|
||||||
|
*
|
||||||
|
* A gamma function can be specified at compile time to make it more flexible.
|
||||||
|
*/
|
||||||
|
using _RasterGrayscaleAA =
|
||||||
|
AGGRaster<agg::pixfmt_gray8, agg::renderer_scanline_aa_solid>;
|
||||||
|
|
||||||
|
class RasterGrayscaleAA : public _RasterGrayscaleAA {
|
||||||
|
using Base = _RasterGrayscaleAA;
|
||||||
|
using typename Base::TColor;
|
||||||
|
using typename Base::TValue;
|
||||||
|
public:
|
||||||
|
template<class GammaFn>
|
||||||
|
RasterGrayscaleAA(const RasterBase::Resolution &res,
|
||||||
|
const RasterBase::PixelDim & pd,
|
||||||
|
const RasterBase::Trafo & trafo,
|
||||||
|
GammaFn && fn)
|
||||||
|
: Base(res, pd, trafo, Colors<TColor>::White, Colors<TColor>::Black,
|
||||||
|
std::forward<GammaFn>(fn))
|
||||||
|
{}
|
||||||
|
|
||||||
|
uint8_t read_pixel(size_t col, size_t row) const
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<TValue, uint8_t>::value, "Not grayscale pix");
|
||||||
|
|
||||||
|
uint8_t px;
|
||||||
|
Base::m_buf[row * Base::resolution().width_px + col].get(px);
|
||||||
|
return px;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() { Base::clear(Colors<TColor>::Black); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class RasterGrayscaleAAGammaPower: public RasterGrayscaleAA {
|
||||||
|
public:
|
||||||
|
RasterGrayscaleAAGammaPower(const RasterBase::Resolution &res,
|
||||||
|
const RasterBase::PixelDim & pd,
|
||||||
|
const RasterBase::Trafo & trafo,
|
||||||
|
double gamma = 1.)
|
||||||
|
: RasterGrayscaleAA(res, pd, trafo, agg::gamma_power(gamma))
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace Slic3r::sla
|
||||||
|
|
||||||
|
#endif // AGGRASTER_HPP
|
|
@ -11,6 +11,8 @@
|
||||||
#include "Tesselate.hpp"
|
#include "Tesselate.hpp"
|
||||||
#include "MTUtils.hpp"
|
#include "MTUtils.hpp"
|
||||||
|
|
||||||
|
#include "TriangulateWall.hpp"
|
||||||
|
|
||||||
// For debugging:
|
// For debugging:
|
||||||
// #include <fstream>
|
// #include <fstream>
|
||||||
// #include <libnest2d/tools/benchmark.h>
|
// #include <libnest2d/tools/benchmark.h>
|
||||||
|
@ -27,175 +29,17 @@ namespace Slic3r { namespace sla {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/// This function will return a triangulation of a sheet connecting an upper
|
|
||||||
/// and a lower plate given as input polygons. It will not triangulate the
|
|
||||||
/// plates themselves only the sheet. The caller has to specify the lower and
|
|
||||||
/// upper z levels in world coordinates as well as the offset difference
|
|
||||||
/// between the sheets. If the lower_z_mm is higher than upper_z_mm or the
|
|
||||||
/// offset difference is negative, the resulting triangle orientation will be
|
|
||||||
/// reversed.
|
|
||||||
///
|
|
||||||
/// IMPORTANT: This is not a universal triangulation algorithm. It assumes
|
|
||||||
/// that the lower and upper polygons are offsetted versions of the same
|
|
||||||
/// original polygon. In general, it assumes that one of the polygons is
|
|
||||||
/// completely inside the other. The offset difference is the reference
|
|
||||||
/// distance from the inner polygon's perimeter to the outer polygon's
|
|
||||||
/// perimeter. The real distance will be variable as the clipper offset has
|
|
||||||
/// different strategies (rounding, etc...). This algorithm should have
|
|
||||||
/// O(2n + 3m) complexity where n is the number of upper vertices and m is the
|
|
||||||
/// number of lower vertices.
|
|
||||||
Contour3D walls(
|
Contour3D walls(
|
||||||
const Polygon &lower,
|
const Polygon &lower,
|
||||||
const Polygon &upper,
|
const Polygon &upper,
|
||||||
double lower_z_mm,
|
double lower_z_mm,
|
||||||
double upper_z_mm,
|
double upper_z_mm)
|
||||||
double offset_difference_mm,
|
|
||||||
ThrowOnCancel thr = [] {})
|
|
||||||
{
|
{
|
||||||
|
Wall w = triangulate_wall(lower, upper, lower_z_mm, upper_z_mm);
|
||||||
|
|
||||||
Contour3D ret;
|
Contour3D ret;
|
||||||
|
ret.points = std::move(w.first);
|
||||||
if(upper.points.size() < 3 || lower.size() < 3) return ret;
|
ret.faces3 = std::move(w.second);
|
||||||
|
|
||||||
// The concept of the algorithm is relatively simple. It will try to find
|
|
||||||
// the closest vertices from the upper and the lower polygon and use those
|
|
||||||
// as starting points. Then it will create the triangles sequentially using
|
|
||||||
// an edge from the upper polygon and a vertex from the lower or vice versa,
|
|
||||||
// depending on the resulting triangle's quality.
|
|
||||||
// The quality is measured by a scalar value. So far it looks like it is
|
|
||||||
// enough to derive it from the slope of the triangle's two edges connecting
|
|
||||||
// the upper and the lower part. A reference slope is calculated from the
|
|
||||||
// height and the offset difference.
|
|
||||||
|
|
||||||
// Offset in the index array for the ceiling
|
|
||||||
const auto offs = upper.points.size();
|
|
||||||
|
|
||||||
// Shorthand for the vertex arrays
|
|
||||||
auto& upts = upper.points, &lpts = lower.points;
|
|
||||||
auto& rpts = ret.points; auto& ind = ret.faces3;
|
|
||||||
|
|
||||||
// If the Z levels are flipped, or the offset difference is negative, we
|
|
||||||
// will interpret that as the triangles normals should be inverted.
|
|
||||||
bool inverted = upper_z_mm < lower_z_mm || offset_difference_mm < 0;
|
|
||||||
|
|
||||||
// Copy the points into the mesh, convert them from 2D to 3D
|
|
||||||
rpts.reserve(upts.size() + lpts.size());
|
|
||||||
ind.reserve(2 * upts.size() + 2 * lpts.size());
|
|
||||||
for (auto &p : upts)
|
|
||||||
rpts.emplace_back(unscaled(p.x()), unscaled(p.y()), upper_z_mm);
|
|
||||||
for (auto &p : lpts)
|
|
||||||
rpts.emplace_back(unscaled(p.x()), unscaled(p.y()), lower_z_mm);
|
|
||||||
|
|
||||||
// Create pointing indices into vertex arrays. u-upper, l-lower
|
|
||||||
size_t uidx = 0, lidx = offs, unextidx = 1, lnextidx = offs + 1;
|
|
||||||
|
|
||||||
// Simple squared distance calculation.
|
|
||||||
auto distfn = [](const Vec3d& p1, const Vec3d& p2) {
|
|
||||||
auto p = p1 - p2; return p.transpose() * p;
|
|
||||||
};
|
|
||||||
|
|
||||||
// We need to find the closest point on lower polygon to the first point on
|
|
||||||
// the upper polygon. These will be our starting points.
|
|
||||||
double distmin = std::numeric_limits<double>::max();
|
|
||||||
for(size_t l = lidx; l < rpts.size(); ++l) {
|
|
||||||
thr();
|
|
||||||
double d = distfn(rpts[l], rpts[uidx]);
|
|
||||||
if(d < distmin) { lidx = l; distmin = d; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up lnextidx to be ahead of lidx in cyclic mode
|
|
||||||
lnextidx = lidx + 1;
|
|
||||||
if(lnextidx == rpts.size()) lnextidx = offs;
|
|
||||||
|
|
||||||
// This will be the flip switch to toggle between upper and lower triangle
|
|
||||||
// creation mode
|
|
||||||
enum class Proceed {
|
|
||||||
UPPER, // A segment from the upper polygon and one vertex from the lower
|
|
||||||
LOWER // A segment from the lower polygon and one vertex from the upper
|
|
||||||
} proceed = Proceed::UPPER;
|
|
||||||
|
|
||||||
// Flags to help evaluating loop termination.
|
|
||||||
bool ustarted = false, lstarted = false;
|
|
||||||
|
|
||||||
// The variables for the fitness values, one for the actual and one for the
|
|
||||||
// previous.
|
|
||||||
double current_fit = 0, prev_fit = 0;
|
|
||||||
|
|
||||||
// Every triangle of the wall has two edges connecting the upper plate with
|
|
||||||
// the lower plate. From the length of these two edges and the zdiff we
|
|
||||||
// can calculate the momentary squared offset distance at a particular
|
|
||||||
// position on the wall. The average of the differences from the reference
|
|
||||||
// (squared) offset distance will give us the driving fitness value.
|
|
||||||
const double offsdiff2 = std::pow(offset_difference_mm, 2);
|
|
||||||
const double zdiff2 = std::pow(upper_z_mm - lower_z_mm, 2);
|
|
||||||
|
|
||||||
// Mark the current vertex iterator positions. If the iterators return to
|
|
||||||
// the same position, the loop can be terminated.
|
|
||||||
size_t uendidx = uidx, lendidx = lidx;
|
|
||||||
|
|
||||||
do { thr(); // check throw if canceled
|
|
||||||
|
|
||||||
prev_fit = current_fit;
|
|
||||||
|
|
||||||
switch(proceed) { // proceed depending on the current state
|
|
||||||
case Proceed::UPPER:
|
|
||||||
if(!ustarted || uidx != uendidx) { // there are vertices remaining
|
|
||||||
// Get the 3D vertices in order
|
|
||||||
const Vec3d& p_up1 = rpts[uidx];
|
|
||||||
const Vec3d& p_low = rpts[lidx];
|
|
||||||
const Vec3d& p_up2 = rpts[unextidx];
|
|
||||||
|
|
||||||
// Calculate fitness: the average of the two connecting edges
|
|
||||||
double a = offsdiff2 - (distfn(p_up1, p_low) - zdiff2);
|
|
||||||
double b = offsdiff2 - (distfn(p_up2, p_low) - zdiff2);
|
|
||||||
current_fit = (std::abs(a) + std::abs(b)) / 2;
|
|
||||||
|
|
||||||
if(current_fit > prev_fit) { // fit is worse than previously
|
|
||||||
proceed = Proceed::LOWER;
|
|
||||||
} else { // good to go, create the triangle
|
|
||||||
inverted
|
|
||||||
? ind.emplace_back(int(unextidx), int(lidx), int(uidx))
|
|
||||||
: ind.emplace_back(int(uidx), int(lidx), int(unextidx));
|
|
||||||
|
|
||||||
// Increment the iterators, rotate if necessary
|
|
||||||
++uidx; ++unextidx;
|
|
||||||
if(unextidx == offs) unextidx = 0;
|
|
||||||
if(uidx == offs) uidx = 0;
|
|
||||||
|
|
||||||
ustarted = true; // mark the movement of the iterators
|
|
||||||
// so that the comparison to uendidx can be made correctly
|
|
||||||
}
|
|
||||||
} else proceed = Proceed::LOWER;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case Proceed::LOWER:
|
|
||||||
// Mode with lower segment, upper vertex. Same structure:
|
|
||||||
if(!lstarted || lidx != lendidx) {
|
|
||||||
const Vec3d& p_low1 = rpts[lidx];
|
|
||||||
const Vec3d& p_low2 = rpts[lnextidx];
|
|
||||||
const Vec3d& p_up = rpts[uidx];
|
|
||||||
|
|
||||||
double a = offsdiff2 - (distfn(p_up, p_low1) - zdiff2);
|
|
||||||
double b = offsdiff2 - (distfn(p_up, p_low2) - zdiff2);
|
|
||||||
current_fit = (std::abs(a) + std::abs(b)) / 2;
|
|
||||||
|
|
||||||
if(current_fit > prev_fit) {
|
|
||||||
proceed = Proceed::UPPER;
|
|
||||||
} else {
|
|
||||||
inverted
|
|
||||||
? ind.emplace_back(int(uidx), int(lnextidx), int(lidx))
|
|
||||||
: ind.emplace_back(int(lidx), int(lnextidx), int(uidx));
|
|
||||||
|
|
||||||
++lidx; ++lnextidx;
|
|
||||||
if(lnextidx == rpts.size()) lnextidx = offs;
|
|
||||||
if(lidx == rpts.size()) lidx = offs;
|
|
||||||
|
|
||||||
lstarted = true;
|
|
||||||
}
|
|
||||||
} else proceed = Proceed::UPPER;
|
|
||||||
|
|
||||||
break;
|
|
||||||
} // end of switch
|
|
||||||
} while(!ustarted || !lstarted || uidx != uendidx || lidx != lendidx);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -203,10 +47,9 @@ Contour3D walls(
|
||||||
// Same as walls() but with identical higher and lower polygons.
|
// Same as walls() but with identical higher and lower polygons.
|
||||||
Contour3D inline straight_walls(const Polygon &plate,
|
Contour3D inline straight_walls(const Polygon &plate,
|
||||||
double lo_z,
|
double lo_z,
|
||||||
double hi_z,
|
double hi_z)
|
||||||
ThrowOnCancel thr)
|
|
||||||
{
|
{
|
||||||
return walls(plate, plate, lo_z, hi_z, .0 /*offset_diff*/, thr);
|
return walls(plate, plate, lo_z, hi_z);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to cut tiny connector cavities for a given polygon. The input poly
|
// Function to cut tiny connector cavities for a given polygon. The input poly
|
||||||
|
@ -534,10 +377,8 @@ bool add_cavity(Contour3D &pad, ExPolygon &top_poly, const PadConfig3D &cfg,
|
||||||
top_poly = pdiff.front();
|
top_poly = pdiff.front();
|
||||||
|
|
||||||
double z_min = -cfg.wing_height, z_max = 0;
|
double z_min = -cfg.wing_height, z_max = 0;
|
||||||
double offset_difference = -wing_distance;
|
pad.merge(walls(inner_base.contour, middle_base.contour, z_min, z_max));
|
||||||
pad.merge(walls(inner_base.contour, middle_base.contour, z_min, z_max,
|
thr();
|
||||||
offset_difference, thr));
|
|
||||||
|
|
||||||
pad.merge(triangulate_expolygon_3d(inner_base, z_min, NORMALS_UP));
|
pad.merge(triangulate_expolygon_3d(inner_base, z_min, NORMALS_UP));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -555,16 +396,16 @@ Contour3D create_outer_pad_geometry(const ExPolygons & skeleton,
|
||||||
offset_contour_only(pad_part, -scaled(cfg.bottom_offset()));
|
offset_contour_only(pad_part, -scaled(cfg.bottom_offset()));
|
||||||
|
|
||||||
if (bottom_poly.empty()) continue;
|
if (bottom_poly.empty()) continue;
|
||||||
|
thr();
|
||||||
|
|
||||||
double z_min = -cfg.height, z_max = 0;
|
double z_min = -cfg.height, z_max = 0;
|
||||||
ret.merge(walls(top_poly.contour, bottom_poly.contour, z_max, z_min,
|
ret.merge(walls(top_poly.contour, bottom_poly.contour, z_max, z_min));
|
||||||
cfg.bottom_offset(), thr));
|
|
||||||
|
|
||||||
if (cfg.wing_height > 0. && add_cavity(ret, top_poly, cfg, thr))
|
if (cfg.wing_height > 0. && add_cavity(ret, top_poly, cfg, thr))
|
||||||
z_max = -cfg.wing_height;
|
z_max = -cfg.wing_height;
|
||||||
|
|
||||||
for (auto &h : bottom_poly.holes)
|
for (auto &h : bottom_poly.holes)
|
||||||
ret.merge(straight_walls(h, z_max, z_min, thr));
|
ret.merge(straight_walls(h, z_max, z_min));
|
||||||
|
|
||||||
ret.merge(triangulate_expolygon_3d(bottom_poly, z_min, NORMALS_DOWN));
|
ret.merge(triangulate_expolygon_3d(bottom_poly, z_min, NORMALS_DOWN));
|
||||||
ret.merge(triangulate_expolygon_3d(top_poly, NORMALS_UP));
|
ret.merge(triangulate_expolygon_3d(top_poly, NORMALS_UP));
|
||||||
|
@ -581,10 +422,11 @@ Contour3D create_inner_pad_geometry(const ExPolygons & skeleton,
|
||||||
|
|
||||||
double z_max = 0., z_min = -cfg.height;
|
double z_max = 0., z_min = -cfg.height;
|
||||||
for (const ExPolygon &pad_part : skeleton) {
|
for (const ExPolygon &pad_part : skeleton) {
|
||||||
ret.merge(straight_walls(pad_part.contour, z_max, z_min,thr));
|
thr();
|
||||||
|
ret.merge(straight_walls(pad_part.contour, z_max, z_min));
|
||||||
|
|
||||||
for (auto &h : pad_part.holes)
|
for (auto &h : pad_part.holes)
|
||||||
ret.merge(straight_walls(h, z_max, z_min, thr));
|
ret.merge(straight_walls(h, z_max, z_min));
|
||||||
|
|
||||||
ret.merge(triangulate_expolygon_3d(pad_part, z_min, NORMALS_DOWN));
|
ret.merge(triangulate_expolygon_3d(pad_part, z_min, NORMALS_DOWN));
|
||||||
ret.merge(triangulate_expolygon_3d(pad_part, z_max, NORMALS_UP));
|
ret.merge(triangulate_expolygon_3d(pad_part, z_max, NORMALS_UP));
|
||||||
|
|
|
@ -1,320 +0,0 @@
|
||||||
#ifndef SLARASTER_CPP
|
|
||||||
#define SLARASTER_CPP
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include <libslic3r/SLA/Raster.hpp>
|
|
||||||
#include "libslic3r/ExPolygon.hpp"
|
|
||||||
#include "libslic3r/MTUtils.hpp"
|
|
||||||
#include <libnest2d/backends/clipper/clipper_polygon.hpp>
|
|
||||||
|
|
||||||
// For rasterizing
|
|
||||||
#include <agg/agg_basics.h>
|
|
||||||
#include <agg/agg_rendering_buffer.h>
|
|
||||||
#include <agg/agg_pixfmt_gray.h>
|
|
||||||
#include <agg/agg_pixfmt_rgb.h>
|
|
||||||
#include <agg/agg_renderer_base.h>
|
|
||||||
#include <agg/agg_renderer_scanline.h>
|
|
||||||
|
|
||||||
#include <agg/agg_scanline_p.h>
|
|
||||||
#include <agg/agg_rasterizer_scanline_aa.h>
|
|
||||||
#include <agg/agg_path_storage.h>
|
|
||||||
|
|
||||||
// Experimental minz image write:
|
|
||||||
#include <miniz.h>
|
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
|
|
||||||
inline const Polygon& contour(const ExPolygon& p) { return p.contour; }
|
|
||||||
inline const ClipperLib::Path& contour(const ClipperLib::Polygon& p) { return p.Contour; }
|
|
||||||
|
|
||||||
inline const Polygons& holes(const ExPolygon& p) { return p.holes; }
|
|
||||||
inline const ClipperLib::Paths& holes(const ClipperLib::Polygon& p) { return p.Holes; }
|
|
||||||
|
|
||||||
namespace sla {
|
|
||||||
|
|
||||||
const Raster::TMirroring Raster::NoMirror = {false, false};
|
|
||||||
const Raster::TMirroring Raster::MirrorX = {true, false};
|
|
||||||
const Raster::TMirroring Raster::MirrorY = {false, true};
|
|
||||||
const Raster::TMirroring Raster::MirrorXY = {true, true};
|
|
||||||
|
|
||||||
|
|
||||||
using TPixelRenderer = agg::pixfmt_gray8; // agg::pixfmt_rgb24;
|
|
||||||
using TRawRenderer = agg::renderer_base<TPixelRenderer>;
|
|
||||||
using TPixel = TPixelRenderer::color_type;
|
|
||||||
using TRawBuffer = agg::rendering_buffer;
|
|
||||||
using TBuffer = std::vector<TPixelRenderer::pixel_type>;
|
|
||||||
|
|
||||||
using TRendererAA = agg::renderer_scanline_aa_solid<TRawRenderer>;
|
|
||||||
|
|
||||||
class Raster::Impl {
|
|
||||||
public:
|
|
||||||
|
|
||||||
static const TPixel ColorWhite;
|
|
||||||
static const TPixel ColorBlack;
|
|
||||||
|
|
||||||
using Format = Raster::RawData;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Raster::Resolution m_resolution;
|
|
||||||
Raster::PixelDim m_pxdim_scaled; // used for scaled coordinate polygons
|
|
||||||
TBuffer m_buf;
|
|
||||||
TRawBuffer m_rbuf;
|
|
||||||
TPixelRenderer m_pixfmt;
|
|
||||||
TRawRenderer m_raw_renderer;
|
|
||||||
TRendererAA m_renderer;
|
|
||||||
|
|
||||||
std::function<double(double)> m_gammafn;
|
|
||||||
Trafo m_trafo;
|
|
||||||
|
|
||||||
inline void flipy(agg::path_storage& path) const {
|
|
||||||
path.flip_y(0, double(m_resolution.height_px));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void flipx(agg::path_storage& path) const {
|
|
||||||
path.flip_x(0, double(m_resolution.width_px));
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
inline Impl(const Raster::Resolution & res,
|
|
||||||
const Raster::PixelDim & pd,
|
|
||||||
const Trafo &trafo)
|
|
||||||
: m_resolution(res)
|
|
||||||
, m_pxdim_scaled(SCALING_FACTOR / pd.w_mm, SCALING_FACTOR / pd.h_mm)
|
|
||||||
, m_buf(res.pixels())
|
|
||||||
, m_rbuf(reinterpret_cast<TPixelRenderer::value_type *>(m_buf.data()),
|
|
||||||
unsigned(res.width_px),
|
|
||||||
unsigned(res.height_px),
|
|
||||||
int(res.width_px * TPixelRenderer::num_components))
|
|
||||||
, m_pixfmt(m_rbuf)
|
|
||||||
, m_raw_renderer(m_pixfmt)
|
|
||||||
, m_renderer(m_raw_renderer)
|
|
||||||
, m_trafo(trafo)
|
|
||||||
{
|
|
||||||
m_renderer.color(ColorWhite);
|
|
||||||
|
|
||||||
if (trafo.gamma > 0) m_gammafn = agg::gamma_power(trafo.gamma);
|
|
||||||
else m_gammafn = agg::gamma_threshold(0.5);
|
|
||||||
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class P> void draw(const P &poly) {
|
|
||||||
agg::rasterizer_scanline_aa<> ras;
|
|
||||||
agg::scanline_p8 scanlines;
|
|
||||||
|
|
||||||
ras.gamma(m_gammafn);
|
|
||||||
|
|
||||||
ras.add_path(to_path(contour(poly)));
|
|
||||||
for(auto& h : holes(poly)) ras.add_path(to_path(h));
|
|
||||||
|
|
||||||
agg::render_scanlines(ras, scanlines, m_renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void clear() {
|
|
||||||
m_raw_renderer.clear(ColorBlack);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline TBuffer& buffer() { return m_buf; }
|
|
||||||
inline const TBuffer& buffer() const { return m_buf; }
|
|
||||||
|
|
||||||
|
|
||||||
inline const Raster::Resolution resolution() { return m_resolution; }
|
|
||||||
inline const Raster::PixelDim pixdim()
|
|
||||||
{
|
|
||||||
return {SCALING_FACTOR / m_pxdim_scaled.w_mm,
|
|
||||||
SCALING_FACTOR / m_pxdim_scaled.h_mm};
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
inline double getPx(const Point& p) {
|
|
||||||
return p(0) * m_pxdim_scaled.w_mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double getPy(const Point& p) {
|
|
||||||
return p(1) * m_pxdim_scaled.h_mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline agg::path_storage to_path(const Polygon& poly)
|
|
||||||
{
|
|
||||||
return to_path(poly.points);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double getPx(const ClipperLib::IntPoint& p) {
|
|
||||||
return p.X * m_pxdim_scaled.w_mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double getPy(const ClipperLib::IntPoint& p) {
|
|
||||||
return p.Y * m_pxdim_scaled.h_mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class PointVec> agg::path_storage _to_path(const PointVec& v)
|
|
||||||
{
|
|
||||||
agg::path_storage path;
|
|
||||||
|
|
||||||
auto it = v.begin();
|
|
||||||
path.move_to(getPx(*it), getPy(*it));
|
|
||||||
while(++it != v.end()) path.line_to(getPx(*it), getPy(*it));
|
|
||||||
path.line_to(getPx(v.front()), getPy(v.front()));
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class PointVec> agg::path_storage _to_path_flpxy(const PointVec& v)
|
|
||||||
{
|
|
||||||
agg::path_storage path;
|
|
||||||
|
|
||||||
auto it = v.begin();
|
|
||||||
path.move_to(getPy(*it), getPx(*it));
|
|
||||||
while(++it != v.end()) path.line_to(getPy(*it), getPx(*it));
|
|
||||||
path.line_to(getPy(v.front()), getPx(v.front()));
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class PointVec> agg::path_storage to_path(const PointVec &v)
|
|
||||||
{
|
|
||||||
auto path = m_trafo.flipXY ? _to_path_flpxy(v) : _to_path(v);
|
|
||||||
|
|
||||||
path.translate_all_paths(m_trafo.origin_x * m_pxdim_scaled.w_mm,
|
|
||||||
m_trafo.origin_y * m_pxdim_scaled.h_mm);
|
|
||||||
|
|
||||||
if(m_trafo.mirror_x) flipx(path);
|
|
||||||
if(m_trafo.mirror_y) flipy(path);
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
const TPixel Raster::Impl::ColorWhite = TPixel(255);
|
|
||||||
const TPixel Raster::Impl::ColorBlack = TPixel(0);
|
|
||||||
|
|
||||||
Raster::Raster() { reset(); }
|
|
||||||
|
|
||||||
Raster::Raster(const Raster::Resolution &r,
|
|
||||||
const Raster::PixelDim & pd,
|
|
||||||
const Raster::Trafo & tr)
|
|
||||||
{
|
|
||||||
reset(r, pd, tr);
|
|
||||||
}
|
|
||||||
|
|
||||||
Raster::~Raster() = default;
|
|
||||||
|
|
||||||
Raster::Raster(Raster &&m) = default;
|
|
||||||
Raster &Raster::operator=(Raster &&) = default;
|
|
||||||
|
|
||||||
void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd,
|
|
||||||
const Trafo &trafo)
|
|
||||||
{
|
|
||||||
m_impl.reset();
|
|
||||||
m_impl.reset(new Impl(r, pd, trafo));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Raster::reset()
|
|
||||||
{
|
|
||||||
m_impl.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
Raster::Resolution Raster::resolution() const
|
|
||||||
{
|
|
||||||
if (m_impl) return m_impl->resolution();
|
|
||||||
|
|
||||||
return Resolution{0, 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
Raster::PixelDim Raster::pixel_dimensions() const
|
|
||||||
{
|
|
||||||
if (m_impl) return m_impl->pixdim();
|
|
||||||
|
|
||||||
return PixelDim{0., 0.};
|
|
||||||
}
|
|
||||||
|
|
||||||
void Raster::clear()
|
|
||||||
{
|
|
||||||
assert(m_impl);
|
|
||||||
m_impl->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Raster::draw(const ExPolygon &expoly)
|
|
||||||
{
|
|
||||||
assert(m_impl);
|
|
||||||
m_impl->draw(expoly);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Raster::draw(const ClipperLib::Polygon &poly)
|
|
||||||
{
|
|
||||||
assert(m_impl);
|
|
||||||
m_impl->draw(poly);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t Raster::read_pixel(size_t x, size_t y) const
|
|
||||||
{
|
|
||||||
assert (m_impl);
|
|
||||||
TPixel::value_type px;
|
|
||||||
m_impl->buffer()[y * resolution().width_px + x].get(px);
|
|
||||||
return px;
|
|
||||||
}
|
|
||||||
|
|
||||||
PNGImage & PNGImage::serialize(const Raster &raster)
|
|
||||||
{
|
|
||||||
size_t s = 0;
|
|
||||||
m_buffer.clear();
|
|
||||||
|
|
||||||
void *rawdata = tdefl_write_image_to_png_file_in_memory(
|
|
||||||
get_internals(raster).buffer().data(),
|
|
||||||
int(raster.resolution().width_px),
|
|
||||||
int(raster.resolution().height_px), 1, &s);
|
|
||||||
|
|
||||||
// On error, data() will return an empty vector. No other info can be
|
|
||||||
// retrieved from miniz anyway...
|
|
||||||
if (rawdata == nullptr) return *this;
|
|
||||||
|
|
||||||
auto ptr = static_cast<std::uint8_t*>(rawdata);
|
|
||||||
|
|
||||||
m_buffer.reserve(s);
|
|
||||||
std::copy(ptr, ptr + s, std::back_inserter(m_buffer));
|
|
||||||
|
|
||||||
MZ_FREE(rawdata);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &stream, const Raster::RawData &bytes)
|
|
||||||
{
|
|
||||||
stream.write(reinterpret_cast<const char *>(bytes.data()),
|
|
||||||
std::streamsize(bytes.size()));
|
|
||||||
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
Raster::RawData::~RawData() = default;
|
|
||||||
|
|
||||||
PPMImage & PPMImage::serialize(const Raster &raster)
|
|
||||||
{
|
|
||||||
auto header = std::string("P5 ") +
|
|
||||||
std::to_string(raster.resolution().width_px) + " " +
|
|
||||||
std::to_string(raster.resolution().height_px) + " " + "255 ";
|
|
||||||
|
|
||||||
const auto &impl = get_internals(raster);
|
|
||||||
auto sz = impl.buffer().size() * sizeof(TBuffer::value_type);
|
|
||||||
size_t s = sz + header.size();
|
|
||||||
|
|
||||||
m_buffer.clear();
|
|
||||||
m_buffer.reserve(s);
|
|
||||||
|
|
||||||
auto buff = reinterpret_cast<const std::uint8_t*>(impl.buffer().data());
|
|
||||||
std::copy(header.begin(), header.end(), std::back_inserter(m_buffer));
|
|
||||||
std::copy(buff, buff+sz, std::back_inserter(m_buffer));
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Raster::Impl &Raster::RawData::get_internals(const Raster &raster)
|
|
||||||
{
|
|
||||||
return *raster.m_impl;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sla
|
|
||||||
} // namespace Slic3r
|
|
||||||
|
|
||||||
#endif // SLARASTER_CPP
|
|
|
@ -1,157 +0,0 @@
|
||||||
#ifndef SLA_RASTER_HPP
|
|
||||||
#define SLA_RASTER_HPP
|
|
||||||
|
|
||||||
#include <ostream>
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
#include <array>
|
|
||||||
#include <utility>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
#include <libslic3r/ExPolygon.hpp>
|
|
||||||
|
|
||||||
namespace ClipperLib { struct Polygon; }
|
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
namespace sla {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Raster captures an anti-aliased monochrome canvas where vectorial
|
|
||||||
* polygons can be rasterized. Fill color is always white and the background is
|
|
||||||
* black. Contours are anti-aliased.
|
|
||||||
*
|
|
||||||
* It also supports saving the raster data into a standard output stream in raw
|
|
||||||
* or PNG format.
|
|
||||||
*/
|
|
||||||
class Raster {
|
|
||||||
class Impl;
|
|
||||||
std::unique_ptr<Impl> m_impl;
|
|
||||||
public:
|
|
||||||
|
|
||||||
// Raw byte buffer paired with its size. Suitable for compressed image data.
|
|
||||||
class RawData
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
std::vector<std::uint8_t> m_buffer;
|
|
||||||
const Impl& get_internals(const Raster& raster);
|
|
||||||
public:
|
|
||||||
RawData() = default;
|
|
||||||
RawData(std::vector<std::uint8_t>&& data): m_buffer(std::move(data)) {}
|
|
||||||
virtual ~RawData();
|
|
||||||
|
|
||||||
RawData(const RawData &) = delete;
|
|
||||||
RawData &operator=(const RawData &) = delete;
|
|
||||||
|
|
||||||
RawData(RawData &&) = default;
|
|
||||||
RawData &operator=(RawData &&) = default;
|
|
||||||
|
|
||||||
size_t size() const { return m_buffer.size(); }
|
|
||||||
const uint8_t * data() const { return m_buffer.data(); }
|
|
||||||
|
|
||||||
virtual RawData& serialize(const Raster &/*raster*/) { return *this; }
|
|
||||||
virtual std::string get_file_extension() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Type that represents a resolution in pixels.
|
|
||||||
struct Resolution {
|
|
||||||
size_t width_px;
|
|
||||||
size_t height_px;
|
|
||||||
|
|
||||||
inline Resolution(size_t w = 0, size_t h = 0)
|
|
||||||
: width_px(w), height_px(h)
|
|
||||||
{}
|
|
||||||
|
|
||||||
inline size_t pixels() const { return width_px * height_px; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Types that represents the dimension of a pixel in millimeters.
|
|
||||||
struct PixelDim {
|
|
||||||
double w_mm;
|
|
||||||
double h_mm;
|
|
||||||
inline PixelDim(double px_width_mm = 0.0, double px_height_mm = 0.0):
|
|
||||||
w_mm(px_width_mm), h_mm(px_height_mm) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Orientation { roLandscape, roPortrait };
|
|
||||||
|
|
||||||
using TMirroring = std::array<bool, 2>;
|
|
||||||
static const TMirroring NoMirror;
|
|
||||||
static const TMirroring MirrorX;
|
|
||||||
static const TMirroring MirrorY;
|
|
||||||
static const TMirroring MirrorXY;
|
|
||||||
|
|
||||||
struct Trafo {
|
|
||||||
bool mirror_x = false, mirror_y = false, flipXY = false;
|
|
||||||
coord_t origin_x = 0, origin_y = 0;
|
|
||||||
|
|
||||||
// If gamma is zero, thresholding will be performed which disables AA.
|
|
||||||
double gamma = 1.;
|
|
||||||
|
|
||||||
// Portrait orientation will make sure the drawed polygons are rotated
|
|
||||||
// by 90 degrees.
|
|
||||||
Trafo(Orientation o = roLandscape, const TMirroring &mirror = NoMirror)
|
|
||||||
// XY flipping implicitly does an X mirror
|
|
||||||
: mirror_x(o == roPortrait ? !mirror[0] : mirror[0])
|
|
||||||
, mirror_y(!mirror[1]) // Makes raster origin to be top left corner
|
|
||||||
, flipXY(o == roPortrait)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
Raster();
|
|
||||||
Raster(const Resolution &r,
|
|
||||||
const PixelDim & pd,
|
|
||||||
const Trafo & tr = {});
|
|
||||||
|
|
||||||
Raster(const Raster& cpy) = delete;
|
|
||||||
Raster& operator=(const Raster& cpy) = delete;
|
|
||||||
Raster(Raster&& m);
|
|
||||||
Raster& operator=(Raster&&);
|
|
||||||
~Raster();
|
|
||||||
|
|
||||||
/// Reallocated everything for the given resolution and pixel dimension.
|
|
||||||
void reset(const Resolution& r,
|
|
||||||
const PixelDim& pd,
|
|
||||||
const Trafo &tr = {});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Release the allocated resources. Drawing in this state ends in
|
|
||||||
* unspecified behavior.
|
|
||||||
*/
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
/// Get the resolution of the raster.
|
|
||||||
Resolution resolution() const;
|
|
||||||
PixelDim pixel_dimensions() const;
|
|
||||||
|
|
||||||
/// Clear the raster with black color.
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
/// Draw a polygon with holes.
|
|
||||||
void draw(const ExPolygon& poly);
|
|
||||||
void draw(const ClipperLib::Polygon& poly);
|
|
||||||
|
|
||||||
uint8_t read_pixel(size_t w, size_t h) const;
|
|
||||||
|
|
||||||
inline bool empty() const { return ! bool(m_impl); }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class PNGImage: public Raster::RawData {
|
|
||||||
public:
|
|
||||||
PNGImage& serialize(const Raster &raster) override;
|
|
||||||
std::string get_file_extension() const override { return "png"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class PPMImage: public Raster::RawData {
|
|
||||||
public:
|
|
||||||
PPMImage& serialize(const Raster &raster) override;
|
|
||||||
std::string get_file_extension() const override { return "ppm"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream &stream, const Raster::RawData &bytes);
|
|
||||||
|
|
||||||
} // sla
|
|
||||||
} // Slic3r
|
|
||||||
|
|
||||||
|
|
||||||
#endif // SLARASTER_HPP
|
|
89
src/libslic3r/SLA/RasterBase.cpp
Normal file
89
src/libslic3r/SLA/RasterBase.cpp
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#ifndef SLARASTER_CPP
|
||||||
|
#define SLARASTER_CPP
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <libslic3r/SLA/RasterBase.hpp>
|
||||||
|
#include <libslic3r/SLA/AGGRaster.hpp>
|
||||||
|
|
||||||
|
// minz image write:
|
||||||
|
#include <miniz.h>
|
||||||
|
|
||||||
|
namespace Slic3r { namespace sla {
|
||||||
|
|
||||||
|
const RasterBase::TMirroring RasterBase::NoMirror = {false, false};
|
||||||
|
const RasterBase::TMirroring RasterBase::MirrorX = {true, false};
|
||||||
|
const RasterBase::TMirroring RasterBase::MirrorY = {false, true};
|
||||||
|
const RasterBase::TMirroring RasterBase::MirrorXY = {true, true};
|
||||||
|
|
||||||
|
EncodedRaster PNGRasterEncoder::operator()(const void *ptr, size_t w, size_t h,
|
||||||
|
size_t num_components)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> buf;
|
||||||
|
size_t s = 0;
|
||||||
|
|
||||||
|
void *rawdata = tdefl_write_image_to_png_file_in_memory(
|
||||||
|
ptr, int(w), int(h), int(num_components), &s);
|
||||||
|
|
||||||
|
// On error, data() will return an empty vector. No other info can be
|
||||||
|
// retrieved from miniz anyway...
|
||||||
|
if (rawdata == nullptr) return EncodedRaster({}, "png");
|
||||||
|
|
||||||
|
auto pptr = static_cast<std::uint8_t*>(rawdata);
|
||||||
|
|
||||||
|
buf.reserve(s);
|
||||||
|
std::copy(pptr, pptr + s, std::back_inserter(buf));
|
||||||
|
|
||||||
|
MZ_FREE(rawdata);
|
||||||
|
return EncodedRaster(std::move(buf), "png");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &stream, const EncodedRaster &bytes)
|
||||||
|
{
|
||||||
|
stream.write(reinterpret_cast<const char *>(bytes.data()),
|
||||||
|
std::streamsize(bytes.size()));
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncodedRaster PPMRasterEncoder::operator()(const void *ptr, size_t w, size_t h,
|
||||||
|
size_t num_components)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> buf;
|
||||||
|
|
||||||
|
auto header = std::string("P5 ") +
|
||||||
|
std::to_string(w) + " " +
|
||||||
|
std::to_string(h) + " " + "255 ";
|
||||||
|
|
||||||
|
auto sz = w * h * num_components;
|
||||||
|
size_t s = sz + header.size();
|
||||||
|
|
||||||
|
buf.reserve(s);
|
||||||
|
|
||||||
|
auto buff = reinterpret_cast<const std::uint8_t*>(ptr);
|
||||||
|
std::copy(header.begin(), header.end(), std::back_inserter(buf));
|
||||||
|
std::copy(buff, buff+sz, std::back_inserter(buf));
|
||||||
|
|
||||||
|
return EncodedRaster(std::move(buf), "ppm");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<RasterBase> create_raster_grayscale_aa(
|
||||||
|
const RasterBase::Resolution &res,
|
||||||
|
const RasterBase::PixelDim & pxdim,
|
||||||
|
double gamma,
|
||||||
|
const RasterBase::Trafo & tr)
|
||||||
|
{
|
||||||
|
std::unique_ptr<RasterBase> rst;
|
||||||
|
|
||||||
|
if (gamma > 0)
|
||||||
|
rst = std::make_unique<RasterGrayscaleAAGammaPower>(res, pxdim, tr, gamma);
|
||||||
|
else
|
||||||
|
rst = std::make_unique<RasterGrayscaleAA>(res, pxdim, tr, agg::gamma_threshold(.5));
|
||||||
|
|
||||||
|
return rst;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sla
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // SLARASTER_CPP
|
124
src/libslic3r/SLA/RasterBase.hpp
Normal file
124
src/libslic3r/SLA/RasterBase.hpp
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
#ifndef SLA_RASTERBASE_HPP
|
||||||
|
#define SLA_RASTERBASE_HPP
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <array>
|
||||||
|
#include <utility>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <libslic3r/ExPolygon.hpp>
|
||||||
|
#include <libslic3r/SLA/Concurrency.hpp>
|
||||||
|
|
||||||
|
namespace ClipperLib { struct Polygon; }
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
template<class T> using uqptr = std::unique_ptr<T>;
|
||||||
|
template<class T> using shptr = std::shared_ptr<T>;
|
||||||
|
template<class T> using wkptr = std::weak_ptr<T>;
|
||||||
|
|
||||||
|
namespace sla {
|
||||||
|
|
||||||
|
// Raw byte buffer paired with its size. Suitable for compressed image data.
|
||||||
|
class EncodedRaster {
|
||||||
|
protected:
|
||||||
|
std::vector<uint8_t> m_buffer;
|
||||||
|
std::string m_ext;
|
||||||
|
public:
|
||||||
|
EncodedRaster() = default;
|
||||||
|
explicit EncodedRaster(std::vector<uint8_t> &&buf, std::string ext)
|
||||||
|
: m_buffer(std::move(buf)), m_ext(std::move(ext))
|
||||||
|
{}
|
||||||
|
|
||||||
|
size_t size() const { return m_buffer.size(); }
|
||||||
|
const void * data() const { return m_buffer.data(); }
|
||||||
|
const char * extension() const { return m_ext.c_str(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
using RasterEncoder =
|
||||||
|
std::function<EncodedRaster(const void *ptr, size_t w, size_t h, size_t num_components)>;
|
||||||
|
|
||||||
|
class RasterBase {
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Orientation { roLandscape, roPortrait };
|
||||||
|
|
||||||
|
using TMirroring = std::array<bool, 2>;
|
||||||
|
static const TMirroring NoMirror;
|
||||||
|
static const TMirroring MirrorX;
|
||||||
|
static const TMirroring MirrorY;
|
||||||
|
static const TMirroring MirrorXY;
|
||||||
|
|
||||||
|
struct Trafo {
|
||||||
|
bool mirror_x = false, mirror_y = false, flipXY = false;
|
||||||
|
coord_t center_x = 0, center_y = 0;
|
||||||
|
|
||||||
|
// Portrait orientation will make sure the drawed polygons are rotated
|
||||||
|
// by 90 degrees.
|
||||||
|
Trafo(Orientation o = roLandscape, const TMirroring &mirror = NoMirror)
|
||||||
|
// XY flipping implicitly does an X mirror
|
||||||
|
: mirror_x(o == roPortrait ? !mirror[0] : mirror[0])
|
||||||
|
, mirror_y(!mirror[1]) // Makes raster origin to be top left corner
|
||||||
|
, flipXY(o == roPortrait)
|
||||||
|
{}
|
||||||
|
|
||||||
|
TMirroring get_mirror() const { return { (roPortrait ? !mirror_x : mirror_x), mirror_y}; }
|
||||||
|
Orientation get_orientation() const { return flipXY ? roPortrait : roLandscape; }
|
||||||
|
Point get_center() const { return {center_x, center_y}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Type that represents a resolution in pixels.
|
||||||
|
struct Resolution {
|
||||||
|
size_t width_px = 0;
|
||||||
|
size_t height_px = 0;
|
||||||
|
|
||||||
|
Resolution(size_t w = 0, size_t h = 0) : width_px(w), height_px(h) {}
|
||||||
|
size_t pixels() const { return width_px * height_px; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Types that represents the dimension of a pixel in millimeters.
|
||||||
|
struct PixelDim {
|
||||||
|
double w_mm = 0.;
|
||||||
|
double h_mm = 0.;
|
||||||
|
|
||||||
|
PixelDim(double px_width_mm = 0.0, double px_height_mm = 0.0)
|
||||||
|
: w_mm(px_width_mm), h_mm(px_height_mm)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~RasterBase() = default;
|
||||||
|
|
||||||
|
/// Draw a polygon with holes.
|
||||||
|
virtual void draw(const ExPolygon& poly) = 0;
|
||||||
|
virtual void draw(const ClipperLib::Polygon& poly) = 0;
|
||||||
|
|
||||||
|
/// Get the resolution of the raster.
|
||||||
|
virtual Resolution resolution() const = 0;
|
||||||
|
virtual PixelDim pixel_dimensions() const = 0;
|
||||||
|
virtual Trafo trafo() const = 0;
|
||||||
|
|
||||||
|
virtual EncodedRaster encode(RasterEncoder encoder) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PNGRasterEncoder {
|
||||||
|
EncodedRaster operator()(const void *ptr, size_t w, size_t h, size_t num_components);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PPMRasterEncoder {
|
||||||
|
EncodedRaster operator()(const void *ptr, size_t w, size_t h, size_t num_components);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream &stream, const EncodedRaster &bytes);
|
||||||
|
|
||||||
|
// If gamma is zero, thresholding will be performed which disables AA.
|
||||||
|
uqptr<RasterBase> create_raster_grayscale_aa(
|
||||||
|
const RasterBase::Resolution &res,
|
||||||
|
const RasterBase::PixelDim & pxdim,
|
||||||
|
double gamma = 1.0,
|
||||||
|
const RasterBase::Trafo & tr = {});
|
||||||
|
|
||||||
|
}} // namespace Slic3r::sla
|
||||||
|
|
||||||
|
#endif // SLARASTERBASE_HPP
|
91
src/libslic3r/SLA/RasterToPolygons.cpp
Normal file
91
src/libslic3r/SLA/RasterToPolygons.cpp
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#include "RasterToPolygons.hpp"
|
||||||
|
|
||||||
|
#include "AGGRaster.hpp"
|
||||||
|
#include "libslic3r/MarchingSquares.hpp"
|
||||||
|
#include "MTUtils.hpp"
|
||||||
|
#include "ClipperUtils.hpp"
|
||||||
|
|
||||||
|
namespace marchsq {
|
||||||
|
|
||||||
|
// Specialize this struct to register a raster type for the Marching squares alg
|
||||||
|
template<> struct _RasterTraits<Slic3r::sla::RasterGrayscaleAA> {
|
||||||
|
using Rst = Slic3r::sla::RasterGrayscaleAA;
|
||||||
|
|
||||||
|
// The type of pixel cell in the raster
|
||||||
|
using ValueType = uint8_t;
|
||||||
|
|
||||||
|
// Value at a given position
|
||||||
|
static uint8_t get(const Rst &rst, size_t row, size_t col) { return rst.read_pixel(col, row); }
|
||||||
|
|
||||||
|
// Number of rows and cols of the raster
|
||||||
|
static size_t rows(const Rst &rst) { return rst.resolution().height_px; }
|
||||||
|
static size_t cols(const Rst &rst) { return rst.resolution().width_px; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Slic3r::marchsq
|
||||||
|
|
||||||
|
namespace Slic3r { namespace sla {
|
||||||
|
|
||||||
|
template<class Fn> void foreach_vertex(ExPolygon &poly, Fn &&fn)
|
||||||
|
{
|
||||||
|
for (auto &p : poly.contour.points) fn(p);
|
||||||
|
for (auto &h : poly.holes)
|
||||||
|
for (auto &p : h.points) fn(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExPolygons raster_to_polygons(const RasterGrayscaleAA &rst, Vec2i windowsize)
|
||||||
|
{
|
||||||
|
size_t rows = rst.resolution().height_px, cols = rst.resolution().width_px;
|
||||||
|
|
||||||
|
if (rows < 2 || cols < 2) return {};
|
||||||
|
|
||||||
|
Polygons polys;
|
||||||
|
long w_rows = std::max(2l, long(windowsize.y()));
|
||||||
|
long w_cols = std::max(2l, long(windowsize.x()));
|
||||||
|
|
||||||
|
std::vector<marchsq::Ring> rings =
|
||||||
|
marchsq::execute(rst, 128, {w_rows, w_cols});
|
||||||
|
|
||||||
|
polys.reserve(rings.size());
|
||||||
|
|
||||||
|
auto pxd = rst.pixel_dimensions();
|
||||||
|
pxd.w_mm = (rst.resolution().width_px * pxd.w_mm) / (rst.resolution().width_px - 1);
|
||||||
|
pxd.h_mm = (rst.resolution().height_px * pxd.h_mm) / (rst.resolution().height_px - 1);
|
||||||
|
|
||||||
|
for (const marchsq::Ring &ring : rings) {
|
||||||
|
Polygon poly; Points &pts = poly.points;
|
||||||
|
pts.reserve(ring.size());
|
||||||
|
|
||||||
|
for (const marchsq::Coord &crd : ring)
|
||||||
|
pts.emplace_back(scaled(crd.c * pxd.w_mm), scaled(crd.r * pxd.h_mm));
|
||||||
|
|
||||||
|
polys.emplace_back(poly);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reverse the raster transformations
|
||||||
|
ExPolygons unioned = union_ex(polys);
|
||||||
|
coord_t width = scaled(cols * pxd.h_mm), height = scaled(rows * pxd.w_mm);
|
||||||
|
|
||||||
|
auto tr = rst.trafo();
|
||||||
|
for (ExPolygon &expoly : unioned) {
|
||||||
|
if (tr.mirror_y)
|
||||||
|
foreach_vertex(expoly, [height](Point &p) {p.y() = height - p.y(); });
|
||||||
|
|
||||||
|
if (tr.mirror_x)
|
||||||
|
foreach_vertex(expoly, [width](Point &p) {p.x() = width - p.x(); });
|
||||||
|
|
||||||
|
expoly.translate(-tr.center_x, -tr.center_y);
|
||||||
|
|
||||||
|
if (tr.flipXY)
|
||||||
|
foreach_vertex(expoly, [](Point &p) { std::swap(p.x(), p.y()); });
|
||||||
|
|
||||||
|
if ((tr.mirror_x + tr.mirror_y + tr.flipXY) % 2) {
|
||||||
|
expoly.contour.reverse();
|
||||||
|
for (auto &h : expoly.holes) h.reverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return unioned;
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace Slic3r
|
15
src/libslic3r/SLA/RasterToPolygons.hpp
Normal file
15
src/libslic3r/SLA/RasterToPolygons.hpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef RASTERTOPOLYGONS_HPP
|
||||||
|
#define RASTERTOPOLYGONS_HPP
|
||||||
|
|
||||||
|
#include "libslic3r/ExPolygon.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
namespace sla {
|
||||||
|
|
||||||
|
class RasterGrayscaleAA;
|
||||||
|
|
||||||
|
ExPolygons raster_to_polygons(const RasterGrayscaleAA &rst, Vec2i windowsize = {2, 2});
|
||||||
|
|
||||||
|
}} // namespace Slic3r::sla
|
||||||
|
|
||||||
|
#endif // RASTERTOPOLYGONS_HPP
|
|
@ -1,151 +0,0 @@
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
#include <libslic3r/SLA/RasterWriter.hpp>
|
|
||||||
|
|
||||||
#include "libslic3r/PrintConfig.hpp"
|
|
||||||
#include <libslic3r/Zipper.hpp>
|
|
||||||
#include <libslic3r/Time.hpp>
|
|
||||||
|
|
||||||
#include "ExPolygon.hpp"
|
|
||||||
#include <libnest2d/backends/clipper/clipper_polygon.hpp>
|
|
||||||
|
|
||||||
#include <boost/log/trivial.hpp>
|
|
||||||
#include <boost/filesystem/path.hpp>
|
|
||||||
|
|
||||||
namespace Slic3r { namespace sla {
|
|
||||||
|
|
||||||
void RasterWriter::write_ini(const std::map<std::string, std::string> &m, std::string &ini)
|
|
||||||
{
|
|
||||||
for (auto ¶m : m) ini += param.first + " = " + param.second + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string RasterWriter::create_ini_content(const std::string& projectname) const
|
|
||||||
{
|
|
||||||
std::string out("action = print\njobDir = ");
|
|
||||||
out += projectname + "\n";
|
|
||||||
write_ini(m_config, out);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
RasterWriter::RasterWriter(const Raster::Resolution &res,
|
|
||||||
const Raster::PixelDim & pixdim,
|
|
||||||
const Raster::Trafo & trafo,
|
|
||||||
double gamma)
|
|
||||||
: m_res(res), m_pxdim(pixdim), m_trafo(trafo), m_gamma(gamma)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void RasterWriter::save(const std::string &fpath, const std::string &prjname)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
Zipper zipper(fpath); // zipper with no compression
|
|
||||||
save(zipper, prjname);
|
|
||||||
zipper.finalize();
|
|
||||||
} catch(std::exception& e) {
|
|
||||||
BOOST_LOG_TRIVIAL(error) << e.what();
|
|
||||||
// Rethrow the exception
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RasterWriter::save(Zipper &zipper, const std::string &prjname)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
std::string project =
|
|
||||||
prjname.empty() ?
|
|
||||||
boost::filesystem::path(zipper.get_filename()).stem().string() :
|
|
||||||
prjname;
|
|
||||||
|
|
||||||
zipper.add_entry("config.ini");
|
|
||||||
|
|
||||||
zipper << create_ini_content(project);
|
|
||||||
|
|
||||||
zipper.add_entry("prusaslicer.ini");
|
|
||||||
std::string prusaslicer_ini;
|
|
||||||
write_ini(m_slicer_config, prusaslicer_ini);
|
|
||||||
zipper << prusaslicer_ini;
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < m_layers_rst.size(); i++)
|
|
||||||
{
|
|
||||||
if(m_layers_rst[i].rawbytes.size() > 0) {
|
|
||||||
char lyrnum[6];
|
|
||||||
std::sprintf(lyrnum, "%.5d", i);
|
|
||||||
auto zfilename = project + lyrnum + ".png";
|
|
||||||
|
|
||||||
// Add binary entry to the zipper
|
|
||||||
zipper.add_entry(zfilename,
|
|
||||||
m_layers_rst[i].rawbytes.data(),
|
|
||||||
m_layers_rst[i].rawbytes.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(std::exception& e) {
|
|
||||||
BOOST_LOG_TRIVIAL(error) << e.what();
|
|
||||||
// Rethrow the exception
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
std::string get_cfg_value(const DynamicPrintConfig &cfg, const std::string &key)
|
|
||||||
{
|
|
||||||
std::string ret;
|
|
||||||
|
|
||||||
if (cfg.has(key)) {
|
|
||||||
auto opt = cfg.option(key);
|
|
||||||
if (opt) ret = opt->serialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void append_full_config(const DynamicPrintConfig &cfg, std::map<std::string, std::string> &keys)
|
|
||||||
{
|
|
||||||
using namespace std::literals::string_view_literals;
|
|
||||||
|
|
||||||
// Sorted list of config keys, which shall not be stored into the ini.
|
|
||||||
static constexpr auto banned_keys = {
|
|
||||||
"compatible_printers"sv,
|
|
||||||
"compatible_prints"sv,
|
|
||||||
"print_host"sv,
|
|
||||||
"printhost_apikey"sv,
|
|
||||||
"printhost_cafile"sv
|
|
||||||
};
|
|
||||||
|
|
||||||
assert(std::is_sorted(banned_keys.begin(), banned_keys.end()));
|
|
||||||
auto is_banned = [](const std::string &key) {
|
|
||||||
return std::binary_search(banned_keys.begin(), banned_keys.end(), key);
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const std::string &key : cfg.keys())
|
|
||||||
if (! is_banned(key) && ! cfg.option(key)->is_nil())
|
|
||||||
keys[key] = cfg.opt_serialize(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void RasterWriter::set_config(const DynamicPrintConfig &cfg)
|
|
||||||
{
|
|
||||||
m_config["layerHeight"] = get_cfg_value(cfg, "layer_height");
|
|
||||||
m_config["expTime"] = get_cfg_value(cfg, "exposure_time");
|
|
||||||
m_config["expTimeFirst"] = get_cfg_value(cfg, "initial_exposure_time");
|
|
||||||
m_config["materialName"] = get_cfg_value(cfg, "sla_material_settings_id");
|
|
||||||
m_config["printerModel"] = get_cfg_value(cfg, "printer_model");
|
|
||||||
m_config["printerVariant"] = get_cfg_value(cfg, "printer_variant");
|
|
||||||
m_config["printerProfile"] = get_cfg_value(cfg, "printer_settings_id");
|
|
||||||
m_config["printProfile"] = get_cfg_value(cfg, "sla_print_settings_id");
|
|
||||||
m_config["fileCreationTimestamp"] = Utils::utc_timestamp();
|
|
||||||
m_config["prusaSlicerVersion"] = SLIC3R_BUILD_ID;
|
|
||||||
append_full_config(cfg, m_slicer_config);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RasterWriter::set_statistics(const PrintStatistics &stats)
|
|
||||||
{
|
|
||||||
m_config["usedMaterial"] = std::to_string(stats.used_material);
|
|
||||||
m_config["numFade"] = std::to_string(stats.num_fade);
|
|
||||||
m_config["numSlow"] = std::to_string(stats.num_slow);
|
|
||||||
m_config["numFast"] = std::to_string(stats.num_fast);
|
|
||||||
m_config["printTime"] = std::to_string(stats.estimated_print_time_s);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sla
|
|
||||||
} // namespace Slic3r
|
|
|
@ -1,130 +0,0 @@
|
||||||
#ifndef SLA_RASTERWRITER_HPP
|
|
||||||
#define SLA_RASTERWRITER_HPP
|
|
||||||
|
|
||||||
// For png export of the sliced model
|
|
||||||
#include <fstream>
|
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#include <libslic3r/SLA/Raster.hpp>
|
|
||||||
#include <libslic3r/Zipper.hpp>
|
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
|
|
||||||
class DynamicPrintConfig;
|
|
||||||
|
|
||||||
namespace sla {
|
|
||||||
|
|
||||||
// API to write the zipped sla output layers and metadata.
|
|
||||||
// Implementation uses PNG raster output.
|
|
||||||
// Be aware that if a large number of layers are allocated, it can very well
|
|
||||||
// exhaust the available memory especially on 32 bit platform.
|
|
||||||
// This class is designed to be used in parallel mode. Layers have an ID and
|
|
||||||
// each layer can be written and compressed independently (in parallel).
|
|
||||||
// At the end when all layers where written, the save method can be used to
|
|
||||||
// write out the result into a zipped archive.
|
|
||||||
class RasterWriter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
// Used for addressing parameters of set_statistics()
|
|
||||||
struct PrintStatistics
|
|
||||||
{
|
|
||||||
double used_material = 0.;
|
|
||||||
double estimated_print_time_s = 0.;
|
|
||||||
size_t num_fade = 0;
|
|
||||||
size_t num_slow = 0;
|
|
||||||
size_t num_fast = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
// A struct to bind the raster image data and its compressed bytes together.
|
|
||||||
struct Layer {
|
|
||||||
Raster raster;
|
|
||||||
PNGImage rawbytes;
|
|
||||||
|
|
||||||
Layer() = default;
|
|
||||||
|
|
||||||
// The image is big, do not copy by accident
|
|
||||||
Layer(const Layer&) = delete;
|
|
||||||
Layer& operator=(const Layer&) = delete;
|
|
||||||
|
|
||||||
Layer(Layer &&m) = default;
|
|
||||||
Layer &operator=(Layer &&) = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
// We will save the compressed PNG data into RawBytes type buffers in
|
|
||||||
// parallel. Later we can write every layer to the disk sequentially.
|
|
||||||
std::vector<Layer> m_layers_rst;
|
|
||||||
Raster::Resolution m_res;
|
|
||||||
Raster::PixelDim m_pxdim;
|
|
||||||
Raster::Trafo m_trafo;
|
|
||||||
double m_gamma;
|
|
||||||
|
|
||||||
std::map<std::string, std::string> m_config;
|
|
||||||
std::map<std::string, std::string> m_slicer_config;
|
|
||||||
|
|
||||||
static void write_ini(const std::map<std::string, std::string> &m, std::string &ini);
|
|
||||||
std::string create_ini_content(const std::string& projectname) const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// SLARasterWriter is using Raster in custom mirroring mode
|
|
||||||
RasterWriter(const Raster::Resolution &res,
|
|
||||||
const Raster::PixelDim & pixdim,
|
|
||||||
const Raster::Trafo & trafo,
|
|
||||||
double gamma = 1.);
|
|
||||||
|
|
||||||
RasterWriter(const RasterWriter& ) = delete;
|
|
||||||
RasterWriter& operator=(const RasterWriter&) = delete;
|
|
||||||
RasterWriter(RasterWriter&& m) = default;
|
|
||||||
RasterWriter& operator=(RasterWriter&&) = default;
|
|
||||||
|
|
||||||
inline void layers(unsigned cnt) { if(cnt > 0) m_layers_rst.resize(cnt); }
|
|
||||||
inline unsigned layers() const { return unsigned(m_layers_rst.size()); }
|
|
||||||
|
|
||||||
template<class Poly> void draw_polygon(const Poly& p, unsigned lyr)
|
|
||||||
{
|
|
||||||
assert(lyr < m_layers_rst.size());
|
|
||||||
m_layers_rst[lyr].raster.draw(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void begin_layer(unsigned lyr) {
|
|
||||||
if(m_layers_rst.size() <= lyr) m_layers_rst.resize(lyr+1);
|
|
||||||
m_layers_rst[lyr].raster.reset(m_res, m_pxdim, m_trafo);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void begin_layer() {
|
|
||||||
m_layers_rst.emplace_back();
|
|
||||||
m_layers_rst.front().raster.reset(m_res, m_pxdim, m_trafo);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void finish_layer(unsigned lyr_id) {
|
|
||||||
assert(lyr_id < m_layers_rst.size());
|
|
||||||
m_layers_rst[lyr_id].rawbytes.serialize(m_layers_rst[lyr_id].raster);
|
|
||||||
m_layers_rst[lyr_id].raster.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void finish_layer() {
|
|
||||||
if(!m_layers_rst.empty()) {
|
|
||||||
m_layers_rst.back().rawbytes.serialize(m_layers_rst.back().raster);
|
|
||||||
m_layers_rst.back().raster.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void save(const std::string &fpath, const std::string &prjname = "");
|
|
||||||
void save(Zipper &zipper, const std::string &prjname = "");
|
|
||||||
|
|
||||||
void set_statistics(const PrintStatistics &statistics);
|
|
||||||
|
|
||||||
void set_config(const DynamicPrintConfig &cfg);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace sla
|
|
||||||
} // namespace Slic3r
|
|
||||||
|
|
||||||
#endif // SLARASTERWRITER_HPP
|
|
|
@ -228,6 +228,8 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
|
||||||
// Handle changes to object config defaults
|
// Handle changes to object config defaults
|
||||||
m_default_object_config.apply_only(config, object_diff, true);
|
m_default_object_config.apply_only(config, object_diff, true);
|
||||||
|
|
||||||
|
if (m_printer) m_printer->apply(m_printer_config);
|
||||||
|
|
||||||
struct ModelObjectStatus {
|
struct ModelObjectStatus {
|
||||||
enum Status {
|
enum Status {
|
||||||
Unknown,
|
Unknown,
|
||||||
|
@ -482,7 +484,6 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_objects.empty()) {
|
if(m_objects.empty()) {
|
||||||
m_printer.reset();
|
|
||||||
m_printer_input = {};
|
m_printer_input = {};
|
||||||
m_print_statistics = {};
|
m_print_statistics = {};
|
||||||
}
|
}
|
||||||
|
@ -657,6 +658,12 @@ std::string SLAPrint::validate() const
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SLAPrint::set_printer(SLAPrinter *arch)
|
||||||
|
{
|
||||||
|
invalidate_step(slapsRasterize);
|
||||||
|
m_printer = arch;
|
||||||
|
}
|
||||||
|
|
||||||
bool SLAPrint::invalidate_step(SLAPrintStep step)
|
bool SLAPrint::invalidate_step(SLAPrintStep step)
|
||||||
{
|
{
|
||||||
bool invalidated = Inherited::invalidate_step(step);
|
bool invalidated = Inherited::invalidate_step(step);
|
||||||
|
@ -676,7 +683,7 @@ void SLAPrint::process()
|
||||||
// Assumption: at this point the print objects should be populated only with
|
// Assumption: at this point the print objects should be populated only with
|
||||||
// the model objects we have to process and the instances are also filtered
|
// the model objects we have to process and the instances are also filtered
|
||||||
|
|
||||||
Steps printsteps{this};
|
Steps printsteps(this);
|
||||||
|
|
||||||
// We want to first process all objects...
|
// We want to first process all objects...
|
||||||
std::vector<SLAPrintObjectStep> level1_obj_steps = {
|
std::vector<SLAPrintObjectStep> level1_obj_steps = {
|
||||||
|
@ -855,36 +862,6 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt
|
||||||
return invalidated;
|
return invalidated;
|
||||||
}
|
}
|
||||||
|
|
||||||
sla::RasterWriter & SLAPrint::init_printer()
|
|
||||||
{
|
|
||||||
sla::Raster::Resolution res;
|
|
||||||
sla::Raster::PixelDim pxdim;
|
|
||||||
std::array<bool, 2> mirror;
|
|
||||||
|
|
||||||
double w = m_printer_config.display_width.getFloat();
|
|
||||||
double h = m_printer_config.display_height.getFloat();
|
|
||||||
auto pw = size_t(m_printer_config.display_pixels_x.getInt());
|
|
||||||
auto ph = size_t(m_printer_config.display_pixels_y.getInt());
|
|
||||||
|
|
||||||
mirror[X] = m_printer_config.display_mirror_x.getBool();
|
|
||||||
mirror[Y] = m_printer_config.display_mirror_y.getBool();
|
|
||||||
|
|
||||||
auto orientation = get_printer_orientation();
|
|
||||||
if (orientation == sla::Raster::roPortrait) {
|
|
||||||
std::swap(w, h);
|
|
||||||
std::swap(pw, ph);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = sla::Raster::Resolution{pw, ph};
|
|
||||||
pxdim = sla::Raster::PixelDim{w / pw, h / ph};
|
|
||||||
sla::Raster::Trafo tr{orientation, mirror};
|
|
||||||
tr.gamma = m_printer_config.gamma_correction.getFloat();
|
|
||||||
|
|
||||||
m_printer.reset(new sla::RasterWriter(res, pxdim, tr));
|
|
||||||
m_printer->set_config(m_full_print_config);
|
|
||||||
return *m_printer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if an object step is done on all objects and there's at least one object.
|
// Returns true if an object step is done on all objects and there's at least one object.
|
||||||
bool SLAPrint::is_step_done(SLAPrintObjectStep step) const
|
bool SLAPrint::is_step_done(SLAPrintObjectStep step) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include "PrintBase.hpp"
|
#include "PrintBase.hpp"
|
||||||
#include "SLA/RasterWriter.hpp"
|
#include "SLA/RasterBase.hpp"
|
||||||
#include "SLA/SupportTree.hpp"
|
#include "SLA/SupportTree.hpp"
|
||||||
#include "Point.hpp"
|
#include "Point.hpp"
|
||||||
#include "MTUtils.hpp"
|
#include "MTUtils.hpp"
|
||||||
|
@ -369,6 +369,31 @@ struct SLAPrintStatistics
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SLAPrinter {
|
||||||
|
protected:
|
||||||
|
std::vector<sla::EncodedRaster> m_layers;
|
||||||
|
|
||||||
|
virtual uqptr<sla::RasterBase> create_raster() const = 0;
|
||||||
|
virtual sla::EncodedRaster encode_raster(const sla::RasterBase &rst) const = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~SLAPrinter() = default;
|
||||||
|
|
||||||
|
virtual void apply(const SLAPrinterConfig &cfg) = 0;
|
||||||
|
|
||||||
|
// Fn have to be thread safe: void(sla::RasterBase& raster, size_t lyrid);
|
||||||
|
template<class Fn> void draw_layers(size_t layer_num, Fn &&drawfn)
|
||||||
|
{
|
||||||
|
m_layers.resize(layer_num);
|
||||||
|
sla::ccr::enumerate(m_layers.begin(), m_layers.end(),
|
||||||
|
[this, &drawfn](sla::EncodedRaster& enc, size_t idx) {
|
||||||
|
auto rst = create_raster();
|
||||||
|
drawfn(*rst, idx);
|
||||||
|
enc = encode_raster(*rst);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This class is the high level FSM for the SLA printing process.
|
* @brief This class is the high level FSM for the SLA printing process.
|
||||||
*
|
*
|
||||||
|
@ -403,18 +428,6 @@ public:
|
||||||
// Returns true if the last step was finished with success.
|
// Returns true if the last step was finished with success.
|
||||||
bool finished() const override { return this->is_step_done(slaposSliceSupports) && this->Inherited::is_step_done(slapsRasterize); }
|
bool finished() const override { return this->is_step_done(slaposSliceSupports) && this->Inherited::is_step_done(slapsRasterize); }
|
||||||
|
|
||||||
inline void export_raster(const std::string& fpath,
|
|
||||||
const std::string& projectname = "")
|
|
||||||
{
|
|
||||||
if(m_printer) m_printer->save(fpath, projectname);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void export_raster(Zipper &zipper,
|
|
||||||
const std::string& projectname = "")
|
|
||||||
{
|
|
||||||
if(m_printer) m_printer->save(zipper, projectname);
|
|
||||||
}
|
|
||||||
|
|
||||||
const PrintObjects& objects() const { return m_objects; }
|
const PrintObjects& objects() const { return m_objects; }
|
||||||
|
|
||||||
const SLAPrintConfig& print_config() const { return m_print_config; }
|
const SLAPrintConfig& print_config() const { return m_print_config; }
|
||||||
|
@ -445,7 +458,8 @@ public:
|
||||||
|
|
||||||
std::vector<ClipperLib::Polygon> m_transformed_slices;
|
std::vector<ClipperLib::Polygon> m_transformed_slices;
|
||||||
|
|
||||||
template<class Container> void transformed_slices(Container&& c) {
|
template<class Container> void transformed_slices(Container&& c)
|
||||||
|
{
|
||||||
m_transformed_slices = std::forward<Container>(c);
|
m_transformed_slices = std::forward<Container>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,7 +489,10 @@ public:
|
||||||
// TODO: use this structure for the preview in the future.
|
// TODO: use this structure for the preview in the future.
|
||||||
const std::vector<PrintLayer>& print_layers() const { return m_printer_input; }
|
const std::vector<PrintLayer>& print_layers() const { return m_printer_input; }
|
||||||
|
|
||||||
|
void set_printer(SLAPrinter *archiver);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Implement same logic as in SLAPrintObject
|
// Implement same logic as in SLAPrintObject
|
||||||
bool invalidate_step(SLAPrintStep st);
|
bool invalidate_step(SLAPrintStep st);
|
||||||
|
|
||||||
|
@ -493,8 +510,8 @@ private:
|
||||||
// Ready-made data for rasterization.
|
// Ready-made data for rasterization.
|
||||||
std::vector<PrintLayer> m_printer_input;
|
std::vector<PrintLayer> m_printer_input;
|
||||||
|
|
||||||
// The printer itself
|
// The archive object which collects the raster images after slicing
|
||||||
std::unique_ptr<sla::RasterWriter> m_printer;
|
SLAPrinter *m_printer = nullptr;
|
||||||
|
|
||||||
// Estimated print time, material consumed.
|
// Estimated print time, material consumed.
|
||||||
SLAPrintStatistics m_print_statistics;
|
SLAPrintStatistics m_print_statistics;
|
||||||
|
@ -513,15 +530,6 @@ private:
|
||||||
double status() const { return m_st; }
|
double status() const { return m_st; }
|
||||||
} m_report_status;
|
} m_report_status;
|
||||||
|
|
||||||
sla::RasterWriter &init_printer();
|
|
||||||
|
|
||||||
inline sla::Raster::Orientation get_printer_orientation() const
|
|
||||||
{
|
|
||||||
auto ro = m_printer_config.display_orientation.getInt();
|
|
||||||
return ro == sla::Raster::roPortrait ? sla::Raster::roPortrait :
|
|
||||||
sla::Raster::roLandscape;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend SLAPrintObject;
|
friend SLAPrintObject;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -816,16 +816,7 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
|
||||||
// Rasterizing the model objects, and their supports
|
// Rasterizing the model objects, and their supports
|
||||||
void SLAPrint::Steps::rasterize()
|
void SLAPrint::Steps::rasterize()
|
||||||
{
|
{
|
||||||
if(canceled()) return;
|
if(canceled() || !m_print->m_printer) return;
|
||||||
|
|
||||||
auto &print_statistics = m_print->m_print_statistics;
|
|
||||||
auto &printer_input = m_print->m_printer_input;
|
|
||||||
|
|
||||||
// Set up the printer, allocate space for all the layers
|
|
||||||
sla::RasterWriter &printer = m_print->init_printer();
|
|
||||||
|
|
||||||
auto lvlcnt = unsigned(printer_input.size());
|
|
||||||
printer.layers(lvlcnt);
|
|
||||||
|
|
||||||
// coefficient to map the rasterization state (0-99) to the allocated
|
// coefficient to map the rasterization state (0-99) to the allocated
|
||||||
// portion (slot) of the process state
|
// portion (slot) of the process state
|
||||||
|
@ -837,7 +828,7 @@ void SLAPrint::Steps::rasterize()
|
||||||
// pst: previous state
|
// pst: previous state
|
||||||
double pst = current_status();
|
double pst = current_status();
|
||||||
|
|
||||||
double increment = (slot * sd) / printer_input.size();
|
double increment = (slot * sd) / m_print->m_printer_input.size();
|
||||||
double dstatus = current_status();
|
double dstatus = current_status();
|
||||||
|
|
||||||
sla::ccr::SpinningMutex slck;
|
sla::ccr::SpinningMutex slck;
|
||||||
|
@ -845,20 +836,14 @@ void SLAPrint::Steps::rasterize()
|
||||||
|
|
||||||
// procedure to process one height level. This will run in parallel
|
// procedure to process one height level. This will run in parallel
|
||||||
auto lvlfn =
|
auto lvlfn =
|
||||||
[this, &slck, &printer, increment, &dstatus, &pst]
|
[this, &slck, increment, &dstatus, &pst]
|
||||||
(PrintLayer& printlayer, size_t idx)
|
(sla::RasterBase& raster, size_t idx)
|
||||||
{
|
{
|
||||||
|
PrintLayer& printlayer = m_print->m_printer_input[idx];
|
||||||
if(canceled()) return;
|
if(canceled()) return;
|
||||||
auto level_id = unsigned(idx);
|
|
||||||
|
|
||||||
// Switch to the appropriate layer in the printer
|
|
||||||
printer.begin_layer(level_id);
|
|
||||||
|
|
||||||
for (const ClipperLib::Polygon& poly : printlayer.transformed_slices())
|
for (const ClipperLib::Polygon& poly : printlayer.transformed_slices())
|
||||||
printer.draw_polygon(poly, level_id);
|
raster.draw(poly);
|
||||||
|
|
||||||
// Finish the layer for later saving it.
|
|
||||||
printer.finish_layer(level_id);
|
|
||||||
|
|
||||||
// Status indication guarded with the spinlock
|
// Status indication guarded with the spinlock
|
||||||
{
|
{
|
||||||
|
@ -875,24 +860,8 @@ void SLAPrint::Steps::rasterize()
|
||||||
// last minute escape
|
// last minute escape
|
||||||
if(canceled()) return;
|
if(canceled()) return;
|
||||||
|
|
||||||
// Sequential version (for testing)
|
|
||||||
// for(unsigned l = 0; l < lvlcnt; ++l) lvlfn(l);
|
|
||||||
|
|
||||||
// Print all the layers in parallel
|
// Print all the layers in parallel
|
||||||
sla::ccr::enumerate(printer_input.begin(), printer_input.end(), lvlfn);
|
m_print->m_printer->draw_layers(m_print->m_printer_input.size(), lvlfn);
|
||||||
|
|
||||||
// Set statistics values to the printer
|
|
||||||
sla::RasterWriter::PrintStatistics stats;
|
|
||||||
stats.used_material = (print_statistics.objects_used_material +
|
|
||||||
print_statistics.support_used_material) / 1000;
|
|
||||||
|
|
||||||
int num_fade = m_print->m_default_object_config.faded_layers.getInt();
|
|
||||||
stats.num_fade = num_fade >= 0 ? size_t(num_fade) : size_t(0);
|
|
||||||
stats.num_fast = print_statistics.fast_layers_count;
|
|
||||||
stats.num_slow = print_statistics.slow_layers_count;
|
|
||||||
stats.estimated_print_time_s = print_statistics.estimated_print_time;
|
|
||||||
|
|
||||||
printer.set_statistics(stats);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SLAPrint::Steps::label(SLAPrintObjectStep step)
|
std::string SLAPrint::Steps::label(SLAPrintObjectStep step)
|
||||||
|
|
|
@ -46,7 +46,7 @@ private:
|
||||||
void apply_printer_corrections(SLAPrintObject &po, SliceOrigin o);
|
void apply_printer_corrections(SLAPrintObject &po, SliceOrigin o);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Steps(SLAPrint *print);
|
explicit Steps(SLAPrint *print);
|
||||||
|
|
||||||
void hollow_model(SLAPrintObject &po);
|
void hollow_model(SLAPrintObject &po);
|
||||||
void drill_holes (SLAPrintObject &po);
|
void drill_holes (SLAPrintObject &po);
|
||||||
|
|
|
@ -38,11 +38,12 @@ std::vector<std::pair<size_t, bool>> chain_segments_closest_point(std::vector<En
|
||||||
// Ignore the starting point as the starting point is considered to be occupied, no end point coud connect to it.
|
// Ignore the starting point as the starting point is considered to be occupied, no end point coud connect to it.
|
||||||
size_t next_idx = find_closest_point(kdtree, this_point.pos,
|
size_t next_idx = find_closest_point(kdtree, this_point.pos,
|
||||||
[this_idx, &end_points, &could_reverse_func](size_t idx) {
|
[this_idx, &end_points, &could_reverse_func](size_t idx) {
|
||||||
return (idx ^ this_idx) > 1 && end_points[idx].chain_id == 0 && ((idx ^ 1) == 0 || could_reverse_func(idx >> 1));
|
return (idx ^ this_idx) > 1 && end_points[idx].chain_id == 0 && ((idx & 1) == 0 || could_reverse_func(idx >> 1));
|
||||||
});
|
});
|
||||||
assert(next_idx < end_points.size());
|
assert(next_idx < end_points.size());
|
||||||
EndPointType &end_point = end_points[next_idx];
|
EndPointType &end_point = end_points[next_idx];
|
||||||
end_point.chain_id = 1;
|
end_point.chain_id = 1;
|
||||||
|
assert((next_idx & 1) == 0 || could_reverse_func(next_idx >> 1));
|
||||||
out.emplace_back(next_idx / 2, (next_idx & 1) != 0);
|
out.emplace_back(next_idx / 2, (next_idx & 1) != 0);
|
||||||
this_idx = next_idx ^ 1;
|
this_idx = next_idx ^ 1;
|
||||||
}
|
}
|
||||||
|
@ -165,7 +166,9 @@ std::vector<std::pair<size_t, bool>> chain_segments_greedy_constrained_reversals
|
||||||
EndPoint *first_point = nullptr;
|
EndPoint *first_point = nullptr;
|
||||||
size_t first_point_idx = std::numeric_limits<size_t>::max();
|
size_t first_point_idx = std::numeric_limits<size_t>::max();
|
||||||
if (start_near != nullptr) {
|
if (start_near != nullptr) {
|
||||||
size_t idx = find_closest_point(kdtree, start_near->template cast<double>());
|
size_t idx = find_closest_point(kdtree, start_near->template cast<double>(),
|
||||||
|
// Don't start with a reverse segment, if flipping of the segment is not allowed.
|
||||||
|
[&could_reverse_func](size_t idx) { return (idx & 1) == 0 || could_reverse_func(idx >> 1); });
|
||||||
assert(idx < end_points.size());
|
assert(idx < end_points.size());
|
||||||
first_point = &end_points[idx];
|
first_point = &end_points[idx];
|
||||||
first_point->distance_out = 0.;
|
first_point->distance_out = 0.;
|
||||||
|
|
128
src/libslic3r/SlicesToTriangleMesh.cpp
Normal file
128
src/libslic3r/SlicesToTriangleMesh.cpp
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
|
||||||
|
#include "SlicesToTriangleMesh.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/MTUtils.hpp"
|
||||||
|
#include "libslic3r/SLA/Contour3D.hpp"
|
||||||
|
#include "libslic3r/ClipperUtils.hpp"
|
||||||
|
#include "libslic3r/Tesselate.hpp"
|
||||||
|
|
||||||
|
#include <tbb/parallel_for.h>
|
||||||
|
#include <tbb/parallel_reduce.h>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
inline sla::Contour3D wall_strip(const Polygon &poly,
|
||||||
|
double lower_z_mm,
|
||||||
|
double upper_z_mm)
|
||||||
|
{
|
||||||
|
sla::Contour3D ret;
|
||||||
|
|
||||||
|
size_t startidx = ret.points.size();
|
||||||
|
size_t offs = poly.points.size();
|
||||||
|
|
||||||
|
ret.points.reserve(ret.points.size() + 2 *offs);
|
||||||
|
|
||||||
|
for (const Point &p : poly.points)
|
||||||
|
ret.points.emplace_back(to_3d(unscaled(p), lower_z_mm));
|
||||||
|
|
||||||
|
for (const Point &p : poly.points)
|
||||||
|
ret.points.emplace_back(to_3d(unscaled(p), upper_z_mm));
|
||||||
|
|
||||||
|
for (size_t i = startidx + 1; i < startidx + offs; ++i) {
|
||||||
|
ret.faces3.emplace_back(i - 1, i, i + offs - 1);
|
||||||
|
ret.faces3.emplace_back(i, i + offs, i + offs - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.faces3.emplace_back(startidx + offs - 1, startidx, startidx + 2 * offs - 1);
|
||||||
|
ret.faces3.emplace_back(startidx, startidx + offs, startidx + 2 * offs - 1);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as walls() but with identical higher and lower polygons.
|
||||||
|
sla::Contour3D inline straight_walls(const Polygon &plate,
|
||||||
|
double lo_z,
|
||||||
|
double hi_z)
|
||||||
|
{
|
||||||
|
return wall_strip(plate, lo_z, hi_z);
|
||||||
|
}
|
||||||
|
|
||||||
|
sla::Contour3D inline straight_walls(const ExPolygon &plate,
|
||||||
|
double lo_z,
|
||||||
|
double hi_z)
|
||||||
|
{
|
||||||
|
sla::Contour3D ret;
|
||||||
|
ret.merge(straight_walls(plate.contour, lo_z, hi_z));
|
||||||
|
for (auto &h : plate.holes) ret.merge(straight_walls(h, lo_z, hi_z));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
sla::Contour3D inline straight_walls(const ExPolygons &slice,
|
||||||
|
double lo_z,
|
||||||
|
double hi_z)
|
||||||
|
{
|
||||||
|
sla::Contour3D ret;
|
||||||
|
for (const ExPolygon &poly : slice)
|
||||||
|
ret.merge(straight_walls(poly, lo_z, hi_z));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
sla::Contour3D slices_to_triangle_mesh(const std::vector<ExPolygons> &slices,
|
||||||
|
double zmin,
|
||||||
|
const std::vector<float> & grid)
|
||||||
|
{
|
||||||
|
assert(slices.size() == grid.size());
|
||||||
|
|
||||||
|
using Layers = std::vector<sla::Contour3D>;
|
||||||
|
std::vector<sla::Contour3D> layers(slices.size());
|
||||||
|
size_t len = slices.size() - 1;
|
||||||
|
|
||||||
|
tbb::parallel_for(size_t(0), len, [&slices, &layers, &grid](size_t i) {
|
||||||
|
const ExPolygons &upper = slices[i + 1];
|
||||||
|
const ExPolygons &lower = slices[i];
|
||||||
|
|
||||||
|
ExPolygons dff1 = diff_ex(lower, upper);
|
||||||
|
ExPolygons dff2 = diff_ex(upper, lower);
|
||||||
|
layers[i].merge(triangulate_expolygons_3d(dff1, grid[i], NORMALS_UP));
|
||||||
|
layers[i].merge(triangulate_expolygons_3d(dff2, grid[i], NORMALS_DOWN));
|
||||||
|
layers[i].merge(straight_walls(upper, grid[i], grid[i + 1]));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
sla::Contour3D ret = tbb::parallel_reduce(
|
||||||
|
tbb::blocked_range(layers.begin(), layers.end()),
|
||||||
|
sla::Contour3D{},
|
||||||
|
[](const tbb::blocked_range<Layers::iterator>& r, sla::Contour3D init) {
|
||||||
|
for(auto it = r.begin(); it != r.end(); ++it ) init.merge(*it);
|
||||||
|
return init;
|
||||||
|
},
|
||||||
|
[]( const sla::Contour3D &a, const sla::Contour3D &b ) {
|
||||||
|
sla::Contour3D res{a}; res.merge(b); return res;
|
||||||
|
});
|
||||||
|
|
||||||
|
ret.merge(triangulate_expolygons_3d(slices.front(), zmin, NORMALS_DOWN));
|
||||||
|
ret.merge(straight_walls(slices.front(), zmin, grid.front()));
|
||||||
|
ret.merge(triangulate_expolygons_3d(slices.back(), grid.back(), NORMALS_UP));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void slices_to_triangle_mesh(TriangleMesh & mesh,
|
||||||
|
const std::vector<ExPolygons> &slices,
|
||||||
|
double zmin,
|
||||||
|
double lh,
|
||||||
|
double ilh)
|
||||||
|
{
|
||||||
|
std::vector<sla::Contour3D> wall_meshes(slices.size());
|
||||||
|
std::vector<float> grid(slices.size(), zmin + ilh);
|
||||||
|
|
||||||
|
for (size_t i = 1; i < grid.size(); ++i) grid[i] = grid[i - 1] + lh;
|
||||||
|
|
||||||
|
sla::Contour3D cntr = slices_to_triangle_mesh(slices, zmin, grid);
|
||||||
|
mesh.merge(sla::to_triangle_mesh(cntr));
|
||||||
|
mesh.repaired = true;
|
||||||
|
mesh.require_shared_vertices();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
24
src/libslic3r/SlicesToTriangleMesh.hpp
Normal file
24
src/libslic3r/SlicesToTriangleMesh.hpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef SLICESTOTRIANGLEMESH_HPP
|
||||||
|
#define SLICESTOTRIANGLEMESH_HPP
|
||||||
|
|
||||||
|
#include "libslic3r/TriangleMesh.hpp"
|
||||||
|
#include "libslic3r/ExPolygon.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
void slices_to_triangle_mesh(TriangleMesh & mesh,
|
||||||
|
const std::vector<ExPolygons> &slices,
|
||||||
|
double zmin,
|
||||||
|
double lh,
|
||||||
|
double ilh);
|
||||||
|
|
||||||
|
inline TriangleMesh slices_to_triangle_mesh(
|
||||||
|
const std::vector<ExPolygons> &slices, double zmin, double lh, double ilh)
|
||||||
|
{
|
||||||
|
TriangleMesh out; slices_to_triangle_mesh(out, slices, zmin, lh, ilh);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // SLICESTOTRIANGLEMESH_HPP
|
|
@ -971,6 +971,10 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
||||||
std::vector<ExPolygons> enforcers = object.slice_support_enforcers();
|
std::vector<ExPolygons> enforcers = object.slice_support_enforcers();
|
||||||
std::vector<ExPolygons> blockers = object.slice_support_blockers();
|
std::vector<ExPolygons> blockers = object.slice_support_blockers();
|
||||||
|
|
||||||
|
// Append custom supports.
|
||||||
|
object.project_and_append_custom_enforcers(enforcers);
|
||||||
|
object.project_and_append_custom_blockers(blockers);
|
||||||
|
|
||||||
// Output layers, sorted by top Z.
|
// Output layers, sorted by top Z.
|
||||||
MyLayersPtr contact_out;
|
MyLayersPtr contact_out;
|
||||||
|
|
||||||
|
@ -1097,10 +1101,10 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
||||||
if (! enforcers.empty()) {
|
if (! enforcers.empty()) {
|
||||||
// Apply the "support enforcers".
|
// Apply the "support enforcers".
|
||||||
//FIXME add the "enforcers" to the sparse support regions only.
|
//FIXME add the "enforcers" to the sparse support regions only.
|
||||||
const ExPolygons &enforcer = enforcers[layer_id - 1];
|
const ExPolygons &enforcer = enforcers[layer_id];
|
||||||
if (! enforcer.empty()) {
|
if (! enforcer.empty()) {
|
||||||
// Enforce supports (as if with 90 degrees of slope) for the regions covered by the enforcer meshes.
|
// Enforce supports (as if with 90 degrees of slope) for the regions covered by the enforcer meshes.
|
||||||
Polygons new_contacts = diff(intersection(layerm_polygons, to_polygons(enforcer)),
|
Polygons new_contacts = diff(intersection(layerm_polygons, to_polygons(std::move(enforcer))),
|
||||||
offset(lower_layer_polygons, 0.05f * fw, SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
offset(lower_layer_polygons, 0.05f * fw, SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
||||||
if (! new_contacts.empty()) {
|
if (! new_contacts.empty()) {
|
||||||
if (diff_polygons.empty())
|
if (diff_polygons.empty())
|
||||||
|
@ -1111,14 +1115,21 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Apply the "support blockers".
|
|
||||||
if (! diff_polygons.empty() && ! blockers.empty() && ! blockers[layer_id].empty()) {
|
|
||||||
// Enforce supports (as if with 90 degrees of slope) for the regions covered by the enforcer meshes.
|
|
||||||
diff_polygons = diff(diff_polygons, to_polygons(blockers[layer_id]));
|
|
||||||
}
|
|
||||||
if (diff_polygons.empty())
|
if (diff_polygons.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Apply the "support blockers".
|
||||||
|
if (! blockers.empty() && ! blockers[layer_id].empty()) {
|
||||||
|
// Expand the blocker a bit. Custom blockers produce strips
|
||||||
|
// spanning just the projection between the two slices.
|
||||||
|
// Subtracting them as they are may leave unwanted narrow
|
||||||
|
// residues of diff_polygons that would then be supported.
|
||||||
|
diff_polygons = diff(diff_polygons,
|
||||||
|
offset(union_(to_polygons(std::move(blockers[layer_id]))),
|
||||||
|
1000.*SCALED_EPSILON));
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
{
|
{
|
||||||
::Slic3r::SVG svg(debug_out_path("support-top-contacts-raw-run%d-layer%d-region%d.svg",
|
::Slic3r::SVG svg(debug_out_path("support-top-contacts-raw-run%d-layer%d-region%d.svg",
|
||||||
|
@ -2317,9 +2328,14 @@ static inline void fill_expolygons_generate_paths(
|
||||||
fill_params.dont_adjust = true;
|
fill_params.dont_adjust = true;
|
||||||
for (const ExPolygon &expoly : expolygons) {
|
for (const ExPolygon &expoly : expolygons) {
|
||||||
Surface surface(stInternal, expoly);
|
Surface surface(stInternal, expoly);
|
||||||
|
Polylines polylines;
|
||||||
|
try {
|
||||||
|
polylines = filler->fill_surface(&surface, fill_params);
|
||||||
|
} catch (InfillFailedException &) {
|
||||||
|
}
|
||||||
extrusion_entities_append_paths(
|
extrusion_entities_append_paths(
|
||||||
dst,
|
dst,
|
||||||
filler->fill_surface(&surface, fill_params),
|
std::move(polylines),
|
||||||
role,
|
role,
|
||||||
flow.mm3_per_mm(), flow.width, flow.height);
|
flow.mm3_per_mm(), flow.width, flow.height);
|
||||||
}
|
}
|
||||||
|
@ -2339,9 +2355,14 @@ static inline void fill_expolygons_generate_paths(
|
||||||
fill_params.dont_adjust = true;
|
fill_params.dont_adjust = true;
|
||||||
for (ExPolygon &expoly : expolygons) {
|
for (ExPolygon &expoly : expolygons) {
|
||||||
Surface surface(stInternal, std::move(expoly));
|
Surface surface(stInternal, std::move(expoly));
|
||||||
|
Polylines polylines;
|
||||||
|
try {
|
||||||
|
polylines = filler->fill_surface(&surface, fill_params);
|
||||||
|
} catch (InfillFailedException &) {
|
||||||
|
}
|
||||||
extrusion_entities_append_paths(
|
extrusion_entities_append_paths(
|
||||||
dst,
|
dst,
|
||||||
filler->fill_surface(&surface, fill_params),
|
std::move(polylines),
|
||||||
role,
|
role,
|
||||||
flow.mm3_per_mm(), flow.width, flow.height);
|
flow.mm3_per_mm(), flow.width, flow.height);
|
||||||
}
|
}
|
||||||
|
|
133
src/libslic3r/TriangulateWall.cpp
Normal file
133
src/libslic3r/TriangulateWall.cpp
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
#include "TriangulateWall.hpp"
|
||||||
|
#include "MTUtils.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class Ring {
|
||||||
|
size_t idx = 0, nextidx = 1, startidx = 0, begin = 0, end = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Ring(size_t from, size_t to) : begin(from), end(to) { init(begin); }
|
||||||
|
|
||||||
|
size_t size() const { return end - begin; }
|
||||||
|
std::pair<size_t, size_t> pos() const { return {idx, nextidx}; }
|
||||||
|
bool is_lower() const { return idx < size(); }
|
||||||
|
|
||||||
|
void inc()
|
||||||
|
{
|
||||||
|
if (nextidx != startidx) nextidx++;
|
||||||
|
if (nextidx == end) nextidx = begin;
|
||||||
|
idx ++;
|
||||||
|
if (idx == end) idx = begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(size_t pos)
|
||||||
|
{
|
||||||
|
startidx = begin + (pos - begin) % size();
|
||||||
|
idx = startidx;
|
||||||
|
nextidx = begin + (idx + 1 - begin) % size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_finished() const { return nextidx == idx; }
|
||||||
|
};
|
||||||
|
|
||||||
|
static double sq_dst(const Vec3d &v1, const Vec3d& v2)
|
||||||
|
{
|
||||||
|
Vec3d v = v1 - v2;
|
||||||
|
return v.x() * v.x() + v.y() * v.y() /*+ v.z() * v.z()*/;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double score(const Ring& onring, const Ring &offring,
|
||||||
|
const std::vector<Vec3d> &pts)
|
||||||
|
{
|
||||||
|
double a = sq_dst(pts[onring.pos().first], pts[offring.pos().first]);
|
||||||
|
double b = sq_dst(pts[onring.pos().second], pts[offring.pos().first]);
|
||||||
|
return (std::abs(a) + std::abs(b)) / 2.;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Triangulator {
|
||||||
|
const std::vector<Vec3d> *pts;
|
||||||
|
Ring *onring, *offring;
|
||||||
|
|
||||||
|
double calc_score() const
|
||||||
|
{
|
||||||
|
return Slic3r::score(*onring, *offring, *pts);
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronize_rings()
|
||||||
|
{
|
||||||
|
Ring lring = *offring;
|
||||||
|
auto minsc = Slic3r::score(*onring, lring, *pts);
|
||||||
|
size_t imin = lring.pos().first;
|
||||||
|
|
||||||
|
lring.inc();
|
||||||
|
|
||||||
|
while(!lring.is_finished()) {
|
||||||
|
double score = Slic3r::score(*onring, lring, *pts);
|
||||||
|
if (score < minsc) { minsc = score; imin = lring.pos().first; }
|
||||||
|
lring.inc();
|
||||||
|
}
|
||||||
|
|
||||||
|
offring->init(imin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emplace_indices(std::vector<Vec3i> &indices)
|
||||||
|
{
|
||||||
|
Vec3i tr{int(onring->pos().first), int(onring->pos().second),
|
||||||
|
int(offring->pos().first)};
|
||||||
|
if (onring->is_lower()) std::swap(tr(0), tr(1));
|
||||||
|
indices.emplace_back(tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void run(std::vector<Vec3i> &indices)
|
||||||
|
{
|
||||||
|
synchronize_rings();
|
||||||
|
|
||||||
|
double score = 0, prev_score = 0;
|
||||||
|
while (!onring->is_finished() || !offring->is_finished()) {
|
||||||
|
prev_score = score;
|
||||||
|
if (onring->is_finished() || (score = calc_score()) > prev_score) {
|
||||||
|
std::swap(onring, offring);
|
||||||
|
} else {
|
||||||
|
emplace_indices(indices);
|
||||||
|
onring->inc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit Triangulator(const std::vector<Vec3d> *points,
|
||||||
|
Ring & lower,
|
||||||
|
Ring & upper)
|
||||||
|
: pts{points}, onring{&upper}, offring{&lower}
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
Wall triangulate_wall(
|
||||||
|
const Polygon & lower,
|
||||||
|
const Polygon & upper,
|
||||||
|
double lower_z_mm,
|
||||||
|
double upper_z_mm)
|
||||||
|
{
|
||||||
|
if (upper.points.size() < 3 || lower.points.size() < 3) return {};
|
||||||
|
|
||||||
|
Wall wall;
|
||||||
|
auto &pts = wall.first;
|
||||||
|
auto &ind = wall.second;
|
||||||
|
|
||||||
|
pts.reserve(lower.points.size() + upper.points.size());
|
||||||
|
for (auto &p : lower.points)
|
||||||
|
wall.first.emplace_back(unscaled(p.x()), unscaled(p.y()), lower_z_mm);
|
||||||
|
for (auto &p : upper.points)
|
||||||
|
wall.first.emplace_back(unscaled(p.x()), unscaled(p.y()), upper_z_mm);
|
||||||
|
|
||||||
|
ind.reserve(2 * (lower.size() + upper.size()));
|
||||||
|
|
||||||
|
Ring lring{0, lower.points.size()}, uring{lower.points.size(), pts.size()};
|
||||||
|
Triangulator t{&pts, lring, uring};
|
||||||
|
t.run(ind);
|
||||||
|
|
||||||
|
return wall;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
17
src/libslic3r/TriangulateWall.hpp
Normal file
17
src/libslic3r/TriangulateWall.hpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef TRIANGULATEWALL_HPP
|
||||||
|
#define TRIANGULATEWALL_HPP
|
||||||
|
|
||||||
|
#include "libslic3r/Polygon.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
using Wall = std::pair<std::vector<Vec3d>, std::vector<Vec3i>>;
|
||||||
|
|
||||||
|
Wall triangulate_wall(
|
||||||
|
const Polygon & lower,
|
||||||
|
const Polygon & upper,
|
||||||
|
double lower_z_mm,
|
||||||
|
double upper_z_mm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // TRIANGULATEWALL_HPP
|
|
@ -17,90 +17,14 @@
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class Zipper::Impl {
|
class Zipper::Impl: public MZ_Archive {
|
||||||
public:
|
public:
|
||||||
mz_zip_archive arch;
|
|
||||||
std::string m_zipname;
|
std::string m_zipname;
|
||||||
|
|
||||||
static std::string get_errorstr(mz_zip_error mz_err)
|
|
||||||
{
|
|
||||||
switch (mz_err)
|
|
||||||
{
|
|
||||||
case MZ_ZIP_NO_ERROR:
|
|
||||||
return "no error";
|
|
||||||
case MZ_ZIP_UNDEFINED_ERROR:
|
|
||||||
return L("undefined error");
|
|
||||||
case MZ_ZIP_TOO_MANY_FILES:
|
|
||||||
return L("too many files");
|
|
||||||
case MZ_ZIP_FILE_TOO_LARGE:
|
|
||||||
return L("file too large");
|
|
||||||
case MZ_ZIP_UNSUPPORTED_METHOD:
|
|
||||||
return L("unsupported method");
|
|
||||||
case MZ_ZIP_UNSUPPORTED_ENCRYPTION:
|
|
||||||
return L("unsupported encryption");
|
|
||||||
case MZ_ZIP_UNSUPPORTED_FEATURE:
|
|
||||||
return L("unsupported feature");
|
|
||||||
case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR:
|
|
||||||
return L("failed finding central directory");
|
|
||||||
case MZ_ZIP_NOT_AN_ARCHIVE:
|
|
||||||
return L("not a ZIP archive");
|
|
||||||
case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED:
|
|
||||||
return L("invalid header or archive is corrupted");
|
|
||||||
case MZ_ZIP_UNSUPPORTED_MULTIDISK:
|
|
||||||
return L("unsupported multidisk archive");
|
|
||||||
case MZ_ZIP_DECOMPRESSION_FAILED:
|
|
||||||
return L("decompression failed or archive is corrupted");
|
|
||||||
case MZ_ZIP_COMPRESSION_FAILED:
|
|
||||||
return L("compression failed");
|
|
||||||
case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE:
|
|
||||||
return L("unexpected decompressed size");
|
|
||||||
case MZ_ZIP_CRC_CHECK_FAILED:
|
|
||||||
return L("CRC-32 check failed");
|
|
||||||
case MZ_ZIP_UNSUPPORTED_CDIR_SIZE:
|
|
||||||
return L("unsupported central directory size");
|
|
||||||
case MZ_ZIP_ALLOC_FAILED:
|
|
||||||
return L("allocation failed");
|
|
||||||
case MZ_ZIP_FILE_OPEN_FAILED:
|
|
||||||
return L("file open failed");
|
|
||||||
case MZ_ZIP_FILE_CREATE_FAILED:
|
|
||||||
return L("file create failed");
|
|
||||||
case MZ_ZIP_FILE_WRITE_FAILED:
|
|
||||||
return L("file write failed");
|
|
||||||
case MZ_ZIP_FILE_READ_FAILED:
|
|
||||||
return L("file read failed");
|
|
||||||
case MZ_ZIP_FILE_CLOSE_FAILED:
|
|
||||||
return L("file close failed");
|
|
||||||
case MZ_ZIP_FILE_SEEK_FAILED:
|
|
||||||
return L("file seek failed");
|
|
||||||
case MZ_ZIP_FILE_STAT_FAILED:
|
|
||||||
return L("file stat failed");
|
|
||||||
case MZ_ZIP_INVALID_PARAMETER:
|
|
||||||
return L("invalid parameter");
|
|
||||||
case MZ_ZIP_INVALID_FILENAME:
|
|
||||||
return L("invalid filename");
|
|
||||||
case MZ_ZIP_BUF_TOO_SMALL:
|
|
||||||
return L("buffer too small");
|
|
||||||
case MZ_ZIP_INTERNAL_ERROR:
|
|
||||||
return L("internal error");
|
|
||||||
case MZ_ZIP_FILE_NOT_FOUND:
|
|
||||||
return L("file not found");
|
|
||||||
case MZ_ZIP_ARCHIVE_TOO_LARGE:
|
|
||||||
return L("archive is too large");
|
|
||||||
case MZ_ZIP_VALIDATION_FAILED:
|
|
||||||
return L("validation failed");
|
|
||||||
case MZ_ZIP_WRITE_CALLBACK_FAILED:
|
|
||||||
return L("write calledback failed");
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "unknown error";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string formatted_errorstr() const
|
std::string formatted_errorstr() const
|
||||||
{
|
{
|
||||||
return L("Error with zip archive") + " " + m_zipname + ": " +
|
return L("Error with zip archive") + " " + m_zipname + ": " +
|
||||||
get_errorstr(arch.m_last_error) + "!";
|
get_errorstr() + "!";
|
||||||
}
|
}
|
||||||
|
|
||||||
SLIC3R_NORETURN void blow_up() const
|
SLIC3R_NORETURN void blow_up() const
|
||||||
|
@ -167,7 +91,7 @@ void Zipper::add_entry(const std::string &name)
|
||||||
m_entry = name;
|
m_entry = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Zipper::add_entry(const std::string &name, const uint8_t *data, size_t l)
|
void Zipper::add_entry(const std::string &name, const void *data, size_t l)
|
||||||
{
|
{
|
||||||
if(!m_impl->is_alive()) return;
|
if(!m_impl->is_alive()) return;
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ public:
|
||||||
|
|
||||||
// Will blow up in a runtime exception if the file cannot be created.
|
// Will blow up in a runtime exception if the file cannot be created.
|
||||||
explicit Zipper(const std::string& zipfname,
|
explicit Zipper(const std::string& zipfname,
|
||||||
e_compression level = NO_COMPRESSION);
|
e_compression level = FAST_COMPRESSION);
|
||||||
~Zipper();
|
~Zipper();
|
||||||
|
|
||||||
// No copies allwed, this is a file resource...
|
// No copies allwed, this is a file resource...
|
||||||
|
@ -49,7 +49,7 @@ public:
|
||||||
|
|
||||||
/// Add a new binary file entry with an instantly given byte buffer.
|
/// Add a new binary file entry with an instantly given byte buffer.
|
||||||
/// This method throws exactly like finish_entry() does.
|
/// This method throws exactly like finish_entry() does.
|
||||||
void add_entry(const std::string& name, const std::uint8_t* data, size_t l);
|
void add_entry(const std::string& name, const void* data, size_t bytes);
|
||||||
|
|
||||||
// Writing data to the archive works like with standard streams. The target
|
// Writing data to the archive works like with standard streams. The target
|
||||||
// within the zip file is the entry created with the add_entry method.
|
// within the zip file is the entry created with the add_entry method.
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include "Technologies.hpp"
|
#include "Technologies.hpp"
|
||||||
#include "Semver.hpp"
|
#include "Semver.hpp"
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
// Saves around 32% RAM after slicing step, 6.7% after G-code export (tested on PrusaSlicer 2.2.0 final).
|
// Saves around 32% RAM after slicing step, 6.7% after G-code export (tested on PrusaSlicer 2.2.0 final).
|
||||||
typedef int32_t coord_t;
|
typedef int32_t coord_t;
|
||||||
#else
|
#else
|
||||||
|
//FIXME At least FillRectilinear2 requires coord_t to be 32bit.
|
||||||
typedef int64_t coord_t;
|
typedef int64_t coord_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -247,6 +249,37 @@ static inline bool is_approx(Number value, Number test_value)
|
||||||
return std::fabs(double(value) - double(test_value)) < double(EPSILON);
|
return std::fabs(double(value) - double(test_value)) < double(EPSILON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A meta-predicate which is true for integers wider than or equal to coord_t
|
||||||
|
template<class I> struct is_scaled_coord
|
||||||
|
{
|
||||||
|
static const constexpr bool value =
|
||||||
|
std::is_integral<I>::value &&
|
||||||
|
std::numeric_limits<I>::digits >=
|
||||||
|
std::numeric_limits<coord_t>::digits;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Meta predicates for floating, 'scaled coord' and generic arithmetic types
|
||||||
|
// Can be used to restrict templates to work for only the specified set of types.
|
||||||
|
// parameter T is the type we want to restrict
|
||||||
|
// parameter O (Optional defaults to T) is the type that the whole expression
|
||||||
|
// will be evaluated to.
|
||||||
|
// e.g. template<class T> FloatingOnly<T, bool> is_nan(T val);
|
||||||
|
// The whole template will be defined only for floating point types and the
|
||||||
|
// return type will be bool.
|
||||||
|
// For more info how to use, see docs for std::enable_if
|
||||||
|
//
|
||||||
|
template<class T, class O = T>
|
||||||
|
using FloatingOnly = std::enable_if_t<std::is_floating_point<T>::value, O>;
|
||||||
|
|
||||||
|
template<class T, class O = T>
|
||||||
|
using ScaledCoordOnly = std::enable_if_t<is_scaled_coord<T>::value, O>;
|
||||||
|
|
||||||
|
template<class T, class O = T>
|
||||||
|
using IntegerOnly = std::enable_if_t<std::is_integral<T>::value, O>;
|
||||||
|
|
||||||
|
template<class T, class O = T>
|
||||||
|
using ArithmeticOnly = std::enable_if_t<std::is_arithmetic<T>::value, O>;
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
#include "miniz_extension.hpp"
|
#include "miniz_extension.hpp"
|
||||||
|
|
||||||
#if defined(_MSC_VER) || defined(__MINGW64__)
|
#if defined(_MSC_VER) || defined(__MINGW64__)
|
||||||
#include "boost/nowide/cstdio.hpp"
|
#include "boost/nowide/cstdio.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "I18N.hpp"
|
||||||
|
|
||||||
|
//! macro used to mark string used at localization,
|
||||||
|
//! return same string
|
||||||
|
#define L(s) Slic3r::I18N::translate(s)
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -68,4 +76,84 @@ bool open_zip_writer(mz_zip_archive *zip, const std::string &fname)
|
||||||
bool close_zip_reader(mz_zip_archive *zip) { return close_zip(zip, true); }
|
bool close_zip_reader(mz_zip_archive *zip) { return close_zip(zip, true); }
|
||||||
bool close_zip_writer(mz_zip_archive *zip) { return close_zip(zip, false); }
|
bool close_zip_writer(mz_zip_archive *zip) { return close_zip(zip, false); }
|
||||||
|
|
||||||
|
MZ_Archive::MZ_Archive()
|
||||||
|
{
|
||||||
|
mz_zip_zero_struct(&arch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string MZ_Archive::get_errorstr(mz_zip_error mz_err)
|
||||||
|
{
|
||||||
|
switch (mz_err)
|
||||||
|
{
|
||||||
|
case MZ_ZIP_NO_ERROR:
|
||||||
|
return "no error";
|
||||||
|
case MZ_ZIP_UNDEFINED_ERROR:
|
||||||
|
return L("undefined error");
|
||||||
|
case MZ_ZIP_TOO_MANY_FILES:
|
||||||
|
return L("too many files");
|
||||||
|
case MZ_ZIP_FILE_TOO_LARGE:
|
||||||
|
return L("file too large");
|
||||||
|
case MZ_ZIP_UNSUPPORTED_METHOD:
|
||||||
|
return L("unsupported method");
|
||||||
|
case MZ_ZIP_UNSUPPORTED_ENCRYPTION:
|
||||||
|
return L("unsupported encryption");
|
||||||
|
case MZ_ZIP_UNSUPPORTED_FEATURE:
|
||||||
|
return L("unsupported feature");
|
||||||
|
case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR:
|
||||||
|
return L("failed finding central directory");
|
||||||
|
case MZ_ZIP_NOT_AN_ARCHIVE:
|
||||||
|
return L("not a ZIP archive");
|
||||||
|
case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED:
|
||||||
|
return L("invalid header or archive is corrupted");
|
||||||
|
case MZ_ZIP_UNSUPPORTED_MULTIDISK:
|
||||||
|
return L("unsupported multidisk archive");
|
||||||
|
case MZ_ZIP_DECOMPRESSION_FAILED:
|
||||||
|
return L("decompression failed or archive is corrupted");
|
||||||
|
case MZ_ZIP_COMPRESSION_FAILED:
|
||||||
|
return L("compression failed");
|
||||||
|
case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE:
|
||||||
|
return L("unexpected decompressed size");
|
||||||
|
case MZ_ZIP_CRC_CHECK_FAILED:
|
||||||
|
return L("CRC-32 check failed");
|
||||||
|
case MZ_ZIP_UNSUPPORTED_CDIR_SIZE:
|
||||||
|
return L("unsupported central directory size");
|
||||||
|
case MZ_ZIP_ALLOC_FAILED:
|
||||||
|
return L("allocation failed");
|
||||||
|
case MZ_ZIP_FILE_OPEN_FAILED:
|
||||||
|
return L("file open failed");
|
||||||
|
case MZ_ZIP_FILE_CREATE_FAILED:
|
||||||
|
return L("file create failed");
|
||||||
|
case MZ_ZIP_FILE_WRITE_FAILED:
|
||||||
|
return L("file write failed");
|
||||||
|
case MZ_ZIP_FILE_READ_FAILED:
|
||||||
|
return L("file read failed");
|
||||||
|
case MZ_ZIP_FILE_CLOSE_FAILED:
|
||||||
|
return L("file close failed");
|
||||||
|
case MZ_ZIP_FILE_SEEK_FAILED:
|
||||||
|
return L("file seek failed");
|
||||||
|
case MZ_ZIP_FILE_STAT_FAILED:
|
||||||
|
return L("file stat failed");
|
||||||
|
case MZ_ZIP_INVALID_PARAMETER:
|
||||||
|
return L("invalid parameter");
|
||||||
|
case MZ_ZIP_INVALID_FILENAME:
|
||||||
|
return L("invalid filename");
|
||||||
|
case MZ_ZIP_BUF_TOO_SMALL:
|
||||||
|
return L("buffer too small");
|
||||||
|
case MZ_ZIP_INTERNAL_ERROR:
|
||||||
|
return L("internal error");
|
||||||
|
case MZ_ZIP_FILE_NOT_FOUND:
|
||||||
|
return L("file not found");
|
||||||
|
case MZ_ZIP_ARCHIVE_TOO_LARGE:
|
||||||
|
return L("archive is too large");
|
||||||
|
case MZ_ZIP_VALIDATION_FAILED:
|
||||||
|
return L("validation failed");
|
||||||
|
case MZ_ZIP_WRITE_CALLBACK_FAILED:
|
||||||
|
return L("write calledback failed");
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown error";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
|
@ -11,6 +11,25 @@ bool open_zip_writer(mz_zip_archive *zip, const std::string &fname_utf8);
|
||||||
bool close_zip_reader(mz_zip_archive *zip);
|
bool close_zip_reader(mz_zip_archive *zip);
|
||||||
bool close_zip_writer(mz_zip_archive *zip);
|
bool close_zip_writer(mz_zip_archive *zip);
|
||||||
|
|
||||||
|
class MZ_Archive {
|
||||||
|
public:
|
||||||
|
mz_zip_archive arch;
|
||||||
|
|
||||||
|
MZ_Archive();
|
||||||
|
|
||||||
|
static std::string get_errorstr(mz_zip_error mz_err);
|
||||||
|
|
||||||
|
std::string get_errorstr() const
|
||||||
|
{
|
||||||
|
return get_errorstr(arch.m_last_error) + "!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_alive() const
|
||||||
|
{
|
||||||
|
return arch.m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
#endif // MINIZ_EXTENSION_HPP
|
#endif // MINIZ_EXTENSION_HPP
|
||||||
|
|
|
@ -142,18 +142,27 @@ set(SLIC3R_GUI_SOURCES
|
||||||
GUI/UpdateDialogs.hpp
|
GUI/UpdateDialogs.hpp
|
||||||
GUI/FirmwareDialog.cpp
|
GUI/FirmwareDialog.cpp
|
||||||
GUI/FirmwareDialog.hpp
|
GUI/FirmwareDialog.hpp
|
||||||
GUI/ProgressIndicator.hpp
|
|
||||||
GUI/ProgressStatusBar.hpp
|
|
||||||
GUI/ProgressStatusBar.cpp
|
|
||||||
GUI/PrintHostDialogs.cpp
|
GUI/PrintHostDialogs.cpp
|
||||||
GUI/PrintHostDialogs.hpp
|
GUI/PrintHostDialogs.hpp
|
||||||
GUI/Job.hpp
|
GUI/Jobs/Job.hpp
|
||||||
|
GUI/Jobs/Job.cpp
|
||||||
|
GUI/Jobs/ArrangeJob.hpp
|
||||||
|
GUI/Jobs/ArrangeJob.cpp
|
||||||
|
GUI/Jobs/RotoptimizeJob.hpp
|
||||||
|
GUI/Jobs/RotoptimizeJob.cpp
|
||||||
|
GUI/Jobs/SLAImportJob.hpp
|
||||||
|
GUI/Jobs/SLAImportJob.cpp
|
||||||
|
GUI/Jobs/ProgressIndicator.hpp
|
||||||
|
GUI/ProgressStatusBar.hpp
|
||||||
|
GUI/ProgressStatusBar.cpp
|
||||||
GUI/Mouse3DController.cpp
|
GUI/Mouse3DController.cpp
|
||||||
GUI/Mouse3DController.hpp
|
GUI/Mouse3DController.hpp
|
||||||
GUI/DoubleSlider.cpp
|
GUI/DoubleSlider.cpp
|
||||||
GUI/DoubleSlider.hpp
|
GUI/DoubleSlider.hpp
|
||||||
GUI/ObjectDataViewModel.cpp
|
GUI/ObjectDataViewModel.cpp
|
||||||
GUI/ObjectDataViewModel.hpp
|
GUI/ObjectDataViewModel.hpp
|
||||||
|
GUI/InstanceCheck.cpp
|
||||||
|
GUI/InstanceCheck.hpp
|
||||||
GUI/Search.cpp
|
GUI/Search.cpp
|
||||||
GUI/Search.hpp
|
GUI/Search.hpp
|
||||||
Utils/Http.cpp
|
Utils/Http.cpp
|
||||||
|
@ -179,6 +188,8 @@ set(SLIC3R_GUI_SOURCES
|
||||||
Utils/HexFile.cpp
|
Utils/HexFile.cpp
|
||||||
Utils/HexFile.hpp
|
Utils/HexFile.hpp
|
||||||
Utils/Thread.hpp
|
Utils/Thread.hpp
|
||||||
|
Utils/SLAImport.hpp
|
||||||
|
Utils/SLAImport.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
@ -188,6 +199,8 @@ if (APPLE)
|
||||||
GUI/RemovableDriveManagerMM.mm
|
GUI/RemovableDriveManagerMM.mm
|
||||||
GUI/RemovableDriveManagerMM.h
|
GUI/RemovableDriveManagerMM.h
|
||||||
GUI/Mouse3DHandlerMac.mm
|
GUI/Mouse3DHandlerMac.mm
|
||||||
|
GUI/InstanceCheckMac.mm
|
||||||
|
GUI/InstanceCheckMac.h
|
||||||
)
|
)
|
||||||
FIND_LIBRARY(DISKARBITRATION_LIBRARY DiskArbitration)
|
FIND_LIBRARY(DISKARBITRATION_LIBRARY DiskArbitration)
|
||||||
|
|
||||||
|
@ -199,6 +212,10 @@ encoding_check(libslic3r_gui)
|
||||||
|
|
||||||
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL OpenGL::GLU hidapi libcurl ${wxWidgets_LIBRARIES})
|
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL OpenGL::GLU hidapi libcurl ${wxWidgets_LIBRARIES})
|
||||||
|
|
||||||
|
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
target_link_libraries(libslic3r_gui ${DBUS_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY})
|
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY})
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -259,7 +259,8 @@ Point Bed3D::point_projection(const Point& point) const
|
||||||
return m_polygon.point_projection(point);
|
return m_polygon.point_projection(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes) const
|
void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor,
|
||||||
|
bool show_axes, bool show_texture) const
|
||||||
{
|
{
|
||||||
m_scale_factor = scale_factor;
|
m_scale_factor = scale_factor;
|
||||||
|
|
||||||
|
@ -270,9 +271,9 @@ void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool sho
|
||||||
|
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
case System: { render_system(canvas, bottom); break; }
|
case System: { render_system(canvas, bottom, show_texture); break; }
|
||||||
default:
|
default:
|
||||||
case Custom: { render_custom(canvas, bottom); break; }
|
case Custom: { render_custom(canvas, bottom, show_texture); break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||||
|
@ -384,11 +385,12 @@ void Bed3D::render_axes() const
|
||||||
m_axes.render();
|
m_axes.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bed3D::render_system(GLCanvas3D& canvas, bool bottom) const
|
void Bed3D::render_system(GLCanvas3D& canvas, bool bottom, bool show_texture) const
|
||||||
{
|
{
|
||||||
if (!bottom)
|
if (!bottom)
|
||||||
render_model();
|
render_model();
|
||||||
|
|
||||||
|
if (show_texture)
|
||||||
render_texture(bottom, canvas);
|
render_texture(bottom, canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,7 +566,7 @@ void Bed3D::render_model() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom) const
|
void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture) const
|
||||||
{
|
{
|
||||||
if (m_texture_filename.empty() && m_model_filename.empty())
|
if (m_texture_filename.empty() && m_model_filename.empty())
|
||||||
{
|
{
|
||||||
|
@ -575,6 +577,7 @@ void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom) const
|
||||||
if (!bottom)
|
if (!bottom)
|
||||||
render_model();
|
render_model();
|
||||||
|
|
||||||
|
if (show_texture)
|
||||||
render_texture(bottom, canvas);
|
render_texture(bottom, canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,11 +103,15 @@ public:
|
||||||
// Return true if the bed shape changed, so the calee will update the UI.
|
// Return true if the bed shape changed, so the calee will update the UI.
|
||||||
bool set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model);
|
bool set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model);
|
||||||
|
|
||||||
const BoundingBoxf3& get_bounding_box(bool extended) const { return extended ? m_extended_bounding_box : m_bounding_box; }
|
const BoundingBoxf3& get_bounding_box(bool extended) const {
|
||||||
|
return extended ? m_extended_bounding_box : m_bounding_box;
|
||||||
|
}
|
||||||
|
|
||||||
bool contains(const Point& point) const;
|
bool contains(const Point& point) const;
|
||||||
Point point_projection(const Point& point) const;
|
Point point_projection(const Point& point) const;
|
||||||
|
|
||||||
void render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes) const;
|
void render(GLCanvas3D& canvas, bool bottom, float scale_factor,
|
||||||
|
bool show_axes, bool show_texture) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void calc_bounding_boxes() const;
|
void calc_bounding_boxes() const;
|
||||||
|
@ -115,10 +119,10 @@ private:
|
||||||
void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox);
|
void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox);
|
||||||
std::tuple<EType, std::string, std::string> detect_type(const Pointfs& shape) const;
|
std::tuple<EType, std::string, std::string> detect_type(const Pointfs& shape) const;
|
||||||
void render_axes() const;
|
void render_axes() const;
|
||||||
void render_system(GLCanvas3D& canvas, bool bottom) const;
|
void render_system(GLCanvas3D& canvas, bool bottom, bool show_texture) const;
|
||||||
void render_texture(bool bottom, GLCanvas3D& canvas) const;
|
void render_texture(bool bottom, GLCanvas3D& canvas) const;
|
||||||
void render_model() const;
|
void render_model() const;
|
||||||
void render_custom(GLCanvas3D& canvas, bool bottom) const;
|
void render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture) const;
|
||||||
void render_default(bool bottom) const;
|
void render_default(bool bottom) const;
|
||||||
void reset();
|
void reset();
|
||||||
};
|
};
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue