This commit is contained in:
bubnikv 2020-04-28 19:31:18 +02:00
commit 4de4d765ee
154 changed files with 21745 additions and 4745 deletions

View file

@ -1,13 +1,13 @@
Did you encounter an issue with using Slic3r? Fear not! This guide will help you to write a good bug report in just a few, simple steps.
Did you encounter an issue with using PrusaSlicer? Fear not! This guide will help you to write a good bug report in just a few, simple steps.
There is a good chance that the issue, you have encountered, is already reported. Please check the [list of reported issues](https://github.com/alexrj/Slic3r/issues) before creating a new issue report. If you find an existing issue report, feel free to add further information to that report.
There is a good chance that the issue, you have encountered, is already reported. Please check the [list of reported issues](https://github.com/prusa3d/PrusaSlicer/issues) before creating a new issue report. If you find an existing issue report, feel free to add further information to that report.
If possible, please include the following information when [reporting an issue](https://github.com/alexrj/Slic3r/issues/new):
* Slic3r version (See the about dialog for the version number. If running from git, please include the git commit ID from `git rev-parse HEAD` also.)
If possible, please include the following information when [reporting an issue](https://github.com/prusa3d/PrusaSlicer/issues/new):
* PrusaSlicer version (See the about dialog for the version number. If running from git, please include the git commit ID from `git rev-parse HEAD` also.)
* Operating system type + version
* Steps to reproduce the issue, including:
* Command line parameters used, if any
* Slic3r configuration file (Use ``Export Config...`` from the ``File`` menu - please don't export a bundle)
* PrusaSlicer configuration file (Use ``Export Config...`` from the ``File`` menu - please don't export a bundle)
* Expected result
* Actual result
* Any error messages
@ -17,5 +17,5 @@ If possible, please include the following information when [reporting an issue](
Please make sure only to include one issue per report. If you encounter multiple, unrelated issues, please report them as such.
Simon Tatham has written an excellent on article on [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) which is well worth reading, although it is not specific to Slic3r.
Simon Tatham has written an excellent on article on [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) which is well worth reading, although it is not specific to PrusaSlicer.

View file

@ -369,9 +369,9 @@ include_directories(BEFORE SYSTEM ${EIGEN3_INCLUDE_DIR})
# Find expat or use bundled version
# Always use the system libexpat on Linux.
if (NOT SLIC3R_STATIC OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
find_package(EXPAT)
endif ()
find_package(EXPAT)
if (NOT EXPAT_FOUND)
add_library(expat STATIC
${LIBDIR}/expat/xmlparse.c
@ -382,7 +382,8 @@ if (NOT EXPAT_FOUND)
set(EXPAT_INCLUDE_DIRS ${LIBDIR}/expat/)
set(EXPAT_LIBRARIES expat)
endif ()
include_directories(${EXPAT_INCLUDE_DIRS})
find_package(PNG REQUIRED)
find_package(OpenGL REQUIRED)

35
deps/CMakeLists.txt vendored
View file

@ -34,8 +34,10 @@ endif ()
set(DESTDIR "${CMAKE_CURRENT_BINARY_DIR}/destdir" CACHE PATH "Destination directory")
option(DEP_DEBUG "Build debug variants (only applicable on Windows)" ON)
option(DEP_WX_STABLE "Build against wxWidgets stable 3.0 as opposed to default 3.1 (Linux only)" OFF)
option(DEP_WX_GTK3 "Build wxWidgets against GTK3" OFF)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
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.
# FIXME:
@ -127,12 +129,28 @@ else()
include("deps-linux.cmake")
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(OpenCSG/OpenCSG.cmake)
include(GMP/GMP.cmake)
include(MPFR/MPFR.cmake)
include(CGAL/CGAL.cmake)
include(wxWidgets/wxWidgets.cmake)
if (MSVC)
@ -141,15 +159,17 @@ if (MSVC)
dep_boost
dep_tbb
dep_libcurl
dep_wxwidgets
dep_wxWidgets
dep_gtest
dep_cereal
dep_nlopt
# dep_qhull # Experimental
dep_ZLIB # on Windows we still need zlib
dep_openvdb
dep_OpenCSG
dep_CGAL
${PNG_PKG}
${ZLIB_PKG}
${EXPAT_PKG}
)
else()
@ -159,7 +179,7 @@ else()
dep_boost
dep_tbb
dep_libcurl
dep_wxwidgets
dep_wxWidgets
dep_gtest
dep_cereal
dep_nlopt
@ -167,6 +187,9 @@ else()
dep_openvdb
dep_OpenCSG
dep_CGAL
${PNG_PKG}
${ZLIB_PKG}
${EXPAT_PKG}
# dep_libigl # Not working, static build has different Eigen
)

9
deps/EXPAT/EXPAT.cmake vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

33
deps/EXPAT/expat/expat_config.h vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

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
View 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

File diff suppressed because it is too large Load diff

322
deps/EXPAT/expat/xmltok.h vendored Normal file
View 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
View 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

File diff suppressed because it is too large Load diff

115
deps/EXPAT/expat/xmltok_ns.inc vendored Normal file
View 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 */

View file

@ -1,5 +1,6 @@
# We have to check for OpenGL to compile GLEW
find_package(OpenGL QUIET REQUIRED)
set(OpenGL_GL_PREFERENCE "LEGACY") # to prevent a nasty warning by cmake
find_package(OpenGL QUIET)
prusaslicer_add_cmake_project(
GLEW

View file

@ -6,8 +6,8 @@ prusaslicer_add_cmake_project(OpenCSG
DEPENDS dep_GLEW
)
if (TARGET dep_ZLIB)
add_dependencies(dep_OpenCSG dep_ZLIB)
if (TARGET ${ZLIB_PKG})
add_dependencies(dep_OpenCSG ${ZLIB_PKG})
endif()
if (MSVC)

13
deps/PNG/PNG.cmake vendored Normal file
View 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
View file

@ -3,6 +3,13 @@ set(DEP_CMAKE_OPTS "-DCMAKE_POSITION_INDEPENDENT_CODE=ON")
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
EXCLUDE_FROM_ALL 1
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}"
)
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)

26
deps/deps-macos.cmake vendored
View file

@ -86,30 +86,4 @@ ExternalProject_Add(dep_libcurl
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)

16
deps/deps-mingw.cmake vendored
View file

@ -57,20 +57,4 @@ ExternalProject_Add(dep_libcurl
-DCURL_DISABLE_GOPHER=ON
-DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local
${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}
)

View file

@ -9,9 +9,15 @@ endif ()
find_package(ZLIB QUIET)
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 ()
# 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
EXCLUDE_FROM_ALL 1
URL "https://github.com/wjakob/tbb/archive/a0dc9bf76d0120f917b641ed095360448cabc85b.tar.gz"

View file

@ -149,38 +149,6 @@ ExternalProject_Add(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)
set(DEP_LIBCURL_TARGET "x86")
else ()
@ -243,36 +211,13 @@ endif ()
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
EXCLUDE_FROM_ALL 1
#URL https://github.com/Blosc/c-blosc/archive/v1.17.0.zip
#URL_HASH SHA256=7463a1df566704f212263312717ab2c36b45d45cba6cd0dccebf91b2cc4b4da9
GIT_REPOSITORY https://github.com/Blosc/c-blosc.git
GIT_TAG e63775855294b50820ef44d1b157f4de1cc38d3e #v1.17.0
DEPENDS dep_ZLIB
DEPENDS ${ZLIB_PKG}
CMAKE_GENERATOR "${DEP_MSVC_GEN}"
CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}"
CMAKE_ARGS
@ -299,7 +244,7 @@ ExternalProject_Add(dep_openexr
EXCLUDE_FROM_ALL 1
GIT_REPOSITORY https://github.com/openexr/openexr.git
GIT_TAG eae0e337c9f5117e78114fd05f7a415819df413a #v2.4.0
DEPENDS dep_ZLIB
DEPENDS ${ZLIB_PKG}
CMAKE_GENERATOR "${DEP_MSVC_GEN}"
CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}"
CMAKE_ARGS
@ -352,4 +297,4 @@ if (${DEP_DEBUG})
COMMAND msbuild /m /P:Configuration=Debug INSTALL.vcxproj
WORKING_DIRECTORY "${BINARY_DIR}"
)
endif ()
endif ()

36
deps/wxWidgets/wxWidgets.cmake vendored Normal file
View 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 ()

File diff suppressed because it is too large Load diff

View file

@ -6360,7 +6360,7 @@ msgstr "Redimensionner"
#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:459
msgid "Scale factors"
msgstr "Facteurs de redimensionnement"
msgstr "Échelle"
#: src/slic3r/GUI/KBShortcutsDialog.cpp:196
msgid ""

View file

@ -429,7 +429,7 @@ msgstr "서포트 생성"
#: src/slic3r/GUI/ConfigManipulation.cpp:200
msgid "The %1% infill pattern is not supposed to work at 100%% density."
msgstr "%1% 채우기 패턴은 100% 밀도로 작동하도록 되어 있지 않습니다."
msgstr "%1% 채우기 패턴은 100%% 밀도로 작동하도록 되어 있지 않습니다."
#: src/slic3r/GUI/ConfigManipulation.cpp:202
msgid "Shall I switch to rectilinear fill pattern?"

View file

@ -31,17 +31,18 @@ avoid_crossing_perimeters = 0
bottom_fill_pattern = rectilinear
bridge_angle = 0
bridge_flow_ratio = 0.95
bridge_speed = 25
bridge_speed = 20
brim_width = 0
clip_multipart_objects = 1
compatible_printers =
compatible_printers =
complete_objects = 0
dont_support_bridges = 1
elefant_foot_compensation = 0
ensure_vertical_shell_thickness = 1
external_fill_pattern = rectilinear
external_perimeters_first = 0
external_perimeter_extrusion_width = 0.45
external_perimeter_extrusion_width = 0.40
external_perimeter_speed = 25
extra_perimeters = 0
extruder_clearance_height = 12
extruder_clearance_radius = 45
@ -52,14 +53,14 @@ fill_pattern = grid
first_layer_extrusion_width = 0.42
first_layer_height = 0.2
first_layer_speed = 20
gap_fill_speed = 30
gap_fill_speed = 15
gcode_comments = 0
infill_every_layers = 1
infill_extruder = 1
infill_extrusion_width = 0.45
infill_first = 0
infill_only_where_needed = 0
infill_overlap = 25%
infill_overlap = 20%
interface_shells = 0
max_print_speed = 60
max_volumetric_extrusion_rate_slope_negative = 0
@ -83,7 +84,7 @@ single_extruder_multi_material_priming = 0
skirts = 3
skirt_distance = 2
skirt_height = 1
small_perimeter_speed = 25
small_perimeter_speed = 15
solid_infill_below_area = 0
solid_infill_every_layers = 0
solid_infill_extruder = 1
@ -92,7 +93,7 @@ spiral_vase = 0
standby_temperature_delta = -5
support_material = 0
support_material_extruder = 0
support_material_extrusion_width = 0.4
support_material_extrusion_width = 0.40
support_material_interface_extruder = 0
support_material_angle = 0
support_material_buildplate_only = 0
@ -110,8 +111,8 @@ support_material_threshold = 45
support_material_with_sheath = 0
support_material_xy_spacing = 60%
thin_walls = 0
top_infill_extrusion_width = 0.45
top_solid_infill_speed = 40
top_infill_extrusion_width = 0.40
top_solid_infill_speed = 20
travel_speed = 130
wipe_tower = 0
wipe_tower_bridging = 10
@ -194,7 +195,7 @@ top_solid_layers = 7
[print:*0.15mm*]
inherits = *common*
external_perimeter_speed = 40
external_perimeter_speed = 25
infill_acceleration = 1100
infill_speed = 50
layer_height = 0.15
@ -242,7 +243,7 @@ top_solid_layers = 4
inherits = *common*
bottom_solid_layers = 4
bridge_flow_ratio = 0.95
external_perimeter_speed = 40
external_perimeter_speed = 25
infill_acceleration = 1100
infill_speed = 60
layer_height = 0.3
@ -334,7 +335,7 @@ inherits = *0.30mm*
# alias = 0.30mm ULTRADRAFT
bottom_solid_layers = 3
bridge_speed = 30
external_perimeter_speed = 35
external_perimeter_speed = 30
infill_acceleration = 1100
infill_speed = 55
max_print_speed = 60

View file

@ -22,6 +22,12 @@ bed_model = ender3_bed.stl
bed_texture = ender3.svg
default_materials = Generic PLA @ENDER3; Generic PETG @ENDER3; Generic ABS @ENDER3; Prusament PLA @ENDER3; Prusament PETG @ENDER3
[printer_model:ENDER2]
name = Creality Ender-2
variants = 0.4
technology = FFF
default_materials = Generic PLA @ENDER3; Generic PETG @ENDER3; Generic ABS @ENDER3; Prusament PLA @ENDER3; Prusament PETG @ENDER3
# All presets starting with asterisk, for example *common*, are intermediate and they will
# not make it into the user interface.
@ -423,3 +429,9 @@ default_print_profile = 0.20mm NORMAL
default_filament_profile = Creality PLA
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 ; home all\nG1 Z2 F240\nG1 X2 Y10 F3000\nG1 Z0.28 F240\nG92 E0.0\nG1 Y190 E15.0 F1500.0 ; intro line\nG1 X2.3 F5000\nG1 Y10 E30 F1200.0 ; intro line\nG92 E0.0
end_gcode = M104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+10, max_print_height)} F600{endif} ; Move print head up\nG1 X0 Y200 F3000 ; present print\nM84 X Y E ; disable motors
[printer:Creality ENDER-2]
inherits = Creality ENDER-3
bed_shape = 0x0,150x0,150x150,0x150
printer_model = ENDER2
max_print_height = 200

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View file

@ -62,10 +62,8 @@ void main()
float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0);
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
intensity.y = 0.0;
if (NdotL > 0.0)
intensity.y += LIGHT_TOP_SPECULAR * pow(max(dot(normal, reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS);
vec3 position = (gl_ModelViewMatrix * gl_Vertex).xyz;
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS);
// Perform the same lighting calculation for the 2nd light source (no specular applied).
NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0);

