Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbubnikv <bubnikv@gmail.com>2019-07-04 21:22:15 +0300
committerbubnikv <bubnikv@gmail.com>2019-07-04 21:22:15 +0300
commitc7cc76006706fefef52060a2165708c233dbadfd (patch)
treeafa1f11f7643f12c9a1a698be34b6ab33707604c
parent1070991149b5279f96fb4365094c6eec98d9243f (diff)
parentf617d747293de0e0bbb500ced8c4a66cdbdadf24 (diff)
Merge remote-tracking branch 'origin/master' into vb_undo_redo
-rw-r--r--deps/CMakeLists.txt9
-rw-r--r--deps/deps-unix-common.cmake2
-rw-r--r--deps/deps-windows.cmake2
-rw-r--r--lib/Slic3r.pm1
-rw-r--r--lib/Slic3r/Print/Simple.pm104
-rw-r--r--lib/Slic3r/Test.pm82
-rw-r--r--resources/icons/row.pngbin0 -> 1923 bytes
-rw-r--r--resources/icons/table.pngbin0 -> 465 bytes
-rw-r--r--src/PrusaSlicer.cpp2
-rw-r--r--src/avrdude/arduino.c13
-rw-r--r--src/avrdude/avr.c24
-rw-r--r--src/avrdude/avr910.c2
-rw-r--r--src/avrdude/avrdude-slic3r.conf.h6
-rw-r--r--src/avrdude/avrdude-slic3r.cpp6
-rw-r--r--src/avrdude/avrdude.h2
-rw-r--r--src/avrdude/avrpart.c4
-rw-r--r--src/avrdude/buspirate.c4
-rw-r--r--src/avrdude/butterfly.c2
-rw-r--r--src/avrdude/conf-generate.cpp6
-rw-r--r--src/avrdude/config.c6
-rw-r--r--src/avrdude/config_gram.c2
-rw-r--r--src/avrdude/config_gram.y2
-rw-r--r--src/avrdude/fileio.c43
-rw-r--r--src/avrdude/lists.c12
-rw-r--r--src/avrdude/main.c6
-rw-r--r--src/avrdude/pindefs.c2
-rw-r--r--src/avrdude/ser_win32.c12
-rw-r--r--src/avrdude/serbb_win32.c8
-rw-r--r--src/avrdude/stk500.c12
-rw-r--r--src/avrdude/stk500v2.c205
-rw-r--r--src/avrdude/term.c26
-rw-r--r--src/libigl/CMakeLists.txt2
-rw-r--r--src/libnest2d/tests/test.cpp548
-rw-r--r--src/libslic3r/Config.cpp8
-rw-r--r--src/libslic3r/Config.hpp6
-rw-r--r--src/libslic3r/Fill/Fill.cpp12
-rw-r--r--src/libslic3r/Format/3mf.cpp162
-rw-r--r--src/libslic3r/Format/AMF.cpp63
-rw-r--r--src/libslic3r/GCode.cpp4
-rw-r--r--src/libslic3r/MTUtils.hpp92
-rw-r--r--src/libslic3r/MinAreaBoundingBox.cpp68
-rw-r--r--src/libslic3r/Model.cpp12
-rw-r--r--src/libslic3r/Model.hpp4
-rw-r--r--src/libslic3r/ModelArrange.cpp24
-rw-r--r--src/libslic3r/Print.cpp482
-rw-r--r--src/libslic3r/Print.hpp28
-rw-r--r--src/libslic3r/PrintObject.cpp332
-rw-r--r--src/libslic3r/SLA/SLABasePool.cpp15
-rw-r--r--src/libslic3r/SLAPrint.cpp39
-rw-r--r--src/libslic3r/Slicing.cpp21
-rw-r--r--src/libslic3r/Slicing.hpp10
-rw-r--r--src/libslic3r/SupportMaterial.cpp6
-rw-r--r--src/libslic3r/Technologies.hpp2
-rw-r--r--src/libslic3r/TriangleMesh.cpp4
-rw-r--r--src/libslic3r/Utils.hpp2
-rw-r--r--src/libslic3r/libslic3r.h14
-rw-r--r--src/semver/semver.c17
-rw-r--r--src/slic3r/CMakeLists.txt2
-rw-r--r--src/slic3r/GUI/3DBed.cpp4
-rw-r--r--src/slic3r/GUI/3DBed.hpp4
-rw-r--r--src/slic3r/GUI/AppConfig.cpp7
-rw-r--r--src/slic3r/GUI/BedShapeDialog.cpp36
-rw-r--r--src/slic3r/GUI/BonjourDialog.cpp2
-rw-r--r--src/slic3r/GUI/Camera.cpp2
-rw-r--r--src/slic3r/GUI/ConfigWizard.cpp6
-rw-r--r--src/slic3r/GUI/Field.cpp14
-rw-r--r--src/slic3r/GUI/FirmwareDialog.cpp3
-rw-r--r--src/slic3r/GUI/GLCanvas3D.cpp52
-rw-r--r--src/slic3r/GUI/GLCanvas3D.hpp10
-rw-r--r--src/slic3r/GUI/GLCanvas3DManager.cpp10
-rw-r--r--src/slic3r/GUI/GLCanvas3DManager.hpp1
-rw-r--r--src/slic3r/GUI/GLSelectionRectangle.cpp8
-rw-r--r--src/slic3r/GUI/GUI_App.cpp17
-rw-r--r--src/slic3r/GUI/GUI_App.hpp2
-rw-r--r--src/slic3r/GUI/GUI_ObjectLayers.cpp341
-rw-r--r--src/slic3r/GUI/GUI_ObjectLayers.hpp88
-rw-r--r--src/slic3r/GUI/GUI_ObjectList.cpp644
-rw-r--r--src/slic3r/GUI/GUI_ObjectList.hpp55
-rw-r--r--src/slic3r/GUI/GUI_ObjectSettings.cpp15
-rw-r--r--src/slic3r/GUI/GUI_Preview.cpp51
-rw-r--r--src/slic3r/GUI/GUI_Preview.hpp2
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoCut.cpp44
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp4
-rw-r--r--src/slic3r/GUI/ImGuiWrapper.cpp4
-rw-r--r--src/slic3r/GUI/KBShortcutsDialog.cpp3
-rw-r--r--src/slic3r/GUI/OptionsGroup.cpp11
-rw-r--r--src/slic3r/GUI/OptionsGroup.hpp2
-rw-r--r--src/slic3r/GUI/Plater.cpp105
-rw-r--r--src/slic3r/GUI/Plater.hpp18
-rw-r--r--src/slic3r/GUI/Preferences.cpp13
-rw-r--r--src/slic3r/GUI/Preset.cpp20
-rw-r--r--src/slic3r/GUI/Selection.cpp165
-rw-r--r--src/slic3r/GUI/Selection.hpp5
-rw-r--r--src/slic3r/GUI/Tab.cpp93
-rw-r--r--src/slic3r/GUI/Tab.hpp6
-rw-r--r--src/slic3r/GUI/wxExtensions.cpp308
-rw-r--r--src/slic3r/GUI/wxExtensions.hpp38
-rw-r--r--src/slic3r/Utils/PresetUpdater.cpp22
-rw-r--r--t/combineinfill.t2
-rw-r--r--t/print.t23
-rw-r--r--t/skirt_brim.t4
-rw-r--r--xs/t/19_model.t8
-rw-r--r--xs/xsp/Config.xsp2
-rw-r--r--xs/xsp/Model.xsp6
-rw-r--r--xs/xsp/Print.xsp8
105 files changed, 3279 insertions, 1595 deletions
diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt
index 1c468607e..4845b1cba 100644
--- a/deps/CMakeLists.txt
+++ b/deps/CMakeLists.txt
@@ -36,10 +36,11 @@ set(DESTDIR "${CMAKE_CURRENT_BINARY_DIR}/destdir" CACHE PATH "Destination direct
option(DEP_DEBUG "Build debug variants (only applicable on Windows)" ON)
option(DEP_WX_STABLE "Build against wxWidgets stable 3.0 as opposed to default 3.1 (Linux only)" OFF)
-# IGL static library in release mode produces 50MB binary. On the build server, it should be
-# disabled and used in header-only mode. On developer machines, it can be enabled to speed
-# up conpilation and suppress warnings coming from IGL.
-option(DEP_BUILD_IGL_STATIC "Build IGL as a static library. Might cause link errors and increase binary size." OFF)
+# On developer machines, it can be enabled to speed up compilation and suppress warnings coming from IGL.
+# FIXME:
+# Enabling this option is not safe. IGL will compile itself with its own version of Eigen while
+# Slic3r compiles with a different version which will cause runtime errors.
+# option(DEP_BUILD_IGL_STATIC "Build IGL as a static library. Might cause link errors and increase binary size." OFF)
message(STATUS "PrusaSlicer deps DESTDIR: ${DESTDIR}")
message(STATUS "PrusaSlicer deps debug build: ${DEP_DEBUG}")
diff --git a/deps/deps-unix-common.cmake b/deps/deps-unix-common.cmake
index 6d9d6fd75..e323460a6 100644
--- a/deps/deps-unix-common.cmake
+++ b/deps/deps-unix-common.cmake
@@ -64,7 +64,7 @@ ExternalProject_Add(dep_libigl
-DLIBIGL_BUILD_PYTHON=OFF
-DLIBIGL_BUILD_TESTS=OFF
-DLIBIGL_BUILD_TUTORIALS=OFF
- -DLIBIGL_USE_STATIC_LIBRARY=${DEP_BUILD_IGL_STATIC}
+ -DLIBIGL_USE_STATIC_LIBRARY=OFF #${DEP_BUILD_IGL_STATIC}
-DLIBIGL_WITHOUT_COPYLEFT=OFF
-DLIBIGL_WITH_CGAL=OFF
-DLIBIGL_WITH_COMISO=OFF
diff --git a/deps/deps-windows.cmake b/deps/deps-windows.cmake
index 2595f94d8..9092f330b 100644
--- a/deps/deps-windows.cmake
+++ b/deps/deps-windows.cmake
@@ -278,7 +278,7 @@ ExternalProject_Add(dep_libigl
-DLIBIGL_BUILD_PYTHON=OFF
-DLIBIGL_BUILD_TESTS=OFF
-DLIBIGL_BUILD_TUTORIALS=OFF
- -DLIBIGL_USE_STATIC_LIBRARY=${DEP_BUILD_IGL_STATIC}
+ -DLIBIGL_USE_STATIC_LIBRARY=OFF #${DEP_BUILD_IGL_STATIC}
-DLIBIGL_WITHOUT_COPYLEFT=OFF
-DLIBIGL_WITH_CGAL=OFF
-DLIBIGL_WITH_COMISO=OFF
diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm
index 44100db8c..94f0b5658 100644
--- a/lib/Slic3r.pm
+++ b/lib/Slic3r.pm
@@ -50,7 +50,6 @@ use Slic3r::Point;
use Slic3r::Polygon;
use Slic3r::Polyline;
use Slic3r::Print::Object;
-use Slic3r::Print::Simple;
use Slic3r::Surface;
our $build = eval "use Slic3r::Build; 1";
diff --git a/lib/Slic3r/Print/Simple.pm b/lib/Slic3r/Print/Simple.pm
deleted file mode 100644
index 2ab68f4d3..000000000
--- a/lib/Slic3r/Print/Simple.pm
+++ /dev/null
@@ -1,104 +0,0 @@
-# A simple wrapper to quickly print a single model without a GUI.
-# Used by the command line slic3r.pl, by command line utilities pdf-slic3s.pl and view-toolpaths.pl,
-# and by the quick slice menu of the Slic3r GUI.
-#
-# It creates and owns an instance of Slic3r::Print to perform the slicing
-# and it accepts an instance of Slic3r::Model from the outside.
-
-package Slic3r::Print::Simple;
-use Moo;
-
-use Slic3r::Geometry qw(X Y);
-
-has '_print' => (
- is => 'ro',
- default => sub { Slic3r::Print->new },
- handles => [qw(apply_config_perl_tests_only extruders output_filepath
- total_used_filament total_extruded_volume
- placeholder_parser process)],
-);
-
-has 'duplicate' => (
- is => 'rw',
- default => sub { 1 },
-);
-
-has 'scale' => (
- is => 'rw',
- default => sub { 1 },
-);
-
-has 'rotate' => (
- is => 'rw',
- default => sub { 0 },
-);
-
-has 'duplicate_grid' => (
- is => 'rw',
- default => sub { [1,1] },
-);
-
-has 'print_center' => (
- is => 'rw',
- default => sub { Slic3r::Pointf->new(100,100) },
-);
-
-has 'dont_arrange' => (
- is => 'rw',
- default => sub { 0 },
-);
-
-has 'output_file' => (
- is => 'rw',
-);
-
-sub set_model {
- # $model is of type Slic3r::Model
- my ($self, $model) = @_;
-
- # make method idempotent so that the object is reusable
- $self->_print->clear_objects;
-
- # make sure all objects have at least one defined instance
- my $need_arrange = $model->add_default_instances && ! $self->dont_arrange;
-
- # apply scaling and rotation supplied from command line if any
- foreach my $instance (map @{$_->instances}, @{$model->objects}) {
- $instance->set_scaling_factor($instance->scaling_factor * $self->scale);
- $instance->set_rotation($instance->rotation + $self->rotate);
- }
-
- if ($self->duplicate_grid->[X] > 1 || $self->duplicate_grid->[Y] > 1) {
- $model->duplicate_objects_grid($self->duplicate_grid->[X], $self->duplicate_grid->[Y], $self->_print->config->duplicate_distance);
- } elsif ($need_arrange) {
- $model->duplicate_objects($self->duplicate, $self->_print->config->min_object_distance);
- } elsif ($self->duplicate > 1) {
- # if all input objects have defined position(s) apply duplication to the whole model
- $model->duplicate($self->duplicate, $self->_print->config->min_object_distance);
- }
- $_->translate(0,0,-$_->bounding_box->z_min) for @{$model->objects};
- $model->center_instances_around_point($self->print_center) if (! $self->dont_arrange);
-
- foreach my $model_object (@{$model->objects}) {
- $self->_print->auto_assign_extruders($model_object);
- $self->_print->add_model_object($model_object);
- }
-}
-
-sub export_gcode {
- my ($self) = @_;
- $self->_print->validate;
- $self->_print->export_gcode($self->output_file // '');
-}
-
-sub export_png {
- my ($self) = @_;
-
- $self->_before_export;
-
- $self->_print->export_png(output_file => $self->output_file);
-
- $self->_after_export;
-}
-
-1;
diff --git a/lib/Slic3r/Test.pm b/lib/Slic3r/Test.pm
index d1b99e48c..570bca41b 100644
--- a/lib/Slic3r/Test.pm
+++ b/lib/Slic3r/Test.pm
@@ -146,60 +146,66 @@ sub mesh {
}
sub model {
- my ($model_name, %params) = @_;
+ my ($model_names, %params) = @_;
+ $model_names = [ $model_names ] if ! ref($model_names);
- my $input_file = "${model_name}.stl";
- my $mesh = mesh($model_name, %params);
-# $mesh->write_ascii("out/$input_file");
-
my $model = Slic3r::Model->new;
- my $object = $model->add_object(input_file => $input_file);
- $model->set_material($model_name);
- $object->add_volume(mesh => $mesh, material_id => $model_name);
- $object->add_instance(
- offset => Slic3r::Pointf->new(0,0),
- # 3D full transform
- rotation => Slic3r::Pointf3->new(0, 0, $params{rotation} // 0),
- scaling_factor => Slic3r::Pointf3->new($params{scale} // 1, $params{scale} // 1, $params{scale} // 1),
- # old transform
-# rotation => $params{rotation} // 0,
-# scaling_factor => $params{scale} // 1,
- );
+
+ for my $model_name (@$model_names) {
+ my $input_file = "${model_name}.stl";
+ my $mesh = mesh($model_name, %params);
+ # $mesh->write_ascii("out/$input_file");
+
+ my $object = $model->add_object(input_file => $input_file);
+ $model->set_material($model_name);
+ $object->add_volume(mesh => $mesh, material_id => $model_name);
+ $object->add_instance(
+ offset => Slic3r::Pointf->new(0,0),
+ # 3D full transform
+ rotation => Slic3r::Pointf3->new(0, 0, $params{rotation} // 0),
+ scaling_factor => Slic3r::Pointf3->new($params{scale} // 1, $params{scale} // 1, $params{scale} // 1),
+ # old transform
+ # rotation => $params{rotation} // 0,
+ # scaling_factor => $params{scale} // 1,
+ );
+ }
return $model;
}
sub init_print {
my ($models, %params) = @_;
+ my $model;
+ if (ref($models) eq 'ARRAY') {
+ $model = model($models, %params);
+ } elsif (ref($models)) {
+ $model = $models;
+ } else {
+ $model = model([$models], %params);
+ }
my $config = Slic3r::Config->new;
$config->apply($params{config}) if $params{config};
$config->set('gcode_comments', 1) if $ENV{SLIC3R_TESTS_GCODE};
my $print = Slic3r::Print->new;
- $print->apply_config_perl_tests_only($config);
-
- $models = [$models] if ref($models) ne 'ARRAY';
- $models = [ map { ref($_) ? $_ : model($_, %params) } @$models ];
- for my $model (@$models) {
- die "Unknown model in test" if !defined $model;
- if (defined $params{duplicate} && $params{duplicate} > 1) {
- $model->duplicate($params{duplicate} // 1, $print->config->min_object_distance);
- }
- $model->arrange_objects($print->config->min_object_distance);
- $model->center_instances_around_point($params{print_center} ? Slic3r::Pointf->new(@{$params{print_center}}) : Slic3r::Pointf->new(100,100));
- foreach my $model_object (@{$model->objects}) {
- $print->auto_assign_extruders($model_object);
- $print->add_model_object($model_object);
- }
+ die "Unknown model in test" if !defined $model;
+ if (defined $params{duplicate} && $params{duplicate} > 1) {
+ $model->duplicate($params{duplicate} // 1, $config->min_object_distance);
}
- # Call apply_config_perl_tests_only one more time, so that the layer height profiles are updated over all PrintObjects.
- $print->apply_config_perl_tests_only($config);
+ $model->arrange_objects($config->min_object_distance);
+ $model->center_instances_around_point($params{print_center} ? Slic3r::Pointf->new(@{$params{print_center}}) : Slic3r::Pointf->new(100,100));
+ foreach my $model_object (@{$model->objects}) {
+ $model_object->ensure_on_bed;
+ $print->auto_assign_extruders($model_object);
+ }
+
+ $print->apply($model, $config);
$print->validate;
# We return a proxy object in order to keep $models alive as required by the Print API.
return Slic3r::Test::Print->new(
- print => $print,
- models => $models,
+ print => $print,
+ model => $model,
);
}
@@ -250,7 +256,7 @@ sub add_facet {
package Slic3r::Test::Print;
use Moo;
-has 'print' => (is => 'ro', required => 1, handles => [qw(process apply_config_perl_tests_only)]);
-has 'models' => (is => 'ro', required => 1);
+has 'print' => (is => 'ro', required => 1, handles => [qw(process apply)]);
+has 'model' => (is => 'ro', required => 1);
1;
diff --git a/resources/icons/row.png b/resources/icons/row.png
new file mode 100644
index 000000000..18a6034fd
--- /dev/null
+++ b/resources/icons/row.png
Binary files differ
diff --git a/resources/icons/table.png b/resources/icons/table.png
new file mode 100644
index 000000000..3bc0bd32f
--- /dev/null
+++ b/resources/icons/table.png
Binary files differ
diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp
index 2becb8071..9983c691b 100644
--- a/src/PrusaSlicer.cpp
+++ b/src/PrusaSlicer.cpp
@@ -579,7 +579,7 @@ void CLI::print_help(bool include_print_options, PrinterTechnology printer_techn
#endif /* SLIC3R_GUI */
<< std::endl
<< "https://github.com/prusa3d/PrusaSlicer" << std::endl << std::endl
- << "Usage: slic3r [ ACTIONS ] [ TRANSFORM ] [ OPTIONS ] [ file.stl ... ]" << std::endl
+ << "Usage: prusa-slicer [ ACTIONS ] [ TRANSFORM ] [ OPTIONS ] [ file.stl ... ]" << std::endl
<< std::endl
<< "Actions:" << std::endl;
cli_actions_config_def.print_cli_help(boost::nowide::cout, false);
diff --git a/src/avrdude/arduino.c b/src/avrdude/arduino.c
index 53e5ed822..e6008adeb 100644
--- a/src/avrdude/arduino.c
+++ b/src/avrdude/arduino.c
@@ -41,6 +41,7 @@
static int arduino_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
{
unsigned char buf[32];
+ (void)p;
/* Signature byte reads are always 3 bytes. */
@@ -83,9 +84,9 @@ static int arduino_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
static int prusa_init_external_flash(PROGRAMMER * pgm)
{
// Note: send/receive as in _the firmare_ send & receives
- const char entry_magic_send [] = "start\n";
- const char entry_magic_receive[] = "w25x20cl_enter\n";
- const char entry_magic_cfm [] = "w25x20cl_cfm\n";
+ const char entry_magic_send[] = "start\n";
+ const unsigned char entry_magic_receive[] = "w25x20cl_enter\n";
+ const char entry_magic_cfm[] = "w25x20cl_cfm\n";
const size_t buffer_len = 32; // Should be large enough for the above messages
int res;
@@ -94,7 +95,7 @@ static int prusa_init_external_flash(PROGRAMMER * pgm)
// 1. receive the "start" command
recv_size = sizeof(entry_magic_send) - 1;
- res = serial_recv(&pgm->fd, buffer, recv_size);
+ res = serial_recv(&pgm->fd, (unsigned char *)buffer, recv_size);
if (res < 0) {
avrdude_message(MSG_INFO, "%s: prusa_init_external_flash(): MK3 printer did not boot up on time or serial communication failed\n", progname);
return -1;
@@ -111,7 +112,7 @@ static int prusa_init_external_flash(PROGRAMMER * pgm)
// 3. Receive the entry confirmation command
recv_size = sizeof(entry_magic_cfm) - 1;
- res = serial_recv(&pgm->fd, buffer, recv_size);
+ res = serial_recv(&pgm->fd, (unsigned char *)buffer, recv_size);
if (res < 0) {
avrdude_message(MSG_INFO, "%s: prusa_init_external_flash(): MK3 printer did not boot up on time or serial communication failed\n", progname);
return -1;
@@ -142,7 +143,7 @@ static int arduino_open(PROGRAMMER * pgm, char * port)
// Sometimes there may be line noise generating input on the printer's USB-to-serial IC
// Here we try to clean its input buffer with a sequence of newlines (a minimum of 9 is needed):
- const char cleanup_newlines[] = "\n\n\n\n\n\n\n\n\n\n";
+ const unsigned char cleanup_newlines[] = "\n\n\n\n\n\n\n\n\n\n";
if (serial_send(&pgm->fd, cleanup_newlines, sizeof(cleanup_newlines) - 1) < 0) {
return -1;
}
diff --git a/src/avrdude/avr.c b/src/avrdude/avr.c
index 73dcaf4ff..defae75d5 100644
--- a/src/avrdude/avr.c
+++ b/src/avrdude/avr.c
@@ -341,7 +341,7 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype,
avr_tpi_setup_rw(pgm, mem, 0, TPI_NVMCMD_NO_OPERATION);
/* load bytes */
- for (lastaddr = i = 0; i < mem->size; i++) {
+ for (lastaddr = i = 0; i < (unsigned)mem->size; i++) {
RETURN_IF_CANCEL();
if (vmem == NULL ||
(vmem->tags[i] & TAG_ALLOCATED) != 0)
@@ -374,7 +374,7 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype,
/* quickly scan number of pages to be written to first */
for (pageaddr = 0, npages = 0;
- pageaddr < mem->size;
+ pageaddr < (unsigned)mem->size;
pageaddr += mem->page_size) {
/* check whether this page must be read */
for (i = pageaddr;
@@ -391,7 +391,7 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype,
}
for (pageaddr = 0, failure = 0, nread = 0;
- !failure && pageaddr < mem->size;
+ !failure && pageaddr < (unsigned)mem->size;
pageaddr += mem->page_size) {
RETURN_IF_CANCEL();
/* check whether this page must be read */
@@ -437,7 +437,7 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype,
}
}
- for (i=0; i < mem->size; i++) {
+ for (i = 0; i < (unsigned)mem->size; i++) {
RETURN_IF_CANCEL();
if (vmem == NULL ||
(vmem->tags[i] & TAG_ALLOCATED) != 0)
@@ -634,18 +634,18 @@ int avr_write_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
writeop = mem->op[AVR_OP_WRITE_HI];
else
writeop = mem->op[AVR_OP_WRITE_LO];
- caddr = addr / 2;
+ caddr = (unsigned short)(addr / 2);
}
else if (mem->paged && mem->op[AVR_OP_LOADPAGE_LO]) {
if (addr & 0x01)
writeop = mem->op[AVR_OP_LOADPAGE_HI];
else
writeop = mem->op[AVR_OP_LOADPAGE_LO];
- caddr = addr / 2;
+ caddr = (unsigned short)(addr / 2);
}
else {
writeop = mem->op[AVR_OP_WRITE];
- caddr = addr;
+ caddr = (unsigned short)addr;
}
if (writeop == NULL) {
@@ -723,7 +723,7 @@ int avr_write_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
gettimeofday (&tv, NULL);
prog_time = (tv.tv_sec * 1000000) + tv.tv_usec;
} while ((r != data) &&
- ((prog_time-start_time) < mem->max_write_delay));
+ ((prog_time - start_time) < (unsigned long)mem->max_write_delay));
}
/*
@@ -878,7 +878,7 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
}
/* write words, low byte first */
- for (lastaddr = i = 0; i < wsize; i += 2) {
+ for (lastaddr = i = 0; i < (unsigned)wsize; i += 2) {
RETURN_IF_CANCEL();
if ((m->tags[i] & TAG_ALLOCATED) != 0 ||
(m->tags[i + 1] & TAG_ALLOCATED) != 0) {
@@ -915,7 +915,7 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
/* quickly scan number of pages to be written to first */
for (pageaddr = 0, npages = 0;
- pageaddr < wsize;
+ pageaddr < (unsigned)wsize;
pageaddr += m->page_size) {
/* check whether this page must be written to */
for (i = pageaddr;
@@ -928,7 +928,7 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
}
for (pageaddr = 0, failure = 0, nwritten = 0;
- !failure && pageaddr < wsize;
+ !failure && pageaddr < (unsigned)wsize;
pageaddr += m->page_size) {
RETURN_IF_CANCEL();
/* check whether this page must be written to */
@@ -968,7 +968,7 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
page_tainted = 0;
flush_page = 0;
- for (i=0; i<wsize; i++) {
+ for (i = 0; i < (unsigned)wsize; i++) {
RETURN_IF_CANCEL();
data = m->buf[i];
report_progress(i, wsize, NULL);
diff --git a/src/avrdude/avr910.c b/src/avrdude/avr910.c
index aa5cc07a9..17a4ab69f 100644
--- a/src/avrdude/avr910.c
+++ b/src/avrdude/avr910.c
@@ -676,7 +676,7 @@ static int avr910_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
avr910_set_addr(pgm, addr / rd_size);
while (addr < max_addr) {
- if ((max_addr - addr) < blocksize) {
+ if ((max_addr - addr) < (unsigned)blocksize) {
blocksize = max_addr - addr;
}
cmd[1] = (blocksize >> 8) & 0xff;
diff --git a/src/avrdude/avrdude-slic3r.conf.h b/src/avrdude/avrdude-slic3r.conf.h
index 7cc901336..905b14ee8 100644
--- a/src/avrdude/avrdude-slic3r.conf.h
+++ b/src/avrdude/avrdude-slic3r.conf.h
@@ -1,5 +1,5 @@
/* WARN: This file is auto-generated from `avrdude-slic3r.conf` */
-unsigned char avrdude_slic3r_conf[] = {
+const unsigned char avrdude_slic3r_conf[] = {
0x0a, 0x23, 0x0a, 0x23, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
0x20, 0x61, 0x20, 0x62, 0x61, 0x73, 0x69, 0x63, 0x20, 0x6d, 0x69, 0x6e,
0x69, 0x6d, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20,
@@ -1184,5 +1184,5 @@ unsigned char avrdude_slic3r_conf[] = {
0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x0a,
0, 0
};
-size_t avrdude_slic3r_conf_size = 14178;
-size_t avrdude_slic3r_conf_size_yy = 14180;
+const size_t avrdude_slic3r_conf_size = 14178;
+const size_t avrdude_slic3r_conf_size_yy = 14180;
diff --git a/src/avrdude/avrdude-slic3r.cpp b/src/avrdude/avrdude-slic3r.cpp
index 0140d93ed..7eff436e2 100644
--- a/src/avrdude/avrdude-slic3r.cpp
+++ b/src/avrdude/avrdude-slic3r.cpp
@@ -93,7 +93,7 @@ void AvrDude::priv::unset_handlers()
int AvrDude::priv::run_one(const std::vector<std::string> &args) {
- std::vector<char*> c_args {{ const_cast<char*>(PACKAGE) }};
+ std::vector<char*> c_args { const_cast<char*>(PACKAGE) };
std::string command_line { PACKAGE };
for (const auto &arg : args) {
@@ -105,7 +105,7 @@ int AvrDude::priv::run_one(const std::vector<std::string> &args) {
HandlerGuard guard(*this);
- message_fn(command_line.c_str(), command_line.size());
+ message_fn(command_line.c_str(), (unsigned)command_line.size());
const auto res = ::avrdude_main(static_cast<int>(c_args.size()), c_args.data());
@@ -200,7 +200,7 @@ AvrDude::Ptr AvrDude::run()
auto &message_fn = self->p->message_fn;
if (message_fn) {
message_fn(msg, sizeof(msg));
- message_fn(what, std::strlen(what));
+ message_fn(what, (unsigned)std::strlen(what));
message_fn("\n", 1);
}
diff --git a/src/avrdude/avrdude.h b/src/avrdude/avrdude.h
index ff464f46f..bc784cec6 100644
--- a/src/avrdude/avrdude.h
+++ b/src/avrdude/avrdude.h
@@ -64,6 +64,8 @@ int avrdude_main(int argc, char * argv []);
#include <windows.h>
#include <unistd.h>
+#define strdup _strdup
+
#ifdef UNICODE
#error "UNICODE should not be defined for avrdude bits on Windows"
#endif
diff --git a/src/avrdude/avrpart.c b/src/avrdude/avrpart.c
index d0bb951ee..1c7d6af00 100644
--- a/src/avrdude/avrpart.c
+++ b/src/avrdude/avrpart.c
@@ -358,7 +358,7 @@ AVRMEM * avr_locate_mem(AVRPART * p, char * desc)
int matches;
int l;
- l = strlen(desc);
+ l = (int)strlen(desc);
matches = 0;
match = NULL;
for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
@@ -662,7 +662,7 @@ void avr_display(FILE * f, AVRPART * p, const char * prefix, int verbose)
prefix);
px = prefix;
- i = strlen(prefix) + 5;
+ i = (int)strlen(prefix) + 5;
buf = (char *)malloc(i);
if (buf == NULL) {
/* ugh, this is not important enough to bail, just ignore it */
diff --git a/src/avrdude/buspirate.c b/src/avrdude/buspirate.c
index 5875d4283..dc8c68fbe 100644
--- a/src/avrdude/buspirate.c
+++ b/src/avrdude/buspirate.c
@@ -128,7 +128,7 @@ static int buspirate_recv_bin(struct programmer_t *pgm, unsigned char *buf, size
avrdude_message(MSG_DEBUG, "%s: buspirate_recv_bin():\n", progname);
dump_mem(MSG_DEBUG, buf, len);
- return len;
+ return (int)len;
}
static int buspirate_expect_bin(struct programmer_t *pgm,
@@ -249,7 +249,7 @@ static int buspirate_send(struct programmer_t *pgm, const char *str)
static int buspirate_is_prompt(const char *str)
{
- int strlen_str = strlen(str);
+ int strlen_str = (int)strlen(str);
/* Prompt ends with '>' or '> '
* all other input probably ends with '\n' */
return (str[strlen_str - 1] == '>' || str[strlen_str - 2] == '>');
diff --git a/src/avrdude/butterfly.c b/src/avrdude/butterfly.c
index beb5e04de..8f582e72a 100644
--- a/src/avrdude/butterfly.c
+++ b/src/avrdude/butterfly.c
@@ -675,7 +675,7 @@ static int butterfly_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
butterfly_set_addr(pgm, addr / rd_size);
}
while (addr < max_addr) {
- if ((max_addr - addr) < blocksize) {
+ if ((max_addr - addr) < (unsigned)blocksize) {
blocksize = max_addr - addr;
};
cmd[1] = (blocksize >> 8) & 0xff;
diff --git a/src/avrdude/conf-generate.cpp b/src/avrdude/conf-generate.cpp
index f2761ba22..4aa80ae0a 100644
--- a/src/avrdude/conf-generate.cpp
+++ b/src/avrdude/conf-generate.cpp
@@ -21,7 +21,7 @@ int main(int argc, char const *argv[])
}
std::cout << "/* WARN: This file is auto-generated from `" << filename << "` */" << std::endl;
- std::cout << "unsigned char " << symbol << "[] = {";
+ std::cout << "const unsigned char " << symbol << "[] = {";
char c;
std::cout << std::hex;
@@ -34,8 +34,8 @@ int main(int argc, char const *argv[])
std::cout << "\n 0, 0\n};\n";
std::cout << std::dec;
- std::cout << "size_t " << symbol << "_size = " << size << ";" << std::endl;
- std::cout << "size_t " << symbol << "_size_yy = " << size + 2 << ";" << std::endl;
+ std::cout << "const size_t " << symbol << "_size = " << size << ";" << std::endl;
+ std::cout << "const size_t " << symbol << "_size_yy = " << size + 2 << ";" << std::endl;
return 0;
}
diff --git a/src/avrdude/config.c b/src/avrdude/config.c
index 1c0ff5525..b82fb29cb 100644
--- a/src/avrdude/config.c
+++ b/src/avrdude/config.c
@@ -240,7 +240,7 @@ TOKEN * string(char * text)
return NULL; /* yyerror already called */
}
- len = strlen(text);
+ len = (int)strlen(text);
tkn->value.type = V_STR;
tkn->value.string = (char *) malloc(len+1);
@@ -351,7 +351,7 @@ int read_config(const char * file)
}
typedef struct yy_buffer_state *YY_BUFFER_STATE;
-extern YY_BUFFER_STATE yy_scan_bytes(char *base, size_t size);
+extern YY_BUFFER_STATE yy_scan_bytes(const char *base, size_t size);
extern void yy_delete_buffer(YY_BUFFER_STATE b);
int read_config_builtin()
@@ -363,7 +363,7 @@ int read_config_builtin()
// Note: Can't use yy_scan_buffer, it's buggy (?), leads to fread from a null FILE*
// and so unfortunatelly we have to use the copying variant here
- YY_BUFFER_STATE buffer = yy_scan_bytes(avrdude_slic3r_conf, avrdude_slic3r_conf_size);
+ YY_BUFFER_STATE buffer = yy_scan_bytes((const char *)avrdude_slic3r_conf, avrdude_slic3r_conf_size);
if (buffer == NULL) {
avrdude_message(MSG_INFO, "%s: read_config_builtin: Failed to initialize parsing buffer\n", progname);
return -1;
diff --git a/src/avrdude/config_gram.c b/src/avrdude/config_gram.c
index c1a65b13e..2d32fe739 100644
--- a/src/avrdude/config_gram.c
+++ b/src/avrdude/config_gram.c
@@ -3640,7 +3640,7 @@ static int parse_cmdbits(OPCODE * op)
break;
}
- len = strlen(s);
+ len = (int)strlen(s);
if (len == 0) {
yyerror("invalid bit specifier \"\"");
diff --git a/src/avrdude/config_gram.y b/src/avrdude/config_gram.y
index 0aa95a8e8..6a062352b 100644
--- a/src/avrdude/config_gram.y
+++ b/src/avrdude/config_gram.y
@@ -1493,7 +1493,7 @@ static int parse_cmdbits(OPCODE * op)
break;
}
- len = strlen(s);
+ len = (int)strlen(s);
if (len == 0) {
yyerror("invalid bit specifier \"\"");
diff --git a/src/avrdude/fileio.c b/src/avrdude/fileio.c
index 7803497a0..7f4c8edee 100644
--- a/src/avrdude/fileio.c
+++ b/src/avrdude/fileio.c
@@ -264,7 +264,7 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
unsigned char cksum;
int rc;
- len = strlen(rec);
+ len = (int)strlen(rec);
offset = 1;
cksum = 0;
@@ -274,7 +274,7 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
for (i=0; i<2; i++)
buf[i] = rec[offset++];
buf[i] = 0;
- ihex->reclen = strtoul(buf, &e, 16);
+ ihex->reclen = (unsigned char)strtoul(buf, &e, 16);
if (e == buf || *e != 0)
return -1;
@@ -294,7 +294,7 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
for (i=0; i<2; i++)
buf[i] = rec[offset++];
buf[i] = 0;
- ihex->rectyp = strtoul(buf, &e, 16);
+ ihex->rectyp = (unsigned char)strtoul(buf, &e, 16);
if (e == buf || *e != 0)
return -1;
@@ -308,7 +308,7 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
for (i=0; i<2; i++)
buf[i] = rec[offset++];
buf[i] = 0;
- ihex->data[j] = strtoul(buf, &e, 16);
+ ihex->data[j] = (char)strtoul(buf, &e, 16);
if (e == buf || *e != 0)
return -1;
cksum += ihex->data[j];
@@ -320,7 +320,7 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
for (i=0; i<2; i++)
buf[i] = rec[offset++];
buf[i] = 0;
- ihex->cksum = strtoul(buf, &e, 16);
+ ihex->cksum = (char)strtoul(buf, &e, 16);
if (e == buf || *e != 0)
return -1;
@@ -361,7 +361,7 @@ static int ihex2b(char * infile, FILE * inf,
while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) {
lineno++;
- len = strlen(buffer);
+ len = (int)strlen(buffer);
if (buffer[len-1] == '\n')
buffer[--len] = 0;
if (buffer[0] != ':')
@@ -388,7 +388,7 @@ static int ihex2b(char * infile, FILE * inf,
return -1;
}
nextaddr = ihex.loadofs + baseaddr - fileoffset;
- if (nextaddr + ihex.reclen > bufsize) {
+ if (nextaddr + ihex.reclen > (unsigned)bufsize) {
avrdude_message(MSG_INFO, "%s: ERROR: address 0x%04x out of range at line %d of %s\n",
progname, nextaddr+ihex.reclen, lineno, infile);
return -1;
@@ -502,10 +502,11 @@ static int b2srec(unsigned char * inbuf, int bufsize,
cksum += n + addr_width + 1;
- for (i=addr_width; i>0; i--)
+ for (i = addr_width; i>0; i--) {
cksum += (nextaddr >> (i-1) * 8) & 0xff;
+ }
- for (i=nextaddr; i<nextaddr + n; i++) {
+ for (unsigned i = nextaddr; i < nextaddr + n; i++) {
fprintf(outf, "%02X", buf[i]);
cksum += buf[i];
}
@@ -562,7 +563,7 @@ static int srec_readrec(struct ihexrec * srec, char * rec)
unsigned char cksum;
int rc;
- len = strlen(rec);
+ len = (int)strlen(rec);
offset = 1;
cksum = 0;
addr_width = 2;
@@ -582,7 +583,7 @@ static int srec_readrec(struct ihexrec * srec, char * rec)
for (i=0; i<2; i++)
buf[i] = rec[offset++];
buf[i] = 0;
- srec->reclen = strtoul(buf, &e, 16);
+ srec->reclen = (char)strtoul(buf, &e, 16);
cksum += srec->reclen;
srec->reclen -= (addr_width+1);
if (e == buf || *e != 0)
@@ -594,7 +595,7 @@ static int srec_readrec(struct ihexrec * srec, char * rec)
for (i=0; i<addr_width*2; i++)
buf[i] = rec[offset++];
buf[i] = 0;
- srec->loadofs = strtoull(buf, &e, 16);
+ srec->loadofs = strtoul(buf, &e, 16);
if (e == buf || *e != 0)
return -1;
@@ -608,7 +609,7 @@ static int srec_readrec(struct ihexrec * srec, char * rec)
for (i=0; i<2; i++)
buf[i] = rec[offset++];
buf[i] = 0;
- srec->data[j] = strtoul(buf, &e, 16);
+ srec->data[j] = (char)strtoul(buf, &e, 16);
if (e == buf || *e != 0)
return -1;
cksum += srec->data[j];
@@ -620,7 +621,7 @@ static int srec_readrec(struct ihexrec * srec, char * rec)
for (i=0; i<2; i++)
buf[i] = rec[offset++];
buf[i] = 0;
- srec->cksum = strtoul(buf, &e, 16);
+ srec->cksum = (char)strtoul(buf, &e, 16);
if (e == buf || *e != 0)
return -1;
@@ -650,7 +651,7 @@ static int srec2b(char * infile, FILE * inf,
while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) {
lineno++;
- len = strlen(buffer);
+ len = (int)strlen(buffer);
if (buffer[len-1] == '\n')
buffer[--len] = 0;
if (buffer[0] != 0x53)
@@ -729,7 +730,7 @@ static int srec2b(char * infile, FILE * inf,
return -1;
}
nextaddr -= fileoffset;
- if (nextaddr + srec.reclen > bufsize) {
+ if (nextaddr + srec.reclen > (unsigned)bufsize) {
avrdude_message(MSG_INFO, msg, progname, nextaddr+srec.reclen, "",
lineno, infile);
return -1;
@@ -740,7 +741,7 @@ static int srec2b(char * infile, FILE * inf,
}
if (nextaddr+srec.reclen > maxaddr)
maxaddr = nextaddr+srec.reclen;
- reccount++;
+ reccount++;
}
}
@@ -1143,12 +1144,12 @@ static int fileio_rbin(struct fioparms * fio,
switch (fio->op) {
case FIO_READ:
- rc = fread(buf, 1, size, f);
+ rc = (int)fread(buf, 1, size, f);
if (rc > 0)
memset(mem->tags, TAG_ALLOCATED, rc);
break;
case FIO_WRITE:
- rc = fwrite(buf, 1, size, f);
+ rc = (int)fwrite(buf, 1, size, f);
break;
default:
avrdude_message(MSG_INFO, "%s: fileio: invalid operation=%d\n",
@@ -1190,7 +1191,7 @@ static int fileio_imm(struct fioparms * fio,
progname, p);
return -1;
}
- mem->buf[loc] = b;
+ mem->buf[loc] = (char)b;
mem->tags[loc++] = TAG_ALLOCATED;
p = strtok(NULL, " ,");
rc = loc;
@@ -1452,7 +1453,7 @@ static int fmt_autodetect(char * fname, unsigned section)
}
buf[MAX_LINE_LEN-1] = 0;
- len = strlen((char *)buf);
+ len = (int)strlen((char *)buf);
if (buf[len-1] == '\n')
buf[--len] = 0;
diff --git a/src/avrdude/lists.c b/src/avrdude/lists.c
index cab88364e..063507ed3 100644
--- a/src/avrdude/lists.c
+++ b/src/avrdude/lists.c
@@ -444,7 +444,7 @@ lcreat ( void * liststruct, int elements )
l->poolsize = DEFAULT_POOLSIZE;
}
else {
- l->poolsize = elements*sizeof(LISTNODE)+sizeof(NODEPOOL);
+ l->poolsize = (short)(elements*sizeof(LISTNODE)+sizeof(NODEPOOL));
}
l->n_ln_pool = (l->poolsize-sizeof(NODEPOOL))/sizeof(LISTNODE);
@@ -803,7 +803,7 @@ lget_n ( LISTID lid, unsigned int n )
CKLMAGIC(l);
- if ((n<1)||(n>lsize(l))) {
+ if ((n < 1) || (n > (unsigned)lsize(l))) {
return NULL;
}
@@ -844,7 +844,7 @@ lget_ln ( LISTID lid, unsigned int n )
CKLMAGIC(l);
- if ((n<1)||(n>lsize(l))) {
+ if ((n < 1) || (n > (unsigned)lsize(l))) {
return NULL;
}
@@ -941,7 +941,7 @@ insert_ln ( LIST * l, LISTNODE * ln, void * data_ptr )
|
| Insert data before the nth item in the list.
-----------------------------------------------------------------*/
-int
+int
lins_n ( LISTID lid, void * data_ptr, unsigned int n )
{
int i;
@@ -952,7 +952,7 @@ lins_n ( LISTID lid, void * data_ptr, unsigned int n )
CKLMAGIC(l);
- if ((n<1)||(n>(l->num+1))) {
+ if ((n < 1) || (n > (unsigned)(l->num+1))) {
return -1;
}
@@ -1193,7 +1193,7 @@ lrmv_n ( LISTID lid, unsigned int n )
CKLMAGIC(l);
- if ((n<1)||(n>l->num)) {
+ if ((n < 1) || (n > (unsigned)l->num)) {
return NULL;
}
diff --git a/src/avrdude/main.c b/src/avrdude/main.c
index 8f9040349..60be7ec3a 100644
--- a/src/avrdude/main.c
+++ b/src/avrdude/main.c
@@ -107,7 +107,7 @@ int avrdude_message(const int msglvl, const char *format, ...)
if (rc > 0 && rc < MSGBUFFER_SIZE) {
avrdude_message_handler(msgbuffer, rc, avrdude_message_handler_user_p);
} else {
- avrdude_message_handler(format_error, strlen(format_error), avrdude_message_handler_user_p);
+ avrdude_message_handler(format_error, (unsigned)strlen(format_error), avrdude_message_handler_user_p);
}
}
@@ -567,7 +567,7 @@ int avrdude_main(int argc, char * argv [])
// #endif
- len = strlen(progname) + 2;
+ len = (int)strlen(progname) + 2;
for (i=0; i<len; i++)
progbuf[i] = ' ';
progbuf[i] = 0;
@@ -601,7 +601,7 @@ int avrdude_main(int argc, char * argv [])
bitclock = strtod(optarg, &e);
if (*e != 0) {
/* trailing unit of measure present */
- int suffixlen = strlen(e);
+ size_t suffixlen = strlen(e);
switch (suffixlen) {
case 2:
if ((e[0] != 'h' && e[0] != 'H') || e[1] != 'z')
diff --git a/src/avrdude/pindefs.c b/src/avrdude/pindefs.c
index 5753fc67b..d89f4828b 100644
--- a/src/avrdude/pindefs.c
+++ b/src/avrdude/pindefs.c
@@ -217,7 +217,7 @@ const char * pinmask_to_str(const pinmask_t * const pinmask) {
* @param[in] size the number of entries in checklist
* @returns 0 if all pin definitions are valid, -1 otherwise
*/
-int pins_check(const struct programmer_t * const pgm, const struct pin_checklist_t * const checklist, const int size, bool output) {
+int pins_check(const struct programmer_t *const pgm, const struct pin_checklist_t *const checklist, const int size, const bool output) {
static const struct pindef_t no_valid_pins = {{0}, {0}}; // default value if check list does not contain anything else
int rv = 0; // return value
int pinname; // loop counter through pinnames
diff --git a/src/avrdude/ser_win32.c b/src/avrdude/ser_win32.c
index 8efca0397..6b8a18f8f 100644
--- a/src/avrdude/ser_win32.c
+++ b/src/avrdude/ser_win32.c
@@ -292,7 +292,7 @@ static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp)
if (hComPort == INVALID_HANDLE_VALUE) {
const char *error = last_error_string(0);
avrdude_message(MSG_INFO, "%s: ser_open(): can't open device \"%s\": %s\n", progname, port, error);
- free(error);
+ free((char *)error);
return -1;
}
@@ -460,10 +460,10 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t
serial_w32SetTimeOut(hComPort,500);
- if (!WriteFile(hComPort, buf, buflen, &written, NULL)) {
+ if (!WriteFile(hComPort, buf, (DWORD)buflen, &written, NULL)) {
const char *error = last_error_string(0);
avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n", progname, error);
- free(error);
+ free((char *)error);
return -1;
}
@@ -576,10 +576,10 @@ static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen
serial_w32SetTimeOut(hComPort, serial_recv_timeout);
- if (!ReadFile(hComPort, buf, buflen, &read, NULL)) {
+ if (!ReadFile(hComPort, buf, (DWORD)buflen, &read, NULL)) {
const char *error = last_error_string(0);
avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, error);
- free(error);
+ free((char *)error);
return -1;
}
@@ -642,7 +642,7 @@ static int ser_drain(union filedescriptor *fd, int display)
if (!readres) {
const char *error = last_error_string(0);
avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", progname, error);
- free(error);
+ free((char *)error);
return -1;
}
diff --git a/src/avrdude/serbb_win32.c b/src/avrdude/serbb_win32.c
index 4f1069c85..76db6ce3f 100644
--- a/src/avrdude/serbb_win32.c
+++ b/src/avrdude/serbb_win32.c
@@ -308,8 +308,8 @@ static int serbb_open(PROGRAMMER *pgm, char *port)
progname, port);
return -1;
}
- avrdude_message(MSG_DEBUG, "%s: ser_open(): opened comm port \"%s\", handle 0x%x\n",
- progname, port, (int)hComPort);
+ avrdude_message(MSG_DEBUG, "%s: ser_open(): opened comm port \"%s\", handle %p\n",
+ progname, port, (void *)hComPort);
pgm->fd.pfd = (void *)hComPort;
@@ -326,8 +326,8 @@ static void serbb_close(PROGRAMMER *pgm)
pgm->setpin(pgm, PIN_AVR_RESET, 1);
CloseHandle (hComPort);
}
- avrdude_message(MSG_DEBUG, "%s: ser_close(): closed comm port handle 0x%x\n",
- progname, (int)hComPort);
+ avrdude_message(MSG_DEBUG, "%s: ser_close(): closed comm port handle %p\n",
+ progname, (void *)hComPort);
hComPort = INVALID_HANDLE_VALUE;
}
diff --git a/src/avrdude/stk500.c b/src/avrdude/stk500.c
index efb7078bc..256076cc6 100644
--- a/src/avrdude/stk500.c
+++ b/src/avrdude/stk500.c
@@ -504,7 +504,7 @@ static int stk500_initialize(PROGRAMMER * pgm, AVRPART * p)
}
else {
buf[9] = 0xff;
- buf[10] = 0xff;
+ buf[10] = 0xff;
buf[13] = 0;
buf[14] = 0;
buf[17] = 0;
@@ -821,7 +821,7 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
break;
}
- for (prusa3d_semicolon_workaround_round = 0; prusa3d_semicolon_workaround_round < (has_semicolon ? 2 : 1); ++ prusa3d_semicolon_workaround_round) {
+ for (prusa3d_semicolon_workaround_round = 0; prusa3d_semicolon_workaround_round < (has_semicolon ? 2u : 1u); prusa3d_semicolon_workaround_round++) {
/* build command block and avoid multiple send commands as it leads to a crash
of the silabs usb serial driver on mac os x */
i = 0;
@@ -834,7 +834,7 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
buf[i++] = block_size & 0x0f;
buf[i++] = memtype;
if (has_semicolon) {
- for (j = 0; j < block_size; ++i, ++ j) {
+ for (j = 0; j < (unsigned)block_size; ++i, ++ j) {
buf[i] = m->buf[addr + j];
if (buf[i] == ';')
buf[i] |= (prusa3d_semicolon_workaround_round ? 0xf0 : 0x0f);
@@ -1088,8 +1088,8 @@ static int stk500_set_sck_period(PROGRAMMER * pgm, double v)
min = 8.0 / STK500_XTAL;
max = 255 * min;
- dur = v / min + 0.5;
-
+ dur = (int)(v / min + 0.5);
+
if (v < min) {
dur = 1;
avrdude_message(MSG_INFO, "%s: stk500_set_sck_period(): p = %.1f us too small, using %.1f us\n",
@@ -1099,7 +1099,7 @@ static int stk500_set_sck_period(PROGRAMMER * pgm, double v)
avrdude_message(MSG_INFO, "%s: stk500_set_sck_period(): p = %.1f us too large, using %.1f us\n",
progname, v / 1e-6, dur * min / 1e-6);
}
-
+
return stk500_setparm(pgm, Parm_STK_SCK_DURATION, dur);
}
diff --git a/src/avrdude/stk500v2.c b/src/avrdude/stk500v2.c
index 9bc629ba4..33bdf8eea 100644
--- a/src/avrdude/stk500v2.c
+++ b/src/avrdude/stk500v2.c
@@ -130,58 +130,58 @@ struct jtagispentry
#define SZ_SPI_MULTI (USHRT_MAX - 1)
};
-static const struct jtagispentry jtagispcmds[] = {
- /* generic */
- { CMD_SET_PARAMETER, 2 },
- { CMD_GET_PARAMETER, 3 },
- { CMD_OSCCAL, 2 },
- { CMD_LOAD_ADDRESS, 2 },
- /* ISP mode */
- { CMD_ENTER_PROGMODE_ISP, 2 },
- { CMD_LEAVE_PROGMODE_ISP, 2 },
- { CMD_CHIP_ERASE_ISP, 2 },
- { CMD_PROGRAM_FLASH_ISP, 2 },
- { CMD_READ_FLASH_ISP, SZ_READ_FLASH_EE },
- { CMD_PROGRAM_EEPROM_ISP, 2 },
- { CMD_READ_EEPROM_ISP, SZ_READ_FLASH_EE },
- { CMD_PROGRAM_FUSE_ISP, 3 },
- { CMD_READ_FUSE_ISP, 4 },
- { CMD_PROGRAM_LOCK_ISP, 3 },
- { CMD_READ_LOCK_ISP, 4 },
- { CMD_READ_SIGNATURE_ISP, 4 },
- { CMD_READ_OSCCAL_ISP, 4 },
- { CMD_SPI_MULTI, SZ_SPI_MULTI },
- /* all HV modes */
- { CMD_SET_CONTROL_STACK, 2 },
- /* HVSP mode */
- { CMD_ENTER_PROGMODE_HVSP, 2 },
- { CMD_LEAVE_PROGMODE_HVSP, 2 },
- { CMD_CHIP_ERASE_HVSP, 2 },
- { CMD_PROGRAM_FLASH_HVSP, 2 },
- { CMD_READ_FLASH_HVSP, SZ_READ_FLASH_EE },
- { CMD_PROGRAM_EEPROM_HVSP, 2 },
- { CMD_READ_EEPROM_HVSP, SZ_READ_FLASH_EE },
- { CMD_PROGRAM_FUSE_HVSP, 2 },
- { CMD_READ_FUSE_HVSP, 3 },
- { CMD_PROGRAM_LOCK_HVSP, 2 },
- { CMD_READ_LOCK_HVSP, 3 },
- { CMD_READ_SIGNATURE_HVSP, 3 },
- { CMD_READ_OSCCAL_HVSP, 3 },
- /* PP mode */
- { CMD_ENTER_PROGMODE_PP, 2 },
- { CMD_LEAVE_PROGMODE_PP, 2 },
- { CMD_CHIP_ERASE_PP, 2 },
- { CMD_PROGRAM_FLASH_PP, 2 },
- { CMD_READ_FLASH_PP, SZ_READ_FLASH_EE },
- { CMD_PROGRAM_EEPROM_PP, 2 },
- { CMD_READ_EEPROM_PP, SZ_READ_FLASH_EE },
- { CMD_PROGRAM_FUSE_PP, 2 },
- { CMD_READ_FUSE_PP, 3 },
- { CMD_PROGRAM_LOCK_PP, 2 },
- { CMD_READ_LOCK_PP, 3 },
- { CMD_READ_SIGNATURE_PP, 3 },
- { CMD_READ_OSCCAL_PP, 3 },
-};
+// static const struct jtagispentry jtagispcmds[] = {
+// /* generic */
+// { CMD_SET_PARAMETER, 2 },
+// { CMD_GET_PARAMETER, 3 },
+// { CMD_OSCCAL, 2 },
+// { CMD_LOAD_ADDRESS, 2 },
+// /* ISP mode */
+// { CMD_ENTER_PROGMODE_ISP, 2 },
+// { CMD_LEAVE_PROGMODE_ISP, 2 },
+// { CMD_CHIP_ERASE_ISP, 2 },
+// { CMD_PROGRAM_FLASH_ISP, 2 },
+// { CMD_READ_FLASH_ISP, SZ_READ_FLASH_EE },
+// { CMD_PROGRAM_EEPROM_ISP, 2 },
+// { CMD_READ_EEPROM_ISP, SZ_READ_FLASH_EE },
+// { CMD_PROGRAM_FUSE_ISP, 3 },
+// { CMD_READ_FUSE_ISP, 4 },
+// { CMD_PROGRAM_LOCK_ISP, 3 },
+// { CMD_READ_LOCK_ISP, 4 },
+// { CMD_READ_SIGNATURE_ISP, 4 },
+// { CMD_READ_OSCCAL_ISP, 4 },
+// { CMD_SPI_MULTI, SZ_SPI_MULTI },
+// /* all HV modes */
+// { CMD_SET_CONTROL_STACK, 2 },
+// /* HVSP mode */
+// { CMD_ENTER_PROGMODE_HVSP, 2 },
+// { CMD_LEAVE_PROGMODE_HVSP, 2 },
+// { CMD_CHIP_ERASE_HVSP, 2 },
+// { CMD_PROGRAM_FLASH_HVSP, 2 },
+// { CMD_READ_FLASH_HVSP, SZ_READ_FLASH_EE },
+// { CMD_PROGRAM_EEPROM_HVSP, 2 },
+// { CMD_READ_EEPROM_HVSP, SZ_READ_FLASH_EE },
+// { CMD_PROGRAM_FUSE_HVSP, 2 },
+// { CMD_READ_FUSE_HVSP, 3 },
+// { CMD_PROGRAM_LOCK_HVSP, 2 },
+// { CMD_READ_LOCK_HVSP, 3 },
+// { CMD_READ_SIGNATURE_HVSP, 3 },
+// { CMD_READ_OSCCAL_HVSP, 3 },
+// /* PP mode */
+// { CMD_ENTER_PROGMODE_PP, 2 },
+// { CMD_LEAVE_PROGMODE_PP, 2 },
+// { CMD_CHIP_ERASE_PP, 2 },
+// { CMD_PROGRAM_FLASH_PP, 2 },
+// { CMD_READ_FLASH_PP, SZ_READ_FLASH_EE },
+// { CMD_PROGRAM_EEPROM_PP, 2 },
+// { CMD_READ_EEPROM_PP, SZ_READ_FLASH_EE },
+// { CMD_PROGRAM_FUSE_PP, 2 },
+// { CMD_READ_FUSE_PP, 3 },
+// { CMD_PROGRAM_LOCK_PP, 2 },
+// { CMD_READ_LOCK_PP, 3 },
+// { CMD_READ_SIGNATURE_PP, 3 },
+// { CMD_READ_OSCCAL_PP, 3 },
+// };
/*
* From XML file:
@@ -379,15 +379,15 @@ static void stk500v2_jtag3_teardown(PROGRAMMER * pgm)
}
-static unsigned short
-b2_to_u16(unsigned char *b)
-{
- unsigned short l;
- l = b[0];
- l += (unsigned)b[1] << 8;
+// static unsigned short
+// b2_to_u16(unsigned char *b)
+// {
+// unsigned short l;
+// l = b[0];
+// l += (unsigned)b[1] << 8;
- return l;
-}
+// return l;
+// }
static int stk500v2_send_mk2(PROGRAMMER * pgm, unsigned char * data, size_t len)
{
@@ -399,16 +399,16 @@ static int stk500v2_send_mk2(PROGRAMMER * pgm, unsigned char * data, size_t len)
return 0;
}
-static unsigned short get_jtagisp_return_size(unsigned char cmd)
-{
- int i;
+// static unsigned short get_jtagisp_return_size(unsigned char cmd)
+// {
+// int i;
- for (i = 0; i < sizeof jtagispcmds / sizeof jtagispcmds[0]; i++)
- if (jtagispcmds[i].cmd == cmd)
- return jtagispcmds[i].size;
+// for (i = 0; i < sizeof jtagispcmds / sizeof jtagispcmds[0]; i++)
+// if (jtagispcmds[i].cmd == cmd)
+// return jtagispcmds[i].size;
- return 0;
-}
+// return 0;
+// }
/*
* Send the data as a JTAG ICE mkII encapsulated ISP packet.
@@ -504,7 +504,7 @@ static int stk500v2_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
buf[0] = MESSAGE_START;
buf[1] = PDATA(pgm)->command_sequence;
- buf[2] = len / 256;
+ buf[2] = (char)(len / 256);
buf[3] = len % 256;
buf[4] = TOKEN;
memcpy(buf+5, data, len);
@@ -1128,7 +1128,8 @@ static int stk500v2_program_enable(PROGRAMMER * pgm, AVRPART * p)
{
unsigned char buf[16];
char msg[100]; /* see remarks above about size needed */
- int rv, tries;
+ int rv;
+ // int tries;
PDATA(pgm)->lastpart = p;
@@ -1143,7 +1144,7 @@ static int stk500v2_program_enable(PROGRAMMER * pgm, AVRPART * p)
/* Activate AVR-style (low active) RESET */
stk500v2_setparm_real(pgm, PARAM_RESET_POLARITY, 0x01);
- tries = 0;
+ // tries = 0;
// retry:
buf[0] = CMD_ENTER_PROGMODE_ISP;
buf[1] = p->timeout;
@@ -1882,7 +1883,7 @@ static int stk500hv_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
if (stk500v2_loadaddr(pgm, use_ext_addr | (paddr >> addrshift)) < 0)
return -1;
} else {
- buf[1] = addr;
+ buf[1] = (char)addr;
}
avrdude_message(MSG_NOTICE2, "%s: stk500hv_read_byte(): Sending read memory command: ",
@@ -2137,7 +2138,7 @@ static int stk500hv_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
if (stk500v2_loadaddr(pgm, use_ext_addr | (paddr >> addrshift)) < 0)
return -1;
} else {
- buf[1] = addr;
+ buf[1] = (char)addr;
buf[2] = data;
if (mode == PPMODE) {
buf[3] = pulsewidth;
@@ -2298,7 +2299,7 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
unsigned int page_size,
unsigned int addr, unsigned int n_bytes)
{
-static int page = 0;
+// static int page = 0;
unsigned int block_size, last_addr, addrshift, use_ext_addr;
unsigned int maxaddr = addr + n_bytes;
unsigned char commandbuf[10];
@@ -2833,10 +2834,10 @@ static int stk500v2_set_fosc(PROGRAMMER * pgm, double v)
progname, v, unit, STK500V2_XTAL / 2e6);
fosc = STK500V2_XTAL / 2;
} else
- fosc = (unsigned)v;
+ fosc = (int)v;
for (idx = 0; idx < sizeof(ps) / sizeof(ps[0]); idx++) {
- if (fosc >= STK500V2_XTAL / (256 * ps[idx] * 2)) {
+ if (fosc >= (int)(STK500V2_XTAL / (256 * ps[idx] * 2))) {
/* this prescaler value can handle our frequency */
prescale = idx + 1;
cmatch = (unsigned)(STK500V2_XTAL / (2 * fosc * ps[idx])) - 1;
@@ -3065,8 +3066,8 @@ static int stk600_set_fosc(PROGRAMMER * pgm, double v)
{
unsigned int oct, dac;
- oct = 1.443 * log(v / 1039.0);
- dac = 2048 - (2078.0 * pow(2, (double)(10 + oct))) / v;
+ oct = (unsigned)(1.443 * log(v / 1039.0));
+ dac = (unsigned)(2048.0 - (2078.0 * pow(2, (double)(10 + oct))) / v);
return stk500v2_setparm2(pgm, PARAM2_CLOCK_CONF, (oct << 12) | (dac << 2));
}
@@ -3075,7 +3076,7 @@ static int stk600_set_sck_period(PROGRAMMER * pgm, double v)
{
unsigned int sck;
- sck = ceil((16e6 / (2 * 1.0 / v)) - 1);
+ sck = (unsigned)ceil((16e6 / (2 * 1.0 / v)) - 1);
if (sck >= 4096)
sck = 4095;
@@ -3093,7 +3094,7 @@ static int stk500v2_jtag3_set_sck_period(PROGRAMMER * pgm, double v)
else if (v > 1E-3)
sck = 1;
else
- sck = 1.0 / (1000.0 * v);
+ sck = (unsigned)(1.0 / (1000.0 * v));
value[0] = CMD_SET_SCK;
value[1] = sck & 0xff;
@@ -3143,7 +3144,7 @@ static int stk500v2_setparm_real(PROGRAMMER * pgm, unsigned char parm, unsigned
static int stk500v2_setparm(PROGRAMMER * pgm, unsigned char parm, unsigned char value)
{
- unsigned char current_value;
+ unsigned char current_value = 0;
int res;
res = stk500v2_getparm(pgm, parm, &current_value);
@@ -3214,8 +3215,15 @@ static const char *stk600_get_cardname(const struct carddata *table,
static void stk500v2_display(PROGRAMMER * pgm, const char * p)
{
- unsigned char maj, min, hdw, topcard, maj_s1, min_s1, maj_s2, min_s2;
- unsigned int rev;
+ unsigned char maj = 0;
+ unsigned char min = 0;
+ unsigned char hdw = 0;
+ unsigned char topcard = 0;
+ unsigned char maj_s1 = 0;
+ unsigned char min_s1 = 0;
+ unsigned char maj_s2 = 0;
+ unsigned char min_s2 = 0;
+ unsigned int rev = 0;
const char *topcard_name, *pgmname;
switch (PDATA(pgm)->pgmtype) {
@@ -3294,13 +3302,20 @@ f_to_kHz_MHz(double f, const char **unit)
static void stk500v2_print_parms1(PROGRAMMER * pgm, const char * p)
{
- unsigned char vtarget, vadjust, osc_pscale, osc_cmatch, sck_duration =0; //XXX 0 is not correct, check caller
- unsigned int sck_stk600, clock_conf, dac, oct, varef;
- unsigned char vtarget_jtag[4];
+ unsigned char vtarget = 0;
+ unsigned char vadjust = 0;
+ unsigned char sck_duration = 0;
+ unsigned char osc_pscale = 0;
+ unsigned char osc_cmatch = 0;
+ unsigned varef = 0;
+ unsigned sck_stk600 = 0;
+ unsigned clock_conf = 0;
+ unsigned dac, oct;
+ // unsigned char vtarget_jtag[4];
int prescale;
double f;
const char *unit;
- void *mycookie;
+ // void *mycookie;
if (PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE_MKII) {
return;
@@ -3963,10 +3978,10 @@ static int stk600_xprog_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
b[0] = XPRG_CMD_WRITE_MEM;
b[1] = memcode;
b[2] = 0; /* pagemode: non-paged write */
- b[3] = addr >> 24;
- b[4] = addr >> 16;
- b[5] = addr >> 8;
- b[6] = addr;
+ b[3] = (char)(addr >> 24);
+ b[4] = (char)(addr >> 16);
+ b[5] = (char)(addr >> 8);
+ b[6] = (char)addr;
b[7] = 0;
b[8] = write_size;
b[9] = data;
@@ -4011,10 +4026,10 @@ static int stk600_xprog_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
addr += mem->offset;
b[0] = XPRG_CMD_READ_MEM;
- b[2] = addr >> 24;
- b[3] = addr >> 16;
- b[4] = addr >> 8;
- b[5] = addr;
+ b[2] = (char)(addr >> 24);
+ b[3] = (char)(addr >> 16);
+ b[4] = (char)(addr >> 8);
+ b[5] = (char)addr;
b[6] = 0;
b[7] = 1;
if (stk600_xprog_command(pgm, b, 8, 3) < 0) {
diff --git a/src/avrdude/term.c b/src/avrdude/term.c
index 012f6f1a5..182367cf2 100644
--- a/src/avrdude/term.c
+++ b/src/avrdude/term.c
@@ -281,7 +281,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
maxsize = mem->size;
- if (addr >= maxsize) {
+ if (addr >= (unsigned long)maxsize) {
if (argc == 2) {
/* wrap around */
addr = 0;
@@ -294,7 +294,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
}
/* trim len if nessary to not read past the end of memory */
- if ((addr + len) > maxsize)
+ if ((addr + len) > (unsigned long)maxsize)
len = maxsize - addr;
buf = malloc(len);
@@ -303,7 +303,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
return -1;
}
- for (i=0; i<len; i++) {
+ for (i = 0; i < (unsigned long)len; i++) {
rc = pgm->read_byte(pgm, p, mem, addr+i, &buf[i]);
if (rc != 0) {
avrdude_message(MSG_INFO, "error reading %s address 0x%05lx of part %s\n",
@@ -364,7 +364,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
return -1;
}
- if (addr > maxsize) {
+ if (addr > (unsigned long)maxsize) {
avrdude_message(MSG_INFO, "%s (write): address 0x%05lx is out of range for %s memory\n",
progname, addr, memtype);
return -1;
@@ -373,7 +373,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
/* number of bytes to write at the specified address */
len = argc - 3;
- if ((addr + len) > maxsize) {
+ if ((addr + len) > (unsigned long)maxsize) {
avrdude_message(MSG_INFO, "%s (write): selected address and # bytes exceed "
"range for %s memory\n",
progname, memtype);
@@ -386,8 +386,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
return -1;
}
- for (i=3; i<argc; i++) {
- buf[i-3] = strtoul(argv[i], &e, 0);
+ for (i = 3; i < (unsigned long)argc; i++) {
+ buf[i-3] = (char)strtoul(argv[i], &e, 0);
if (*e || (e == argv[i])) {
avrdude_message(MSG_INFO, "%s (write): can't parse byte \"%s\"\n",
progname, argv[i]);
@@ -397,7 +397,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
}
pgm->err_led(pgm, OFF);
- for (werror=0, i=0; i<len; i++) {
+ for (werror = 0, i = 0; i < (unsigned long)len; i++) {
rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]);
if (rc) {
@@ -462,7 +462,7 @@ static int cmd_send(PROGRAMMER * pgm, struct avrpart * p,
/* load command bytes */
for (i=1; i<argc; i++) {
- cmd[i-1] = strtoul(argv[i], &e, 0);
+ cmd[i-1] = (char)strtoul(argv[i], &e, 0);
if (*e || (e == argv[i])) {
avrdude_message(MSG_INFO, "%s (send): can't parse byte \"%s\"\n",
progname, argv[i]);
@@ -789,7 +789,7 @@ static int tokenize(char * s, char *** argv)
char * nbuf;
char ** av;
- slen = strlen(s);
+ slen = (int)strlen(s);
/*
* initialize allow for 20 arguments, use realloc to grow this if
@@ -812,7 +812,7 @@ static int tokenize(char * s, char *** argv)
nexttok(r, &q, &r);
strcpy(nbuf, q);
bufv[n] = nbuf;
- len = strlen(q);
+ len = (int)strlen(q);
l += len + 1;
nbuf += len + 1;
nbuf[0] = 0;
@@ -841,7 +841,7 @@ static int tokenize(char * s, char *** argv)
q = (char *)&av[n+1];
memcpy(q, buf, l);
for (i=0; i<n; i++) {
- offset = bufv[i] - buf;
+ offset = (int)(bufv[i] - buf);
av[i] = q + offset;
}
av[i] = NULL;
@@ -862,7 +862,7 @@ static int do_cmd(PROGRAMMER * pgm, struct avrpart * p,
int hold;
int len;
- len = strlen(argv[0]);
+ len = (int)strlen(argv[0]);
hold = -1;
for (i=0; i<NCMDS; i++) {
if (strcasecmp(argv[0], cmd[i].name) == 0) {
diff --git a/src/libigl/CMakeLists.txt b/src/libigl/CMakeLists.txt
index 0852fad72..3daac757b 100644
--- a/src/libigl/CMakeLists.txt
+++ b/src/libigl/CMakeLists.txt
@@ -10,5 +10,5 @@ if(libigl_FOUND)
target_link_libraries(libigl INTERFACE igl::core)
else()
message(STATUS "IGL NOT found, using bundled version...")
- target_include_directories(libigl INTERFACE SYSTEM ${LIBDIR}/libigl)
+ target_include_directories(libigl SYSTEM BEFORE INTERFACE ${LIBDIR}/libigl)
endif()
diff --git a/src/libnest2d/tests/test.cpp b/src/libnest2d/tests/test.cpp
index 5741e87b4..2f2b9beb5 100644
--- a/src/libnest2d/tests/test.cpp
+++ b/src/libnest2d/tests/test.cpp
@@ -10,10 +10,6 @@
#include "boost/multiprecision/integer.hpp"
#include "boost/rational.hpp"
-//#include "../tools/Int128.hpp"
-
-//#include "gte/Mathematics/GteMinimumAreaBox2.h"
-
//#include "../tools/libnfpglue.hpp"
//#include "../tools/nfp_svgnest_glue.hpp"
@@ -42,151 +38,151 @@ struct NfpImpl<S, NfpLevel::CONVEX_ONLY>
std::vector<libnest2d::Item>& prusaParts() {
static std::vector<libnest2d::Item> ret;
-
+
if(ret.empty()) {
ret.reserve(PRINTER_PART_POLYGONS.size());
for(auto& inp : PRINTER_PART_POLYGONS) ret.emplace_back(inp);
}
-
+
return ret;
}
TEST(BasicFunctionality, Angles)
{
-
+
using namespace libnest2d;
-
+
Degrees deg(180);
Radians rad(deg);
Degrees deg2(rad);
-
+
ASSERT_DOUBLE_EQ(rad, Pi);
ASSERT_DOUBLE_EQ(deg, 180);
ASSERT_DOUBLE_EQ(deg2, 180);
ASSERT_DOUBLE_EQ(rad, Radians(deg));
ASSERT_DOUBLE_EQ( Degrees(rad), deg);
-
+
ASSERT_TRUE(rad == deg);
-
+
Segment seg = {{0, 0}, {12, -10}};
-
+
ASSERT_TRUE(Degrees(seg.angleToXaxis()) > 270 &&
Degrees(seg.angleToXaxis()) < 360);
-
+
seg = {{0, 0}, {12, 10}};
-
+
ASSERT_TRUE(Degrees(seg.angleToXaxis()) > 0 &&
Degrees(seg.angleToXaxis()) < 90);
-
+
seg = {{0, 0}, {-12, 10}};
-
+
ASSERT_TRUE(Degrees(seg.angleToXaxis()) > 90 &&
Degrees(seg.angleToXaxis()) < 180);
-
+
seg = {{0, 0}, {-12, -10}};
-
+
ASSERT_TRUE(Degrees(seg.angleToXaxis()) > 180 &&
Degrees(seg.angleToXaxis()) < 270);
-
+
seg = {{0, 0}, {1, 0}};
-
+
ASSERT_DOUBLE_EQ(Degrees(seg.angleToXaxis()), 0);
-
+
seg = {{0, 0}, {0, 1}};
-
+
ASSERT_DOUBLE_EQ(Degrees(seg.angleToXaxis()), 90);
-
-
+
+
seg = {{0, 0}, {-1, 0}};
-
+
ASSERT_DOUBLE_EQ(Degrees(seg.angleToXaxis()), 180);
-
-
+
+
seg = {{0, 0}, {0, -1}};
-
+
ASSERT_DOUBLE_EQ(Degrees(seg.angleToXaxis()), 270);
-
+
}
// Simple test, does not use gmock
TEST(BasicFunctionality, creationAndDestruction)
{
using namespace libnest2d;
-
+
Item sh = { {0, 0}, {1, 0}, {1, 1}, {0, 1} };
-
+
ASSERT_EQ(sh.vertexCount(), 4u);
-
+
Item sh2 ({ {0, 0}, {1, 0}, {1, 1}, {0, 1} });
-
+
ASSERT_EQ(sh2.vertexCount(), 4u);
-
+
// copy
Item sh3 = sh2;
-
+
ASSERT_EQ(sh3.vertexCount(), 4u);
-
+
sh2 = {};
-
+
ASSERT_EQ(sh2.vertexCount(), 0u);
ASSERT_EQ(sh3.vertexCount(), 4u);
-
+
}
TEST(GeometryAlgorithms, boundingCircle) {
using namespace libnest2d;
using placers::boundingCircle;
-
+
PolygonImpl p = {{{0, 10}, {10, 0}, {0, -10}, {0, 10}}, {}};
Circle c = boundingCircle(p);
-
+
ASSERT_EQ(c.center().X, 0);
ASSERT_EQ(c.center().Y, 0);
ASSERT_DOUBLE_EQ(c.radius(), 10);
-
+
shapelike::translate(p, PointImpl{10, 10});
c = boundingCircle(p);
-
+
ASSERT_EQ(c.center().X, 10);
ASSERT_EQ(c.center().Y, 10);
ASSERT_DOUBLE_EQ(c.radius(), 10);
-
+
auto parts = prusaParts();
-
+
int i = 0;
for(auto& part : parts) {
c = boundingCircle(part.transformedShape());
if(std::isnan(c.radius())) std::cout << "fail: radius is nan" << std::endl;
-
+
else for(auto v : shapelike::contour(part.transformedShape()) ) {
- auto d = pointlike::distance(v, c.center());
- if(d > c.radius() ) {
- auto e = std::abs( 1.0 - d/c.radius());
- ASSERT_LE(e, 1e-3);
+ auto d = pointlike::distance(v, c.center());
+ if(d > c.radius() ) {
+ auto e = std::abs( 1.0 - d/c.radius());
+ ASSERT_LE(e, 1e-3);
+ }
}
- }
i++;
}
-
+
}
TEST(GeometryAlgorithms, Distance) {
using namespace libnest2d;
-
+
Point p1 = {0, 0};
-
+
Point p2 = {10, 0};
Point p3 = {10, 10};
-
+
ASSERT_DOUBLE_EQ(pointlike::distance(p1, p2), 10);
ASSERT_DOUBLE_EQ(pointlike::distance(p1, p3), sqrt(200));
-
+
Segment seg(p1, p3);
-
-// ASSERT_DOUBLE_EQ(pointlike::distance(p2, seg), 7.0710678118654755);
-
+
+ // ASSERT_DOUBLE_EQ(pointlike::distance(p2, seg), 7.0710678118654755);
+
auto result = pointlike::horizontalDistance(p2, seg);
-
+
auto check = [](TCompute<Coord> val, TCompute<Coord> expected) {
if(std::is_floating_point<TCompute<Coord>>::value)
ASSERT_DOUBLE_EQ(static_cast<double>(val),
@@ -194,44 +190,44 @@ TEST(GeometryAlgorithms, Distance) {
else
ASSERT_EQ(val, expected);
};
-
+
ASSERT_TRUE(result.second);
check(result.first, 10);
-
+
result = pointlike::verticalDistance(p2, seg);
ASSERT_TRUE(result.second);
check(result.first, -10);
-
+
result = pointlike::verticalDistance(Point{10, 20}, seg);
ASSERT_TRUE(result.second);
check(result.first, 10);
-
-
+
+
Point p4 = {80, 0};
Segment seg2 = { {0, 0}, {0, 40} };
-
+
result = pointlike::horizontalDistance(p4, seg2);
-
+
ASSERT_TRUE(result.second);
check(result.first, 80);
-
+
result = pointlike::verticalDistance(p4, seg2);
// Point should not be related to the segment
ASSERT_FALSE(result.second);
-
+
}
TEST(GeometryAlgorithms, Area) {
using namespace libnest2d;
-
+
Rectangle rect(10, 10);
-
+
ASSERT_EQ(rect.area(), 100);
-
+
Rectangle rect2 = {100, 100};
-
+
ASSERT_EQ(rect2.area(), 10000);
-
+
Item item = {
{61, 97},
{70, 151},
@@ -242,33 +238,33 @@ TEST(GeometryAlgorithms, Area) {
{61, 77},
{61, 97}
};
-
+
ASSERT_TRUE(shapelike::area(item.transformedShape()) > 0 );
}
TEST(GeometryAlgorithms, IsPointInsidePolygon) {
using namespace libnest2d;
-
+
Rectangle rect(10, 10);
-
+
Point p = {1, 1};
-
+
ASSERT_TRUE(rect.isInside(p));
-
+
p = {11, 11};
-
+
ASSERT_FALSE(rect.isInside(p));
-
-
+
+
p = {11, 12};
-
+
ASSERT_FALSE(rect.isInside(p));
-
-
+
+
p = {3, 3};
-
+
ASSERT_TRUE(rect.isInside(p));
-
+
}
//TEST(GeometryAlgorithms, Intersections) {
@@ -294,21 +290,21 @@ TEST(GeometryAlgorithms, LeftAndDownPolygon)
{
using namespace libnest2d;
using namespace libnest2d;
-
+
Box bin(100, 100);
BottomLeftPlacer placer(bin);
-
+
Item item = {{70, 75}, {88, 60}, {65, 50}, {60, 30}, {80, 20}, {42, 20},
{35, 35}, {35, 55}, {40, 75}, {70, 75}};
-
+
Item leftControl = { {40, 75},
- {35, 55},
- {35, 35},
- {42, 20},
- {0, 20},
- {0, 75},
- {40, 75}};
-
+ {35, 55},
+ {35, 35},
+ {42, 20},
+ {0, 20},
+ {0, 75},
+ {40, 75}};
+
Item downControl = {{88, 60},
{88, 0},
{35, 0},
@@ -318,22 +314,22 @@ TEST(GeometryAlgorithms, LeftAndDownPolygon)
{60, 30},
{65, 50},
{88, 60}};
-
+
Item leftp(placer.leftPoly(item));
-
+
ASSERT_TRUE(shapelike::isValid(leftp.rawShape()).first);
ASSERT_EQ(leftp.vertexCount(), leftControl.vertexCount());
-
+
for(unsigned long i = 0; i < leftControl.vertexCount(); i++) {
ASSERT_EQ(getX(leftp.vertex(i)), getX(leftControl.vertex(i)));
ASSERT_EQ(getY(leftp.vertex(i)), getY(leftControl.vertex(i)));
}
-
+
Item downp(placer.downPoly(item));
-
+
ASSERT_TRUE(shapelike::isValid(downp.rawShape()).first);
ASSERT_EQ(downp.vertexCount(), downControl.vertexCount());
-
+
for(unsigned long i = 0; i < downControl.vertexCount(); i++) {
ASSERT_EQ(getX(downp.vertex(i)), getX(downControl.vertex(i)));
ASSERT_EQ(getY(downp.vertex(i)), getY(downControl.vertex(i)));
@@ -344,7 +340,7 @@ TEST(GeometryAlgorithms, LeftAndDownPolygon)
TEST(GeometryAlgorithms, ArrangeRectanglesTight)
{
using namespace libnest2d;
-
+
std::vector<Rectangle> rects = {
{80, 80},
{60, 90},
@@ -366,17 +362,17 @@ TEST(GeometryAlgorithms, ArrangeRectanglesTight)
{5, 5},
{5, 5},
{20, 20} };
-
-
+
+
Nester<BottomLeftPlacer, DJDHeuristic> arrange(Box(210, 250));
-
+
auto groups = arrange(rects.begin(), rects.end());
-
+
ASSERT_EQ(groups.size(), 1u);
ASSERT_EQ(groups[0].size(), rects.size());
-
+
// check for no intersections, no containment:
-
+
for(auto result : groups) {
bool valid = true;
for(Item& r1 : result) {
@@ -389,14 +385,14 @@ TEST(GeometryAlgorithms, ArrangeRectanglesTight)
}
}
}
-
+
}
TEST(GeometryAlgorithms, ArrangeRectanglesLoose)
{
using namespace libnest2d;
-
-// std::vector<Rectangle> rects = { {40, 40}, {10, 10}, {20, 20} };
+
+ // std::vector<Rectangle> rects = { {40, 40}, {10, 10}, {20, 20} };
std::vector<Rectangle> rects = {
{80, 80},
{60, 90},
@@ -418,17 +414,17 @@ TEST(GeometryAlgorithms, ArrangeRectanglesLoose)
{5, 5},
{5, 5},
{20, 20} };
-
+
Coord min_obj_distance = 5;
-
+
Nester<BottomLeftPlacer, DJDHeuristic> arrange(Box(210, 250),
- min_obj_distance);
-
+ min_obj_distance);
+
auto groups = arrange(rects.begin(), rects.end());
-
+
ASSERT_EQ(groups.size(), 1u);
ASSERT_EQ(groups[0].size(), rects.size());
-
+
// check for no intersections, no containment:
auto result = groups[0];
bool valid = true;
@@ -441,7 +437,7 @@ TEST(GeometryAlgorithms, ArrangeRectanglesLoose)
}
}
}
-
+
}
namespace {
@@ -449,68 +445,68 @@ using namespace libnest2d;
template<long long SCALE = 1, class Bin>
void exportSVG(std::vector<std::reference_wrapper<Item>>& result, const Bin& bin, int idx = 0) {
-
-
+
+
std::string loc = "out";
-
+
static std::string svg_header =
-R"raw(<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+ R"raw(<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg height="500" width="500" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
)raw";
-
+
int i = idx;
auto r = result;
-// for(auto r : result) {
- std::fstream out(loc + std::to_string(i) + ".svg", std::fstream::out);
- if(out.is_open()) {
- out << svg_header;
- Item rbin( Rectangle(bin.width(), bin.height()) );
- for(unsigned i = 0; i < rbin.vertexCount(); i++) {
- auto v = rbin.vertex(i);
- setY(v, -getY(v)/SCALE + 500 );
+ // for(auto r : result) {
+ std::fstream out(loc + std::to_string(i) + ".svg", std::fstream::out);
+ if(out.is_open()) {
+ out << svg_header;
+ Item rbin( Rectangle(bin.width(), bin.height()) );
+ for(unsigned i = 0; i < rbin.vertexCount(); i++) {
+ auto v = rbin.vertex(i);
+ setY(v, -getY(v)/SCALE + 500 );
+ setX(v, getX(v)/SCALE);
+ rbin.setVertex(i, v);
+ }
+ out << shapelike::serialize<Formats::SVG>(rbin.rawShape()) << std::endl;
+ for(Item& sh : r) {
+ Item tsh(sh.transformedShape());
+ for(unsigned i = 0; i < tsh.vertexCount(); i++) {
+ auto v = tsh.vertex(i);
+ setY(v, -getY(v)/SCALE + 500);
setX(v, getX(v)/SCALE);
- rbin.setVertex(i, v);
+ tsh.setVertex(i, v);
}
- out << shapelike::serialize<Formats::SVG>(rbin.rawShape()) << std::endl;
- for(Item& sh : r) {
- Item tsh(sh.transformedShape());
- for(unsigned i = 0; i < tsh.vertexCount(); i++) {
- auto v = tsh.vertex(i);
- setY(v, -getY(v)/SCALE + 500);
- setX(v, getX(v)/SCALE);
- tsh.setVertex(i, v);
- }
- out << shapelike::serialize<Formats::SVG>(tsh.rawShape()) << std::endl;
- }
- out << "\n</svg>" << std::endl;
+ out << shapelike::serialize<Formats::SVG>(tsh.rawShape()) << std::endl;
}
- out.close();
-
-// i++;
-// }
+ out << "\n</svg>" << std::endl;
+ }
+ out.close();
+
+ // i++;
+ // }
}
}
TEST(GeometryAlgorithms, BottomLeftStressTest) {
using namespace libnest2d;
-
+
const Coord SCALE = 1000000;
auto& input = prusaParts();
-
+
Box bin(210*SCALE, 250*SCALE);
BottomLeftPlacer placer(bin);
-
+
auto it = input.begin();
auto next = it;
int i = 0;
while(it != input.end() && ++next != input.end()) {
placer.pack(*it);
placer.pack(*next);
-
+
auto result = placer.getItems();
bool valid = true;
-
+
if(result.size() == 2) {
Item& r1 = result[0];
Item& r2 = result[1];
@@ -525,7 +521,7 @@ TEST(GeometryAlgorithms, BottomLeftStressTest) {
std::cout << "something went terribly wrong!" << std::endl;
FAIL();
}
-
+
placer.clearItems();
it++;
i++;
@@ -534,9 +530,9 @@ TEST(GeometryAlgorithms, BottomLeftStressTest) {
TEST(GeometryAlgorithms, convexHull) {
using namespace libnest2d;
-
+
ClipperLib::Path poly = PRINTER_PART_POLYGONS[0];
-
+
auto chull = sl::convexHull(poly);
ASSERT_EQ(chull.size(), poly.size());
@@ -545,7 +541,7 @@ TEST(GeometryAlgorithms, convexHull) {
TEST(GeometryAlgorithms, NestTest) {
std::vector<Item> input = prusaParts();
-
+
PackGroup result = libnest2d::nest(input,
Box(250000000, 210000000),
[](unsigned cnt) {
@@ -553,16 +549,17 @@ TEST(GeometryAlgorithms, NestTest) {
<< "parts left: " << cnt
<< std::endl;
});
-
+
ASSERT_LE(result.size(), 2);
-
- int partsum = std::accumulate(result.begin(),
- result.end(),
- 0,
- [](int s,
- const decltype(result)::value_type &bin) {
- return s += bin.size();
- });
+
+ size_t partsum = std::accumulate(result.begin(),
+ result.end(),
+ size_t(0),
+ [](size_t s,
+ const decltype(
+ result)::value_type &bin) {
+ return s += bin.size();
+ });
ASSERT_EQ(input.size(), partsum);
}
@@ -647,7 +644,7 @@ std::vector<ItemPair> nfp_testdata = {
{118, 101},
{117, 103},
{117, 107}
- },
+ },
{
{102, 116},
{111, 126},
@@ -658,7 +655,7 @@ std::vector<ItemPair> nfp_testdata = {
{147, 84},
{102, 84},
{102, 116},
- }
+ }
},
{
{
@@ -674,7 +671,7 @@ std::vector<ItemPair> nfp_testdata = {
{108, 70},
{99, 102},
{99, 122},
- },
+ },
{
{107, 124},
{128, 125},
@@ -691,7 +688,7 @@ std::vector<ItemPair> nfp_testdata = {
{108, 85},
{107, 86},
{107, 124},
- }
+ }
},
{
{
@@ -706,7 +703,7 @@ std::vector<ItemPair> nfp_testdata = {
{132, 57},
{91, 98},
{91, 100},
- },
+ },
{
{101, 90},
{103, 98},
@@ -724,74 +721,74 @@ std::vector<ItemPair> nfp_testdata = {
{102, 87},
{101, 89},
{101, 90},
- }
+ }
}
};
-std::vector<ItemPair> nfp_concave_testdata = {
- { // ItemPair
- {
- {
- {533726, 142141},
- {532359, 143386},
- {530141, 142155},
- {528649, 160091},
- {533659, 157607},
- {538669, 160091},
- {537178, 142155},
- {534959, 143386},
- {533726, 142141},
- }
- },
- {
- {
- {118305, 11603},
- {118311, 26616},
- {113311, 26611},
- {109311, 29604},
- {109300, 44608},
- {109311, 49631},
- {113300, 52636},
- {118311, 52636},
- {118308, 103636},
- {223830, 103636},
- {236845, 90642},
- {236832, 11630},
- {232825, 11616},
- {210149, 11616},
- {211308, 13625},
- {209315, 17080},
- {205326, 17080},
- {203334, 13629},
- {204493, 11616},
- {118305, 11603},
- }
- },
- }
+ std::vector<ItemPair> nfp_concave_testdata = {
+ { // ItemPair
+ {
+ {
+ {533726, 142141},
+ {532359, 143386},
+ {530141, 142155},
+ {528649, 160091},
+ {533659, 157607},
+ {538669, 160091},
+ {537178, 142155},
+ {534959, 143386},
+ {533726, 142141},
+ }
+ },
+ {
+ {
+ {118305, 11603},
+ {118311, 26616},
+ {113311, 26611},
+ {109311, 29604},
+ {109300, 44608},
+ {109311, 49631},
+ {113300, 52636},
+ {118311, 52636},
+ {118308, 103636},
+ {223830, 103636},
+ {236845, 90642},
+ {236832, 11630},
+ {232825, 11616},
+ {210149, 11616},
+ {211308, 13625},
+ {209315, 17080},
+ {205326, 17080},
+ {203334, 13629},
+ {204493, 11616},
+ {118305, 11603},
+ }
+ },
+ }
};
template<nfp::NfpLevel lvl, Coord SCALE>
void testNfp(const std::vector<ItemPair>& testdata) {
using namespace libnest2d;
-
+
Box bin(210*SCALE, 250*SCALE);
-
+
int testcase = 0;
-
+
auto& exportfun = exportSVG<SCALE, Box>;
-
+
auto onetest = [&](Item& orbiter, Item& stationary, unsigned /*testidx*/){
testcase++;
-
+
orbiter.translate({210*SCALE, 0});
-
+
auto&& nfp = nfp::noFitPolygon<lvl>(stationary.rawShape(),
orbiter.transformedShape());
-
+
placers::correctNfpPosition(nfp, stationary, orbiter);
-
+
auto valid = shapelike::isValid(nfp.first);
-
+
/*Item infp(nfp.first);
if(!valid.first) {
std::cout << "test instance: " << testidx << " "
@@ -799,46 +796,46 @@ void testNfp(const std::vector<ItemPair>& testdata) {
std::vector<std::reference_wrapper<Item>> inp = {std::ref(infp)};
exportfun(inp, bin, testidx);
}*/
-
+
ASSERT_TRUE(valid.first);
-
+
Item infp(nfp.first);
-
+
int i = 0;
auto rorbiter = orbiter.transformedShape();
auto vo = nfp::referenceVertex(rorbiter);
-
+
ASSERT_TRUE(stationary.isInside(infp));
-
+
for(auto v : infp) {
auto dx = getX(v) - getX(vo);
auto dy = getY(v) - getY(vo);
-
+
Item tmp = orbiter;
-
+
tmp.translate({dx, dy});
-
+
bool touching = Item::touches(tmp, stationary);
-
+
if(!touching || !valid.first) {
std::vector<std::reference_wrapper<Item>> inp = {
std::ref(stationary), std::ref(tmp), std::ref(infp)
};
-
+
exportfun(inp, bin, testcase*i++);
}
-
+
ASSERT_TRUE(touching);
}
};
-
+
unsigned tidx = 0;
for(auto& td : testdata) {
auto orbiter = td.orbiter;
auto stationary = td.stationary;
onetest(orbiter, stationary, tidx++);
}
-
+
tidx = 0;
for(auto& td : testdata) {
auto orbiter = td.stationary;
@@ -858,19 +855,19 @@ TEST(GeometryAlgorithms, nfpConvexConvex) {
TEST(GeometryAlgorithms, pointOnPolygonContour) {
using namespace libnest2d;
-
+
Rectangle input(10, 10);
-
+
placers::EdgeCache<PolygonImpl> ecache(input);
-
+
auto first = *input.begin();
ASSERT_TRUE(getX(first) == getX(ecache.coords(0)));
ASSERT_TRUE(getY(first) == getY(ecache.coords(0)));
-
+
auto last = *std::prev(input.end());
ASSERT_TRUE(getX(last) == getX(ecache.coords(1.0)));
ASSERT_TRUE(getY(last) == getY(ecache.coords(1.0)));
-
+
for(int i = 0; i <= 100; i++) {
auto v = ecache.coords(i*(0.01));
ASSERT_TRUE(shapelike::touches(v, input.transformedShape()));
@@ -879,24 +876,24 @@ TEST(GeometryAlgorithms, pointOnPolygonContour) {
TEST(GeometryAlgorithms, mergePileWithPolygon) {
using namespace libnest2d;
-
+
Rectangle rect1(10, 15);
Rectangle rect2(15, 15);
Rectangle rect3(20, 15);
-
+
rect2.translate({10, 0});
rect3.translate({25, 0});
-
+
TMultiShape<PolygonImpl> pile;
pile.push_back(rect1.transformedShape());
pile.push_back(rect2.transformedShape());
-
+
auto result = nfp::merge(pile, rect3.transformedShape());
-
+
ASSERT_EQ(result.size(), 1);
-
+
Rectangle ref(45, 15);
-
+
ASSERT_EQ(shapelike::area(result.front()), ref.area());
}
@@ -908,7 +905,7 @@ long double refMinAreaBox(const PolygonImpl& p) {
long double min_area = std::numeric_limits<long double>::max();
-
+
auto update_min = [&min_area, &it, &itx, &p]() {
Segment s(*it, *itx);
@@ -935,67 +932,39 @@ template<class T> struct BoostGCD {
};
using Unit = int64_t;
-using Ratio = boost::rational<boost::multiprecision::int128_t>;// Rational<boost::multiprecision::int256_t>;
-
-//double gteMinAreaBox(const PolygonImpl& p) {
-
-// using GteCoord = ClipperLib::cInt;
-// using GtePoint = gte::Vector2<GteCoord>;
-
-// gte::MinimumAreaBox2<GteCoord, Ratio> mb;
-
-// std::vector<GtePoint> points;
-// points.reserve(p.Contour.size());
-
-// for(auto& pt : p.Contour) points.emplace_back(GtePoint{GteCoord(pt.X), GteCoord(pt.Y)});
-
-// mb(int(points.size()), points.data(), 0, nullptr, true);
-
-// auto min_area = double(mb.GetArea());
-
-// return min_area;
-//}
+using Ratio = boost::rational<boost::multiprecision::int128_t>;
}
TEST(RotatingCalipers, MinAreaBBCClk) {
-// PolygonImpl poly({{-50, 30}, {-50, -50}, {50, -50}, {50, 50}, {-40, 50}});
-
-// PolygonImpl poly({{-50, 0}, {50, 0}, {0, 100}});
-
auto u = [](ClipperLib::cInt n) { return n*1000000; };
PolygonImpl poly({ {u(0), u(0)}, {u(4), u(1)}, {u(2), u(4)}});
-
long double arearef = refMinAreaBox(poly);
long double area = minAreaBoundingBox<PolygonImpl, Unit, Ratio>(poly).area();
-// double gtearea = gteMinAreaBox(poly);
ASSERT_LE(std::abs(area - arearef), 500e6 );
-// ASSERT_LE(std::abs(gtearea - arearef), 500 );
-// ASSERT_DOUBLE_EQ(gtearea, arearef);
}
TEST(RotatingCalipers, AllPrusaMinBB) {
- size_t idx = 0;
+ // /size_t idx = 0;
long double err_epsilon = 500e6l;
for(ClipperLib::Path rinput : PRINTER_PART_POLYGONS) {
-// ClipperLib::Path rinput = PRINTER_PART_POLYGONS[idx];
-// rinput.pop_back();
-// std::reverse(rinput.begin(), rinput.end());
+ // ClipperLib::Path rinput = PRINTER_PART_POLYGONS[idx];
+ // rinput.pop_back();
+ // std::reverse(rinput.begin(), rinput.end());
-// PolygonImpl poly(removeCollinearPoints<PathImpl, PointImpl, Unit>(rinput, 1000000));
+ // PolygonImpl poly(removeCollinearPoints<PathImpl, PointImpl, Unit>(rinput, 1000000));
PolygonImpl poly(rinput);
long double arearef = refMinAreaBox(poly);
auto bb = minAreaBoundingBox<PathImpl, Unit, Ratio>(rinput);
long double area = cast<long double>(bb.area());
-// double area = gteMinAreaBox(poly);
bool succ = std::abs(arearef - area) < err_epsilon;
- std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: "
- << arearef << " actual: " << area << std::endl;
+ // std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: "
+// << arearef << " actual: " << area << std::endl;
ASSERT_TRUE(succ);
}
@@ -1006,21 +975,20 @@ TEST(RotatingCalipers, AllPrusaMinBB) {
PolygonImpl poly(removeCollinearPoints<PathImpl, PointImpl, Unit>(rinput, 1000000));
-
long double arearef = refMinAreaBox(poly);
auto bb = minAreaBoundingBox<PolygonImpl, Unit, Ratio>(poly);
long double area = cast<long double>(bb.area());
-// double area = gteMinAreaBox(poly);
+
bool succ = std::abs(arearef - area) < err_epsilon;
- std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: "
- << arearef << " actual: " << area << std::endl;
+ // std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: "
+// << arearef << " actual: " << area << std::endl;
ASSERT_TRUE(succ);
}
}
int main(int argc, char **argv) {
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
}
diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp
index 794beff21..c5754fb83 100644
--- a/src/libslic3r/Config.cpp
+++ b/src/libslic3r/Config.cpp
@@ -751,18 +751,18 @@ bool DynamicConfig::read_cli(int argc, char** argv, t_config_option_keys* extra,
}
// Store the option value.
const bool existing = this->has(opt_key);
- if (keys != nullptr && !existing) {
+ if (keys != nullptr && ! existing) {
// Save the order of detected keys.
keys->push_back(opt_key);
}
ConfigOption *opt_base = this->option(opt_key, true);
ConfigOptionVectorBase *opt_vector = opt_base->is_vector() ? static_cast<ConfigOptionVectorBase*>(opt_base) : nullptr;
if (opt_vector) {
+ if (! existing)
+ // remove the default values
+ opt_vector->clear();
// Vector values will be chained. Repeated use of a parameter will append the parameter or parameters
// to the end of the value.
- if (!existing)
- // remove the default values
- opt_vector->deserialize("", true);
if (opt_base->type() == coBools)
static_cast<ConfigOptionBools*>(opt_base)->values.push_back(!no);
else
diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp
index d1fb9b7f4..1511c4b28 100644
--- a/src/libslic3r/Config.hpp
+++ b/src/libslic3r/Config.hpp
@@ -177,8 +177,10 @@ public:
// Set a single vector item from either a scalar option or the first value of a vector option.vector of ConfigOptions.
// This function is useful to split values from multiple extrder / filament settings into separate configurations.
virtual void set_at(const ConfigOption *rhs, size_t i, size_t j) = 0;
-
+ // Resize the vector of values, copy the newly added values from opt_default if provided.
virtual void resize(size_t n, const ConfigOption *opt_default = nullptr) = 0;
+ // Clear the values vector.
+ virtual void clear() = 0;
// Get size of this vector.
virtual size_t size() const = 0;
@@ -287,6 +289,8 @@ public:
}
}
+ // Clear the values vector.
+ void clear() override { this->values.clear(); }
size_t size() const override { return this->values.size(); }
bool empty() const override { return this->values.empty(); }
diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp
index 75952e4c2..fbdef29b9 100644
--- a/src/libslic3r/Fill/Fill.cpp
+++ b/src/libslic3r/Fill/Fill.cpp
@@ -126,7 +126,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
Polygons surfaces_polygons = to_polygons(surfaces);
Polygons collapsed = diff(
surfaces_polygons,
- offset2(surfaces_polygons, -distance_between_surfaces/2, +distance_between_surfaces/2),
+ offset2(surfaces_polygons, (float)-distance_between_surfaces/2, (float)+distance_between_surfaces/2),
true);
Polygons to_subtract;
to_subtract.reserve(collapsed.size() + number_polygons(surfaces));
@@ -137,7 +137,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
surfaces_append(
surfaces,
intersection_ex(
- offset(collapsed, distance_between_surfaces),
+ offset(collapsed, (float)distance_between_surfaces),
to_subtract,
true),
stInternalSolid);
@@ -219,14 +219,14 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
f->z = layerm.layer()->print_z;
f->angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
// Maximum length of the perimeter segment linking two infill lines.
- f->link_max_length = scale_(link_max_length);
+ f->link_max_length = (coord_t)scale_(link_max_length);
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
- f->loop_clipping = scale_(flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER;
+ f->loop_clipping = coord_t(scale_(flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
// f->layer_height = h;
// apply half spacing using this flow's own spacing and generate infill
FillParams params;
- params.density = 0.01 * density;
+ params.density = float(0.01 * density);
// params.dont_adjust = true;
params.dont_adjust = false;
Polylines polylines = f->fill_surface(&surface, params);
@@ -240,7 +240,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
// so we can safely ignore the slight variation that might have
// been applied to $f->flow_spacing
} else {
- flow = Flow::new_from_spacing(f->spacing, flow.nozzle_diameter, h, is_bridge || f->use_bridge_flow());
+ flow = Flow::new_from_spacing(f->spacing, flow.nozzle_diameter, (float)h, is_bridge || f->use_bridge_flow());
}
// Save into layer.
diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index 0cb0af119..e9f068974 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -11,10 +11,16 @@
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/nowide/fstream.hpp>
#include <boost/nowide/cstdio.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+#include <boost/foreach.hpp>
+namespace pt = boost::property_tree;
+
#include <expat.h>
#include <Eigen/Dense>
#include "miniz_extension.hpp"
@@ -33,6 +39,7 @@ const std::string RELATIONSHIPS_FILE = "_rels/.rels";
const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config";
const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config";
const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt";
+const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/Prusa_Slicer_layer_config_ranges.xml";
const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt";
const char* MODEL_TAG = "model";
@@ -331,6 +338,7 @@ namespace Slic3r {
typedef std::map<int, ObjectMetadata> IdToMetadataMap;
typedef std::map<int, Geometry> IdToGeometryMap;
typedef std::map<int, std::vector<coordf_t>> IdToLayerHeightsProfileMap;
+ typedef std::map<int, t_layer_config_ranges> IdToLayerConfigRangesMap;
typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap;
// Version of the 3mf file
@@ -347,6 +355,7 @@ namespace Slic3r {
CurrentConfig m_curr_config;
IdToMetadataMap m_objects_metadata;
IdToLayerHeightsProfileMap m_layer_heights_profiles;
+ IdToLayerConfigRangesMap m_layer_config_ranges;
IdToSlaSupportPointsMap m_sla_support_points;
std::string m_curr_metadata_name;
std::string m_curr_characters;
@@ -365,6 +374,7 @@ namespace Slic3r {
bool _load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config);
bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
+ void _extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, const std::string& archive_filename);
@@ -476,6 +486,7 @@ namespace Slic3r {
m_curr_config.volume_id = -1;
m_objects_metadata.clear();
m_layer_heights_profiles.clear();
+ m_layer_config_ranges.clear();
m_sla_support_points.clear();
m_curr_metadata_name.clear();
m_curr_characters.clear();
@@ -546,9 +557,14 @@ namespace Slic3r {
if (boost::algorithm::iequals(name, LAYER_HEIGHTS_PROFILE_FILE))
{
- // extract slic3r lazer heights profile file
+ // extract slic3r layer heights profile file
_extract_layer_heights_profile_config_from_archive(archive, stat);
}
+ if (boost::algorithm::iequals(name, LAYER_CONFIG_RANGES_FILE))
+ {
+ // extract slic3r layer config ranges file
+ _extract_layer_config_ranges_from_archive(archive, stat);
+ }
else if (boost::algorithm::iequals(name, SLA_SUPPORT_POINTS_FILE))
{
// extract sla support points file
@@ -592,6 +608,11 @@ namespace Slic3r {
if (obj_layer_heights_profile != m_layer_heights_profiles.end())
model_object->layer_height_profile = obj_layer_heights_profile->second;
+ // m_layer_config_ranges are indexed by a 1 based model object index.
+ IdToLayerConfigRangesMap::iterator obj_layer_config_ranges = m_layer_config_ranges.find(object.second + 1);
+ if (obj_layer_config_ranges != m_layer_config_ranges.end())
+ model_object->layer_config_ranges = obj_layer_config_ranges->second;
+
// m_sla_support_points are indexed by a 1 based model object index.
IdToSlaSupportPointsMap::iterator obj_sla_support_points = m_sla_support_points.find(object.second + 1);
if (obj_sla_support_points != m_sla_support_points.end() && !obj_sla_support_points->second.empty()) {
@@ -769,6 +790,66 @@ namespace Slic3r {
}
}
+ void _3MF_Importer::_extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
+ {
+ if (stat.m_uncomp_size > 0)
+ {
+ std::string buffer((size_t)stat.m_uncomp_size, 0);
+ mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
+ if (res == 0) {
+ add_error("Error while reading layer config ranges data to buffer");
+ return;
+ }
+
+ std::istringstream iss(buffer); // wrap returned xml to istringstream
+ pt::ptree objects_tree;
+ pt::read_xml(iss, objects_tree);
+
+ for (const auto& object : objects_tree.get_child("objects"))
+ {
+ pt::ptree object_tree = object.second;
+ int obj_idx = object_tree.get<int>("<xmlattr>.id", -1);
+ if (obj_idx <= 0) {
+ add_error("Found invalid object id");
+ continue;
+ }
+
+ IdToLayerConfigRangesMap::iterator object_item = m_layer_config_ranges.find(obj_idx);
+ if (object_item != m_layer_config_ranges.end()) {
+ add_error("Found duplicated layer config range");
+ continue;
+ }
+
+ t_layer_config_ranges config_ranges;
+
+ for (const auto& range : object_tree)
+ {
+ if (range.first != "range")
+ continue;
+ pt::ptree range_tree = range.second;
+ double min_z = range_tree.get<double>("<xmlattr>.min_z");
+ double max_z = range_tree.get<double>("<xmlattr>.max_z");
+
+ // get Z range information
+ DynamicPrintConfig& config = config_ranges[{ min_z, max_z }];
+
+ for (const auto& option : range_tree)
+ {
+ if (option.first != "option")
+ continue;
+ std::string opt_key = option.second.get<std::string>("<xmlattr>.opt_key");
+ std::string value = option.second.data();
+
+ config.set_deserialize(opt_key, value);
+ }
+ }
+
+ if (!config_ranges.empty())
+ m_layer_config_ranges.insert(IdToLayerConfigRangesMap::value_type(obj_idx, config_ranges));
+ }
+ }
+ }
+
void _3MF_Importer::_extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
{
if (stat.m_uncomp_size > 0)
@@ -1624,6 +1705,7 @@ namespace Slic3r {
bool _add_mesh_to_object_stream(std::stringstream& stream, ModelObject& object, VolumeToOffsetsMap& volumes_offsets);
bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items);
bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model);
+ bool _add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config);
bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data);
@@ -1684,6 +1766,16 @@ namespace Slic3r {
return false;
}
+ // Adds layer config ranges file ("Metadata/Slic3r_PE_layer_config_ranges.txt").
+ // All layer height profiles of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
+ // The index differes from the index of an object ID of an object instance of a 3MF file!
+ if (!_add_layer_config_ranges_file_to_archive(archive, model))
+ {
+ close_zip_writer(&archive);
+ boost::filesystem::remove(filename);
+ return false;
+ }
+
// Adds sla support points file ("Metadata/Slic3r_PE_sla_support_points.txt").
// All sla support points of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
// The index differes from the index of an object ID of an object instance of a 3MF file!
@@ -1895,7 +1987,7 @@ namespace Slic3r {
return false;
}
- vertices_count += its.vertices.size();
+ vertices_count += (int)its.vertices.size();
const Transform3d& matrix = volume->get_matrix();
@@ -1925,7 +2017,7 @@ namespace Slic3r {
// updates triangle offsets
volume_it->second.first_triangle_id = triangles_count;
- triangles_count += its.indices.size();
+ triangles_count += (int)its.indices.size();
volume_it->second.last_triangle_id = triangles_count - 1;
for (size_t i = 0; i < its.indices.size(); ++ i)
@@ -2013,6 +2105,70 @@ namespace Slic3r {
return true;
}
+ bool _3MF_Exporter::_add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model)
+ {
+ std::string out = "";
+ pt::ptree tree;
+
+ unsigned int object_cnt = 0;
+ for (const ModelObject* object : model.objects)
+ {
+ object_cnt++;
+ const t_layer_config_ranges& ranges = object->layer_config_ranges;
+ if (!ranges.empty())
+ {
+ pt::ptree& obj_tree = tree.add("objects.object","");
+
+ obj_tree.put("<xmlattr>.id", object_cnt);
+
+ // Store the layer config ranges.
+ for (const auto& range : ranges)
+ {
+ pt::ptree& range_tree = obj_tree.add("range", "");
+
+ // store minX and maxZ
+ range_tree.put("<xmlattr>.min_z", range.first.first);
+ range_tree.put("<xmlattr>.max_z", range.first.second);
+
+ // store range configuration
+ const DynamicPrintConfig& config = range.second;
+ for (const std::string& opt_key : config.keys())
+ {
+ pt::ptree& opt_tree = range_tree.add("option", config.serialize(opt_key));
+ opt_tree.put("<xmlattr>.opt_key", opt_key);
+ }
+ }
+ }
+ }
+
+ if (!tree.empty())
+ {
+ std::ostringstream oss;
+ boost::property_tree::write_xml(oss, tree);
+ out = oss.str();
+
+ // Post processing("beautification") of the output string for a better preview
+ boost::replace_all(out, "><object", ">\n <object");
+ boost::replace_all(out, "><range", ">\n <range");
+ boost::replace_all(out, "><option", ">\n <option");
+ boost::replace_all(out, "></range>", ">\n </range>");
+ boost::replace_all(out, "></object>", ">\n </object>");
+ // OR just
+ boost::replace_all(out, "><", ">\n<");
+ }
+
+ if (!out.empty())
+ {
+ if (!mz_zip_writer_add_mem(&archive, LAYER_CONFIG_RANGES_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
+ {
+ add_error("Unable to add layer heights profile file to archive");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
bool _3MF_Exporter::_add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model)
{
std::string out = "";
diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index 0228bd906..074b7e933 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -106,6 +106,9 @@ struct AMFParserContext
// amf/material/metadata
NODE_TYPE_OBJECT, // amf/object
// amf/object/metadata
+ NODE_TYPE_LAYER_CONFIG, // amf/object/layer_config_ranges
+ NODE_TYPE_RANGE, // amf/object/layer_config_ranges/range
+ // amf/object/layer_config_ranges/range/metadata
NODE_TYPE_MESH, // amf/object/mesh
NODE_TYPE_VERTICES, // amf/object/mesh/vertices
NODE_TYPE_VERTEX, // amf/object/mesh/vertices/vertex
@@ -189,7 +192,7 @@ struct AMFParserContext
};
// Version of the amf file
- unsigned int m_version;
+ unsigned int m_version;
// Current Expat XML parser instance.
XML_Parser m_parser;
// Model to receive objects extracted from an AMF file.
@@ -260,7 +263,9 @@ void AMFParserContext::startElement(const char *name, const char **atts)
m_value[0] = get_attribute(atts, "type");
node_type_new = NODE_TYPE_METADATA;
}
- } else if (strcmp(name, "mesh") == 0) {
+ } else if (strcmp(name, "layer_config_ranges") == 0 && m_path[1] == NODE_TYPE_OBJECT)
+ node_type_new = NODE_TYPE_LAYER_CONFIG;
+ else if (strcmp(name, "mesh") == 0) {
if (m_path[1] == NODE_TYPE_OBJECT)
node_type_new = NODE_TYPE_MESH;
} else if (strcmp(name, "instance") == 0) {
@@ -317,6 +322,10 @@ void AMFParserContext::startElement(const char *name, const char **atts)
else if (strcmp(name, "mirrorz") == 0)
node_type_new = NODE_TYPE_MIRRORZ;
}
+ else if (m_path[2] == NODE_TYPE_LAYER_CONFIG && strcmp(name, "range") == 0) {
+ assert(m_object);
+ node_type_new = NODE_TYPE_RANGE;
+ }
break;
case 4:
if (m_path[3] == NODE_TYPE_VERTICES) {
@@ -334,6 +343,10 @@ void AMFParserContext::startElement(const char *name, const char **atts)
} else if (strcmp(name, "triangle") == 0)
node_type_new = NODE_TYPE_TRIANGLE;
}
+ else if (m_path[3] == NODE_TYPE_RANGE && strcmp(name, "metadata") == 0) {
+ m_value[0] = get_attribute(atts, "type");
+ node_type_new = NODE_TYPE_METADATA;
+ }
break;
case 5:
if (strcmp(name, "coordinates") == 0) {
@@ -571,8 +584,13 @@ void AMFParserContext::endElement(const char * /* name */)
config = &m_material->config;
else if (m_path[1] == NODE_TYPE_OBJECT && m_object)
config = &m_object->config;
- } else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume)
+ }
+ else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume)
config = &m_volume->config;
+ else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_RANGE && m_object && !m_object->layer_config_ranges.empty()) {
+ auto it = --m_object->layer_config_ranges.end();
+ config = &it->second;
+ }
if (config)
config->set_deserialize(opt_key, m_value[1]);
} else if (m_path.size() == 3 && m_path[1] == NODE_TYPE_OBJECT && m_object && strcmp(opt_key, "layer_height_profile") == 0) {
@@ -598,7 +616,7 @@ void AMFParserContext::endElement(const char * /* name */)
if (end != nullptr)
*end = 0;
- point(coord_idx) = atof(p);
+ point(coord_idx) = float(atof(p));
if (++coord_idx == 5) {
m_object->sla_support_points.push_back(sla::SupportPoint(point));
coord_idx = 0;
@@ -609,6 +627,16 @@ void AMFParserContext::endElement(const char * /* name */)
}
m_object->sla_points_status = sla::PointsStatus::UserModified;
}
+ else if (m_path.size() == 5 && m_path[1] == NODE_TYPE_OBJECT && m_path[3] == NODE_TYPE_RANGE &&
+ m_object && strcmp(opt_key, "layer_height_range") == 0) {
+ // Parse object's layer_height_range, a semicolon separated doubles.
+ char* p = const_cast<char*>(m_value[1].c_str());
+ char* end = strchr(p, ';');
+ *end = 0;
+
+ const t_layer_height_range range = {double(atof(p)), double(atof(end + 1))};
+ m_object->layer_config_ranges[range];
+ }
else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume) {
if (strcmp(opt_key, "modifier") == 0) {
// Is this volume a modifier volume?
@@ -907,6 +935,31 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
}
//FIXME Store the layer height ranges (ModelObject::layer_height_ranges)
+
+ // #ys_FIXME_experiment : Try to export layer config range
+ const t_layer_config_ranges& config_ranges = object->layer_config_ranges;
+ if (!config_ranges.empty())
+ {
+ // Store the layer config range as a single semicolon separated list.
+ stream << " <layer_config_ranges>\n";
+ size_t layer_counter = 0;
+ for (auto range : config_ranges) {
+ stream << " <range id=\"" << layer_counter << "\">\n";
+
+ stream << " <metadata type=\"slic3r.layer_height_range\">";
+ stream << range.first.first << ";" << range.first.second << "</metadata>\n";
+
+ for (const std::string& key : range.second.keys())
+ stream << " <metadata type=\"slic3r." << key << "\">" << range.second.serialize(key) << "</metadata>\n";
+
+ stream << " </range>\n";
+ layer_counter++;
+ }
+
+ stream << " </layer_config_ranges>\n";
+ }
+
+
const std::vector<sla::SupportPoint>& sla_support_points = object->sla_support_points;
if (!sla_support_points.empty()) {
// Store the SLA supports as a single semicolon separated list.
@@ -941,7 +994,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
stream << " </coordinates>\n";
stream << " </vertex>\n";
}
- num_vertices += its.vertices.size();
+ num_vertices += (int)its.vertices.size();
}
stream << " </vertices>\n";
for (size_t i_volume = 0; i_volume < object->volumes.size(); ++i_volume) {
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index f868aa079..d9b3e74f4 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -1405,7 +1405,9 @@ void GCode::process_layer(
m_colorprint_heights.erase(m_colorprint_heights.begin());
colorprint_change = true;
}
- if (colorprint_change && print.extruders().size()==1)
+
+ // we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count
+ if (colorprint_change && print./*extruders()*/config().nozzle_diameter.size()==1)
gcode += "M600\n";
diff --git a/src/libslic3r/MTUtils.hpp b/src/libslic3r/MTUtils.hpp
index b261a79be..ce26887f2 100644
--- a/src/libslic3r/MTUtils.hpp
+++ b/src/libslic3r/MTUtils.hpp
@@ -7,6 +7,9 @@
#include <utility> // for std::forward
#include <algorithm>
+#include "libslic3r.h"
+#include "Point.hpp"
+
namespace Slic3r {
/// Handy little spin mutex for the cached meshes.
@@ -239,13 +242,92 @@ template<class C> bool all_of(const C &container)
});
}
-template<class X, class Y> inline X ceil_i(X x, Y y)
+// A shorter C++14 style form of the enable_if metafunction
+template<bool B, class T>
+using enable_if_t = typename std::enable_if<B, T>::type;
+
+// /////////////////////////////////////////////////////////////////////////////
+// Type safe conversions to and from scaled and unscaled coordinates
+// /////////////////////////////////////////////////////////////////////////////
+
+// A meta-predicate which is true for integers wider than or equal to coord_t
+template<class I> struct is_scaled_coord
+{
+ static const SLIC3R_CONSTEXPR bool value =
+ std::is_integral<I>::value &&
+ std::numeric_limits<I>::digits >=
+ std::numeric_limits<coord_t>::digits;
+};
+
+// Meta predicates for floating, 'scaled coord' and generic arithmetic types
+template<class T>
+using FloatingOnly = enable_if_t<std::is_floating_point<T>::value, T>;
+
+template<class T>
+using ScaledCoordOnly = enable_if_t<is_scaled_coord<T>::value, T>;
+
+template<class T>
+using ArithmeticOnly = enable_if_t<std::is_arithmetic<T>::value, T>;
+
+// A shorter form for a generic Eigen vector which is widely used in PrusaSlicer
+template<class T, int N>
+using EigenVec = Eigen::Matrix<T, N, 1, Eigen::DontAlign>;
+
+// Semantics are the following:
+// Upscaling (scaled()): only from floating point types (or Vec) to either
+// floating point or integer 'scaled coord' coordinates.
+// Downscaling (unscaled()): from arithmetic types (or Vec) to either
+// floating point only
+
+// Conversion definition from unscaled to floating point scaled
+template<class Tout,
+ class Tin,
+ class = FloatingOnly<Tin>,
+ class = FloatingOnly<Tout>>
+inline SLIC3R_CONSTEXPR Tout scaled(const Tin &v) SLIC3R_NOEXCEPT
+{
+ return static_cast<Tout>(v / static_cast<Tin>(SCALING_FACTOR));
+}
+
+// Conversion definition from unscaled to integer 'scaled coord'.
+// TODO: is the rounding necessary ? Here it is to show that it can be different
+// but it does not have to be. Using std::round means loosing noexcept and
+// constexpr modifiers
+template<class Tout = coord_t, class Tin, class = FloatingOnly<Tin>>
+inline SLIC3R_CONSTEXPR ScaledCoordOnly<Tout> scaled(const Tin &v) SLIC3R_NOEXCEPT
{
- static_assert(std::is_integral<X>::value &&
- std::is_integral<Y>::value && sizeof(X) >= sizeof(Y),
- "");
+ //return static_cast<Tout>(std::round(v / SCALING_FACTOR));
+ return static_cast<Tout>(v / static_cast<Tin>(SCALING_FACTOR));
+}
- return (x % y) ? x / y + 1 : x / y;
+// Conversion for Eigen vectors (N dimensional points)
+template<class Tout = coord_t, class Tin, int N, class = FloatingOnly<Tin>>
+inline EigenVec<ArithmeticOnly<Tout>, N> scaled(const EigenVec<Tin, N> &v)
+{
+ return v.template cast<Tout>() / SCALING_FACTOR;
+}
+
+// Conversion from arithmetic scaled type to floating point unscaled
+template<class Tout = double,
+ class Tin,
+ class = ArithmeticOnly<Tin>,
+ class = FloatingOnly<Tout>>
+inline SLIC3R_CONSTEXPR Tout unscaled(const Tin &v) SLIC3R_NOEXCEPT
+{
+ return static_cast<Tout>(v * static_cast<Tout>(SCALING_FACTOR));
+}
+
+// Unscaling for Eigen vectors. Input base type can be arithmetic, output base
+// type can only be floating point.
+template<class Tout = double,
+ class Tin,
+ int N,
+ class = ArithmeticOnly<Tin>,
+ class = FloatingOnly<Tout>>
+inline SLIC3R_CONSTEXPR EigenVec<Tout, N> unscaled(
+ const EigenVec<Tin, N> &v) SLIC3R_NOEXCEPT
+{
+ return v.template cast<Tout>() * SCALING_FACTOR;
}
} // namespace Slic3r
diff --git a/src/libslic3r/MinAreaBoundingBox.cpp b/src/libslic3r/MinAreaBoundingBox.cpp
index 6fc1b3327..fafb54a58 100644
--- a/src/libslic3r/MinAreaBoundingBox.cpp
+++ b/src/libslic3r/MinAreaBoundingBox.cpp
@@ -39,7 +39,7 @@ template<> inline Slic3r::Points& contour(Slic3r::Polygon& sh) { return sh.point
template<> inline const Slic3r::Points& contour(const Slic3r::Polygon& sh) { return sh.points; }
template<> Slic3r::Points::iterator begin(Slic3r::Points& pts, const PathTag&) { return pts.begin();}
-template<> Slic3r::Points::const_iterator cbegin(const Slic3r::Points& pts, const PathTag&) { return pts.begin(); }
+template<> Slic3r::Points::const_iterator cbegin(const Slic3r::Points& pts, const PathTag&) { return pts.cbegin(); }
template<> Slic3r::Points::iterator end(Slic3r::Points& pts, const PathTag&) { return pts.end();}
template<> Slic3r::Points::const_iterator cend(const Slic3r::Points& pts, const PathTag&) { return pts.cend(); }
@@ -71,62 +71,67 @@ using Rational = boost::rational<__int128>;
MinAreaBoundigBox::MinAreaBoundigBox(const Polygon &p, PolygonLevel pc)
{
- const Polygon& chull = pc == pcConvex ? p : libnest2d::sl::convexHull(p);
-
- libnest2d::RotatedBox<Point, Unit> box =
- libnest2d::minAreaBoundingBox<Polygon, Unit, Rational>(chull);
-
- m_right = box.right_extent();
- m_bottom = box.bottom_extent();
- m_axis = box.axis();
+ const Polygon &chull = pc == pcConvex ? p :
+ libnest2d::sl::convexHull(p);
+
+ libnest2d::RotatedBox<Point, Unit> box =
+ libnest2d::minAreaBoundingBox<Polygon, Unit, Rational>(chull);
+
+ m_right = libnest2d::cast<long double>(box.right_extent());
+ m_bottom = libnest2d::cast<long double>(box.bottom_extent());
+ m_axis = box.axis();
}
MinAreaBoundigBox::MinAreaBoundigBox(const ExPolygon &p, PolygonLevel pc)
{
- const ExPolygon& chull = pc == pcConvex ? p : libnest2d::sl::convexHull(p);
-
- libnest2d::RotatedBox<Point, Unit> box =
- libnest2d::minAreaBoundingBox<ExPolygon, Unit, Rational>(chull);
-
- m_right = box.right_extent();
- m_bottom = box.bottom_extent();
- m_axis = box.axis();
+ const ExPolygon &chull = pc == pcConvex ? p :
+ libnest2d::sl::convexHull(p);
+
+ libnest2d::RotatedBox<Point, Unit> box =
+ libnest2d::minAreaBoundingBox<ExPolygon, Unit, Rational>(chull);
+
+ m_right = libnest2d::cast<long double>(box.right_extent());
+ m_bottom = libnest2d::cast<long double>(box.bottom_extent());
+ m_axis = box.axis();
}
MinAreaBoundigBox::MinAreaBoundigBox(const Points &pts, PolygonLevel pc)
{
- const Points& chull = pc == pcConvex ? pts : libnest2d::sl::convexHull(pts);
-
- libnest2d::RotatedBox<Point, Unit> box =
- libnest2d::minAreaBoundingBox<Points, Unit, Rational>(chull);
-
- m_right = box.right_extent();
- m_bottom = box.bottom_extent();
- m_axis = box.axis();
+ const Points &chull = pc == pcConvex ? pts :
+ libnest2d::sl::convexHull(pts);
+
+ libnest2d::RotatedBox<Point, Unit> box =
+ libnest2d::minAreaBoundingBox<Points, Unit, Rational>(chull);
+
+ m_right = libnest2d::cast<long double>(box.right_extent());
+ m_bottom = libnest2d::cast<long double>(box.bottom_extent());
+ m_axis = box.axis();
}
double MinAreaBoundigBox::angle_to_X() const
{
double ret = std::atan2(m_axis.y(), m_axis.x());
- auto s = std::signbit(ret);
- if(s) ret += 2 * PI;
+ auto s = std::signbit(ret);
+ if (s) ret += 2 * PI;
return -ret;
}
long double MinAreaBoundigBox::width() const
{
- return std::abs(m_bottom) / std::sqrt(libnest2d::pl::magnsq<Point, long double>(m_axis));
+ return std::abs(m_bottom) /
+ std::sqrt(libnest2d::pl::magnsq<Point, long double>(m_axis));
}
long double MinAreaBoundigBox::height() const
{
- return std::abs(m_right) / std::sqrt(libnest2d::pl::magnsq<Point, long double>(m_axis));
+ return std::abs(m_right) /
+ std::sqrt(libnest2d::pl::magnsq<Point, long double>(m_axis));
}
long double MinAreaBoundigBox::area() const
{
long double asq = libnest2d::pl::magnsq<Point, long double>(m_axis);
- return m_bottom * m_right / asq;
+ return m_bottom * m_right / asq;
}
void remove_collinear_points(Polygon &p)
@@ -138,5 +143,4 @@ void remove_collinear_points(ExPolygon &p)
{
p = libnest2d::removeCollinearPoints<ExPolygon>(p, Unit(0));
}
-
-}
+} // namespace Slic3r
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index fbf10bf83..0c29aa721 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -631,7 +631,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
assert(this->config.id() == rhs.config.id());
this->sla_support_points = rhs.sla_support_points;
this->sla_points_status = rhs.sla_points_status;
- this->layer_height_ranges = rhs.layer_height_ranges;
+ this->layer_config_ranges = rhs.layer_config_ranges; // #ys_FIXME_experiment
this->layer_height_profile = rhs.layer_height_profile;
this->origin_translation = rhs.origin_translation;
m_bounding_box = rhs.m_bounding_box;
@@ -670,7 +670,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
assert(this->config.id() == rhs.config.id());
this->sla_support_points = std::move(rhs.sla_support_points);
this->sla_points_status = std::move(rhs.sla_points_status);
- this->layer_height_ranges = std::move(rhs.layer_height_ranges);
+ this->layer_config_ranges = std::move(rhs.layer_config_ranges); // #ys_FIXME_experiment
this->layer_height_profile = std::move(rhs.layer_height_profile);
this->origin_translation = std::move(rhs.origin_translation);
m_bounding_box = std::move(rhs.m_bounding_box);
@@ -1578,8 +1578,10 @@ void ModelVolume::center_geometry_after_creation()
Vec3d shift = this->mesh().bounding_box().center();
if (!shift.isApprox(Vec3d::Zero()))
{
- const_cast<TriangleMesh*>(m_mesh.get())->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
- const_cast<TriangleMesh*>(m_convex_hull.get())->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
+ if (m_mesh)
+ m_mesh->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
+ if (m_convex_hull)
+ m_convex_hull->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
translate(shift);
}
}
@@ -1857,7 +1859,7 @@ bool model_volume_list_changed(const ModelObject &model_object_old, const ModelO
if (!mv_old.get_matrix().isApprox(mv_new.get_matrix()))
return true;
- ++i_old;
+ ++ i_old;
++ i_new;
}
for (; i_old < model_object_old.volumes.size(); ++ i_old) {
diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp
index 0c4c2ed2b..0a50315ce 100644
--- a/src/libslic3r/Model.hpp
+++ b/src/libslic3r/Model.hpp
@@ -160,8 +160,8 @@ public:
ModelVolumePtrs volumes;
// Configuration parameters specific to a single ModelObject, overriding the global Slic3r settings.
ModelConfig config;
- // Variation of a layer thickness for spans of Z coordinates.
- t_layer_height_ranges layer_height_ranges;
+ // Variation of a layer thickness for spans of Z coordinates + optional parameter overrides.
+ t_layer_config_ranges layer_config_ranges;
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
// The pairs of <z, layer_height> are packed into a 1D array.
std::vector<coordf_t> layer_height_profile;
diff --git a/src/libslic3r/ModelArrange.cpp b/src/libslic3r/ModelArrange.cpp
index 36f7e3971..d3586651b 100644
--- a/src/libslic3r/ModelArrange.cpp
+++ b/src/libslic3r/ModelArrange.cpp
@@ -62,10 +62,10 @@ std::string toString(const Model& model, bool holes = true) {
objinst->transform_mesh(&tmpmesh);
ExPolygons expolys = tmpmesh.horizontal_projection();
for(auto& expoly_complex : expolys) {
-
- auto tmp = expoly_complex.simplify(1.0/SCALING_FACTOR);
+
+ ExPolygons tmp = expoly_complex.simplify(scaled<double>(1.));
if(tmp.empty()) continue;
- auto expoly = tmp.front();
+ ExPolygon expoly = tmp.front();
expoly.contour.make_clockwise();
for(auto& h : expoly.holes) h.make_counter_clockwise();
@@ -610,7 +610,7 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model,
if(tolerance > EPSILON) {
Polygons pp { p };
- pp = p.simplify(double(scaled(tolerance)));
+ pp = p.simplify(scaled<double>(tolerance));
if (!pp.empty()) p = pp.front();
}
@@ -633,8 +633,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model,
if(item.vertexCount() > 3) {
item.rotation(Geometry::rotation_diff_z(rotation0, objinst->get_rotation()));
item.translation({
- ClipperLib::cInt(objinst->get_offset(X)/SCALING_FACTOR),
- ClipperLib::cInt(objinst->get_offset(Y)/SCALING_FACTOR)
+ scaled<ClipperLib::cInt>(objinst->get_offset(X)),
+ scaled<ClipperLib::cInt>(objinst->get_offset(Y))
});
ret.emplace_back(objinst, item);
}
@@ -658,8 +658,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model,
Item item(std::move(pn));
item.rotation(wti.rotation),
item.translation({
- ClipperLib::cInt(wti.pos(0)/SCALING_FACTOR),
- ClipperLib::cInt(wti.pos(1)/SCALING_FACTOR)
+ scaled<ClipperLib::cInt>(wti.pos(0)),
+ scaled<ClipperLib::cInt>(wti.pos(1))
});
ret.emplace_back(nullptr, item);
}
@@ -822,7 +822,9 @@ bool arrange(Model &model, // The model with the geometries
auto& cfn = stopcondition;
- coord_t md = ceil_i(min_obj_distance, 2) - SCALED_EPSILON;
+ // Integer ceiling the min distance from the bed perimeters
+ coord_t md = min_obj_distance - SCALED_EPSILON;
+ md = (md % 2) ? md / 2 + 1 : md / 2;
auto binbb = Box({libnest2d::Coord{bbb.min(0)} - md,
libnest2d::Coord{bbb.min(1)} - md},
@@ -916,7 +918,9 @@ void find_new_position(const Model &model,
BoundingBox bbb(bed);
- coord_t md = ceil_i(min_obj_distance, 2) - SCALED_EPSILON;
+ // Integer ceiling the min distance from the bed perimeters
+ coord_t md = min_obj_distance - SCALED_EPSILON;
+ md = (md % 2) ? md / 2 + 1 : md / 2;
auto binbb = Box({libnest2d::Coord{bbb.min(0)} - md,
libnest2d::Coord{bbb.min(1)} - md},
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index e545b9b7b..122034c53 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -12,6 +12,8 @@
//#include "PrintExport.hpp"
+#include <float.h>
+
#include <algorithm>
#include <limits>
#include <unordered_set>
@@ -41,36 +43,6 @@ void Print::clear()
m_model.clear_objects();
}
-// Only used by the Perl test cases.
-void Print::reload_object(size_t /* idx */)
-{
- ModelObjectPtrs model_objects;
- {
- tbb::mutex::scoped_lock lock(this->state_mutex());
- // The following call should stop background processing if it is running.
- this->invalidate_all_steps();
- /* TODO: this method should check whether the per-object config and per-material configs
- have changed in such a way that regions need to be rearranged or we can just apply
- the diff and invalidate something. Same logic as apply()
- For now we just re-add all objects since we haven't implemented this incremental logic yet.
- This should also check whether object volumes (parts) have changed. */
- // collect all current model objects
- model_objects.reserve(m_objects.size());
- for (PrintObject *object : m_objects)
- model_objects.push_back(object->model_object());
- // remove our print objects
- for (PrintObject *object : m_objects)
- delete object;
- m_objects.clear();
- for (PrintRegion *region : m_regions)
- delete region;
- m_regions.clear();
- }
- // re-add model objects
- for (ModelObject *mo : model_objects)
- this->add_model_object(mo);
-}
-
PrintRegion* Print::add_region()
{
m_regions.emplace_back(new PrintRegion(this));
@@ -335,7 +307,7 @@ unsigned int Print::num_object_instances() const
{
unsigned int instances = 0;
for (const PrintObject *print_object : m_objects)
- instances += print_object->copies().size();
+ instances += (unsigned int)print_object->copies().size();
return instances;
}
@@ -358,198 +330,6 @@ double Print::max_allowed_layer_height() const
return nozzle_diameter_max;
}
-// Caller is responsible for supplying models whose objects don't collide
-// and have explicit instance positions.
-void Print::add_model_object(ModelObject* model_object, int idx)
-{
- tbb::mutex::scoped_lock lock(this->state_mutex());
- // Add a copy of this ModelObject to this Print.
- m_model.objects.emplace_back(ModelObject::new_copy(*model_object));
- m_model.objects.back()->set_model(&m_model);
- // Initialize a new print object and store it at the given position.
- PrintObject *object = new PrintObject(this, model_object, true);
- if (idx != -1) {
- delete m_objects[idx];
- m_objects[idx] = object;
- } else
- m_objects.emplace_back(object);
- // Invalidate all print steps.
- this->invalidate_all_steps();
-
- // Set the transformation matrix without translation from the first instance.
- if (! model_object->instances.empty()) {
- // Trafo and bounding box, both in world coordinate system.
- Transform3d trafo = model_object->instances.front()->get_matrix();
- BoundingBoxf3 bbox = model_object->instance_bounding_box(0);
- // Now shift the object up to align it with the print bed.
- trafo.data()[14] -= bbox.min(2);
- // and reset the XY translation.
- trafo.data()[12] = 0;
- trafo.data()[13] = 0;
- object->set_trafo(trafo);
- }
-
- size_t volume_id = 0;
- for (const ModelVolume *volume : model_object->volumes) {
- if (! volume->is_model_part() && ! volume->is_modifier())
- continue;
- // Get the config applied to this volume.
- PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, *volume, 99999);
- // Find an existing print region with the same config.
- size_t region_id = size_t(-1);
- for (size_t i = 0; i < m_regions.size(); ++ i)
- if (config.equals(m_regions[i]->config())) {
- region_id = i;
- break;
- }
- // If no region exists with the same config, create a new one.
- if (region_id == size_t(-1)) {
- region_id = m_regions.size();
- this->add_region(config);
- }
- // Assign volume to a region.
- object->add_region_volume(region_id, volume_id);
- ++ volume_id;
- }
-
- // Apply config to print object.
- object->config_apply(this->default_object_config());
- {
- //normalize_and_apply_config(object->config(), model_object->config);
- DynamicPrintConfig src_normalized(model_object->config);
- src_normalized.normalize();
- object->config_apply(src_normalized, true);
- }
-}
-
-// This function is only called through the Perl-C++ binding from the unit tests, should be
-// removed when unit tests are rewritten to C++.
-bool Print::apply_config_perl_tests_only(DynamicPrintConfig config)
-{
- tbb::mutex::scoped_lock lock(this->state_mutex());
-
-
- // Perl unit tests were failing in case the preset was not normalized (e.g. https://github.com/prusa3d/PrusaSlicer/issues/2288 was caused
- // by too short max_layer_height vector. Calling the necessary function Preset::normalize(...) is not currently possible because there is no
- // access to preset. This should be solved when the unit tests are rewritten to C++. For now we just copy-pasted code from Preset.cpp
- // to make sure the unit tests pass (functions set_num_extruders and nozzle_options()).
- auto *nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(config.option("nozzle_diameter", true));
- assert(nozzle_diameter != nullptr);
- const auto &defaults = FullPrintConfig::defaults();
- for (const std::string &key : { "nozzle_diameter", "min_layer_height", "max_layer_height", "extruder_offset",
- "retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed",
- "retract_before_wipe", "retract_restart_extra", "retract_before_travel", "wipe",
- "retract_layer_change", "retract_length_toolchange", "retract_restart_extra_toolchange", "extruder_colour" })
- {
- auto *opt = config.option(key, true);
- assert(opt != nullptr);
- assert(opt->is_vector());
- unsigned int num_extruders = (unsigned int)nozzle_diameter->values.size();
- static_cast<ConfigOptionVectorBase*>(opt)->resize(num_extruders, defaults.option(key));
- }
-
- // we get a copy of the config object so we can modify it safely
- config.normalize();
-
- // apply variables to placeholder parser
- this->placeholder_parser().apply_config(config);
-
- // handle changes to print config
- t_config_option_keys print_diff = m_config.diff(config);
- m_config.apply_only(config, print_diff, true);
- bool invalidated = this->invalidate_state_by_config_options(print_diff);
-
- // handle changes to object config defaults
- m_default_object_config.apply(config, true);
- for (PrintObject *object : m_objects) {
- // we don't assume that config contains a full ObjectConfig,
- // so we base it on the current print-wise default
- PrintObjectConfig new_config = this->default_object_config();
- // we override the new config with object-specific options
- normalize_and_apply_config(new_config, object->model_object()->config);
- // check whether the new config is different from the current one
- t_config_option_keys diff = object->config().diff(new_config);
- object->config_apply_only(new_config, diff, true);
- invalidated |= object->invalidate_state_by_config_options(diff);
- }
-
- // handle changes to regions config defaults
- m_default_region_config.apply(config, true);
-
- // All regions now have distinct settings.
- // Check whether applying the new region config defaults we'd get different regions.
- bool rearrange_regions = false;
- {
- // Collect the already visited region configs into other_region_configs,
- // so one may check for duplicates.
- std::vector<PrintRegionConfig> other_region_configs;
- for (size_t region_id = 0; region_id < m_regions.size(); ++ region_id) {
- PrintRegion &region = *m_regions[region_id];
- PrintRegionConfig this_region_config;
- bool this_region_config_set = false;
- for (PrintObject *object : m_objects) {
- if (region_id < object->region_volumes.size()) {
- for (int volume_id : object->region_volumes[region_id]) {
- const ModelVolume &volume = *object->model_object()->volumes[volume_id];
- if (this_region_config_set) {
- // If the new config for this volume differs from the other
- // volume configs currently associated to this region, it means
- // the region subdivision does not make sense anymore.
- if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, volume, 99999))) {
- rearrange_regions = true;
- goto exit_for_rearrange_regions;
- }
- } else {
- this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, volume, 99999);
- this_region_config_set = true;
- }
- for (const PrintRegionConfig &cfg : other_region_configs) {
- // If the new config for this volume equals any of the other
- // volume configs that are not currently associated to this
- // region, it means the region subdivision does not make
- // sense anymore.
- if (cfg.equals(this_region_config)) {
- rearrange_regions = true;
- goto exit_for_rearrange_regions;
- }
- }
- }
- }
- }
- if (this_region_config_set) {
- t_config_option_keys diff = region.config().diff(this_region_config);
- if (! diff.empty()) {
- region.config_apply_only(this_region_config, diff, false);
- for (PrintObject *object : m_objects)
- if (region_id < object->region_volumes.size() && ! object->region_volumes[region_id].empty())
- invalidated |= object->invalidate_state_by_config_options(diff);
- }
- other_region_configs.emplace_back(std::move(this_region_config));
- }
- }
- }
-
-exit_for_rearrange_regions:
-
- if (rearrange_regions) {
- // The current subdivision of regions does not make sense anymore.
- // We need to remove all objects and re-add them.
- ModelObjectPtrs model_objects;
- model_objects.reserve(m_objects.size());
- for (PrintObject *object : m_objects)
- model_objects.push_back(object->model_object());
- this->clear();
- for (ModelObject *mo : model_objects)
- this->add_model_object(mo);
- invalidated = true;
- }
-
- for (PrintObject *object : m_objects)
- object->update_slicing_parameters();
-
- return invalidated;
-}
-
// Add or remove support modifier ModelVolumes from model_object_dst to match the ModelVolumes of model_object_new
// in the exact order and with the same IDs.
// It is expected, that the model_object_dst already contains the non-support volumes of model_object_new in the correct order.
@@ -620,6 +400,20 @@ static inline void model_volume_list_copy_configs(ModelObject &model_object_dst,
}
}
+static inline void layer_height_ranges_copy_configs(t_layer_config_ranges &lr_dst, const t_layer_config_ranges &lr_src)
+{
+ assert(lr_dst.size() == lr_src.size());
+ auto it_src = lr_src.cbegin();
+ for (auto &kvp_dst : lr_dst) {
+ const auto &kvp_src = *it_src ++;
+ assert(std::abs(kvp_dst.first.first - kvp_src.first.first ) <= EPSILON);
+ assert(std::abs(kvp_dst.first.second - kvp_src.first.second) <= EPSILON);
+ // Layer heights are allowed do differ in case the layer height table is being overriden by the smooth profile.
+ // assert(std::abs(kvp_dst.second.option("layer_height")->getFloat() - kvp_src.second.option("layer_height")->getFloat()) <= EPSILON);
+ kvp_dst.second = kvp_src.second;
+ }
+}
+
static inline bool transform3d_lower(const Transform3d &lhs, const Transform3d &rhs)
{
typedef Transform3d::Scalar T;
@@ -674,6 +468,23 @@ static std::vector<PrintInstances> print_objects_from_model_object(const ModelOb
return std::vector<PrintInstances>(trafos.begin(), trafos.end());
}
+// Compare just the layer ranges and their layer heights, not the associated configs.
+// Ignore the layer heights if check_layer_heights is false.
+bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_layer_config_ranges &lr2, bool check_layer_height)
+{
+ if (lr1.size() != lr2.size())
+ return false;
+ auto it2 = lr2.begin();
+ for (const auto &kvp1 : lr1) {
+ const auto &kvp2 = *it2 ++;
+ if (std::abs(kvp1.first.first - kvp2.first.first ) > EPSILON ||
+ std::abs(kvp1.first.second - kvp2.first.second) > EPSILON ||
+ (check_layer_height && std::abs(kvp1.second.option("layer_height")->getFloat() - kvp2.second.option("layer_height")->getFloat()) > EPSILON))
+ return false;
+ }
+ return true;
+}
+
Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &config_in)
{
#ifdef _DEBUG
@@ -724,6 +535,50 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
// Handle changes to regions config defaults
m_default_region_config.apply_only(config, region_diff, true);
+ class LayerRanges
+ {
+ public:
+ LayerRanges() {}
+ // Convert input config ranges into continuous non-overlapping sorted vector of intervals and their configs.
+ void assign(const t_layer_config_ranges &in) {
+ m_ranges.clear();
+ m_ranges.reserve(in.size());
+ // Input ranges are sorted lexicographically. First range trims the other ranges.
+ coordf_t last_z = 0;
+ for (const std::pair<const t_layer_height_range, DynamicPrintConfig> &range : in) {
+// for (auto &range : in) {
+ if (range.first.second > last_z) {
+ coordf_t min_z = std::max(range.first.first, 0.);
+ if (min_z > last_z + EPSILON) {
+ m_ranges.emplace_back(t_layer_height_range(last_z, min_z), nullptr);
+ last_z = min_z;
+ }
+ if (range.first.second > last_z + EPSILON) {
+ const DynamicPrintConfig* cfg = &range.second;
+ m_ranges.emplace_back(t_layer_height_range(last_z, range.first.second), cfg);
+ last_z = range.first.second;
+ }
+ }
+ }
+ if (m_ranges.empty())
+ m_ranges.emplace_back(t_layer_height_range(0, DBL_MAX), nullptr);
+ else if (m_ranges.back().second == nullptr)
+ m_ranges.back().first.second = DBL_MAX;
+ else
+ m_ranges.emplace_back(t_layer_height_range(m_ranges.back().first.second, DBL_MAX), nullptr);
+ }
+ const DynamicPrintConfig* config(const t_layer_height_range &range) const {
+ auto it = std::lower_bound(m_ranges.begin(), m_ranges.end(), std::make_pair< t_layer_height_range, const DynamicPrintConfig*>(t_layer_height_range(range.first - EPSILON, range.second - EPSILON), nullptr));
+ assert(it != m_ranges.end());
+ assert(it == m_ranges.end() || std::abs(it->first.first - range.first ) < EPSILON);
+ assert(it == m_ranges.end() || std::abs(it->first.second - range.second) < EPSILON);
+ return (it == m_ranges.end()) ? nullptr : it->second;
+ }
+ std::vector<std::pair<t_layer_height_range, const DynamicPrintConfig*>>::const_iterator begin() const { return m_ranges.cbegin(); }
+ std::vector<std::pair<t_layer_height_range, const DynamicPrintConfig*>>::const_iterator end() const { return m_ranges.cend(); }
+ private:
+ std::vector<std::pair<t_layer_height_range, const DynamicPrintConfig*>> m_ranges;
+ };
struct ModelObjectStatus {
enum Status {
Unknown,
@@ -732,9 +587,10 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
Moved,
Deleted,
};
- ModelObjectStatus(ObjectID id, Status status = Unknown) : id(id), status(status) {}
- ObjectID id;
- Status status;
+ ModelObjectStatus(ModelID id, Status status = Unknown) : id(id), status(status) {}
+ ModelID id;
+ Status status;
+ LayerRanges layer_ranges;
// Search by id.
bool operator<(const ModelObjectStatus &rhs) const { return id < rhs.id; }
};
@@ -861,21 +717,23 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
auto it_status = model_object_status.find(ModelObjectStatus(model_object.id()));
assert(it_status != model_object_status.end());
assert(it_status->status != ModelObjectStatus::Deleted);
+ const ModelObject& model_object_new = *model.objects[idx_model_object];
+ const_cast<ModelObjectStatus&>(*it_status).layer_ranges.assign(model_object_new.layer_config_ranges);
if (it_status->status == ModelObjectStatus::New)
// PrintObject instances will be added in the next loop.
continue;
// Update the ModelObject instance, possibly invalidate the linked PrintObjects.
assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved);
- const ModelObject &model_object_new = *model.objects[idx_model_object];
// Check whether a model part volume was added or removed, their transformations or order changed.
+ // Only volume IDs, volume types and their order are checked, configuration and other parameters are NOT checked.
bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART);
bool modifiers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::PARAMETER_MODIFIER);
bool support_blockers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_BLOCKER);
bool support_enforcers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER);
if (model_parts_differ || modifiers_differ ||
model_object.origin_translation != model_object_new.origin_translation ||
- model_object.layer_height_ranges != model_object_new.layer_height_ranges ||
- model_object.layer_height_profile != model_object_new.layer_height_profile) {
+ model_object.layer_height_profile != model_object_new.layer_height_profile ||
+ ! layer_height_ranges_equal(model_object.layer_config_ranges, model_object_new.layer_config_ranges, model_object_new.layer_height_profile.empty())) {
// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
for (auto it = range.first; it != range.second; ++ it) {
@@ -915,7 +773,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
//FIXME What to do with m_material_id?
model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::MODEL_PART);
model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::PARAMETER_MODIFIER);
- // Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
+ layer_height_ranges_copy_configs(model_object.layer_config_ranges /* dst */, model_object_new.layer_config_ranges /* src */);
+ // Copy the ModelObject name, input_file and instances. The instances will be compared against PrintObject instances in the next step.
model_object.name = model_object_new.name;
model_object.input_file = model_object_new.input_file;
model_object.clear_instances();
@@ -1027,19 +886,27 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
PrintRegionConfig this_region_config;
bool this_region_config_set = false;
for (PrintObject *print_object : m_objects) {
+ const LayerRanges *layer_ranges;
+ {
+ auto it_status = model_object_status.find(ModelObjectStatus(print_object->model_object()->id()));
+ assert(it_status != model_object_status.end());
+ assert(it_status->status != ModelObjectStatus::Deleted);
+ layer_ranges = &it_status->layer_ranges;
+ }
if (region_id < print_object->region_volumes.size()) {
- for (int volume_id : print_object->region_volumes[region_id]) {
- const ModelVolume &volume = *print_object->model_object()->volumes[volume_id];
+ for (const std::pair<t_layer_height_range, int> &volume_and_range : print_object->region_volumes[region_id]) {
+ const ModelVolume &volume = *print_object->model_object()->volumes[volume_and_range.second];
+ const DynamicPrintConfig *layer_range_config = layer_ranges->config(volume_and_range.first);
if (this_region_config_set) {
// If the new config for this volume differs from the other
// volume configs currently associated to this region, it means
// the region subdivision does not make sense anymore.
- if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, volume, num_extruders)))
+ if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, layer_range_config, volume, num_extruders)))
// Regions were split. Reset this print_object.
goto print_object_end;
} else {
- this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, volume, num_extruders);
- for (size_t i = 0; i < region_id; ++i) {
+ this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, layer_range_config, volume, num_extruders);
+ for (size_t i = 0; i < region_id; ++ i) {
const PrintRegion &region_other = *m_regions[i];
if (region_other.m_refcnt != 0 && region_other.config().equals(this_region_config))
// Regions were merged. Reset this print_object.
@@ -1054,7 +921,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
update_apply_status(print_object->invalidate_all_steps());
// Decrease the references to regions from this volume.
int ireg = 0;
- for (const std::vector<int> &volumes : print_object->region_volumes) {
+ for (const std::vector<std::pair<t_layer_height_range, int>> &volumes : print_object->region_volumes) {
if (! volumes.empty())
-- m_regions[ireg]->m_refcnt;
++ ireg;
@@ -1076,52 +943,65 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
for (size_t idx_print_object = 0; idx_print_object < m_objects.size(); ++ idx_print_object) {
PrintObject &print_object0 = *m_objects[idx_print_object];
const ModelObject &model_object = *print_object0.model_object();
- std::vector<int> map_volume_to_region(model_object.volumes.size(), -1);
+ const LayerRanges *layer_ranges;
+ {
+ auto it_status = model_object_status.find(ModelObjectStatus(model_object.id()));
+ assert(it_status != model_object_status.end());
+ assert(it_status->status != ModelObjectStatus::Deleted);
+ layer_ranges = &it_status->layer_ranges;
+ }
+ std::vector<int> regions_in_object;
+ regions_in_object.reserve(64);
for (size_t i = idx_print_object; i < m_objects.size() && m_objects[i]->model_object() == &model_object; ++ i) {
PrintObject &print_object = *m_objects[i];
bool fresh = print_object.region_volumes.empty();
unsigned int volume_id = 0;
+ unsigned int idx_region_in_object = 0;
for (const ModelVolume *volume : model_object.volumes) {
if (! volume->is_model_part() && ! volume->is_modifier()) {
++ volume_id;
continue;
}
- int region_id = -1;
- if (&print_object == &print_object0) {
- // Get the config applied to this volume.
- PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, *volume, num_extruders);
- // Find an existing print region with the same config.
- int idx_empty_slot = -1;
- for (int i = 0; i < (int)m_regions.size(); ++ i) {
- if (m_regions[i]->m_refcnt == 0) {
- if (idx_empty_slot == -1)
- idx_empty_slot = i;
- } else if (config.equals(m_regions[i]->config())) {
- region_id = i;
- break;
+ // Filter the layer ranges, so they do not overlap and they contain at least a single layer.
+ // Now insert a volume with a layer range to its own region.
+ for (auto it_range = layer_ranges->begin(); it_range != layer_ranges->end(); ++ it_range) {
+ int region_id = -1;
+ if (&print_object == &print_object0) {
+ // Get the config applied to this volume.
+ PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, it_range->second, *volume, num_extruders);
+ // Find an existing print region with the same config.
+ int idx_empty_slot = -1;
+ for (int i = 0; i < (int)m_regions.size(); ++ i) {
+ if (m_regions[i]->m_refcnt == 0) {
+ if (idx_empty_slot == -1)
+ idx_empty_slot = i;
+ } else if (config.equals(m_regions[i]->config())) {
+ region_id = i;
+ break;
+ }
+ }
+ // If no region exists with the same config, create a new one.
+ if (region_id == -1) {
+ if (idx_empty_slot == -1) {
+ region_id = (int)m_regions.size();
+ this->add_region(config);
+ } else {
+ region_id = idx_empty_slot;
+ m_regions[region_id]->set_config(std::move(config));
+ }
}
- }
- // If no region exists with the same config, create a new one.
- if (region_id == -1) {
- if (idx_empty_slot == -1) {
- region_id = (int)m_regions.size();
- this->add_region(config);
- } else {
- region_id = idx_empty_slot;
- m_regions[region_id]->set_config(std::move(config));
- }
- }
- map_volume_to_region[volume_id] = region_id;
- } else
- region_id = map_volume_to_region[volume_id];
- // Assign volume to a region.
- if (fresh) {
- if (region_id >= print_object.region_volumes.size() || print_object.region_volumes[region_id].empty())
- ++ m_regions[region_id]->m_refcnt;
- print_object.add_region_volume(region_id, volume_id);
- }
- ++ volume_id;
- }
+ regions_in_object.emplace_back(region_id);
+ } else
+ region_id = regions_in_object[idx_region_in_object ++];
+ // Assign volume to a region.
+ if (fresh) {
+ if (region_id >= print_object.region_volumes.size() || print_object.region_volumes[region_id].empty())
+ ++ m_regions[region_id]->m_refcnt;
+ print_object.add_region_volume(region_id, volume_id, it_range->first);
+ }
+ }
+ ++ volume_id;
+ }
}
}
@@ -1175,9 +1055,9 @@ std::string Print::validate() const
Polygon convex_hull0 = offset(
print_object->model_object()->convex_hull_2d(
Geometry::assemble_transform(Vec3d::Zero(), rotation, model_instance0->get_scaling_factor(), model_instance0->get_mirror())),
- scale_(m_config.extruder_clearance_radius.value) / 2., jtRound, scale_(0.1)).front();
+ float(scale_(0.5 * m_config.extruder_clearance_radius.value)), jtRound, float(scale_(0.1))).front();
// Now we check that no instance of convex_hull intersects any of the previously checked object instances.
- for (const Point &copy : print_object->m_copies) {
+ for (const Point &copy : print_object->copies()) {
Polygon convex_hull = convex_hull0;
convex_hull.translate(copy);
if (! intersection(convex_hulls_other, convex_hull).empty())
@@ -1227,7 +1107,7 @@ std::string Print::validate() const
bool has_custom_layering = false;
std::vector<std::vector<coordf_t>> layer_height_profiles;
for (const PrintObject *object : m_objects) {
- has_custom_layering = ! object->model_object()->layer_height_ranges.empty() || ! object->model_object()->layer_height_profile.empty();
+ has_custom_layering = ! object->model_object()->layer_config_ranges.empty() || ! object->model_object()->layer_height_profile.empty(); // #ys_FIXME_experiment
if (has_custom_layering) {
layer_height_profiles.assign(m_objects.size(), std::vector<coordf_t>());
break;
@@ -1435,9 +1315,9 @@ Flow Print::brim_flow() const
generation as well. */
return Flow::new_from_config_width(
frPerimeter,
- width,
- m_config.nozzle_diameter.get_at(m_regions.front()->config().perimeter_extruder-1),
- this->skirt_first_layer_height(),
+ width,
+ (float)m_config.nozzle_diameter.get_at(m_regions.front()->config().perimeter_extruder-1),
+ (float)this->skirt_first_layer_height(),
0
);
}
@@ -1457,9 +1337,9 @@ Flow Print::skirt_flow() const
generation as well. */
return Flow::new_from_config_width(
frPerimeter,
- width,
- m_config.nozzle_diameter.get_at(m_objects.front()->config().support_material_extruder-1),
- this->skirt_first_layer_height(),
+ width,
+ (float)m_config.nozzle_diameter.get_at(m_objects.front()->config().support_material_extruder-1),
+ (float)this->skirt_first_layer_height(),
0
);
}
@@ -1634,20 +1514,20 @@ void Print::_make_skirt()
// Initial offset of the brim inner edge from the object (possible with a support & raft).
// The skirt will touch the brim if the brim is extruded.
- Flow brim_flow = this->brim_flow();
+ Flow brim_flow = this->brim_flow();
double actual_brim_width = brim_flow.spacing() * floor(m_config.brim_width.value / brim_flow.spacing());
- coord_t distance = scale_(std::max(m_config.skirt_distance.value, actual_brim_width) - spacing/2.);
+ auto distance = float(scale_(std::max(m_config.skirt_distance.value, actual_brim_width) - spacing/2.));
// Draw outlines from outside to inside.
// Loop while we have less skirts than required or any extruder hasn't reached the min length if any.
std::vector<coordf_t> extruded_length(extruders.size(), 0.);
for (int i = n_skirts, extruder_idx = 0; i > 0; -- i) {
this->throw_if_canceled();
// Offset the skirt outside.
- distance += coord_t(scale_(spacing));
+ distance += float(scale_(spacing));
// Generate the skirt centerline.
Polygon loop;
{
- Polygons loops = offset(convex_hull, distance, ClipperLib::jtRound, scale_(0.1));
+ Polygons loops = offset(convex_hull, distance, ClipperLib::jtRound, float(scale_(0.1)));
Geometry::simplify_polygons(loops, scale_(0.05), &loops);
if (loops.empty())
break;
@@ -1658,9 +1538,9 @@ void Print::_make_skirt()
eloop.paths.emplace_back(ExtrusionPath(
ExtrusionPath(
erSkirt,
- mm3_per_mm, // this will be overridden at G-code export time
+ (float)mm3_per_mm, // this will be overridden at G-code export time
flow.width,
- first_layer_height // this will be overridden at G-code export time
+ (float)first_layer_height // this will be overridden at G-code export time
)));
eloop.paths.back().polyline = loop.split_at_first_point();
m_skirt.append(eloop);
@@ -1786,7 +1666,7 @@ void Print::_make_wipe_tower()
// Insert the new support layer.
double height = lt.print_z - m_wipe_tower_data.tool_ordering.layer_tools()[i-1].print_z;
//FIXME the support layer ID is set to -1, as Vojtech hopes it is not being used anyway.
- it_layer = m_objects.front()->insert_support_layer(it_layer, size_t(-1), height, lt.print_z, lt.print_z - 0.5 * height);
+ it_layer = m_objects.front()->insert_support_layer(it_layer, -1, height, lt.print_z, lt.print_z - 0.5 * height);
++ it_layer;
}
}
@@ -1813,19 +1693,19 @@ void Print::_make_wipe_tower()
WipeTowerPrusaMM::parse_material(m_config.filament_type.get_at(i).c_str()),
m_config.temperature.get_at(i),
m_config.first_layer_temperature.get_at(i),
- m_config.filament_loading_speed.get_at(i),
- m_config.filament_loading_speed_start.get_at(i),
- m_config.filament_unloading_speed.get_at(i),
- m_config.filament_unloading_speed_start.get_at(i),
- m_config.filament_toolchange_delay.get_at(i),
+ (float)m_config.filament_loading_speed.get_at(i),
+ (float)m_config.filament_loading_speed_start.get_at(i),
+ (float)m_config.filament_unloading_speed.get_at(i),
+ (float)m_config.filament_unloading_speed_start.get_at(i),
+ (float)m_config.filament_toolchange_delay.get_at(i),
m_config.filament_cooling_moves.get_at(i),
- m_config.filament_cooling_initial_speed.get_at(i),
- m_config.filament_cooling_final_speed.get_at(i),
+ (float)m_config.filament_cooling_initial_speed.get_at(i),
+ (float)m_config.filament_cooling_final_speed.get_at(i),
m_config.filament_ramming_parameters.get_at(i),
- m_config.nozzle_diameter.get_at(i));
+ (float)m_config.nozzle_diameter.get_at(i));
m_wipe_tower_data.priming = Slic3r::make_unique<WipeTower::ToolChangeResult>(
- wipe_tower.prime(this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false));
+ wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false));
// Lets go through the wipe tower layers and determine pairs of extruder changes for each
// to pass to wipe_tower (so that it can use it for planning the layout of the tower)
@@ -1834,21 +1714,21 @@ void Print::_make_wipe_tower()
for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers
if (!layer_tools.has_wipe_tower) continue;
bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front();
- wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id,false);
+ wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id, false);
for (const auto extruder_id : layer_tools.extruders) {
if ((first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || extruder_id != current_extruder_id) {
float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange
// Not all of that can be used for infill purging:
- volume_to_wipe -= m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id);
+ volume_to_wipe -= (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id);
// try to assign some infills/objects for the wiping:
volume_to_wipe = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_extruder_id, extruder_id, volume_to_wipe);
// add back the minimal amount toforce on the wipe tower:
- volume_to_wipe += m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id);
+ volume_to_wipe += (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id);
// request a toolchange at the wipe tower with at least volume_to_wipe purging amount
- wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id,
+ wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id,
first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back(), volume_to_wipe);
current_extruder_id = extruder_id;
}
diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp
index 53d6d692d..c3fa5e062 100644
--- a/src/libslic3r/Print.hpp
+++ b/src/libslic3r/Print.hpp
@@ -80,8 +80,8 @@ private: // Prevents erroneous use by other classes.
typedef PrintObjectBaseWithState<Print, PrintObjectStep, posCount> Inherited;
public:
- // vector of (vectors of volume ids), indexed by region_id
- std::vector<std::vector<int>> region_volumes;
+ // vector of (layer height ranges and vectors of volume ids), indexed by region_id
+ std::vector<std::vector<std::pair<t_layer_height_range, int>>> region_volumes;
// this is set to true when LayerRegion->slices is split in top/internal/bottom
// so that next call to make_perimeters() performs a union() before computing loops
@@ -99,10 +99,10 @@ public:
BoundingBox bounding_box() const { return BoundingBox(Point(0,0), to_2d(this->size)); }
// adds region_id, too, if necessary
- void add_region_volume(unsigned int region_id, int volume_id) {
+ void add_region_volume(unsigned int region_id, int volume_id, const t_layer_height_range &layer_range) {
if (region_id >= region_volumes.size())
region_volumes.resize(region_id + 1);
- region_volumes[region_id].emplace_back(volume_id);
+ region_volumes[region_id].emplace_back(layer_range, volume_id);
}
// This is the *total* layer count (including support layers)
// this value is not supposed to be compared with Layer::id
@@ -141,8 +141,9 @@ public:
void slice();
// Helpers to slice support enforcer / blocker meshes by the support generator.
- std::vector<ExPolygons> slice_support_enforcers() const;
- std::vector<ExPolygons> slice_support_blockers() const;
+ std::vector<ExPolygons> slice_support_volumes(const ModelVolumeType &model_volume_type) const;
+ std::vector<ExPolygons> slice_support_blockers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_BLOCKER); }
+ std::vector<ExPolygons> slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); }
protected:
// to be called from Print only.
@@ -165,7 +166,7 @@ protected:
void update_slicing_parameters();
static PrintObjectConfig object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders);
- static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders);
+ static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_region_config, const DynamicPrintConfig *layer_range_config, const ModelVolume &volume, size_t num_extruders);
private:
void make_perimeters();
@@ -201,9 +202,11 @@ private:
LayerPtrs m_layers;
SupportLayerPtrs m_support_layers;
- std::vector<ExPolygons> _slice_region(size_t region_id, const std::vector<float> &z, bool modifier);
- std::vector<ExPolygons> _slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const;
- std::vector<ExPolygons> _slice_volume(const std::vector<float> &z, const ModelVolume &volume) const;
+ std::vector<ExPolygons> slice_region(size_t region_id, const std::vector<float> &z) const;
+ std::vector<ExPolygons> slice_modifiers(size_t region_id, const std::vector<float> &z) const;
+ std::vector<ExPolygons> slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const;
+ std::vector<ExPolygons> slice_volume(const std::vector<float> &z, const ModelVolume &volume) const;
+ std::vector<ExPolygons> slice_volume(const std::vector<float> &z, const std::vector<t_layer_height_range> &ranges, const ModelVolume &volume) const;
};
struct WipeTowerData
@@ -291,11 +294,6 @@ public:
ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override;
- // The following three methods are used by the Perl tests only. Get rid of them!
- void reload_object(size_t idx);
- void add_model_object(ModelObject* model_object, int idx = -1);
- bool apply_config_perl_tests_only(DynamicPrintConfig config);
-
void process() override;
// Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file.
// If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r).
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index d99aceabf..f7d6f891d 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -49,7 +49,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, bool add_insta
{
// Translate meshes so that our toolpath generation algorithms work with smaller
// XY coordinates; this translation is an optimization and not strictly required.
- // A cloned mesh will be aligned to 0 before slicing in _slice_region() since we
+ // A cloned mesh will be aligned to 0 before slicing in slice_region() since we
// don't assume it's already aligned and we don't alter the original position in model.
// We store the XY translation so that we can place copies correctly in the output G-code
// (copies are expressed in G-code coordinates and this translation is not publicly exposed).
@@ -590,7 +590,12 @@ bool PrintObject::invalidate_step(PrintObjectStep step)
bool PrintObject::invalidate_all_steps()
{
- return Inherited::invalidate_all_steps() | m_print->invalidate_all_steps();
+ // First call the "invalidate" functions, which may cancel background processing.
+ bool result = Inherited::invalidate_all_steps() | m_print->invalidate_all_steps();
+ // Then reset some of the depending values.
+ this->m_slicing_params.valid = false;
+ this->region_volumes.clear();
+ return result;
}
bool PrintObject::has_support_material() const
@@ -1354,10 +1359,12 @@ PrintObjectConfig PrintObject::object_config_from_model_object(const PrintObject
return config;
}
-PrintRegionConfig PrintObject::region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders)
+PrintRegionConfig PrintObject::region_config_from_model_volume(const PrintRegionConfig &default_region_config, const DynamicPrintConfig *layer_range_config, const ModelVolume &volume, size_t num_extruders)
{
PrintRegionConfig config = default_region_config;
normalize_and_apply_config(config, volume.get_object()->config);
+ if (layer_range_config != nullptr)
+ normalize_and_apply_config(config, *layer_range_config);
normalize_and_apply_config(config, volume.config);
if (! volume.material_id().empty())
normalize_and_apply_config(config, volume.material()->config);
@@ -1375,28 +1382,37 @@ void PrintObject::update_slicing_parameters()
this->print()->config(), m_config, unscale<double>(this->size(2)), this->object_extruders());
}
-SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object, float object_max_z)
+SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full_config, const ModelObject& model_object, float object_max_z)
{
- PrintConfig print_config;
- PrintObjectConfig object_config;
- PrintRegionConfig default_region_config;
- print_config .apply(full_config, true);
- object_config.apply(full_config, true);
- default_region_config.apply(full_config, true);
- size_t num_extruders = print_config.nozzle_diameter.size();
- object_config = object_config_from_model_object(object_config, model_object, num_extruders);
-
- std::vector<unsigned int> object_extruders;
- for (const ModelVolume *model_volume : model_object.volumes)
- if (model_volume->is_model_part())
- PrintRegion::collect_object_printing_extruders(
- print_config,
- region_config_from_model_volume(default_region_config, *model_volume, num_extruders),
- object_extruders);
+ PrintConfig print_config;
+ PrintObjectConfig object_config;
+ PrintRegionConfig default_region_config;
+ print_config.apply(full_config, true);
+ object_config.apply(full_config, true);
+ default_region_config.apply(full_config, true);
+ size_t num_extruders = print_config.nozzle_diameter.size();
+ object_config = object_config_from_model_object(object_config, model_object, num_extruders);
+
+ std::vector<unsigned int> object_extruders;
+ for (const ModelVolume* model_volume : model_object.volumes)
+ if (model_volume->is_model_part()) {
+ PrintRegion::collect_object_printing_extruders(
+ print_config,
+ region_config_from_model_volume(default_region_config, nullptr, *model_volume, num_extruders),
+ object_extruders);
+ for (const std::pair<const t_layer_height_range, DynamicPrintConfig> &range_and_config : model_object.layer_config_ranges)
+ if (range_and_config.second.has("perimeter_extruder") ||
+ range_and_config.second.has("infill_extruder") ||
+ range_and_config.second.has("solid_infill_extruder"))
+ PrintRegion::collect_object_printing_extruders(
+ print_config,
+ region_config_from_model_volume(default_region_config, &range_and_config.second, *model_volume, num_extruders),
+ object_extruders);
+ }
sort_remove_duplicates(object_extruders);
if (object_max_z <= 0.f)
- object_max_z = model_object.raw_bounding_box().size().z();
+ object_max_z = (float)model_object.raw_bounding_box().size().z();
return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders);
}
@@ -1430,12 +1446,12 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
layer_height_profile.clear();
if (layer_height_profile.empty()) {
- if (0)
+ if (0)
// if (this->layer_height_profile.empty())
- layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_height_ranges, model_object.volumes);
+ layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes);
else
- layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_height_ranges);
- updated = true;
+ layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges); // #ys_FIXME_experiment
+ updated = true;
}
return updated;
}
@@ -1489,22 +1505,28 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
}
// Count model parts and modifier meshes, check whether the model parts are of the same region.
- int single_volume_region = -2; // not set yet
+ int all_volumes_single_region = -2; // not set yet
+ bool has_z_ranges = false;
size_t num_volumes = 0;
size_t num_modifiers = 0;
- std::vector<int> map_volume_to_region(this->model_object()->volumes.size());
for (int region_id = 0; region_id < (int)this->region_volumes.size(); ++ region_id) {
- for (int volume_id : this->region_volumes[region_id]) {
+ int last_volume_id = -1;
+ for (const std::pair<t_layer_height_range, int> &volume_and_range : this->region_volumes[region_id]) {
+ const int volume_id = volume_and_range.second;
const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
if (model_volume->is_model_part()) {
- map_volume_to_region[volume_id] = region_id;
- if (single_volume_region == -2)
- // first model volume met
- single_volume_region = region_id;
- else if (single_volume_region != region_id)
- // multiple volumes met and they are not equal
- single_volume_region = -1;
- ++ num_volumes;
+ if (last_volume_id == volume_id) {
+ has_z_ranges = true;
+ } else {
+ last_volume_id = volume_id;
+ if (all_volumes_single_region == -2)
+ // first model volume met
+ all_volumes_single_region = region_id;
+ else if (all_volumes_single_region != region_id)
+ // multiple volumes met and they are not equal
+ all_volumes_single_region = -1;
+ ++ num_volumes;
+ }
} else if (model_volume->is_modifier())
++ num_modifiers;
}
@@ -1514,13 +1536,13 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
// Slice all non-modifier volumes.
bool clipped = false;
bool upscaled = false;
- if (! m_config.clip_multipart_objects.value || single_volume_region >= 0) {
+ if (! has_z_ranges && (! m_config.clip_multipart_objects.value || all_volumes_single_region >= 0)) {
// Cheap path: Slice regions without mutual clipping.
// The cheap path is possible if no clipping is allowed or if slicing volumes of just a single region.
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id;
// slicing in parallel
- std::vector<ExPolygons> expolygons_by_layer = this->_slice_region(region_id, slice_zs, false);
+ std::vector<ExPolygons> expolygons_by_layer = this->slice_region(region_id, slice_zs);
m_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " start";
for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id)
@@ -1541,15 +1563,29 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
};
std::vector<SlicedVolume> sliced_volumes;
sliced_volumes.reserve(num_volumes);
- for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id)
- for (int volume_id : this->region_volumes[region_id]) {
+ for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
+ const std::vector<std::pair<t_layer_height_range, int>> &volumes_and_ranges = this->region_volumes[region_id];
+ for (size_t i = 0; i < volumes_and_ranges.size(); ) {
+ int volume_id = volumes_and_ranges[i].second;
const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
if (model_volume->is_model_part()) {
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - volume " << volume_id;
+ // Find the ranges of this volume. Ranges in volumes_and_ranges must not overlap for a single volume.
+ std::vector<t_layer_height_range> ranges;
+ ranges.emplace_back(volumes_and_ranges[i].first);
+ size_t j = i + 1;
+ for (; j < volumes_and_ranges.size() && volume_id == volumes_and_ranges[j].second; ++ j)
+ if (! ranges.empty() && std::abs(ranges.back().second - volumes_and_ranges[j].first.first) < EPSILON)
+ ranges.back().second = volumes_and_ranges[j].first.second;
+ else
+ ranges.emplace_back(volumes_and_ranges[j].first);
// slicing in parallel
- sliced_volumes.emplace_back(volume_id, map_volume_to_region[volume_id], this->_slice_volume(slice_zs, *model_volume));
- }
+ sliced_volumes.emplace_back(volume_id, (int)region_id, this->slice_volume(slice_zs, ranges, *model_volume));
+ i = j;
+ } else
+ ++ i;
}
+ }
// Second clip the volumes in the order they are presented at the user interface.
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - parallel clipping - start";
tbb::parallel_for(
@@ -1603,7 +1639,7 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - region " << region_id;
// slicing in parallel
- std::vector<ExPolygons> expolygons_by_layer = this->_slice_region(region_id, slice_zs, true);
+ std::vector<ExPolygons> expolygons_by_layer = this->slice_modifiers(region_id, slice_zs);
m_print->throw_if_canceled();
if (expolygons_by_layer.empty())
continue;
@@ -1619,7 +1655,7 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
Layer *layer = m_layers[layer_id];
LayerRegion *layerm = layer->m_regions[region_id];
LayerRegion *other_layerm = layer->m_regions[other_region_id];
- if (layerm == nullptr || other_layerm == nullptr)
+ if (layerm == nullptr || other_layerm == nullptr || other_layerm->slices.empty() || expolygons_by_layer[layer_id].empty())
continue;
Polygons other_slices = to_polygons(other_layerm->slices);
ExPolygons my_parts = intersection_ex(other_slices, to_polygons(expolygons_by_layer[layer_id]));
@@ -1752,46 +1788,127 @@ end:
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - end";
}
-std::vector<ExPolygons> PrintObject::_slice_region(size_t region_id, const std::vector<float> &z, bool modifier)
+// To be used only if there are no layer span specific configurations applied, which would lead to z ranges being generated for this region.
+std::vector<ExPolygons> PrintObject::slice_region(size_t region_id, const std::vector<float> &z) const
{
- std::vector<const ModelVolume*> volumes;
+ std::vector<const ModelVolume*> volumes;
if (region_id < this->region_volumes.size()) {
- for (int volume_id : this->region_volumes[region_id]) {
- const ModelVolume *volume = this->model_object()->volumes[volume_id];
- if (modifier ? volume->is_modifier() : volume->is_model_part())
- volumes.emplace_back(volume);
- }
+ for (const std::pair<t_layer_height_range, int> &volume_and_range : this->region_volumes[region_id]) {
+ const ModelVolume *volume = this->model_object()->volumes[volume_and_range.second];
+ if (volume->is_model_part())
+ volumes.emplace_back(volume);
+ }
}
- return this->_slice_volumes(z, volumes);
+ return this->slice_volumes(z, volumes);
}
-std::vector<ExPolygons> PrintObject::slice_support_enforcers() const
+// Z ranges are not applicable to modifier meshes, therefore a sinle volume will be found in volume_and_range at most once.
+std::vector<ExPolygons> PrintObject::slice_modifiers(size_t region_id, const std::vector<float> &slice_zs) const
{
- std::vector<const ModelVolume*> volumes;
- for (const ModelVolume *volume : this->model_object()->volumes)
- if (volume->is_support_enforcer())
- volumes.emplace_back(volume);
- std::vector<float> zs;
- zs.reserve(this->layers().size());
- for (const Layer *l : this->layers())
- zs.emplace_back((float)l->slice_z);
- return this->_slice_volumes(zs, volumes);
+ std::vector<ExPolygons> out;
+ if (region_id < this->region_volumes.size())
+ {
+ std::vector<std::vector<t_layer_height_range>> volume_ranges;
+ const std::vector<std::pair<t_layer_height_range, int>> &volumes_and_ranges = this->region_volumes[region_id];
+ volume_ranges.reserve(volumes_and_ranges.size());
+ for (size_t i = 0; i < volumes_and_ranges.size(); ) {
+ int volume_id = volumes_and_ranges[i].second;
+ const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
+ if (model_volume->is_modifier()) {
+ std::vector<t_layer_height_range> ranges;
+ ranges.emplace_back(volumes_and_ranges[i].first);
+ size_t j = i + 1;
+ for (; j < volumes_and_ranges.size() && volume_id == volumes_and_ranges[j].second; ++ j) {
+ if (! ranges.empty() && std::abs(ranges.back().second - volumes_and_ranges[j].first.first) < EPSILON)
+ ranges.back().second = volumes_and_ranges[j].first.second;
+ else
+ ranges.emplace_back(volumes_and_ranges[j].first);
+ }
+ volume_ranges.emplace_back(std::move(ranges));
+ i = j;
+ } else
+ ++ i;
+ }
+
+ if (! volume_ranges.empty())
+ {
+ bool equal_ranges = true;
+ for (size_t i = 1; i < volume_ranges.size(); ++ i) {
+ assert(! volume_ranges[i].empty());
+ if (volume_ranges.front() != volume_ranges[i]) {
+ equal_ranges = false;
+ break;
+ }
+ }
+
+ if (equal_ranges && volume_ranges.front().size() == 1 && volume_ranges.front().front() == t_layer_height_range(0, DBL_MAX)) {
+ // No modifier in this region was split to layer spans.
+ std::vector<const ModelVolume*> volumes;
+ for (const std::pair<t_layer_height_range, int> &volume_and_range : this->region_volumes[region_id]) {
+ const ModelVolume *volume = this->model_object()->volumes[volume_and_range.second];
+ if (volume->is_modifier())
+ volumes.emplace_back(volume);
+ }
+ out = this->slice_volumes(slice_zs, volumes);
+ } else {
+ // Some modifier in this region was split to layer spans.
+ std::vector<char> merge;
+ for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
+ const std::vector<std::pair<t_layer_height_range, int>> &volumes_and_ranges = this->region_volumes[region_id];
+ for (size_t i = 0; i < volumes_and_ranges.size(); ) {
+ int volume_id = volumes_and_ranges[i].second;
+ const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
+ if (model_volume->is_modifier()) {
+ BOOST_LOG_TRIVIAL(debug) << "Slicing modifiers - volume " << volume_id;
+ // Find the ranges of this volume. Ranges in volumes_and_ranges must not overlap for a single volume.
+ std::vector<t_layer_height_range> ranges;
+ ranges.emplace_back(volumes_and_ranges[i].first);
+ size_t j = i + 1;
+ for (; j < volumes_and_ranges.size() && volume_id == volumes_and_ranges[j].second; ++ j)
+ ranges.emplace_back(volumes_and_ranges[j].first);
+ // slicing in parallel
+ std::vector<ExPolygons> this_slices = this->slice_volume(slice_zs, ranges, *model_volume);
+ if (out.empty()) {
+ out = std::move(this_slices);
+ merge.assign(out.size(), false);
+ } else {
+ for (size_t i = 0; i < out.size(); ++ i)
+ if (! this_slices[i].empty())
+ if (! out[i].empty()) {
+ append(out[i], this_slices[i]);
+ merge[i] = true;
+ } else
+ out[i] = std::move(this_slices[i]);
+ }
+ i = j;
+ } else
+ ++ i;
+ }
+ }
+ for (size_t i = 0; i < merge.size(); ++ i)
+ if (merge[i])
+ out[i] = union_ex(out[i]);
+ }
+ }
+ }
+
+ return out;
}
-std::vector<ExPolygons> PrintObject::slice_support_blockers() const
+std::vector<ExPolygons> PrintObject::slice_support_volumes(const ModelVolumeType &model_volume_type) const
{
std::vector<const ModelVolume*> volumes;
for (const ModelVolume *volume : this->model_object()->volumes)
- if (volume->is_support_blocker())
+ if (volume->type() == model_volume_type)
volumes.emplace_back(volume);
std::vector<float> zs;
zs.reserve(this->layers().size());
for (const Layer *l : this->layers())
zs.emplace_back((float)l->slice_z);
- return this->_slice_volumes(zs, volumes);
+ return this->slice_volumes(zs, volumes);
}
-std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const
+std::vector<ExPolygons> PrintObject::slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const
{
std::vector<ExPolygons> layers;
if (! volumes.empty()) {
@@ -1828,34 +1945,71 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
return layers;
}
-std::vector<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &z, const ModelVolume &volume) const
+std::vector<ExPolygons> PrintObject::slice_volume(const std::vector<float> &z, const ModelVolume &volume) const
{
std::vector<ExPolygons> layers;
- // Compose mesh.
- //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
- TriangleMesh mesh(volume.mesh());
- mesh.transform(volume.get_matrix(), true);
- if (mesh.repaired) {
- //FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it.
- stl_check_facets_exact(&mesh.stl);
+ if (! z.empty()) {
+ // Compose mesh.
+ //FIXME better to split the mesh into separate shells, perform slicing over each shell separately and then to use a Boolean operation to merge them.
+ TriangleMesh mesh(volume.mesh());
+ mesh.transform(volume.get_matrix(), true);
+ if (mesh.repaired) {
+ //FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it.
+ stl_check_facets_exact(&mesh.stl);
+ }
+ if (mesh.stl.stats.number_of_facets > 0) {
+ mesh.transform(m_trafo, true);
+ // apply XY shift
+ mesh.translate(- unscale<float>(m_copies_shift(0)), - unscale<float>(m_copies_shift(1)), 0);
+ // perform actual slicing
+ TriangleMeshSlicer mslicer;
+ const Print *print = this->print();
+ auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
+ // TriangleMeshSlicer needs the shared vertices.
+ mesh.require_shared_vertices();
+ mslicer.init(&mesh, callback);
+ mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
+ m_print->throw_if_canceled();
+ }
}
- if (mesh.stl.stats.number_of_facets > 0) {
- mesh.transform(m_trafo, true);
- // apply XY shift
- mesh.translate(- unscale<float>(m_copies_shift(0)), - unscale<float>(m_copies_shift(1)), 0);
- // perform actual slicing
- TriangleMeshSlicer mslicer;
- const Print *print = this->print();
- auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
- // TriangleMeshSlicer needs the shared vertices.
- mesh.require_shared_vertices();
- mslicer.init(&mesh, callback);
- mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
- m_print->throw_if_canceled();
- }
return layers;
}
+// Filter the zs not inside the ranges. The ranges are closed at the botton and open at the top, they are sorted lexicographically and non overlapping.
+std::vector<ExPolygons> PrintObject::slice_volume(const std::vector<float> &z, const std::vector<t_layer_height_range> &ranges, const ModelVolume &volume) const
+{
+ std::vector<ExPolygons> out;
+ if (! z.empty() && ! ranges.empty()) {
+ if (ranges.size() == 1 && z.front() >= ranges.front().first && z.back() < ranges.front().second) {
+ // All layers fit into a single range.
+ out = this->slice_volume(z, volume);
+ } else {
+ std::vector<float> z_filtered;
+ std::vector<std::pair<size_t, size_t>> n_filtered;
+ z_filtered.reserve(z.size());
+ n_filtered.reserve(2 * ranges.size());
+ size_t i = 0;
+ for (const t_layer_height_range &range : ranges) {
+ for (; i < z.size() && z[i] < range.first; ++ i) ;
+ size_t first = i;
+ for (; i < z.size() && z[i] < range.second; ++ i)
+ z_filtered.emplace_back(z[i]);
+ if (i > first)
+ n_filtered.emplace_back(std::make_pair(first, i));
+ }
+ if (! n_filtered.empty()) {
+ std::vector<ExPolygons> layers = this->slice_volume(z_filtered, volume);
+ out.assign(z.size(), ExPolygons());
+ i = 0;
+ for (const std::pair<size_t, size_t> &span : n_filtered)
+ for (size_t j = span.first; j < span.second; ++ j)
+ out[j] = std::move(layers[i ++]);
+ }
+ }
+ }
+ return out;
+}
+
std::string PrintObject::_fix_slicing_errors()
{
// Collect layers with slicing errors.
@@ -2119,7 +2273,7 @@ void PrintObject::clip_fill_surfaces()
//Should the pw not be half of the current value?
float pw = FLT_MAX;
for (const LayerRegion *layerm : layer->m_regions)
- pw = std::min<float>(pw, layerm->flow(frPerimeter).scaled_width());
+ pw = std::min(pw, (float)layerm->flow(frPerimeter).scaled_width());
// Append such thick perimeters to the areas that need support
polygons_append(overhangs, offset2(perimeters, -pw, +pw));
}
diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp
index 3b199c4eb..04cbd7824 100644
--- a/src/libslic3r/SLA/SLABasePool.cpp
+++ b/src/libslic3r/SLA/SLABasePool.cpp
@@ -5,6 +5,7 @@
#include "SLABoostAdapter.hpp"
#include "ClipperUtils.hpp"
#include "Tesselate.hpp"
+#include "MTUtils.hpp"
// For debugging:
//#include <fstream>
@@ -203,7 +204,7 @@ void offset(ExPolygon& sh, coord_t distance) {
}
ClipperOffset offs;
- offs.ArcTolerance = 0.01*scaled(1.0);
+ offs.ArcTolerance = scaled<double>(0.01);
Paths result;
offs.AddPath(ctour, jtRound, etClosedPolygon);
offs.AddPaths(holes, jtRound, etClosedPolygon);
@@ -351,7 +352,7 @@ Contour3D round_edges(const ExPolygon& base_plate,
double x2 = xx*xx;
double stepy = std::sqrt(r2 - x2);
- offset(ob, s*scaled(xx));
+ offset(ob, s * scaled(xx));
wh = ceilheight_mm - radius_mm + stepy;
Contour3D pwalls;
@@ -375,7 +376,7 @@ Contour3D round_edges(const ExPolygon& base_plate,
double xx = radius_mm - i*stepx;
double x2 = xx*xx;
double stepy = std::sqrt(r2 - x2);
- offset(ob, s*scaled(xx));
+ offset(ob, s * scaled(xx));
wh = ceilheight_mm - radius_mm - stepy;
Contour3D pwalls;
@@ -476,7 +477,7 @@ ExPolygons concave_hull(const ExPolygons& polys, double max_dist_mm = 50,
double dx = x(c) - x(cc), dy = y(c) - y(cc);
double l = std::sqrt(dx * dx + dy * dy);
double nx = dx / l, ny = dy / l;
- double max_dist = scaled(max_dist_mm);
+ double max_dist = scaled<double>(max_dist_mm);
ExPolygon& expo = punion[idx++];
BoundingBox querybb(expo);
@@ -492,7 +493,7 @@ ExPolygons concave_hull(const ExPolygons& polys, double max_dist_mm = 50,
ctour.reserve(3);
ctour.emplace_back(cc);
- Point d(coord_t(scaled(1.)*nx), coord_t(scaled(1.)*ny));
+ Point d(scaled(nx), scaled(ny));
ctour.emplace_back(c + Point( -y(d), x(d) ));
ctour.emplace_back(c + Point( y(d), -x(d) ));
offset(r, scaled(1.));
@@ -529,14 +530,14 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
ExPolygons tmp; tmp.reserve(count);
for(ExPolygons& o : out)
for(ExPolygon& e : o) {
- auto&& exss = e.simplify(scaled(0.1));
+ auto&& exss = e.simplify(scaled<double>(0.1));
for(ExPolygon& ep : exss) tmp.emplace_back(std::move(ep));
}
ExPolygons utmp = unify(tmp);
for(auto& o : utmp) {
- auto&& smp = o.simplify(scaled(0.1));
+ auto&& smp = o.simplify(scaled<double>(0.1));
output.insert(output.end(), smp.begin(), smp.end());
}
}
diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp
index 47b259f64..15aece10a 100644
--- a/src/libslic3r/SLAPrint.cpp
+++ b/src/libslic3r/SLAPrint.cpp
@@ -668,7 +668,7 @@ void SLAPrint::process()
double ilhd = m_material_config.initial_layer_height.getFloat();
auto ilh = float(ilhd);
- auto ilhs = scaled(ilhd);
+ coord_t ilhs = scaled(ilhd);
const size_t objcount = m_objects.size();
static const unsigned min_objstatus = 0; // where the per object operations start
@@ -694,17 +694,15 @@ void SLAPrint::process()
// We need to prepare the slice index...
- double lhd = m_objects.front()->m_config.layer_height.getFloat();
- float lh = float(lhd);
- auto lhs = scaled(lhd);
-
- auto &&bb3d = mesh.bounding_box();
- double minZ = bb3d.min(Z) - po.get_elevation();
- double maxZ = bb3d.max(Z);
- auto minZf = float(minZ);
-
- auto minZs = scaled(minZ);
- auto maxZs = scaled(maxZ);
+ double lhd = m_objects.front()->m_config.layer_height.getFloat();
+ float lh = float(lhd);
+ coord_t lhs = scaled(lhd);
+ auto && bb3d = mesh.bounding_box();
+ double minZ = bb3d.min(Z) - po.get_elevation();
+ double maxZ = bb3d.max(Z);
+ auto minZf = float(minZ);
+ coord_t minZs = scaled(minZ);
+ coord_t maxZs = scaled(maxZ);
po.m_slice_index.clear();
@@ -722,8 +720,9 @@ void SLAPrint::process()
if(slindex_it == po.m_slice_index.end())
//TRN To be shown at the status bar on SLA slicing error.
- throw std::runtime_error(L("Slicing had to be stopped "
- "due to an internal error."));
+ throw std::runtime_error(
+ L("Slicing had to be stopped due to an internal error: "
+ "Inconsistent slice index."));
po.m_model_height_levels.clear();
po.m_model_height_levels.reserve(po.m_slice_index.size());
@@ -1013,9 +1012,6 @@ void SLAPrint::process()
using ClipperPolygons = std::vector<ClipperPolygon>;
namespace sl = libnest2d::shapelike; // For algorithms
- // If the raster has vertical orientation, we will flip the coordinates
-// bool flpXY = m_printer_config.display_orientation.getInt() == SLADisplayOrientation::sladoPortrait;
-
// Set up custom union and diff functions for clipper polygons
auto polyunion = [] (const ClipperPolygons& subjects)
{
@@ -1066,8 +1062,8 @@ void SLAPrint::process()
const int fade_layers_cnt = m_default_object_config.faded_layers.getInt();// 10 // [3;20]
- const double width = scaled(m_printer_config.display_width.getFloat());
- const double height = scaled(m_printer_config.display_height.getFloat());
+ const auto width = scaled<double>(m_printer_config.display_width.getFloat());
+ const auto height = scaled<double>(m_printer_config.display_height.getFloat());
const double display_area = width*height;
// get polygons for all instances in the object
@@ -1123,11 +1119,6 @@ void SLAPrint::process()
sl::translate(poly, ClipperPoint{instances[i].shift(X),
instances[i].shift(Y)});
-// if (flpXY) {
-// for(auto& p : poly.Contour) std::swap(p.X, p.Y);
-// for(auto& h : poly.Holes) for(auto& p : h) std::swap(p.X, p.Y);
-// }
-
polygons.emplace_back(std::move(poly));
}
}
diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp
index e1bb4b313..6b0e3f895 100644
--- a/src/libslic3r/Slicing.cpp
+++ b/src/libslic3r/Slicing.cpp
@@ -153,24 +153,33 @@ SlicingParameters SlicingParameters::create_from_config(
return params;
}
-// Convert layer_height_ranges to layer_height_profile. Both are referenced to z=0, meaning the raft layers are not accounted for
+std::vector<std::pair<t_layer_height_range, coordf_t>> layer_height_ranges(const t_layer_config_ranges &config_ranges)
+{
+ std::vector<std::pair<t_layer_height_range, coordf_t>> out;
+ out.reserve(config_ranges.size());
+ for (const auto &kvp : config_ranges)
+ out.emplace_back(kvp.first, kvp.second.option("layer_height")->getFloat());
+ return out;
+}
+
+// Convert layer_config_ranges to layer_height_profile. Both are referenced to z=0, meaning the raft layers are not accounted for
// in the height profile and the printed object may be lifted by the raft thickness at the time of the G-code generation.
std::vector<coordf_t> layer_height_profile_from_ranges(
const SlicingParameters &slicing_params,
- const t_layer_height_ranges &layer_height_ranges)
+ const t_layer_config_ranges &layer_config_ranges) // #ys_FIXME_experiment
{
// 1) If there are any height ranges, trim one by the other to make them non-overlapping. Insert the 1st layer if fixed.
std::vector<std::pair<t_layer_height_range,coordf_t>> ranges_non_overlapping;
- ranges_non_overlapping.reserve(layer_height_ranges.size() * 4);
+ ranges_non_overlapping.reserve(layer_config_ranges.size() * 4); // #ys_FIXME_experiment
if (slicing_params.first_object_layer_height_fixed())
ranges_non_overlapping.push_back(std::pair<t_layer_height_range,coordf_t>(
t_layer_height_range(0., slicing_params.first_object_layer_height),
slicing_params.first_object_layer_height));
// The height ranges are sorted lexicographically by low / high layer boundaries.
- for (t_layer_height_ranges::const_iterator it_range = layer_height_ranges.begin(); it_range != layer_height_ranges.end(); ++ it_range) {
+ for (t_layer_config_ranges::const_iterator it_range = layer_config_ranges.begin(); it_range != layer_config_ranges.end(); ++ it_range) {
coordf_t lo = it_range->first.first;
coordf_t hi = std::min(it_range->first.second, slicing_params.object_print_z_height());
- coordf_t height = it_range->second;
+ coordf_t height = it_range->second.option("layer_height")->getFloat();
if (! ranges_non_overlapping.empty())
// Trim current low with the last high.
lo = std::max(lo, ranges_non_overlapping.back().first.second);
@@ -219,7 +228,7 @@ std::vector<coordf_t> layer_height_profile_from_ranges(
// Fill layer_height_profile by heights ensuring a prescribed maximum cusp height.
std::vector<coordf_t> layer_height_profile_adaptive(
const SlicingParameters &slicing_params,
- const t_layer_height_ranges &layer_height_ranges,
+ const t_layer_config_ranges & /* layer_config_ranges */,
const ModelVolumePtrs &volumes)
{
// 1) Initialize the SlicingAdaptive class with the object meshes.
diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp
index cd6affdeb..064363ec2 100644
--- a/src/libslic3r/Slicing.hpp
+++ b/src/libslic3r/Slicing.hpp
@@ -11,6 +11,8 @@
#include "libslic3r.h"
#include "Utils.hpp"
+#include "PrintConfig.hpp"
+
namespace Slic3r
{
@@ -128,15 +130,17 @@ inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters
}
typedef std::pair<coordf_t,coordf_t> t_layer_height_range;
-typedef std::map<t_layer_height_range,coordf_t> t_layer_height_ranges;
+typedef std::map<t_layer_height_range, DynamicPrintConfig> t_layer_config_ranges;
+
+extern std::vector<std::pair<t_layer_height_range, coordf_t>> layer_height_ranges(const t_layer_config_ranges &config_ranges);
extern std::vector<coordf_t> layer_height_profile_from_ranges(
const SlicingParameters &slicing_params,
- const t_layer_height_ranges &layer_height_ranges);
+ const t_layer_config_ranges &layer_config_ranges);
extern std::vector<coordf_t> layer_height_profile_adaptive(
const SlicingParameters &slicing_params,
- const t_layer_height_ranges &layer_height_ranges,
+ const t_layer_config_ranges &layer_config_ranges,
const ModelVolumePtrs &volumes);
diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp
index fde35ca1e..0ad4f816a 100644
--- a/src/libslic3r/SupportMaterial.cpp
+++ b/src/libslic3r/SupportMaterial.cpp
@@ -829,7 +829,7 @@ namespace SupportMaterialInternal {
assert(expansion_scaled >= 0.f);
for (const ExtrusionPath &ep : loop.paths)
if (ep.role() == erOverhangPerimeter && ! ep.polyline.empty()) {
- float exp = 0.5f * scale_(ep.width) + expansion_scaled;
+ float exp = 0.5f * (float)scale_(ep.width) + expansion_scaled;
if (ep.is_closed()) {
if (ep.size() >= 3) {
// This is a complete loop.
@@ -2214,7 +2214,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
// Expand the bases of the support columns in the 1st layer.
columns_base->polygons = diff(
offset(columns_base->polygons, inflate_factor_1st_layer),
- offset(m_object->layers().front()->slices.expolygons, scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS));
+ offset(m_object->layers().front()->slices.expolygons, (float)scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS));
if (contacts != nullptr)
columns_base->polygons = diff(columns_base->polygons, interface_polygons);
}
@@ -3226,7 +3226,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// TODO: use brim ordering algorithm
Polygons to_infill_polygons = to_polygons(to_infill);
// TODO: use offset2_ex()
- to_infill = offset_ex(to_infill, - 0.4 * float(flow.scaled_spacing()));
+ to_infill = offset_ex(to_infill, - 0.4f * float(flow.scaled_spacing()));
extrusion_entities_append_paths(
base_layer.extrusions,
to_polylines(std::move(to_infill_polygons)),
diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp
index a5f93b24f..f05bc0b57 100644
--- a/src/libslic3r/Technologies.hpp
+++ b/src/libslic3r/Technologies.hpp
@@ -15,6 +15,8 @@
#define ENABLE_RENDER_STATISTICS 0
// Shows an imgui dialog with camera related data
#define ENABLE_CAMERA_STATISTICS 0
+// Render the picking pass instead of the main scene (use [T] key to toggle between regular rendering and picking pass only rendering)
+#define ENABLE_RENDER_PICKING_PASS 0
//====================
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index 56accfefa..fbfff90fb 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -547,9 +547,9 @@ TriangleMesh TriangleMesh::convex_hull_3d() const
#if REALfloat
qhull.runQhull("", 3, (int)this->its.vertices.size(), (const realT*)(this->its.vertices.front().data()), "Qt");
#else
- src_vertices.reserve(this->its.vertices() * 3);
+ src_vertices.reserve(this->its.vertices.size() * 3);
// We will now fill the vector with input points for computation:
- for (const stl_vertex &v : ths->its.vertices.size())
+ for (const stl_vertex &v : this->its.vertices)
for (int i = 0; i < 3; ++ i)
src_vertices.emplace_back(v(i));
qhull.runQhull("", 3, (int)src_vertices.size() / 3, src_vertices.data(), "Qt");
diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp
index e76fccdb8..adf7f57a7 100644
--- a/src/libslic3r/Utils.hpp
+++ b/src/libslic3r/Utils.hpp
@@ -167,7 +167,7 @@ template<class T> size_t next_highest_power_of_2(T v,
extern std::string xml_escape(std::string text);
-#if defined __GNUC__ & __GNUC__ < 5
+#if defined __GNUC__ && __GNUC__ < 5 && !defined __clang__
// Older GCCs don't have std::is_trivially_copyable
// cf. https://gcc.gnu.org/onlinedocs/gcc-4.9.4/libstdc++/manual/manual/status.html#status.iso.2011
#warning "GCC version < 5, faking std::is_trivially_copyable"
diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h
index 8cafae17c..dc2b6a4ec 100644
--- a/src/libslic3r/libslic3r.h
+++ b/src/libslic3r/libslic3r.h
@@ -61,20 +61,6 @@ typedef double coordf_t;
#define SLIC3R_NOEXCEPT noexcept
#endif
-template<class Tf> inline SLIC3R_CONSTEXPR coord_t scaled(Tf val)
-{
- static_assert (std::is_floating_point<Tf>::value, "Floating point only");
- return coord_t(val / Tf(SCALING_FACTOR));
-}
-
-template<class Tf = double> inline SLIC3R_CONSTEXPR Tf unscaled(coord_t val)
-{
- static_assert (std::is_floating_point<Tf>::value, "Floating point only");
- return Tf(val * Tf(SCALING_FACTOR));
-}
-
-inline SLIC3R_CONSTEXPR float unscaledf(coord_t val) { return unscaled<float>(val); }
-
inline std::string debug_out_path(const char *name, ...)
{
char buffer[2048];
diff --git a/src/semver/semver.c b/src/semver/semver.c
index 527738644..e8bd6edcf 100644
--- a/src/semver/semver.c
+++ b/src/semver/semver.c
@@ -22,6 +22,10 @@
static const size_t MAX_SIZE = sizeof(char) * 255;
static const int MAX_SAFE_INT = (unsigned int) -1 >> 1;
+#ifdef _WIN32
+ #define strdup _strdup
+#endif
+
/**
* Define comparison operators, storing the
* ASCII code per each symbol in hexadecimal notation.
@@ -50,8 +54,8 @@ strcut (char *str, int begin, int len) {
if((int)l < 0 || (int)l > MAX_SAFE_INT) return -1;
- if (len < 0) len = l - begin + 1;
- if (begin + len > (int)l) len = l - begin;
+ if (len < 0) len = (int)l - begin + 1;
+ if (begin + len > (int)l) len = (int)l - begin;
memmove(str + begin, str + begin + len, l - len + 1 - begin);
return len;
@@ -104,7 +108,7 @@ parse_int (const char *s) {
static char *
parse_slice (char *buf, char sep) {
char *pr, *part;
- int plen;
+ size_t plen;
/* Find separator in buf */
pr = strchr(buf, sep);
@@ -210,8 +214,9 @@ semver_parse_version (const char *str, semver_t *ver) {
static int
compare_prerelease (char *x, char *y) {
char *lastx, *lasty, *xptr, *yptr, *endptr;
- int xlen, ylen, xisnum, yisnum, xnum, ynum;
- int xn, yn, min, res;
+ size_t xlen, ylen, xn, yn, min;
+ int xisnum, yisnum, xnum, ynum;
+ int res;
if (x == NULL && y == NULL) return 0;
if (y == NULL && x) return -1;
if (x == NULL && y) return 1;
@@ -572,7 +577,7 @@ semver_clean (char *s) {
for (i = 0; i < len; i++) {
if (contains(s[i], VALID_CHARS, mlen) == 0) {
- res = strcut(s, i, 1);
+ res = strcut(s, (int)i, 1);
if(res == -1) return -1;
--len; --i;
}
diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt
index da1afdfee..e3a910d6d 100644
--- a/src/slic3r/CMakeLists.txt
+++ b/src/slic3r/CMakeLists.txt
@@ -81,6 +81,8 @@ set(SLIC3R_GUI_SOURCES
GUI/GUI_ObjectManipulation.hpp
GUI/GUI_ObjectSettings.cpp
GUI/GUI_ObjectSettings.hpp
+ GUI/GUI_ObjectLayers.cpp
+ GUI/GUI_ObjectLayers.hpp
GUI/LambdaObjectDialog.cpp
GUI/LambdaObjectDialog.hpp
GUI/Tab.cpp
diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp
index d73e423e0..2cbfd75d7 100644
--- a/src/slic3r/GUI/3DBed.cpp
+++ b/src/slic3r/GUI/3DBed.cpp
@@ -628,12 +628,12 @@ void Bed3D::render_prusa_shader(bool transparent) const
if (position_id != -1)
{
glsafe(::glEnableVertexAttribArray(position_id));
- glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_position_offset()));
+ glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_position_offset()));
}
if (tex_coords_id != -1)
{
glsafe(::glEnableVertexAttribArray(tex_coords_id));
- glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_tex_coords_offset()));
+ glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_tex_coords_offset()));
}
glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_triangles.get_vertices_count()));
diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp
index 68a74f61c..fc07581e6 100644
--- a/src/slic3r/GUI/3DBed.hpp
+++ b/src/slic3r/GUI/3DBed.hpp
@@ -44,8 +44,8 @@ public:
const float* get_vertices_data() const;
unsigned int get_vertices_data_size() const { return (unsigned int)m_vertices.size() * get_vertex_data_size(); }
unsigned int get_vertex_data_size() const { return (unsigned int)(5 * sizeof(float)); }
- unsigned int get_position_offset() const { return 0; }
- unsigned int get_tex_coords_offset() const { return (unsigned int)(3 * sizeof(float)); }
+ size_t get_position_offset() const { return 0; }
+ size_t get_tex_coords_offset() const { return (size_t)(3 * sizeof(float)); }
unsigned int get_vertices_count() const { return (unsigned int)m_vertices.size(); }
#else
const float* get_vertices() const { return m_vertices.data(); }
diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp
index 51bee9e75..3b6210058 100644
--- a/src/slic3r/GUI/AppConfig.cpp
+++ b/src/slic3r/GUI/AppConfig.cpp
@@ -54,10 +54,9 @@ void AppConfig::set_defaults()
if (get("preset_update").empty())
set("preset_update", "1");
- // Use OpenGL 1.1 even if OpenGL 2.0 is available. This is mainly to support some buggy Intel HD Graphics drivers.
- // github.com/prusa3d/PrusaSlicer/issues/233
- if (get("use_legacy_opengl").empty())
- set("use_legacy_opengl", "0");
+ // remove old 'use_legacy_opengl' parameter from this config, if present
+ if (!get("use_legacy_opengl").empty())
+ erase("", "use_legacy_opengl");
#if __APPLE__
if (get("use_retina_opengl").empty())
diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp
index cec0f5067..d52204d4a 100644
--- a/src/slic3r/GUI/BedShapeDialog.cpp
+++ b/src/slic3r/GUI/BedShapeDialog.cpp
@@ -53,15 +53,12 @@ void BedShapeDialog::on_dpi_changed(const wxRect &suggested_rect)
void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
{
-// on_change(nullptr);
-
- auto box = new wxStaticBox(this, wxID_ANY, _(L("Shape")));
- auto sbsizer = new wxStaticBoxSizer(box, wxVERTICAL);
+ auto sbsizer = new wxStaticBoxSizer(wxVERTICAL, this, _(L("Shape")));
// shape options
m_shape_options_book = new wxChoicebook(this, wxID_ANY, wxDefaultPosition,
wxSize(25*wxGetApp().em_unit(), -1), wxCHB_TOP);
- sbsizer->Add(m_shape_options_book);
+ sbsizer->Add(m_shape_options_book);
auto optgroup = init_shape_options_page(_(L("Rectangular")));
ConfigOptionDef def;
@@ -92,13 +89,15 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
Line line{ "", "" };
line.full_width = 1;
line.widget = [this](wxWindow* parent) {
- auto btn = new wxButton(parent, wxID_ANY, _(L("Load shape from STL...")), wxDefaultPosition, wxDefaultSize);
-
- auto sizer = new wxBoxSizer(wxHORIZONTAL);
- sizer->Add(btn);
+ auto shape_btn = new wxButton(parent, wxID_ANY, _(L("Load shape from STL...")));
+ wxSizer* shape_sizer = new wxBoxSizer(wxHORIZONTAL);
+ shape_sizer->Add(shape_btn, 1, wxEXPAND);
+
+ wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
+ sizer->Add(shape_sizer, 1, wxEXPAND);
- btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e)
- {
+ shape_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
+ {
load_stl();
}));
@@ -106,8 +105,8 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
};
optgroup->append_line(line);
- Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent e)
- {
+ Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent& e)
+ {
update_shape();
}));
@@ -117,8 +116,8 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
// main sizer
auto top_sizer = new wxBoxSizer(wxHORIZONTAL);
- top_sizer->Add(sbsizer, 0, wxEXPAND | wxLeft | wxTOP | wxBOTTOM, 10);
- if (m_canvas)
+ top_sizer->Add(sbsizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 10);
+ if (m_canvas)
top_sizer->Add(m_canvas, 1, wxEXPAND | wxALL, 10) ;
SetSizerAndFit(top_sizer);
@@ -135,8 +134,7 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
// Create a panel for a rectangular / circular / custom bed shape.
ConfigOptionsGroupShp BedShapePanel::init_shape_options_page(const wxString& title)
{
-
- auto panel = new wxPanel(m_shape_options_book);
+ auto panel = new wxPanel(m_shape_options_book);
ConfigOptionsGroupShp optgroup;
optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Settings")));
@@ -234,8 +232,8 @@ void BedShapePanel::set_shape(ConfigOptionPoints* points)
// This is a custom bed shape, use the polygon provided.
m_shape_options_book->SetSelection(SHAPE_CUSTOM);
// Copy the polygon to the canvas, make a copy of the array.
- m_canvas->m_bed_shape = points->values;
- update_shape();
+ m_loaded_bed_shape = points->values;
+ update_shape();
}
void BedShapePanel::update_preview()
diff --git a/src/slic3r/GUI/BonjourDialog.cpp b/src/slic3r/GUI/BonjourDialog.cpp
index 1885dda7b..0e05a517c 100644
--- a/src/slic3r/GUI/BonjourDialog.cpp
+++ b/src/slic3r/GUI/BonjourDialog.cpp
@@ -171,7 +171,7 @@ void BonjourDialog::on_reply(BonjourReplyEvent &e)
// Filter replies based on selected technology
const auto model = e.reply.txt_data.find("model");
const bool sl1 = model != e.reply.txt_data.end() && model->second == "SL1";
- if (tech == ptFFF && sl1 || tech == ptSLA && !sl1) {
+ if ((tech == ptFFF && sl1) || (tech == ptSLA && !sl1)) {
return;
}
diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp
index 6cb8ff520..242d00a07 100644
--- a/src/slic3r/GUI/Camera.cpp
+++ b/src/slic3r/GUI/Camera.cpp
@@ -24,7 +24,7 @@ namespace GUI {
const double Camera::DefaultDistance = 1000.0;
double Camera::FrustrumMinZSize = 50.0;
double Camera::FrustrumZMargin = 10.0;
-double Camera::FovMinDeg = 5.0;
+double Camera::FovMinDeg = 0.5;
double Camera::FovMaxDeg = 75.0;
Camera::Camera()
diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp
index aacbfdc52..8b08f6f7f 100644
--- a/src/slic3r/GUI/ConfigWizard.cpp
+++ b/src/slic3r/GUI/ConfigWizard.cpp
@@ -330,8 +330,8 @@ PagePrinters::PagePrinters(ConfigWizard *parent, wxString title, wxString shortn
const auto families = vendor.families();
for (const auto &family : families) {
const auto filter = [&](const VendorProfile::PrinterModel &model) {
- return (model.technology == ptFFF && technology & T_FFF
- || model.technology == ptSLA && technology & T_SLA)
+ return ((model.technology == ptFFF && technology & T_FFF)
+ || (model.technology == ptSLA && technology & T_SLA))
&& model.family == family;
};
@@ -810,7 +810,7 @@ void ConfigWizardIndex::on_paint(wxPaintEvent & evt)
const Item& item = items[i];
unsigned x = em_w/2 + item.indent * em_w;
- if (i == item_active || item_hover >= 0 && i == (size_t)item_hover) {
+ if (i == item_active || (item_hover >= 0 && i == (size_t)item_hover)) {
dc.DrawBitmap(bullet_blue.bmp(), x, y + yoff_icon, false);
}
else if (i < item_active) { dc.DrawBitmap(bullet_black.bmp(), x, y + yoff_icon, false); }
diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp
index 7f42db4d7..e84e9637f 100644
--- a/src/slic3r/GUI/Field.cpp
+++ b/src/slic3r/GUI/Field.cpp
@@ -113,11 +113,19 @@ wxString Field::get_tooltip_text(const wxString& default_string)
wxString tooltip_text("");
wxString tooltip = _(m_opt.tooltip);
edit_tooltip(tooltip);
+
+ std::string opt_id = m_opt_id;
+ auto hash_pos = opt_id.find("#");
+ if (hash_pos != std::string::npos) {
+ opt_id.replace(hash_pos, 1,"[");
+ opt_id += "]";
+ }
+
if (tooltip.length() > 0)
tooltip_text = tooltip + "\n" + _(L("default value")) + "\t: " +
- (boost::iends_with(m_opt_id, "_gcode") ? "\n" : "") + default_string +
- (boost::iends_with(m_opt_id, "_gcode") ? "" : "\n") +
- _(L("parameter name")) + "\t: " + m_opt_id;
+ (boost::iends_with(opt_id, "_gcode") ? "\n" : "") + default_string +
+ (boost::iends_with(opt_id, "_gcode") ? "" : "\n") +
+ _(L("parameter name")) + "\t: " + opt_id;
return tooltip_text;
}
diff --git a/src/slic3r/GUI/FirmwareDialog.cpp b/src/slic3r/GUI/FirmwareDialog.cpp
index 15a09aa71..7865aecf2 100644
--- a/src/slic3r/GUI/FirmwareDialog.cpp
+++ b/src/slic3r/GUI/FirmwareDialog.cpp
@@ -442,8 +442,7 @@ void FirmwareDialog::priv::avr109_lookup_port(Avr109Pid usb_pid)
auto ports = Utils::scan_serial_ports_extended();
ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) {
return port.id_vendor != USB_VID_PRUSA ||
- port.id_product != usb_pid.boot &&
- port.id_product != usb_pid.app;
+ (port.id_product != usb_pid.boot && port.id_product != usb_pid.app);
}), ports.end());
if (ports.size() == 0) {
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 511c423e6..43d419eea 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -198,8 +198,7 @@ void GLCanvas3D::Shader::_reset()
#endif // !ENABLE_TEXTURES_FROM_SVG
GLCanvas3D::LayersEditing::LayersEditing()
- : m_use_legacy_opengl(false)
- , m_enabled(false)
+ : m_enabled(false)
, m_z_texture_id(0)
, m_model_object(nullptr)
, m_object_max_z(0.f)
@@ -274,12 +273,7 @@ void GLCanvas3D::LayersEditing::select_object(const Model &model, int object_id)
bool GLCanvas3D::LayersEditing::is_allowed() const
{
- return !m_use_legacy_opengl && m_shader.is_initialized() && m_shader.get_shader()->shader_program_id > 0 && m_z_texture_id > 0;
-}
-
-void GLCanvas3D::LayersEditing::set_use_legacy_opengl(bool use_legacy_opengl)
-{
- m_use_legacy_opengl = use_legacy_opengl;
+ return m_shader.is_initialized() && m_shader.get_shader()->shader_program_id > 0 && m_z_texture_id > 0;
}
bool GLCanvas3D::LayersEditing::is_enabled() const
@@ -463,8 +457,10 @@ void GLCanvas3D::LayersEditing::_render_profile(const Rect& bar_rect) const
{
//FIXME show some kind of legend.
+ if (!m_slicing_parameters)
+ return;
+
// Make the vertical bar a bit wider so the layer height curve does not touch the edge of the bar region.
- assert(m_slicing_parameters != nullptr);
float scale_x = bar_rect.get_width() / (float)(1.12 * m_slicing_parameters->max_layer_height);
float scale_y = bar_rect.get_height() / m_object_max_z;
float x = bar_rect.get_left() + (float)m_slicing_parameters->layer_height * scale_x;
@@ -916,7 +912,8 @@ GLCanvas3D::LegendTexture::LegendTexture()
void GLCanvas3D::LegendTexture::fill_color_print_legend_values(const GCodePreviewData& preview_data, const GLCanvas3D& canvas,
std::vector<std::pair<double, double>>& cp_legend_values)
{
- if (preview_data.extrusion.view_type == GCodePreviewData::Extrusion::ColorPrint)
+ if (preview_data.extrusion.view_type == GCodePreviewData::Extrusion::ColorPrint &&
+ wxGetApp().extruders_edited_cnt() == 1) // show color change legend only for single-material presets
{
auto& config = wxGetApp().preset_bundle->project_config;
const std::vector<double>& color_print_values = config.option<ConfigOptionFloats>("colorprint_heights")->values;
@@ -1230,6 +1227,9 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
, m_cursor_type(Standard)
, m_color_by("volume")
, m_reload_delayed(false)
+#if ENABLE_RENDER_PICKING_PASS
+ , m_show_picking_texture(false)
+#endif // ENABLE_RENDER_PICKING_PASS
, m_render_sla_auxiliaries(true)
{
if (m_canvas != nullptr) {
@@ -1255,7 +1255,7 @@ void GLCanvas3D::post_event(wxEvent &&event)
wxPostEvent(m_canvas, event);
}
-bool GLCanvas3D::init(bool useVBOs, bool use_legacy_opengl)
+bool GLCanvas3D::init(bool useVBOs)
{
if (m_initialized)
return true;
@@ -1313,7 +1313,6 @@ bool GLCanvas3D::init(bool useVBOs, bool use_legacy_opengl)
return false;
m_use_VBOs = useVBOs;
- m_layers_editing.set_use_legacy_opengl(use_legacy_opengl);
// on linux the gl context is not valid until the canvas is not shown on screen
// we defer the geometry finalization of volumes until the first call to render()
@@ -1634,6 +1633,10 @@ void GLCanvas3D::render()
_picking_pass();
}
+#if ENABLE_RENDER_PICKING_PASS
+ if (!m_picking_enabled || !m_show_picking_texture)
+ {
+#endif // ENABLE_RENDER_PICKING_PASS
// draw scene
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
_render_background();
@@ -1663,6 +1666,9 @@ void GLCanvas3D::render()
_render_current_gizmo();
_render_selection_sidebar_hints();
+#if ENABLE_RENDER_PICKING_PASS
+ }
+#endif // ENABLE_RENDER_PICKING_PASS
#if ENABLE_SHOW_CAMERA_TARGET
_render_camera_target();
@@ -2423,6 +2429,14 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
case 'k': { m_camera.select_next_type(); m_dirty = true; break; }
case 'O':
case 'o': { set_camera_zoom(-1.0); break; }
+#if ENABLE_RENDER_PICKING_PASS
+ case 'T':
+ case 't': {
+ m_show_picking_texture = !m_show_picking_texture;
+ m_dirty = true;
+ break;
+ }
+#endif // ENABLE_RENDER_PICKING_PASS
case 'Z':
case 'z': { m_selection.is_empty() ? zoom_to_volumes() : zoom_to_selection(); break; }
default: { evt.Skip(); break; }
@@ -3331,6 +3345,12 @@ void GLCanvas3D::handle_sidebar_focus_event(const std::string& opt_key, bool foc
}
}
+void GLCanvas3D::handle_layers_data_focus_event(const t_layer_height_range range, const EditorType type)
+{
+ std::string field = "layer_" + std::to_string(type) + "_" + std::to_string(range.first) + "_" + std::to_string(range.second);
+ handle_sidebar_focus_event(field, true);
+}
+
void GLCanvas3D::update_ui_from_settings()
{
m_camera.set_type(wxGetApp().app_config->get("use_perspective_camera"));
@@ -4296,13 +4316,7 @@ void GLCanvas3D::_render_sla_slices() const
void GLCanvas3D::_render_selection_sidebar_hints() const
{
- if (m_use_VBOs)
- m_shader.start_using();
-
- m_selection.render_sidebar_hints(m_sidebar_field);
-
- if (m_use_VBOs)
- m_shader.stop_using();
+ m_selection.render_sidebar_hints(m_sidebar_field, m_shader);
}
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index d71817b34..47b1c5ec2 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -12,6 +12,7 @@
#include "Camera.hpp"
#include "Selection.hpp"
#include "Gizmos/GLGizmosManager.hpp"
+#include "GUI_ObjectLayers.hpp"
#include <float.h>
@@ -199,7 +200,6 @@ class GLCanvas3D
static const float THICKNESS_BAR_WIDTH;
static const float THICKNESS_RESET_BUTTON_HEIGHT;
- bool m_use_legacy_opengl;
bool m_enabled;
Shader m_shader;
unsigned int m_z_texture_id;
@@ -252,7 +252,6 @@ class GLCanvas3D
void select_object(const Model &model, int object_id);
bool is_allowed() const;
- void set_use_legacy_opengl(bool use_legacy_opengl);
bool is_enabled() const;
void set_enabled(bool enabled);
@@ -481,6 +480,10 @@ private:
GCodePreviewVolumeIndex m_gcode_preview_volume_index;
+#if ENABLE_RENDER_PICKING_PASS
+ bool m_show_picking_texture;
+#endif // ENABLE_RENDER_PICKING_PASS
+
#if ENABLE_RENDER_STATISTICS
RenderStats m_render_stats;
#endif // ENABLE_RENDER_STATISTICS
@@ -494,7 +497,7 @@ public:
wxGLCanvas* get_wxglcanvas() { return m_canvas; }
const wxGLCanvas* get_wxglcanvas() const { return m_canvas; }
- bool init(bool useVBOs, bool use_legacy_opengl);
+ bool init(bool useVBOs);
void post_event(wxEvent &&event);
void set_as_dirty();
@@ -608,6 +611,7 @@ public:
void reset_all_gizmos() { m_gizmos.reset_all_states(); }
void handle_sidebar_focus_event(const std::string& opt_key, bool focus_on);
+ void handle_layers_data_focus_event(const t_layer_height_range range, const EditorType type);
void update_ui_from_settings();
diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp
index 4f64b4e87..a1430ef22 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.cpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.cpp
@@ -192,7 +192,6 @@ GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info;
GLCanvas3DManager::GLCanvas3DManager()
: m_context(nullptr)
, m_gl_initialized(false)
- , m_use_legacy_opengl(false)
, m_use_VBOs(false)
{
}
@@ -268,8 +267,7 @@ void GLCanvas3DManager::init_gl()
{
glewInit();
const AppConfig* config = GUI::get_app_config();
- m_use_legacy_opengl = (config == nullptr) || (config->get("use_legacy_opengl") == "1");
- m_use_VBOs = !m_use_legacy_opengl && s_gl_info.is_version_greater_or_equal_to(2, 0);
+ m_use_VBOs = s_gl_info.is_version_greater_or_equal_to(2, 0);
m_gl_initialized = true;
if (GLEW_EXT_texture_compression_s3tc)
s_compressed_textures_supported = true;
@@ -325,16 +323,14 @@ bool GLCanvas3DManager::init(GLCanvas3D& canvas)
if (!m_gl_initialized)
init_gl();
- return canvas.init(m_use_VBOs, m_use_legacy_opengl);
+ return canvas.init(m_use_VBOs);
}
void GLCanvas3DManager::detect_multisample(int* attribList)
{
int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER;
const AppConfig* app_config = GUI::get_app_config();
- bool enable_multisample = app_config != nullptr
- && app_config->get("use_legacy_opengl") != "1"
- && wxVersion >= 30003;
+ bool enable_multisample = wxVersion >= 30003;
s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? MS_Enabled : MS_Disabled;
// Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows
diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp
index 26c2558d0..7a600dcbd 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.hpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.hpp
@@ -75,7 +75,6 @@ private:
wxGLContext* m_context;
static GLInfo s_gl_info;
bool m_gl_initialized;
- bool m_use_legacy_opengl;
bool m_use_VBOs;
static EMultisampleState s_multisample;
static bool s_compressed_textures_supported;
diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp
index 327cb1fde..684563bff 100644
--- a/src/slic3r/GUI/GLSelectionRectangle.cpp
+++ b/src/slic3r/GUI/GLSelectionRectangle.cpp
@@ -68,7 +68,8 @@ namespace GUI {
if (!is_dragging())
return;
- float zoom = (float)canvas.get_camera().get_zoom();
+ const Camera& camera = canvas.get_camera();
+ float zoom = (float)camera.get_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
Size cnv_size = canvas.get_canvas_size();
@@ -96,6 +97,11 @@ namespace GUI {
glsafe(::glPushMatrix());
glsafe(::glLoadIdentity());
+ // ensure that the rectangle is renderered inside the frustrum
+ glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.5)));
+ // ensure that the overlay fits the frustrum near z plane
+ double gui_scale = camera.get_gui_scale();
+ glsafe(::glScaled(gui_scale, gui_scale, 1.0));
glsafe(::glPushAttrib(GL_ENABLE_BIT));
glsafe(::glLineStipple(4, 0xAAAA));
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index 4f1c3adc8..8a376c3a3 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -141,6 +141,18 @@ GUI_App::GUI_App()
, m_imgui(new ImGuiWrapper())
{}
+GUI_App::~GUI_App()
+{
+ if (app_config != nullptr)
+ delete app_config;
+
+ if (preset_bundle != nullptr)
+ delete preset_bundle;
+
+ if (preset_updater != nullptr)
+ delete preset_updater;
+}
+
bool GUI_App::OnInit()
{
try {
@@ -922,6 +934,11 @@ ObjectList* GUI_App::obj_list()
return sidebar().obj_list();
}
+ObjectLayers* GUI_App::obj_layers()
+{
+ return sidebar().obj_layers();
+}
+
Plater* GUI_App::plater()
{
return plater_;
diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp
index 3f8b23e2d..e69503ff8 100644
--- a/src/slic3r/GUI/GUI_App.hpp
+++ b/src/slic3r/GUI/GUI_App.hpp
@@ -95,6 +95,7 @@ public:
bool initialized() const { return m_initialized; }
GUI_App();
+ ~GUI_App();
static unsigned get_colour_approx_luma(const wxColour &colour);
static bool dark_mode();
@@ -155,6 +156,7 @@ public:
ObjectManipulation* obj_manipul();
ObjectSettings* obj_settings();
ObjectList* obj_list();
+ ObjectLayers* obj_layers();
Plater* plater();
std::vector<ModelObject*> *model_objects();
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
new file mode 100644
index 000000000..b30d3ecd3
--- /dev/null
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -0,0 +1,341 @@
+#include "GUI_ObjectLayers.hpp"
+#include "GUI_ObjectList.hpp"
+
+#include "OptionsGroup.hpp"
+#include "PresetBundle.hpp"
+#include "libslic3r/Model.hpp"
+#include "GLCanvas3D.hpp"
+
+#include <boost/algorithm/string.hpp>
+
+#include "I18N.hpp"
+
+#include <wx/wupdlock.h>
+
+namespace Slic3r
+{
+namespace GUI
+{
+
+ObjectLayers::ObjectLayers(wxWindow* parent) :
+ OG_Settings(parent, true)
+{
+ m_grid_sizer = new wxFlexGridSizer(3, 5, 5); // "Min Z", "Max Z", "Layer height" & buttons sizer
+ m_grid_sizer->SetFlexibleDirection(wxHORIZONTAL);
+
+ // Legend for object layers
+ for (const std::string col : { "Min Z", "Max Z", "Layer height" }) {
+ auto temp = new wxStaticText(m_parent, wxID_ANY, _(L(col)), wxDefaultPosition, /*size*/wxDefaultSize, wxST_ELLIPSIZE_MIDDLE);
+ temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
+ temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
+ temp->SetFont(wxGetApp().bold_font());
+
+ m_grid_sizer->Add(temp);
+ }
+
+ m_og->sizer->Clear(true);
+ m_og->sizer->Add(m_grid_sizer, 0, wxEXPAND | wxALL, wxOSX ? 0 : 5);
+
+ m_bmp_delete = ScalableBitmap(parent, "remove_copies"/*"cross"*/);
+ m_bmp_add = ScalableBitmap(parent, "add_copies");
+}
+
+void ObjectLayers::select_editor(LayerRangeEditor* editor, const bool is_last_edited_range)
+{
+ if (is_last_edited_range && m_selection_type == editor->type()) {
+ /* Workaround! Under OSX we should use CallAfter() for SetFocus() after LayerEditors "reorganizations",
+ * because of selected control's strange behavior:
+ * cursor is set to the control, but blue border - doesn't.
+ * And as a result we couldn't edit this control.
+ * */
+#ifdef __WXOSX__
+ wxTheApp->CallAfter([editor]() {
+#endif
+ editor->SetFocus();
+ editor->SetInsertionPointEnd();
+#ifdef __WXOSX__
+ });
+#endif
+ }
+}
+
+wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range)
+{
+ const bool is_last_edited_range = range == m_selectable_range;
+
+ auto set_focus_data = [range, this](const EditorType type)
+ {
+ m_selectable_range = range;
+ m_selection_type = type;
+ };
+
+ auto update_focus_data = [range, this](const t_layer_height_range& new_range, EditorType type, bool enter_pressed)
+ {
+ // change selectable range for new one, if enter was pressed or if same range was selected
+ if (enter_pressed || m_selectable_range == range)
+ m_selectable_range = new_range;
+ if (enter_pressed)
+ m_selection_type = type;
+ };
+
+ // Add control for the "Min Z"
+
+ auto editor = new LayerRangeEditor(this, double_to_string(range.first), etMinZ,
+ set_focus_data, [range, update_focus_data, this](coordf_t min_z, bool enter_pressed)
+ {
+ if (fabs(min_z - range.first) < EPSILON) {
+ m_selection_type = etUndef;
+ return false;
+ }
+
+ // data for next focusing
+ coordf_t max_z = min_z < range.second ? range.second : min_z + 0.5;
+ const t_layer_height_range& new_range = { min_z, max_z };
+ update_focus_data(new_range, etMinZ, enter_pressed);
+
+ return wxGetApp().obj_list()->edit_layer_range(range, new_range);
+ });
+
+ select_editor(editor, is_last_edited_range);
+ m_grid_sizer->Add(editor);
+
+ // Add control for the "Max Z"
+
+ editor = new LayerRangeEditor(this, double_to_string(range.second), etMaxZ,
+ set_focus_data, [range, update_focus_data, this](coordf_t max_z, bool enter_pressed)
+ {
+ if (fabs(max_z - range.second) < EPSILON || range.first > max_z) {
+ m_selection_type = etUndef;
+ return false; // LayersList would not be updated/recreated
+ }
+
+ // data for next focusing
+ const t_layer_height_range& new_range = { range.first, max_z };
+ update_focus_data(new_range, etMaxZ, enter_pressed);
+
+ return wxGetApp().obj_list()->edit_layer_range(range, new_range);
+ });
+
+ select_editor(editor, is_last_edited_range);
+ m_grid_sizer->Add(editor);
+
+ // Add control for the "Layer height"
+
+ editor = new LayerRangeEditor(this,
+ double_to_string(m_object->layer_config_ranges[range].option("layer_height")->getFloat()),
+ etLayerHeight, set_focus_data, [range, this](coordf_t layer_height, bool)
+ {
+ return wxGetApp().obj_list()->edit_layer_range(range, layer_height);
+ });
+
+ select_editor(editor, is_last_edited_range);
+
+ auto sizer = new wxBoxSizer(wxHORIZONTAL);
+ sizer->Add(editor);
+ m_grid_sizer->Add(sizer);
+
+ return sizer;
+}
+
+void ObjectLayers::create_layers_list()
+{
+ for (const auto layer : m_object->layer_config_ranges)
+ {
+ const t_layer_height_range& range = layer.first;
+ auto sizer = create_layer(range);
+
+ auto del_btn = new ScalableButton(m_parent, wxID_ANY, m_bmp_delete);
+ del_btn->SetToolTip(_(L("Remove layer")));
+
+ sizer->Add(del_btn, 0, wxRIGHT | wxLEFT, em_unit(m_parent));
+
+ del_btn->Bind(wxEVT_BUTTON, [this, range](wxEvent &event) {
+ wxGetApp().obj_list()->del_layer_range(range);
+ });
+
+ auto add_btn = new ScalableButton(m_parent, wxID_ANY, m_bmp_add);
+ add_btn->SetToolTip(_(L("Add layer")));
+
+ sizer->Add(add_btn, 0, wxRIGHT, em_unit(m_parent));
+
+ add_btn->Bind(wxEVT_BUTTON, [this, range](wxEvent &event) {
+ wxGetApp().obj_list()->add_layer_range_after_current(range);
+ });
+ }
+}
+
+void ObjectLayers::update_layers_list()
+{
+ ObjectList* objects_ctrl = wxGetApp().obj_list();
+ if (objects_ctrl->multiple_selection()) return;
+
+ const auto item = objects_ctrl->GetSelection();
+ if (!item) return;
+
+ const int obj_idx = objects_ctrl->get_selected_obj_idx();
+ if (obj_idx < 0) return;
+
+ const ItemType type = objects_ctrl->GetModel()->GetItemType(item);
+ if (!(type & (itLayerRoot | itLayer))) return;
+
+ m_object = objects_ctrl->object(obj_idx);
+ if (!m_object || m_object->layer_config_ranges.empty()) return;
+
+ // Delete all controls from options group except of the legends
+
+ const int cols = m_grid_sizer->GetEffectiveColsCount();
+ const int rows = m_grid_sizer->GetEffectiveRowsCount();
+ for (int idx = cols*rows-1; idx >= cols; idx--) {
+ wxSizerItem* t = m_grid_sizer->GetItem(idx);
+ if (t->IsSizer())
+ t->GetSizer()->Clear(true);
+ else
+ t->DeleteWindows();
+ m_grid_sizer->Remove(idx);
+ }
+
+ // Add new control according to the selected item
+
+ if (type & itLayerRoot)
+ create_layers_list();
+ else
+ create_layer(objects_ctrl->GetModel()->GetLayerRangeByItem(item));
+
+ m_parent->Layout();
+}
+
+void ObjectLayers::update_scene_from_editor_selection() const
+{
+ // needed to show the visual hints in 3D scene
+ wxGetApp().plater()->canvas3D()->handle_layers_data_focus_event(m_selectable_range, m_selection_type);
+}
+
+void ObjectLayers::UpdateAndShow(const bool show)
+{
+ if (show)
+ update_layers_list();
+
+ OG_Settings::UpdateAndShow(show);
+}
+
+void ObjectLayers::msw_rescale()
+{
+ m_bmp_delete.msw_rescale();
+ m_bmp_add.msw_rescale();
+}
+
+void ObjectLayers::reset_selection()
+{
+ m_selectable_range = { 0.0, 0.0 };
+ m_selection_type = etLayerHeight;
+}
+
+LayerRangeEditor::LayerRangeEditor( ObjectLayers* parent,
+ const wxString& value,
+ EditorType type,
+ std::function<void(EditorType)> set_focus_data_fn,
+ std::function<bool(coordf_t, bool enter_pressed)> edit_fn
+ ) :
+ m_valid_value(value),
+ m_type(type),
+ m_set_focus_data(set_focus_data_fn),
+ wxTextCtrl(parent->m_parent, wxID_ANY, value, wxDefaultPosition,
+ wxSize(8 * em_unit(parent->m_parent), wxDefaultCoord), wxTE_PROCESS_ENTER)
+{
+ this->SetFont(wxGetApp().normal_font());
+
+ this->Bind(wxEVT_TEXT_ENTER, [this, edit_fn](wxEvent&)
+ {
+ m_enter_pressed = true;
+ // If LayersList wasn't updated/recreated, we can call wxEVT_KILL_FOCUS.Skip()
+ if (m_type&etLayerHeight) {
+ if (!edit_fn(get_value(), true))
+ SetValue(m_valid_value);
+ else
+ m_valid_value = double_to_string(get_value());
+ m_call_kill_focus = true;
+ }
+ else if (!edit_fn(get_value(), true)) {
+ SetValue(m_valid_value);
+ m_call_kill_focus = true;
+ }
+ }, this->GetId());
+
+ this->Bind(wxEVT_KILL_FOCUS, [this, edit_fn](wxFocusEvent& e)
+ {
+ if (!m_enter_pressed) {
+#ifndef __WXGTK__
+ /* Update data for next editor selection.
+ * But under GTK it lucks like there is no information about selected control at e.GetWindow(),
+ * so we'll take it from wxEVT_LEFT_DOWN event
+ * */
+ LayerRangeEditor* new_editor = dynamic_cast<LayerRangeEditor*>(e.GetWindow());
+ if (new_editor)
+ new_editor->set_focus_data();
+#endif // not __WXGTK__
+ // If LayersList wasn't updated/recreated, we should call e.Skip()
+ if (m_type & etLayerHeight) {
+ if (!edit_fn(get_value(), false))
+ SetValue(m_valid_value);
+ else
+ m_valid_value = double_to_string(get_value());
+ e.Skip();
+ }
+ else if (!edit_fn(get_value(), false)) {
+ SetValue(m_valid_value);
+ e.Skip();
+ }
+ }
+ else if (m_call_kill_focus) {
+ m_call_kill_focus = false;
+ e.Skip();
+ }
+ }, this->GetId());
+
+ this->Bind(wxEVT_SET_FOCUS, [this, parent](wxFocusEvent& e)
+ {
+ set_focus_data();
+ parent->update_scene_from_editor_selection();
+ e.Skip();
+ }, this->GetId());
+
+#ifdef __WXGTK__ // Workaround! To take information about selectable range
+ this->Bind(wxEVT_LEFT_DOWN, [this](wxEvent& e)
+ {
+ set_focus_data();
+ e.Skip();
+ }, this->GetId());
+#endif //__WXGTK__
+
+ this->Bind(wxEVT_CHAR, ([this](wxKeyEvent& event)
+ {
+ // select all text using Ctrl+A
+ if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL))
+ this->SetSelection(-1, -1); //select all
+ event.Skip();
+ }));
+}
+
+coordf_t LayerRangeEditor::get_value()
+{
+ wxString str = GetValue();
+
+ coordf_t layer_height;
+ // Replace the first occurence of comma in decimal number.
+ str.Replace(",", ".", false);
+ if (str == ".")
+ layer_height = 0.0;
+ else
+ {
+ if (!str.ToCDouble(&layer_height) || layer_height < 0.0f)
+ {
+ show_error(m_parent, _(L("Invalid numeric input.")));
+ SetValue(double_to_string(layer_height));
+ }
+ }
+
+ return layer_height;
+}
+
+} //namespace GUI
+} //namespace Slic3r \ No newline at end of file
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
new file mode 100644
index 000000000..f274183e2
--- /dev/null
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -0,0 +1,88 @@
+#ifndef slic3r_GUI_ObjectLayers_hpp_
+#define slic3r_GUI_ObjectLayers_hpp_
+
+#include "GUI_ObjectSettings.hpp"
+#include "wxExtensions.hpp"
+
+#ifdef __WXOSX__
+#include "../libslic3r/PrintConfig.hpp"
+#endif
+
+class wxBoxSizer;
+
+namespace Slic3r {
+class ModelObject;
+
+namespace GUI {
+class ConfigOptionsGroup;
+
+typedef double coordf_t;
+typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
+
+class ObjectLayers;
+
+enum EditorType
+{
+ etUndef = 0,
+ etMinZ = 1,
+ etMaxZ = 2,
+ etLayerHeight = 4,
+};
+
+class LayerRangeEditor : public wxTextCtrl
+{
+ bool m_enter_pressed { false };
+ bool m_call_kill_focus { false };
+ wxString m_valid_value;
+ EditorType m_type;
+
+ std::function<void(EditorType)> m_set_focus_data;
+
+public:
+ LayerRangeEditor( ObjectLayers* parent,
+ const wxString& value = wxEmptyString,
+ EditorType type = etUndef,
+ std::function<void(EditorType)> set_focus_data_fn = [](EditorType) {;},
+ std::function<bool(coordf_t, bool)> edit_fn = [](coordf_t, bool) {return false; }
+ );
+ ~LayerRangeEditor() {}
+
+ EditorType type() const {return m_type;}
+ void set_focus_data() const { m_set_focus_data(m_type);}
+
+private:
+ coordf_t get_value();
+};
+
+class ObjectLayers : public OG_Settings
+{
+ ScalableBitmap m_bmp_delete;
+ ScalableBitmap m_bmp_add;
+ ModelObject* m_object {nullptr};
+
+ wxFlexGridSizer* m_grid_sizer;
+ t_layer_height_range m_selectable_range;
+ EditorType m_selection_type {etUndef};
+
+public:
+ ObjectLayers(wxWindow* parent);
+ ~ObjectLayers() {}
+
+ void select_editor(LayerRangeEditor* editor, const bool is_last_edited_range);
+ wxSizer* create_layer(const t_layer_height_range& range); // without_buttons
+ void create_layers_list();
+ void update_layers_list();
+
+ void update_scene_from_editor_selection() const;
+
+ void UpdateAndShow(const bool show) override;
+ void msw_rescale();
+ void reset_selection();
+ void set_selectable_range(const t_layer_height_range& range) { m_selectable_range = range; }
+
+ friend class LayerRangeEditor;
+};
+
+}}
+
+#endif // slic3r_GUI_ObjectLayers_hpp_
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index acb6d3a86..d47c84c37 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1,6 +1,7 @@
#include "libslic3r/libslic3r.h"
#include "GUI_ObjectList.hpp"
#include "GUI_ObjectManipulation.hpp"
+#include "GUI_ObjectLayers.hpp"
#include "GUI_App.hpp"
#include "I18N.hpp"
@@ -152,10 +153,10 @@ ObjectList::ObjectList(wxWindow* parent) :
wxAcceleratorTable accel(6, entries);
SetAcceleratorTable(accel);
- this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY)); }, wxID_COPY);
- this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE)); }, wxID_PASTE);
- this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->select_item_all_children(); }, wxID_SELECTALL);
- this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->remove(); }, wxID_DELETE);
+ this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->copy(); }, wxID_COPY);
+ this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->paste(); }, wxID_PASTE);
+ this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->select_item_all_children(); }, wxID_SELECTALL);
+ this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->remove(); }, wxID_DELETE);
}
#else __WXOSX__
Bind(wxEVT_CHAR, [this](wxKeyEvent& event) { key_event(event); }); // doesn't work on OSX
@@ -355,12 +356,13 @@ DynamicPrintConfig& ObjectList::get_item_config(const wxDataViewItem& item) cons
const ItemType type = m_objects_model->GetItemType(item);
const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) :
- m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
+ m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
const int vol_idx = type & itVolume ? m_objects_model->GetVolumeIdByItem(item) : -1;
assert(obj_idx >= 0 || ((type & itVolume) && vol_idx >=0));
return type & itVolume ?(*m_objects)[obj_idx]->volumes[vol_idx]->config :
+ type & itLayer ?(*m_objects)[obj_idx]->layer_config_ranges[m_objects_model->GetLayerRangeByItem(item)] :
(*m_objects)[obj_idx]->config;
}
@@ -446,16 +448,23 @@ void ObjectList::update_extruder_in_config(const wxDataViewItem& item)
{
if (m_prevent_update_extruder_in_config)
return;
- if (m_objects_model->GetParent(item) == wxDataViewItem(0)) {
+
+ const ItemType item_type = m_objects_model->GetItemType(item);
+ if (item_type & itObject) {
const int obj_idx = m_objects_model->GetIdByItem(item);
m_config = &(*m_objects)[obj_idx]->config;
}
else {
- const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item));
+ const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
+ if (item_type & itVolume)
+ {
const int volume_id = m_objects_model->GetVolumeIdByItem(item);
if (obj_idx < 0 || volume_id < 0)
return;
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
+ }
+ else if (item_type & itLayer)
+ m_config = &get_item_config(item);
}
wxVariant variant;
@@ -465,7 +474,7 @@ void ObjectList::update_extruder_in_config(const wxDataViewItem& item)
if (!m_config || selection.empty())
return;
- const int extruder = selection.size() > 1 ? 0 : atoi(selection.c_str());
+ const int extruder = /*selection.size() > 1 ? 0 : */atoi(selection.c_str());
m_config->set_key_value("extruder", new ConfigOptionInt(extruder));
// update scene
@@ -574,9 +583,75 @@ void ObjectList::selection_changed()
wxPostEvent(this, event);
}
+ if (const wxDataViewItem item = GetSelection())
+ {
+ const ItemType type = m_objects_model->GetItemType(item);
+ // to correct visual hints for layers editing on the Scene
+ if (type & (itLayer|itLayerRoot)) {
+ wxGetApp().obj_layers()->reset_selection();
+
+ if (type & itLayerRoot)
+ wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false);
+ else {
+ wxGetApp().obj_layers()->set_selectable_range(m_objects_model->GetLayerRangeByItem(item));
+ wxGetApp().obj_layers()->update_scene_from_editor_selection();
+ }
+ }
+ }
+
part_selection_changed();
}
+void ObjectList::fill_layer_config_ranges_cache()
+{
+ wxDataViewItemArray sel_layers;
+ GetSelections(sel_layers);
+
+ const int obj_idx = m_objects_model->GetObjectIdByItem(sel_layers[0]);
+ if (obj_idx < 0 || (int)m_objects->size() <= obj_idx)
+ return;
+
+ const t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
+ m_layer_config_ranges_cache.clear();
+
+ for (const auto layer_item : sel_layers)
+ if (m_objects_model->GetItemType(layer_item) & itLayer) {
+ auto range = m_objects_model->GetLayerRangeByItem(layer_item);
+ auto it = ranges.find(range);
+ if (it != ranges.end())
+ m_layer_config_ranges_cache[it->first] = it->second;
+ }
+}
+
+void ObjectList::paste_layers_into_list()
+{
+ const int obj_idx = m_objects_model->GetObjectIdByItem(GetSelection());
+
+ if (obj_idx < 0 || (int)m_objects->size() <= obj_idx ||
+ m_layer_config_ranges_cache.empty() || printer_technology() == ptSLA)
+ return;
+
+ const wxDataViewItem object_item = m_objects_model->GetItemById(obj_idx);
+ wxDataViewItem layers_item = m_objects_model->GetLayerRootItem(object_item);
+ if (layers_item)
+ m_objects_model->Delete(layers_item);
+
+ t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
+
+ // and create Layer item(s) according to the layer_config_ranges
+ for (const auto range : m_layer_config_ranges_cache)
+ ranges.emplace(range);
+
+ layers_item = add_layer_root_item(object_item);
+
+ changed_object(obj_idx);
+
+ select_item(layers_item);
+#ifndef __WXOSX__
+ selection_changed();
+#endif //no __WXOSX__
+}
+
void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes)
{
if ((obj_idx < 0) || ((int)m_objects->size() <= obj_idx))
@@ -657,7 +732,7 @@ void ObjectList::OnContextMenu(wxDataViewEvent&)
const wxPoint pt = get_mouse_position_in_control();
HitTest(pt, item, col);
if (!item)
-#ifdef __WXOSX__ // #ys_FIXME temporary workaround for OSX
+#ifdef __WXOSX__ // temporary workaround for OSX
// after Yosemite OS X version, HitTest return undefined item
item = GetSelection();
if (item)
@@ -703,10 +778,11 @@ void ObjectList::show_context_menu()
if (item)
{
const ItemType type = m_objects_model->GetItemType(item);
- if (!(type & (itObject | itVolume | itInstance)))
+ if (!(type & (itObject | itVolume | itLayer | itInstance)))
return;
wxMenu* menu = type & itInstance ? &m_menu_instance :
+ type & itLayer ? &m_menu_layer :
m_objects_model->GetParent(item) != wxDataViewItem(0) ? &m_menu_part :
printer_technology() == ptFFF ? &m_menu_object : &m_menu_sla_object;
@@ -717,6 +793,22 @@ void ObjectList::show_context_menu()
}
}
+void ObjectList::copy()
+{
+ if (m_selection_mode & smLayer)
+ fill_layer_config_ranges_cache();
+ else
+ wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY));
+}
+
+void ObjectList::paste()
+{
+ if (!m_layer_config_ranges_cache.empty())
+ paste_layers_into_list();
+ else
+ wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE));
+}
+
#ifndef __WXOSX__
void ObjectList::key_event(wxKeyEvent& event)
{
@@ -731,10 +823,10 @@ void ObjectList::key_event(wxKeyEvent& event)
}
else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/))
select_item_all_children();
- else if (wxGetKeyState(wxKeyCode('C')) && wxGetKeyState(WXK_CONTROL))
- wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY));
+ else if (wxGetKeyState(wxKeyCode('C')) && wxGetKeyState(WXK_CONTROL))
+ copy();
else if (wxGetKeyState(wxKeyCode('V')) && wxGetKeyState(WXK_CONTROL))
- wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE));
+ paste();
else
event.Skip();
}
@@ -1040,7 +1132,17 @@ void ObjectList::get_settings_choice(const wxString& category_name)
void ObjectList::get_freq_settings_choice(const wxString& bundle_name)
{
- const std::vector<std::string>& options = get_options_for_bundle(bundle_name);
+ std::vector<std::string> options = get_options_for_bundle(bundle_name);
+
+ /* Because of we couldn't edited layer_height for ItVolume from settings list,
+ * correct options according to the selected item type :
+ * remove "layer_height" option
+ */
+ if ((m_objects_model->GetItemType(GetSelection()) & itVolume) && bundle_name == _("Layers and Perimeters")) {
+ const auto layer_height_it = std::find(options.begin(), options.end(), "layer_height");
+ if (layer_height_it != options.end())
+ options.erase(layer_height_it);
+ }
assert(m_config);
auto opt_keys = m_config->keys();
@@ -1144,6 +1246,12 @@ wxMenuItem* ObjectList::append_menu_item_split(wxMenu* menu)
[this]() { return is_splittable(); }, wxGetApp().plater());
}
+wxMenuItem* ObjectList::append_menu_item_layers_editing(wxMenu* menu)
+{
+ return append_menu_item(menu, wxID_ANY, _(L("Edit Layers")), "",
+ [this](wxCommandEvent&) { layers_editing(); }, "layers", menu);
+}
+
wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
{
MenuWithSeparators* menu = dynamic_cast<MenuWithSeparators*>(menu_);
@@ -1308,7 +1416,11 @@ void ObjectList::create_object_popupmenu(wxMenu *menu)
append_menu_item_scale_selection_to_fit_print_volume(menu);
// Split object to parts
- m_menu_item_split = append_menu_item_split(menu);
+ append_menu_item_split(menu);
+ menu->AppendSeparator();
+
+ // Layers Editing for object
+ append_menu_item_layers_editing(menu);
menu->AppendSeparator();
// rest of a object_menu will be added later in:
@@ -1337,7 +1449,7 @@ void ObjectList::create_part_popupmenu(wxMenu *menu)
append_menu_item_fix_through_netfabb(menu);
append_menu_item_export_stl(menu);
- m_menu_item_split_part = append_menu_item_split(menu);
+ append_menu_item_split(menu);
// Append change part type
menu->AppendSeparator();
@@ -1587,38 +1699,52 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
ItemType type;
m_objects_model->GetItemInfo(item, type, obj_idx, idx);
- if (type == itUndef)
+ if (type & itUndef)
return;
- if (type == itSettings)
- del_settings_from_config();
- else if (type == itInstanceRoot && obj_idx != -1)
+ if (type & itSettings)
+ del_settings_from_config(m_objects_model->GetParent(item));
+ else if (type & itInstanceRoot && obj_idx != -1)
del_instances_from_object(obj_idx);
+ else if (type & itLayerRoot && obj_idx != -1)
+ del_layers_from_object(obj_idx);
+ else if (type & itLayer && obj_idx != -1)
+ del_layer_from_object(obj_idx, m_objects_model->GetLayerRangeByItem(item));
else if (idx == -1)
return;
else if (!del_subobject_from_object(obj_idx, idx, type))
return;
// If last volume item with warning was deleted, unmark object item
- if (type == itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0)
+ if (type & itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0)
m_objects_model->DeleteWarningIcon(m_objects_model->GetParent(item));
m_objects_model->Delete(item);
}
-void ObjectList::del_settings_from_config()
+void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item)
{
- auto opt_keys = m_config->keys();
- if (opt_keys.size() == 1 && opt_keys[0] == "extruder")
+ const bool is_layer_settings = m_objects_model->GetItemType(parent_item) == itLayer;
+
+ const int opt_cnt = m_config->keys().size();
+ if (opt_cnt == 1 && m_config->has("extruder") ||
+ is_layer_settings && opt_cnt == 2 && m_config->has("extruder") && m_config->has("layer_height"))
return;
+
int extruder = -1;
if (m_config->has("extruder"))
extruder = m_config->option<ConfigOptionInt>("extruder")->value;
+ coordf_t layer_height = 0.0;
+ if (is_layer_settings)
+ layer_height = m_config->opt_float("layer_height");
+
m_config->clear();
if (extruder >= 0)
m_config->set_key_value("extruder", new ConfigOptionInt(extruder));
+ if (is_layer_settings)
+ m_config->set_key_value("layer_height", new ConfigOptionFloat(layer_height));
}
void ObjectList::del_instances_from_object(const int obj_idx)
@@ -1637,6 +1763,24 @@ void ObjectList::del_instances_from_object(const int obj_idx)
changed_object(obj_idx);
}
+void ObjectList::del_layer_from_object(const int obj_idx, const t_layer_height_range& layer_range)
+{
+ const auto del_range = object(obj_idx)->layer_config_ranges.find(layer_range);
+ if (del_range == object(obj_idx)->layer_config_ranges.end())
+ return;
+
+ object(obj_idx)->layer_config_ranges.erase(del_range);
+
+ changed_object(obj_idx);
+}
+
+void ObjectList::del_layers_from_object(const int obj_idx)
+{
+ object(obj_idx)->layer_config_ranges.clear();
+
+ changed_object(obj_idx);
+}
+
bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, const int type)
{
if (obj_idx == 1000)
@@ -1738,6 +1882,70 @@ void ObjectList::split()
changed_object(obj_idx);
}
+void ObjectList::layers_editing()
+{
+ const auto item = GetSelection();
+ const int obj_idx = get_selected_obj_idx();
+ if (!item || obj_idx < 0)
+ return;
+
+ const wxDataViewItem obj_item = m_objects_model->GetTopParent(item);
+ wxDataViewItem layers_item = m_objects_model->GetLayerRootItem(obj_item);
+
+ // if it doesn't exist now
+ if (!layers_item.IsOk())
+ {
+ t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
+
+ // set some default value
+ if (ranges.empty())
+ ranges[{ 0.0f, 2.0f }] = get_default_layer_config(obj_idx);
+
+ // create layer root item
+ layers_item = add_layer_root_item(obj_item);
+ }
+ if (!layers_item.IsOk())
+ return;
+
+ // to correct visual hints for layers editing on the Scene, reset previous selection
+ wxGetApp().obj_layers()->reset_selection();
+ wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false);
+
+ // select LayerRoor item and expand
+ select_item(layers_item);
+ Expand(layers_item);
+}
+
+wxDataViewItem ObjectList::add_layer_root_item(const wxDataViewItem obj_item)
+{
+ const int obj_idx = m_objects_model->GetIdByItem(obj_item);
+ if (obj_idx < 0 ||
+ object(obj_idx)->layer_config_ranges.empty() ||
+ printer_technology() == ptSLA)
+ return wxDataViewItem(0);
+
+ // create LayerRoot item
+ wxDataViewItem layers_item = m_objects_model->AddLayersRoot(obj_item);
+
+ // and create Layer item(s) according to the layer_config_ranges
+ for (const auto range : object(obj_idx)->layer_config_ranges)
+ add_layer_item(range.first, layers_item);
+
+ return layers_item;
+}
+
+DynamicPrintConfig ObjectList::get_default_layer_config(const int obj_idx)
+{
+ DynamicPrintConfig config;
+ coordf_t layer_height = object(obj_idx)->config.has("layer_height") ?
+ object(obj_idx)->config.opt_float("layer_height") :
+ wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_float("layer_height");
+ config.set_key_value("layer_height",new ConfigOptionFloat(layer_height));
+ config.set_key_value("extruder", new ConfigOptionInt(0));
+
+ return config;
+}
+
bool ObjectList::get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume)
{
auto obj_idx = get_selected_obj_idx();
@@ -1807,6 +2015,7 @@ void ObjectList::part_selection_changed()
bool update_and_show_manipulations = false;
bool update_and_show_settings = false;
+ bool update_and_show_layers = false;
const auto item = GetSelection();
@@ -1829,36 +2038,47 @@ void ObjectList::part_selection_changed()
update_and_show_manipulations = true;
}
else {
- auto parent = m_objects_model->GetParent(item);
- // Take ID of the parent object to "inform" perl-side which object have to be selected on the scene
- obj_idx = m_objects_model->GetIdByItem(parent);
- if (m_objects_model->GetItemType(item) == itSettings) {
- if (m_objects_model->GetParent(parent) == wxDataViewItem(0)) {
+ obj_idx = m_objects_model->GetObjectIdByItem(item);
+
+ const ItemType type = m_objects_model->GetItemType(item);
+ if (type & itSettings) {
+ const auto parent = m_objects_model->GetParent(item);
+ const ItemType parent_type = m_objects_model->GetItemType(parent);
+
+ if (parent_type & itObject) {
og_name = _(L("Object Settings to modify"));
m_config = &(*m_objects)[obj_idx]->config;
}
- else {
+ else if (parent_type & itVolume) {
og_name = _(L("Part Settings to modify"));
- auto main_parent = m_objects_model->GetParent(parent);
- obj_idx = m_objects_model->GetIdByItem(main_parent);
- const auto volume_id = m_objects_model->GetVolumeIdByItem(parent);
+ volume_id = m_objects_model->GetVolumeIdByItem(parent);
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
}
+ else if (parent_type & itLayer) {
+ og_name = _(L("Layer range Settings to modify"));
+ m_config = &get_item_config(parent);
+ }
update_and_show_settings = true;
}
- else if (m_objects_model->GetItemType(item) == itVolume) {
+ else if (type & itVolume) {
og_name = _(L("Part manipulation"));
volume_id = m_objects_model->GetVolumeIdByItem(item);
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
update_and_show_manipulations = true;
}
- else if (m_objects_model->GetItemType(item) == itInstance) {
+ else if (type & itInstance) {
og_name = _(L("Instance manipulation"));
update_and_show_manipulations = true;
// fill m_config by object's values
- const int obj_idx_ = m_objects_model->GetObjectIdByItem(item);
- m_config = &(*m_objects)[obj_idx_]->config;
+ m_config = &(*m_objects)[obj_idx]->config;
+ }
+ else if (type & (itLayerRoot|itLayer)) {
+ og_name = type & itLayerRoot ? _(L("Layers Editing")) : _(L("Layer Editing"));
+ update_and_show_layers = true;
+
+ if (type & itLayer)
+ m_config = &get_item_config(item);
}
}
}
@@ -1878,11 +2098,18 @@ void ObjectList::part_selection_changed()
if (update_and_show_settings)
wxGetApp().obj_settings()->get_og()->set_name(" " + og_name + " ");
+ if (printer_technology() == ptSLA)
+ update_and_show_layers = false;
+ else if (update_and_show_layers)
+ wxGetApp().obj_layers()->get_og()->set_name(" " + og_name + " ");
+
Sidebar& panel = wxGetApp().sidebar();
panel.Freeze();
+ wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false);
wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations);
wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings);
+ wxGetApp().obj_layers() ->UpdateAndShow(update_and_show_layers);
wxGetApp().sidebar().show_info_sizer();
panel.Layout();
@@ -1928,6 +2155,9 @@ void ObjectList::add_object_to_list(size_t obj_idx)
Expand(item);
}
+ // Add layers if it has
+ add_layer_root_item(item);
+
#ifndef __WXOSX__
selection_changed();
#endif //__WXMSW__
@@ -2074,16 +2304,196 @@ void ObjectList::remove()
wxDataViewItemArray sels;
GetSelections(sels);
+ wxDataViewItem parent = wxDataViewItem(0);
+
for (auto& item : sels)
{
if (m_objects_model->GetParent(item) == wxDataViewItem(0))
delete_from_model_and_list(itObject, m_objects_model->GetIdByItem(item), -1);
else {
- if (sels.size() == 1)
+ if (m_objects_model->GetItemType(item) & itLayer) {
+ parent = m_objects_model->GetParent(item);
+ wxDataViewItemArray children;
+ if (m_objects_model->GetChildren(parent, children) == 1)
+ parent = m_objects_model->GetTopParent(item);
+ }
+ else if (sels.size() == 1)
select_item(m_objects_model->GetParent(item));
+
del_subobject_item(item);
}
}
+
+ if (parent)
+ select_item(parent);
+}
+
+void ObjectList::del_layer_range(const t_layer_height_range& range)
+{
+ const int obj_idx = get_selected_obj_idx();
+ if (obj_idx < 0) return;
+
+ t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
+
+ wxDataViewItem selectable_item = GetSelection();
+
+ if (ranges.size() == 1)
+ selectable_item = m_objects_model->GetParent(selectable_item);
+
+ wxDataViewItem layer_item = m_objects_model->GetItemByLayerRange(obj_idx, range);
+ del_subobject_item(layer_item);
+
+ select_item(selectable_item);
+}
+
+double get_min_layer_height(const int extruder_idx)
+{
+ const DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
+ return config.opt_float("min_layer_height", extruder_idx <= 0 ? 0 : extruder_idx-1);
+}
+
+double get_max_layer_height(const int extruder_idx)
+{
+ const DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
+ return config.opt_float("max_layer_height", extruder_idx <= 0 ? 0 : extruder_idx-1);
+}
+
+void ObjectList::add_layer_range_after_current(const t_layer_height_range& current_range)
+{
+ const int obj_idx = get_selected_obj_idx();
+ if (obj_idx < 0) return;
+
+ const wxDataViewItem layers_item = GetSelection();
+
+ t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
+
+ const t_layer_height_range& last_range = (--ranges.end())->first;
+
+ if (current_range == last_range)
+ {
+ const t_layer_height_range& new_range = { last_range.second, last_range.second + 2.0f };
+ ranges[new_range] = get_default_layer_config(obj_idx);
+ add_layer_item(new_range, layers_item);
+ }
+ else
+ {
+ const t_layer_height_range& next_range = (++ranges.find(current_range))->first;
+
+ if (current_range.second > next_range.first)
+ return; // range division has no sense
+
+ const int layer_idx = m_objects_model->GetItemIdByLayerRange(obj_idx, next_range);
+ if (layer_idx < 0)
+ return;
+
+ if (current_range.second == next_range.first)
+ {
+ const auto old_config = ranges.at(next_range);
+
+ const coordf_t delta = (next_range.second - next_range.first);
+ if (delta < get_min_layer_height(old_config.opt_int("extruder"))/*0.05f*/) // next range division has no sense
+ return;
+
+ const coordf_t midl_layer = next_range.first + 0.5f * delta;
+
+ t_layer_height_range new_range = { midl_layer, next_range.second };
+
+ // delete old layer
+
+ wxDataViewItem layer_item = m_objects_model->GetItemByLayerRange(obj_idx, next_range);
+ del_subobject_item(layer_item);
+
+ // create new 2 layers instead of deleted one
+
+ ranges[new_range] = old_config;
+ add_layer_item(new_range, layers_item, layer_idx);
+
+ new_range = { current_range.second, midl_layer };
+ ranges[new_range] = get_default_layer_config(obj_idx);
+ add_layer_item(new_range, layers_item, layer_idx);
+ }
+ else
+ {
+ const t_layer_height_range new_range = { current_range.second, next_range.first };
+ ranges[new_range] = get_default_layer_config(obj_idx);
+ add_layer_item(new_range, layers_item, layer_idx);
+ }
+ }
+
+ changed_object(obj_idx);
+
+ // select item to update layers sizer
+ select_item(layers_item);
+}
+
+void ObjectList::add_layer_item(const t_layer_height_range& range,
+ const wxDataViewItem layers_item,
+ const int layer_idx /* = -1*/)
+{
+ const int obj_idx = m_objects_model->GetObjectIdByItem(layers_item);
+ if (obj_idx < 0) return;
+
+ const DynamicPrintConfig& config = object(obj_idx)->layer_config_ranges[range];
+ if (!config.has("extruder"))
+ return;
+
+ const auto layer_item = m_objects_model->AddLayersChild(layers_item,
+ range,
+ config.opt_int("extruder"),
+ layer_idx);
+
+ if (config.keys().size() > 2)
+ select_item(m_objects_model->AddSettingsChild(layer_item));
+}
+
+bool ObjectList::edit_layer_range(const t_layer_height_range& range, coordf_t layer_height)
+{
+ const int obj_idx = get_selected_obj_idx();
+ if (obj_idx < 0)
+ return false;
+
+ DynamicPrintConfig* config = &object(obj_idx)->layer_config_ranges[range];
+ if (fabs(layer_height - config->opt_float("layer_height")) < EPSILON)
+ return false;
+
+ const int extruder_idx = config->opt_int("extruder");
+
+ if (layer_height >= get_min_layer_height(extruder_idx) &&
+ layer_height <= get_max_layer_height(extruder_idx))
+ {
+ config->set_key_value("layer_height", new ConfigOptionFloat(layer_height));
+ return true;
+ }
+
+ return false;
+}
+
+bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_layer_height_range& new_range)
+{
+ const int obj_idx = get_selected_obj_idx();
+ if (obj_idx < 0) return false;
+
+ const ItemType sel_type = m_objects_model->GetItemType(GetSelection());
+
+ t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
+
+ const DynamicPrintConfig config = ranges[range];
+
+ ranges.erase(range);
+ ranges[new_range] = config;
+
+ wxDataViewItem root_item = m_objects_model->GetLayerRootItem(m_objects_model->GetItemById(obj_idx));
+ m_objects_model->DeleteChildren(root_item);
+
+ if (root_item.IsOk())
+ // create Layer item(s) according to the layer_config_ranges
+ for (const auto r : ranges)
+ add_layer_item(r.first, root_item);
+
+ select_item(sel_type&itLayer ? m_objects_model->GetItemByLayerRange(obj_idx, new_range) : root_item);
+ Expand(root_item);
+
+ return true;
}
void ObjectList::init_objects()
@@ -2113,11 +2523,12 @@ void ObjectList::update_selections()
m_selection_mode = smInstance;
// We doesn't update selection if SettingsItem for the current object/part is selected
- if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings )
+// if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings )
+ if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) & (itSettings | itLayerRoot | itLayer))
{
const auto item = GetSelection();
if (selection.is_single_full_object()) {
- if ( m_objects_model->GetIdByItem(m_objects_model->GetParent(item)) == selection.get_object_idx())
+ if (m_objects_model->GetObjectIdByItem(item) == selection.get_object_idx())
return;
sels.Add(m_objects_model->GetItemById(selection.get_object_idx()));
}
@@ -2238,22 +2649,18 @@ void ObjectList::update_selections_on_canvas()
auto add_to_selection = [this](const wxDataViewItem& item, Selection& selection, int instance_idx, bool as_single_selection)
{
const ItemType& type = m_objects_model->GetItemType(item);
- if ( type == itInstanceRoot || m_objects_model->GetParent(item) == wxDataViewItem(0) ) {
- wxDataViewItem obj_item = type == itInstanceRoot ? m_objects_model->GetParent(item) : item;
- selection.add_object(m_objects_model->GetIdByItem(obj_item), as_single_selection);
- return;
- }
+ const int obj_idx = m_objects_model->GetObjectIdByItem(item);
if (type == itVolume) {
- const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item));
const int vol_idx = m_objects_model->GetVolumeIdByItem(item);
selection.add_volume(obj_idx, vol_idx, std::max(instance_idx, 0), as_single_selection);
}
else if (type == itInstance) {
- const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
const int inst_idx = m_objects_model->GetInstanceIdByItem(item);
selection.add_instance(obj_idx, inst_idx, as_single_selection);
}
+ else
+ selection.add_object(obj_idx, as_single_selection);
};
// stores current instance idx before to clear the selection
@@ -2261,7 +2668,7 @@ void ObjectList::update_selections_on_canvas()
if (sel_cnt == 1) {
wxDataViewItem item = GetSelection();
- if (m_objects_model->GetItemType(item) & (itSettings|itInstanceRoot))
+ if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer))
add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, true);
else
add_to_selection(item, selection, instance_idx, true);
@@ -2324,11 +2731,13 @@ void ObjectList::select_item_all_children()
}
else {
const auto item = GetSelection();
- // Some volume(instance) is selected => select all volumes(instances) inside the current object
- if (m_objects_model->GetItemType(item) & (itVolume | itInstance))
+ const ItemType item_type = m_objects_model->GetItemType(item);
+ // Some volume/layer/instance is selected => select all volumes/layers/instances inside the current object
+ if (item_type & (itVolume | itInstance | itLayer))
m_objects_model->GetChildren(m_objects_model->GetParent(item), sels);
- m_selection_mode = m_objects_model->GetItemType(item)&itVolume ? smVolume : smInstance;
+ m_selection_mode = item_type&itVolume ? smVolume :
+ item_type&itLayer ? smLayer : smInstance;
}
SetSelections(sels);
@@ -2347,8 +2756,9 @@ void ObjectList::update_selection_mode()
}
const ItemType type = m_objects_model->GetItemType(GetSelection());
- m_selection_mode = type&itSettings ? smUndef :
- type&itVolume ? smVolume : smInstance;
+ m_selection_mode = type & itSettings ? smUndef :
+ type & itLayer ? smLayer :
+ type & itVolume ? smVolume : smInstance;
}
// check last selected item. If is it possible to select it
@@ -2359,33 +2769,37 @@ bool ObjectList::check_last_selection(wxString& msg_str)
const bool is_shift_pressed = wxGetKeyState(WXK_SHIFT);
- /* We can't mix Parts and Objects/Instances.
+ /* We can't mix Volumes, Layers and Objects/Instances.
* So, show information about it
*/
const ItemType type = m_objects_model->GetItemType(m_last_selected_item);
- // check a case of a selection of the Parts from different Objects
- bool impossible_multipart_selection = false;
- if (type & itVolume && m_selection_mode == smVolume)
- {
+ // check a case of a selection of the same type items from different Objects
+ auto impossible_multi_selection = [type, this](const ItemType item_type, const SELECTION_MODE selection_mode) {
+ if (!(type & item_type && m_selection_mode & selection_mode))
+ return false;
+
wxDataViewItemArray sels;
GetSelections(sels);
- for (const auto& sel: sels)
- if (sel != m_last_selected_item &&
- m_objects_model->GetParent(sel) != m_objects_model->GetParent(m_last_selected_item))
- {
- impossible_multipart_selection = true;
- break;
- }
- }
+ for (const auto& sel : sels)
+ if (sel != m_last_selected_item &&
+ m_objects_model->GetTopParent(sel) != m_objects_model->GetTopParent(m_last_selected_item))
+ return true;
- if (impossible_multipart_selection ||
+ return false;
+ };
+
+ if (impossible_multi_selection(itVolume, smVolume) ||
+ impossible_multi_selection(itLayer, smLayer ) ||
type & itSettings ||
- type & itVolume && m_selection_mode == smInstance ||
- !(type & itVolume) && m_selection_mode == smVolume)
+ type & itVolume && !(m_selection_mode & smVolume ) ||
+ type & itLayer && !(m_selection_mode & smLayer ) ||
+ type & itInstance && !(m_selection_mode & smInstance)
+ )
{
// Inform user why selection isn't complited
- const wxString item_type = m_selection_mode == smInstance ? _(L("Object or Instance")) : _(L("Part"));
+ const wxString item_type = m_selection_mode & smInstance ? _(L("Object or Instance")) :
+ m_selection_mode & smVolume ? _(L("Part")) : _(L("Layer"));
msg_str = wxString::Format( _(L("Unsupported selection")) + "\n\n" +
_(L("You started your selection with %s Item.")) + "\n" +
@@ -2422,7 +2836,7 @@ void ObjectList::fix_multiselection_conflicts()
wxDataViewItemArray sels;
GetSelections(sels);
- if (m_selection_mode == smVolume)
+ if (m_selection_mode & (smVolume|smLayer))
{
// identify correct parent of the initial selected item
const wxDataViewItem& parent = m_objects_model->GetParent(m_last_selected_item == sels.front() ? sels.back() : sels.front());
@@ -2431,8 +2845,10 @@ void ObjectList::fix_multiselection_conflicts()
wxDataViewItemArray children; // selected volumes from current parent
m_objects_model->GetChildren(parent, children);
+ const ItemType item_type = m_selection_mode & smVolume ? itVolume : itLayer;
+
for (const auto child : children)
- if (IsSelected(child) && m_objects_model->GetItemType(child)&itVolume)
+ if (IsSelected(child) && m_objects_model->GetItemType(child) & item_type)
sels.Add(child);
// If some part is selected, unselect all items except of selected parts of the current object
@@ -2599,6 +3015,87 @@ void ObjectList::update_settings_items()
m_prevent_canvas_selection_update = false;
}
+// Update settings item for item had it
+void ObjectList::update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections)
+{
+ const wxDataViewItem& settings_item = m_objects_model->GetSettingsItem(item);
+ select_item(settings_item ? settings_item : m_objects_model->AddSettingsChild(item));
+
+ // If settings item was deleted from the list,
+ // it's need to be deleted from selection array, if it was there
+ if (settings_item != m_objects_model->GetSettingsItem(item) &&
+ selections.Index(settings_item) != wxNOT_FOUND) {
+ selections.Remove(settings_item);
+
+ // Select item, if settings_item doesn't exist for item anymore, but was selected
+ if (selections.Index(item) == wxNOT_FOUND)
+ selections.Add(item);
+ }
+}
+
+void ObjectList::update_object_list_by_printer_technology()
+{
+ m_prevent_canvas_selection_update = true;
+ wxDataViewItemArray sel;
+ GetSelections(sel); // stash selection
+
+ wxDataViewItemArray object_items;
+ m_objects_model->GetChildren(wxDataViewItem(0), object_items);
+
+ for (auto& object_item : object_items) {
+ // Update Settings Item for object
+ update_settings_item_and_selection(object_item, sel);
+
+ // Update settings for Volumes
+ wxDataViewItemArray all_object_subitems;
+ m_objects_model->GetChildren(object_item, all_object_subitems);
+ for (auto item : all_object_subitems)
+ if (m_objects_model->GetItemType(item) & itVolume)
+ // update settings for volume
+ update_settings_item_and_selection(item, sel);
+
+ // Update Layers Items
+ wxDataViewItem layers_item = m_objects_model->GetLayerRootItem(object_item);
+ if (!layers_item)
+ layers_item = add_layer_root_item(object_item);
+ else if (printer_technology() == ptSLA) {
+ // If layers root item will be deleted from the list, so
+ // it's need to be deleted from selection array, if it was there
+ wxDataViewItemArray del_items;
+ bool some_layers_was_selected = false;
+ m_objects_model->GetAllChildren(layers_item, del_items);
+ for (auto& del_item:del_items)
+ if (sel.Index(del_item) != wxNOT_FOUND) {
+ some_layers_was_selected = true;
+ sel.Remove(del_item);
+ }
+ if (sel.Index(layers_item) != wxNOT_FOUND) {
+ some_layers_was_selected = true;
+ sel.Remove(layers_item);
+ }
+
+ // delete all "layers" items
+ m_objects_model->Delete(layers_item);
+
+ // Select object_item, if layers_item doesn't exist for item anymore, but was some of layer items was/were selected
+ if (some_layers_was_selected)
+ sel.Add(object_item);
+ }
+ else {
+ wxDataViewItemArray all_obj_layers;
+ m_objects_model->GetChildren(layers_item, all_obj_layers);
+
+ for (auto item : all_obj_layers)
+ // update settings for layer
+ update_settings_item_and_selection(item, sel);
+ }
+ }
+
+ // restore selection:
+ SetSelections(sel);
+ m_prevent_canvas_selection_update = false;
+}
+
void ObjectList::update_object_menu()
{
append_menu_items_add_volume(&m_menu_object);
@@ -2772,7 +3269,8 @@ void ObjectList::msw_rescale()
for (MenuWithSeparators* menu : { &m_menu_object,
&m_menu_part,
&m_menu_sla_object,
- &m_menu_instance })
+ &m_menu_instance,
+ &m_menu_layer })
msw_rescale_menu(menu);
Layout();
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 3d312d9c9..354f6c019 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -33,6 +33,10 @@ typedef std::map< std::string, std::vector< std::pair<std::string, std::string>
typedef std::vector<ModelVolume*> ModelVolumePtrs;
+typedef double coordf_t;
+typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
+typedef std::map<t_layer_height_range, DynamicPrintConfig> t_layer_config_ranges;
+
namespace GUI {
wxDECLARE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent);
@@ -64,9 +68,10 @@ class ObjectList : public wxDataViewCtrl
{
enum SELECTION_MODE
{
- smUndef,
- smVolume,
- smInstance
+ smUndef = 0,
+ smVolume = 1,
+ smInstance = 2,
+ smLayer = 4
} m_selection_mode {smUndef};
struct dragged_item_data
@@ -119,12 +124,17 @@ class ObjectList : public wxDataViewCtrl
MenuWithSeparators m_menu_part;
MenuWithSeparators m_menu_sla_object;
MenuWithSeparators m_menu_instance;
- wxMenuItem* m_menu_item_split { nullptr };
- wxMenuItem* m_menu_item_split_part { nullptr };
+ MenuWithSeparators m_menu_layer;
wxMenuItem* m_menu_item_settings { nullptr };
wxMenuItem* m_menu_item_split_instances { nullptr };
- std::vector<wxBitmap*> m_bmp_vector;
+ ObjectDataViewModel *m_objects_model{ nullptr };
+ DynamicPrintConfig *m_config {nullptr};
+ std::vector<ModelObject*> *m_objects{ nullptr };
+
+ std::vector<wxBitmap*> m_bmp_vector;
+
+ t_layer_config_ranges m_layer_config_ranges_cache;
int m_selected_object_id = -1;
bool m_prevent_list_events = false; // We use this flag to avoid circular event handling Select()
@@ -153,11 +163,11 @@ public:
std::map<std::string, wxBitmap> CATEGORY_ICON;
- ObjectDataViewModel *m_objects_model{ nullptr };
- DynamicPrintConfig *m_config {nullptr};
-
- std::vector<ModelObject*> *m_objects{ nullptr };
+ ObjectDataViewModel* GetModel() const { return m_objects_model; }
+ DynamicPrintConfig* config() const { return m_config; }
+ std::vector<ModelObject*>* objects() const { return m_objects; }
+ ModelObject* object(const int obj_idx) const ;
void create_objects_ctrl();
void create_popup_menus();
@@ -192,6 +202,9 @@ public:
void key_event(wxKeyEvent& event);
#endif /* __WXOSX__ */
+ void copy();
+ void paste();
+
void get_settings_choice(const wxString& category_name);
void get_freq_settings_choice(const wxString& bundle_name);
void update_settings_item();
@@ -199,6 +212,7 @@ public:
wxMenu* append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type);
void append_menu_items_add_volume(wxMenu* menu);
wxMenuItem* append_menu_item_split(wxMenu* menu);
+ wxMenuItem* append_menu_item_layers_editing(wxMenu* menu);
wxMenuItem* append_menu_item_settings(wxMenu* menu);
wxMenuItem* append_menu_item_change_type(wxMenu* menu);
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent);
@@ -222,10 +236,17 @@ public:
void load_generic_subobject(const std::string& type_name, const ModelVolumeType type);
void del_object(const int obj_idx);
void del_subobject_item(wxDataViewItem& item);
- void del_settings_from_config();
+ void del_settings_from_config(const wxDataViewItem& parent_item);
void del_instances_from_object(const int obj_idx);
+ void del_layer_from_object(const int obj_idx, const t_layer_height_range& layer_range);
+ void del_layers_from_object(const int obj_idx);
bool del_subobject_from_object(const int obj_idx, const int idx, const int type);
void split();
+ void layers_editing();
+
+ wxDataViewItem add_layer_root_item(const wxDataViewItem obj_item);
+
+ DynamicPrintConfig get_default_layer_config(const int obj_idx);
bool get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume);
bool is_splittable();
bool selected_instances_of_same_object();
@@ -265,6 +286,14 @@ public:
// Remove objects/sub-object from the list
void remove();
+ void del_layer_range(const t_layer_height_range& range);
+ void add_layer_range_after_current(const t_layer_height_range& current_range);
+ void add_layer_item (const t_layer_height_range& range,
+ const wxDataViewItem layers_item,
+ const int layer_idx = -1);
+ bool edit_layer_range(const t_layer_height_range& range, coordf_t layer_height);
+ bool edit_layer_range(const t_layer_height_range& range,
+ const t_layer_height_range& new_range);
void init_objects();
bool multiple_selection() const ;
@@ -286,6 +315,8 @@ public:
void last_volume_is_deleted(const int obj_idx);
bool has_multi_part_objects();
void update_settings_items();
+ void update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections);
+ void update_object_list_by_printer_technology();
void update_object_menu();
void instances_to_separated_object(const int obj_idx, const std::set<int>& inst_idx);
@@ -295,6 +326,8 @@ public:
void fix_through_netfabb();
void update_item_error_icon(const int obj_idx, int vol_idx) const ;
+ void fill_layer_config_ranges_cache();
+ void paste_layers_into_list();
void paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes);
void paste_objects_into_list(const std::vector<size_t>& object_idxs);
diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp
index 4107e872a..ab2614895 100644
--- a/src/slic3r/GUI/GUI_ObjectSettings.cpp
+++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp
@@ -68,10 +68,12 @@ void ObjectSettings::update_settings_list()
m_settings_list_sizer->Clear(true);
auto objects_ctrl = wxGetApp().obj_list();
- auto objects_model = wxGetApp().obj_list()->m_objects_model;
- auto config = wxGetApp().obj_list()->m_config;
+ auto objects_model = wxGetApp().obj_list()->GetModel();
+ auto config = wxGetApp().obj_list()->config();
const auto item = objects_ctrl->GetSelection();
+ const bool is_layers_range_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itLayer;
+
if (item && !objects_ctrl->multiple_selection() &&
config && objects_model->IsSettingsItem(item))
{
@@ -119,7 +121,8 @@ void ObjectSettings::update_settings_list()
}
for (auto& cat : cat_options) {
- if (cat.second.size() == 1 && cat.second[0] == "extruder")
+ if (cat.second.size() == 1 &&
+ (cat.second[0] == "extruder" || is_layers_range_settings && cat.second[0] == "layer_height"))
continue;
auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), _(cat.first), config, false, extra_column);
@@ -129,14 +132,14 @@ void ObjectSettings::update_settings_list()
optgroup->m_on_change = [](const t_config_option_key& opt_id, const boost::any& value) {
wxGetApp().obj_list()->changed_object(); };
- const bool is_extriders_cat = cat.first == "Extruders";
+ const bool is_extruders_cat = cat.first == "Extruders";
for (auto& opt : cat.second)
{
- if (opt == "extruder")
+ if (opt == "extruder" || is_layers_range_settings && opt == "layer_height")
continue;
Option option = optgroup->get_option(opt);
option.opt.width = 12;
- if (is_extriders_cat)
+ if (is_extruders_cat)
option.opt.max = wxGetApp().extruders_cnt();
optgroup->append_single_option_line(option);
}
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index 671c49eef..0ba447c1b 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -541,6 +541,26 @@ void Preview::on_checkbox_shells(wxCommandEvent& evt)
refresh_print();
}
+void Preview::update_view_type()
+{
+ const DynamicPrintConfig& config = wxGetApp().preset_bundle->project_config;
+
+ const wxString& choice = !config.option<ConfigOptionFloats>("colorprint_heights")->values.empty() &&
+ wxGetApp().extruders_edited_cnt()==1 ?
+ _(L("Color Print")) :
+ config.option<ConfigOptionFloats>("wiping_volumes_matrix")->values.size() > 1 ?
+ _(L("Tool")) :
+ _(L("Feature type"));
+
+ int type = m_choice_view_type->FindString(choice);
+ if (m_choice_view_type->GetSelection() != type) {
+ m_choice_view_type->SetSelection(type);
+ if (0 <= type && type < (int)GCodePreviewData::Extrusion::Num_View_Types)
+ m_gcode_preview_data->extrusion.view_type = (GCodePreviewData::Extrusion::EViewType)type;
+ m_preferred_color_mode = "feature";
+ }
+}
+
void Preview::create_double_slider()
{
m_slider = new DoubleSlider(this, wxID_ANY, 0, 0, 0, 100);
@@ -553,23 +573,13 @@ void Preview::create_double_slider()
Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) {
- auto& config = wxGetApp().preset_bundle->project_config;
- ((config.option<ConfigOptionFloats>("colorprint_heights"))->values) = (m_slider->GetTicksValues());
- m_schedule_background_process();
-
- const wxString& choise = !config.option<ConfigOptionFloats>("colorprint_heights")->values.empty() ? _(L("Color Print")) :
- config.option<ConfigOptionFloats>("wiping_volumes_matrix")->values.size() > 1 ?
- _(L("Tool")) : _(L("Feature type"));
-
- int type = m_choice_view_type->FindString(choise);
- if (m_choice_view_type->GetSelection() != type) {
- m_choice_view_type->SetSelection(type);
- if ((0 <= type) && (type < (int)GCodePreviewData::Extrusion::Num_View_Types))
- m_gcode_preview_data->extrusion.view_type = (GCodePreviewData::Extrusion::EViewType)type;
- m_preferred_color_mode = "feature";
- }
- reload_print();
- });
+ wxGetApp().preset_bundle->project_config.option<ConfigOptionFloats>("colorprint_heights")->values = m_slider->GetTicksValues();
+ m_schedule_background_process();
+
+ update_view_type();
+
+ reload_print();
+ });
}
// Find an index of a value in a sorted vector, which is in <z-eps, z+eps>.
@@ -787,9 +797,14 @@ void Preview::load_print_as_fff(bool keep_z_range)
// Load the real G-code preview.
m_canvas->load_gcode_preview(*m_gcode_preview_data, colors);
m_loaded = true;
- } else
+ } else {
+ // disable color change information for multi-material presets
+ if (wxGetApp().extruders_edited_cnt() > 1)
+ color_print_values.clear();
+
// Load the initial preview based on slices, not the final G-code.
m_canvas->load_preview(colors, color_print_values);
+ }
show_hide_ui_elements(gcode_preview_data_valid ? "full" : "simple");
// recalculates zs and update sliders accordingly
std::vector<double> zs = m_canvas->get_current_print_zs(true);
diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp
index 993e260e4..e86d0e430 100644
--- a/src/slic3r/GUI/GUI_Preview.hpp
+++ b/src/slic3r/GUI/GUI_Preview.hpp
@@ -127,6 +127,8 @@ public:
void move_double_slider(wxKeyEvent& evt);
void edit_double_slider(wxKeyEvent& evt);
+ void update_view_type();
+
private:
bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
index 8934bc52b..17db953d4 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
@@ -15,48 +15,6 @@
namespace Slic3r {
namespace GUI {
-
-class GLGizmoCutPanel : public wxPanel
-{
-public:
- GLGizmoCutPanel(wxWindow *parent);
-
- void display(bool display);
-private:
- bool m_active;
- wxCheckBox *m_cb_rotate;
- wxButton *m_btn_cut;
- wxButton *m_btn_cancel;
-};
-
-GLGizmoCutPanel::GLGizmoCutPanel(wxWindow *parent)
- : wxPanel(parent)
- , m_active(false)
- , m_cb_rotate(new wxCheckBox(this, wxID_ANY, _(L("Rotate lower part upwards"))))
- , m_btn_cut(new wxButton(this, wxID_OK, _(L("Perform cut"))))
- , m_btn_cancel(new wxButton(this, wxID_CANCEL, _(L("Cancel"))))
-{
- enum { MARGIN = 5 };
-
- auto *sizer = new wxBoxSizer(wxHORIZONTAL);
-
- auto *label = new wxStaticText(this, wxID_ANY, _(L("Cut object:")));
- sizer->Add(label, 0, wxALL | wxALIGN_CENTER, MARGIN);
- sizer->Add(m_cb_rotate, 0, wxALL | wxALIGN_CENTER, MARGIN);
- sizer->AddStretchSpacer();
- sizer->Add(m_btn_cut, 0, wxALL | wxALIGN_CENTER, MARGIN);
- sizer->Add(m_btn_cancel, 0, wxALL | wxALIGN_CENTER, MARGIN);
-
- SetSizer(sizer);
-}
-
-void GLGizmoCutPanel::display(bool display)
-{
- Show(display);
- GetParent()->Layout();
-}
-
-
const double GLGizmoCut::Offset = 10.0;
const double GLGizmoCut::Margin = 20.0;
const std::array<float, 3> GLGizmoCut::GrabberColor = { 1.0, 0.5, 0.0 };
@@ -188,7 +146,7 @@ void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit, co
m_imgui->begin(_(L("Cut")), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
ImGui::PushItemWidth(m_imgui->scaled(5.0f));
- bool _value_changed = ImGui::InputDouble("Z", &m_cut_z, 0.0f, 0.0f, "%.2f");
+ ImGui::InputDouble("Z", &m_cut_z, 0.0f, 0.0f, "%.2f");
m_imgui->checkbox(_(L("Keep upper part")), m_keep_upper);
m_imgui->checkbox(_(L("Keep lower part")), m_keep_lower);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index 9e703caaa..a4a6d1459 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -259,6 +259,10 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const
void GLGizmoSlaSupports::on_render_for_picking(const Selection& selection) const
{
+#if ENABLE_RENDER_PICKING_PASS
+ m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z();
+#endif
+
glsafe(::glEnable(GL_DEPTH_TEST));
render_points(selection, true);
}
diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp
index ca1538bf7..b6abf641a 100644
--- a/src/slic3r/GUI/ImGuiWrapper.cpp
+++ b/src/slic3r/GUI/ImGuiWrapper.cpp
@@ -326,9 +326,9 @@ bool ImGuiWrapper::combo(const wxString& label, const std::vector<std::string>&
int selection_out = -1;
bool res = false;
- const char *selection_str = selection < options.size() ? options[selection].c_str() : "";
+ const char *selection_str = selection < (int)options.size() ? options[selection].c_str() : "";
if (ImGui::BeginCombo("", selection_str)) {
- for (int i = 0; i < options.size(); i++) {
+ for (int i = 0; i < (int)options.size(); i++) {
if (ImGui::Selectable(options[i].c_str(), i == selection)) {
selection_out = i;
}
diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp
index 1af658ed3..955c4b60b 100644
--- a/src/slic3r/GUI/KBShortcutsDialog.cpp
+++ b/src/slic3r/GUI/KBShortcutsDialog.cpp
@@ -154,6 +154,9 @@ void KBShortcutsDialog::fill_shortcuts()
plater_shortcuts.push_back(Shortcut("I", L("Zoom in")));
plater_shortcuts.push_back(Shortcut("O", L("Zoom out")));
plater_shortcuts.push_back(Shortcut("ESC", L("Unselect gizmo / Clear selection")));
+#if ENABLE_RENDER_PICKING_PASS
+ plater_shortcuts.push_back(Shortcut("T", L("Toggle picking pass texture rendering on/off")));
+#endif // ENABLE_RENDER_PICKING_PASS
m_full_shortcuts.push_back(std::make_pair(_(L("Plater Shortcuts")), std::make_pair(plater_shortcuts, szRight)));
diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp
index 014932900..0ed23889e 100644
--- a/src/slic3r/GUI/OptionsGroup.cpp
+++ b/src/slic3r/GUI/OptionsGroup.cpp
@@ -320,6 +320,17 @@ Line OptionsGroup::create_single_option_line(const Option& option) const {
return retval;
}
+void OptionsGroup::clear_fields_except_of(const std::vector<std::string> left_fields)
+{
+ auto it = m_fields.begin();
+ while (it != m_fields.end()) {
+ if (std::find(left_fields.begin(), left_fields.end(), it->first) == left_fields.end())
+ it = m_fields.erase(it);
+ else
+ it++;
+ }
+}
+
void OptionsGroup::on_set_focus(const std::string& opt_key)
{
if (m_set_focus != nullptr)
diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp
index 73b2c5110..422a5c2a2 100644
--- a/src/slic3r/GUI/OptionsGroup.hpp
+++ b/src/slic3r/GUI/OptionsGroup.hpp
@@ -160,6 +160,8 @@ public:
m_show_modified_btns = show;
}
+ void clear_fields_except_of(const std::vector<std::string> left_fields);
+
OptionsGroup( wxWindow* _parent, const wxString& title, bool is_tab_opt = false,
column_t extra_clmn = nullptr) :
m_parent(_parent), title(title),
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 184b23c9b..0865ab713 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -50,6 +50,7 @@
#include "GUI_App.hpp"
#include "GUI_ObjectList.hpp"
#include "GUI_ObjectManipulation.hpp"
+#include "GUI_ObjectLayers.hpp"
#include "GUI_Utils.hpp"
#include "wxExtensions.hpp"
#include "MainFrame.hpp"
@@ -615,10 +616,11 @@ struct Sidebar::priv
PresetComboBox *combo_printer;
wxBoxSizer *sizer_params;
- FreqChangedParams *frequently_changed_parameters;
- ObjectList *object_list;
- ObjectManipulation *object_manipulation;
- ObjectSettings *object_settings;
+ FreqChangedParams *frequently_changed_parameters{ nullptr };
+ ObjectList *object_list{ nullptr };
+ ObjectManipulation *object_manipulation{ nullptr };
+ ObjectSettings *object_settings{ nullptr };
+ ObjectLayers *object_layers{ nullptr };
ObjectInfo *object_info;
SlicedInfo *sliced_info;
@@ -627,10 +629,26 @@ struct Sidebar::priv
wxButton *btn_send_gcode;
priv(Plater *plater) : plater(plater) {}
+ ~priv();
void show_preset_comboboxes();
};
+Sidebar::priv::~priv()
+{
+ if (object_manipulation != nullptr)
+ delete object_manipulation;
+
+ if (object_settings != nullptr)
+ delete object_settings;
+
+ if (frequently_changed_parameters != nullptr)
+ delete frequently_changed_parameters;
+
+ if (object_layers != nullptr)
+ delete object_layers;
+}
+
void Sidebar::priv::show_preset_comboboxes()
{
const bool showSLA = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA;
@@ -737,6 +755,11 @@ Sidebar::Sidebar(Plater *parent)
p->object_settings = new ObjectSettings(p->scrolled);
p->object_settings->Hide();
p->sizer_params->Add(p->object_settings->get_sizer(), 0, wxEXPAND | wxTOP, margin_5);
+
+ // Object Layers
+ p->object_layers = new ObjectLayers(p->scrolled);
+ p->object_layers->Hide();
+ p->sizer_params->Add(p->object_layers->get_sizer(), 0, wxEXPAND | wxTOP, margin_5);
// Info boxes
p->object_info = new ObjectInfo(p->scrolled);
@@ -930,6 +953,7 @@ void Sidebar::msw_rescale()
p->object_list->msw_rescale();
p->object_manipulation->msw_rescale();
p->object_settings->msw_rescale();
+ p->object_layers->msw_rescale();
p->object_info->msw_rescale();
@@ -951,6 +975,11 @@ ObjectSettings* Sidebar::obj_settings()
return p->object_settings;
}
+ObjectLayers* Sidebar::obj_layers()
+{
+ return p->object_layers;
+}
+
wxScrolledWindow* Sidebar::scrolled_panel()
{
return p->scrolled;
@@ -1264,6 +1293,7 @@ struct Plater::priv
Preview *preview;
BackgroundSlicingProcess background_process;
+ bool suppressed_backround_processing_update { false };
// A class to handle UI jobs like arranging and optimizing rotation.
// These are not instant jobs, the user has to be informed about their
@@ -1516,6 +1546,7 @@ struct Plater::priv
static const std::regex pattern_prusa;
priv(Plater *q, MainFrame *main_frame);
+ ~priv();
void update(bool force_full_scene_refresh = false);
void select_view(const std::string& direction);
@@ -1705,7 +1736,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
panels.push_back(preview);
this->background_process_timer.SetOwner(this->q, 0);
- this->q->Bind(wxEVT_TIMER, [this](wxTimerEvent &evt) { this->update_restart_background_process(false, false); });
+ this->q->Bind(wxEVT_TIMER, [this](wxTimerEvent &evt)
+ {
+ if (!this->suppressed_backround_processing_update)
+ this->update_restart_background_process(false, false);
+ });
update();
@@ -1795,6 +1830,12 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
this->take_snapshot(_(L("New Project")));
}
+Plater::priv::~priv()
+{
+ if (config != nullptr)
+ delete config;
+}
+
void Plater::priv::update(bool force_full_scene_refresh)
{
// the following line, when enabled, causes flickering on NVIDIA graphics cards
@@ -2170,9 +2211,6 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
}
object->ensure_on_bed();
-
- // print.auto_assign_extruders(object);
- // print.add_model_object(object);
}
#ifdef AUTOPLACEMENT_ON_LOAD
@@ -2957,8 +2995,14 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
// update plater with new config
wxGetApp().plater()->on_config_change(wxGetApp().preset_bundle->full_config());
+ /* Settings list can be changed after printer preset changing, so
+ * update all settings items for all item had it.
+ * Furthermore, Layers editing is implemented only for FFF printers
+ * and for SLA presets they should be deleted
+ */
if (preset_type == Preset::TYPE_PRINTER)
- wxGetApp().obj_list()->update_settings_items();
+// wxGetApp().obj_list()->update_settings_items();
+ wxGetApp().obj_list()->update_object_list_by_printer_technology();
}
void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
@@ -3309,6 +3353,10 @@ bool Plater::priv::complit_init_object_menu()
[this]() { return can_split() && wxGetApp().get_mode() > comSimple; }, q);
object_menu.AppendSeparator();
+ // Layers Editing for object
+ sidebar->obj_list()->append_menu_item_layers_editing(&object_menu);
+ object_menu.AppendSeparator();
+
// "Add (volumes)" popupmenu will be added later in append_menu_items_add_volume()
return true;
@@ -4000,6 +4048,9 @@ void Plater::reslice()
}
else if (!p->background_process.empty() && !p->background_process.idle())
p->show_action_buttons(true);
+
+ // update type of preview
+ p->preview->update_view_type();
}
void Plater::reslice_SLA_supports(const ModelObject &object)
@@ -4257,9 +4308,25 @@ void Plater::changed_objects(const std::vector<size_t>& object_idxs)
this->p->schedule_background_process();
}
-void Plater::schedule_background_process()
+void Plater::schedule_background_process(bool schedule/* = true*/)
{
- this->p->schedule_background_process();
+ if (schedule)
+ this->p->schedule_background_process();
+
+ this->p->suppressed_backround_processing_update = false;
+}
+
+bool Plater::is_background_process_running() const
+{
+ return this->p->background_process_timer.IsRunning();
+}
+
+void Plater::suppress_background_process(const bool stop_background_process)
+{
+ if (stop_background_process)
+ this->p->background_process_timer.Stop();
+
+ this->p->suppressed_backround_processing_update = true;
}
void Plater::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) { p->fix_through_netfabb(obj_idx, vol_idx); }
@@ -4295,6 +4362,11 @@ void Plater::msw_rescale()
GetParent()->Layout();
}
+const Camera& Plater::get_camera() const
+{
+ return p->camera;
+}
+
bool Plater::can_delete() const { return p->can_delete(); }
bool Plater::can_delete_all() const { return p->can_delete_all(); }
bool Plater::can_increase_instances() const { return p->can_increase_instances(); }
@@ -4338,4 +4410,15 @@ bool Plater::can_copy_to_clipboard() const
return true;
}
+SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() :
+ m_was_running(wxGetApp().plater()->is_background_process_running())
+{
+ wxGetApp().plater()->suppress_background_process(m_was_running);
+}
+
+SuppressBackgroundProcessingUpdate::~SuppressBackgroundProcessingUpdate()
+{
+ wxGetApp().plater()->schedule_background_process(m_was_running);
+}
+
}} // namespace Slic3r::GUI
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index 91f218f6c..d38957b3a 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -33,6 +33,7 @@ class MainFrame;
class ConfigOptionsGroup;
class ObjectManipulation;
class ObjectSettings;
+class ObjectLayers;
class ObjectList;
class GLCanvas3D;
@@ -93,6 +94,7 @@ public:
ObjectManipulation* obj_manipul();
ObjectList* obj_list();
ObjectSettings* obj_settings();
+ ObjectLayers* obj_layers();
wxScrolledWindow* scrolled_panel();
wxPanel* presets_panel();
@@ -175,7 +177,9 @@ public:
void reslice_SLA_supports(const ModelObject &object);
void changed_object(int obj_idx);
void changed_objects(const std::vector<size_t>& object_idxs);
- void schedule_background_process();
+ void schedule_background_process(bool schedule = true);
+ bool is_background_process_running() const;
+ void suppress_background_process(const bool stop_background_process) ;
void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
void send_gcode();
@@ -221,11 +225,23 @@ public:
void msw_rescale();
+ const Camera& get_camera() const;
+
private:
struct priv;
std::unique_ptr<priv> p;
+
+ friend class SuppressBackgroundProcessingUpdate;
};
+class SuppressBackgroundProcessingUpdate
+{
+public:
+ SuppressBackgroundProcessingUpdate();
+ ~SuppressBackgroundProcessingUpdate();
+private:
+ bool m_was_running;
+};
}}
diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp
index 7b3187012..827d1f4e0 100644
--- a/src/slic3r/GUI/Preferences.cpp
+++ b/src/slic3r/GUI/Preferences.cpp
@@ -97,16 +97,6 @@ void PreferencesDialog::build()
option = Option (def,"show_incompatible_presets");
m_optgroup->append_single_option_line(option);
- // TODO: remove?
- def.label = L("Use legacy OpenGL 1.1 rendering");
- def.type = coBool;
- def.tooltip = L("If you have rendering issues caused by a buggy OpenGL 2.0 driver, "
- "you may try to check this checkbox. This will disable the layer height "
- "editing and anti aliasing, so it is likely better to upgrade your graphics driver.");
- def.set_default_value(new ConfigOptionBool{ app_config->get("use_legacy_opengl") == "1" });
- option = Option (def,"use_legacy_opengl");
- m_optgroup->append_single_option_line(option);
-
#if __APPLE__
def.label = L("Use Retina resolution for the 3D scene");
def.type = coBool;
@@ -150,8 +140,7 @@ void PreferencesDialog::build()
void PreferencesDialog::accept()
{
- if (m_values.find("no_defaults") != m_values.end() ||
- m_values.find("use_legacy_opengl") != m_values.end()) {
+ if (m_values.find("no_defaults") != m_values.end()) {
warning_catcher(this, wxString::Format(_(L("You need to restart %s to make the changes effective.")), SLIC3R_APP_NAME));
}
diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp
index 7192d485c..b8add9fc7 100644
--- a/src/slic3r/GUI/Preset.cpp
+++ b/src/slic3r/GUI/Preset.cpp
@@ -824,11 +824,25 @@ const Preset* PresetCollection::get_selected_preset_parent() const
if (this->get_selected_idx() == -1)
// This preset collection has no preset activated yet. Only the get_edited_preset() is valid.
return nullptr;
- const std::string &inherits = this->get_edited_preset().inherits();
+// const std::string &inherits = this->get_edited_preset().inherits();
+// if (inherits.empty())
+// return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr;
+
+ std::string inherits = this->get_edited_preset().inherits();
if (inherits.empty())
- return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr;
+ {
+ if (this->get_selected_preset().is_system || this->get_selected_preset().is_default)
+ return &this->get_selected_preset();
+ if (this->get_selected_preset().is_external)
+ return nullptr;
+
+ inherits = m_type != Preset::Type::TYPE_PRINTER ? "- default -" :
+ this->get_edited_preset().printer_technology() == ptFFF ?
+ "- default FFF -" : "- default SLA -" ;
+ }
+
const Preset* preset = this->find_preset(inherits, false);
- return (preset == nullptr || preset->is_default || preset->is_external) ? nullptr : preset;
+ return (preset == nullptr/* || preset->is_default*/ || preset->is_external) ? nullptr : preset;
}
const Preset* PresetCollection::get_preset_parent(const Preset& child) const
diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp
index ffb423758..2d5be01ff 100644
--- a/src/slic3r/GUI/Selection.cpp
+++ b/src/slic3r/GUI/Selection.cpp
@@ -6,7 +6,8 @@
#include "GUI_ObjectManipulation.hpp"
#include "GUI_ObjectList.hpp"
#include "Gizmos/GLGizmoBase.hpp"
-#include "slic3r/GUI/3DScene.hpp"
+#include "3DScene.hpp"
+#include "Camera.hpp"
#include <GL/glew.h>
@@ -347,6 +348,9 @@ void Selection::clear()
// resets the cache in the sidebar
wxGetApp().obj_manipul()->reset_cache();
+
+ // #et_FIXME fake KillFocus from sidebar
+ wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false);
}
// Update the selection based on the new instance IDs.
@@ -1086,62 +1090,69 @@ void Selection::render_center(bool gizmo_is_dragging) const
}
#endif // ENABLE_RENDER_SELECTION_CENTER
-void Selection::render_sidebar_hints(const std::string& sidebar_field) const
+void Selection::render_sidebar_hints(const std::string& sidebar_field, const Shader& shader) const
{
if (sidebar_field.empty())
return;
- glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
- glsafe(::glEnable(GL_DEPTH_TEST));
+ if (!boost::starts_with(sidebar_field, "layer"))
+ {
+ shader.start_using();
+ glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
+ glsafe(::glEnable(GL_LIGHTING));
+ }
- glsafe(::glEnable(GL_LIGHTING));
+ glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glPushMatrix());
- const Vec3d& center = get_bounding_box().center();
-
- if (is_single_full_instance() && ! wxGetApp().obj_manipul()->get_world_coordinates())
+ if (!boost::starts_with(sidebar_field, "layer"))
{
- glsafe(::glTranslated(center(0), center(1), center(2)));
- if (!boost::starts_with(sidebar_field, "position"))
+ const Vec3d& center = get_bounding_box().center();
+
+ if (is_single_full_instance() && !wxGetApp().obj_manipul()->get_world_coordinates())
{
- Transform3d orient_matrix = Transform3d::Identity();
- if (boost::starts_with(sidebar_field, "scale"))
- orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
- else if (boost::starts_with(sidebar_field, "rotation"))
+ glsafe(::glTranslated(center(0), center(1), center(2)));
+ if (!boost::starts_with(sidebar_field, "position"))
{
- if (boost::ends_with(sidebar_field, "x"))
+ Transform3d orient_matrix = Transform3d::Identity();
+ if (boost::starts_with(sidebar_field, "scale"))
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
- else if (boost::ends_with(sidebar_field, "y"))
+ else if (boost::starts_with(sidebar_field, "rotation"))
{
- const Vec3d& rotation = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation();
- if (rotation(0) == 0.0)
+ if (boost::ends_with(sidebar_field, "x"))
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
- else
- orient_matrix.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ()));
+ else if (boost::ends_with(sidebar_field, "y"))
+ {
+ const Vec3d& rotation = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation();
+ if (rotation(0) == 0.0)
+ orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
+ else
+ orient_matrix.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ()));
+ }
}
- }
- glsafe(::glMultMatrixd(orient_matrix.data()));
+ glsafe(::glMultMatrixd(orient_matrix.data()));
+ }
}
- }
- else if (is_single_volume() || is_single_modifier())
- {
- glsafe(::glTranslated(center(0), center(1), center(2)));
- Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
- if (!boost::starts_with(sidebar_field, "position"))
- orient_matrix = orient_matrix * (*m_volumes)[*m_list.begin()]->get_volume_transformation().get_matrix(true, false, true, true);
-
- glsafe(::glMultMatrixd(orient_matrix.data()));
- }
- else
- {
- glsafe(::glTranslated(center(0), center(1), center(2)));
- if (requires_local_axes())
+ else if (is_single_volume() || is_single_modifier())
{
+ glsafe(::glTranslated(center(0), center(1), center(2)));
Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
+ if (!boost::starts_with(sidebar_field, "position"))
+ orient_matrix = orient_matrix * (*m_volumes)[*m_list.begin()]->get_volume_transformation().get_matrix(true, false, true, true);
+
glsafe(::glMultMatrixd(orient_matrix.data()));
}
+ else
+ {
+ glsafe(::glTranslated(center(0), center(1), center(2)));
+ if (requires_local_axes())
+ {
+ Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
+ glsafe(::glMultMatrixd(orient_matrix.data()));
+ }
+ }
}
if (boost::starts_with(sidebar_field, "position"))
@@ -1152,10 +1163,16 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field) const
render_sidebar_scale_hints(sidebar_field);
else if (boost::starts_with(sidebar_field, "size"))
render_sidebar_size_hints(sidebar_field);
+ else if (boost::starts_with(sidebar_field, "layer"))
+ render_sidebar_layers_hints(sidebar_field);
glsafe(::glPopMatrix());
- glsafe(::glDisable(GL_LIGHTING));
+ if (!boost::starts_with(sidebar_field, "layer"))
+ {
+ glsafe(::glDisable(GL_LIGHTING));
+ shader.stop_using();
+ }
}
bool Selection::requires_local_axes() const
@@ -1179,7 +1196,7 @@ void Selection::copy_to_clipboard()
static_cast<DynamicPrintConfig&>(dst_object->config) = static_cast<const DynamicPrintConfig&>(src_object->config);
dst_object->sla_support_points = src_object->sla_support_points;
dst_object->sla_points_status = src_object->sla_points_status;
- dst_object->layer_height_ranges = src_object->layer_height_ranges;
+ dst_object->layer_config_ranges = src_object->layer_config_ranges; // #ys_FIXME_experiment
dst_object->layer_height_profile = src_object->layer_height_profile;
dst_object->origin_translation = src_object->origin_translation;
@@ -1725,6 +1742,78 @@ void Selection::render_sidebar_size_hints(const std::string& sidebar_field) cons
render_sidebar_scale_hints(sidebar_field);
}
+void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) const
+{
+ static const double Margin = 10.0;
+
+ std::string field = sidebar_field;
+
+ // extract max_z
+ std::string::size_type pos = field.rfind("_");
+ if (pos == std::string::npos)
+ return;
+
+ double max_z = std::stod(field.substr(pos + 1));
+
+ // extract min_z
+ field = field.substr(0, pos);
+ pos = field.rfind("_");
+ if (pos == std::string::npos)
+ return;
+
+ double min_z = std::stod(field.substr(pos + 1));
+
+ // extract type
+ field = field.substr(0, pos);
+ pos = field.rfind("_");
+ if (pos == std::string::npos)
+ return;
+
+ int type = std::stoi(field.substr(pos + 1));
+
+ const BoundingBoxf3& box = get_bounding_box();
+
+ const float min_x = box.min(0) - Margin;
+ const float max_x = box.max(0) + Margin;
+ const float min_y = box.min(1) - Margin;
+ const float max_y = box.max(1) + Margin;
+
+ // view dependend order of rendering to keep correct transparency
+ bool camera_on_top = wxGetApp().plater()->get_camera().get_theta() <= 90.0f;
+ float z1 = camera_on_top ? min_z : max_z;
+ float z2 = camera_on_top ? max_z : min_z;
+
+ glsafe(::glEnable(GL_DEPTH_TEST));
+ glsafe(::glDisable(GL_CULL_FACE));
+ glsafe(::glEnable(GL_BLEND));
+ glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
+
+ ::glBegin(GL_QUADS);
+ if ((camera_on_top && (type == 1)) || (!camera_on_top && (type == 2)))
+ ::glColor4f(1.0f, 0.38f, 0.0f, 1.0f);
+ else
+ ::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
+ ::glVertex3f(min_x, min_y, z1);
+ ::glVertex3f(max_x, min_y, z1);
+ ::glVertex3f(max_x, max_y, z1);
+ ::glVertex3f(min_x, max_y, z1);
+ glsafe(::glEnd());
+
+ ::glBegin(GL_QUADS);
+ if ((camera_on_top && (type == 2)) || (!camera_on_top && (type == 1)))
+ ::glColor4f(1.0f, 0.38f, 0.0f, 1.0f);
+ else
+ ::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
+ ::glVertex3f(min_x, min_y, z2);
+ ::glVertex3f(max_x, min_y, z2);
+ ::glVertex3f(max_x, max_y, z2);
+ ::glVertex3f(min_x, max_y, z2);
+ glsafe(::glEnd());
+
+ glsafe(::glEnable(GL_CULL_FACE));
+ glsafe(::glDisable(GL_BLEND));
+}
+
void Selection::render_sidebar_position_hint(Axis axis) const
{
m_arrow.set_color(AXES_COLOR[axis], 3);
diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp
index 35336c2b3..705ed4c73 100644
--- a/src/slic3r/GUI/Selection.hpp
+++ b/src/slic3r/GUI/Selection.hpp
@@ -11,8 +11,8 @@ typedef class GLUquadric GLUquadricObj;
#endif // ENABLE_RENDER_SELECTION_CENTER
namespace Slic3r {
+class Shader;
namespace GUI {
-
class TransformationType
{
public:
@@ -305,7 +305,7 @@ public:
#if ENABLE_RENDER_SELECTION_CENTER
void render_center(bool gizmo_is_dragging) const;
#endif // ENABLE_RENDER_SELECTION_CENTER
- void render_sidebar_hints(const std::string& sidebar_field) const;
+ void render_sidebar_hints(const std::string& sidebar_field, const Shader& shader) const;
bool requires_local_axes() const;
@@ -335,6 +335,7 @@ private:
void render_sidebar_rotation_hints(const std::string& sidebar_field) const;
void render_sidebar_scale_hints(const std::string& sidebar_field) const;
void render_sidebar_size_hints(const std::string& sidebar_field) const;
+ void render_sidebar_layers_hints(const std::string& sidebar_field) const;
void render_sidebar_position_hint(Axis axis) const;
void render_sidebar_rotation_hint(Axis axis) const;
void render_sidebar_scale_hint(Axis axis) const;
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index 22aecf38d..5b69aec93 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -423,7 +423,7 @@ void Tab::update_changed_ui()
const ScalableBitmap *sys_icon = &m_bmp_value_lock;
const ScalableBitmap *icon = &m_bmp_value_revert;
- const wxColour *color = &m_sys_label_clr;
+ const wxColour *color = m_is_default_preset ? &m_default_text_clr : &m_sys_label_clr;
const wxString *sys_tt = &m_tt_value_lock;
const wxString *tt = &m_tt_value_revert;
@@ -590,7 +590,7 @@ void Tab::update_changed_tree_ui()
}
}
- const wxColor *clr = sys_page ? &m_sys_label_clr :
+ const wxColor *clr = sys_page ? (m_is_default_preset ? &m_default_text_clr : &m_sys_label_clr) :
modified_page ? &m_modified_label_clr :
&m_default_text_clr;
@@ -2314,6 +2314,40 @@ void TabPrinter::build_unregular_pages()
auto optgroup = page->new_optgroup(_(L("Size")));
optgroup->append_single_option_line("nozzle_diameter", extruder_idx);
+
+ optgroup->m_on_change = [this, extruder_idx](const t_config_option_key& opt_key, boost::any value)
+ {
+ if (m_extruders_count > 1 && opt_key.find_first_of("nozzle_diameter") != std::string::npos)
+ {
+ SuppressBackgroundProcessingUpdate sbpu;
+ const double new_nd = boost::any_cast<double>(value);
+ std::vector<double> nozzle_diameters = static_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values;
+
+ // if value was changed
+ if (fabs(nozzle_diameters[extruder_idx == 0 ? 1 : 0] - new_nd) > EPSILON)
+ {
+ const wxString msg_text = _(L("Do you want to change the diameter for all extruders?"));
+ auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO);
+
+ DynamicPrintConfig new_conf = *m_config;
+ if (dialog->ShowModal() == wxID_YES) {
+ for (size_t i = 0; i < nozzle_diameters.size(); i++) {
+ if (i==extruder_idx)
+ continue;
+ nozzle_diameters[i] = new_nd;
+ }
+ }
+ else
+ nozzle_diameters[extruder_idx] = nozzle_diameters[extruder_idx == 0 ? 1 : 0];
+
+ new_conf.set_key_value("nozzle_diameter", new ConfigOptionFloats(nozzle_diameters));
+ load_config(new_conf);
+ }
+ }
+
+ update_dirty();
+ update();
+ };
optgroup = page->new_optgroup(_(L("Layer height limits")));
optgroup->append_single_option_line("min_layer_height", extruder_idx);
@@ -2550,11 +2584,14 @@ void Tab::load_current_preset()
// Reload preset pages with the new configuration values.
reload_config();
- m_bmp_non_system = m_presets->get_selected_preset_parent() ? &m_bmp_value_unlock : &m_bmp_white_bullet;
- m_ttg_non_system = m_presets->get_selected_preset_parent() ? &m_ttg_value_unlock : &m_ttg_white_bullet_ns;
- m_tt_non_system = m_presets->get_selected_preset_parent() ? &m_tt_value_unlock : &m_ttg_white_bullet_ns;
+ const Preset* selected_preset_parent = m_presets->get_selected_preset_parent();
+ m_is_default_preset = selected_preset_parent != nullptr && selected_preset_parent->is_default;
- m_undo_to_sys_btn->Enable(!preset.is_default);
+ m_bmp_non_system = selected_preset_parent ? &m_bmp_value_unlock : &m_bmp_white_bullet;
+ m_ttg_non_system = selected_preset_parent ? &m_ttg_value_unlock : &m_ttg_white_bullet_ns;
+ m_tt_non_system = selected_preset_parent ? &m_tt_value_unlock : &m_ttg_white_bullet_ns;
+
+// m_undo_to_sys_btn->Enable(!preset.is_default);
#if 0
// use CallAfter because some field triggers schedule on_change calls using CallAfter,
@@ -3140,18 +3177,18 @@ void Tab::fill_icon_descriptions()
{
m_icon_descriptions.emplace_back(&m_bmp_value_lock, L("LOCKED LOCK"),
// TRN Description for "LOCKED LOCK"
- L("indicates that the settings are the same as the system values for the current option group"));
+ L("indicates that the settings are the same as the system (or default) values for the current option group"));
m_icon_descriptions.emplace_back(&m_bmp_value_unlock, L("UNLOCKED LOCK"),
// TRN Description for "UNLOCKED LOCK"
- L("indicates that some settings were changed and are not equal to the system values for "
+ L("indicates that some settings were changed and are not equal to the system (or default) values for "
"the current option group.\n"
"Click the UNLOCKED LOCK icon to reset all settings for current option group to "
- "the system values."));
+ "the system (or default) values."));
m_icon_descriptions.emplace_back(&m_bmp_white_bullet, L("WHITE BULLET"),
// TRN Description for "WHITE BULLET"
- L("for the left button: \tindicates a non-system preset,\n"
+ L("for the left button: \tindicates a non-system (or non-default) preset,\n"
"for the right button: \tindicates that the settings hasn't been modified."));
m_icon_descriptions.emplace_back(&m_bmp_value_revert, L("BACK ARROW"),
@@ -3164,29 +3201,14 @@ void Tab::fill_icon_descriptions()
void Tab::set_tooltips_text()
{
-// m_undo_to_sys_btn->SetToolTip(_(L( "LOCKED LOCK icon indicates that the settings are the same as the system values "
-// "for the current option group.\n"
-// "UNLOCKED LOCK icon indicates that some settings were changed and are not equal "
-// "to the system values for the current option group.\n"
-// "WHITE BULLET icon indicates a non system preset.\n\n"
-// "Click the UNLOCKED LOCK icon to reset all settings for current option group to "
-// "the system values.")));
-//
-// m_undo_btn->SetToolTip(_(L( "WHITE BULLET icon indicates that the settings are the same as in the last saved"
-// "preset for the current option group.\n"
-// "BACK ARROW icon indicates that the settings were changed and are not equal to "
-// "the last saved preset for the current option group.\n\n"
-// "Click the BACK ARROW icon to reset all settings for the current option group to "
-// "the last saved preset.")));
-
// --- Tooltip text for reset buttons (for whole options group)
// Text to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
- m_ttg_value_lock = _(L("LOCKED LOCK icon indicates that the settings are the same as the system values "
+ m_ttg_value_lock = _(L("LOCKED LOCK icon indicates that the settings are the same as the system (or default) values "
"for the current option group"));
m_ttg_value_unlock = _(L("UNLOCKED LOCK icon indicates that some settings were changed and are not equal "
- "to the system values for the current option group.\n"
- "Click to reset all settings for current option group to the system values."));
- m_ttg_white_bullet_ns = _(L("WHITE BULLET icon indicates a non system preset."));
+ "to the system (or default) values for the current option group.\n"
+ "Click to reset all settings for current option group to the system (or default) values."));
+ m_ttg_white_bullet_ns = _(L("WHITE BULLET icon indicates a non system (or non default) preset."));
m_ttg_non_system = &m_ttg_white_bullet_ns;
// Text to be shown on the "Undo user changes" button next to each input field.
m_ttg_white_bullet = _(L("WHITE BULLET icon indicates that the settings are the same as in the last saved "
@@ -3197,10 +3219,10 @@ void Tab::set_tooltips_text()
// --- Tooltip text for reset buttons (for each option in group)
// Text to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
- m_tt_value_lock = _(L("LOCKED LOCK icon indicates that the value is the same as the system value."));
+ m_tt_value_lock = _(L("LOCKED LOCK icon indicates that the value is the same as the system (or default) value."));
m_tt_value_unlock = _(L("UNLOCKED LOCK icon indicates that the value was changed and is not equal "
- "to the system value.\n"
- "Click to reset current value to the system value."));
+ "to the system (or default) value.\n"
+ "Click to reset current value to the system (or default) value."));
// m_tt_white_bullet_ns= _(L("WHITE BULLET icon indicates a non system preset."));
m_tt_non_system = &m_ttg_white_bullet_ns;
// Text to be shown on the "Undo user changes" button next to each input field.
@@ -3454,9 +3476,9 @@ void TabSLAMaterial::reload_config()
void TabSLAMaterial::update()
{
if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF)
- return; // #ys_FIXME
+ return;
-// #ys_FIXME
+// #ys_FIXME. Just a template for this function
// m_update_cnt++;
// ! something to update
// m_update_cnt--;
@@ -3554,9 +3576,8 @@ void TabSLAPrint::reload_config()
void TabSLAPrint::update()
{
if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF)
- return; // #ys_FIXME
+ return;
-// #ys_FIXME
m_update_cnt++;
double head_penetration = m_config->opt_float("support_head_penetration");
diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp
index 6bbe15f7f..73b6bb08d 100644
--- a/src/slic3r/GUI/Tab.hpp
+++ b/src/slic3r/GUI/Tab.hpp
@@ -142,6 +142,12 @@ protected:
PresetDependencies m_compatible_printers;
PresetDependencies m_compatible_prints;
+ /* Indicates, that default preset or preset inherited from default is selected
+ * This value is used for a options color updating
+ * (use green color only for options, which values are equal to system values)
+ */
+ bool m_is_default_preset {false};
+
ScalableButton* m_undo_btn;
ScalableButton* m_undo_to_sys_btn;
ScalableButton* m_question_btn;
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index aed423674..1def2915c 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -437,27 +437,69 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
m_type(type),
m_extruder(wxEmptyString)
{
- if (type == itSettings) {
+ if (type == itSettings)
m_name = "Settings to modified";
- }
- else if (type == itInstanceRoot) {
+ else if (type == itInstanceRoot)
m_name = _(L("Instances"));
-#ifdef __WXGTK__
- m_container = true;
-#endif //__WXGTK__
- }
- else if (type == itInstance) {
+ else if (type == itInstance)
+ {
m_idx = parent->GetChildCount();
m_name = wxString::Format(_(L("Instance %d")), m_idx + 1);
set_action_icon();
}
+ else if (type == itLayerRoot)
+ {
+ m_bmp = create_scaled_bitmap(nullptr, "layers"); // FIXME: pass window ptr
+ m_name = _(L("Layers"));
+ }
+
+#ifdef __WXGTK__
+ // it's necessary on GTK because of control have to know if this item will be container
+ // in another case you couldn't to add subitem for this item
+ // it will be produce "segmentation fault"
+ if (type & (itInstanceRoot | itLayerRoot))
+ m_container = true;
+#endif //__WXGTK__
+}
+
+ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
+ const t_layer_height_range& layer_range,
+ const int idx /*= -1 */,
+ const wxString& extruder) :
+ m_parent(parent),
+ m_type(itLayer),
+ m_idx(idx),
+ m_layer_range(layer_range),
+ m_extruder(extruder)
+{
+ const int children_cnt = parent->GetChildCount();
+ if (idx < 0)
+ m_idx = children_cnt;
+ else
+ {
+ // update indexes for another Laeyr Nodes
+ for (int i = m_idx; i < children_cnt; i++)
+ parent->GetNthChild(i)->SetIdx(i + 1);
+ }
+ const std::string label_range = (boost::format(" %.2f-%.2f ") % layer_range.first % layer_range.second).str();
+ m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")";
+ m_bmp = create_scaled_bitmap(nullptr, "layers_white"); // FIXME: pass window ptr
+
+#ifdef __WXGTK__
+ // it's necessary on GTK because of control have to know if this item will be container
+ // in another case you couldn't to add subitem for this item
+ // it will be produce "segmentation fault"
+ m_container = true;
+#endif //__WXGTK__
+
+ set_action_icon();
}
void ObjectDataViewModelNode::set_action_icon()
{
- m_action_icon_name = m_type == itObject ? "advanced_plus" :
- m_type == itVolume ? "cog" : "set_separate_obj";
+ m_action_icon_name = m_type & itObject ? "advanced_plus" :
+ m_type & (itVolume | itLayer) ? "cog" : /*m_type & itInstance*/ "set_separate_obj";
m_action_icon = create_scaled_bitmap(nullptr, m_action_icon_name); // FIXME: pass window ptr
}
@@ -523,6 +565,22 @@ void ObjectDataViewModelNode::SetIdx(const int& idx)
// ObjectDataViewModel
// ----------------------------------------------------------------------------
+static int get_root_idx(ObjectDataViewModelNode *parent_node, const ItemType root_type)
+{
+ // because of istance_root and layers_root are at the end of the list, so
+ // start locking from the end
+ for (int root_idx = parent_node->GetChildCount() - 1; root_idx >= 0; root_idx--)
+ {
+ // if there is SettingsItem or VolumeItem, then RootItems don't exist in current ObjectItem
+ if (parent_node->GetNthChild(root_idx)->GetType() & (itSettings | itVolume))
+ break;
+ if (parent_node->GetNthChild(root_idx)->GetType() & root_type)
+ return root_idx;
+ }
+
+ return -1;
+}
+
ObjectDataViewModel::ObjectDataViewModel()
{
m_bitmap_cache = new Slic3r::GUI::BitmapCache;
@@ -567,10 +625,10 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent
wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
- // because of istance_root is a last item of the object
- int insert_position = root->GetChildCount() - 1;
- if (insert_position < 0 || root->GetNthChild(insert_position)->m_type != itInstanceRoot)
- insert_position = -1;
+ // get insertion position according to the existed Layers and/or Instances Items
+ int insert_position = get_root_idx(root, itLayerRoot);
+ if (insert_position < 0)
+ insert_position = get_root_idx(root, itInstanceRoot);
const bool obj_errors = root->m_bmp.IsOk();
@@ -619,15 +677,30 @@ wxDataViewItem ObjectDataViewModel::AddSettingsChild(const wxDataViewItem &paren
return child;
}
-int get_istances_root_idx(ObjectDataViewModelNode *parent_node)
+/* return values:
+ * true => root_node is created and added to the parent_root
+ * false => root node alredy exists
+*/
+static bool append_root_node(ObjectDataViewModelNode *parent_node,
+ ObjectDataViewModelNode **root_node,
+ const ItemType root_type)
{
- // because of istance_root is a last item of the object
- const int inst_root_idx = parent_node->GetChildCount()-1;
+ const int inst_root_id = get_root_idx(parent_node, root_type);
- if (inst_root_idx < 0 || parent_node->GetNthChild(inst_root_idx)->GetType() == itInstanceRoot)
- return inst_root_idx;
+ *root_node = inst_root_id < 0 ?
+ new ObjectDataViewModelNode(parent_node, root_type) :
+ parent_node->GetNthChild(inst_root_id);
- return -1;
+ if (inst_root_id < 0) {
+ if ((root_type&itInstanceRoot) ||
+ (root_type&itLayerRoot) && get_root_idx(parent_node, itInstanceRoot)<0)
+ parent_node->Append(*root_node);
+ else if (root_type&itLayerRoot)
+ parent_node->Insert(*root_node, static_cast<unsigned int>(get_root_idx(parent_node, itInstanceRoot)));
+ return true;
+ }
+
+ return false;
}
wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num)
@@ -635,20 +708,15 @@ wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &paren
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
if (!parent_node) return wxDataViewItem(0);
- // Check and create/get instances root node
- const int inst_root_id = get_istances_root_idx(parent_node);
+ // get InstanceRoot node
+ ObjectDataViewModelNode *inst_root_node { nullptr };
- ObjectDataViewModelNode *inst_root_node = inst_root_id < 0 ?
- new ObjectDataViewModelNode(parent_node, itInstanceRoot) :
- parent_node->GetNthChild(inst_root_id);
+ const bool appended = append_root_node(parent_node, &inst_root_node, itInstanceRoot);
const wxDataViewItem inst_root_item((void*)inst_root_node);
+ if (!inst_root_node) return wxDataViewItem(0);
- if (inst_root_id < 0) {
- parent_node->Append(inst_root_node);
- // notify control
- ItemAdded(parent_item, inst_root_item);
-// if (num == 1) num++;
- }
+ if (appended)
+ ItemAdded(parent_item, inst_root_item);// notify control
// Add instance nodes
ObjectDataViewModelNode *instance_node = nullptr;
@@ -665,6 +733,63 @@ wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &paren
return wxDataViewItem((void*)instance_node);
}
+wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_item)
+{
+ ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
+ if (!parent_node) return wxDataViewItem(0);
+
+ // get LayerRoot node
+ ObjectDataViewModelNode *layer_root_node{ nullptr };
+ const bool appended = append_root_node(parent_node, &layer_root_node, itLayerRoot);
+ if (!layer_root_node) return wxDataViewItem(0);
+
+ const wxDataViewItem layer_root_item((void*)layer_root_node);
+
+ if (appended)
+ ItemAdded(parent_item, layer_root_item);// notify control
+
+ return layer_root_item;
+}
+
+wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item,
+ const t_layer_height_range& layer_range,
+ const int extruder/* = 0*/,
+ const int index /* = -1*/)
+{
+ ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
+ if (!parent_node) return wxDataViewItem(0);
+
+ wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
+
+ // get LayerRoot node
+ ObjectDataViewModelNode *layer_root_node;
+ wxDataViewItem layer_root_item;
+
+ if (parent_node->GetType() & itLayerRoot) {
+ layer_root_node = parent_node;
+ layer_root_item = parent_item;
+ }
+ else {
+ const int root_idx = get_root_idx(parent_node, itLayerRoot);
+ if (root_idx < 0) return wxDataViewItem(0);
+ layer_root_node = parent_node->GetNthChild(root_idx);
+ layer_root_item = wxDataViewItem((void*)layer_root_node);
+ }
+
+ // Add layer node
+ ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, layer_range, index, extruder_str);
+ if (index < 0)
+ layer_root_node->Append(layer_node);
+ else
+ layer_root_node->Insert(layer_node, index);
+
+ // notify control
+ const wxDataViewItem layer_item((void*)layer_node);
+ ItemAdded(layer_root_item, layer_item);
+
+ return layer_item;
+}
+
wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
{
auto ret_item = wxDataViewItem(0);
@@ -679,9 +804,9 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
// thus removing the node from it doesn't result in freeing it
if (node_parent) {
- if (node->m_type == itInstanceRoot)
+ if (node->m_type & (itInstanceRoot|itLayerRoot))
{
- for (int i = node->GetChildCount() - 1; i > 0; i--)
+ for (int i = node->GetChildCount() - 1; i >= (node->m_type & itInstanceRoot ? 1 : 0); i--)
Delete(wxDataViewItem(node->GetNthChild(i)));
return parent;
}
@@ -690,7 +815,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
auto idx = node->GetIdx();
- if (node->m_type == itVolume) {
+ if (node->m_type & (itVolume|itLayer)) {
node_parent->m_volumes_cnt--;
DeleteSettings(item);
}
@@ -734,8 +859,24 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
return ret_item;
}
+ // if there was last layer item, delete this one and layers root item
+ if (node_parent->GetChildCount() == 0 && node_parent->m_type == itLayerRoot)
+ {
+ ObjectDataViewModelNode *obj_node = node_parent->GetParent();
+ obj_node->GetChildren().Remove(node_parent);
+ delete node_parent;
+ ret_item = wxDataViewItem(obj_node);
+
+#ifndef __WXGTK__
+ if (obj_node->GetChildCount() == 0)
+ obj_node->m_container = false;
+#endif //__WXGTK__
+ ItemDeleted(ret_item, wxDataViewItem(node_parent));
+ return ret_item;
+ }
+
// if there is last volume item after deleting, delete this last volume too
- if (node_parent->GetChildCount() <= 3)
+ if (node_parent->GetChildCount() <= 3) // 3??? #ys_FIXME
{
int vol_cnt = 0;
int vol_idx = 0;
@@ -817,7 +958,7 @@ wxDataViewItem ObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &par
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
if (!parent_node) return ret_item;
- const int inst_root_id = get_istances_root_idx(parent_node);
+ const int inst_root_id = get_root_idx(parent_node, itInstanceRoot);
if (inst_root_id < 0) return ret_item;
wxDataViewItemArray items;
@@ -974,28 +1115,67 @@ wxDataViewItem ObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volume_id
return wxDataViewItem(0);
}
+wxDataViewItem ObjectDataViewModel::GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type)
+{
+ if (obj_idx >= m_objects.size() || obj_idx < 0) {
+ printf("Error! Out of objects range.\n");
+ return wxDataViewItem(0);
+ }
+
+ auto item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), parent_type);
+ if (!item)
+ return wxDataViewItem(0);
+
+ auto parent = (ObjectDataViewModelNode*)item.GetID();
+ for (size_t i = 0; i < parent->GetChildCount(); i++)
+ if (parent->GetNthChild(i)->m_idx == sub_obj_idx)
+ return wxDataViewItem(parent->GetNthChild(i));
+
+ return wxDataViewItem(0);
+}
+
wxDataViewItem ObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx)
{
+ return GetItemById(obj_idx, inst_idx, itInstanceRoot);
+}
+
+wxDataViewItem ObjectDataViewModel::GetItemByLayerId(int obj_idx, int layer_idx)
+{
+ return GetItemById(obj_idx, layer_idx, itLayerRoot);
+}
+
+wxDataViewItem ObjectDataViewModel::GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range)
+{
if (obj_idx >= m_objects.size() || obj_idx < 0) {
printf("Error! Out of objects range.\n");
return wxDataViewItem(0);
}
- auto instances_item = GetInstanceRootItem(wxDataViewItem(m_objects[obj_idx]));
- if (!instances_item)
+ auto item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), itLayerRoot);
+ if (!item)
return wxDataViewItem(0);
- auto parent = (ObjectDataViewModelNode*)instances_item.GetID();;
+ auto parent = (ObjectDataViewModelNode*)item.GetID();
for (size_t i = 0; i < parent->GetChildCount(); i++)
- if (parent->GetNthChild(i)->m_idx == inst_idx)
+ if (parent->GetNthChild(i)->m_layer_range == layer_range)
return wxDataViewItem(parent->GetNthChild(i));
return wxDataViewItem(0);
}
+int ObjectDataViewModel::GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range)
+{
+ wxDataViewItem item = GetItemByLayerRange(obj_idx, layer_range);
+ if (!item)
+ return -1;
+
+ return GetLayerIdByItem(item);
+}
+
int ObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) const
{
- wxASSERT(item.IsOk());
+ if(!item.IsOk())
+ return -1;
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
auto it = find(m_objects.begin(), m_objects.end(), node);
@@ -1030,13 +1210,28 @@ int ObjectDataViewModel::GetInstanceIdByItem(const wxDataViewItem& item) const
return GetIdByItemAndType(item, itInstance);
}
+int ObjectDataViewModel::GetLayerIdByItem(const wxDataViewItem& item) const
+{
+ return GetIdByItemAndType(item, itLayer);
+}
+
+t_layer_height_range ObjectDataViewModel::GetLayerRangeByItem(const wxDataViewItem& item) const
+{
+ wxASSERT(item.IsOk());
+
+ ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
+ if (!node || node->m_type != itLayer)
+ return { 0.0f, 0.0f };
+ return node->GetLayerRange();
+}
+
void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx)
{
wxASSERT(item.IsOk());
type = itUndef;
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
- if (!node || node->GetIdx() <-1 || node->GetIdx() ==-1 && !(node->GetType() & (itObject | itSettings | itInstanceRoot)))
+ if (!node || node->GetIdx() <-1 || node->GetIdx() == -1 && !(node->GetType() & (itObject | itSettings | itInstanceRoot | itLayerRoot/* | itLayer*/)))
return;
idx = node->GetIdx();
@@ -1044,9 +1239,10 @@ void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type
ObjectDataViewModelNode *parent_node = node->GetParent();
if (!parent_node) return;
- if (type == itInstance)
- parent_node = node->GetParent()->GetParent();
- if (!parent_node || parent_node->m_type != itObject) { type = itUndef; return; }
+
+ // get top parent (Object) node
+ while (parent_node->m_type != itObject)
+ parent_node = parent_node->GetParent();
auto it = find(m_objects.begin(), m_objects.end(), parent_node);
if (it != m_objects.end())
@@ -1214,10 +1410,7 @@ wxDataViewItem ObjectDataViewModel::GetTopParent(const wxDataViewItem &item) con
ObjectDataViewModelNode *parent_node = node->GetParent();
while (parent_node->m_type != itObject)
- {
- node = parent_node;
- parent_node = node->GetParent();
- }
+ parent_node = parent_node->GetParent();
return wxDataViewItem((void*)parent_node);
}
@@ -1318,6 +1511,11 @@ wxDataViewItem ObjectDataViewModel::GetInstanceRootItem(const wxDataViewItem &it
return GetItemByType(item, itInstanceRoot);
}
+wxDataViewItem ObjectDataViewModel::GetLayerRootItem(const wxDataViewItem &item) const
+{
+ return GetItemByType(item, itLayerRoot);
+}
+
bool ObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const
{
if (!item.IsOk())
@@ -2027,6 +2225,9 @@ void DoubleSlider::draw_thumbs(wxDC& dc, const wxCoord& lower_pos, const wxCoord
void DoubleSlider::draw_ticks(wxDC& dc)
{
+ if (!m_is_enabled_tick_manipulation)
+ return;
+
dc.SetPen(m_is_enabled_tick_manipulation ? DARK_GREY_PEN : LIGHT_GREY_PEN );
int height, width;
get_size(&width, &height);
@@ -2044,6 +2245,9 @@ void DoubleSlider::draw_ticks(wxDC& dc)
void DoubleSlider::draw_colored_band(wxDC& dc)
{
+ if (!m_is_enabled_tick_manipulation)
+ return;
+
int height, width;
get_size(&width, &height);
@@ -2113,7 +2317,7 @@ void DoubleSlider::draw_one_layer_icon(wxDC& dc)
void DoubleSlider::draw_revert_icon(wxDC& dc)
{
- if (m_ticks.empty())
+ if (m_ticks.empty() || !m_is_enabled_tick_manipulation)
return;
int width, height;
@@ -2218,7 +2422,7 @@ void DoubleSlider::OnLeftDown(wxMouseEvent& event)
m_selection == ssLower ? correct_lower_value() : correct_higher_value();
if (!m_selection) m_selection = ssHigher;
}
- else if (is_point_in_rect(pos, m_rect_revert_icon)) {
+ else if (is_point_in_rect(pos, m_rect_revert_icon) && m_is_enabled_tick_manipulation) {
// discard all color changes
SetLowerValue(m_min_value);
SetHigherValue(m_max_value);
@@ -2647,7 +2851,7 @@ ModeSizer::ModeSizer(wxWindow *parent, int hgap/* = 10*/) :
m_mode_btns.push_back(new ModeButton(parent, wxID_ANY, button.second, button.first));;
#endif // __WXOSX__
- m_mode_btns.back()->Bind(wxEVT_BUTTON, std::bind(modebtnfn, std::placeholders::_1, m_mode_btns.size() - 1));
+ m_mode_btns.back()->Bind(wxEVT_BUTTON, std::bind(modebtnfn, std::placeholders::_1, int(m_mode_btns.size() - 1)));
Add(m_mode_btns.back());
}
}
diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp
index 081c0d48f..d0edf9760 100644
--- a/src/slic3r/GUI/wxExtensions.hpp
+++ b/src/slic3r/GUI/wxExtensions.hpp
@@ -20,6 +20,9 @@ namespace Slic3r {
enum class ModelVolumeType : int;
};
+typedef double coordf_t;
+typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
+
#ifdef __WXMSW__
void msw_rescale_menu(wxMenu* menu);
#else /* __WXMSW__ */
@@ -159,12 +162,14 @@ DECLARE_VARIANT_OBJECT(DataViewBitmapText)
// ----------------------------------------------------------------------------
enum ItemType {
- itUndef = 0,
- itObject = 1,
- itVolume = 2,
- itInstanceRoot = 4,
- itInstance = 8,
- itSettings = 16
+ itUndef = 0,
+ itObject = 1,
+ itVolume = 2,
+ itInstanceRoot = 4,
+ itInstance = 8,
+ itSettings = 16,
+ itLayerRoot = 32,
+ itLayer = 64,
};
class ObjectDataViewModelNode;
@@ -177,6 +182,7 @@ class ObjectDataViewModelNode
wxBitmap m_empty_bmp;
size_t m_volumes_cnt = 0;
std::vector< std::string > m_opt_categories;
+ t_layer_height_range m_layer_range = { 0.0f, 0.0f };
wxString m_name;
wxBitmap& m_bmp = m_empty_bmp;
@@ -229,6 +235,11 @@ public:
set_action_icon();
}
+ ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
+ const t_layer_height_range& layer_range,
+ const int idx = -1,
+ const wxString& extruder = wxEmptyString );
+
ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type);
~ObjectDataViewModelNode()
@@ -318,6 +329,7 @@ public:
ItemType GetType() const { return m_type; }
void SetIdx(const int& idx);
int GetIdx() const { return m_idx; }
+ t_layer_height_range GetLayerRange() const { return m_layer_range; }
// use this function only for childrens
void AssignAllVal(ObjectDataViewModelNode& from_node)
@@ -348,7 +360,7 @@ public:
}
// Set action icons for node
- void set_action_icon();
+ void set_action_icon();
void update_settings_digest_bitmaps();
bool update_settings_digest(const std::vector<std::string>& categories);
@@ -388,6 +400,11 @@ public:
const bool create_frst_child = true);
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
+ wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
+ wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item,
+ const t_layer_height_range& layer_range,
+ const int extruder = 0,
+ const int index = -1);
wxDataViewItem Delete(const wxDataViewItem &item);
wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
void DeleteAll();
@@ -395,13 +412,18 @@ public:
void DeleteVolumeChildren(wxDataViewItem& parent);
void DeleteSettings(const wxDataViewItem& parent);
wxDataViewItem GetItemById(int obj_idx);
+ wxDataViewItem GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type);
wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx);
wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx);
+ wxDataViewItem GetItemByLayerId(int obj_idx, int layer_idx);
+ wxDataViewItem GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
+ int GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
int GetIdByItem(const wxDataViewItem& item) const;
int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
int GetObjectIdByItem(const wxDataViewItem& item) const;
int GetVolumeIdByItem(const wxDataViewItem& item) const;
int GetInstanceIdByItem(const wxDataViewItem& item) const;
+ int GetLayerIdByItem(const wxDataViewItem& item) const;
void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx);
int GetRowByItem(const wxDataViewItem& item) const;
bool IsEmpty() { return m_objects.empty(); }
@@ -450,6 +472,7 @@ public:
ItemType type) const;
wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const;
wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const;
+ wxDataViewItem GetLayerRootItem(const wxDataViewItem &item) const;
bool IsSettingsItem(const wxDataViewItem &item) const;
void UpdateSettingsDigest( const wxDataViewItem &item,
const std::vector<std::string>& categories);
@@ -465,6 +488,7 @@ public:
wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type,
const bool is_marked = false);
void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
+ t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const;
};
// ----------------------------------------------------------------------------
diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp
index 8c3ced31a..bc600fcad 100644
--- a/src/slic3r/Utils/PresetUpdater.cpp
+++ b/src/slic3r/Utils/PresetUpdater.cpp
@@ -402,15 +402,8 @@ Updates PresetUpdater::priv::get_config_updates() const
}
}
- copy_file_fix(idx.path(), bundle_path_idx);
-
const auto ver_current = idx.find(vp.config_version);
const bool ver_current_found = ver_current != idx.end();
- if (! ver_current_found) {
- auto message = (boost::format("Preset bundle `%1%` version not found in index: %2%") % idx.vendor() % vp.config_version.to_string()).str();
- BOOST_LOG_TRIVIAL(error) << message;
- GUI::show_error(nullptr, GUI::from_u8(message));
- }
BOOST_LOG_TRIVIAL(debug) << boost::format("Vendor: %1%, version installed: %2%%3%, version cached: %4%")
% vp.name
@@ -418,6 +411,13 @@ Updates PresetUpdater::priv::get_config_updates() const
% (ver_current_found ? "" : " (not found in index!)")
% recommended->config_version.to_string();
+ if (! ver_current_found) {
+ auto message = (boost::format("Preset bundle `%1%` version not found in index: %2%") % idx.vendor() % vp.config_version.to_string()).str();
+ BOOST_LOG_TRIVIAL(error) << message;
+ GUI::show_error(nullptr, GUI::from_u8(message));
+ continue;
+ }
+
if (ver_current_found && !ver_current->is_current_slic3r_supported()) {
BOOST_LOG_TRIVIAL(warning) << "Current Slic3r incompatible with installed bundle: " << bundle_path.string();
updates.incompats.emplace_back(std::move(bundle_path), *ver_current, vp.name);
@@ -459,10 +459,16 @@ Updates PresetUpdater::priv::get_config_updates() const
found = true;
}
}
- if (! found)
+
+ if (found) {
+ // 'Install' the index in the vendor directory. This is used to memoize
+ // offered updates and to not offer the same update again if it was cancelled by the user.
+ copy_file_fix(idx.path(), bundle_path_idx);
+ } else {
BOOST_LOG_TRIVIAL(warning) << boost::format("Index for vendor %1% indicates update (%2%) but the new bundle was found neither in cache nor resources")
% idx.vendor()
% recommended->config_version.to_string();
+ }
}
}
diff --git a/t/combineinfill.t b/t/combineinfill.t
index 8aa0ff5e3..282bf467a 100644
--- a/t/combineinfill.t
+++ b/t/combineinfill.t
@@ -89,7 +89,7 @@ plan tests => 8;
# we disable combination after infill has been generated
$config->set('infill_every_layers', 1);
- $print->apply_config_perl_tests_only($config);
+ $print->apply($print->print->model->clone, $config);
$print->process;
ok !(defined first { @{$_->get_region(0)->fill_surfaces} == 0 }
diff --git a/t/print.t b/t/print.t
index be2db3431..2144e80c1 100644
--- a/t/print.t
+++ b/t/print.t
@@ -34,25 +34,30 @@ use Slic3r::Test;
{
# this represents the aggregate config from presets
my $config = Slic3r::Config::new_from_defaults;
+ # Define 4 extruders.
+ $config->set('nozzle_diameter', [0.4, 0.4, 0.4, 0.4]);
# user adds one object to the plater
my $print = Slic3r::Test::init_print(my $model = Slic3r::Test::model('20mm_cube'), config => $config);
# user sets a per-region option
- $print->print->objects->[0]->model_object->config->set('fill_density', 100);
- $print->print->reload_object(0);
+ my $model2 = $model->clone;
+ $model2->get_object(0)->config->set('fill_density', 100);
+ $print->apply($model2, $config);
+
is $print->print->regions->[0]->config->fill_density, 100, 'region config inherits model object config';
# user exports G-code, thus the default config is reapplied
- $print->print->apply_config_perl_tests_only($config);
-
- is $print->print->regions->[0]->config->fill_density, 100, 'apply_config() does not override per-object settings';
+ $model2->get_object(0)->config->erase('fill_density');
+ $print->apply($model2, $config);
+
+ is $print->print->regions->[0]->config->fill_density, 20, 'region config is resetted';
# user assigns object extruders
- $print->print->objects->[0]->model_object->config->set('extruder', 3);
- $print->print->objects->[0]->model_object->config->set('perimeter_extruder', 2);
- $print->print->reload_object(0);
-
+ $model2->get_object(0)->config->set('extruder', 3);
+ $model2->get_object(0)->config->set('perimeter_extruder', 2);
+ $print->apply($model2, $config);
+
is $print->print->regions->[0]->config->infill_extruder, 3, 'extruder setting is correctly expanded';
is $print->print->regions->[0]->config->perimeter_extruder, 2, 'extruder setting does not override explicitely specified extruders';
}
diff --git a/t/skirt_brim.t b/t/skirt_brim.t
index b05435784..beb3c94c5 100644
--- a/t/skirt_brim.t
+++ b/t/skirt_brim.t
@@ -91,6 +91,8 @@ use Slic3r::Test;
{
my $config = Slic3r::Config::new_from_defaults;
+ # Define 4 extruders.
+ $config->set('nozzle_diameter', [0.4, 0.4, 0.4, 0.4]);
$config->set('layer_height', 0.4);
$config->set('first_layer_height', 0.4);
$config->set('skirts', 1);
@@ -106,7 +108,7 @@ use Slic3r::Test;
# we enable support material after skirt has been generated
$config->set('support_material', 1);
- $print->apply_config_perl_tests_only($config);
+ $print->apply($print->print->model->clone, $config);
my $skirt_length = 0;
my @extrusion_points = ();
diff --git a/xs/t/19_model.t b/xs/t/19_model.t
index d6f6d97a1..48a000e46 100644
--- a/xs/t/19_model.t
+++ b/xs/t/19_model.t
@@ -4,7 +4,7 @@ use strict;
use warnings;
use Slic3r::XS;
-use Test::More tests => 4;
+use Test::More tests => 3;
{
my $model = Slic3r::Model->new;
@@ -14,9 +14,9 @@ use Test::More tests => 4;
$object->origin_translation->translate(10,0,0);
is_deeply \@{$object->origin_translation}, [10,0,0], 'origin_translation is modified by ref';
- my $lhr = [ [ 5, 10, 0.1 ] ];
- $object->set_layer_height_ranges($lhr);
- is_deeply $object->layer_height_ranges, $lhr, 'layer_height_ranges roundtrip';
+# my $lhr = [ [ 5, 10, 0.1 ] ];
+# $object->set_layer_height_ranges($lhr);
+# is_deeply $object->layer_height_ranges, $lhr, 'layer_height_ranges roundtrip';
}
__END__
diff --git a/xs/xsp/Config.xsp b/xs/xsp/Config.xsp
index c374880a1..f5e6ffb05 100644
--- a/xs/xsp/Config.xsp
+++ b/xs/xsp/Config.xsp
@@ -49,7 +49,7 @@
void erase(t_config_option_key opt_key);
void normalize();
%name{setenv} void setenv_();
- double min_object_distance() %code{% RETVAL = PrintConfig::min_object_distance(THIS); %};
+ double min_object_distance() %code{% PrintConfig cfg; cfg.apply(*THIS, true); RETVAL = cfg.min_object_distance(); %};
static DynamicPrintConfig* load(char *path)
%code%{
auto config = new DynamicPrintConfig();
diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp
index 6a2cc6080..35b1c01ce 100644
--- a/xs/xsp/Model.xsp
+++ b/xs/xsp/Model.xsp
@@ -206,16 +206,12 @@ ModelMaterial::attributes()
Ref<Model> model()
%code%{ RETVAL = THIS->get_model(); %};
- t_layer_height_ranges layer_height_ranges()
- %code%{ RETVAL = THIS->layer_height_ranges; %};
- void set_layer_height_ranges(t_layer_height_ranges ranges)
- %code%{ THIS->layer_height_ranges = ranges; %};
-
Ref<Vec3d> origin_translation()
%code%{ RETVAL = &THIS->origin_translation; %};
void set_origin_translation(Vec3d* point)
%code%{ THIS->origin_translation = *point; %};
+ void ensure_on_bed();
bool needed_repair() const;
int materials_count() const;
int facets_count();
diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp
index c35f967f8..df5f48587 100644
--- a/xs/xsp/Print.xsp
+++ b/xs/xsp/Print.xsp
@@ -70,6 +70,8 @@ _constant()
Print();
~Print();
+ Ref<Model> model()
+ %code%{ RETVAL = const_cast<Model*>(&THIS->model()); %};
Ref<StaticPrintConfig> config()
%code%{ RETVAL = const_cast<GCodeConfig*>(static_cast<const GCodeConfig*>(&THIS->config())); %};
Ref<PlaceholderParser> placeholder_parser()
@@ -100,7 +102,6 @@ _constant()
%code%{ RETVAL = const_cast<PrintObjectPtrs*>(&THIS->objects()); %};
Ref<PrintObject> get_object(int idx)
%code%{ RETVAL = THIS->objects()[idx]; %};
- void reload_object(int idx);
size_t object_count()
%code%{ RETVAL = THIS->objects().size(); %};
@@ -141,9 +142,8 @@ _constant()
}
%};
- void add_model_object(ModelObject* model_object, int idx = -1);
- bool apply_config_perl_tests_only(DynamicPrintConfig* config)
- %code%{ RETVAL = THIS->apply_config_perl_tests_only(*config); %};
+ bool apply(Model *model, DynamicPrintConfig* config)
+ %code%{ RETVAL = THIS->apply(*model, *config); %};
bool has_infinite_skirt();
std::vector<unsigned int> extruders() const;
int validate() %code%{