Merge branch 'master_27x'
1
.gitignore
vendored
@ -12,7 +12,6 @@ xs/MANIFEST.bak
|
||||
xs/assertlib*
|
||||
.init_bundle.ini
|
||||
.vs/*
|
||||
local-lib
|
||||
/src/TAGS
|
||||
/.vscode/
|
||||
build-linux/*
|
||||
|
132
Build.PL
@ -1,132 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
print "This script is currently used for installing Perl dependenices for running\n";
|
||||
print "the libslic3r unit / integration tests through Perl prove.\n";
|
||||
print "If you don't plan to run the unit / integration tests, you don't need to\n";
|
||||
print "install these dependencies to build and run PrusaSlicer.\n";
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Config;
|
||||
use File::Spec;
|
||||
|
||||
my %prereqs = qw(
|
||||
Devel::CheckLib 0
|
||||
ExtUtils::MakeMaker 6.80
|
||||
ExtUtils::ParseXS 3.22
|
||||
ExtUtils::XSpp 0
|
||||
ExtUtils::XSpp::Cmd 0
|
||||
ExtUtils::CppGuess 0
|
||||
ExtUtils::Typemaps 0
|
||||
ExtUtils::Typemaps::Basic 0
|
||||
File::Basename 0
|
||||
File::Spec 0
|
||||
Getopt::Long 0
|
||||
Module::Build::WithXSpp 0.14
|
||||
Moo 1.003001
|
||||
POSIX 0
|
||||
Scalar::Util 0
|
||||
Test::More 0
|
||||
IO::Scalar 0
|
||||
Time::HiRes 0
|
||||
);
|
||||
my %recommends = qw(
|
||||
Class::XSAccessor 0
|
||||
Test::Harness 0
|
||||
);
|
||||
|
||||
my $sudo = grep { $_ eq '--sudo' } @ARGV;
|
||||
my $nolocal = grep { $_ eq '--nolocal' } @ARGV;
|
||||
|
||||
my @missing_prereqs = ();
|
||||
if ($ENV{SLIC3R_NO_AUTO}) {
|
||||
foreach my $module (sort keys %prereqs) {
|
||||
my $version = $prereqs{$module};
|
||||
next if eval "use $module $version; 1";
|
||||
push @missing_prereqs, $module if exists $prereqs{$module};
|
||||
print "Missing prerequisite $module $version\n";
|
||||
}
|
||||
foreach my $module (sort keys %recommends) {
|
||||
my $version = $recommends{$module};
|
||||
next if eval "use $module $version; 1";
|
||||
print "Missing optional $module $version\n";
|
||||
}
|
||||
} else {
|
||||
my @try = (
|
||||
$ENV{CPANM} // (),
|
||||
File::Spec->catfile($Config{sitebin}, 'cpanm'),
|
||||
File::Spec->catfile($Config{installscript}, 'cpanm'),
|
||||
);
|
||||
|
||||
my $cpanm;
|
||||
foreach my $path (@try) {
|
||||
if (-e $path) { # don't use -x because it fails on Windows
|
||||
$cpanm = $path;
|
||||
last;
|
||||
}
|
||||
}
|
||||
if (!$cpanm) {
|
||||
if ($^O =~ /^(?:darwin|linux)$/ && system(qw(which cpanm)) == 0) {
|
||||
$cpanm = 'cpanm';
|
||||
}
|
||||
}
|
||||
die <<'EOF'
|
||||
cpanm was not found. Please install it before running this script.
|
||||
|
||||
There are several ways to install cpanm, try one of these:
|
||||
|
||||
apt-get install cpanminus
|
||||
curl -L http://cpanmin.us | perl - --sudo App::cpanminus
|
||||
cpan App::cpanminus
|
||||
|
||||
If it is installed in a non-standard location you can do:
|
||||
|
||||
CPANM=/path/to/cpanm perl Build.PL
|
||||
|
||||
EOF
|
||||
if !$cpanm;
|
||||
my @cpanm_args = ();
|
||||
push @cpanm_args, "--sudo" if $sudo;
|
||||
|
||||
# install local::lib without --local-lib otherwise it's not usable afterwards
|
||||
if (!eval "use local::lib qw(local-lib); 1") {
|
||||
my $res = system $cpanm, @cpanm_args, 'local::lib';
|
||||
warn "Warning: local::lib is required. You might need to run the `cpanm --sudo local::lib` command in order to install it.\n"
|
||||
if $res != 0;
|
||||
}
|
||||
|
||||
push @cpanm_args, ('--local-lib', 'local-lib') if ! $nolocal;
|
||||
|
||||
# make sure our cpanm is updated (old ones don't support the ~ syntax)
|
||||
system $cpanm, @cpanm_args, 'App::cpanminus';
|
||||
|
||||
my %modules = (%prereqs, %recommends);
|
||||
foreach my $module (sort keys %modules) {
|
||||
my $version = $modules{$module};
|
||||
my @cmd = ($cpanm, @cpanm_args);
|
||||
|
||||
# temporary workaround for upstream bug in test
|
||||
push @cmd, '--notest'
|
||||
if $module =~ /^(?:OpenGL|Test::Harness)$/;
|
||||
|
||||
push @cmd, "$module~$version";
|
||||
|
||||
my $res = system @cmd;
|
||||
if ($res != 0) {
|
||||
if (exists $prereqs{$module}) {
|
||||
push @missing_prereqs, $module;
|
||||
} else {
|
||||
printf "Don't worry, this module is optional.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print "\n";
|
||||
print "In the next step, you need to build the PrusaSlicer C++ library.\n";
|
||||
print "1) Create a build directory and change to it\n";
|
||||
print "2) run cmake .. -DCMAKE_BUILD_TYPE=Release\n";
|
||||
print "3) run make\n";
|
||||
print "4) to execute the automatic tests, run ctest --verbose\n";
|
||||
__END__
|
@ -39,7 +39,6 @@ option(SLIC3R_FHS "Assume PrusaSlicer is to be installed in a FHS
|
||||
option(SLIC3R_PCH "Use precompiled headers" 1)
|
||||
option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
|
||||
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
|
||||
option(SLIC3R_PERL_XS "Compile XS Perl module and enable Perl unit and integration tests" 0)
|
||||
option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
|
||||
option(SLIC3R_UBSAN "Enable UBSan on Clang and GCC" 0)
|
||||
option(SLIC3R_ENABLE_FORMAT_STEP "Enable compilation of STEP file support" ON)
|
||||
@ -83,7 +82,6 @@ option(SLIC3R_BUILD_TESTS "Build unit tests" ON)
|
||||
|
||||
if (IS_CROSS_COMPILE)
|
||||
message("Detected cross compilation setup. Tests and encoding checks will be forcedly disabled!")
|
||||
set(SLIC3R_PERL_XS OFF CACHE BOOL "" FORCE)
|
||||
set(SLIC3R_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||
endif ()
|
||||
|
||||
@ -176,10 +174,6 @@ if(NOT WIN32)
|
||||
add_compile_options("$<$<CONFIG:DEBUG>:-DDEBUG>")
|
||||
endif()
|
||||
|
||||
# To be able to link libslic3r with the Perl XS module.
|
||||
# Once we get rid of Perl and libslic3r is linked statically, we can get rid of -fPIC
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
# WIN10SDK_PATH is used to point CMake to the WIN10 SDK installation directory.
|
||||
# We pick it from environment if it is not defined in another way
|
||||
if(WIN32)
|
||||
@ -621,13 +615,6 @@ set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT P
|
||||
|
||||
add_dependencies(gettext_make_pot hintsToPot)
|
||||
|
||||
# Perl bindings, currently only used for the unit / integration tests of libslic3r.
|
||||
# Also runs the unit / integration tests.
|
||||
#FIXME Port the tests into C++ to finally get rid of the Perl!
|
||||
if (SLIC3R_PERL_XS)
|
||||
add_subdirectory(xs)
|
||||
endif ()
|
||||
|
||||
if(SLIC3R_BUILD_SANDBOXES)
|
||||
add_subdirectory(sandboxes)
|
||||
endif()
|
||||
|
@ -1,103 +0,0 @@
|
||||
{
|
||||
"build_systems":
|
||||
[
|
||||
{
|
||||
"name": "List",
|
||||
//"file_regex": " at ([^-\\s]*) line ([0-9]*)",
|
||||
// "file_regex": " at (D\\:\\/src\\/Slic3r\\/.*?) line ([0-9]*)",
|
||||
"shell_cmd": "ls -l"
|
||||
},
|
||||
{
|
||||
"name": "Run",
|
||||
"working_dir": "$project_path",
|
||||
"file_regex": " at (.*?) line ([0-9]*)",
|
||||
// "shell_cmd": "chdir & perl slic3r.pl --DataDir \"C:\\Users\\Public\\Documents\\Prusa3D\\Slic3r settings MK2\" --gui \"..\\Slic3r-tests\\gap fill torture 20 -rt.stl\""
|
||||
"shell_cmd": "chdir & perl slic3r.pl"
|
||||
},
|
||||
{
|
||||
"name": "full",
|
||||
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
|
||||
"shell_cmd": "chdir & perl Build.pl"
|
||||
},
|
||||
{
|
||||
"name": "xs",
|
||||
"working_dir": "$project_path/build",
|
||||
// for Visual Studio:
|
||||
"file_regex": "^(..[^:]*)\\(([0-9]+)\\)(.*)$",
|
||||
// For GCC:
|
||||
// "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
|
||||
"shell_cmd": "chdir & ninja -j 6 -v",
|
||||
"env": {
|
||||
// "PATH": "C:\\Program Files (x86)\\MSBuild\\12.0\\bin\\amd64;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\BIN\\amd64;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\IDE;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\Tools;%PATH%;c:\\wperl64d\\site\\bin;c:\\wperl64d\\bin",
|
||||
// "PERL_CPANM_HOME": "c:\\wperl64d\\cpanm",
|
||||
// "WXDIR": "D:\\src-perl\\wxWidgets-3.0.3-beta1",
|
||||
// "BOOST_DIR": "D:\\src-perl\\boost_1_61_0",
|
||||
// "BOOST_INCLUDEDIR": "D:\\src-perl\\boost_1_61_0",
|
||||
// "BOOST_LIBRARYDIR": "D:\\src-perl\\boost_1_61_0\\stage\\x64\\lib",
|
||||
// "SLIC3R_STATIC": "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "xs & run",
|
||||
"working_dir": "$project_path/build",
|
||||
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
|
||||
"shell_cmd": "chdir & ninja -j 6 & cd .. & perl slic3r.pl --gui \"..\\Slic3r-tests\\star3-big2.stl\""
|
||||
},
|
||||
{
|
||||
"name": "Slic3r - clean",
|
||||
"working_dir": "$project_path/build",
|
||||
"file_regex": "^(..[^:]*)(?::|\\()([0-9]+)(?::|\\))(?:([0-9]+):)?\\s*(.*)",
|
||||
"shell_cmd": ["chdir & ninja clean"]
|
||||
},
|
||||
{
|
||||
"name": "run tests",
|
||||
"working_dir": "$project_path/build",
|
||||
// for Visual Studio:
|
||||
"file_regex": "^(..[^:]*)\\(([0-9]+)\\)(.*)$",
|
||||
"shell_cmd": "chdir & ctest --verbose"
|
||||
},
|
||||
{
|
||||
"name": "Clean & Configure",
|
||||
"working_dir": "$project_path",
|
||||
// for Visual Studio:
|
||||
"file_regex": "^(..[^:]*)(?::|\\()([0-9]+)(?::|\\))(?:([0-9]+):)?\\s*(.*)",
|
||||
"shell_cmd": "chdir & rmdir /S /Q build & mkdir build & cd build & cmake -G Ninja .. -DCMAKE_COLOR_MAKEFILE=OFF -DCMAKE_RULE_PROGRESS=OFF -DCMAKE_RULE_MESSAGES=OFF -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "Configure",
|
||||
"working_dir": "$project_path/build",
|
||||
// for Visual Studio:
|
||||
"file_regex": "^(..[^:]*)(?::|\\()([0-9]+)(?::|\\))(?:([0-9]+):)?\\s*(.*)",
|
||||
"shell_cmd": "cmake -G Ninja .. -DCMAKE_COLOR_MAKEFILE=OFF -DCMAKE_RULE_PROGRESS=OFF -DCMAKE_RULE_MESSAGES=OFF -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo"
|
||||
}
|
||||
],
|
||||
"folders":
|
||||
[
|
||||
{
|
||||
"path": ".",
|
||||
// "folder_exclude_patterns": [".svn", "._d", ".metadata", ".settings"],
|
||||
"file_exclude_patterns": ["XS.c", "*.pch", "*.ilk", "*.js" ]
|
||||
}
|
||||
],
|
||||
|
||||
"settings":
|
||||
{
|
||||
"sublimegdb_workingdir": "${folder:${project_path:run}}",
|
||||
// NOTE: You MUST provide --interpreter=mi for the plugin to work
|
||||
// "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi -ex 'target localhost:2345'",
|
||||
// "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi perl --args perl slic3r.pl",
|
||||
// "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi perl --args slic3r.pl ",
|
||||
// "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi -e C:\\Strawberry\\perl\\bin\\perl.exe -s C:\\Strawberry\\perl\\site\\lib\\auto\\Slic3r\\XS\\XS.xs.dll --args perl slic3r.pl -j 1 --gui D:\\src\\Slic3r-tests\\star3-big.stl",
|
||||
"sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi perl.exe --args perl slic3r.pl -j 1 --gui", // D:\\src\\Slic3r-tests\\star3-big.stl",
|
||||
// "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi -x slic3r.gdb",
|
||||
// "arguments": "slic3r -j 1 --gui ../Slic3r-tests/star3-big.stl",
|
||||
// "arguments": "../slic3r.pl -j 1 --gui",
|
||||
// "sublimegdb_exec_cmd": "-exec-continue",
|
||||
|
||||
// Add "pending breakpoints" for symbols that are dynamically loaded from
|
||||
// external shared libraries
|
||||
"debug_ext" : true,
|
||||
"run_after_init": false,
|
||||
"close_views": false
|
||||
}
|
||||
}
|
@ -19,10 +19,7 @@ the [documentation directory](doc/) for more information.
|
||||
|
||||
### What language is it written in?
|
||||
|
||||
All user facing code is written in C++, and some legacy code as well as unit
|
||||
tests are written in Perl. Perl is not required for either development or use
|
||||
of PrusaSlicer.
|
||||
|
||||
All user facing code is written in C++.
|
||||
The slicing core is the `libslic3r` library, which can be built and used in a standalone way.
|
||||
The command line interface is a thin wrapper over `libslic3r`.
|
||||
|
||||
|
@ -1,109 +0,0 @@
|
||||
# Find the wxWidgets module based on the information provided by the Perl Alien::wxWidgets module.
|
||||
|
||||
# Check for the Perl & PerlLib modules
|
||||
include(LibFindMacros)
|
||||
libfind_package(AlienWx Perl)
|
||||
libfind_package(AlienWx PerlLibs)
|
||||
|
||||
if (AlienWx_DEBUG)
|
||||
message(STATUS " AlienWx_FIND_COMPONENTS=${AlienWx_FIND_COMPONENTS}")
|
||||
endif()
|
||||
|
||||
# Execute an Alien::Wx module to find the relevant information regarding
|
||||
# the wxWidgets used by the Perl interpreter.
|
||||
# Perl specific stuff
|
||||
set(AlienWx_TEMP_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/AlienWx_TEMP_INCLUDE.txt)
|
||||
execute_process(
|
||||
COMMAND ${PERL_EXECUTABLE} -e "
|
||||
# Import Perl modules.
|
||||
use strict;
|
||||
use warnings;
|
||||
use Text::ParseWords;
|
||||
|
||||
BEGIN {
|
||||
# CMake sets the environment variables CC and CXX to the detected C compiler.
|
||||
# There is an issue with the Perl ExtUtils::CBuilder, which does not handle whitespaces
|
||||
# in the paths correctly on Windows, so we rather drop the CMake auto-detected paths.
|
||||
delete \$ENV{CC};
|
||||
delete \$ENV{CXX};
|
||||
}
|
||||
|
||||
use Alien::wxWidgets;
|
||||
use ExtUtils::CppGuess;
|
||||
|
||||
# Test for a Visual Studio compiler
|
||||
my \$cpp_guess = ExtUtils::CppGuess->new;
|
||||
my \$mswin = \$^O eq 'MSWin32';
|
||||
my \$msvc = \$cpp_guess->is_msvc;
|
||||
|
||||
# List of wxWidgets components to be used.
|
||||
my @components = split /;/, '${AlienWx_FIND_COMPONENTS}';
|
||||
|
||||
# Query the available data from Alien::wxWidgets.
|
||||
my \$version = Alien::wxWidgets->version;
|
||||
my \$config = Alien::wxWidgets->config;
|
||||
my \$compiler = Alien::wxWidgets->compiler;
|
||||
my \$linker = Alien::wxWidgets->linker;
|
||||
my \$include_path = ' ' . Alien::wxWidgets->include_path;
|
||||
my \$defines = ' ' . Alien::wxWidgets->defines;
|
||||
my \$cflags = Alien::wxWidgets->c_flags;
|
||||
my \$linkflags = Alien::wxWidgets->link_flags;
|
||||
my \$libraries = ' ' . Alien::wxWidgets->libraries(@components);
|
||||
my \$gui_toolkit = Alien::wxWidgets->config->{toolkit};
|
||||
#my @libraries = Alien::wxWidgets->link_libraries(@components);
|
||||
#my @implib = Alien::wxWidgets->import_libraries(@components);
|
||||
#my @shrlib = Alien::wxWidgets->shared_libraries(@components);
|
||||
#my @keys = Alien::wxWidgets->library_keys; # 'gl', 'adv', ...
|
||||
#my \$library_path = Alien::wxWidgets->shared_library_path;
|
||||
#my \$key = Alien::wxWidgets->key;
|
||||
#my \$prefix = Alien::wxWidgets->prefix;
|
||||
|
||||
my \$filename = '${AlienWx_TEMP_INCLUDE}';
|
||||
open(my $fh, '>', \$filename) or die \"Could not open file '\$filename' \$!\";
|
||||
|
||||
# Convert a space separated lists to CMake semicolon separated lists,
|
||||
# escape the backslashes,
|
||||
# export the resulting list to a temp file.
|
||||
sub cmake_set_var {
|
||||
my (\$varname, \$content) = @_;
|
||||
# Remove line separators.
|
||||
\$content =~ s/\\r|\\n//g;
|
||||
# Escape the path separators.
|
||||
\$content =~ s/\\\\/\\\\\\\\\\\\\\\\/g;
|
||||
my @words = shellwords(\$content);
|
||||
print \$fh \"set(AlienWx_\$varname \\\"\" . join(';', @words) . \"\\\")\\n\";
|
||||
}
|
||||
cmake_set_var('VERSION', \$version);
|
||||
\$include_path =~ s/ -I/ /g;
|
||||
cmake_set_var('INCLUDE_DIRS', \$include_path);
|
||||
\$libraries =~ s/ -L/ -LIBPATH:/g if \$msvc;
|
||||
cmake_set_var('LIBRARIES', \$libraries);
|
||||
#cmake_set_var('LIBRARY_DIRS', );
|
||||
#\$defines =~ s/ -D/ /g;
|
||||
cmake_set_var('DEFINITIONS', \$defines);
|
||||
#cmake_set_var('DEFINITIONS_DEBUG', );
|
||||
cmake_set_var('CXX_FLAGS', \$cflags);
|
||||
cmake_set_var('GUI_TOOLKIT', \$gui_toolkit);
|
||||
close \$fh;
|
||||
")
|
||||
include(${AlienWx_TEMP_INCLUDE})
|
||||
file(REMOVE ${AlienWx_TEMP_INCLUDE})
|
||||
unset(AlienWx_TEMP_INCLUDE)
|
||||
|
||||
if (AlienWx_DEBUG)
|
||||
message(STATUS " AlienWx_VERSION = ${AlienWx_VERSION}")
|
||||
message(STATUS " AlienWx_INCLUDE_DIRS = ${AlienWx_INCLUDE_DIRS}")
|
||||
message(STATUS " AlienWx_LIBRARIES = ${AlienWx_LIBRARIES}")
|
||||
message(STATUS " AlienWx_LIBRARY_DIRS = ${AlienWx_LIBRARY_DIRS}")
|
||||
message(STATUS " AlienWx_DEFINITIONS = ${AlienWx_DEFINITIONS}")
|
||||
message(STATUS " AlienWx_DEFINITIONS_DEBUG = ${AlienWx_DEFINITIONS_DEBUG}")
|
||||
message(STATUS " AlienWx_CXX_FLAGS = ${AlienWx_CXX_FLAGS}")
|
||||
message(STATUS " AlienWx_GUI_TOOLKIT = ${AlienWx_GUI_TOOLKIT}")
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package_handle_standard_args(AlienWx
|
||||
REQUIRED_VARS AlienWx_INCLUDE_DIRS AlienWx_LIBRARIES
|
||||
# HANDLE_COMPONENTS
|
||||
VERSION_VAR AlienWx_VERSION)
|
@ -1,88 +0,0 @@
|
||||
# Find the dependencies for linking with the Perl runtime library.
|
||||
|
||||
# Check for the Perl & PerlLib modules
|
||||
include(LibFindMacros)
|
||||
libfind_package(PerlEmbed Perl)
|
||||
libfind_package(PerlEmbed PerlLibs)
|
||||
|
||||
# Execute an Alien::Wx module to find the relevant information regarding
|
||||
# the wxWidgets used by the Perl interpreter.
|
||||
# Perl specific stuff
|
||||
set(PerlEmbed_TEMP_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/PerlEmbed_TEMP_INCLUDE.txt)
|
||||
execute_process(
|
||||
COMMAND ${PERL_EXECUTABLE} -MExtUtils::Embed -e "
|
||||
# Import Perl modules.
|
||||
use strict;
|
||||
use warnings;
|
||||
use Config;
|
||||
use Text::ParseWords;
|
||||
use ExtUtils::CppGuess;
|
||||
|
||||
# Test for a Visual Studio compiler
|
||||
my \$cpp_guess = ExtUtils::CppGuess->new;
|
||||
my \$mswin = \$^O eq 'MSWin32';
|
||||
my \$msvc = \$cpp_guess->is_msvc;
|
||||
|
||||
# Query the available data from Alien::wxWidgets.
|
||||
my \$ccflags;
|
||||
my \$ldflags;
|
||||
{ local *STDOUT; open STDOUT, '>', \\\$ccflags; ccflags; }
|
||||
{ local *STDOUT; open STDOUT, '>', \\\$ldflags; ldopts; }
|
||||
\$ccflags = ' ' . \$ccflags;
|
||||
\$ldflags = ' ' . \$ldflags;
|
||||
|
||||
my \$filename = '${PerlEmbed_TEMP_INCLUDE}';
|
||||
open(my $fh, '>', \$filename) or die \"Could not open file '\$filename' \$!\";
|
||||
|
||||
# Convert a space separated lists to CMake semicolon separated lists,
|
||||
# escape the backslashes,
|
||||
# export the resulting list to a temp file.
|
||||
sub cmake_set_var {
|
||||
my (\$varname, \$content) = @_;
|
||||
# Remove line separators.
|
||||
\$content =~ s/\\r|\\n//g;
|
||||
# Escape the path separators.
|
||||
\$content =~ s/\\\\/\\\\\\\\\\\\\\\\/g;
|
||||
my @words = shellwords(\$content);
|
||||
print \$fh \"set(PerlEmbed_\$varname \\\"\" . join(';', @words) . \"\\\")\\n\";
|
||||
}
|
||||
cmake_set_var('ARCHNAME', \$Config{archname});
|
||||
cmake_set_var('CCFLAGS', \$ccflags);
|
||||
\$ldflags =~ s/ -L/ -LIBPATH:/g if \$msvc;
|
||||
cmake_set_var('LD', \$Config{ld});
|
||||
cmake_set_var('LDFLAGS', \$ldflags);
|
||||
cmake_set_var('CCCDLFLAGS', \$Config{cccdlflags});
|
||||
cmake_set_var('LDDLFLAGS', \$Config{lddlflags});
|
||||
cmake_set_var('DLEXT', \$Config{dlext});
|
||||
close \$fh;
|
||||
")
|
||||
include(${PerlEmbed_TEMP_INCLUDE})
|
||||
file(REMOVE ${PerlEmbed_TEMP_INCLUDE})
|
||||
unset(PerlEmbed_TEMP_INCLUDE)
|
||||
|
||||
if (PerlEmbed_DEBUG)
|
||||
# First show the configuration extracted by FindPerl & FindPerlLibs:
|
||||
message(STATUS " PERL_INCLUDE_PATH = ${PERL_INCLUDE_PATH}")
|
||||
message(STATUS " PERL_LIBRARY = ${PERL_LIBRARY}")
|
||||
message(STATUS " PERL_EXECUTABLE = ${PERL_EXECUTABLE}")
|
||||
message(STATUS " PERL_SITESEARCH = ${PERL_SITESEARCH}")
|
||||
message(STATUS " PERL_SITELIB = ${PERL_SITELIB}")
|
||||
message(STATUS " PERL_VENDORARCH = ${PERL_VENDORARCH}")
|
||||
message(STATUS " PERL_VENDORLIB = ${PERL_VENDORLIB}")
|
||||
message(STATUS " PERL_ARCHLIB = ${PERL_ARCHLIB}")
|
||||
message(STATUS " PERL_PRIVLIB = ${PERL_PRIVLIB}")
|
||||
message(STATUS " PERL_EXTRA_C_FLAGS = ${PERL_EXTRA_C_FLAGS}")
|
||||
# Second show the configuration extracted by this module (FindPerlEmbed):
|
||||
message(STATUS " PerlEmbed_ARCHNAME = ${PerlEmbed_ARCHNAME}")
|
||||
message(STATUS " PerlEmbed_CCFLAGS = ${PerlEmbed_CCFLAGS}")
|
||||
message(STATUS " PerlEmbed_CCCDLFLAGS = ${PerlEmbed_CCCDLFLAGS}")
|
||||
message(STATUS " LD = ${PerlEmbed_LD}")
|
||||
message(STATUS " PerlEmbed_LDFLAGS = ${PerlEmbed_LDFLAGS}")
|
||||
message(STATUS " PerlEmbed_LDDLFLAGS = ${PerlEmbed_LDDLFLAGS}")
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package_handle_standard_args(PerlEmbed
|
||||
REQUIRED_VARS PerlEmbed_CCFLAGS PerlEmbed_LDFLAGS
|
||||
VERSION_VAR PERL_VERSION)
|
2
deps/+OpenVDB/OpenVDB.cmake
vendored
@ -15,7 +15,7 @@ endif ()
|
||||
|
||||
add_cmake_project(OpenVDB
|
||||
# 8.2 patched
|
||||
URL https://github.com/tamasmeszaros/openvdb/archive/a68fd58d0e2b85f01adeb8b13d7555183ab10aa5.zip
|
||||
URL https://github.com/prusa3d/openvdb/archive/a68fd58d0e2b85f01adeb8b13d7555183ab10aa5.zip
|
||||
URL_HASH SHA256=f353e7b99bd0cbfc27ac9082de51acf32a8bc0b3e21ff9661ecca6f205ec1d81
|
||||
CMAKE_ARGS
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
|
@ -1,61 +0,0 @@
|
||||
#/|/ Copyright (c) Prusa Research 2016 - 2022 Vojtěch Bubník @bubnikv, Tomáš Mészáros @tamasmeszaros, Vojtěch Král @vojtechkral, Oleksandra Iushchenko @YuSanka
|
||||
#/|/ Copyright (c) 2018 Martin Loidl @LoidlM
|
||||
#/|/ Copyright (c) Slic3r 2011 - 2016 Alessandro Ranellucci @alranel
|
||||
#/|/ Copyright (c) 2012 Henrik Brix Andersen @henrikbrixandersen
|
||||
#/|/ Copyright (c) 2012 Mark Hindess
|
||||
#/|/ Copyright (c) 2012 Michael Moon
|
||||
#/|/ Copyright (c) 2011 Clarence Risher
|
||||
#/|/
|
||||
#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
#/|/
|
||||
# This package loads all the non-GUI Slic3r perl packages.
|
||||
|
||||
package Slic3r;
|
||||
|
||||
# Copyright holder: Alessandro Ranellucci
|
||||
# This application is licensed under the GNU Affero General Public License, version 3
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Config;
|
||||
require v5.10;
|
||||
|
||||
our $VERSION = VERSION();
|
||||
our $BUILD = BUILD();
|
||||
our $FORK_NAME = FORK_NAME();
|
||||
|
||||
our $debug = 0;
|
||||
sub debugf {
|
||||
printf @_ if $debug;
|
||||
}
|
||||
|
||||
our $loglevel = 0;
|
||||
|
||||
BEGIN {
|
||||
$debug = 1 if (defined($ENV{'SLIC3R_DEBUGOUT'}) && $ENV{'SLIC3R_DEBUGOUT'} == 1);
|
||||
print "Debugging output enabled\n" if $debug;
|
||||
}
|
||||
|
||||
use FindBin;
|
||||
|
||||
use Moo 1.003001;
|
||||
|
||||
use Slic3r::XS; # import all symbols (constants etc.) before they get parsed
|
||||
use Slic3r::Config;
|
||||
use Slic3r::GCode::Reader;
|
||||
use Slic3r::Line;
|
||||
use Slic3r::Model;
|
||||
use Slic3r::Point;
|
||||
use Slic3r::Polygon;
|
||||
use Slic3r::Polyline;
|
||||
our $build = eval "use Slic3r::Build; 1";
|
||||
|
||||
# Scaling between the float and integer coordinates.
|
||||
# Floats are in mm.
|
||||
use constant SCALING_FACTOR => 0.000001;
|
||||
|
||||
# Set the logging level at the Slic3r XS module.
|
||||
$Slic3r::loglevel = (defined($ENV{'SLIC3R_LOGLEVEL'}) && $ENV{'SLIC3R_LOGLEVEL'} =~ /^[1-9]/) ? $ENV{'SLIC3R_LOGLEVEL'} : 0;
|
||||
set_logging_level($Slic3r::loglevel);
|
||||
|
||||
1;
|
@ -1,46 +0,0 @@
|
||||
#/|/ Copyright (c) Prusa Research 2016 - 2022 Vojtěch Bubník @bubnikv
|
||||
#/|/ Copyright (c) 2017 Joseph Lenox @lordofhyphens
|
||||
#/|/ Copyright (c) Slic3r 2011 - 2016 Alessandro Ranellucci @alranel
|
||||
#/|/ Copyright (c) 2015 Alexander Rössler @machinekoder
|
||||
#/|/ Copyright (c) 2012 Henrik Brix Andersen @henrikbrixandersen
|
||||
#/|/ Copyright (c) 2012 Mark Hindess
|
||||
#/|/ Copyright (c) 2012 Josh McCullough
|
||||
#/|/ Copyright (c) 2011 - 2012 Michael Moon
|
||||
#/|/ Copyright (c) 2012 Simon George
|
||||
#/|/ Copyright (c) 2012 Johannes Reinhardt
|
||||
#/|/ Copyright (c) 2011 Clarence Risher
|
||||
#/|/
|
||||
#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
#/|/
|
||||
# Extends C++ class Slic3r::DynamicPrintConfig
|
||||
# This perl class does not keep any perl class variables,
|
||||
# all the storage is handled by the underlying C++ code.
|
||||
package Slic3r::Config;
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
use List::Util qw(first max);
|
||||
|
||||
# C++ Slic3r::PrintConfigDef exported as a Perl hash of hashes.
|
||||
# The C++ counterpart is a constant singleton.
|
||||
our $Options = print_config_def();
|
||||
|
||||
# Generate accessors.
|
||||
{
|
||||
no strict 'refs';
|
||||
for my $opt_key (keys %$Options) {
|
||||
*{$opt_key} = sub {
|
||||
#print "Slic3r::Config::accessor $opt_key\n";
|
||||
$_[0]->get($opt_key)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
package Slic3r::Config::Static;
|
||||
use parent 'Slic3r::Config';
|
||||
|
||||
sub Slic3r::Config::GCode::new { Slic3r::Config::Static::new_GCodeConfig }
|
||||
sub Slic3r::Config::Print::new { Slic3r::Config::Static::new_PrintConfig }
|
||||
|
||||
1;
|
@ -1,95 +0,0 @@
|
||||
#/|/ Copyright (c) Prusa Research 2016 - 2017 Vojtěch Bubník @bubnikv
|
||||
#/|/ Copyright (c) Slic3r 2013 - 2015 Alessandro Ranellucci @alranel
|
||||
#/|/
|
||||
#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
#/|/
|
||||
# Helper module to parse and interpret a G-code file,
|
||||
# invoking a callback for each move extracted from the G-code.
|
||||
# Currently used by the automatic tests only.
|
||||
package Slic3r::GCode::Reader;
|
||||
use Moo;
|
||||
|
||||
has 'config' => (is => 'ro', default => sub { Slic3r::Config::GCode->new });
|
||||
has 'X' => (is => 'rw', default => sub {0});
|
||||
has 'Y' => (is => 'rw', default => sub {0});
|
||||
has 'Z' => (is => 'rw', default => sub {0});
|
||||
has 'E' => (is => 'rw', default => sub {0});
|
||||
has 'F' => (is => 'rw', default => sub {0});
|
||||
has '_extrusion_axis' => (is => 'rw', default => sub {"E"});
|
||||
|
||||
our $Verbose = 0;
|
||||
my @AXES = qw(X Y Z E);
|
||||
|
||||
sub apply_print_config {
|
||||
my ($self, $print_config) = @_;
|
||||
|
||||
$self->config->apply_static($print_config);
|
||||
$self->_extrusion_axis($self->config->get_extrusion_axis);
|
||||
}
|
||||
|
||||
sub clone {
|
||||
my $self = shift;
|
||||
return (ref $self)->new(
|
||||
map { $_ => $self->$_ } (@AXES, 'F', '_extrusion_axis', 'config'),
|
||||
);
|
||||
}
|
||||
|
||||
sub parse {
|
||||
my $self = shift;
|
||||
my ($gcode, $cb) = @_;
|
||||
|
||||
foreach my $raw_line (split /\R+/, $gcode) {
|
||||
print "$raw_line\n" if $Verbose || $ENV{SLIC3R_TESTS_GCODE};
|
||||
my $line = $raw_line;
|
||||
$line =~ s/\s*;(.*)//; # strip comment
|
||||
my %info = (comment => $1, raw => $raw_line);
|
||||
|
||||
# parse command
|
||||
my ($command, @args) = split /\s+/, $line;
|
||||
$command //= '';
|
||||
my %args = map { /([A-Z])(.*)/; ($1 => $2) } @args;
|
||||
|
||||
# convert extrusion axis
|
||||
if (exists $args{ $self->_extrusion_axis }) {
|
||||
$args{E} = $args{ $self->_extrusion_axis };
|
||||
}
|
||||
|
||||
# check motion
|
||||
if ($command =~ /^G[01]$/) {
|
||||
foreach my $axis (@AXES) {
|
||||
if (exists $args{$axis}) {
|
||||
$self->$axis(0) if $axis eq 'E' && $self->config->use_relative_e_distances;
|
||||
$info{"dist_$axis"} = $args{$axis} - $self->$axis;
|
||||
$info{"new_$axis"} = $args{$axis};
|
||||
} else {
|
||||
$info{"dist_$axis"} = 0;
|
||||
$info{"new_$axis"} = $self->$axis;
|
||||
}
|
||||
}
|
||||
$info{dist_XY} = sqrt(($info{dist_X}**2) + ($info{dist_Y}**2));
|
||||
if (exists $args{E}) {
|
||||
if ($info{dist_E} > 0) {
|
||||
$info{extruding} = 1;
|
||||
} elsif ($info{dist_E} < 0) {
|
||||
$info{retracting} = 1
|
||||
}
|
||||
} else {
|
||||
$info{travel} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
# run callback
|
||||
$cb->($self, $command, \%args, \%info);
|
||||
|
||||
# update coordinates
|
||||
if ($command =~ /^(?:G[01]|G92)$/) {
|
||||
for my $axis (@AXES, 'F') {
|
||||
$self->$axis($args{$axis}) if exists $args{$axis};
|
||||
}
|
||||
}
|
||||
|
||||
# TODO: update temperatures
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -1,46 +0,0 @@
|
||||
#/|/ Copyright (c) Prusa Research 2017 - 2022 Vojtěch Bubník @bubnikv
|
||||
#/|/ Copyright (c) Slic3r 2011 - 2015 Alessandro Ranellucci @alranel
|
||||
#/|/ Copyright (c) 2013 Jose Luis Perez Diez
|
||||
#/|/ Copyright (c) 2013 Anders Sundman
|
||||
#/|/ Copyright (c) 2013 Jesse Vincent
|
||||
#/|/ Copyright (c) 2012 Mike Sheldrake @mesheldrake
|
||||
#/|/ Copyright (c) 2012 Mark Hindess
|
||||
#/|/
|
||||
#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
#/|/
|
||||
package Slic3r::Geometry;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
require Exporter;
|
||||
our @ISA = qw(Exporter);
|
||||
|
||||
# Exported by this module. The last section starting with convex_hull is exported by Geometry.xsp
|
||||
our @EXPORT_OK = qw(
|
||||
PI epsilon
|
||||
|
||||
scale
|
||||
unscale
|
||||
scaled_epsilon
|
||||
|
||||
X Y Z
|
||||
convex_hull
|
||||
deg2rad
|
||||
rad2deg
|
||||
);
|
||||
|
||||
use constant PI => 4 * atan2(1, 1);
|
||||
use constant A => 0;
|
||||
use constant B => 1;
|
||||
use constant X1 => 0;
|
||||
use constant Y1 => 1;
|
||||
use constant X2 => 2;
|
||||
use constant Y2 => 3;
|
||||
|
||||
sub epsilon () { 1E-4 }
|
||||
sub scaled_epsilon () { epsilon / &Slic3r::SCALING_FACTOR }
|
||||
|
||||
sub scale ($) { $_[0] / &Slic3r::SCALING_FACTOR }
|
||||
sub unscale ($) { $_[0] * &Slic3r::SCALING_FACTOR }
|
||||
|
||||
1;
|
@ -1,13 +0,0 @@
|
||||
#/|/ Copyright (c) Prusa Research 2022 Vojtěch Bubník @bubnikv
|
||||
#/|/ Copyright (c) Slic3r 2011 - 2014 Alessandro Ranellucci @alranel
|
||||
#/|/
|
||||
#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
#/|/
|
||||
package Slic3r::Line;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# a line is a two-points line
|
||||
use parent 'Slic3r::Polyline';
|
||||
|
||||
1;
|
@ -1,141 +0,0 @@
|
||||
#/|/ Copyright (c) Prusa Research 2016 - 2022 Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966
|
||||
#/|/ Copyright (c) Slic3r 2012 - 2016 Alessandro Ranellucci @alranel
|
||||
#/|/
|
||||
#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
#/|/
|
||||
# extends C++ class Slic3r::Model
|
||||
package Slic3r::Model;
|
||||
|
||||
use List::Util qw(first max any);
|
||||
|
||||
sub merge {
|
||||
my $class = shift;
|
||||
my @models = @_;
|
||||
|
||||
my $new_model = ref($class)
|
||||
? $class
|
||||
: $class->new;
|
||||
|
||||
$new_model->add_object($_) for map @{$_->objects}, @models;
|
||||
return $new_model;
|
||||
}
|
||||
|
||||
sub add_object {
|
||||
my $self = shift;
|
||||
|
||||
if (@_ == 1) {
|
||||
# we have a Model::Object
|
||||
my ($object) = @_;
|
||||
return $self->_add_object_clone($object);
|
||||
} else {
|
||||
my (%args) = @_;
|
||||
|
||||
my $new_object = $self->_add_object;
|
||||
|
||||
$new_object->set_name($args{name})
|
||||
if defined $args{name};
|
||||
$new_object->set_input_file($args{input_file})
|
||||
if defined $args{input_file};
|
||||
$new_object->config->apply($args{config})
|
||||
if defined $args{config};
|
||||
$new_object->set_layer_height_ranges($args{layer_height_ranges})
|
||||
if defined $args{layer_height_ranges};
|
||||
$new_object->set_origin_translation($args{origin_translation})
|
||||
if defined $args{origin_translation};
|
||||
|
||||
return $new_object;
|
||||
}
|
||||
}
|
||||
|
||||
sub set_material {
|
||||
my $self = shift;
|
||||
my ($material_id, $attributes) = @_;
|
||||
|
||||
my $material = $self->add_material($material_id);
|
||||
$material->apply($attributes // {});
|
||||
return $material;
|
||||
}
|
||||
|
||||
# Extends C++ class Slic3r::ModelMaterial
|
||||
package Slic3r::Model::Material;
|
||||
|
||||
sub apply {
|
||||
my ($self, $attributes) = @_;
|
||||
$self->set_attribute($_, $attributes{$_}) for keys %$attributes;
|
||||
}
|
||||
|
||||
# Extends C++ class Slic3r::ModelObject
|
||||
package Slic3r::Model::Object;
|
||||
|
||||
use List::Util qw(first sum);
|
||||
|
||||
sub add_volume {
|
||||
my $self = shift;
|
||||
|
||||
my $new_volume;
|
||||
if (@_ == 1) {
|
||||
# we have a Model::Volume
|
||||
my ($volume) = @_;
|
||||
|
||||
$new_volume = $self->_add_volume_clone($volume);
|
||||
|
||||
if ($volume->material_id ne '') {
|
||||
# merge material attributes and config (should we rename materials in case of duplicates?)
|
||||
if (my $material = $volume->object->model->get_material($volume->material_id)) {
|
||||
my %attributes = %{ $material->attributes };
|
||||
if ($self->model->has_material($volume->material_id)) {
|
||||
%attributes = (%attributes, %{ $self->model->get_material($volume->material_id)->attributes })
|
||||
}
|
||||
my $new_material = $self->model->set_material($volume->material_id, {%attributes});
|
||||
$new_material->config->apply($material->config);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
my %args = @_;
|
||||
|
||||
$new_volume = $self->_add_volume($args{mesh});
|
||||
|
||||
$new_volume->set_name($args{name})
|
||||
if defined $args{name};
|
||||
$new_volume->set_material_id($args{material_id})
|
||||
if defined $args{material_id};
|
||||
$new_volume->set_modifier($args{modifier})
|
||||
if defined $args{modifier};
|
||||
$new_volume->config->apply($args{config})
|
||||
if defined $args{config};
|
||||
}
|
||||
|
||||
if ($new_volume->material_id ne '' && !defined $self->model->get_material($new_volume->material_id)) {
|
||||
# TODO: this should be a trigger on Volume::material_id
|
||||
$self->model->set_material($new_volume->material_id);
|
||||
}
|
||||
|
||||
$self->invalidate_bounding_box;
|
||||
|
||||
return $new_volume;
|
||||
}
|
||||
|
||||
sub add_instance {
|
||||
my $self = shift;
|
||||
|
||||
if (@_ == 1) {
|
||||
# we have a Model::Instance
|
||||
my ($instance) = @_;
|
||||
return $self->_add_instance_clone($instance);
|
||||
} else {
|
||||
my (%args) = @_;
|
||||
|
||||
my $new_instance = $self->_add_instance;
|
||||
|
||||
$new_instance->set_rotations($args{rotation})
|
||||
if defined $args{rotation};
|
||||
$new_instance->set_scaling_factors($args{scaling_factor})
|
||||
if defined $args{scaling_factor};
|
||||
$new_instance->set_offset($args{offset})
|
||||
if defined $args{offset};
|
||||
|
||||
return $new_instance;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -1,33 +0,0 @@
|
||||
#/|/ Copyright (c) Prusa Research 2018 Vojtěch Bubník @bubnikv
|
||||
#/|/ Copyright (c) Slic3r 2011 - 2015 Alessandro Ranellucci @alranel
|
||||
#/|/
|
||||
#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
#/|/
|
||||
package Slic3r::Point;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub new_scale {
|
||||
my $class = shift;
|
||||
return $class->new(map Slic3r::Geometry::scale($_), @_);
|
||||
}
|
||||
|
||||
package Slic3r::Pointf;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub new_unscale {
|
||||
my $class = shift;
|
||||
return $class->new(map Slic3r::Geometry::unscale($_), @_);
|
||||
}
|
||||
|
||||
package Slic3r::Pointf3;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub new_unscale {
|
||||
my $class = shift;
|
||||
return $class->new(map Slic3r::Geometry::unscale($_), @_);
|
||||
}
|
||||
|
||||
1;
|
@ -1,14 +0,0 @@
|
||||
#/|/ Copyright (c) Prusa Research 2017 - 2022 Vojtěch Bubník @bubnikv
|
||||
#/|/ Copyright (c) Slic3r 2011 - 2014 Alessandro Ranellucci @alranel
|
||||
#/|/ Copyright (c) 2012 Mark Hindess
|
||||
#/|/
|
||||
#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
#/|/
|
||||
package Slic3r::Polygon;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# a polygon is a closed polyline.
|
||||
use parent 'Slic3r::Polyline';
|
||||
|
||||
1;
|
@ -1,19 +0,0 @@
|
||||
#/|/ Copyright (c) Prusa Research 2018 Vojtěch Bubník @bubnikv
|
||||
#/|/ Copyright (c) Slic3r 2011 - 2014 Alessandro Ranellucci @alranel
|
||||
#/|/ Copyright (c) 2012 Mark Hindess
|
||||
#/|/
|
||||
#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
#/|/
|
||||
package Slic3r::Polyline;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Slic3r::Geometry qw(X Y);
|
||||
|
||||
sub new_scale {
|
||||
my $class = shift;
|
||||
my @points = map { ref($_) eq 'Slic3r::Point' ? $_->pp : $_ } @_;
|
||||
return $class->new(map [ Slic3r::Geometry::scale($_->[X]), Slic3r::Geometry::scale($_->[Y]) ], @points);
|
||||
}
|
||||
|
||||
1;
|
@ -1,4 +1,6 @@
|
||||
min_slic3r_version = 2.6.0-alpha4
|
||||
1.1.3 Fixed top solid infill extrusion width for M5C.
|
||||
1.1.2 Added AnkerMake M5C.
|
||||
1.1.1 Initial official version
|
||||
1.0.1 Initial Version
|
||||
min_slic3r_version = 2.6.0-alpha1
|
||||
|
@ -5,7 +5,7 @@
|
||||
name = AnkerMake
|
||||
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
||||
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
||||
config_version = 1.1.1
|
||||
config_version = 1.1.3
|
||||
# Where to get the updates from?
|
||||
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Anker/
|
||||
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
|
||||
@ -24,6 +24,18 @@ bed_texture = M5-texture_v2.svg
|
||||
thumbnail = M5_thumbnail_v2.png
|
||||
default_materials = Generic PLA+ @ANKER; Generic PLA @ANKER; Generic PET @ANKER; Generic ABS @ANKER;
|
||||
|
||||
# All presets starting with asterisk, for example *common*, are intermediate and they will
|
||||
# not make it into the user interface.
|
||||
[printer_model:M5C]
|
||||
name = AnkerMake M5C
|
||||
variants = 0.4
|
||||
technology = FFF
|
||||
family = AnkerMake
|
||||
bed_model = M5C-bed.stl
|
||||
bed_texture = M5C-texture_v2.svg
|
||||
thumbnail = M5C_thumbnail_v2.png
|
||||
default_materials = Generic PLA+ @ANKER; Generic PLA @ANKER; Generic PET @ANKER; Generic ABS @ANKER;
|
||||
|
||||
# All presets starting with asterisk, for example *common*, are intermediate and they will
|
||||
# not make it into the user interface.
|
||||
|
||||
@ -166,16 +178,265 @@ top_solid_layers = 4
|
||||
|
||||
[print:0.10 mm HIGHDETAIL (0.4 mm nozzle) @ANKER]
|
||||
inherits = *0.10mm*
|
||||
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4
|
||||
compatible_printers_condition = printer_notes=~/.*(MACHINE_M5_).*/ and nozzle_diameter[0]==0.4
|
||||
|
||||
[print:0.20 mm NORMAL (0.4 mm nozzle) @ANKER]
|
||||
inherits = *0.20mm*
|
||||
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4
|
||||
compatible_printers_condition = printer_notes=~/.*(MACHINE_M5_).*/ and nozzle_diameter[0]==0.4
|
||||
|
||||
|
||||
[print:0.30 mm SUPERDRAFT (0.4 mm nozzle) @ANKER]
|
||||
inherits = *0.30mm*
|
||||
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4
|
||||
compatible_printers_condition = printer_notes=~/.*(MACHINE_M5_).*/ and nozzle_diameter[0]==0.4
|
||||
|
||||
[print:*common-M5C*]
|
||||
avoid_crossing_curled_overhangs = 0
|
||||
avoid_crossing_perimeters = 0
|
||||
avoid_crossing_perimeters_max_detour = 0
|
||||
bottom_fill_pattern = rectilinear
|
||||
bottom_solid_min_thickness = 0.8
|
||||
bridge_angle = 0
|
||||
bridge_flow_ratio = 1
|
||||
bridge_speed = 30
|
||||
brim_separation = 0.1
|
||||
brim_type = no_brim
|
||||
brim_width = 8
|
||||
complete_objects = 0
|
||||
dont_support_bridges = 1
|
||||
draft_shield = disabled
|
||||
elefant_foot_compensation = 0
|
||||
enable_dynamic_overhang_speeds = 1
|
||||
external_perimeter_extrusion_width = 0.44
|
||||
external_perimeter_speed = 75
|
||||
external_perimeters_first = 1
|
||||
extra_perimeters = 1
|
||||
extra_perimeters_on_overhangs = 0
|
||||
extruder_clearance_height = 20
|
||||
extruder_clearance_radius = 20
|
||||
extrusion_width = 0.4
|
||||
fill_angle = 45
|
||||
fill_density = 10%
|
||||
fill_pattern = grid
|
||||
first_layer_acceleration = 2500
|
||||
first_layer_acceleration_over_raft = 0
|
||||
first_layer_extrusion_width = 0.5
|
||||
first_layer_speed = 50
|
||||
first_layer_speed_over_raft = 30
|
||||
fuzzy_skin = none
|
||||
fuzzy_skin_point_dist = 0.8
|
||||
fuzzy_skin_thickness = 0.3
|
||||
gap_fill_enabled = 1
|
||||
gap_fill_speed = 75
|
||||
gcode_comments = 0
|
||||
gcode_label_objects = 0
|
||||
gcode_resolution = 0.0125
|
||||
gcode_substitutions = "(G28 ;Home.*$)";"${1}\\nM4899 T3\\n";;";S-Curve"
|
||||
infill_acceleration = 4000
|
||||
infill_anchor = 30
|
||||
infill_anchor_max = 60
|
||||
infill_every_layers = 1
|
||||
infill_extruder = 1
|
||||
infill_extrusion_width = 0.4
|
||||
infill_first = 0
|
||||
infill_overlap = 25%
|
||||
infill_speed = 250
|
||||
interface_shells = 0
|
||||
ironing = 0
|
||||
ironing_flowrate = 15%
|
||||
ironing_spacing = 0.1
|
||||
ironing_speed = 15
|
||||
ironing_type = top
|
||||
max_print_speed = 500
|
||||
max_volumetric_extrusion_rate_slope_negative = 0
|
||||
max_volumetric_extrusion_rate_slope_positive = 0
|
||||
max_volumetric_speed = 0
|
||||
min_bead_width = 85%
|
||||
min_feature_size = 25%
|
||||
min_skirt_length = 0
|
||||
mmu_segmented_region_max_width = 0
|
||||
only_retract_when_crossing_perimeters = 0
|
||||
ooze_prevention = 0
|
||||
output_filename_format = {input_filename_base}_{layer_height}mm_{initial_filament_type}_{printer_model}.gcode
|
||||
overhang_speed_0 = 25
|
||||
overhang_speed_1 = 55
|
||||
overhang_speed_2 = 55
|
||||
overhang_speed_3 = 100%
|
||||
overhangs = 1
|
||||
perimeter_extruder = 1
|
||||
perimeter_extrusion_width = 0.4
|
||||
perimeter_generator = classic
|
||||
perimeter_speed = 200
|
||||
post_process =
|
||||
print_settings_id =
|
||||
raft_contact_distance = 0.1
|
||||
raft_expansion = 1.5
|
||||
raft_first_layer_density = 90%
|
||||
raft_first_layer_expansion = 0
|
||||
raft_layers = 0
|
||||
resolution = 0
|
||||
seam_position = aligned
|
||||
single_extruder_multi_material_priming = 1
|
||||
skirt_distance = 6
|
||||
skirt_height = 1
|
||||
skirts = 1
|
||||
slice_closing_radius = 0.049
|
||||
slicing_mode = regular
|
||||
small_perimeter_speed = 75
|
||||
solid_infill_below_area = 0
|
||||
solid_infill_every_layers = 0
|
||||
solid_infill_extruder = 1
|
||||
solid_infill_extrusion_width = 0.4
|
||||
solid_infill_speed = 100
|
||||
spiral_vase = 0
|
||||
staggered_inner_seams = 0
|
||||
standby_temperature_delta = -5
|
||||
support_material = 0
|
||||
support_material_angle = 90
|
||||
support_material_auto = 1
|
||||
support_material_bottom_contact_distance = 0
|
||||
support_material_bottom_interface_layers = -1
|
||||
support_material_buildplate_only = 0
|
||||
support_material_closing_radius = 2
|
||||
support_material_contact_distance = 0.2
|
||||
support_material_enforce_layers = 0
|
||||
support_material_extruder = 1
|
||||
support_material_extrusion_width = 0.3
|
||||
support_material_interface_contact_loops = 0
|
||||
support_material_interface_extruder = 1
|
||||
support_material_interface_layers = 0
|
||||
support_material_interface_pattern = rectilinear
|
||||
support_material_interface_spacing = 0.2
|
||||
support_material_interface_speed = 100%
|
||||
support_material_pattern = rectilinear
|
||||
support_material_spacing = 1.333
|
||||
support_material_speed = 150
|
||||
support_material_style = grid
|
||||
support_material_synchronize_layers = 0
|
||||
support_material_threshold = 30
|
||||
support_material_with_sheath = 0
|
||||
support_material_xy_spacing = 0.8
|
||||
support_tree_angle = 40
|
||||
support_tree_angle_slow = 25
|
||||
support_tree_branch_diameter = 2
|
||||
support_tree_branch_diameter_angle = 5
|
||||
support_tree_branch_distance = 1
|
||||
support_tree_tip_diameter = 0.8
|
||||
support_tree_top_rate = 15%
|
||||
thick_bridges = 0
|
||||
thin_walls = 1
|
||||
threads = 10
|
||||
top_fill_pattern = rectilinear
|
||||
top_infill_extrusion_width = 0.4
|
||||
top_solid_infill_speed = 50
|
||||
top_solid_min_thickness = 0.8
|
||||
travel_speed = 500
|
||||
travel_speed_z = 10
|
||||
wall_distribution_count = 1
|
||||
wall_transition_angle = 10
|
||||
wall_transition_filter_deviation = 25%
|
||||
wall_transition_length = 100%
|
||||
wipe_tower = 0
|
||||
wipe_tower_bridging = 10
|
||||
wipe_tower_brim_width = 2
|
||||
wipe_tower_cone_angle = 0
|
||||
wipe_tower_extra_spacing = 100%
|
||||
wipe_tower_no_sparse_layers = 0
|
||||
wipe_tower_rotation_angle = 0
|
||||
wipe_tower_width = 60
|
||||
wipe_tower_x = 180
|
||||
wipe_tower_y = 140
|
||||
xy_size_compensation = 0
|
||||
|
||||
[print:Precision - M5C (0.4 mm nozzle) @ANKER]
|
||||
inherits = *common-M5C*
|
||||
compatible_printers_condition = printer_notes=~/.*(MACHINE_M5C_).*/ and printer_notes=~/.*(P_PRECISION).*/ and nozzle_diameter[0]==0.4
|
||||
first_layer_height = 0.14
|
||||
layer_height = 0.16
|
||||
top_solid_layers = 5
|
||||
bottom_solid_layers = 3
|
||||
perimeters = 2
|
||||
bridge_acceleration = 500
|
||||
default_acceleration = 4000
|
||||
external_perimeter_acceleration = 3000
|
||||
perimeter_acceleration = 3000
|
||||
top_solid_infill_acceleration = 2500
|
||||
travel_acceleration = 4000
|
||||
solid_infill_acceleration = 2500
|
||||
|
||||
[print:Normal - M5C (0.4 mm nozzle) @ANKER]
|
||||
inherits = *common-M5C*
|
||||
notes = PRINT_COMPATIBLE\n P_NORMAL\n F_PLA__Basic\n
|
||||
compatible_printers_condition = printer_notes=~/.*(MACHINE_M5C_).*/ and printer_notes=~/.*(P_NORMAL).*/ and nozzle_diameter[0]==0.4
|
||||
first_layer_height = 0.14
|
||||
layer_height = 0.2
|
||||
top_solid_layers = 4
|
||||
bottom_solid_layers = 4
|
||||
perimeters = 3
|
||||
bridge_acceleration = 500
|
||||
default_acceleration = 2500
|
||||
external_perimeter_acceleration = 2500
|
||||
external_perimeter_speed = 150
|
||||
first_layer_acceleration = 2500
|
||||
first_layer_acceleration_over_raft = 0
|
||||
first_layer_speed = 50
|
||||
gap_fill_speed = 75
|
||||
infill_acceleration = 2500
|
||||
infill_speed = 250
|
||||
max_print_speed = 250
|
||||
overhang_speed_0 = 15
|
||||
overhang_speed_1 = 20
|
||||
overhang_speed_2 = 30
|
||||
overhang_speed_3 = 30
|
||||
perimeter_acceleration = 2500
|
||||
perimeter_speed = 250
|
||||
small_perimeter_speed = 75
|
||||
solid_infill_acceleration = 2500
|
||||
solid_infill_speed = 150
|
||||
top_solid_infill_acceleration = 2500
|
||||
top_solid_infill_speed = 150
|
||||
travel_acceleration = 2500
|
||||
travel_speed = 250
|
||||
travel_speed_z = 10
|
||||
|
||||
[print:Fast - M5C (0.4 mm nozzle) @ANKER]
|
||||
inherits = *common-M5C*
|
||||
notes = PRINT_COMPATIBLE\n P_FAST\n F_PLA__Basic\n
|
||||
compatible_printers_condition = printer_notes=~/.*(MACHINE_M5C_).*/ and printer_notes=~/.*(P_FAST).*/ and nozzle_diameter[0]==0.4
|
||||
layer_height = 0.25
|
||||
first_layer_height = 0.14
|
||||
perimeters = 2
|
||||
top_solid_layers = 4
|
||||
bottom_solid_layers = 3
|
||||
external_perimeter_acceleration = 3000
|
||||
perimeter_acceleration = 5000
|
||||
top_solid_infill_acceleration = 4000
|
||||
solid_infill_acceleration = 4000
|
||||
infill_acceleration = 5000
|
||||
bridge_acceleration = 500
|
||||
first_layer_acceleration = 2500
|
||||
first_layer_acceleration_over_raft = 0
|
||||
travel_acceleration = 5000
|
||||
default_acceleration = 5000
|
||||
# Speed
|
||||
perimeter_speed = 250
|
||||
small_perimeter_speed = 75
|
||||
external_perimeter_speed = 150
|
||||
infill_speed = 270
|
||||
solid_infill_speed = 100
|
||||
top_solid_infill_speed = 100
|
||||
support_material_speed = 150
|
||||
support_material_interface_speed = 100%
|
||||
bridge_speed = 20
|
||||
gap_fill_speed = 75
|
||||
overhang_speed_0 = 15
|
||||
overhang_speed_1 = 20
|
||||
overhang_speed_2 = 30
|
||||
overhang_speed_3 = 30
|
||||
travel_speed = 500
|
||||
travel_speed_z = 10
|
||||
first_layer_speed = 50
|
||||
first_layer_speed_over_raft = 30
|
||||
max_print_speed = 500
|
||||
|
||||
# When submitting new filaments please print the following temperature tower at 0.1mm layer height:
|
||||
# https://www.thingiverse.com/thing:2615842
|
||||
@ -186,7 +447,7 @@ compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==
|
||||
# So having some leeway to get good bed adhesion is not a luxury for many users
|
||||
|
||||
[filament:*common*]
|
||||
cooling = 0
|
||||
cooling = 1
|
||||
compatible_printers =
|
||||
extrusion_multiplier = 1
|
||||
filament_cost = 0
|
||||
@ -218,13 +479,13 @@ temperature = 200
|
||||
|
||||
[filament:*PLA+*]
|
||||
inherits = *common*
|
||||
bed_temperature = 60
|
||||
bed_temperature = 65
|
||||
fan_below_layer_time = 100
|
||||
filament_colour = #DDDDDD
|
||||
filament_type = PLA+
|
||||
filament_density = 1.24
|
||||
filament_cost = 20
|
||||
first_layer_bed_temperature = 60
|
||||
first_layer_bed_temperature = 65
|
||||
first_layer_temperature = 230
|
||||
fan_always_on = 1
|
||||
max_fan_speed = 100
|
||||
@ -243,12 +504,12 @@ filament_type = PETG
|
||||
filament_density = 1.27
|
||||
filament_cost = 30
|
||||
first_layer_bed_temperature = 80
|
||||
first_layer_temperature = 260
|
||||
first_layer_temperature = 255
|
||||
fan_always_on = 1
|
||||
max_fan_speed = 50
|
||||
min_fan_speed = 50
|
||||
bridge_fan_speed = 100
|
||||
temperature = 260
|
||||
temperature = 255
|
||||
|
||||
[filament:*ABS*]
|
||||
inherits = *common*
|
||||
@ -260,13 +521,13 @@ filament_type = ABS
|
||||
filament_density = 1.04
|
||||
filament_cost = 20
|
||||
first_layer_bed_temperature = 90
|
||||
first_layer_temperature = 260
|
||||
first_layer_temperature = 255
|
||||
fan_always_on = 0
|
||||
max_fan_speed = 0
|
||||
min_fan_speed = 0
|
||||
bridge_fan_speed = 30
|
||||
top_fan_speed = 0
|
||||
temperature = 260
|
||||
temperature = 255
|
||||
|
||||
[filament:Generic PLA @ANKER]
|
||||
inherits = *PLA*
|
||||
@ -289,61 +550,91 @@ filament_vendor = Generic
|
||||
|
||||
# Common printer preset
|
||||
[printer:*common*]
|
||||
printer_technology = FFF
|
||||
before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;{layer_z}
|
||||
between_objects_gcode =
|
||||
pause_print_gcode =
|
||||
deretract_speed = 60
|
||||
extruder_colour = #FCE94F
|
||||
extruder_offset = 0x0
|
||||
gcode_flavor = marlin
|
||||
silent_mode = 1
|
||||
remaining_times = 1
|
||||
machine_max_acceleration_e = 2500
|
||||
machine_max_acceleration_extruding = 2500
|
||||
machine_max_acceleration_retracting = 2500
|
||||
machine_max_acceleration_travel = 1500,1250
|
||||
machine_max_acceleration_x = 2500
|
||||
machine_max_acceleration_y = 2500
|
||||
machine_max_acceleration_z = 2500
|
||||
machine_max_feedrate_e = 100
|
||||
machine_max_feedrate_x = 300
|
||||
machine_max_feedrate_y = 300
|
||||
machine_max_feedrate_z = 20
|
||||
machine_max_jerk_e = 3
|
||||
machine_max_jerk_x = 15
|
||||
machine_max_jerk_y = 15
|
||||
machine_max_jerk_z = 0.3
|
||||
machine_min_extruding_rate = 0
|
||||
machine_min_travel_rate = 0
|
||||
layer_gcode = ;AFTER_LAYER_CHANGE\n;{layer_z}
|
||||
printer_vendor = AnkerMake
|
||||
# General
|
||||
## Size and coordinates
|
||||
max_print_height = 250
|
||||
printer_notes =
|
||||
printer_settings_id =
|
||||
retract_before_travel = 3
|
||||
retract_before_wipe = 0
|
||||
retract_layer_change = 1
|
||||
retract_length_toolchange = 4
|
||||
z_offset = 0
|
||||
## Capabilities
|
||||
#extruders_count = 1
|
||||
single_extruder_multi_material = 0
|
||||
## Firmware
|
||||
gcode_flavor = marlin2
|
||||
thumbnails = 256x256
|
||||
thumbnails_format = PNG
|
||||
silent_mode = 0
|
||||
remaining_times = 1
|
||||
## Advanced
|
||||
use_relative_e_distances = 1
|
||||
use_firmware_retraction = 0
|
||||
use_volumetric_e = 0
|
||||
variable_layer_height = 1
|
||||
# Custom G-code
|
||||
start_gcode = M104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; set and wait for bed temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG28 ;Home\n;LAYER_COUNT:{total_layer_count}\n
|
||||
autoemit_temperature_commands = 1
|
||||
end_gcode = M104 S0\nM140 S0\n;Retract the filament\nG92 E1\nG1 E-1 F300\nG28 X0 Y0\nM84
|
||||
before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;{layer_z}\n;LAYER:{layer_num+1}
|
||||
layer_gcode = ;AFTER_LAYER_CHANGE\nG92 E0
|
||||
toolchange_gcode =
|
||||
between_objects_gcode =
|
||||
color_change_gcode = M600
|
||||
pause_print_gcode = M601
|
||||
template_custom_gcode =
|
||||
# Machine limits
|
||||
## General
|
||||
### machine_limits_usage = emit_to_gcode time_estimate_only ignore
|
||||
machine_limits_usage = time_estimate_only
|
||||
## Maximum feedrates
|
||||
machine_max_feedrate_e = 100
|
||||
machine_max_feedrate_x = 500
|
||||
machine_max_feedrate_y = 500
|
||||
machine_max_feedrate_z = 50
|
||||
## Maximum accelerations
|
||||
machine_max_acceleration_e = 10000
|
||||
machine_max_acceleration_extruding = 10000
|
||||
machine_max_acceleration_retracting = 10000
|
||||
machine_max_acceleration_travel = 10000
|
||||
machine_max_acceleration_x = 10000
|
||||
machine_max_acceleration_y = 10000
|
||||
machine_max_acceleration_z = 10000
|
||||
## Jerk limits
|
||||
machine_max_jerk_x = 15, 15
|
||||
machine_max_jerk_y = 15, 15
|
||||
machine_max_jerk_z = 0.3, 0.3
|
||||
machine_max_jerk_e = 3, 3
|
||||
machine_min_extruding_rate = 0, 0
|
||||
machine_min_travel_rate = 0, 0
|
||||
# Extruder 1 2 3 4 5 6
|
||||
## Size
|
||||
nozzle_diameter = 0.4
|
||||
## Preview
|
||||
extruder_colour = #9BE198
|
||||
## Layer height limits
|
||||
min_layer_height = 0.08
|
||||
max_layer_height = 0.32
|
||||
## Position (for multi-extruder printers)
|
||||
extruder_offset = 0x0
|
||||
## Retraction
|
||||
retract_length = 3
|
||||
retract_lift = 0
|
||||
retract_lift_above = 0
|
||||
retract_lift_below = 0
|
||||
retract_restart_extra = 0
|
||||
retract_restart_extra_toolchange = 0
|
||||
retract_speed = 60
|
||||
single_extruder_multi_material = 0
|
||||
thumbnails = 64x64,256x256
|
||||
thumbnails_format = JPG
|
||||
toolchange_gcode =
|
||||
use_firmware_retraction = 0
|
||||
use_relative_e_distances = 0
|
||||
use_volumetric_e = 0
|
||||
variable_layer_height = 1
|
||||
deretract_speed = 0
|
||||
retract_restart_extra = 0
|
||||
retract_before_travel = 0.8
|
||||
retract_layer_change = 1
|
||||
wipe = 0
|
||||
z_offset = 0
|
||||
retract_before_wipe = 0%
|
||||
## Retraction when tool is disabled (advanced settings for multi-extruder setups)
|
||||
retract_length_toolchange = 4
|
||||
retract_restart_extra_toolchange = 0
|
||||
# Notes
|
||||
printer_notes = Base printer notes is EMPTY!
|
||||
default_print_profile =
|
||||
default_filament_profile = Generic PLA+ @ANKER
|
||||
start_gcode = M104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; set and wait for bed temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG28 ;Home\nM420 S1; restore saved Auto Bed Leveling data\nG1 E10 F3600; push out retracted filament(fix for over retraction after prime)
|
||||
end_gcode = M104 S0\nM140 S0\n;Retract the filament\nG92 E1\nG1 E-1 F300\nG28 X0 Y0\nM84
|
||||
|
||||
printer_technology = FFF
|
||||
printer_settings_id =
|
||||
[printer:*M5*]
|
||||
inherits = *common*
|
||||
bed_shape = 0x0,235-0,235x235,0x235
|
||||
@ -354,8 +645,19 @@ retract_speed = 60
|
||||
deretract_speed = 60
|
||||
retract_before_travel = 3
|
||||
retract_before_wipe = 0%
|
||||
printer_notes = Don not remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ANKERMAKE\nPRINTER_MODEL_M5
|
||||
|
||||
printer_notes = MACHINE_M5_\n PRINTER_VENDOR_ANKERMAKE\n PRINTER_MODEL_M5\n
|
||||
[printer:*M5C*]
|
||||
inherits = *common*
|
||||
bed_shape = 0x0,220x0,220x220,0x220
|
||||
max_print_height = 250
|
||||
printer_model = M5C
|
||||
retract_length = 0.8
|
||||
retract_speed = 60
|
||||
deretract_speed = 60
|
||||
retract_before_travel = 3
|
||||
retract_before_wipe = 0%
|
||||
wipe = 1
|
||||
printer_notes = MACHINE_M5C_\n PRINTER_VENDOR_ANKERMAKE\n P_PRECISION P_NORMAL P_FAST\n
|
||||
[printer:AnkerMake M5 (0.4 mm nozzle)]
|
||||
inherits = *M5*
|
||||
nozzle_diameter = 0.4
|
||||
@ -364,3 +666,11 @@ min_layer_height = 0.08
|
||||
max_layer_height = 0.32
|
||||
retract_lift_above = 0
|
||||
default_print_profile = 0.2 mm OPTIMAL (0.4 mm nozzle) @ANKER
|
||||
[printer:AnkerMake M5C (0.4 mm nozzle)]
|
||||
inherits = *M5C*
|
||||
nozzle_diameter = 0.4
|
||||
printer_variant = 0.4
|
||||
min_layer_height = 0.08
|
||||
max_layer_height = 0.32
|
||||
retract_lift_above = 0
|
||||
default_print_profile = 0.2 mm OPTIMAL (0.4 mm nozzle) @ANKER
|
||||
|
BIN
resources/profiles/Anker/M5C-bed.stl
Normal file
1
resources/profiles/Anker/M5C-texture.svg
Normal file
After Width: | Height: | Size: 17 KiB |
1
resources/profiles/Anker/M5C-texture_v2.svg
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
resources/profiles/Anker/M5C_thumbnail.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
resources/profiles/Anker/M5C_thumbnail_v2.png
Normal file
After Width: | Height: | Size: 19 KiB |
@ -1,2 +1,6 @@
|
||||
min_slic3r_version = 2.6.0
|
||||
1.1.1 Fixed overhang speeds. Fixed branch diameter angle for organic supports.
|
||||
1.1.0 Add more Snapmaker printers.
|
||||
min_slic3r_version = 2.4.1
|
||||
1.0.1 Fix for leading zeroes.
|
||||
1.0.0 Initial Snapmaker bundle
|
||||
|
BIN
resources/profiles/Snapmaker/Snapmaker A250 Dual QSKit_cover.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
resources/profiles/Snapmaker/Snapmaker A250 Dual_cover.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
resources/profiles/Snapmaker/Snapmaker A250 QSKit_cover.png
Normal file
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 51 KiB |
BIN
resources/profiles/Snapmaker/Snapmaker A250_bed.stl
Normal file
BIN
resources/profiles/Snapmaker/Snapmaker A250_cover.png
Normal file
After Width: | Height: | Size: 22 KiB |
59
resources/profiles/Snapmaker/Snapmaker A250_texture.svg
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
resources/profiles/Snapmaker/Snapmaker A350 Dual QSKit_cover.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
resources/profiles/Snapmaker/Snapmaker A350 Dual_cover.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
resources/profiles/Snapmaker/Snapmaker A350 QSKit_cover.png
Normal file
After Width: | Height: | Size: 26 KiB |
107
resources/profiles/Snapmaker/Snapmaker A350 QSKit_texture.svg
Normal file
After Width: | Height: | Size: 78 KiB |
BIN
resources/profiles/Snapmaker/Snapmaker A350_bed.stl
Normal file
BIN
resources/profiles/Snapmaker/Snapmaker A350_cover.png
Normal file
After Width: | Height: | Size: 23 KiB |
103
resources/profiles/Snapmaker/Snapmaker A350_texture.svg
Normal file
After Width: | Height: | Size: 69 KiB |
BIN
resources/profiles/Snapmaker/Snapmaker J1_bed.stl
Normal file
BIN
resources/profiles/Snapmaker/Snapmaker J1_cover.png
Normal file
After Width: | Height: | Size: 20 KiB |
56
resources/profiles/Snapmaker/Snapmaker J1_texture.svg
Normal file
After Width: | Height: | Size: 18 KiB |
@ -130,12 +130,6 @@ int CLI::run(int argc, char **argv)
|
||||
// On Unix systems, the prusa-slicer binary may be symlinked to give the application a different meaning.
|
||||
boost::algorithm::iends_with(boost::filesystem::path(argv[0]).filename().string(), "gcodeviewer");
|
||||
#endif // _WIN32
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
std::pair<int, int> opengl_version = { 0, 0 };
|
||||
#if ENABLE_OPENGL_DEBUG_OPTION
|
||||
bool opengl_debug = false;
|
||||
#endif // ENABLE_OPENGL_DEBUG_OPTION
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
|
||||
const std::vector<std::string> &load_configs = m_config.option<ConfigOptionStrings>("load", true)->values;
|
||||
const ForwardCompatibilitySubstitutionRule config_substitution_rule = m_config.option<ConfigOptionEnum<ForwardCompatibilitySubstitutionRule>>("config_compatibility", true)->value;
|
||||
@ -174,7 +168,12 @@ int CLI::run(int argc, char **argv)
|
||||
m_print_config.apply(config);
|
||||
}
|
||||
|
||||
#ifdef SLIC3R_GUI
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
std::pair<int, int> opengl_version = { 0, 0 };
|
||||
bool opengl_debug = false;
|
||||
bool opengl_compatibility_profile = false;
|
||||
|
||||
// search for special keys into command line parameters
|
||||
auto it = std::find(m_actions.begin(), m_actions.end(), "gcodeviewer");
|
||||
if (it != m_actions.end()) {
|
||||
@ -185,30 +184,37 @@ int CLI::run(int argc, char **argv)
|
||||
|
||||
it = std::find(m_actions.begin(), m_actions.end(), "opengl-version");
|
||||
if (it != m_actions.end()) {
|
||||
std::string opengl_version_str = m_config.opt_string("opengl-version");
|
||||
if (std::find(Slic3r::GUI::OpenGLVersions::core_str.begin(), Slic3r::GUI::OpenGLVersions::core_str.end(), opengl_version_str) == Slic3r::GUI::OpenGLVersions::core_str.end()) {
|
||||
if (std::find(Slic3r::GUI::OpenGLVersions::precore_str.begin(), Slic3r::GUI::OpenGLVersions::precore_str.end(), opengl_version_str) == Slic3r::GUI::OpenGLVersions::precore_str.end()) {
|
||||
boost::nowide::cerr << "Found invalid OpenGL version: " << opengl_version_str << std::endl;
|
||||
opengl_version_str.clear();
|
||||
const Semver opengl_minimum = Semver(3,2,0);
|
||||
const std::string opengl_version_str = m_config.opt_string("opengl-version");
|
||||
boost::optional<Semver> semver = Semver::parse(opengl_version_str);
|
||||
if (semver.has_value() && (*semver) >= opengl_minimum ) {
|
||||
opengl_version.first = semver->maj();
|
||||
opengl_version.second = semver->min();
|
||||
if (std::find(Slic3r::GUI::OpenGLVersions::core.begin(), Slic3r::GUI::OpenGLVersions::core.end(), std::make_pair(opengl_version.first, opengl_version.second)) == Slic3r::GUI::OpenGLVersions::core.end()) {
|
||||
opengl_version = { 0, 0 };
|
||||
boost::nowide::cerr << "Required OpenGL version " << opengl_version_str << " not recognized.\n Option 'opengl-version' ignored." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (!opengl_version_str.empty()) {
|
||||
std::vector<std::string> tokens;
|
||||
boost::split(tokens, opengl_version_str, boost::is_any_of("."), boost::token_compress_on);
|
||||
opengl_version.first = std::stoi(tokens[0].c_str());
|
||||
opengl_version.second = std::stoi(tokens[1].c_str());
|
||||
}
|
||||
} else
|
||||
boost::nowide::cerr << "Required OpenGL version " << opengl_version_str << " is invalid. Must be greater than or equal to " <<
|
||||
opengl_minimum.to_string() << "\n Option 'opengl-version' ignored." << std::endl;
|
||||
start_gui = true;
|
||||
m_actions.erase(it);
|
||||
}
|
||||
|
||||
it = std::find(m_actions.begin(), m_actions.end(), "opengl-compatibility");
|
||||
if (it != m_actions.end()) {
|
||||
start_gui = true;
|
||||
opengl_compatibility_profile = true;
|
||||
// reset version as compatibility profile always take the highest version
|
||||
// supported by the graphic card
|
||||
opengl_version = std::make_pair(0, 0);
|
||||
m_actions.erase(it);
|
||||
}
|
||||
|
||||
it = std::find(m_actions.begin(), m_actions.end(), "opengl-debug");
|
||||
if (it != m_actions.end()) {
|
||||
start_gui = true;
|
||||
#if ENABLE_OPENGL_DEBUG_OPTION
|
||||
opengl_debug = true;
|
||||
#endif // ENABLE_OPENGL_DEBUG_OPTION
|
||||
m_actions.erase(it);
|
||||
}
|
||||
#else
|
||||
@ -222,6 +228,17 @@ int CLI::run(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
#else // SLIC3R_GUI
|
||||
// If there is no GUI, we shall ignore the parameters. Remove them from the list.
|
||||
for (const std::string& s : { "opengl-version", "opengl-compatibility", "opengl-debug", "gcodeviewer" }) {
|
||||
auto it = std::find(m_actions.cbegin(), m_actions.cend(), s);
|
||||
if (it != m_actions.end()) {
|
||||
boost::nowide::cerr << "Parameter '" << s << "' is ignored, this PrusaSlicer build is CLI only." << std::endl;
|
||||
m_actions.erase(it);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Read input file(s) if any.
|
||||
for (const std::string& file : m_input_files)
|
||||
@ -703,10 +720,9 @@ int CLI::run(int argc, char **argv)
|
||||
params.download_url = download_url;
|
||||
params.delete_after_load = delete_after_load;
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
#if ENABLE_OPENGL_DEBUG_OPTION
|
||||
params.opengl_version = opengl_version;
|
||||
params.opengl_debug = opengl_debug;
|
||||
#endif // ENABLE_OPENGL_DEBUG_OPTION
|
||||
params.opengl_compatibiity_profile = opengl_compatibility_profile;
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
return Slic3r::GUI::GUI_Run(params);
|
||||
#else // SLIC3R_GUI
|
||||
@ -806,7 +822,13 @@ bool CLI::setup(int argc, char **argv)
|
||||
if (opt_loglevel != 0)
|
||||
set_logging_level(opt_loglevel->value);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
const ConfigOptionInt *opt_threads = m_config.opt<ConfigOptionInt>("threads");
|
||||
if (opt_threads != nullptr)
|
||||
thread_count = opt_threads->value;
|
||||
}
|
||||
|
||||
//FIXME Validating at this stage most likely does not make sense, as the config is not fully initialized yet.
|
||||
std::string validity = m_config.validate();
|
||||
|
||||
|
@ -266,7 +266,7 @@ int wmain(int argc, wchar_t **argv)
|
||||
// In that case, use Mesa.
|
||||
(::GetSystemMetrics(SM_REMOTESESSION) && !force_hw) ||
|
||||
// Try to load the default OpenGL driver and test its context version.
|
||||
! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(2, 0);
|
||||
! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(3, 2);
|
||||
#endif /* SLIC3R_GUI */
|
||||
|
||||
wchar_t path_to_exe[MAX_PATH + 1] = { 0 };
|
||||
|
@ -61,7 +61,7 @@ class DefaultArrangerCtl : public Arranger<ArrItem>::Ctl {
|
||||
public:
|
||||
DefaultArrangerCtl() = default;
|
||||
|
||||
explicit DefaultArrangerCtl(ArrangeTaskBase::Ctl &ctl) : taskctl{&ctl} {}
|
||||
explicit DefaultArrangerCtl(ArrangeTaskCtl &ctl) : taskctl{&ctl} {}
|
||||
|
||||
void update_status(int st) override
|
||||
{
|
||||
|
@ -292,7 +292,7 @@ class DefaultArranger: public Arranger<ArrItem> {
|
||||
|
||||
firstfit::SelectionStrategy sel{cmpfn, on_arranged, stop_cond};
|
||||
|
||||
constexpr auto ep = ex_tbb;
|
||||
constexpr auto ep = ex_seq;
|
||||
|
||||
VariantKernel basekernel;
|
||||
switch (m_settings.get_arrange_strategy()) {
|
||||
@ -328,7 +328,7 @@ class DefaultArranger: public Arranger<ArrItem> {
|
||||
// a pure RectangleBed with inner-fit polygon calculation.
|
||||
if (!with_wipe_tower &&
|
||||
m_settings.get_arrange_strategy() == ArrangeSettingsView::asAuto &&
|
||||
std::is_convertible_v<Bed, RectangleBed>) {
|
||||
IsRectangular<Bed>) {
|
||||
PackStrategyNFP base_strategy{std::move(kernel), ep, Accuracy, stop_cond};
|
||||
|
||||
RectangleOverfitPackingStrategy final_strategy{std::move(base_strategy)};
|
||||
|
@ -184,6 +184,12 @@ inline ExPolygons to_expolygons(const ArrangeBed &bed)
|
||||
|
||||
ArrangeBed to_arrange_bed(const Points &bedpts);
|
||||
|
||||
template<class Bed, class En = void> struct IsRectangular_ : public std::false_type {};
|
||||
template<> struct IsRectangular_<RectangleBed>: public std::true_type {};
|
||||
template<> struct IsRectangular_<BoundingBox>: public std::true_type {};
|
||||
|
||||
template<class Bed> static constexpr bool IsRectangular = IsRectangular_<Bed>::value;
|
||||
|
||||
} // namespace arr2
|
||||
|
||||
inline BoundingBox &bounding_box(BoundingBox &bb) { return bb; }
|
||||
|
@ -54,9 +54,9 @@ protected:
|
||||
public:
|
||||
TMArrangeKernel() = default;
|
||||
TMArrangeKernel(Vec2crd gravity_center, size_t itm_cnt, double bedarea = NaNd)
|
||||
: sink{gravity_center}
|
||||
, m_bin_area(bedarea)
|
||||
: m_bin_area(bedarea)
|
||||
, m_item_cnt{itm_cnt}
|
||||
, sink{gravity_center}
|
||||
{}
|
||||
|
||||
TMArrangeKernel(size_t itm_cnt, double bedarea = NaNd)
|
||||
@ -90,18 +90,12 @@ public:
|
||||
// Will hold the resulting score
|
||||
double score = 0;
|
||||
|
||||
// Density is the pack density: how big is the arranged pile
|
||||
double density = 0;
|
||||
|
||||
// Distinction of cases for the arrangement scene
|
||||
enum e_cases {
|
||||
// This branch is for big items in a mixed (big and small) scene
|
||||
// OR for all items in a small-only scene.
|
||||
BIG_ITEM,
|
||||
|
||||
// This branch is for the last big item in a mixed scene
|
||||
LAST_BIG_ITEM,
|
||||
|
||||
// For small items in a mixed scene.
|
||||
SMALL_ITEM,
|
||||
|
||||
@ -112,10 +106,8 @@ public:
|
||||
bool bigitems = is_big(envelope_area(item)) || m_rtree.empty();
|
||||
if (is_wt)
|
||||
compute_case = WIPE_TOWER;
|
||||
else if (bigitems && m_rem_cnt > 0)
|
||||
else if (bigitems)
|
||||
compute_case = BIG_ITEM;
|
||||
else if (bigitems && m_rem_cnt == 0)
|
||||
compute_case = LAST_BIG_ITEM;
|
||||
else
|
||||
compute_case = SMALL_ITEM;
|
||||
|
||||
@ -132,20 +124,8 @@ public:
|
||||
Point top_left{minc.x(), maxc.y()};
|
||||
Point bottom_right{maxc.x(), minc.y()};
|
||||
|
||||
// Now the distance of the gravity center will be calculated to the
|
||||
// five anchor points and the smallest will be chosen.
|
||||
std::array<double, 5> dists;
|
||||
auto cc = fullbb.center(); // The gravity center
|
||||
dists[0] = (minc - cc).cast<double>().norm();
|
||||
dists[1] = (maxc - cc).cast<double>().norm();
|
||||
dists[2] = (itmcntr - cc).template cast<double>().norm();
|
||||
dists[3] = (top_left - cc).cast<double>().norm();
|
||||
dists[4] = (bottom_right - cc).cast<double>().norm();
|
||||
|
||||
// The smalles distance from the arranged pile center:
|
||||
double dist = norm(*(std::min_element(dists.begin(), dists.end())));
|
||||
double bindist = norm((ibb.center() - active_sink).template cast<double>().norm());
|
||||
dist = 0.8 * dist + 0.2 * bindist;
|
||||
// The smallest distance from the arranged pile center:
|
||||
double dist = norm((itmcntr - m_pilebb.center()).template cast<double>().norm());
|
||||
|
||||
// Prepare a variable for the alignment score.
|
||||
// This will indicate: how well is the candidate item
|
||||
@ -153,7 +133,7 @@ public:
|
||||
// with all neighbors and return the score for the best
|
||||
// alignment. So it is enough for the candidate to be
|
||||
// aligned with only one item.
|
||||
auto alignment_score = 1.0;
|
||||
auto alignment_score = 1.;
|
||||
|
||||
auto query = bgi::intersects(ibb);
|
||||
auto& index = is_big(envelope_area(item)) ? m_rtree : m_smallsrtree;
|
||||
@ -173,31 +153,23 @@ public:
|
||||
auto bb = p.bb;
|
||||
bb.merge(ibb);
|
||||
auto bbarea = area(bb);
|
||||
auto ascore = 1.0 - (fixed_area(item) + parea) / bbarea;
|
||||
auto ascore = 1.0 - (area(fixed_bounding_box(item)) + area(p.bb)) / bbarea;
|
||||
|
||||
if(ascore < alignment_score)
|
||||
alignment_score = ascore;
|
||||
}
|
||||
}
|
||||
|
||||
auto fullbbsz = fullbb.size();
|
||||
density = std::sqrt(norm(fullbbsz.x()) * norm(fullbbsz.y()));
|
||||
double R = double(m_rem_cnt) / (m_item_cnt);
|
||||
R = std::pow(R, 1./3.);
|
||||
|
||||
// The final mix of the score is the balance between the
|
||||
// distance from the full pile center, the pack density and
|
||||
// the alignment with the neighbors
|
||||
if (result.empty())
|
||||
score = 0.50 * dist + 0.50 * density;
|
||||
else
|
||||
// Let the density matter more when fewer objects remain
|
||||
score = 0.50 * dist + (1.0 - R) * 0.20 * density +
|
||||
0.30 * alignment_score;
|
||||
|
||||
break;
|
||||
}
|
||||
case LAST_BIG_ITEM: {
|
||||
score = norm((itmcntr - m_pilebb.center()).template cast<double>().norm());
|
||||
// Let the density matter more when fewer objects remain
|
||||
score = 0.6 * dist + 0.1 * alignment_score + (1.0 - R) * (0.3 * dist) + R * 0.3 * alignment_score;
|
||||
|
||||
break;
|
||||
}
|
||||
case SMALL_ITEM: {
|
||||
@ -239,8 +211,11 @@ public:
|
||||
if (m_item_cnt == 0)
|
||||
m_item_cnt = m_rem_cnt + fixed.size() + 1;
|
||||
|
||||
if (std::isnan(m_bin_area))
|
||||
m_bin_area = area(bed);
|
||||
if (std::isnan(m_bin_area)) {
|
||||
auto sz = bounding_box(bed).size();
|
||||
|
||||
m_bin_area = scaled<double>(unscaled(sz.x()) * unscaled(sz.y()));
|
||||
}
|
||||
|
||||
m_norm = std::sqrt(m_bin_area);
|
||||
|
||||
@ -248,7 +223,7 @@ public:
|
||||
m_itemstats.reserve(fixed.size());
|
||||
m_rtree.clear();
|
||||
m_smallsrtree.clear();
|
||||
m_pilebb = {};
|
||||
m_pilebb = {active_sink, active_sink};
|
||||
unsigned idx = 0;
|
||||
for (auto &fixitem : fixed) {
|
||||
auto fixitmbb = fixed_bounding_box(fixitem);
|
||||
|
@ -104,6 +104,10 @@ ExPolygons to_expolygons(const SegmentedRectangleBed<Args...> &bed)
|
||||
return to_expolygons(RectangleBed{bed.bb});
|
||||
}
|
||||
|
||||
template<class SegB>
|
||||
struct IsRectangular_<SegB, std::enable_if_t<IsSegmentedBed<SegB>, void>> : public std::true_type
|
||||
{};
|
||||
|
||||
}} // namespace Slic3r::arr2
|
||||
|
||||
#endif // SEGMENTEDRECTANGLEBED_HPP
|
||||
|
@ -118,21 +118,13 @@ ArrangeTask<ArrItem>::process_native(Ctl &ctl)
|
||||
|
||||
} subctl{ctl, *this};
|
||||
|
||||
auto fixed_items = printable.unselected;
|
||||
|
||||
// static (unselected) unprintable objects should not be overlapped by
|
||||
// movable and printable objects
|
||||
std::copy(unprintable.unselected.begin(),
|
||||
unprintable.unselected.end(),
|
||||
std::back_inserter(fixed_items));
|
||||
|
||||
arranger->arrange(printable.selected, fixed_items, bed, subctl);
|
||||
arranger->arrange(printable.selected, printable.unselected, bed, subctl);
|
||||
|
||||
std::vector<int> printable_bed_indices =
|
||||
get_bed_indices(crange(printable.selected), crange(printable.unselected));
|
||||
|
||||
// If there are no printables, leave the physical bed empty
|
||||
constexpr int SearchFrom = 1;
|
||||
static constexpr int SearchFrom = 1;
|
||||
|
||||
// Unprintable items should go to the first logical (!) bed not containing
|
||||
// any printable items
|
||||
|
@ -147,6 +147,16 @@ public:
|
||||
return this->min.x() < other.max.x() && this->max.x() > other.min.x() && this->min.y() < other.max.y() && this->max.y() > other.min.y() &&
|
||||
this->min.z() < other.max.z() && this->max.z() > other.min.z();
|
||||
}
|
||||
|
||||
// Shares some boundary.
|
||||
bool shares_boundary(const BoundingBox3Base<PointType>& other) const {
|
||||
return is_approx(this->min.x(), other.max.x()) ||
|
||||
is_approx(this->max.x(), other.min.x()) ||
|
||||
is_approx(this->min.y(), other.max.y()) ||
|
||||
is_approx(this->max.y(), other.min.y()) ||
|
||||
is_approx(this->min.z(), other.max.z()) ||
|
||||
is_approx(this->max.z(), other.min.z());
|
||||
}
|
||||
};
|
||||
|
||||
// Will prevent warnings caused by non existing definition of template in hpp
|
||||
|
@ -88,7 +88,6 @@ set(SLIC3R_SOURCES
|
||||
ExtrusionSimulator.hpp
|
||||
FileParserError.hpp
|
||||
Fill/Fill.cpp
|
||||
Fill/Fill.hpp
|
||||
Fill/Fill3DHoneycomb.cpp
|
||||
Fill/Fill3DHoneycomb.hpp
|
||||
Fill/FillAdaptive.cpp
|
||||
@ -194,8 +193,6 @@ set(SLIC3R_SOURCES
|
||||
GCode/AvoidCrossingPerimeters.hpp
|
||||
GCode/Travels.cpp
|
||||
GCode/Travels.hpp
|
||||
GCode/LayerChanges.cpp
|
||||
GCode/LayerChanges.hpp
|
||||
GCode.cpp
|
||||
GCode.hpp
|
||||
GCodeReader.cpp
|
||||
|
@ -105,7 +105,7 @@ struct EmbossShape
|
||||
// Note: image is only cache it is not neccessary to store
|
||||
|
||||
// Store file data as plain string
|
||||
assert(file_data != nullptr);
|
||||
// For Embossed text file_data are nullptr
|
||||
ar(path, path_in_3mf, (file_data != nullptr) ? *file_data : std::string(""));
|
||||
}
|
||||
template<class Archive> void load(Archive &ar) {
|
||||
|
@ -446,7 +446,7 @@ inline void expolygons_rotate(ExPolygons &expolys, double angle)
|
||||
expoly.rotate(angle);
|
||||
}
|
||||
|
||||
inline bool expolygons_contain(ExPolygons &expolys, const Point &pt, bool border_result = true)
|
||||
inline bool expolygons_contain(const ExPolygons &expolys, const Point &pt, bool border_result = true)
|
||||
{
|
||||
for (const ExPolygon &expoly : expolys)
|
||||
if (expoly.contains(pt, border_result))
|
||||
|
@ -699,13 +699,16 @@ void gcode_spread_points(
|
||||
}
|
||||
}
|
||||
*/
|
||||
float area_total = 0;
|
||||
float volume_total = 0;
|
||||
float volume_excess = 0;
|
||||
float volume_deficit = 0;
|
||||
size_t n_cells = 0;
|
||||
float area_circle_total = 0;
|
||||
|
||||
float area_total = 0;
|
||||
float volume_total = 0;
|
||||
size_t n_cells = 0;
|
||||
|
||||
#if 0
|
||||
float volume_excess = 0;
|
||||
float volume_deficit = 0;
|
||||
float area_circle_total = 0;
|
||||
|
||||
// The intermediate lines.
|
||||
for (int j = row_first; j < row_last; ++ j) {
|
||||
const std::pair<float, float> &span1 = spans[j];
|
||||
@ -759,7 +762,11 @@ void gcode_spread_points(
|
||||
cell.volume = acc[j][i];
|
||||
cell.area = mask[j][i];
|
||||
assert(cell.area >= 0.f && cell.area <= 1.000001f);
|
||||
area_circle_total += area;
|
||||
|
||||
#if 0
|
||||
area_circle_total += area;
|
||||
#endif
|
||||
|
||||
if (cell.area < area)
|
||||
cell.area = area;
|
||||
cell.fraction_covered = std::clamp((cell.area > 0) ? (area / cell.area) : 0, 0.f, 1.f);
|
||||
@ -769,10 +776,15 @@ void gcode_spread_points(
|
||||
}
|
||||
float cell_height = cell.volume / cell.area;
|
||||
cell.excess_height = cell_height - height_target;
|
||||
|
||||
#if 0
|
||||
area_circle_total += area;
|
||||
if (cell.excess_height > 0.f)
|
||||
volume_excess += cell.excess_height * cell.area * cell.fraction_covered;
|
||||
else
|
||||
volume_deficit -= cell.excess_height * cell.area * cell.fraction_covered;
|
||||
#endif
|
||||
|
||||
volume_total += cell.volume * cell.fraction_covered;
|
||||
area_total += cell.area * cell.fraction_covered;
|
||||
}
|
||||
|
@ -1,37 +0,0 @@
|
||||
///|/ Copyright (c) Prusa Research 2016 - 2020 Vojtěch Bubník @bubnikv, Lukáš Matěna @lukasmatena
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#ifndef slic3r_Fill_hpp_
|
||||
#define slic3r_Fill_hpp_
|
||||
|
||||
#include <memory.h>
|
||||
#include <float.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../libslic3r.h"
|
||||
#include "../PrintConfig.hpp"
|
||||
|
||||
#include "FillBase.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class ExtrusionEntityCollection;
|
||||
class LayerRegion;
|
||||
|
||||
// An interface class to Perl, aggregating an instance of a Fill and a FillData.
|
||||
class Filler
|
||||
{
|
||||
public:
|
||||
Filler() : fill(nullptr) {}
|
||||
~Filler() {
|
||||
delete fill;
|
||||
fill = nullptr;
|
||||
}
|
||||
Fill *fill;
|
||||
FillParams params;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_Fill_hpp_
|
@ -35,7 +35,6 @@
|
||||
#include "GCode/WipeTower.hpp"
|
||||
#include "GCode/WipeTowerIntegration.hpp"
|
||||
#include "GCode/Travels.hpp"
|
||||
#include "GCode/LayerChanges.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "Polygon.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
@ -1214,7 +1213,7 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
||||
m_enable_cooling_markers = false; // we're not filtering these moves through CoolingBuffer
|
||||
m_avoid_crossing_perimeters.use_external_mp_once();
|
||||
file.write(this->retract_and_wipe());
|
||||
file.write(this->travel_to(Point(0, 0), ExtrusionRole::None, "move to origin position for next object"));
|
||||
file.write(this->travel_to(*this->last_position, Point(0, 0), ExtrusionRole::None, "move to origin position for next object"));
|
||||
m_enable_cooling_markers = true;
|
||||
// Disable motion planner when traveling to first object point.
|
||||
m_avoid_crossing_perimeters.disable_once();
|
||||
@ -1250,7 +1249,12 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
||||
// Prusa Multi-Material wipe tower.
|
||||
if (has_wipe_tower && ! layers_to_print.empty()) {
|
||||
m_wipe_tower = std::make_unique<GCode::WipeTowerIntegration>(print.config(), *print.wipe_tower_data().priming.get(), print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get());
|
||||
file.write(m_writer.travel_to_z(first_layer_height + m_config.z_offset.value, "Move to the first layer height"));
|
||||
|
||||
// Set position for wipe tower generation.
|
||||
Vec3d new_position = this->writer().get_position();
|
||||
new_position.z() = first_layer_height;
|
||||
this->writer().update_position(new_position);
|
||||
|
||||
if (print.config().single_extruder_multi_material_priming) {
|
||||
file.write(m_wipe_tower->prime(*this));
|
||||
// Verify, whether the print overaps the priming extrusions.
|
||||
@ -1637,7 +1641,7 @@ std::string GCodeGenerator::placeholder_parser_process(
|
||||
if (const std::vector<double> &pos = ppi.opt_position->values; ppi.position != pos) {
|
||||
// Update G-code writer.
|
||||
m_writer.update_position({ pos[0], pos[1], pos[2] });
|
||||
this->set_last_pos(this->gcode_to_point({ pos[0], pos[1] }));
|
||||
this->last_position = this->gcode_to_point({ pos[0], pos[1] });
|
||||
}
|
||||
|
||||
for (const Extruder &e : m_writer.extruders()) {
|
||||
@ -2061,24 +2065,48 @@ bool GCodeGenerator::line_distancer_is_required(const std::vector<unsigned int>&
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace GCode::Impl {
|
||||
AABBTreeLines::LinesDistancer<Linef> get_previous_layer_distancer(
|
||||
const GCodeGenerator::ObjectsLayerToPrint& objects_to_print,
|
||||
const ExPolygons& slices
|
||||
) {
|
||||
std::vector<Linef> lines;
|
||||
for (const GCodeGenerator::ObjectLayerToPrint &object_to_print : objects_to_print) {
|
||||
for (const PrintInstance& instance: object_to_print.object()->instances()) {
|
||||
for (const ExPolygon& polygon : slices) {
|
||||
for (const Line& line : polygon.lines()) {
|
||||
lines.emplace_back(unscaled(Point{line.a + instance.shift}), unscaled(Point{line.b + instance.shift}));
|
||||
}
|
||||
}
|
||||
std::string GCodeGenerator::get_layer_change_gcode(const Vec3d& from, const Vec3d& to, const unsigned extruder_id) {
|
||||
const Polyline xy_path{
|
||||
this->gcode_to_point(from.head<2>()),
|
||||
this->gcode_to_point(to.head<2>())
|
||||
};
|
||||
|
||||
}
|
||||
using namespace GCode::Impl::Travels;
|
||||
|
||||
ElevatedTravelParams elevation_params{
|
||||
get_elevated_traval_params(xy_path, this->m_config, extruder_id, this->m_travel_obstacle_tracker)};
|
||||
|
||||
const double initial_elevation = from.z();
|
||||
const double z_change = to.z() - from.z();
|
||||
elevation_params.lift_height = std::max(z_change, elevation_params.lift_height);
|
||||
|
||||
const double path_length = unscaled(xy_path.length());
|
||||
const double lift_at_travel_end =
|
||||
(elevation_params.lift_height / elevation_params.slope_end * path_length);
|
||||
if (lift_at_travel_end < z_change) {
|
||||
elevation_params.lift_height = z_change;
|
||||
elevation_params.slope_end = path_length;
|
||||
}
|
||||
return AABBTreeLines::LinesDistancer{std::move(lines)};
|
||||
}
|
||||
|
||||
const std::vector<double> ensure_points_at_distances = linspace(
|
||||
elevation_params.slope_end - elevation_params.blend_width / 2.0,
|
||||
elevation_params.slope_end + elevation_params.blend_width / 2.0,
|
||||
elevation_params.parabola_points_count
|
||||
);
|
||||
|
||||
Points3 travel{generate_elevated_travel(
|
||||
xy_path.points, ensure_points_at_distances, initial_elevation,
|
||||
ElevatedTravelFormula{elevation_params}
|
||||
)};
|
||||
|
||||
std::string travel_gcode;
|
||||
Vec3d previous_point{this->point_to_gcode(travel.front())};
|
||||
for (const Vec3crd& point : tcb::span{travel}.subspan(1)) {
|
||||
const Vec3d gcode_point{this->point_to_gcode(point)};
|
||||
travel_gcode += this->m_writer.get_travel_to_xyz_gcode(previous_point, gcode_point, "layer change");
|
||||
previous_point = gcode_point;
|
||||
}
|
||||
return travel_gcode;
|
||||
}
|
||||
|
||||
// In sequential mode, process_layer is called once per each object and its copy,
|
||||
@ -2124,7 +2152,7 @@ LayerResult GCodeGenerator::process_layer(
|
||||
return result;
|
||||
|
||||
// Extract 1st object_layer and support_layer of this set of layers with an equal print_z.
|
||||
coordf_t print_z = layer.print_z;
|
||||
coordf_t print_z = layer.print_z + m_config.z_offset.value;
|
||||
bool first_layer = layer.id() == 0;
|
||||
unsigned int first_extruder_id = layer_tools.extruders.front();
|
||||
|
||||
@ -2150,6 +2178,7 @@ LayerResult GCodeGenerator::process_layer(
|
||||
m_enable_loop_clipping = !enable;
|
||||
}
|
||||
|
||||
|
||||
std::string gcode;
|
||||
assert(is_decimal_separator_point()); // for the sprintfs
|
||||
|
||||
@ -2168,9 +2197,10 @@ LayerResult GCodeGenerator::process_layer(
|
||||
m_last_layer_z = static_cast<float>(print_z);
|
||||
m_max_layer_z = std::max(m_max_layer_z, m_last_layer_z);
|
||||
m_last_height = height;
|
||||
m_current_layer_first_position = std::nullopt;
|
||||
|
||||
// Set new layer - this will change Z and force a retraction if retract_layer_change is enabled.
|
||||
if (! print.config().before_layer_gcode.value.empty()) {
|
||||
if (!first_layer && ! print.config().before_layer_gcode.value.empty()) {
|
||||
DynamicConfig config;
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index + 1));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
|
||||
@ -2179,13 +2209,13 @@ LayerResult GCodeGenerator::process_layer(
|
||||
print.config().before_layer_gcode.value, m_writer.extruder()->id(), &config)
|
||||
+ "\n";
|
||||
}
|
||||
gcode += this->change_layer(previous_layer_z, print_z, result.spiral_vase_enable); // this will increase m_layer_index
|
||||
gcode += this->change_layer(previous_layer_z, print_z); // this will increase m_layer_index
|
||||
m_layer = &layer;
|
||||
if (this->line_distancer_is_required(layer_tools.extruders) && this->m_layer != nullptr && this->m_layer->lower_layer != nullptr) {
|
||||
this->m_previous_layer_distancer = GCode::Impl::get_previous_layer_distancer(layers, layer.lower_layer->lslices);
|
||||
}
|
||||
if (this->line_distancer_is_required(layer_tools.extruders) && this->m_layer != nullptr && this->m_layer->lower_layer != nullptr)
|
||||
m_travel_obstacle_tracker.init_layer(layer, layers);
|
||||
|
||||
m_object_layer_over_raft = false;
|
||||
if (! print.config().layer_gcode.value.empty()) {
|
||||
if (!first_layer && ! print.config().layer_gcode.value.empty()) {
|
||||
DynamicConfig config;
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
|
||||
@ -2305,6 +2335,32 @@ LayerResult GCodeGenerator::process_layer(
|
||||
is_anything_overridden, false /* print_wipe_extrusions */);
|
||||
}
|
||||
|
||||
|
||||
// During layer change the starting position of next layer is now known.
|
||||
// The solution is thus to emplace a temporary tag to the gcode, cache the postion and
|
||||
// replace the tag later. The tag is Layer_Change_Travel, the cached position is
|
||||
// m_current_layer_first_position and it is replaced here.
|
||||
const std::string tag = GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change_Travel);
|
||||
std::string layer_change_gcode;
|
||||
const bool do_ramping_layer_change = (
|
||||
m_previous_layer_last_position
|
||||
&& m_current_layer_first_position
|
||||
&& m_layer_change_extruder_id
|
||||
&& !result.spiral_vase_enable
|
||||
&& print_z > previous_layer_z
|
||||
&& EXTRUDER_CONFIG(travel_ramping_lift)
|
||||
&& EXTRUDER_CONFIG(travel_slope) > 0 && EXTRUDER_CONFIG(travel_slope) < 90
|
||||
);
|
||||
if (first_layer) {
|
||||
layer_change_gcode = ""; // Explicit for readability.
|
||||
} else if (do_ramping_layer_change) {
|
||||
layer_change_gcode = this->get_layer_change_gcode(*m_previous_layer_last_position, *m_current_layer_first_position, *m_layer_change_extruder_id);
|
||||
} else {
|
||||
layer_change_gcode = this->writer().get_travel_to_z_gcode(print_z, "simple layer change");
|
||||
}
|
||||
|
||||
boost::algorithm::replace_first(gcode, tag, layer_change_gcode);
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
|
||||
log_memory_info();
|
||||
|
||||
@ -2350,10 +2406,10 @@ void GCodeGenerator::process_layer_single_object(
|
||||
m_avoid_crossing_perimeters.init_layer(*m_layer);
|
||||
// When starting a new object, use the external motion planner for the first travel move.
|
||||
const Point &offset = print_object.instances()[print_instance.instance_id].shift;
|
||||
std::pair<const PrintObject*, Point> this_object_copy(&print_object, offset);
|
||||
if (m_last_obj_copy != this_object_copy)
|
||||
GCode::PrintObjectInstance next_instance = {&print_object, int(print_instance.instance_id)};
|
||||
if (m_current_instance != next_instance)
|
||||
m_avoid_crossing_perimeters.use_external_mp_once();
|
||||
m_last_obj_copy = this_object_copy;
|
||||
m_current_instance = next_instance;
|
||||
this->set_origin(unscale(offset));
|
||||
gcode += m_label_objects.start_object(print_instance.print_object.instances()[print_instance.instance_id], GCode::LabelObjects::IncludeName::No);
|
||||
}
|
||||
@ -2462,9 +2518,10 @@ void GCodeGenerator::process_layer_single_object(
|
||||
init_layer_delayed();
|
||||
m_config.apply(region.config());
|
||||
const auto extrusion_name = ironing ? "ironing"sv : "infill"sv;
|
||||
for (const ExtrusionEntityReference &fill : chain_extrusion_references(temp_fill_extrusions, &m_last_pos))
|
||||
const Point* start_near = this->last_position ? &(*(this->last_position)) : nullptr;
|
||||
for (const ExtrusionEntityReference &fill : chain_extrusion_references(temp_fill_extrusions, start_near))
|
||||
if (auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(&fill.extrusion_entity()); eec) {
|
||||
for (const ExtrusionEntityReference &ee : chain_extrusion_references(*eec, &m_last_pos, fill.flipped()))
|
||||
for (const ExtrusionEntityReference &ee : chain_extrusion_references(*eec, start_near, fill.flipped()))
|
||||
gcode += this->extrude_entity(ee, smooth_path_cache, extrusion_name);
|
||||
} else
|
||||
gcode += this->extrude_entity(fill, smooth_path_cache, extrusion_name);
|
||||
@ -2493,9 +2550,11 @@ void GCodeGenerator::process_layer_single_object(
|
||||
init_layer_delayed();
|
||||
m_config.apply(region.config());
|
||||
}
|
||||
for (const ExtrusionEntity *ee : *eec)
|
||||
for (const ExtrusionEntity *ee : *eec) {
|
||||
// Don't reorder, don't flip.
|
||||
gcode += this->extrude_entity({ *ee, false }, smooth_path_cache, comment_perimeter, -1.);
|
||||
gcode += this->extrude_entity({*ee, false}, smooth_path_cache, comment_perimeter, -1.);
|
||||
m_travel_obstacle_tracker.mark_extruded(ee, print_instance.object_layer_to_print_id, print_instance.instance_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -2586,7 +2645,9 @@ void GCodeGenerator::set_origin(const Vec2d &pointf)
|
||||
{
|
||||
// if origin increases (goes towards right), last_pos decreases because it goes towards left
|
||||
const auto offset = Point::new_scale(m_origin - pointf);
|
||||
m_last_pos += offset;
|
||||
if (last_position.has_value())
|
||||
*(this->last_position) += offset;
|
||||
|
||||
m_wipe.offset_path(offset);
|
||||
m_origin = pointf;
|
||||
}
|
||||
@ -2604,63 +2665,10 @@ std::string GCodeGenerator::preamble()
|
||||
return gcode;
|
||||
}
|
||||
|
||||
|
||||
std::optional<std::string> GCodeGenerator::get_helical_layer_change_gcode(
|
||||
const coordf_t previous_layer_z,
|
||||
const coordf_t print_z,
|
||||
const std::string& comment
|
||||
) {
|
||||
|
||||
if (!this->last_pos_defined()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const double circle_radius{2};
|
||||
const unsigned n_gon_points_count{16};
|
||||
|
||||
const Point n_gon_start_point{this->last_pos()};
|
||||
|
||||
GCode::Impl::LayerChanges::Bed bed{
|
||||
this->m_config.bed_shape.values,
|
||||
circle_radius * 2
|
||||
};
|
||||
if (!bed.contains_within_padding(this->point_to_gcode(n_gon_start_point))) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const Vec2crd n_gon_vector{scaled(Vec2d{
|
||||
(bed.centroid - this->point_to_gcode(n_gon_start_point)).normalized() * circle_radius
|
||||
})};
|
||||
const Point n_gon_centeroid{n_gon_start_point + n_gon_vector};
|
||||
|
||||
const Polygon n_gon{GCode::Impl::LayerChanges::generate_regular_polygon(
|
||||
n_gon_centeroid,
|
||||
n_gon_start_point,
|
||||
n_gon_points_count
|
||||
)};
|
||||
|
||||
const double n_gon_circumference = unscaled(n_gon.length());
|
||||
|
||||
const double z_change{print_z - previous_layer_z};
|
||||
Points3 helix{GCode::Impl::Travels::generate_elevated_travel(
|
||||
n_gon.points,
|
||||
{},
|
||||
previous_layer_z,
|
||||
[&](const double distance){
|
||||
return distance / n_gon_circumference * z_change;
|
||||
}
|
||||
)};
|
||||
|
||||
helix.emplace_back(to_3d(this->last_pos(), scaled(print_z)));
|
||||
|
||||
return this->generate_travel_gcode(helix, comment);
|
||||
}
|
||||
|
||||
// called by GCodeGenerator::process_layer()
|
||||
std::string GCodeGenerator::change_layer(
|
||||
coordf_t previous_layer_z,
|
||||
coordf_t print_z,
|
||||
const bool spiral_vase_enabled
|
||||
coordf_t print_z
|
||||
) {
|
||||
std::string gcode;
|
||||
if (m_layer_count > 0)
|
||||
@ -2670,31 +2678,16 @@ std::string GCodeGenerator::change_layer(
|
||||
if (EXTRUDER_CONFIG(retract_layer_change))
|
||||
gcode += this->retract_and_wipe();
|
||||
|
||||
const std::string comment{"move to next layer (" + std::to_string(m_layer_index) + ")"};
|
||||
Vec3d new_position = this->writer().get_position();
|
||||
new_position.z() = print_z;
|
||||
this->writer().update_position(new_position);
|
||||
|
||||
bool do_helical_layer_change{
|
||||
!spiral_vase_enabled
|
||||
&& print_z > previous_layer_z
|
||||
&& EXTRUDER_CONFIG(retract_layer_change)
|
||||
&& EXTRUDER_CONFIG(retract_length) > 0
|
||||
&& EXTRUDER_CONFIG(travel_ramping_lift)
|
||||
&& EXTRUDER_CONFIG(travel_slope) > 0 && EXTRUDER_CONFIG(travel_slope) < 90
|
||||
};
|
||||
m_previous_layer_last_position = this->last_position ?
|
||||
std::optional{to_3d(this->point_to_gcode(*this->last_position), previous_layer_z)} :
|
||||
std::nullopt;
|
||||
|
||||
const std::optional<std::string> helix_gcode{
|
||||
do_helical_layer_change ?
|
||||
this->get_helical_layer_change_gcode(
|
||||
m_config.z_offset.value + previous_layer_z,
|
||||
m_config.z_offset.value + print_z,
|
||||
comment
|
||||
) :
|
||||
std::nullopt
|
||||
};
|
||||
gcode += (
|
||||
helix_gcode ?
|
||||
*helix_gcode :
|
||||
m_writer.travel_to_z(m_config.z_offset.value + print_z, comment)
|
||||
);
|
||||
gcode += GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change_Travel);
|
||||
this->m_layer_change_extruder_id = m_writer.extruder()->id();
|
||||
|
||||
// forget last wiping path as wiping after raising Z is pointless
|
||||
m_wipe.reset_path();
|
||||
@ -2719,11 +2712,11 @@ static constexpr const double min_gcode_segment_length = 0.002;
|
||||
std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed)
|
||||
{
|
||||
// Extrude all loops CCW.
|
||||
bool is_hole = loop_src.is_clockwise();
|
||||
Point seam_point = this->last_pos();
|
||||
if (! m_config.spiral_vase && comment_is_perimeter(description)) {
|
||||
bool is_hole = loop_src.is_clockwise();
|
||||
Point seam_point = this->last_position.has_value() ? *this->last_position : Point::Zero();
|
||||
if (!m_config.spiral_vase && comment_is_perimeter(description)) {
|
||||
assert(m_layer != nullptr);
|
||||
seam_point = m_seam_placer.place_seam(m_layer, loop_src, m_config.external_perimeters_first, this->last_pos());
|
||||
seam_point = m_seam_placer.place_seam(m_layer, loop_src, m_config.external_perimeters_first, seam_point);
|
||||
}
|
||||
// Because the G-code export has 1um resolution, don't generate segments shorter than 1.5 microns,
|
||||
// thus empty path segments will not be produced by G-code export.
|
||||
@ -2762,7 +2755,7 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC
|
||||
if (std::optional<Point> pt = wipe_hide_seam(smooth_path, is_hole, scale_(EXTRUDER_CONFIG(nozzle_diameter))); pt) {
|
||||
// Generate the seam hiding travel move.
|
||||
gcode += m_writer.travel_to_xy(this->point_to_gcode(*pt), "move inwards before travel");
|
||||
this->set_last_pos(*pt);
|
||||
this->last_position = *pt;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2774,8 +2767,9 @@ std::string GCodeGenerator::extrude_skirt(
|
||||
const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed)
|
||||
{
|
||||
assert(loop_src.is_counter_clockwise());
|
||||
Point seam_point = this->last_position.has_value() ? *this->last_position : Point::Zero();
|
||||
GCode::SmoothPath smooth_path = smooth_path_cache.resolve_or_fit_split_with_seam(
|
||||
loop_src, false, m_scaled_resolution, this->last_pos(), scaled<double>(0.0015));
|
||||
loop_src, false, m_scaled_resolution, seam_point, scaled<double>(0.0015));
|
||||
|
||||
// Clip the path to avoid the extruder to get exactly on the first point of the loop;
|
||||
// if polyline was shorter than the clipping distance we'd get a null polyline, so
|
||||
@ -2954,28 +2948,63 @@ void GCodeGenerator::GCodeOutputStream::write_format(const char* format, ...)
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
std::string GCodeGenerator::travel_to_first_position(const Vec3crd& point) {
|
||||
std::string gcode;
|
||||
|
||||
const Vec3d gcode_point = to_3d(this->point_to_gcode(point.head<2>()), unscaled(point.z()));
|
||||
|
||||
if (!this->last_position) {
|
||||
double lift{
|
||||
EXTRUDER_CONFIG(travel_ramping_lift) ? EXTRUDER_CONFIG(travel_max_lift) :
|
||||
EXTRUDER_CONFIG(retract_lift)};
|
||||
const double upper_limit = EXTRUDER_CONFIG(retract_lift_below);
|
||||
const double lower_limit = EXTRUDER_CONFIG(retract_lift_above);
|
||||
if ((lower_limit > 0 && gcode_point.z() < lower_limit) ||
|
||||
(upper_limit > 0 && gcode_point.z() > upper_limit)) {
|
||||
lift = 0.0;
|
||||
}
|
||||
gcode += this->writer().get_travel_to_z_gcode(gcode_point.z() + lift, "lift");
|
||||
}
|
||||
|
||||
this->last_position = point.head<2>();
|
||||
this->writer().update_position(gcode_point);
|
||||
|
||||
std::string comment{"move to first layer point"};
|
||||
gcode += this->writer().get_travel_to_xy_gcode(gcode_point.head<2>(), comment);
|
||||
gcode += this->writer().get_travel_to_z_gcode(gcode_point.z(), comment);
|
||||
|
||||
m_current_layer_first_position = gcode_point;
|
||||
return gcode;
|
||||
}
|
||||
|
||||
std::string GCodeGenerator::_extrude(
|
||||
const ExtrusionAttributes &path_attr,
|
||||
const Geometry::ArcWelder::Path &path,
|
||||
const ExtrusionAttributes &path_attr,
|
||||
const Geometry::ArcWelder::Path &path,
|
||||
const std::string_view description,
|
||||
double speed)
|
||||
{
|
||||
std::string gcode;
|
||||
const std::string_view description_bridge = path_attr.role.is_bridge() ? " (bridge)"sv : ""sv;
|
||||
|
||||
// go to first point of extrusion path
|
||||
if (!m_last_pos_defined) {
|
||||
const double z = this->m_last_layer_z + this->m_config.z_offset.value;
|
||||
const std::string comment{"move to print after unknown position"};
|
||||
gcode += this->retract_and_wipe();
|
||||
gcode += this->m_writer.travel_to_xy(this->point_to_gcode(path.front().point), comment);
|
||||
gcode += this->m_writer.get_travel_to_z_gcode(z, comment);
|
||||
} else if ( m_last_pos != path.front().point) {
|
||||
std::string comment = "move to first ";
|
||||
comment += description;
|
||||
comment += description_bridge;
|
||||
comment += " point";
|
||||
gcode += this->travel_to(path.front().point, path_attr.role, comment);
|
||||
if (!m_current_layer_first_position) {
|
||||
const Vec3crd point = to_3d(path.front().point, scaled(this->m_last_layer_z));
|
||||
gcode += this->travel_to_first_position(point);
|
||||
} else {
|
||||
// go to first point of extrusion path
|
||||
if (!this->last_position) {
|
||||
const double z = this->m_last_layer_z;
|
||||
const std::string comment{"move to print after unknown position"};
|
||||
gcode += this->retract_and_wipe();
|
||||
gcode += this->m_writer.travel_to_xy(this->point_to_gcode(path.front().point), comment);
|
||||
gcode += this->m_writer.get_travel_to_z_gcode(z, comment);
|
||||
} else if ( this->last_position != path.front().point) {
|
||||
std::string comment = "move to first ";
|
||||
comment += description;
|
||||
comment += description_bridge;
|
||||
comment += " point";
|
||||
const std::string travel_gcode{this->travel_to(*this->last_position, path.front().point, path_attr.role, comment)};
|
||||
gcode += travel_gcode;
|
||||
}
|
||||
}
|
||||
|
||||
// compensate retraction
|
||||
@ -3142,7 +3171,7 @@ std::string GCodeGenerator::_extrude(
|
||||
gcode += m_writer.set_speed(F, "", cooling_marker_setspeed_comments);
|
||||
if (dynamic_speed_and_fan_speed.second >= 0)
|
||||
gcode += ";_SET_FAN_SPEED" + std::to_string(int(dynamic_speed_and_fan_speed.second)) + "\n";
|
||||
double path_length = 0.;
|
||||
|
||||
std::string comment;
|
||||
if (m_config.gcode_comments) {
|
||||
comment = description;
|
||||
@ -3176,16 +3205,13 @@ std::string GCodeGenerator::_extrude(
|
||||
}
|
||||
if (radius == 0) {
|
||||
// Extrude line segment.
|
||||
if (const double line_length = (p - prev).norm(); line_length > 0) {
|
||||
path_length += line_length;
|
||||
if (const double line_length = (p - prev).norm(); line_length > 0)
|
||||
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
|
||||
}
|
||||
} else {
|
||||
double angle = Geometry::ArcWelder::arc_angle(prev.cast<double>(), p.cast<double>(), double(radius));
|
||||
assert(angle > 0);
|
||||
const double line_length = angle * std::abs(radius);
|
||||
path_length += line_length;
|
||||
const double dE = e_per_mm * line_length;
|
||||
const double dE = e_per_mm * line_length;
|
||||
assert(dE > 0);
|
||||
gcode += m_writer.extrude_to_xy_G2G3IJ(p, ij, it->ccw(), dE, comment);
|
||||
}
|
||||
@ -3200,7 +3226,7 @@ std::string GCodeGenerator::_extrude(
|
||||
if (dynamic_speed_and_fan_speed.second >= 0)
|
||||
gcode += ";_RESET_FAN_SPEED\n";
|
||||
|
||||
this->set_last_pos(path.back().point);
|
||||
this->last_position = path.back().point;
|
||||
return gcode;
|
||||
}
|
||||
|
||||
@ -3220,9 +3246,13 @@ std::string GCodeGenerator::generate_travel_gcode(
|
||||
// use G1 because we rely on paths being straight (G0 may make round paths)
|
||||
gcode += this->m_writer.set_travel_acceleration(acceleration);
|
||||
|
||||
for (const Vec3crd& point : travel) {
|
||||
gcode += this->m_writer.travel_to_xyz(to_3d(this->point_to_gcode(point.head<2>()), unscaled(point.z())), comment);
|
||||
this->set_last_pos(point.head<2>());
|
||||
Vec3d previous_point{this->point_to_gcode(travel.front())};
|
||||
for (const Vec3crd& point : tcb::span{travel}.subspan(1)) {
|
||||
const Vec3d gcode_point{this->point_to_gcode(point)};
|
||||
|
||||
gcode += this->m_writer.travel_to_xyz(previous_point, gcode_point, comment);
|
||||
this->last_position = point.head<2>();
|
||||
previous_point = gcode_point;
|
||||
}
|
||||
|
||||
if (! GCodeWriter::supports_separate_travel_acceleration(config().gcode_flavor)) {
|
||||
@ -3314,18 +3344,16 @@ Polyline GCodeGenerator::generate_travel_xy_path(
|
||||
}
|
||||
|
||||
// This method accepts &point in print coordinates.
|
||||
std::string GCodeGenerator::travel_to(const Point &point, ExtrusionRole role, std::string comment)
|
||||
{
|
||||
|
||||
const Point start_point = this->last_pos();
|
||||
|
||||
std::string GCodeGenerator::travel_to(
|
||||
const Point &start_point, const Point &end_point, ExtrusionRole role, const std::string &comment
|
||||
) {
|
||||
// check whether a straight travel move would need retraction
|
||||
|
||||
bool could_be_wipe_disabled {false};
|
||||
bool needs_retraction = this->needs_retraction(Polyline{start_point, point}, role);
|
||||
bool needs_retraction = this->needs_retraction(Polyline{start_point, end_point}, role);
|
||||
|
||||
Polyline xy_path{generate_travel_xy_path(
|
||||
start_point, point, needs_retraction, could_be_wipe_disabled
|
||||
start_point, end_point, needs_retraction, could_be_wipe_disabled
|
||||
)};
|
||||
|
||||
needs_retraction = this->needs_retraction(xy_path, role);
|
||||
@ -3336,12 +3364,12 @@ std::string GCodeGenerator::travel_to(const Point &point, ExtrusionRole role, st
|
||||
m_wipe.reset_path();
|
||||
}
|
||||
|
||||
Point position_before_wipe{this->last_pos()};
|
||||
Point position_before_wipe{*this->last_position};
|
||||
wipe_retract_gcode = this->retract_and_wipe();
|
||||
|
||||
if (this->last_pos() != position_before_wipe) {
|
||||
if (*this->last_position != position_before_wipe) {
|
||||
xy_path = generate_travel_xy_path(
|
||||
this->last_pos(), point, needs_retraction, could_be_wipe_disabled
|
||||
*this->last_position, end_point, needs_retraction, could_be_wipe_disabled
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@ -3353,16 +3381,24 @@ std::string GCodeGenerator::travel_to(const Point &point, ExtrusionRole role, st
|
||||
const unsigned extruder_id = this->m_writer.extruder()->id();
|
||||
const double retract_length = this->m_config.retract_length.get_at(extruder_id);
|
||||
bool can_be_flat{!needs_retraction || retract_length == 0};
|
||||
const double initial_elevation = this->m_last_layer_z + this->m_config.z_offset.value;
|
||||
const double initial_elevation = this->m_last_layer_z;
|
||||
|
||||
const double upper_limit = this->m_config.retract_lift_below.get_at(extruder_id);
|
||||
const double lower_limit = this->m_config.retract_lift_above.get_at(extruder_id);
|
||||
if ((lower_limit > 0 && initial_elevation < lower_limit) ||
|
||||
(upper_limit > 0 && initial_elevation > upper_limit)) {
|
||||
can_be_flat = true;
|
||||
}
|
||||
|
||||
const Points3 travel = (
|
||||
can_be_flat ?
|
||||
GCode::Impl::Travels::generate_flat_travel(xy_path.points, initial_elevation) :
|
||||
GCode::Impl::Travels::generate_travel_to_extrusion(
|
||||
xy_path,
|
||||
this->m_config,
|
||||
m_config,
|
||||
extruder_id,
|
||||
initial_elevation,
|
||||
this->m_previous_layer_distancer,
|
||||
m_travel_obstacle_tracker,
|
||||
scaled(m_origin)
|
||||
)
|
||||
);
|
||||
@ -3497,7 +3533,7 @@ std::string GCodeGenerator::set_extruder(unsigned int extruder_id, double print_
|
||||
gcode += m_ooze_prevention.post_toolchange(*this);
|
||||
|
||||
// The position is now known after the tool change.
|
||||
this->m_last_pos_defined = false;
|
||||
this->last_position = std::nullopt;
|
||||
|
||||
return gcode;
|
||||
}
|
||||
|
@ -38,8 +38,9 @@
|
||||
#include "GCode/WipeTowerIntegration.hpp"
|
||||
#include "GCode/SeamPlacer.hpp"
|
||||
#include "GCode/GCodeProcessor.hpp"
|
||||
#include "EdgeGrid.hpp"
|
||||
#include "GCode/ThumbnailData.hpp"
|
||||
#include "GCode/Travels.hpp"
|
||||
#include "EdgeGrid.hpp"
|
||||
#include "tcbspan/span.hpp"
|
||||
|
||||
#include <memory>
|
||||
@ -89,6 +90,30 @@ struct LayerResult {
|
||||
static LayerResult make_nop_layer_result() { return {"", std::numeric_limits<coord_t>::max(), false, false, true}; }
|
||||
};
|
||||
|
||||
namespace GCode {
|
||||
// Object and support extrusions of the same PrintObject at the same print_z.
|
||||
// public, so that it could be accessed by free helper functions from GCode.cpp
|
||||
struct ObjectLayerToPrint
|
||||
{
|
||||
ObjectLayerToPrint() : object_layer(nullptr), support_layer(nullptr) {}
|
||||
const Layer* object_layer;
|
||||
const SupportLayer* support_layer;
|
||||
const Layer* layer() const { return (object_layer != nullptr) ? object_layer : support_layer; }
|
||||
const PrintObject* object() const { return (this->layer() != nullptr) ? this->layer()->object() : nullptr; }
|
||||
coordf_t print_z() const { return (object_layer != nullptr && support_layer != nullptr) ? 0.5 * (object_layer->print_z + support_layer->print_z) : this->layer()->print_z; }
|
||||
};
|
||||
|
||||
struct PrintObjectInstance
|
||||
{
|
||||
const PrintObject *print_object = nullptr;
|
||||
int instance_idx = -1;
|
||||
|
||||
bool operator==(const PrintObjectInstance &other) const {return print_object == other.print_object && instance_idx == other.instance_idx; }
|
||||
bool operator!=(const PrintObjectInstance &other) const { return *this == other; }
|
||||
};
|
||||
|
||||
} // namespace GCode
|
||||
|
||||
class GCodeGenerator {
|
||||
|
||||
public:
|
||||
@ -103,7 +128,6 @@ public:
|
||||
m_layer(nullptr),
|
||||
m_object_layer_over_raft(false),
|
||||
m_volumetric_speed(0),
|
||||
m_last_pos_defined(false),
|
||||
m_last_extrusion_role(GCodeExtrusionRole::None),
|
||||
m_last_width(0.0f),
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
@ -112,7 +136,7 @@ public:
|
||||
m_brim_done(false),
|
||||
m_second_layer_things_done(false),
|
||||
m_silent_time_estimator_enabled(false),
|
||||
m_last_obj_copy(nullptr, Point(std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max()))
|
||||
m_current_instance({nullptr, -1})
|
||||
{}
|
||||
~GCodeGenerator() = default;
|
||||
|
||||
@ -124,14 +148,27 @@ public:
|
||||
const Vec2d& origin() const { return m_origin; }
|
||||
void set_origin(const Vec2d &pointf);
|
||||
void set_origin(const coordf_t x, const coordf_t y) { this->set_origin(Vec2d(x, y)); }
|
||||
const Point& last_pos() const { return m_last_pos; }
|
||||
// Convert coordinates of the active object to G-code coordinates, possibly adjusted for extruder offset.
|
||||
template<typename Derived>
|
||||
Vec2d point_to_gcode(const Eigen::MatrixBase<Derived> &point) const {
|
||||
static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) == 2, "GCodeGenerator::point_to_gcode(): first parameter is not a 2D vector");
|
||||
return Vec2d(unscaled<double>(point.x()), unscaled<double>(point.y())) + m_origin
|
||||
- m_config.extruder_offset.get_at(m_writer.extruder()->id());
|
||||
Eigen::Matrix<double, Derived::SizeAtCompileTime, 1, Eigen::DontAlign> point_to_gcode(const Eigen::MatrixBase<Derived> &point) const {
|
||||
static_assert(
|
||||
Derived::IsVectorAtCompileTime,
|
||||
"GCodeGenerator::point_to_gcode(): first parameter is not a vector"
|
||||
);
|
||||
static_assert(
|
||||
int(Derived::SizeAtCompileTime) == 2 || int(Derived::SizeAtCompileTime) == 3,
|
||||
"GCodeGenerator::point_to_gcode(): first parameter is not a 2D or 3D vector"
|
||||
);
|
||||
|
||||
if constexpr (Derived::SizeAtCompileTime == 2) {
|
||||
return Vec2d(unscaled<double>(point.x()), unscaled<double>(point.y())) + m_origin
|
||||
- m_config.extruder_offset.get_at(m_writer.extruder()->id());
|
||||
} else {
|
||||
const Vec2d gcode_point_xy{this->point_to_gcode(point.template head<2>())};
|
||||
return to_3d(gcode_point_xy, unscaled(point.z()));
|
||||
}
|
||||
}
|
||||
|
||||
// Convert coordinates of the active object to G-code coordinates, possibly adjusted for extruder offset and quantized to G-code resolution.
|
||||
template<typename Derived>
|
||||
Vec2d point_to_gcode_quantized(const Eigen::MatrixBase<Derived> &point) const {
|
||||
@ -151,8 +188,6 @@ public:
|
||||
std::string placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override = nullptr);
|
||||
bool enable_cooling_markers() const { return m_enable_cooling_markers; }
|
||||
|
||||
// For Perl bindings, to be used exclusively by unit tests.
|
||||
unsigned int layer_count() const { return m_layer_count; }
|
||||
void set_layer_count(unsigned int value) { m_layer_count = value; }
|
||||
void apply_print_config(const PrintConfig &print_config);
|
||||
|
||||
@ -161,18 +196,10 @@ public:
|
||||
// translate full config into a list of <key, value> items
|
||||
static void encode_full_config(const Print& print, std::vector<std::pair<std::string, std::string>>& config);
|
||||
|
||||
// Object and support extrusions of the same PrintObject at the same print_z.
|
||||
// public, so that it could be accessed by free helper functions from GCode.cpp
|
||||
struct ObjectLayerToPrint
|
||||
{
|
||||
ObjectLayerToPrint() : object_layer(nullptr), support_layer(nullptr) {}
|
||||
const Layer* object_layer;
|
||||
const SupportLayer* support_layer;
|
||||
const Layer* layer() const { return (object_layer != nullptr) ? object_layer : support_layer; }
|
||||
const PrintObject* object() const { return (this->layer() != nullptr) ? this->layer()->object() : nullptr; }
|
||||
coordf_t print_z() const { return (object_layer != nullptr && support_layer != nullptr) ? 0.5 * (object_layer->print_z + support_layer->print_z) : this->layer()->print_z; }
|
||||
};
|
||||
using ObjectsLayerToPrint = std::vector<ObjectLayerToPrint>;
|
||||
using ObjectLayerToPrint = GCode::ObjectLayerToPrint;
|
||||
using ObjectsLayerToPrint = std::vector<GCode::ObjectLayerToPrint>;
|
||||
|
||||
std::optional<Point> last_position;
|
||||
|
||||
private:
|
||||
class GCodeOutputStream {
|
||||
@ -218,6 +245,9 @@ private:
|
||||
static ObjectsLayerToPrint collect_layers_to_print(const PrintObject &object);
|
||||
static std::vector<std::pair<coordf_t, ObjectsLayerToPrint>> collect_layers_to_print(const Print &print);
|
||||
|
||||
/** @brief Generates ramping travel gcode for layer change. */
|
||||
std::string get_layer_change_gcode(const Vec3d& from, const Vec3d& to, const unsigned extruder_id);
|
||||
|
||||
LayerResult process_layer(
|
||||
const Print &print,
|
||||
// Set of object & print layers of the same PrintObject and with the same print_z.
|
||||
@ -251,19 +281,11 @@ private:
|
||||
const GCode::SmoothPathCache &smooth_path_cache_global,
|
||||
GCodeOutputStream &output_stream);
|
||||
|
||||
void set_last_pos(const Point &pos) { m_last_pos = pos; m_last_pos_defined = true; }
|
||||
bool last_pos_defined() const { return m_last_pos_defined; }
|
||||
void set_extruders(const std::vector<unsigned int> &extruder_ids);
|
||||
std::string preamble();
|
||||
std::optional<std::string> get_helical_layer_change_gcode(
|
||||
const coordf_t previous_layer_z,
|
||||
const coordf_t print_z,
|
||||
const std::string& comment
|
||||
);
|
||||
std::string change_layer(
|
||||
coordf_t previous_layer_z,
|
||||
coordf_t print_z,
|
||||
const bool spiral_vase_enabled
|
||||
coordf_t print_z
|
||||
);
|
||||
std::string extrude_entity(const ExtrusionEntityReference &entity, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.);
|
||||
std::string extrude_loop(const ExtrusionLoop &loop, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.);
|
||||
@ -323,7 +345,15 @@ private:
|
||||
const bool needs_retraction,
|
||||
bool& could_be_wipe_disabled
|
||||
);
|
||||
std::string travel_to(const Point &point, ExtrusionRole role, std::string comment);
|
||||
std::string travel_to(
|
||||
const Point &start_point,
|
||||
const Point &end_point,
|
||||
ExtrusionRole role,
|
||||
const std::string &comment
|
||||
);
|
||||
|
||||
std::string travel_to_first_position(const Vec3crd& point);
|
||||
|
||||
bool needs_retraction(const Polyline &travel, ExtrusionRole role = ExtrusionRole::None);
|
||||
|
||||
std::string retract_and_wipe(bool toolchange = false);
|
||||
@ -379,6 +409,7 @@ private:
|
||||
AvoidCrossingPerimeters m_avoid_crossing_perimeters;
|
||||
JPSPathFinder m_avoid_crossing_curled_overhangs;
|
||||
RetractWhenCrossingPerimeters m_retract_when_crossing_perimeters;
|
||||
GCode::TravelObstacleTracker m_travel_obstacle_tracker;
|
||||
bool m_enable_loop_clipping;
|
||||
// If enabled, the G-code generator will put following comments at the ends
|
||||
// of the G-code lines: _EXTRUDE_SET_SPEED, _WIPE, _BRIDGE_FAN_START, _BRIDGE_FAN_END
|
||||
@ -398,7 +429,6 @@ private:
|
||||
// In non-sequential mode, all its copies will be printed.
|
||||
const Layer* m_layer;
|
||||
// m_layer is an object layer and it is being printed over raft surface.
|
||||
std::optional<AABBTreeLines::LinesDistancer<Linef>> m_previous_layer_distancer;
|
||||
bool m_object_layer_over_raft;
|
||||
double m_volumetric_speed;
|
||||
// Support for the extrusion role markers. Which marker is active?
|
||||
@ -412,9 +442,10 @@ private:
|
||||
double m_last_mm3_per_mm;
|
||||
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
|
||||
Point m_last_pos;
|
||||
bool m_last_pos_defined;
|
||||
|
||||
std::optional<Vec3d> m_previous_layer_last_position;
|
||||
// This needs to be populated during the layer processing!
|
||||
std::optional<Vec3d> m_current_layer_first_position;
|
||||
std::optional<unsigned> m_layer_change_extruder_id;
|
||||
std::unique_ptr<CoolingBuffer> m_cooling_buffer;
|
||||
std::unique_ptr<SpiralVase> m_spiral_vase;
|
||||
std::unique_ptr<GCodeFindReplace> m_find_replace;
|
||||
@ -427,8 +458,8 @@ private:
|
||||
bool m_brim_done;
|
||||
// Flag indicating whether the nozzle temperature changes from 1st to 2nd layer were performed.
|
||||
bool m_second_layer_things_done;
|
||||
// Index of a last object copy extruded.
|
||||
std::pair<const PrintObject*, Point> m_last_obj_copy;
|
||||
// Pointer to currently exporting PrintObject and instance index.
|
||||
GCode::PrintObjectInstance m_current_instance;
|
||||
|
||||
bool m_silent_time_estimator_enabled;
|
||||
|
||||
|
@ -1177,7 +1177,7 @@ Polyline AvoidCrossingPerimeters::travel_to(const GCodeGenerator &gcodegen, cons
|
||||
// Otherwise perform the path planning in the coordinate system of the active object.
|
||||
bool use_external = m_use_external_mp || m_use_external_mp_once;
|
||||
Point scaled_origin = use_external ? Point::new_scale(gcodegen.origin()(0), gcodegen.origin()(1)) : Point(0, 0);
|
||||
const Point start = gcodegen.last_pos() + scaled_origin;
|
||||
const Point start = *gcodegen.last_position + scaled_origin;
|
||||
const Point end = point + scaled_origin;
|
||||
const Line travel(start, end);
|
||||
|
||||
|
@ -57,6 +57,7 @@ const std::vector<std::string> GCodeProcessor::Reserved_Tags = {
|
||||
"HEIGHT:",
|
||||
"WIDTH:",
|
||||
"LAYER_CHANGE",
|
||||
"LAYER_CHANGE_TRAVEL",
|
||||
"COLOR_CHANGE",
|
||||
"PAUSE_PRINT",
|
||||
"CUSTOM_GCODE",
|
||||
|
@ -192,6 +192,7 @@ namespace Slic3r {
|
||||
Height,
|
||||
Width,
|
||||
Layer_Change,
|
||||
Layer_Change_Travel,
|
||||
Color_Change,
|
||||
Pause_Print,
|
||||
Custom_Code,
|
||||
|
@ -275,10 +275,8 @@ std::string GCodeWriter::set_speed(double F, const std::string_view comment, con
|
||||
return w.string();
|
||||
}
|
||||
|
||||
std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string_view comment)
|
||||
std::string GCodeWriter::get_travel_to_xy_gcode(const Vec2d &point, const std::string_view comment) const
|
||||
{
|
||||
m_pos.head<2>() = point.head<2>();
|
||||
|
||||
GCodeG1Formatter w;
|
||||
w.emit_xy(point);
|
||||
w.emit_f(this->config.travel_speed.value * 60.0);
|
||||
@ -286,6 +284,12 @@ std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string_view
|
||||
return w.string();
|
||||
}
|
||||
|
||||
std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string_view comment)
|
||||
{
|
||||
m_pos.head<2>() = point.head<2>();
|
||||
return this->get_travel_to_xy_gcode(point, comment);
|
||||
}
|
||||
|
||||
std::string GCodeWriter::travel_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij, const bool ccw, const std::string_view comment)
|
||||
{
|
||||
assert(std::abs(point.x()) < 1200.);
|
||||
@ -303,35 +307,49 @@ std::string GCodeWriter::travel_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij
|
||||
return w.string();
|
||||
}
|
||||
|
||||
std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string_view comment)
|
||||
std::string GCodeWriter::travel_to_xyz(const Vec3d& from, const Vec3d &to, const std::string_view comment)
|
||||
{
|
||||
if (std::abs(point.x() - m_pos.x()) < EPSILON && std::abs(point.y() - m_pos.y()) < EPSILON) {
|
||||
return this->travel_to_z(point.z(), comment);
|
||||
} else if (std::abs(point.z() - m_pos.z()) < EPSILON) {
|
||||
return this->travel_to_xy(point.head<2>(), comment);
|
||||
if (std::abs(to.x() - m_pos.x()) < EPSILON && std::abs(to.y() - m_pos.y()) < EPSILON) {
|
||||
return this->travel_to_z(to.z(), comment);
|
||||
} else if (std::abs(to.z() - m_pos.z()) < EPSILON) {
|
||||
return this->travel_to_xy(to.head<2>(), comment);
|
||||
} else {
|
||||
m_pos = point;
|
||||
|
||||
GCodeG1Formatter w;
|
||||
w.emit_xyz(point);
|
||||
|
||||
Vec2f speed {this->config.travel_speed_z.value, this->config.travel_speed.value};
|
||||
w.emit_f(speed.norm() * 60.0);
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
return w.string();
|
||||
m_pos = to;
|
||||
return this->get_travel_to_xyz_gcode(from, to, comment);
|
||||
}
|
||||
}
|
||||
|
||||
std::string GCodeWriter::get_travel_to_xyz_gcode(const Vec3d &from, const Vec3d &to, const std::string_view comment) const {
|
||||
GCodeG1Formatter w;
|
||||
w.emit_xyz(to);
|
||||
|
||||
const double distance_xy{(to.head<2>() - from.head<2>()).norm()};
|
||||
const double distnace_z{std::abs(to.z() - from.z())};
|
||||
const double time_z = distnace_z / this->config.travel_speed_z.value;
|
||||
const double time_xy = distance_xy / this->config.travel_speed.value;
|
||||
const double factor = time_z > 0 ? time_xy / time_z : 1;
|
||||
if (factor < 1) {
|
||||
w.emit_f((this->config.travel_speed.value * factor + (1 - factor) * this->config.travel_speed_z.value) * 60.0);
|
||||
} else {
|
||||
w.emit_f(this->config.travel_speed.value * 60.0);
|
||||
}
|
||||
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
return w.string();
|
||||
}
|
||||
|
||||
std::string GCodeWriter::travel_to_z(double z, const std::string_view comment)
|
||||
{
|
||||
return std::abs(m_pos.z() - z) < EPSILON ? "" : this->get_travel_to_z_gcode(z, comment);
|
||||
if (std::abs(m_pos.z() - z) < EPSILON) {
|
||||
return "";
|
||||
} else {
|
||||
m_pos.z() = z;
|
||||
return this->get_travel_to_z_gcode(z, comment);
|
||||
}
|
||||
}
|
||||
|
||||
std::string GCodeWriter::get_travel_to_z_gcode(double z, const std::string_view comment)
|
||||
std::string GCodeWriter::get_travel_to_z_gcode(double z, const std::string_view comment) const
|
||||
{
|
||||
m_pos.z() = z;
|
||||
|
||||
double speed = this->config.travel_speed_z.value;
|
||||
if (speed == 0.)
|
||||
speed = this->config.travel_speed.value;
|
||||
|
@ -66,10 +66,23 @@ public:
|
||||
std::string toolchange_prefix() const;
|
||||
std::string toolchange(unsigned int extruder_id);
|
||||
std::string set_speed(double F, const std::string_view comment = {}, const std::string_view cooling_marker = {}) const;
|
||||
|
||||
std::string get_travel_to_xy_gcode(const Vec2d &point, const std::string_view comment) const;
|
||||
std::string travel_to_xy(const Vec2d &point, const std::string_view comment = {});
|
||||
std::string travel_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij, const bool ccw, const std::string_view comment = {});
|
||||
std::string travel_to_xyz(const Vec3d &point, const std::string_view comment = {});
|
||||
std::string get_travel_to_z_gcode(double z, const std::string_view comment);
|
||||
|
||||
/**
|
||||
* @brief Return gcode with all three axis defined. Optionally adds feedrate.
|
||||
*
|
||||
* Feedrate is added the starting point "from" is specified.
|
||||
*
|
||||
* @param from Optional starting point of the travel.
|
||||
* @param to Where to travel to.
|
||||
* @param comment Description of the travel purpose.
|
||||
*/
|
||||
std::string get_travel_to_xyz_gcode(const Vec3d &from, const Vec3d &to, const std::string_view comment) const;
|
||||
std::string travel_to_xyz(const Vec3d &from, const Vec3d &to, const std::string_view comment = {});
|
||||
std::string get_travel_to_z_gcode(double z, const std::string_view comment) const;
|
||||
std::string travel_to_z(double z, const std::string_view comment = {});
|
||||
std::string extrude_to_xy(const Vec2d &point, double dE, const std::string_view comment = {});
|
||||
std::string extrude_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij, const bool ccw, double dE, const std::string_view comment);
|
||||
@ -200,7 +213,8 @@ public:
|
||||
}
|
||||
|
||||
void emit_string(const std::string_view s) {
|
||||
strncpy(ptr_err.ptr, s.data(), s.size());
|
||||
// Be aware that std::string_view::data() returns a pointer to a buffer that is not necessarily null-terminated.
|
||||
memcpy(ptr_err.ptr, s.data(), s.size());
|
||||
ptr_err.ptr += s.size();
|
||||
}
|
||||
|
||||
|
@ -1,53 +0,0 @@
|
||||
#include "LayerChanges.hpp"
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
|
||||
namespace Slic3r::GCode::Impl::LayerChanges {
|
||||
|
||||
Polygon generate_regular_polygon(
|
||||
const Point ¢roid, const Point &start_point, const unsigned points_count
|
||||
) {
|
||||
Points points;
|
||||
points.reserve(points_count);
|
||||
const double part_angle{2 * M_PI / points_count};
|
||||
for (unsigned i = 0; i < points_count; ++i) {
|
||||
const double current_angle{i * part_angle};
|
||||
points.emplace_back(scaled(std::cos(current_angle)), scaled(std::sin(current_angle)));
|
||||
}
|
||||
|
||||
Polygon regular_polygon{points};
|
||||
const Vec2d current_vector{unscaled(regular_polygon.points.front())};
|
||||
const Vec2d expected_vector{unscaled(start_point) - unscaled(centroid)};
|
||||
|
||||
const double current_scale = current_vector.norm();
|
||||
const double expected_scale = expected_vector.norm();
|
||||
regular_polygon.scale(expected_scale / current_scale);
|
||||
|
||||
regular_polygon.rotate(angle(current_vector, expected_vector));
|
||||
|
||||
regular_polygon.translate(centroid);
|
||||
|
||||
return regular_polygon;
|
||||
}
|
||||
|
||||
Bed::Bed(const std::vector<Vec2d> &shape, const double padding)
|
||||
: inner_offset(get_inner_offset(shape, padding)), centroid(unscaled(inner_offset.centroid())) {}
|
||||
|
||||
bool Bed::contains_within_padding(const Vec2d &point) const {
|
||||
return inner_offset.contains(scaled(point));
|
||||
}
|
||||
|
||||
Polygon Bed::get_inner_offset(const std::vector<Vec2d> &shape, const double padding) {
|
||||
Points shape_scaled;
|
||||
shape_scaled.reserve(shape.size());
|
||||
using std::begin, std::end, std::back_inserter, std::transform;
|
||||
transform(begin(shape), end(shape), back_inserter(shape_scaled), [](const Vec2d &point) {
|
||||
return scaled(point);
|
||||
});
|
||||
const Polygons inner_offset{shrink({Polygon{shape_scaled}}, scaled(padding))};
|
||||
if (inner_offset.empty()) {
|
||||
return Polygon{};
|
||||
}
|
||||
return inner_offset.front();
|
||||
}
|
||||
|
||||
} // namespace Slic3r::GCode::Impl::LayerChanges
|
@ -1,52 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Utility functions for layer change gcode generation.
|
||||
*/
|
||||
|
||||
#ifndef slic3r_GCode_LayerChanges_hpp_
|
||||
#define slic3r_GCode_LayerChanges_hpp_
|
||||
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
|
||||
namespace Slic3r::GCode::Impl::LayerChanges {
|
||||
/**
|
||||
* Generates a regular polygon - all angles are the same (e.g. typical hexagon).
|
||||
*
|
||||
* @param centroid Central point.
|
||||
* @param start_point The polygon point are ordered. This is the first point.
|
||||
* @param points_count Amount of nodes of the polygon (e.g. 6 for haxagon).
|
||||
*
|
||||
* Distance between centroid and start point sets the scale of the polygon.
|
||||
*/
|
||||
Polygon generate_regular_polygon(
|
||||
const Point ¢roid, const Point &start_point, const unsigned points_count
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief A representation of the bed shape with inner padding.
|
||||
*
|
||||
* Its purpose is to facilitate the bed boundary checking.
|
||||
*/
|
||||
class Bed
|
||||
{
|
||||
private:
|
||||
Polygon inner_offset;
|
||||
static Polygon get_inner_offset(const std::vector<Vec2d> &shape, const double padding);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Bed shape with inner padding.
|
||||
*/
|
||||
Bed(const std::vector<Vec2d> &shape, const double padding);
|
||||
|
||||
Vec2d centroid;
|
||||
|
||||
/**
|
||||
* Returns true if the point is within the bed shape including inner padding.
|
||||
*/
|
||||
bool contains_within_padding(const Vec2d &point) const;
|
||||
};
|
||||
} // namespace Slic3r::GCode::Impl::LayerChanges
|
||||
|
||||
#endif // slic3r_GCode_LayerChanges_hpp_
|
@ -1,11 +1,150 @@
|
||||
#include "Travels.hpp"
|
||||
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/Layer.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
|
||||
#include "../GCode.hpp"
|
||||
|
||||
namespace Slic3r::GCode {
|
||||
|
||||
static Lines extrusion_entity_to_lines(const ExtrusionEntity &e_entity)
|
||||
{
|
||||
if (const auto *path = dynamic_cast<const ExtrusionPath *>(&e_entity)) {
|
||||
return to_lines(path->as_polyline());
|
||||
} else if (const auto *multipath = dynamic_cast<const ExtrusionMultiPath *>(&e_entity)) {
|
||||
return to_lines(multipath->as_polyline());
|
||||
} else if (const auto *loop = dynamic_cast<const ExtrusionLoop *>(&e_entity)) {
|
||||
return to_lines(loop->polygon());
|
||||
} else {
|
||||
throw Slic3r::InvalidArgument("Invalid argument supplied to TODO()");
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
AABBTreeLines::LinesDistancer<ObjectOrExtrusionLinef> get_previous_layer_distancer(
|
||||
const GCodeGenerator::ObjectsLayerToPrint &objects_to_print, const ExPolygons &slices
|
||||
) {
|
||||
std::vector<ObjectOrExtrusionLinef> lines;
|
||||
for (const GCodeGenerator::ObjectLayerToPrint &object_to_print : objects_to_print) {
|
||||
if (const PrintObject *object = object_to_print.object(); object) {
|
||||
const size_t object_layer_idx = &object_to_print - &objects_to_print.front();
|
||||
for (const PrintInstance &instance : object->instances()) {
|
||||
const size_t instance_idx = &instance - &object->instances().front();
|
||||
for (const ExPolygon &polygon : slices)
|
||||
for (const Line &line : polygon.lines())
|
||||
lines.emplace_back(unscaled(Point{line.a + instance.shift}), unscaled(Point{line.b + instance.shift}), object_layer_idx, instance_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AABBTreeLines::LinesDistancer{std::move(lines)};
|
||||
}
|
||||
|
||||
std::pair<AABBTreeLines::LinesDistancer<ObjectOrExtrusionLinef>, size_t> get_current_layer_distancer(const ObjectsLayerToPrint &objects_to_print)
|
||||
{
|
||||
std::vector<ObjectOrExtrusionLinef> lines;
|
||||
size_t extrusion_entity_cnt = 0;
|
||||
for (const ObjectLayerToPrint &object_to_print : objects_to_print) {
|
||||
const size_t object_layer_idx = &object_to_print - &objects_to_print.front();
|
||||
if (const Layer *layer = object_to_print.object_layer; layer) {
|
||||
for (const PrintInstance &instance : layer->object()->instances()) {
|
||||
const size_t instance_idx = &instance - &layer->object()->instances().front();
|
||||
for (const LayerSlice &lslice : layer->lslices_ex) {
|
||||
for (const LayerIsland &island : lslice.islands) {
|
||||
const LayerRegion &layerm = *layer->get_region(island.perimeters.region());
|
||||
for (uint32_t perimeter_id : island.perimeters) {
|
||||
assert(dynamic_cast<const ExtrusionEntityCollection *>(layerm.perimeters().entities[perimeter_id]));
|
||||
const auto *eec = static_cast<const ExtrusionEntityCollection *>(layerm.perimeters().entities[perimeter_id]);
|
||||
for (const ExtrusionEntity *ee : *eec) {
|
||||
if (ee->role().is_external_perimeter()) {
|
||||
for (const Line &line : extrusion_entity_to_lines(*ee))
|
||||
lines.emplace_back(unscaled(Point{line.a + instance.shift}), unscaled(Point{line.b + instance.shift}), object_layer_idx, instance_idx, ee);
|
||||
}
|
||||
|
||||
++extrusion_entity_cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {AABBTreeLines::LinesDistancer{std::move(lines)}, extrusion_entity_cnt};
|
||||
}
|
||||
|
||||
void TravelObstacleTracker::init_layer(const Layer &layer, const ObjectsLayerToPrint &objects_to_print)
|
||||
{
|
||||
size_t extrusion_entity_cnt = 0;
|
||||
m_extruded_extrusion.clear();
|
||||
|
||||
m_objects_to_print = objects_to_print;
|
||||
m_previous_layer_distancer = get_previous_layer_distancer(m_objects_to_print, layer.lower_layer->lslices);
|
||||
|
||||
std::tie(m_current_layer_distancer, extrusion_entity_cnt) = get_current_layer_distancer(m_objects_to_print);
|
||||
m_extruded_extrusion.reserve(extrusion_entity_cnt);
|
||||
}
|
||||
|
||||
void TravelObstacleTracker::mark_extruded(const ExtrusionEntity *extrusion_entity, size_t object_layer_idx, size_t instance_idx)
|
||||
{
|
||||
if (extrusion_entity->role().is_external_perimeter())
|
||||
this->m_extruded_extrusion.insert({int(object_layer_idx), int(instance_idx), extrusion_entity});
|
||||
}
|
||||
|
||||
bool TravelObstacleTracker::is_extruded(const ObjectOrExtrusionLinef &line) const
|
||||
{
|
||||
return m_extruded_extrusion.find({line.object_layer_idx, line.instance_idx, line.extrusion_entity}) != m_extruded_extrusion.end();
|
||||
}
|
||||
|
||||
} // namespace Slic3r::GCode
|
||||
|
||||
namespace Slic3r::GCode::Impl::Travels {
|
||||
|
||||
ElevatedTravelFormula::ElevatedTravelFormula(const ElevatedTravelParams ¶ms)
|
||||
: smoothing_from(params.slope_end - params.blend_width / 2.0)
|
||||
, smoothing_to(params.slope_end + params.blend_width / 2.0)
|
||||
, blend_width(params.blend_width)
|
||||
, lift_height(params.lift_height)
|
||||
, slope_end(params.slope_end) {
|
||||
if (smoothing_from < 0) {
|
||||
smoothing_from = params.slope_end;
|
||||
smoothing_to = params.slope_end;
|
||||
}
|
||||
}
|
||||
|
||||
double parabola(const double x, const double a, const double b, const double c) {
|
||||
return a * x * x + b * x + c;
|
||||
}
|
||||
|
||||
double ElevatedTravelFormula::slope_function(double distance_from_start) const {
|
||||
if (distance_from_start < this->slope_end) {
|
||||
const double lift_percent = distance_from_start / this->slope_end;
|
||||
return lift_percent * this->lift_height;
|
||||
} else {
|
||||
return this->lift_height;
|
||||
}
|
||||
}
|
||||
|
||||
double ElevatedTravelFormula::operator()(const double distance_from_start) const {
|
||||
if (distance_from_start > this->smoothing_from && distance_from_start < this->smoothing_to) {
|
||||
const double slope = this->lift_height / this->slope_end;
|
||||
|
||||
// This is a part of a parabola going over a specific
|
||||
// range and with specific end slopes.
|
||||
const double a = -slope / 2.0 / this->blend_width;
|
||||
const double b = slope * this->smoothing_to / this->blend_width;
|
||||
const double c = this->lift_height + a * boost::math::pow<2>(this->smoothing_to);
|
||||
return parabola(distance_from_start, a, b, c);
|
||||
}
|
||||
return slope_function(distance_from_start);
|
||||
}
|
||||
|
||||
Points3 generate_flat_travel(tcb::span<const Point> xy_path, const float elevation) {
|
||||
Points3 result;
|
||||
result.reserve(xy_path.size() - 1);
|
||||
for (const Point &point : xy_path.subspan(1)) {
|
||||
result.reserve(xy_path.size());
|
||||
for (const Point &point : xy_path) {
|
||||
result.emplace_back(point.x(), point.y(), scaled(elevation));
|
||||
}
|
||||
return result;
|
||||
@ -52,26 +191,6 @@ std::vector<DistancedPoint> slice_xy_path(
|
||||
return result;
|
||||
}
|
||||
|
||||
struct ElevatedTravelParams
|
||||
{
|
||||
double lift_height{};
|
||||
double slope_end{};
|
||||
};
|
||||
|
||||
struct ElevatedTravelFormula
|
||||
{
|
||||
double operator()(double distance_from_start) const {
|
||||
if (distance_from_start < this->params.slope_end) {
|
||||
const double lift_percent = distance_from_start / this->params.slope_end;
|
||||
return lift_percent * this->params.lift_height;
|
||||
} else {
|
||||
return this->params.lift_height;
|
||||
}
|
||||
}
|
||||
|
||||
ElevatedTravelParams params{};
|
||||
};
|
||||
|
||||
Points3 generate_elevated_travel(
|
||||
const tcb::span<const Point> xy_path,
|
||||
const std::vector<double> &ensure_points_at_distances,
|
||||
@ -93,59 +212,153 @@ Points3 generate_elevated_travel(
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<double> get_first_crossed_line_distance(
|
||||
tcb::span<const Line> xy_path, const AABBTreeLines::LinesDistancer<Linef> &distancer
|
||||
struct Intersection
|
||||
{
|
||||
int object_layer_idx = -1;
|
||||
int instance_idx = -1;
|
||||
bool is_inside = false;
|
||||
|
||||
bool is_print_instance_equal(const ObjectOrExtrusionLinef &print_istance) {
|
||||
return this->object_layer_idx == print_istance.object_layer_idx && this->instance_idx == print_istance.instance_idx;
|
||||
}
|
||||
};
|
||||
|
||||
double get_first_crossed_line_distance(
|
||||
tcb::span<const Line> xy_path,
|
||||
const AABBTreeLines::LinesDistancer<ObjectOrExtrusionLinef> &distancer,
|
||||
const ObjectsLayerToPrint &objects_to_print,
|
||||
const std::function<bool(const ObjectOrExtrusionLinef &)> &predicate,
|
||||
const bool ignore_starting_object_intersection
|
||||
) {
|
||||
assert(!xy_path.empty());
|
||||
if (xy_path.empty()) {
|
||||
return {};
|
||||
}
|
||||
if (xy_path.empty())
|
||||
return std::numeric_limits<double>::max();
|
||||
|
||||
const Point path_first_point = xy_path.front().a;
|
||||
double traversed_distance = 0;
|
||||
bool skip_intersection = ignore_starting_object_intersection;
|
||||
Intersection first_intersection;
|
||||
|
||||
for (const Line &line : xy_path) {
|
||||
const Linef unscaled_line = {unscaled(line.a), unscaled(line.b)};
|
||||
auto intersections = distancer.intersections_with_line<true>(unscaled_line);
|
||||
if (!intersections.empty()) {
|
||||
const Vec2d intersection = intersections.front().first;
|
||||
const double distance = traversed_distance + (unscaled_line.a - intersection).norm();
|
||||
if (distance > EPSILON) {
|
||||
return distance;
|
||||
} else if (intersections.size() >= 2) { // Edge case
|
||||
const Vec2d second_intersection = intersections[1].first;
|
||||
return traversed_distance + (unscaled_line.a - second_intersection).norm();
|
||||
}
|
||||
const ObjectOrExtrusionLinef unscaled_line = {unscaled(line.a), unscaled(line.b)};
|
||||
const std::vector<std::pair<Vec2d, size_t>> intersections = distancer.intersections_with_line<true>(unscaled_line);
|
||||
|
||||
if (intersections.empty())
|
||||
continue;
|
||||
|
||||
if (!objects_to_print.empty() && ignore_starting_object_intersection && first_intersection.object_layer_idx == -1) {
|
||||
const ObjectOrExtrusionLinef &intersection_line = distancer.get_line(intersections.front().second);
|
||||
const Point shift = objects_to_print[intersection_line.object_layer_idx].layer()->object()->instances()[intersection_line.instance_idx].shift;
|
||||
const Point shifted_first_point = path_first_point - shift;
|
||||
const bool contain_first_point = expolygons_contain(objects_to_print[intersection_line.object_layer_idx].layer()->lslices, shifted_first_point);
|
||||
|
||||
first_intersection = {intersection_line.object_layer_idx, intersection_line.instance_idx, contain_first_point};
|
||||
}
|
||||
|
||||
for (const auto &intersection : intersections) {
|
||||
const ObjectOrExtrusionLinef &intersection_line = distancer.get_line(intersection.second);
|
||||
const double distance = traversed_distance + (unscaled_line.a - intersection.first).norm();
|
||||
if (distance <= EPSILON)
|
||||
continue;
|
||||
|
||||
// There is only one external border for each object, so when we cross this border,
|
||||
// we definitely know that we are outside the object.
|
||||
if (skip_intersection && first_intersection.is_print_instance_equal(intersection_line) && first_intersection.is_inside) {
|
||||
skip_intersection = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!predicate(intersection_line))
|
||||
continue;
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
traversed_distance += (unscaled_line.a - unscaled_line.b).norm();
|
||||
}
|
||||
|
||||
return {};
|
||||
return std::numeric_limits<double>::max();
|
||||
}
|
||||
|
||||
std::optional<double> get_obstacle_adjusted_slope_end(
|
||||
const Lines &xy_path,
|
||||
const std::optional<AABBTreeLines::LinesDistancer<Linef>> &previous_layer_distancer
|
||||
double get_obstacle_adjusted_slope_end(const Lines &xy_path, const GCode::TravelObstacleTracker &obstacle_tracker) {
|
||||
const double previous_layer_crossed_line = get_first_crossed_line_distance(
|
||||
xy_path, obstacle_tracker.previous_layer_distancer(), obstacle_tracker.objects_to_print()
|
||||
);
|
||||
const double current_layer_crossed_line = get_first_crossed_line_distance(
|
||||
xy_path, obstacle_tracker.current_layer_distancer(), obstacle_tracker.objects_to_print(),
|
||||
[&obstacle_tracker](const ObjectOrExtrusionLinef &line) { return obstacle_tracker.is_extruded(line); }
|
||||
);
|
||||
|
||||
return std::min(previous_layer_crossed_line, current_layer_crossed_line);
|
||||
}
|
||||
|
||||
struct SmoothingParams
|
||||
{
|
||||
double blend_width{};
|
||||
unsigned points_count{1};
|
||||
};
|
||||
|
||||
SmoothingParams get_smoothing_params(
|
||||
const double lift_height,
|
||||
const double slope_end,
|
||||
unsigned extruder_id,
|
||||
const double travel_length,
|
||||
const FullPrintConfig &config
|
||||
) {
|
||||
if (!previous_layer_distancer) {
|
||||
return std::nullopt;
|
||||
if (config.gcode_flavor != gcfMarlinFirmware)
|
||||
// Smoothing is supported only on Marlin.
|
||||
return {0, 1};
|
||||
|
||||
const double slope = lift_height / slope_end;
|
||||
const double max_machine_z_velocity = config.machine_max_feedrate_z.get_at(extruder_id);
|
||||
const double max_xy_velocity =
|
||||
Vec2d{
|
||||
config.machine_max_feedrate_x.get_at(extruder_id),
|
||||
config.machine_max_feedrate_y.get_at(extruder_id)}
|
||||
.norm();
|
||||
|
||||
const double xy_acceleration = config.machine_max_acceleration_travel.get_at(extruder_id);
|
||||
|
||||
const double xy_acceleration_time = max_xy_velocity / xy_acceleration;
|
||||
const double xy_acceleration_distance = 1.0 / 2.0 * xy_acceleration *
|
||||
boost::math::pow<2>(xy_acceleration_time);
|
||||
|
||||
if (travel_length < xy_acceleration_distance) {
|
||||
return {0, 1};
|
||||
}
|
||||
std::optional<double> first_obstacle_distance =
|
||||
get_first_crossed_line_distance(xy_path, *previous_layer_distancer);
|
||||
if (!first_obstacle_distance) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return *first_obstacle_distance;
|
||||
|
||||
const double max_z_velocity = std::min(max_xy_velocity * slope, max_machine_z_velocity);
|
||||
const double deceleration_time = max_z_velocity /
|
||||
config.machine_max_acceleration_z.get_at(extruder_id);
|
||||
const double deceleration_xy_distance = deceleration_time * max_xy_velocity;
|
||||
|
||||
const double blend_width = slope_end > deceleration_xy_distance / 2.0 ? deceleration_xy_distance :
|
||||
slope_end * 2.0;
|
||||
|
||||
const unsigned points_count = blend_width > 0 ?
|
||||
std::ceil(max_z_velocity / config.machine_max_jerk_z.get_at(extruder_id)) :
|
||||
1;
|
||||
|
||||
if (blend_width <= 0 // When there is no blend with, there is no need for smoothing.
|
||||
|| points_count > 6 // That would be way to many points. Do not do it at all.
|
||||
|| points_count <= 0 // Always return at least one point.
|
||||
)
|
||||
return {0, 1};
|
||||
|
||||
return {blend_width, points_count};
|
||||
}
|
||||
|
||||
ElevatedTravelParams get_elevated_traval_params(
|
||||
const Lines &xy_path,
|
||||
const Polyline& xy_path,
|
||||
const FullPrintConfig &config,
|
||||
const unsigned extruder_id,
|
||||
const std::optional<AABBTreeLines::LinesDistancer<Linef>> &previous_layer_distancer
|
||||
const GCode::TravelObstacleTracker &obstacle_tracker
|
||||
) {
|
||||
ElevatedTravelParams elevation_params{};
|
||||
if (!config.travel_ramping_lift.get_at(extruder_id)) {
|
||||
elevation_params.slope_end = 0;
|
||||
elevation_params.lift_height = config.retract_lift.get_at(extruder_id);
|
||||
elevation_params.blend_width = 0;
|
||||
return elevation_params;
|
||||
}
|
||||
elevation_params.lift_height = config.travel_max_lift.get_at(extruder_id);
|
||||
@ -159,22 +372,44 @@ ElevatedTravelParams get_elevated_traval_params(
|
||||
elevation_params.slope_end = elevation_params.lift_height / std::tan(slope_rad);
|
||||
}
|
||||
|
||||
std::optional<double> obstacle_adjusted_slope_end{
|
||||
get_obstacle_adjusted_slope_end(xy_path, previous_layer_distancer)};
|
||||
const double obstacle_adjusted_slope_end = get_obstacle_adjusted_slope_end(xy_path.lines(), obstacle_tracker);
|
||||
if (obstacle_adjusted_slope_end < elevation_params.slope_end)
|
||||
elevation_params.slope_end = obstacle_adjusted_slope_end;
|
||||
|
||||
if (obstacle_adjusted_slope_end && obstacle_adjusted_slope_end < elevation_params.slope_end) {
|
||||
elevation_params.slope_end = *obstacle_adjusted_slope_end;
|
||||
}
|
||||
SmoothingParams smoothing_params{get_smoothing_params(
|
||||
elevation_params.lift_height, elevation_params.slope_end, extruder_id,
|
||||
unscaled(xy_path.length()), config
|
||||
)};
|
||||
|
||||
elevation_params.blend_width = smoothing_params.blend_width;
|
||||
elevation_params.parabola_points_count = smoothing_params.points_count;
|
||||
return elevation_params;
|
||||
}
|
||||
|
||||
std::vector<double> linspace(const double from, const double to, const unsigned count) {
|
||||
if (count == 0) {
|
||||
return {};
|
||||
}
|
||||
std::vector<double> result;
|
||||
result.reserve(count);
|
||||
if (count == 1) {
|
||||
result.emplace_back((from + to) / 2.0);
|
||||
return result;
|
||||
}
|
||||
const double step = (to - from) / count;
|
||||
for (unsigned i = 0; i < count - 1; ++i) {
|
||||
result.emplace_back(from + i * step);
|
||||
}
|
||||
result.emplace_back(to); // Make sure the last value is exactly equal to the value of "to".
|
||||
return result;
|
||||
}
|
||||
|
||||
Points3 generate_travel_to_extrusion(
|
||||
const Polyline &xy_path,
|
||||
const FullPrintConfig &config,
|
||||
const unsigned extruder_id,
|
||||
const double initial_elevation,
|
||||
const std::optional<AABBTreeLines::LinesDistancer<Linef>> &previous_layer_distancer,
|
||||
const GCode::TravelObstacleTracker &obstacle_tracker,
|
||||
const Point &xy_path_coord_origin
|
||||
) {
|
||||
const double upper_limit = config.retract_lift_below.get_at(extruder_id);
|
||||
@ -184,15 +419,20 @@ Points3 generate_travel_to_extrusion(
|
||||
return generate_flat_travel(xy_path.points, initial_elevation);
|
||||
}
|
||||
|
||||
Lines global_xy_path;
|
||||
for (const Line &line : xy_path.lines()) {
|
||||
global_xy_path.emplace_back(line.a + xy_path_coord_origin, line.b + xy_path_coord_origin);
|
||||
Points global_xy_path;
|
||||
for (const Point &point : xy_path.points) {
|
||||
global_xy_path.emplace_back(point + xy_path_coord_origin);
|
||||
}
|
||||
|
||||
ElevatedTravelParams elevation_params{
|
||||
get_elevated_traval_params(global_xy_path, config, extruder_id, previous_layer_distancer)};
|
||||
ElevatedTravelParams elevation_params{get_elevated_traval_params(
|
||||
Polyline{std::move(global_xy_path)}, config, extruder_id, obstacle_tracker
|
||||
)};
|
||||
|
||||
const std::vector<double> ensure_points_at_distances{elevation_params.slope_end};
|
||||
const std::vector<double> ensure_points_at_distances = linspace(
|
||||
elevation_params.slope_end - elevation_params.blend_width / 2.0,
|
||||
elevation_params.slope_end + elevation_params.blend_width / 2.0,
|
||||
elevation_params.parabola_points_count
|
||||
);
|
||||
|
||||
Points3 result{generate_elevated_travel(
|
||||
xy_path.points, ensure_points_at_distances, initial_elevation,
|
||||
|
@ -11,18 +11,137 @@
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
#include "libslic3r/Line.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/math/special_functions/pow.hpp>
|
||||
|
||||
#include "libslic3r/AABBTreeLines.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
// Forward declarations.
|
||||
namespace Slic3r {
|
||||
class Layer;
|
||||
class Point;
|
||||
class Linef;
|
||||
class Polyline;
|
||||
class FullPrintConfig;
|
||||
class ExtrusionEntity;
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
namespace Slic3r::GCode {
|
||||
struct ObjectLayerToPrint;
|
||||
using ObjectsLayerToPrint = std::vector<ObjectLayerToPrint>;
|
||||
|
||||
class ObjectOrExtrusionLinef : public Linef
|
||||
{
|
||||
public:
|
||||
ObjectOrExtrusionLinef() = delete;
|
||||
ObjectOrExtrusionLinef(const Vec2d &a, const Vec2d &b) : Linef(a, b) {}
|
||||
explicit ObjectOrExtrusionLinef(const Vec2d &a, const Vec2d &b, size_t object_layer_idx, size_t instance_idx)
|
||||
: Linef(a, b), object_layer_idx(int(object_layer_idx)), instance_idx(int(instance_idx)) {}
|
||||
ObjectOrExtrusionLinef(const Vec2d &a, const Vec2d &b, size_t object_layer_idx, size_t instance_idx, const ExtrusionEntity *extrusion_entity)
|
||||
: Linef(a, b), object_layer_idx(int(object_layer_idx)), instance_idx(int(instance_idx)), extrusion_entity(extrusion_entity) {}
|
||||
|
||||
virtual ~ObjectOrExtrusionLinef() = default;
|
||||
|
||||
const int object_layer_idx = -1;
|
||||
const int instance_idx = -1;
|
||||
const ExtrusionEntity *extrusion_entity = nullptr;
|
||||
};
|
||||
|
||||
struct ExtrudedExtrusionEntity
|
||||
{
|
||||
const int object_layer_idx = -1;
|
||||
const int instance_idx = -1;
|
||||
const ExtrusionEntity *extrusion_entity = nullptr;
|
||||
|
||||
bool operator==(const ExtrudedExtrusionEntity &other) const
|
||||
{
|
||||
return extrusion_entity == other.extrusion_entity && object_layer_idx == other.object_layer_idx &&
|
||||
instance_idx == other.instance_idx;
|
||||
}
|
||||
};
|
||||
|
||||
struct ExtrudedExtrusionEntityHash
|
||||
{
|
||||
size_t operator()(const ExtrudedExtrusionEntity &eee) const noexcept
|
||||
{
|
||||
std::size_t seed = std::hash<const ExtrusionEntity *>{}(eee.extrusion_entity);
|
||||
boost::hash_combine(seed, std::hash<int>{}(eee.object_layer_idx));
|
||||
boost::hash_combine(seed, std::hash<int>{}(eee.instance_idx));
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
class TravelObstacleTracker
|
||||
{
|
||||
public:
|
||||
void init_layer(const Layer &layer, const ObjectsLayerToPrint &objects_to_print);
|
||||
|
||||
void mark_extruded(const ExtrusionEntity *extrusion_entity, size_t object_layer_idx, size_t instance_idx);
|
||||
|
||||
bool is_extruded(const ObjectOrExtrusionLinef &line) const;
|
||||
|
||||
const AABBTreeLines::LinesDistancer<ObjectOrExtrusionLinef> &previous_layer_distancer() const { return m_previous_layer_distancer; }
|
||||
|
||||
const AABBTreeLines::LinesDistancer<ObjectOrExtrusionLinef> ¤t_layer_distancer() const { return m_current_layer_distancer; }
|
||||
|
||||
const ObjectsLayerToPrint &objects_to_print() const { return m_objects_to_print; }
|
||||
|
||||
private:
|
||||
ObjectsLayerToPrint m_objects_to_print;
|
||||
AABBTreeLines::LinesDistancer<ObjectOrExtrusionLinef> m_previous_layer_distancer;
|
||||
|
||||
AABBTreeLines::LinesDistancer<ObjectOrExtrusionLinef> m_current_layer_distancer;
|
||||
std::unordered_set<ExtrudedExtrusionEntity, ExtrudedExtrusionEntityHash> m_extruded_extrusion;
|
||||
};
|
||||
} // namespace Slic3r::GCode
|
||||
|
||||
namespace Slic3r::GCode::Impl::Travels {
|
||||
/**
|
||||
* @brief A point on a curve with a distance from start.
|
||||
*/
|
||||
struct DistancedPoint
|
||||
{
|
||||
Point point;
|
||||
double distance_from_start;
|
||||
};
|
||||
|
||||
struct ElevatedTravelParams
|
||||
{
|
||||
/** Maximal value of nozzle lift. */
|
||||
double lift_height{};
|
||||
|
||||
/** Distance from travel to the middle of the smoothing parabola. */
|
||||
double slope_end{};
|
||||
|
||||
/** Width of the smoothing parabola */
|
||||
double blend_width{};
|
||||
|
||||
/** How many points should be used to approximate the parabola */
|
||||
unsigned parabola_points_count{};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A mathematical formula for a smooth function.
|
||||
*
|
||||
* It starts lineary increasing than there is a parabola part and
|
||||
* at the end it is flat.
|
||||
*/
|
||||
struct ElevatedTravelFormula
|
||||
{
|
||||
ElevatedTravelFormula(const ElevatedTravelParams ¶ms);
|
||||
double operator()(const double distance_from_start) const;
|
||||
|
||||
private:
|
||||
double slope_function(double distance_from_start) const;
|
||||
|
||||
double smoothing_from;
|
||||
double smoothing_to;
|
||||
double blend_width;
|
||||
double lift_height;
|
||||
double slope_end;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Takes a path described as a list of points and adds points to it.
|
||||
*
|
||||
@ -48,6 +167,20 @@ std::vector<DistancedPoint> slice_xy_path(
|
||||
tcb::span<const Point> xy_path, tcb::span<const double> sorted_distances
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Generate regulary spaced points on 1 axis. Includes both from and to.
|
||||
*
|
||||
* If count is 1, the point is in the middle of the range.
|
||||
*/
|
||||
std::vector<double> linspace(const double from, const double to, const unsigned count);
|
||||
|
||||
ElevatedTravelParams get_elevated_traval_params(
|
||||
const Polyline& xy_path,
|
||||
const FullPrintConfig &config,
|
||||
const unsigned extruder_id,
|
||||
const GCode::TravelObstacleTracker &obstacle_tracker
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Simply return the xy_path with z coord set to elevation.
|
||||
*/
|
||||
@ -76,13 +209,19 @@ Points3 generate_elevated_travel(
|
||||
*
|
||||
* @param xy_path A path in 2D.
|
||||
* @param distancer AABB Tree over lines.
|
||||
* @param objects_to_print Objects to print are used to determine in which object xy_path starts.
|
||||
|
||||
* @param ignore_starting_object_intersection When it is true, then the first intersection during traveling from the object out is ignored.
|
||||
* @return Distance to the first intersection if there is one.
|
||||
*
|
||||
* **Ignores intersection with xy_path starting point.**
|
||||
*/
|
||||
std::optional<double> get_first_crossed_line_distance(
|
||||
tcb::span<const Line> xy_path, const AABBTreeLines::LinesDistancer<Linef> &distancer
|
||||
);
|
||||
double get_first_crossed_line_distance(
|
||||
tcb::span<const Line> xy_path,
|
||||
const AABBTreeLines::LinesDistancer<ObjectOrExtrusionLinef> &distancer,
|
||||
const ObjectsLayerToPrint &objects_to_print = {},
|
||||
const std::function<bool(const ObjectOrExtrusionLinef &)> &predicate = [](const ObjectOrExtrusionLinef &) { return true; },
|
||||
bool ignore_starting_object_intersection = true);
|
||||
|
||||
/**
|
||||
* @brief Extract parameters and decide wheather the travel can be elevated.
|
||||
@ -93,7 +232,7 @@ Points3 generate_travel_to_extrusion(
|
||||
const FullPrintConfig &config,
|
||||
const unsigned extruder_id,
|
||||
const double initial_elevation,
|
||||
const std::optional<AABBTreeLines::LinesDistancer<Linef>> &previous_layer_distancer,
|
||||
const GCode::TravelObstacleTracker &obstacle_tracker,
|
||||
const Point &xy_path_coord_origin
|
||||
);
|
||||
} // namespace Slic3r::GCode::Impl::Travels
|
||||
|
@ -21,9 +21,9 @@ void Wipe::init(const PrintConfig &config, const std::vector<unsigned int> &extr
|
||||
if (config.wipe.get_at(id)) {
|
||||
// Wipe length to extrusion ratio.
|
||||
const double xy_to_e = this->calc_xy_to_e_ratio(config, id);
|
||||
wipe_xy = std::max(wipe_xy, xy_to_e * config.retract_length.get_at(id));
|
||||
wipe_xy = std::max(wipe_xy, config.retract_length.get_at(id) / xy_to_e);
|
||||
if (multimaterial)
|
||||
wipe_xy = std::max(wipe_xy, xy_to_e * config.retract_length_toolchange.get_at(id));
|
||||
wipe_xy = std::max(wipe_xy, config.retract_length_toolchange.get_at(id) / xy_to_e);
|
||||
}
|
||||
|
||||
if (wipe_xy == 0)
|
||||
@ -37,11 +37,11 @@ void Wipe::set_path(SmoothPath &&path, bool reversed)
|
||||
this->reset_path();
|
||||
|
||||
if (this->enabled() && ! path.empty()) {
|
||||
if (reversed) {
|
||||
if (coord_t wipe_len_max_scaled = scaled(m_wipe_len_max); reversed) {
|
||||
m_path = std::move(path.back().path);
|
||||
Geometry::ArcWelder::reverse(m_path);
|
||||
int64_t len = Geometry::ArcWelder::estimate_path_length(m_path);
|
||||
for (auto it = std::next(path.rbegin()); len < m_wipe_len_max && it != path.rend(); ++ it) {
|
||||
for (auto it = std::next(path.rbegin()); len < wipe_len_max_scaled && it != path.rend(); ++ it) {
|
||||
if (it->path_attributes.role.is_bridge())
|
||||
break; // Do not perform a wipe on bridges.
|
||||
assert(it->path.size() >= 2);
|
||||
@ -55,7 +55,7 @@ void Wipe::set_path(SmoothPath &&path, bool reversed)
|
||||
} else {
|
||||
m_path = std::move(path.front().path);
|
||||
int64_t len = Geometry::ArcWelder::estimate_path_length(m_path);
|
||||
for (auto it = std::next(path.begin()); len < m_wipe_len_max && it != path.end(); ++ it) {
|
||||
for (auto it = std::next(path.begin()); len < wipe_len_max_scaled && it != path.end(); ++ it) {
|
||||
if (it->path_attributes.role.is_bridge())
|
||||
break; // Do not perform a wipe on bridges.
|
||||
assert(it->path.size() >= 2);
|
||||
@ -164,7 +164,7 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
|
||||
return done;
|
||||
};
|
||||
// Start with the current position, which may be different from the wipe path start in case of loop clipping.
|
||||
Vec2d prev = gcodegen.point_to_gcode_quantized(gcodegen.last_pos());
|
||||
Vec2d prev = gcodegen.point_to_gcode_quantized(*gcodegen.last_position);
|
||||
auto it = this->path().begin();
|
||||
Vec2d p = gcodegen.point_to_gcode(it->point + m_offset);
|
||||
++ it;
|
||||
@ -192,7 +192,7 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
|
||||
// add tag for processor
|
||||
assert(p == GCodeFormatter::quantize(p));
|
||||
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_End) + "\n";
|
||||
gcodegen.set_last_pos(gcodegen.gcode_to_point(p));
|
||||
gcodegen.last_position = gcodegen.gcode_to_point(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,12 +57,23 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip
|
||||
|| is_ramming
|
||||
|| will_go_down); // don't dig into the print
|
||||
if (should_travel_to_tower) {
|
||||
const Point xy_point = wipe_tower_point_to_object_point(gcodegen, start_pos);
|
||||
gcode += gcodegen.retract_and_wipe();
|
||||
gcodegen.m_avoid_crossing_perimeters.use_external_mp_once();
|
||||
gcode += gcodegen.travel_to(
|
||||
wipe_tower_point_to_object_point(gcodegen, start_pos),
|
||||
ExtrusionRole::Mixed,
|
||||
"Travel to a Wipe Tower");
|
||||
const std::string comment{"Travel to a Wipe Tower"};
|
||||
if (gcodegen.m_current_layer_first_position) {
|
||||
if (gcodegen.last_position) {
|
||||
gcode += gcodegen.travel_to(
|
||||
*gcodegen.last_position, xy_point, ExtrusionRole::Mixed, comment
|
||||
);
|
||||
} else {
|
||||
gcode += gcodegen.writer().travel_to_xy(gcodegen.point_to_gcode(xy_point), comment);
|
||||
gcode += gcodegen.writer().get_travel_to_z_gcode(z, comment);
|
||||
}
|
||||
} else {
|
||||
const Vec3crd point = to_3d(xy_point, scaled(z));
|
||||
gcode += gcodegen.travel_to_first_position(point);
|
||||
}
|
||||
gcode += gcodegen.unretract();
|
||||
} else {
|
||||
// When this is multiextruder printer without any ramming, we can just change
|
||||
@ -81,10 +92,10 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip
|
||||
if (is_ramming)
|
||||
gcodegen.m_wipe.reset_path(); // We don't want wiping on the ramming lines.
|
||||
toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z); // TODO: toolchange_z vs print_z
|
||||
if (gcodegen.config().wipe_tower)
|
||||
deretraction_str += gcodegen.writer().get_travel_to_z_gcode(z, "restore layer Z");
|
||||
if (gcodegen.config().wipe_tower) {
|
||||
deretraction_str += gcodegen.writer().get_travel_to_z_gcode(tcr.print_z, "restore layer Z");
|
||||
deretraction_str += gcodegen.unretract();
|
||||
|
||||
}
|
||||
}
|
||||
assert(toolchange_gcode_str.empty() || toolchange_gcode_str.back() == '\n');
|
||||
assert(deretraction_str.empty() || deretraction_str.back() == '\n');
|
||||
@ -98,7 +109,7 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip
|
||||
|
||||
// A phony move to the end position at the wipe tower.
|
||||
gcodegen.writer().travel_to_xy(end_pos.cast<double>());
|
||||
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos));
|
||||
gcodegen.last_position = wipe_tower_point_to_object_point(gcodegen, end_pos);
|
||||
if (!is_approx(z, current_z)) {
|
||||
gcode += gcodegen.writer().retract();
|
||||
gcode += gcodegen.writer().travel_to_z(current_z, "Travel back up to the topmost object layer.");
|
||||
@ -247,7 +258,7 @@ std::string WipeTowerIntegration::finalize(GCodeGenerator &gcodegen)
|
||||
std::string gcode;
|
||||
if (std::abs(gcodegen.writer().get_position().z() - m_final_purge.print_z) > EPSILON)
|
||||
gcode += gcodegen.generate_travel_gcode(
|
||||
{{gcodegen.last_pos().x(), gcodegen.last_pos().y(), scaled(m_final_purge.print_z)}},
|
||||
{{gcodegen.last_position->x(), gcodegen.last_position->y(), scaled(m_final_purge.print_z)}},
|
||||
"move to safe place for purging"
|
||||
);
|
||||
gcode += append_tcr(gcodegen, m_final_purge, -1);
|
||||
|
@ -26,7 +26,8 @@ public:
|
||||
m_tool_changes(tool_changes),
|
||||
m_final_purge(final_purge),
|
||||
m_layer_idx(-1),
|
||||
m_tool_change_idx(0)
|
||||
m_tool_change_idx(0),
|
||||
m_last_wipe_tower_print_z(print_config.z_offset.value)
|
||||
{}
|
||||
|
||||
std::string prime(GCodeGenerator &gcodegen);
|
||||
@ -56,7 +57,7 @@ private:
|
||||
// Current layer index.
|
||||
int m_layer_idx;
|
||||
int m_tool_change_idx;
|
||||
double m_last_wipe_tower_print_z = 0.f;
|
||||
double m_last_wipe_tower_print_z;
|
||||
};
|
||||
|
||||
} // namespace GCode
|
||||
|
@ -120,6 +120,7 @@ static inline bool circle_approximation_sufficient(const Circle &circle, const P
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline bool get_deviation_sum_squared(const Circle &circle, const Points::const_iterator begin, const Points::const_iterator end, const double tolerance, double &total_deviation)
|
||||
{
|
||||
// The circle was calculated from the 1st and last point of the point sequence, thus the fitting of those points does not need to be evaluated.
|
||||
@ -148,6 +149,7 @@ static inline bool get_deviation_sum_squared(const Circle &circle, const Points:
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
double arc_fit_variance(const Point &start_pos, const Point &end_pos, const float radius, bool is_ccw,
|
||||
const Points::const_iterator begin, const Points::const_iterator end)
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "Point.hpp"
|
||||
#include "Polygon.hpp"
|
||||
#include "Print.hpp"
|
||||
#include "Fill/Fill.hpp"
|
||||
#include "ShortestPath.hpp"
|
||||
#include "SVG.hpp"
|
||||
#include "BoundingBox.hpp"
|
||||
@ -874,12 +873,14 @@ void Layer::sort_perimeters_into_islands(
|
||||
int sort_region_id = -1;
|
||||
// Temporary vector of fills for reordering.
|
||||
ExPolygons fills_temp;
|
||||
// Temporary vector of fill_bboxes for reordering.
|
||||
BoundingBoxes fill_bboxes_temp;
|
||||
// Vector of new positions of the above.
|
||||
std::vector<int> new_positions;
|
||||
do {
|
||||
sort_region_id = -1;
|
||||
for (size_t source_slice_idx = 0; source_slice_idx < fill_expolygons_ranges.size(); ++ source_slice_idx)
|
||||
if (ExPolygonRange fill_range = fill_expolygons_ranges[source_slice_idx]; fill_range.size() > 1) {
|
||||
if (const ExPolygonRange fill_range = fill_expolygons_ranges[source_slice_idx]; fill_range.size() > 1) {
|
||||
// More than one expolygon exists for a single island. Check whether they are contiguous inside a single LayerRegion::fill_expolygons() vector.
|
||||
uint32_t fill_idx = *fill_range.begin();
|
||||
if (const int fill_regon_id = map_expolygon_to_region_and_fill[fill_idx].region_id; fill_regon_id != -1) {
|
||||
@ -916,15 +917,23 @@ void Layer::sort_perimeters_into_islands(
|
||||
// Not referenced by any map_expolygon_to_region_and_fill.
|
||||
new_pos = last ++;
|
||||
// Move just the content of m_fill_expolygons to fills_temp, but don't move the container vector.
|
||||
auto &fills = layerm.m_fill_expolygons;
|
||||
auto &fills = layerm.m_fill_expolygons;
|
||||
auto &fill_bboxes = layerm.m_fill_expolygons_bboxes;
|
||||
|
||||
assert(fills.size() == fill_bboxes.size());
|
||||
assert(last == int(fills.size()));
|
||||
fills_temp.reserve(fills.size());
|
||||
fills_temp.insert(fills_temp.end(), std::make_move_iterator(fills.begin()), std::make_move_iterator(fills.end()));
|
||||
for (ExPolygon &ex : fills)
|
||||
ex.clear();
|
||||
// Move / reoder the expolygons back into m_fill_expolygons.
|
||||
for (size_t old_pos = 0; old_pos < new_positions.size(); ++ old_pos)
|
||||
fills[new_positions[old_pos]] = std::move(fills_temp[old_pos]);
|
||||
|
||||
fills_temp.resize(fills.size());
|
||||
fills_temp.assign(std::make_move_iterator(fills.begin()), std::make_move_iterator(fills.end()));
|
||||
|
||||
fill_bboxes_temp.resize(fill_bboxes.size());
|
||||
fill_bboxes_temp.assign(std::make_move_iterator(fill_bboxes.begin()), std::make_move_iterator(fill_bboxes.end()));
|
||||
|
||||
// Move / reorder the ExPolygons and BoundingBoxes back into m_fill_expolygons and m_fill_expolygons_bboxes.
|
||||
for (size_t old_pos = 0; old_pos < new_positions.size(); ++old_pos) {
|
||||
fills[new_positions[old_pos]] = std::move(fills_temp[old_pos]);
|
||||
fill_bboxes[new_positions[old_pos]] = std::move(fill_bboxes_temp[old_pos]);
|
||||
}
|
||||
}
|
||||
} while (sort_region_id != -1);
|
||||
} else {
|
||||
@ -956,7 +965,7 @@ void Layer::sort_perimeters_into_islands(
|
||||
// Check whether the fill expolygons of this island were split into multiple regions.
|
||||
island.fill_region_id = LayerIsland::fill_region_composite_id;
|
||||
for (uint32_t fill_idx : fill_range) {
|
||||
if (const int fill_regon_id = map_expolygon_to_region_and_fill[fill_idx].region_id;
|
||||
if (const int fill_regon_id = map_expolygon_to_region_and_fill[fill_idx].region_id;
|
||||
fill_regon_id == -1 || (island.fill_region_id != LayerIsland::fill_region_composite_id && int(island.fill_region_id) != fill_regon_id)) {
|
||||
island.fill_region_id = LayerIsland::fill_region_composite_id;
|
||||
break;
|
||||
|
@ -377,8 +377,6 @@ public:
|
||||
return false;
|
||||
}
|
||||
void make_perimeters();
|
||||
// Phony version of make_fills() without parameters for Perl integration only.
|
||||
void make_fills() { this->make_fills(nullptr, nullptr, nullptr); }
|
||||
void make_fills(FillAdaptive::Octree *adaptive_fill_octree,
|
||||
FillAdaptive::Octree *support_fill_octree,
|
||||
FillLightning::Generator *lightning_generator);
|
||||
|
@ -280,6 +280,7 @@ class Linef
|
||||
public:
|
||||
Linef() : a(Vec2d::Zero()), b(Vec2d::Zero()) {}
|
||||
Linef(const Vec2d& _a, const Vec2d& _b) : a(_a), b(_b) {}
|
||||
virtual ~Linef() = default;
|
||||
|
||||
Vec2d a;
|
||||
Vec2d b;
|
||||
|
@ -425,18 +425,21 @@ bool Model::looks_like_multipart_object() const
|
||||
{
|
||||
if (this->objects.size() <= 1)
|
||||
return false;
|
||||
double zmin = std::numeric_limits<double>::max();
|
||||
|
||||
BoundingBoxf3 tbb;
|
||||
|
||||
for (const ModelObject *obj : this->objects) {
|
||||
if (obj->volumes.size() > 1 || obj->config.keys().size() > 1)
|
||||
return false;
|
||||
for (const ModelVolume *vol : obj->volumes) {
|
||||
double zmin_this = vol->mesh().bounding_box().min(2);
|
||||
if (zmin == std::numeric_limits<double>::max())
|
||||
zmin = zmin_this;
|
||||
else if (std::abs(zmin - zmin_this) > EPSILON)
|
||||
// The volumes don't share zmin.
|
||||
return true;
|
||||
}
|
||||
|
||||
BoundingBoxf3 bb_this = obj->volumes[0]->mesh().bounding_box();
|
||||
BoundingBoxf3 tbb_this = obj->instances[0]->transform_bounding_box(bb_this);
|
||||
|
||||
if (!tbb.defined)
|
||||
tbb = tbb_this;
|
||||
else if (tbb.intersects(tbb_this) || tbb.shares_boundary(tbb_this))
|
||||
// The volumes has intersects bounding boxes or share some boundary
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -2252,7 +2252,6 @@ size_t ExtruderFilaments::update_compatible_internal(const PresetWithVendorProfi
|
||||
const ConfigOption* opt = active_printer.preset.config.option("nozzle_diameter");
|
||||
if (opt)
|
||||
config.set_key_value("num_extruders", new ConfigOptionInt((int)static_cast<const ConfigOptionFloats*>(opt)->values.size()));
|
||||
bool some_compatible = false;
|
||||
|
||||
// Adjust printer preset config to the first extruder from m_extruder_id
|
||||
Preset printer_preset_adjusted = active_printer.preset;
|
||||
@ -2280,7 +2279,6 @@ size_t ExtruderFilaments::update_compatible_internal(const PresetWithVendorProfi
|
||||
const PresetWithVendorProfile this_preset_with_vendor_profile = m_filaments->get_preset_with_vendor_profile(*preset);
|
||||
bool was_compatible = extr_filament.is_compatible;
|
||||
extr_filament.is_compatible = is_compatible_with_printer(this_preset_with_vendor_profile, active_printer_adjusted, &config);
|
||||
some_compatible |= extr_filament.is_compatible;
|
||||
if (active_print != nullptr)
|
||||
extr_filament.is_compatible &= is_compatible_with_print(this_preset_with_vendor_profile, *active_print, active_printer_adjusted);
|
||||
if (!extr_filament.is_compatible && is_selected &&
|
||||
|
@ -639,10 +639,6 @@ public:
|
||||
// If zero, then the print is empty and the print shall not be executed.
|
||||
unsigned int num_object_instances() const;
|
||||
|
||||
// For Perl bindings.
|
||||
PrintObjectPtrs& objects_mutable() { return m_objects; }
|
||||
PrintRegionPtrs& print_regions_mutable() { return m_print_regions; }
|
||||
|
||||
const ExtrusionEntityCollection& skirt() const { return m_skirt; }
|
||||
const ExtrusionEntityCollection& brim() const { return m_brim; }
|
||||
// Convex hull of the 1st layer extrusions, for bed leveling and placing the initial purge line.
|
||||
|
@ -78,7 +78,7 @@ std::string PrintBase::output_filename(const std::string &format, const std::str
|
||||
cfg.opt_string("input_filename_base") + default_ext :
|
||||
this->placeholder_parser().process(format, 0, &cfg);
|
||||
if (filename.extension().empty())
|
||||
filename = boost::filesystem::change_extension(filename, default_ext);
|
||||
filename.replace_extension(default_ext);
|
||||
return filename.string();
|
||||
} catch (std::runtime_error &err) {
|
||||
throw Slic3r::PlaceholderParserError(_u8L("Failed processing of the output_filename_format template.") + "\n" + err.what());
|
||||
|
@ -4889,9 +4889,15 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
||||
def->cli = "opengl-version";
|
||||
def->set_default_value(new ConfigOptionString());
|
||||
|
||||
def = this->add("opengl-compatibility", coBool);
|
||||
def->label = L("OpenGL compatibility profile");
|
||||
def->tooltip = L("Enable OpenGL compatibility profile");
|
||||
def->cli = "opengl-compatibility";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("opengl-debug", coBool);
|
||||
def->label = L("OpenGL debug output");
|
||||
def->tooltip = L("Activate OpenGL debug output on graphic cards which support it");
|
||||
def->tooltip = L("Activate OpenGL debug output on graphic cards which support it (OpenGL 4.3 or higher)");
|
||||
def->cli = "opengl-debug";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
@ -5066,6 +5072,11 @@ CLIMiscConfigDef::CLIMiscConfigDef()
|
||||
def->label = L("Data directory");
|
||||
def->tooltip = L("Load and store settings at the given directory. This is useful for maintaining different profiles or including configurations from a network storage.");
|
||||
|
||||
def = this->add("threads", coInt);
|
||||
def->label = L("Maximum number of threads");
|
||||
def->tooltip = L("Sets the maximum number of threads the slicing process will use. If not defined, slic3r will decide.");
|
||||
def->min = 1;
|
||||
|
||||
def = this->add("loglevel", coInt);
|
||||
def->label = L("Logging level");
|
||||
def->tooltip = L("Sets logging sensitivity. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:trace\n"
|
||||
|
@ -244,12 +244,16 @@ private:
|
||||
*/
|
||||
std::optional<std::reference_wrapper<const Polygons>> getArea(const TreeModelVolumes::RadiusLayerPair &key) const {
|
||||
std::lock_guard<std::mutex> guard(m_mutex);
|
||||
|
||||
if (key.second >= LayerIndex(m_data.size()))
|
||||
return std::optional<std::reference_wrapper<const Polygons>>{};
|
||||
const auto &layer = m_data[key.second];
|
||||
return std::nullopt;
|
||||
|
||||
const LayerData &layer = m_data[key.second];
|
||||
auto it = layer.find(key.first);
|
||||
return it == layer.end() ?
|
||||
std::optional<std::reference_wrapper<const Polygons>>{} : std::optional<std::reference_wrapper<const Polygons>>{ it->second };
|
||||
if (it == layer.end())
|
||||
return std::nullopt;
|
||||
|
||||
return std::optional<std::reference_wrapper<const Polygons>>{it->second};
|
||||
}
|
||||
// Get a collision area at a given layer for a radius that is a lower or equial to the key radius.
|
||||
std::optional<std::pair<coord_t, std::reference_wrapper<const Polygons>>> get_lower_bound_area(const TreeModelVolumes::RadiusLayerPair &key) const {
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "../BuildVolume.hpp"
|
||||
#include "../ClipperUtils.hpp"
|
||||
#include "../EdgeGrid.hpp"
|
||||
#include "../Fill/Fill.hpp"
|
||||
#include "../Layer.hpp"
|
||||
#include "../Print.hpp"
|
||||
#include "../MultiPoint.hpp"
|
||||
|
@ -55,8 +55,6 @@
|
||||
#define ENABLE_OPENGL_ES 0
|
||||
// Enable OpenGL core profile context (tested against Mesa 20.1.8 on Windows)
|
||||
#define ENABLE_GL_CORE_PROFILE (1 && !ENABLE_OPENGL_ES)
|
||||
// Enable OpenGL debug messages using debug context
|
||||
#define ENABLE_OPENGL_DEBUG_OPTION (1 && ENABLE_GL_CORE_PROFILE)
|
||||
|
||||
// Enable imgui dialog which allows to set the parameters used to export binarized gcode
|
||||
#define ENABLE_BINARIZED_GCODE_DEBUG_WINDOW 0
|
||||
|
@ -235,12 +235,11 @@ void name_tbb_thread_pool_threads_set_locale()
|
||||
// const size_t nthreads_hw = std::thread::hardware_concurrency();
|
||||
const size_t nthreads_hw = tbb::this_task_arena::max_concurrency();
|
||||
size_t nthreads = nthreads_hw;
|
||||
if (thread_count) {
|
||||
nthreads = std::min(nthreads_hw, *thread_count);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Shiny profiler is not thread safe, thus disable parallelization.
|
||||
disable_multi_threading();
|
||||
nthreads = 1;
|
||||
#endif
|
||||
enforce_thread_count(nthreads);
|
||||
|
||||
size_t nthreads_running(0);
|
||||
std::condition_variable cv;
|
||||
|
@ -21,6 +21,7 @@ namespace boost { namespace filesystem { class directory_entry; }}
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
inline std::optional<std::size_t> thread_count;
|
||||
extern void set_logging_level(unsigned int level);
|
||||
extern unsigned get_logging_level();
|
||||
// Format memory allocated, separate thousands by comma.
|
||||
@ -29,7 +30,7 @@ extern std::string format_memsize_MB(size_t n);
|
||||
// The string is non-empty if the loglevel >= info (3) or ignore_loglevel==true.
|
||||
// Latter is used to get the memory info from SysInfoDialog.
|
||||
extern std::string log_memory_info(bool ignore_loglevel = false);
|
||||
extern void disable_multi_threading();
|
||||
extern void enforce_thread_count(std::size_t count);
|
||||
// Returns the size of physical memory (RAM) in bytes.
|
||||
extern size_t total_physical_memory();
|
||||
|
||||
@ -73,10 +74,6 @@ const std::string& data_dir();
|
||||
// so the user knows where to search for the debugging output.
|
||||
std::string debug_out_path(const char *name, ...);
|
||||
|
||||
// A special type for strings encoded in the local Windows 8-bit code page.
|
||||
// This type is only needed for Perl bindings to relay to Perl that the string is raw, not UTF-8 encoded.
|
||||
typedef std::string local_encoded_string;
|
||||
|
||||
// Returns next utf8 sequence length. =number of bytes in string, that creates together one utf-8 character.
|
||||
// Starting at pos. ASCII characters returns 1. Works also if pos is in the middle of the sequence.
|
||||
extern size_t get_utf8_sequence_length(const std::string& text, size_t pos = 0);
|
||||
|
@ -124,23 +124,22 @@ unsigned get_logging_level()
|
||||
}
|
||||
|
||||
// Force set_logging_level(<=error) after loading of the DLL.
|
||||
// This is currently only needed if libslic3r is loaded as a shared library into Perl interpreter
|
||||
// to perform unit and integration tests.
|
||||
// This is used ot disable logging for unit and integration tests.
|
||||
static struct RunOnInit {
|
||||
RunOnInit() {
|
||||
RunOnInit() {
|
||||
set_logging_level(1);
|
||||
}
|
||||
} g_RunOnInit;
|
||||
|
||||
void disable_multi_threading()
|
||||
void enforce_thread_count(const std::size_t count)
|
||||
{
|
||||
// Disable parallelization to simplify debugging.
|
||||
#ifdef TBB_HAS_GLOBAL_CONTROL
|
||||
{
|
||||
static tbb::global_control gc(tbb::global_control::max_allowed_parallelism, 1);
|
||||
static tbb::global_control gc(tbb::global_control::max_allowed_parallelism, count);
|
||||
}
|
||||
#else // TBB_HAS_GLOBAL_CONTROL
|
||||
static tbb::task_scheduler_init *tbb_init = new tbb::task_scheduler_init(1);
|
||||
static tbb::task_scheduler_init *tbb_init = new tbb::task_scheduler_init(count);
|
||||
UNUSED(tbb_init);
|
||||
#endif // TBB_HAS_GLOBAL_CONTROL
|
||||
}
|
||||
@ -707,7 +706,7 @@ CopyFileResult copy_file_inner(const std::string& from, const std::string& to, s
|
||||
// That may happen when copying on some exotic file system, for example Linux on Chrome.
|
||||
copy_file_linux(source, target, ec);
|
||||
#else // __linux__
|
||||
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
|
||||
boost::filesystem::copy_file(source, target, boost::filesystem::copy_options::overwrite_existing, ec);
|
||||
#endif // __linux__
|
||||
if (ec) {
|
||||
error_message = ec.message();
|
||||
|
@ -2785,8 +2785,10 @@ bool ConfigWizard::priv::on_bnt_finish()
|
||||
* than last changes wouldn't be updated for filaments/materials.
|
||||
* SO, do that before check_and_install_missing_materials()
|
||||
*/
|
||||
page_filaments->check_and_update_presets();
|
||||
page_sla_materials->check_and_update_presets();
|
||||
if (page_filaments)
|
||||
page_filaments->check_and_update_presets();
|
||||
if (page_sla_materials)
|
||||
page_sla_materials->check_and_update_presets();
|
||||
|
||||
// there's no need to check that filament is selected if we have only custom printer
|
||||
if (custom_printer_selected && !any_fff_selected && !any_sla_selected) return true;
|
||||
@ -2998,7 +3000,7 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
|
||||
}
|
||||
}
|
||||
}
|
||||
return pt;
|
||||
return ptAny;
|
||||
};
|
||||
// Prusa printers are considered first, then 3rd party.
|
||||
if (preferred_pt = get_preferred_printer_technology("PrusaResearch", bundles.prusa_bundle());
|
||||
|
@ -2239,7 +2239,7 @@ static std::string get_new_color(const std::string& color)
|
||||
data->SetChooseFull(1);
|
||||
data->SetColour(clr);
|
||||
|
||||
wxColourDialog dialog(nullptr, data);
|
||||
wxColourDialog dialog(GUI::wxGetApp().GetTopWindow(), data);
|
||||
dialog.CenterOnParent();
|
||||
if (dialog.ShowModal() == wxID_OK)
|
||||
return dialog.GetColourData().GetColour().GetAsString(wxC2S_HTML_SYNTAX).ToStdString();
|
||||
|
@ -138,7 +138,7 @@ void FileGet::priv::get_perform()
|
||||
if (m_written == 0)
|
||||
{
|
||||
boost::filesystem::path dest_path = m_dest_folder / m_filename;
|
||||
std::string extension = boost::filesystem::extension(dest_path);
|
||||
std::string extension = dest_path.extension().string();
|
||||
std::string just_filename = m_filename.substr(0, m_filename.size() - extension.size());
|
||||
std::string final_filename = just_filename;
|
||||
// Find unsed filename
|
||||
|
@ -4912,8 +4912,9 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const
|
||||
|
||||
camera.apply_projection(volumes_box, near_z, far_z);
|
||||
|
||||
const ModelObjectPtrs &model_objects = GUI::wxGetApp().model().objects;
|
||||
std::vector<ColorRGBA> extruders_colors = get_extruders_colors();
|
||||
const ModelObjectPtrs &model_objects = GUI::wxGetApp().model().objects;
|
||||
std::vector<ColorRGBA> extruders_colors = get_extruders_colors();
|
||||
const bool is_enabled_painted_thumbnail = !model_objects.empty() && !extruders_colors.empty();
|
||||
|
||||
if (thumbnail_params.transparent_background)
|
||||
glsafe(::glClearColor(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
@ -4928,8 +4929,7 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const
|
||||
for (GLVolume *vol : visible_volumes) {
|
||||
const int obj_idx = vol->object_idx();
|
||||
const int vol_idx = vol->volume_idx();
|
||||
const bool render_as_painted = (obj_idx >= 0 && vol_idx >= 0) ?
|
||||
!model_objects[obj_idx]->volumes[vol_idx]->mmu_segmentation_facets.empty() : false;
|
||||
const bool render_as_painted = is_enabled_painted_thumbnail && obj_idx >= 0 && vol_idx >= 0 && !model_objects[obj_idx]->volumes[vol_idx]->mmu_segmentation_facets.empty();
|
||||
GLShaderProgram* shader = wxGetApp().get_shader(render_as_painted ? "mm_gouraud" : "gouraud_light");
|
||||
if (shader == nullptr)
|
||||
continue;
|
||||
@ -4962,7 +4962,7 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const
|
||||
glsafe(::glFrontFace(GL_CW));
|
||||
|
||||
if (render_as_painted) {
|
||||
const ModelVolume& model_volume = *model_objects[obj_idx]->volumes[vol_idx];
|
||||
const ModelVolume& model_volume = *model_objects[obj_idx]->volumes[vol_idx];
|
||||
const size_t extruder_idx = get_extruder_color_idx(model_volume, extruders_count);
|
||||
TriangleSelectorMmGui ts(model_volume.mesh(), extruders_colors, extruders_colors[extruder_idx]);
|
||||
ts.deserialize(model_volume.mmu_segmentation_facets.get_data(), true);
|
||||
|
@ -49,7 +49,6 @@ extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_
|
||||
void show_error(wxWindow* parent, const wxString& message, bool monospaced_font = false);
|
||||
void show_error(wxWindow* parent, const char* message, bool monospaced_font = false);
|
||||
inline void show_error(wxWindow* parent, const std::string& message, bool monospaced_font = false) { show_error(parent, message.c_str(), monospaced_font); }
|
||||
void show_error_id(int id, const std::string& message); // For Perl
|
||||
void show_info(wxWindow* parent, const wxString& message, const wxString& title = wxString());
|
||||
void show_info(wxWindow* parent, const char* message, const char* title = nullptr);
|
||||
inline void show_info(wxWindow* parent, const std::string& message,const std::string& title = std::string()) { show_info(parent, message.c_str(), title.c_str()); }
|
||||
|
@ -567,7 +567,7 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension)
|
||||
return file_wildcards(file_wildcards_by_type[file_type], custom_extension);
|
||||
}
|
||||
|
||||
wxString sla_wildcards(const char *formatid)
|
||||
wxString sla_wildcards(const char *formatid, const std::string& custom_extension)
|
||||
{
|
||||
const ArchiveEntry *entry = get_archive_entry(formatid);
|
||||
wxString ret;
|
||||
@ -587,11 +587,11 @@ wxString sla_wildcards(const char *formatid)
|
||||
wc.file_extensions.emplace_back(ext);
|
||||
}
|
||||
|
||||
ret = file_wildcards(wc, {});
|
||||
ret = file_wildcards(wc, custom_extension);
|
||||
}
|
||||
|
||||
if (ret.empty())
|
||||
ret = file_wildcards(FT_SL1);
|
||||
ret = file_wildcards(FT_SL1, custom_extension);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -889,12 +889,8 @@ std::string GUI_App::get_gl_info(bool for_github)
|
||||
wxGLContext* GUI_App::init_glcontext(wxGLCanvas& canvas)
|
||||
{
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
#if ENABLE_OPENGL_DEBUG_OPTION
|
||||
return m_opengl_mgr.init_glcontext(canvas, init_params != nullptr ? init_params->opengl_version : std::make_pair(0, 0),
|
||||
init_params != nullptr ? init_params->opengl_debug : false);
|
||||
#else
|
||||
return m_opengl_mgr.init_glcontext(canvas, init_params != nullptr ? init_params->opengl_version : std::make_pair(0, 0));
|
||||
#endif // ENABLE_OPENGL_DEBUG_OPTION
|
||||
init_params != nullptr ? init_params->opengl_compatibiity_profile : false, init_params != nullptr ? init_params->opengl_debug : false);
|
||||
#else
|
||||
return m_opengl_mgr.init_glcontext(canvas);
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
|
@ -86,7 +86,7 @@ enum FileType
|
||||
|
||||
extern wxString file_wildcards(FileType file_type, const std::string &custom_extension = {});
|
||||
|
||||
wxString sla_wildcards(const char *formatid);
|
||||
wxString sla_wildcards(const char *formatid, const std::string& custom_extension);
|
||||
|
||||
enum ConfigMenuIDs {
|
||||
ConfigMenuWizard,
|
||||
@ -415,7 +415,6 @@ private:
|
||||
|
||||
bool m_datadir_redefined { false };
|
||||
bool m_wifi_config_dialog_shown { false };
|
||||
bool m_wifi_config_dialog_was_declined { false };
|
||||
};
|
||||
|
||||
DECLARE_APP(GUI_App)
|
||||
|
@ -30,11 +30,7 @@
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
const std::vector<std::string> OpenGLVersions::core_str = { "3.2", "3.3", "4.0", "4.1", "4.2", "4.3", "4.4", "4.5", "4.6" };
|
||||
const std::vector<std::string> OpenGLVersions::precore_str = { "2.0", "2.1", "3.0", "3.1" };
|
||||
|
||||
const std::vector<std::pair<int, int>> OpenGLVersions::core = { {3,2}, {3,3}, {4,0}, {4,1}, {4,2}, {4,3}, {4,4}, {4,5}, {4,6} };
|
||||
const std::vector<std::pair<int, int>> OpenGLVersions::precore = { {2,0}, {2,1}, {3,0}, {3,1} };
|
||||
|
||||
int GUI_Run(GUI_InitParams ¶ms)
|
||||
{
|
||||
|
@ -14,11 +14,7 @@ namespace GUI {
|
||||
|
||||
struct OpenGLVersions
|
||||
{
|
||||
static const std::vector<std::string> core_str;
|
||||
static const std::vector<std::string> precore_str;
|
||||
|
||||
static const std::vector<std::pair<int, int>> core;
|
||||
static const std::vector<std::pair<int, int>> precore;
|
||||
};
|
||||
|
||||
struct GUI_InitParams
|
||||
@ -33,15 +29,14 @@ struct GUI_InitParams
|
||||
DynamicPrintConfig extra_config;
|
||||
std::vector<std::string> input_files;
|
||||
|
||||
bool start_as_gcodeviewer;
|
||||
bool start_downloader;
|
||||
bool delete_after_load;
|
||||
bool start_as_gcodeviewer;
|
||||
bool start_downloader;
|
||||
bool delete_after_load;
|
||||
std::string download_url;
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
std::pair<int, int> opengl_version;
|
||||
#if ENABLE_OPENGL_DEBUG_OPTION
|
||||
bool opengl_debug;
|
||||
#endif // ENABLE_OPENGL_DEBUG_OPTION
|
||||
std::pair<int, int> opengl_version;
|
||||
bool opengl_debug;
|
||||
bool opengl_compatibiity_profile;
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
};
|
||||
|
||||
|
@ -503,7 +503,7 @@ void GalleryDialog::change_thumbnail()
|
||||
png_path.replace_extension("png");
|
||||
|
||||
fs::path current = fs::path(into_u8(input_files.Item(0)));
|
||||
fs::copy_file(current, png_path, fs::copy_option::overwrite_if_exists);
|
||||
fs::copy_file(current, png_path, fs::copy_options::overwrite_existing);
|
||||
}
|
||||
catch (fs::filesystem_error const& e) {
|
||||
std::cerr << e.what() << '\n';
|
||||
|
@ -3311,7 +3311,7 @@ static void check_objects_after_cut(const ModelObjectPtrs& objects)
|
||||
for (int obj_idx : err_objects_idxs)
|
||||
model_names.push_back(objects[obj_idx]->name);
|
||||
|
||||
auto fix_and_update_progress = [plater, model_names, &objects](const int obj_idx, int model_idx,
|
||||
auto fix_and_update_progress = [model_names, &objects](const int obj_idx, int model_idx,
|
||||
wxProgressDialog& progress_dlg,
|
||||
std::vector<std::string>& succes_models,
|
||||
std::vector<std::pair<std::string, std::string>>& failed_models) -> bool
|
||||
|
@ -77,6 +77,14 @@ using namespace Slic3r::GUI;
|
||||
using namespace Slic3r::GUI::Emboss;
|
||||
|
||||
namespace {
|
||||
// TRN - Title in Undo/Redo stack after rotate with text around emboss axe
|
||||
const std::string rotation_snapshot_name = L("Text rotate");
|
||||
// NOTE: Translation is made in "m_parent.do_rotate()"
|
||||
|
||||
// TRN - Title in Undo/Redo stack after move with text along emboss axe - From surface
|
||||
const std::string move_snapshot_name = L("Text move");
|
||||
// NOTE: Translation is made in "m_parent.do_translate()"
|
||||
|
||||
template<typename T> struct Limit {
|
||||
// Limitation for view slider range in GUI
|
||||
MinMax<T> gui;
|
||||
@ -88,7 +96,7 @@ static const struct Limits
|
||||
{
|
||||
MinMax<double> emboss{0.01, 1e4}; // in mm
|
||||
MinMax<float> size_in_mm{0.1f, 1000.f}; // in mm
|
||||
Limit<float> boldness{{-200.f, 200.f}, {-2e4f, 2e4f}}; // in font points
|
||||
Limit<float> boldness{{-.5f, .5f}, {-5e5f, 5e5f}}; // in font points
|
||||
Limit<float> skew{{-1.f, 1.f}, {-100.f, 100.f}}; // ration without unit
|
||||
MinMax<int> char_gap{-20000, 20000}; // in font points
|
||||
MinMax<int> line_gap{-20000, 20000}; // in font points
|
||||
@ -372,7 +380,7 @@ bool GLGizmoEmboss::re_emboss(const ModelVolume &text_volume, std::shared_ptr<st
|
||||
TextLinesModel text_lines;
|
||||
const Selection &selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
DataBasePtr base = create_emboss_data_base(tc.text, style_manager, text_lines, selection, text_volume.type(), job_cancel);
|
||||
DataUpdate data{std::move(base), text_volume.id()};
|
||||
DataUpdate data{std::move(base), text_volume.id(), false};
|
||||
|
||||
RaycastManager raycast_manager; // Nothing is cached now, so It need to create raycasters
|
||||
return start_update_volume(std::move(data), text_volume, selection, raycast_manager);
|
||||
@ -978,7 +986,7 @@ void GLGizmoEmboss::on_stop_dragging()
|
||||
m_rotate_gizmo.set_angle(PI/2);
|
||||
|
||||
// apply rotation
|
||||
m_parent.do_rotate(L("Text-Rotate"));
|
||||
m_parent.do_rotate(rotation_snapshot_name);
|
||||
m_rotate_start_angle.reset();
|
||||
volume_transformation_changed();
|
||||
}
|
||||
@ -1308,7 +1316,7 @@ namespace {
|
||||
bool is_text_empty(std::string_view text) { return text.empty() || text.find_first_not_of(" \n\t\r") == std::string::npos; }
|
||||
} // namespace
|
||||
|
||||
bool GLGizmoEmboss::process()
|
||||
bool GLGizmoEmboss::process(bool make_snapshot)
|
||||
{
|
||||
// no volume is selected -> selection from right panel
|
||||
assert(m_volume != nullptr);
|
||||
@ -1322,7 +1330,7 @@ bool GLGizmoEmboss::process()
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
DataBasePtr base = create_emboss_data_base(m_text, m_style_manager, m_text_lines, selection, m_volume->type(), m_job_cancel);
|
||||
DataUpdate data{std::move(base), m_volume->id()};
|
||||
DataUpdate data{std::move(base), m_volume->id(), make_snapshot};
|
||||
|
||||
// check valid count of text lines
|
||||
assert(data.base->text_lines.empty() || data.base->text_lines.size() == get_count_lines(m_text));
|
||||
@ -2139,7 +2147,9 @@ void fix_transformation(const StyleManager::Style &from, const StyleManager::Sty
|
||||
// fix rotation
|
||||
float f_angle = f_angle_opt.value_or(.0f);
|
||||
float t_angle = t_angle_opt.value_or(.0f);
|
||||
do_local_z_rotate(canvas, t_angle - f_angle);
|
||||
do_local_z_rotate(canvas.get_selection(), t_angle - f_angle);
|
||||
std::string no_snapshot;
|
||||
canvas.do_rotate(no_snapshot);
|
||||
}
|
||||
|
||||
// fix distance (Z move) when exists difference in styles
|
||||
@ -2148,7 +2158,9 @@ void fix_transformation(const StyleManager::Style &from, const StyleManager::Sty
|
||||
if (!is_approx(f_move_opt, t_move_opt)) {
|
||||
float f_move = f_move_opt.value_or(.0f);
|
||||
float t_move = t_move_opt.value_or(.0f);
|
||||
do_local_z_move(canvas, t_move - f_move);
|
||||
do_local_z_move(canvas.get_selection(), t_move - f_move);
|
||||
std::string no_snapshot;
|
||||
canvas.do_move(no_snapshot);
|
||||
}
|
||||
}
|
||||
} // namesapce
|
||||
@ -2412,6 +2424,10 @@ bool GLGizmoEmboss::revertible(const std::string &name,
|
||||
ImGui::SameLine(undo_offset); // change cursor postion
|
||||
if (draw_button(m_icons, IconType::undo)) {
|
||||
value = *default_value;
|
||||
|
||||
// !! Fix to detect change of value after revert of float-slider
|
||||
m_imgui->get_last_slider_status().deactivated_after_edit = true;
|
||||
|
||||
return true;
|
||||
} else if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", undo_tooltip.c_str());
|
||||
@ -2649,7 +2665,6 @@ void GLGizmoEmboss::draw_advanced()
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_GREY_DARK, ff_property);
|
||||
#endif // SHOW_FONT_FILE_PROPERTY
|
||||
|
||||
bool exist_change = false;
|
||||
auto &tr = m_gui_cfg->translations;
|
||||
|
||||
const StyleManager::Style *stored_style = nullptr;
|
||||
@ -2741,6 +2756,7 @@ void GLGizmoEmboss::draw_advanced()
|
||||
auto def_char_gap = stored_style ?
|
||||
&stored_style->prop.char_gap : nullptr;
|
||||
|
||||
bool exist_change = false;
|
||||
int half_ascent = font_info.ascent / 2;
|
||||
int min_char_gap = -half_ascent;
|
||||
int max_char_gap = half_ascent;
|
||||
@ -2756,13 +2772,16 @@ void GLGizmoEmboss::draw_advanced()
|
||||
exist_change = true;
|
||||
}
|
||||
}
|
||||
bool last_change = false;
|
||||
if (m_imgui->get_last_slider_status().deactivated_after_edit)
|
||||
last_change = true;
|
||||
|
||||
// input gap between lines
|
||||
bool is_multiline = m_text_lines.get_lines().size() > 1;
|
||||
bool is_multiline = get_count_lines(m_volume->text_configuration->text) > 1; // TODO: cache count lines
|
||||
m_imgui->disabled_begin(!is_multiline);
|
||||
auto def_line_gap = stored_style ?
|
||||
&stored_style->prop.line_gap : nullptr;
|
||||
int min_line_gap = -half_ascent;
|
||||
int min_line_gap = -half_ascent;
|
||||
int max_line_gap = half_ascent;
|
||||
if (rev_slider(tr.line_gap, current_prop.line_gap, def_line_gap, _u8L("Revert gap between lines"),
|
||||
min_line_gap, max_line_gap, units_fmt, _L("Distance between lines"))){
|
||||
@ -2777,18 +2796,24 @@ void GLGizmoEmboss::draw_advanced()
|
||||
exist_change = true;
|
||||
}
|
||||
}
|
||||
if (m_imgui->get_last_slider_status().deactivated_after_edit)
|
||||
last_change = true;
|
||||
m_imgui->disabled_end(); // !is_multiline
|
||||
|
||||
// input boldness
|
||||
auto def_boldness = stored_style ?
|
||||
&stored_style->prop.boldness : nullptr;
|
||||
int min_boldness = static_cast<int>(font_info.ascent * limits.boldness.gui.min);
|
||||
int max_boldness = static_cast<int>(font_info.ascent * limits.boldness.gui.max);
|
||||
if (rev_slider(tr.boldness, current_prop.boldness, def_boldness, _u8L("Undo boldness"),
|
||||
limits.boldness.gui.min, limits.boldness.gui.max, units_fmt, _L("Tiny / Wide glyphs"))){
|
||||
min_boldness, max_boldness, units_fmt, _L("Tiny / Wide glyphs"))){
|
||||
const std::optional<float> &volume_boldness = m_volume->text_configuration->style.prop.boldness;
|
||||
if (!apply(current_prop.boldness, limits.boldness.values) ||
|
||||
!volume_boldness.has_value() || volume_boldness != current_prop.boldness)
|
||||
exist_change = true;
|
||||
}
|
||||
if (m_imgui->get_last_slider_status().deactivated_after_edit)
|
||||
last_change = true;
|
||||
|
||||
// input italic
|
||||
auto def_skew = stored_style ?
|
||||
@ -2800,6 +2825,8 @@ void GLGizmoEmboss::draw_advanced()
|
||||
!volume_skew.has_value() ||volume_skew != current_prop.skew)
|
||||
exist_change = true;
|
||||
}
|
||||
if (m_imgui->get_last_slider_status().deactivated_after_edit)
|
||||
last_change = true;
|
||||
|
||||
// input surface distance
|
||||
bool allowe_surface_distance = !use_surface && !m_volume->is_the_only_one_part();
|
||||
@ -2839,11 +2866,19 @@ void GLGizmoEmboss::draw_advanced()
|
||||
|
||||
if (is_moved){
|
||||
if (font_prop.per_glyph){
|
||||
process();
|
||||
process(false);
|
||||
} else {
|
||||
do_local_z_move(m_parent, distance.value_or(.0f) - prev_distance);
|
||||
}
|
||||
do_local_z_move(m_parent.get_selection(), distance.value_or(.0f) - prev_distance);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply move to model(backend)
|
||||
if (m_imgui->get_last_slider_status().deactivated_after_edit) {
|
||||
m_parent.do_move(move_snapshot_name);
|
||||
if (font_prop.per_glyph)
|
||||
process();
|
||||
}
|
||||
|
||||
m_imgui->disabled_end(); // allowe_surface_distance
|
||||
|
||||
// slider for Clock-wise angle in degress
|
||||
@ -2865,7 +2900,7 @@ void GLGizmoEmboss::draw_advanced()
|
||||
Geometry::to_range_pi_pi(angle_rad);
|
||||
|
||||
double diff_angle = angle_rad - angle;
|
||||
do_local_z_rotate(m_parent, diff_angle);
|
||||
do_local_z_rotate(m_parent.get_selection(), diff_angle);
|
||||
|
||||
// calc angle after rotation
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
@ -2880,6 +2915,15 @@ void GLGizmoEmboss::draw_advanced()
|
||||
|
||||
// recalculate for surface cut
|
||||
if (use_surface || font_prop.per_glyph)
|
||||
process(false);
|
||||
}
|
||||
|
||||
// Apply rotation on model (backend)
|
||||
if (m_imgui->get_last_slider_status().deactivated_after_edit) {
|
||||
m_parent.do_rotate(rotation_snapshot_name);
|
||||
|
||||
// recalculate for surface cut
|
||||
if (use_surface || font_prop.per_glyph)
|
||||
process();
|
||||
}
|
||||
|
||||
@ -2913,6 +2957,7 @@ void GLGizmoEmboss::draw_advanced()
|
||||
if (i == 0) current_prop.collection_number.reset();
|
||||
else current_prop.collection_number = i;
|
||||
exist_change = true;
|
||||
last_change = true;
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
@ -2922,13 +2967,13 @@ void GLGizmoEmboss::draw_advanced()
|
||||
}
|
||||
}
|
||||
|
||||
if (exist_change) {
|
||||
if (exist_change || last_change) {
|
||||
m_style_manager.clear_glyphs_cache();
|
||||
if (m_style_manager.get_font_prop().per_glyph)
|
||||
if (font_prop.per_glyph)
|
||||
reinit_text_lines();
|
||||
else
|
||||
m_text_lines.reset();
|
||||
process();
|
||||
process(last_change);
|
||||
}
|
||||
|
||||
if (ImGui::Button(_u8L("Set text to face camera").c_str())) {
|
||||
@ -3582,7 +3627,7 @@ GuiCfg create_gui_configuration()
|
||||
float space = line_height_with_spacing - line_height;
|
||||
const ImGuiStyle &style = ImGui::GetStyle();
|
||||
|
||||
cfg.max_style_name_width = ImGui::CalcTextSize("Maximal font name, extended").x;
|
||||
cfg.max_style_name_width = ImGui::CalcTextSize("Maximal style name..").x;
|
||||
|
||||
cfg.icon_width = static_cast<unsigned int>(std::ceil(line_height));
|
||||
// make size pair number
|
||||
@ -3701,11 +3746,11 @@ GuiCfg create_gui_configuration()
|
||||
ImVec2(cfg.minimal_window_size_with_advance.x,
|
||||
cfg.minimal_window_size_with_advance.y + input_height);
|
||||
|
||||
int max_style_image_width = static_cast<int>(std::round(cfg.max_style_name_width/2 - 2 * style.FramePadding.x));
|
||||
int max_style_image_width = static_cast<int>(std::round(cfg.max_style_name_width - 2 * style.FramePadding.x));
|
||||
int max_style_image_height = static_cast<int>(std::round(1.5 * input_height));
|
||||
cfg.max_style_image_size = Vec2i(max_style_image_width, max_style_image_height);
|
||||
cfg.face_name_size = Vec2i(cfg.input_width, line_height_with_spacing);
|
||||
cfg.face_name_texture_offset_x = cfg.face_name_size.x() + space;
|
||||
cfg.face_name_texture_offset_x = cfg.face_name_size.x() + style.WindowPadding.x + space;
|
||||
return cfg;
|
||||
}
|
||||
} // namespace
|
||||
|
@ -114,7 +114,7 @@ private:
|
||||
void reset_volume();
|
||||
|
||||
// create volume from text - main functionality
|
||||
bool process();
|
||||
bool process(bool make_snapshot = true);
|
||||
void close();
|
||||
void draw_window();
|
||||
void draw_text_input();
|
||||
|