View file

@ -32,10 +32,8 @@ void main()
float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0);
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
intensity.y = 0.0;
if (NdotL > 0.0)
intensity.y += LIGHT_TOP_SPECULAR * pow(max(dot(normal, reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS);
vec3 position = (gl_ModelViewMatrix * gl_Vertex).xyz;
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS);
// Perform the same lighting calculation for the 2nd light source (no specular)
NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0);

View file

@ -59,6 +59,10 @@ if (SLIC3R_GUI)
include(${wxWidgets_USE_FILE})
list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX png)
list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX expat)
list(APPEND wxWidgets_LIBRARIES ${PNG_LIBRARIES} ${EXPAT_LIBRARIES})
# list(REMOVE_ITEM wxWidgets_LIBRARIES oleacc)
message(STATUS "wx libs: ${wxWidgets_LIBRARIES}")

View file

@ -34,6 +34,7 @@
#include "libslic3r/Config.hpp"
#include "libslic3r/Geometry.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/ModelArrange.hpp"
#include "libslic3r/Print.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "libslic3r/TriangleMesh.hpp"
@ -41,6 +42,7 @@
#include "libslic3r/Format/3mf.hpp"
#include "libslic3r/Format/STL.hpp"
#include "libslic3r/Format/OBJ.hpp"
#include "libslic3r/Format/SL1.hpp"
#include "libslic3r/Utils.hpp"
#include "PrusaSlicer.hpp"
@ -53,14 +55,16 @@
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)
{
#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.
try {
boost::nowide::nowide_filesystem();
@ -86,13 +90,15 @@ int CLI::run(int argc, char **argv)
m_extra_config.apply(m_config, true);
m_extra_config.normalize();
PrinterTechnology printer_technology = Slic3r::printer_technology(m_config);
bool start_gui = m_actions.empty() &&
// 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_x") == 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;
// load config files supplied via --load
@ -113,7 +119,7 @@ int CLI::run(int argc, char **argv)
return 1;
}
config.normalize();
PrinterTechnology other_printer_technology = get_printer_technology(config);
PrinterTechnology other_printer_technology = Slic3r::printer_technology(config);
if (printer_technology == ptUnknown) {
printer_technology = other_printer_technology;
} else if (printer_technology != other_printer_technology && other_printer_technology != ptUnknown) {
@ -134,7 +140,7 @@ int CLI::run(int argc, char **argv)
// When loading an AMF or 3MF, config is imported as well, including the printer technology.
DynamicPrintConfig config;
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) {
printer_technology = other_printer_technology;
} else if (printer_technology != other_printer_technology && other_printer_technology != ptUnknown) {
@ -161,9 +167,6 @@ int CLI::run(int argc, char **argv)
// Normalizing after importing the 3MFs / AMFs
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.
FullPrintConfig fff_print_config;
SLAFullPrintConfig sla_print_config;
@ -174,6 +177,7 @@ int CLI::run(int argc, char **argv)
m_print_config.apply(fff_print_config, true);
} else if (printer_technology == ptSLA) {
// 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";
// The default bed shape should reflect the default display parameters
@ -186,8 +190,18 @@ int CLI::run(int argc, char **argv)
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.
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) {
if (opt_key == "merge") {
Model m;
@ -197,29 +211,33 @@ int CLI::run(int argc, char **argv)
// Rearrange instances unless --dont-arrange is supplied
if (! m_config.opt_bool("dont_arrange")) {
m.add_default_instances();
const BoundingBoxf &bb = fff_print_config.bed_shape.values;
m.arrange_objects(
fff_print_config.min_object_distance(),
// If we are going to use the merged model for printing, honor
// the configured print bed for arranging, otherwise do it freely.
this->has_print_action() ? &bb : nullptr
);
if (this->has_print_action())
arrange_objects(m, bed, arrange_cfg);
else
arrange_objects(m, InfiniteBed{}, arrange_cfg);
}
m_models.clear();
m_models.emplace_back(std::move(m));
} else if (opt_key == "duplicate") {
const BoundingBoxf &bb = fff_print_config.bed_shape.values;
for (auto &model : m_models) {
const bool all_objects_have_instances = std::none_of(
model.objects.begin(), model.objects.end(),
[](ModelObject* o){ return o->instances.empty(); }
);
if (all_objects_have_instances) {
// 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);
} else {
model.add_default_instances();
model.duplicate_objects(m_config.opt_int("duplicate"), fff_print_config.min_object_distance(), &bb);
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
duplicate(model, size_t(dups), bed, arrange_cfg);
} else {
arrange_objects(model, bed, arrange_cfg);
}
} catch (std::exception &ex) {
boost::nowide::cerr << "error: " << ex.what() << std::endl;
return 1;
}
}
} else if (opt_key == "duplicate_grid") {
@ -413,7 +431,8 @@ int CLI::run(int argc, char **argv)
std::string outfile = m_config.opt_string("output");
Print fff_print;
SLAPrint sla_print;
SL1Archive sla_archive(sla_print.printer_config());
sla_print.set_printer(&sla_archive);
sla_print.set_status_callback(
[](const PrintBase::SlicingStatus& s)
{
@ -423,11 +442,11 @@ int CLI::run(int argc, char **argv)
PrintBase *print = (printer_technology == ptFFF) ? static_cast<PrintBase*>(&fff_print) : static_cast<PrintBase*>(&sla_print);
if (! m_config.opt_bool("dont_arrange")) {
//FIXME make the min_object_distance configurable.
model.arrange_objects(fff_print.config().min_object_distance());
model.center_instances_around_point((! user_center_specified && m_print_config.has("bed_shape")) ?
BoundingBoxf(m_print_config.opt<ConfigOptionPoints>("bed_shape")->values).center() :
m_config.option<ConfigOptionPoint>("center")->value);
if (user_center_specified) {
Vec2d c = m_config.option<ConfigOptionPoint>("center")->value;
arrange_objects(model, InfiniteBed{scaled(c)}, arrange_cfg);
} else
arrange_objects(model, bed, arrange_cfg);
}
if (printer_technology == ptFFF) {
for (auto* mo : model.objects)
@ -453,7 +472,7 @@ int CLI::run(int argc, char **argv)
outfile = sla_print.output_filepath(outfile);
// 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);
sla_print.export_raster(outfile_final);
sla_archive.export_print(outfile_final, sla_print);
}
if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final)) {
boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl;
@ -609,6 +628,8 @@ bool CLI::setup(int argc, char **argv)
if (opt_loglevel != 0)
set_logging_level(opt_loglevel->value);
}
std::string validity = m_config.validate();
// Initialize with defaults.
for (const t_optiondef_map *options : { &cli_actions_config_def.options, &cli_transform_config_def.options, &cli_misc_config_def.options })
@ -616,6 +637,11 @@ bool CLI::setup(int argc, char **argv)
m_config.option(optdef.first, true);
set_data_dir(m_config.opt_string("datadir"));
if (!validity.empty()) {
boost::nowide::cerr << "error: " << validity << std::endl;
return false;
}
return true;
}

View file

@ -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
inline double area(const S& sh)
{

View file

@ -27,6 +27,7 @@ using Coord = TCoord<PointImpl>;
using Box = _Box<PointImpl>;
using Segment = _Segment<PointImpl>;
using Circle = _Circle<PointImpl>;
using MultiPolygon = TMultiShape<PolygonImpl>;
using Item = _Item<PolygonImpl>;
using Rectangle = _Rectangle<PolygonImpl>;

View file

@ -5,7 +5,7 @@
#include <fstream>
#include <string>
#include <libnest2d/libnest2d.hpp>
#include <libnest2d/nester.hpp>
namespace libnest2d { namespace svg {
@ -48,23 +48,28 @@ public:
conf_.width = static_cast<double>(box.width()) /
conf_.mm_in_coord_units;
}
void writeItem(const Item& item) {
void writeShape(RawShape tsh) {
if(svg_layers_.empty()) addLayer();
auto tsh = item.transformedShape();
if(conf_.origo_location == BOTTOMLEFT) {
auto d = static_cast<Coord>(
std::round(conf_.height*conf_.mm_in_coord_units) );
std::round(conf_.height*conf_.mm_in_coord_units) );
auto& contour = shapelike::contour(tsh);
for(auto& v : contour) setY(v, -getY(v) + d);
auto& holes = shapelike::holes(tsh);
for(auto& h : holes) for(auto& v : h) setY(v, -getY(v) + d);
}
currentLayer() += shapelike::serialize<Formats::SVG>(tsh,
1.0/conf_.mm_in_coord_units) + "\n";
currentLayer() +=
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) {

View file

@ -1,7 +1,6 @@
#include "Arrange.hpp"
#include "Geometry.hpp"
//#include "Geometry.hpp"
#include "SVG.hpp"
#include "MTUtils.hpp"
#include <libnest2d/backends/clipper/geometries.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
// Slic3r.
template<class PConf>
void fillConfig(PConf& pcfg) {
void fill_config(PConf& pcfg) {
// Align the arranged pile into the center of the bin
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
// 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);
Box pilebb = std::get<1>(result);
@ -312,7 +311,7 @@ public:
, m_bin_area(sl::area(bin))
, 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
// This functionality is provided by the Nester class (m_pack).
@ -363,6 +362,9 @@ public:
m_item_count = 0;
}
PConfig& config() { return m_pconf; }
const PConfig& config() const { return m_pconf; }
inline void preload(std::vector<Item>& fixeditems) {
m_pconf.alignment = PConfig::Alignment::DONT_ALIGN;
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)
{
auto it = items.begin();
@ -572,12 +453,12 @@ void _arrange(
std::vector<Item> & shapes,
std::vector<Item> & excludes,
const BinT & bin,
coord_t minobjd,
const ArrangeParams & params,
std::function<void(unsigned)> progressfn,
std::function<bool()> stopfn)
{
// 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;
auto corrected_bin = bin;
@ -585,7 +466,10 @@ void _arrange(
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 : excludes) itm.inflate(infl);
@ -603,44 +487,106 @@ void _arrange(
for (Item &itm : inp) itm.inflate(-infl);
}
// The final client function for arrangement. A progress indicator and
// a stop predicate can be also be passed to control the process.
void arrange(ArrangePolygons & arrangables,
const ArrangePolygons & excludes,
coord_t min_obj_dist,
const BedShapeHint & bedhint,
std::function<void(unsigned)> progressind,
std::function<bool()> stopcondition)
inline Box to_nestbin(const BoundingBox &bb) { return Box{{bb.min(X), bb.min(Y)}, {bb.max(X), bb.max(Y)}};}
inline Circle to_nestbin(const CircleBed &c) { return Circle({c.center()(0), c.center()(1)}, c.radius()); }
inline clppr::Polygon to_nestbin(const Polygon &p) { return sl::create<clppr::Polygon>(Slic3rMultiPoint_to_ClipperPath(p)); }
inline Box to_nestbin(const InfiniteBed &bed) { return Box::infinite({bed.center.x(), bed.center.y()}); }
inline coord_t width(const BoundingBox& box) { return box.max.x() - box.min.x(); }
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 &center, 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
static void process_arrangeable(const ArrangePolygon &arrpoly,
std::vector<Item> & outp)
{
Polygon p = arrpoly.poly.contour;
const Vec2crd &offs = arrpoly.translation;
double rotation = arrpoly.rotation;
if (p.is_counter_clockwise()) p.reverse();
clppr::Polygon clpath(Slic3rMultiPoint_to_ClipperPath(p));
if (!clpath.Contour.empty()) {
auto firstp = clpath.Contour.front();
clpath.Contour.emplace_back(firstp);
}
outp.emplace_back(std::move(clpath));
outp.back().rotation(rotation);
outp.back().translation({offs.x(), offs.y()});
outp.back().binId(arrpoly.bed_idx);
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());
// Create Item from Arrangeable
auto process_arrangeable = [](const ArrangePolygon &arrpoly,
std::vector<Item> & outp)
{
Polygon p = arrpoly.poly.contour;
const Vec2crd &offs = arrpoly.translation;
double rotation = arrpoly.rotation;
if (p.is_counter_clockwise()) p.reverse();
clppr::Polygon clpath(Slic3rMultiPoint_to_ClipperPath(p));
if (!clpath.Contour.empty()) {
auto firstp = clpath.Contour.front();
clpath.Contour.emplace_back(firstp);
}
outp.emplace_back(std::move(clpath));
outp.back().rotation(rotation);
outp.back().translation({offs.x(), offs.y()});
outp.back().binId(arrpoly.bed_idx);
outp.back().priority(arrpoly.priority);
};
for (ArrangePolygon &arrangeable : arrangables)
process_arrangeable(arrangeable, items);
@ -649,45 +595,10 @@ void arrange(ArrangePolygons & arrangables,
for (Item &itm : fixeditems) itm.inflate(scaled(-2. * EPSILON));
auto &cfn = stopcondition;
auto &pri = progressind;
auto &cfn = params.stopcondition;
auto &pri = params.progressind;
switch (bedhint.get_type()) {
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;
}
}
_arrange(items, fixeditems, to_nestbin(bed), params, pri, cfn);
for(size_t i = 0; i < items.size(); ++i) {
clppr::IntPoint tr = items[i].translation();
@ -697,15 +608,10 @@ void arrange(ArrangePolygons & arrangables,
}
}
// Arrange, without the fixed items (excludes)
void arrange(ArrangePolygons & inp,
coord_t min_d,
const BedShapeHint & bedhint,
std::function<void(unsigned)> prfn,
std::function<bool()> stopfn)
{
arrange(inp, {}, min_d, bedhint, prfn, stopfn);
}
template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const BoundingBox &bed, const ArrangeParams &params);
template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const CircleBed &bed, const ArrangeParams &params);
template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const Polygon &bed, const ArrangeParams &params);
template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const InfiniteBed &bed, const ArrangeParams &params);
} // namespace arr
} // namespace Slic3r

View file

@ -1,12 +1,10 @@
#ifndef MODELARRANGE_HPP
#define MODELARRANGE_HPP
#ifndef ARRANGE_HPP
#define ARRANGE_HPP
#include "ExPolygon.hpp"
#include "BoundingBox.hpp"
namespace Slic3r {
namespace arrangement {
namespace Slic3r { namespace arrangement {
/// A geometry abstraction for a circular print bed. Similarly to BoundingBox.
class CircleBed {
@ -15,96 +13,16 @@ class CircleBed {
public:
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 const Point& center() const { return center_; }
inline operator bool() { return !std::isnan(radius_); }
};
/// Representing an unbounded bed.
struct InfiniteBed { Point center; };
/// Types of print bed shapes.
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;
}
struct InfiniteBed {
Point center;
explicit InfiniteBed(const Point &p = {0, 0}): center{p} {}
};
/// 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
Vec2crd translation{0, 0}; /// The translation of the poly
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 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
std::function<void(const ArrangePolygon&)> setter = nullptr;
@ -140,6 +63,30 @@ struct 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.
*
@ -150,33 +97,23 @@ using ArrangePolygons = std::vector<ArrangePolygon>;
* \param items Input vector of ArrangePolygons. The transformation, rotation
* and bin_idx fields will be changed after the call finished and can be used
* 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,
coord_t min_obj_distance,
const BedShapeHint & bedhint,
std::function<void(unsigned)> progressind = nullptr,
std::function<bool(void)> stopcondition = nullptr);
template<class TBed> void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const TBed &bed, const ArrangeParams &params = {});
/// Same as the previous, only that it takes unmovable items as an
/// additional argument. Those will be considered as already arranged objects.
void arrange(ArrangePolygons & items,
const ArrangePolygons & excludes,
coord_t min_obj_distance,
const BedShapeHint & bedhint,
std::function<void(unsigned)> progressind = nullptr,
std::function<bool(void)> stopcondition = nullptr);
// A dispatch function that determines the bed shape from a set of points.
template<> void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const Points &bed, const ArrangeParams &params);
extern template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const BoundingBox &bed, const ArrangeParams &params);
extern template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const CircleBed &bed, const ArrangeParams &params);
extern template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const Polygon &bed, const ArrangeParams &params);
extern template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const InfiniteBed &bed, const ArrangeParams &params);
inline void arrange(ArrangePolygons &items, const Points &bed, const ArrangeParams &params = {}) { arrange(items, {}, bed, params); }
inline void arrange(ArrangePolygons &items, const BoundingBox &bed, const ArrangeParams &params = {}) { arrange(items, {}, bed, params); }
inline void arrange(ArrangePolygons &items, const CircleBed &bed, const ArrangeParams &params = {}) { arrange(items, {}, bed, params); }
inline void arrange(ArrangePolygons &items, const Polygon &bed, const ArrangeParams &params = {}) { arrange(items, {}, bed, params); }
inline void arrange(ArrangePolygons &items, const InfiniteBed &bed, const ArrangeParams &params = {}) { arrange(items, {}, bed, params); }
}} // namespace Slic3r::arrangement
} // arr
} // Slic3r
#endif // MODELARRANGE_HPP

View file

@ -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);
}
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
// Serialization through the Cereal library

View file

@ -77,6 +77,8 @@ add_library(libslic3r STATIC
Format/PRUS.hpp
Format/STL.cpp
Format/STL.hpp
Format/SL1.hpp
Format/SL1.cpp
GCode/Analyzer.cpp
GCode/Analyzer.hpp
GCode/ThumbnailData.cpp
@ -120,6 +122,8 @@ add_library(libslic3r STATIC
Line.hpp
Model.cpp
Model.hpp
ModelArrange.hpp
ModelArrange.cpp
CustomGCode.cpp
CustomGCode.hpp
Arrange.hpp
@ -160,6 +164,8 @@ add_library(libslic3r STATIC
SLAPrint.hpp
Slicing.cpp
Slicing.hpp
SlicesToTriangleMesh.hpp
SlicesToTriangleMesh.cpp
SlicingAdaptive.cpp
SlicingAdaptive.hpp
SupportMaterial.cpp
@ -175,6 +181,8 @@ add_library(libslic3r STATIC
Tesselate.hpp
TriangleMesh.cpp
TriangleMesh.hpp
TriangulateWall.hpp
TriangulateWall.cpp
utils.cpp
Utils.hpp
Time.cpp
@ -189,6 +197,7 @@ add_library(libslic3r STATIC
SimplifyMesh.hpp
SimplifyMeshImpl.hpp
SimplifyMesh.cpp
MarchingSquares.hpp
${OpenVDBUtils_SOURCES}
SLA/Common.hpp
SLA/Common.cpp
@ -206,10 +215,11 @@ add_library(libslic3r STATIC
SLA/Rotfinder.cpp
SLA/BoostAdapter.hpp
SLA/SpatIndex.hpp
SLA/Raster.hpp
SLA/Raster.cpp
SLA/RasterWriter.hpp
SLA/RasterWriter.cpp
SLA/RasterBase.hpp
SLA/RasterBase.cpp
SLA/AGGRaster.hpp
SLA/RasterToPolygons.hpp
SLA/RasterToPolygons.cpp
SLA/ConcaveHull.hpp
SLA/ConcaveHull.cpp
SLA/Hollowing.hpp
@ -262,7 +272,8 @@ endif ()
encoding_check(libslic3r)
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
libnest2d
admesh

View 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 &param : 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

View 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

View file

@ -11,6 +11,7 @@
#include "libslic3r.h"
#include "Point.hpp"
#include "BoundingBox.hpp"
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.
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;
// 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
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
template<class T, class I>
template<class T, class I, class = IntegerOnly<I>>
inline std::vector<T> linspace_vector(const ArithmeticOnly<T> &start,
const T &stop,
const IntegerOnly<I> &n)
const I &n)
{
std::vector<T> vals(n, T());

View 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

View file

@ -1,4 +1,5 @@
#include "Model.hpp"
#include "ModelArrange.hpp"
#include "Geometry.hpp"
#include "MTUtils.hpp"
@ -355,116 +356,6 @@ TriangleMesh Model::mesh() const
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)
{
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) {
const auto volume_matrix = volume->get_matrix();
volume->m_supported_facets.clear();
if (! volume->is_model_part()) {
// Modifiers are not cut, but we still need to add the instance transformation
// to the modifier volume transformation to preserve their shape properly.
@ -1848,6 +1741,41 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
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
// 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)
@ -1911,6 +1839,16 @@ bool model_volume_list_changed(const ModelObject &model_object_old, const ModelO
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)
{
for (const ModelObject *model_object : model.objects)
@ -1991,6 +1929,7 @@ void check_model_ids_equal(const Model &model1, const Model &model2)
}
}
}
#endif /* NDEBUG */
}

View file

@ -19,6 +19,7 @@
#include <string>
#include <utility>
#include <vector>
#include <chrono>
namespace cereal {
class BinaryInputArchive;
@ -214,8 +215,8 @@ public:
when user expects that. */
Vec3d origin_translation;
Model* get_model() { return m_model; };
const Model* get_model() const { return m_model; };
Model* get_model() { return m_model; }
const Model* get_model() const { return m_model; }
ModelVolume* add_volume(const TriangleMesh &mesh);
ModelVolume* add_volume(TriangleMesh &&mesh);
@ -391,6 +392,34 @@ enum class ModelVolumeType : int {
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.
// ModelVolume instances are owned by a ModelObject.
class ModelVolume final : public ObjectBase
@ -421,8 +450,11 @@ public:
// overriding the global Slic3r settings and the ModelObject settings.
ModelConfig config;
// List of mesh facets to be supported/unsupported.
FacetsAnnotation m_supported_facets;
// 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; }
void set_type(const ModelVolumeType t) { m_type = t; }
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.
ModelVolume(ModelObject *object, const ModelVolume &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() == other.id() && this->config.id() == other.config.id());
@ -565,6 +599,8 @@ private:
if (mesh.stl.stats.number_of_facets > 1)
calculate_convex_hull();
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;
@ -802,11 +838,9 @@ public:
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); }
TriangleMesh mesh() const;
bool arrange_objects(coordf_t dist, const BoundingBoxf* bb = NULL);
// 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;
void convert_multipart_object(unsigned int max_extruders);
@ -822,7 +856,7 @@ public:
std::string propose_export_file_name_and_path(const std::string &new_extension) const;
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 update_links_bottom_up_recursive();
@ -831,7 +865,7 @@ private:
template<class Archive> void serialize(Archive &ar) {
Internal::StaticSerializationWrapper<ModelWipeTower> wipe_tower_wrapper(wipe_tower);
ar(materials, objects, wipe_tower_wrapper);
}
}
};
#undef OBJECTBASE_DERIVED_COPY_MOVE_CLONE
@ -849,6 +883,10 @@ extern bool model_object_list_extended(const Model &model_old, const Model &mode
// than the old ModelObject.
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.
// Either the model cannot be loaded, or a SLA printer has to be activated.
extern bool model_has_multi_part_objects(const Model &model);

View 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

View 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 &params,
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 &params,
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 &params,
VirtualBedFn vfn = throw_if_out_of_bed)
{
duplicate_objects(model, copies_num);
arrange_objects(model, bed, params, vfn);
}
}
#endif // MODELARRANGE_HPP

View file

@ -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 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, const Point &center);
@ -288,6 +289,72 @@ private:
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
// start Boost

View file

@ -48,12 +48,12 @@ int64_t Polygon::area2x() const
}
*/
double Polygon::area() const
double Polygon::area(const Points &points)
{
size_t n = points.size();
if (n < 3)
return 0.;
double a = 0.;
for (size_t i = 0, j = n - 1; i < n; ++i) {
a += ((double)points[j](0) + (double)points[i](0)) * ((double)points[i](1) - (double)points[j](1));
@ -62,6 +62,11 @@ double Polygon::area() const
return 0.5 * a;
}
double Polygon::area() const
{
return Polygon::area(points);
}
bool Polygon::is_counter_clockwise() const
{
return ClipperLib::Orientation(Slic3rMultiPoint_to_ClipperPath(*this));

View file

@ -22,6 +22,7 @@ public:
const Point& operator[](Points::size_type idx) const { return this->points[idx]; }
Polygon() {}
virtual ~Polygon() = default;
explicit Polygon(const Points &points) : MultiPoint(points) {}
Polygon(std::initializer_list<Point> points) : MultiPoint(points) {}
Polygon(const Polygon &other) : MultiPoint(other.points) {}
@ -46,7 +47,8 @@ public:
// Split a closed polygon into an open polyline, with the split point duplicated at both ends.
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); }
static double area(const Points &pts);
double area() const;
bool is_counter_clockwise() const;
bool is_clockwise() const;

View file

@ -404,6 +404,7 @@ static inline void model_volume_list_copy_configs(ModelObject &model_object_dst,
// Copy the ModelVolume data.
mv_dst.name = mv_src.name;
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?
// mv_dst.m_material_id = mv_src.m_material_id;
++ 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.
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.
this->call_cancel_callback();
update_apply_status(false);
@ -862,8 +863,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
for (auto it = range.first; it != range.second; ++ it)
update_apply_status(it->print_object->invalidate_step(posSupportMaterial));
// Copy just the support volumes.
model_volume_list_update_supports(model_object, model_object_new);
if (support_enforcers_differ || support_blockers_differ) {
// Copy just the support volumes.
model_volume_list_update_supports(model_object, model_object_new);
}
}
if (! model_parts_differ && ! modifiers_differ) {
// Synchronize Object's 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?
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);

View file

@ -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_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:
// to be called from Print only.
friend class Print;

View file

@ -3109,6 +3109,42 @@ DynamicPrintConfig* DynamicPrintConfig::new_from_defaults_keys(const std::vector
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()
{
if (this->has("extruder")) {
@ -3179,22 +3215,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.
std::string FullPrintConfig::validate()
{
@ -3604,8 +3624,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>
CEREAL_REGISTER_TYPE(Slic3r::DynamicPrintConfig)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::DynamicConfig, Slic3r::DynamicPrintConfig)

View file

@ -212,6 +212,9 @@ extern const PrintConfigDef print_config_def;
class StaticPrintConfig;
PrinterTechnology printer_technology(const ConfigBase &cfg);
double min_object_distance(const ConfigBase &cfg);
// Slic3r dynamic configuration, used to override the configuration
// per object, per modification volume or per printing material.
// The dynamic configuration is also used to store user modifications of the print global parameters,
@ -778,8 +781,6 @@ class PrintConfig : public MachineEnvelopeConfig, public GCodeConfig
STATIC_PRINT_CONFIG_CACHE_DERIVED(PrintConfig)
PrintConfig() : MachineEnvelopeConfig(0), GCodeConfig(0) { initialize_cache(); *this = s_cache_PrintConfig.defaults(); }
public:
double min_object_distance() const;
static double min_object_distance(const ConfigBase *config);
ConfigOptionBool avoid_crossing_perimeters;
ConfigOptionPoints bed_shape;
@ -1334,6 +1335,10 @@ private:
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
// Serialization through the Cereal library

View file

@ -2665,4 +2665,168 @@ void PrintObject::_generate_support_material()
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

View 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

View file

@ -303,8 +303,10 @@ EigenMesh3D::query_ray_hit(const Vec3d &s, const Vec3d &dir) const
ret.m_t = double(hit.t);
ret.m_dir = dir;
ret.m_source = s;
if(!std::isinf(hit.t) && !std::isnan(hit.t))
if(!std::isinf(hit.t) && !std::isnan(hit.t)) {
ret.m_normal = this->normal_by_face_id(hit.id);
ret.m_face_id = hit.id;
}
return ret;
}
@ -340,8 +342,10 @@ EigenMesh3D::query_ray_hits(const Vec3d &s, const Vec3d &dir) const
outs.back().m_t = double(hit.t);
outs.back().m_dir = dir;
outs.back().m_source = s;
if(!std::isinf(hit.t) && !std::isnan(hit.t))
if(!std::isinf(hit.t) && !std::isnan(hit.t)) {
outs.back().m_normal = this->normal_by_face_id(hit.id);
outs.back().m_face_id = hit.id;
}
}
return outs;

View file

@ -55,6 +55,7 @@ public:
class hit_result {
// m_t holds a distance from m_source to the intersection.
double m_t = infty();
int m_face_id = -1;
const EigenMesh3D *m_mesh = nullptr;
Vec3d m_dir;
Vec3d m_source;
@ -74,6 +75,7 @@ public:
inline const Vec3d& direction() const { return m_dir; }
inline const Vec3d& source() const { return m_source; }
inline Vec3d position() const { return m_source + m_dir * m_t; }
inline int face() const { return m_face_id; }
inline bool is_valid() const { return m_mesh != nullptr; }
inline bool is_hit() const { return !std::isinf(m_t); }

View file

@ -11,6 +11,8 @@
#include "Tesselate.hpp"
#include "MTUtils.hpp"
#include "TriangulateWall.hpp"
// For debugging:
// #include <fstream>
// #include <libnest2d/tools/benchmark.h>
@ -27,186 +29,27 @@ namespace Slic3r { namespace sla {
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(
const Polygon &lower,
const Polygon &upper,
double lower_z_mm,
double upper_z_mm,
double offset_difference_mm,
ThrowOnCancel thr = [] {})
double upper_z_mm)
{
Wall w = triangulate_wall(lower, upper, lower_z_mm, upper_z_mm);
Contour3D ret;
if(upper.points.size() < 3 || lower.size() < 3) return ret;
// 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);
ret.points = std::move(w.first);
ret.faces3 = std::move(w.second);
return ret;
}
// Same as walls() but with identical higher and lower polygons.
Contour3D inline straight_walls(const Polygon &plate,
double lo_z,
double hi_z,
ThrowOnCancel thr)
double hi_z)
{
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
@ -534,10 +377,8 @@ bool add_cavity(Contour3D &pad, ExPolygon &top_poly, const PadConfig3D &cfg,
top_poly = pdiff.front();
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,
offset_difference, thr));
pad.merge(walls(inner_base.contour, middle_base.contour, z_min, z_max));
thr();
pad.merge(triangulate_expolygon_3d(inner_base, z_min, NORMALS_UP));
return true;
@ -555,17 +396,17 @@ Contour3D create_outer_pad_geometry(const ExPolygons & skeleton,
offset_contour_only(pad_part, -scaled(cfg.bottom_offset()));
if (bottom_poly.empty()) continue;
thr();
double z_min = -cfg.height, z_max = 0;
ret.merge(walls(top_poly.contour, bottom_poly.contour, z_max, z_min,
cfg.bottom_offset(), thr));
ret.merge(walls(top_poly.contour, bottom_poly.contour, z_max, z_min));
if (cfg.wing_height > 0. && add_cavity(ret, top_poly, cfg, thr))
z_max = -cfg.wing_height;
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(top_poly, NORMALS_UP));
}
@ -581,11 +422,12 @@ Contour3D create_inner_pad_geometry(const ExPolygons & skeleton,
double z_max = 0., z_min = -cfg.height;
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)
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_max, NORMALS_UP));
}

View file

@ -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

View file

@ -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

View 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

View 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

View 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

View 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

View file

@ -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 &param : 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

View file

@ -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

View file

@ -227,6 +227,8 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
m_material_config.apply_only(config, material_diff, true);
// Handle changes to object config defaults
m_default_object_config.apply_only(config, object_diff, true);
if (m_printer) m_printer->apply(m_printer_config);
struct ModelObjectStatus {
enum Status {
@ -482,7 +484,6 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
}
if(m_objects.empty()) {
m_printer.reset();
m_printer_input = {};
m_print_statistics = {};
}
@ -657,6 +658,12 @@ std::string SLAPrint::validate() const
return "";
}
void SLAPrint::set_printer(SLAPrinter *arch)
{
invalidate_step(slapsRasterize);
m_printer = arch;
}
bool SLAPrint::invalidate_step(SLAPrintStep 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
// 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...
std::vector<SLAPrintObjectStep> level1_obj_steps = {
@ -729,7 +736,7 @@ void SLAPrint::process()
throw_if_canceled();
po->set_done(step);
}
incr = printsteps.progressrange(step);
}
}
@ -754,7 +761,7 @@ void SLAPrint::process()
throw_if_canceled();
set_done(currentstep);
}
st += printsteps.progressrange(currentstep);
}
@ -855,36 +862,6 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt
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.
bool SLAPrint::is_step_done(SLAPrintObjectStep step) const
{

View file

@ -3,7 +3,7 @@
#include <mutex>
#include "PrintBase.hpp"
#include "SLA/RasterWriter.hpp"
#include "SLA/RasterBase.hpp"
#include "SLA/SupportTree.hpp"
#include "Point.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.
*
@ -403,18 +428,6 @@ public:
// 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); }
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 SLAPrintConfig& print_config() const { return m_print_config; }
@ -445,14 +458,15 @@ public:
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);
}
friend class SLAPrint::Steps;
public:
explicit PrintLayer(coord_t lvl) : m_level(lvl) {}
// for being sorted in their container (see m_printer_input)
@ -474,8 +488,11 @@ public:
// The aggregated and leveled print records from various objects.
// TODO: use this structure for the preview in the future.
const std::vector<PrintLayer>& print_layers() const { return m_printer_input; }
void set_printer(SLAPrinter *archiver);
private:
// Implement same logic as in SLAPrintObject
bool invalidate_step(SLAPrintStep st);
@ -491,13 +508,13 @@ private:
std::vector<bool> m_stepmask;
// Ready-made data for rasterization.
std::vector<PrintLayer> m_printer_input;
// The printer itself
std::unique_ptr<sla::RasterWriter> m_printer;
std::vector<PrintLayer> m_printer_input;
// The archive object which collects the raster images after slicing
SLAPrinter *m_printer = nullptr;
// Estimated print time, material consumed.
SLAPrintStatistics m_print_statistics;
SLAPrintStatistics m_print_statistics;
class StatusReporter
{
@ -512,15 +529,6 @@ private:
double status() const { return m_st; }
} 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;
};

View file

@ -816,16 +816,7 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
// Rasterizing the model objects, and their supports
void SLAPrint::Steps::rasterize()
{
if(canceled()) 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);
if(canceled() || !m_print->m_printer) return;
// coefficient to map the rasterization state (0-99) to the allocated
// portion (slot) of the process state
@ -837,7 +828,7 @@ void SLAPrint::Steps::rasterize()
// pst: previous state
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();
sla::ccr::SpinningMutex slck;
@ -845,20 +836,14 @@ void SLAPrint::Steps::rasterize()
// procedure to process one height level. This will run in parallel
auto lvlfn =
[this, &slck, &printer, increment, &dstatus, &pst]
(PrintLayer& printlayer, size_t idx)
[this, &slck, increment, &dstatus, &pst]
(sla::RasterBase& raster, size_t idx)
{
PrintLayer& printlayer = m_print->m_printer_input[idx];
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())
printer.draw_polygon(poly, level_id);
// Finish the layer for later saving it.
printer.finish_layer(level_id);
for (const ClipperLib::Polygon& poly : printlayer.transformed_slices())
raster.draw(poly);
// Status indication guarded with the spinlock
{
@ -875,24 +860,8 @@ void SLAPrint::Steps::rasterize()
// last minute escape
if(canceled()) return;
// Sequential version (for testing)
// for(unsigned l = 0; l < lvlcnt; ++l) lvlfn(l);
// Print all the layers in parallel
sla::ccr::enumerate(printer_input.begin(), printer_input.end(), 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);
m_print->m_printer->draw_layers(m_print->m_printer_input.size(), lvlfn);
}
std::string SLAPrint::Steps::label(SLAPrintObjectStep step)

View file

@ -46,7 +46,7 @@ private:
void apply_printer_corrections(SLAPrintObject &po, SliceOrigin o);
public:
Steps(SLAPrint *print);
explicit Steps(SLAPrint *print);
void hollow_model(SLAPrintObject &po);
void drill_holes (SLAPrintObject &po);

View 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

View 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

View file

@ -971,6 +971,10 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
std::vector<ExPolygons> enforcers = object.slice_support_enforcers();
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.
MyLayersPtr contact_out;
@ -1097,10 +1101,10 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
if (! enforcers.empty()) {
// Apply the "support enforcers".
//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()) {
// 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));
if (! new_contacts.empty()) {
if (diff_polygons.empty())
@ -1111,19 +1115,26 @@ 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())
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
{
::Slic3r::SVG svg(debug_out_path("support-top-contacts-raw-run%d-layer%d-region%d.svg",
iRun, layer_id,
std::find_if(layer.regions.begin(), layer.regions.end(), [layerm](const LayerRegion* other){return other == layerm;}) - layer.regions.begin()),
std::find_if(layer.regions.begin(), layer.regions.end(), [layerm](const LayerRegion* other){return other == layerm;}) - layer.regions.begin()),
get_extents(diff_polygons));
Slic3r::ExPolygons expolys = union_ex(diff_polygons, false);
svg.draw(expolys);

View 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

View 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

View file

@ -17,90 +17,14 @@
namespace Slic3r {
class Zipper::Impl {
class Zipper::Impl: public MZ_Archive {
public:
mz_zip_archive arch;
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
{
return L("Error with zip archive") + " " + m_zipname + ": " +
get_errorstr(arch.m_last_error) + "!";
get_errorstr() + "!";
}
SLIC3R_NORETURN void blow_up() const
@ -167,7 +91,7 @@ void Zipper::add_entry(const std::string &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;

View file

@ -28,7 +28,7 @@ public:
// Will blow up in a runtime exception if the file cannot be created.
explicit Zipper(const std::string& zipfname,
e_compression level = NO_COMPRESSION);
e_compression level = FAST_COMPRESSION);
~Zipper();
// 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.
/// 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
// within the zip file is the entry created with the add_entry method.

View file

@ -17,6 +17,7 @@
#include <vector>
#include <cassert>
#include <cmath>
#include <type_traits>
#include "Technologies.hpp"
#include "Semver.hpp"
@ -248,6 +249,37 @@ static inline bool is_approx(Number value, Number test_value)
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
#endif

View file

@ -1,9 +1,17 @@
#include <exception>
#include "miniz_extension.hpp"
#if defined(_MSC_VER) || defined(__MINGW64__)
#include "boost/nowide/cstdio.hpp"
#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 {
@ -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_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

View file

@ -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_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

View file

@ -31,9 +31,10 @@ set(SLIC3R_GUI_SOURCES
GUI/GLCanvas3DManager.cpp
GUI/Selection.hpp
GUI/Selection.cpp
GUI/Gizmos/GLGizmos.hpp
GUI/Gizmos/GLGizmosManager.cpp
GUI/Gizmos/GLGizmosManager.hpp
GUI/Gizmos/GLGizmosCommon.cpp
GUI/Gizmos/GLGizmosCommon.hpp
GUI/Gizmos/GLGizmoBase.cpp
GUI/Gizmos/GLGizmoBase.hpp
GUI/Gizmos/GLGizmoMove.cpp
@ -44,6 +45,8 @@ set(SLIC3R_GUI_SOURCES
GUI/Gizmos/GLGizmoScale.hpp
GUI/Gizmos/GLGizmoSlaSupports.cpp
GUI/Gizmos/GLGizmoSlaSupports.hpp
GUI/Gizmos/GLGizmoFdmSupports.cpp
GUI/Gizmos/GLGizmoFdmSupports.hpp
GUI/Gizmos/GLGizmoFlatten.cpp
GUI/Gizmos/GLGizmoFlatten.hpp
GUI/Gizmos/GLGizmoCut.cpp
@ -139,12 +142,19 @@ set(SLIC3R_GUI_SOURCES
GUI/UpdateDialogs.hpp
GUI/FirmwareDialog.cpp
GUI/FirmwareDialog.hpp
GUI/ProgressIndicator.hpp
GUI/ProgressStatusBar.hpp
GUI/ProgressStatusBar.cpp
GUI/PrintHostDialogs.cpp
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.hpp
GUI/DoubleSlider.cpp
@ -174,6 +184,8 @@ set(SLIC3R_GUI_SOURCES
Utils/HexFile.cpp
Utils/HexFile.hpp
Utils/Thread.hpp
Utils/SLAImport.hpp
Utils/SLAImport.cpp
)
if (APPLE)
@ -192,7 +204,7 @@ add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES})
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} rt)
if(APPLE)
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY})

View file

@ -259,7 +259,8 @@ Point Bed3D::point_projection(const Point& point) const
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;
@ -270,9 +271,9 @@ void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool sho
switch (m_type)
{
case System: { render_system(canvas, bottom); break; }
case System: { render_system(canvas, bottom, show_texture); break; }
default:
case Custom: { render_custom(canvas, bottom); break; }
case Custom: { render_custom(canvas, bottom, show_texture); break; }
}
glsafe(::glDisable(GL_DEPTH_TEST));
@ -384,12 +385,13 @@ void Bed3D::render_axes() const
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)
render_model();
render_texture(bottom, canvas);
if (show_texture)
render_texture(bottom, canvas);
}
void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
@ -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())
{
@ -575,7 +577,8 @@ void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom) const
if (!bottom)
render_model();
render_texture(bottom, canvas);
if (show_texture)
render_texture(bottom, canvas);
}
void Bed3D::render_default(bool bottom) const

View file

@ -103,11 +103,15 @@ public:
// 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);
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;
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:
void calc_bounding_boxes() const;
@ -115,10 +119,10 @@ private:
void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox);
std::tuple<EType, std::string, std::string> detect_type(const Pointfs& shape) 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_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 reset();
};

View file

@ -60,7 +60,7 @@ public:
boost::trim_all(key_trimmed);
assert(key_trimmed == key);
assert(! key_trimmed.empty());
#endif _NDEBUG
#endif // _NDEBUG
std::string &old = m_storage[section][key];
if (old != value) {
old = value;

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