Merge remote-tracking branch 'origin/master' into vb_undo_redo

This commit is contained in:
bubnikv 2019-07-04 20:22:15 +02:00
commit c7cc760067
105 changed files with 3283 additions and 1599 deletions

9
deps/CMakeLists.txt vendored
View file

@ -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_DEBUG "Build debug variants (only applicable on Windows)" ON)
option(DEP_WX_STABLE "Build against wxWidgets stable 3.0 as opposed to default 3.1 (Linux only)" OFF) option(DEP_WX_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 # On developer machines, it can be enabled to speed up compilation and suppress warnings coming from IGL.
# disabled and used in header-only mode. On developer machines, it can be enabled to speed # FIXME:
# up conpilation and suppress warnings coming from IGL. # Enabling this option is not safe. IGL will compile itself with its own version of Eigen while
option(DEP_BUILD_IGL_STATIC "Build IGL as a static library. Might cause link errors and increase binary size." OFF) # 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 DESTDIR: ${DESTDIR}")
message(STATUS "PrusaSlicer deps debug build: ${DEP_DEBUG}") message(STATUS "PrusaSlicer deps debug build: ${DEP_DEBUG}")

View file

@ -64,7 +64,7 @@ ExternalProject_Add(dep_libigl
-DLIBIGL_BUILD_PYTHON=OFF -DLIBIGL_BUILD_PYTHON=OFF
-DLIBIGL_BUILD_TESTS=OFF -DLIBIGL_BUILD_TESTS=OFF
-DLIBIGL_BUILD_TUTORIALS=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_WITHOUT_COPYLEFT=OFF
-DLIBIGL_WITH_CGAL=OFF -DLIBIGL_WITH_CGAL=OFF
-DLIBIGL_WITH_COMISO=OFF -DLIBIGL_WITH_COMISO=OFF

View file

@ -278,7 +278,7 @@ ExternalProject_Add(dep_libigl
-DLIBIGL_BUILD_PYTHON=OFF -DLIBIGL_BUILD_PYTHON=OFF
-DLIBIGL_BUILD_TESTS=OFF -DLIBIGL_BUILD_TESTS=OFF
-DLIBIGL_BUILD_TUTORIALS=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_WITHOUT_COPYLEFT=OFF
-DLIBIGL_WITH_CGAL=OFF -DLIBIGL_WITH_CGAL=OFF
-DLIBIGL_WITH_COMISO=OFF -DLIBIGL_WITH_COMISO=OFF

View file

@ -50,7 +50,6 @@ use Slic3r::Point;
use Slic3r::Polygon; use Slic3r::Polygon;
use Slic3r::Polyline; use Slic3r::Polyline;
use Slic3r::Print::Object; use Slic3r::Print::Object;
use Slic3r::Print::Simple;
use Slic3r::Surface; use Slic3r::Surface;
our $build = eval "use Slic3r::Build; 1"; our $build = eval "use Slic3r::Build; 1";

View file

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

View file

@ -146,13 +146,16 @@ sub mesh {
} }
sub model { 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 $model = Slic3r::Model->new;
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); my $object = $model->add_object(input_file => $input_file);
$model->set_material($model_name); $model->set_material($model_name);
$object->add_volume(mesh => $mesh, material_id => $model_name); $object->add_volume(mesh => $mesh, material_id => $model_name);
@ -162,44 +165,47 @@ sub model {
rotation => Slic3r::Pointf3->new(0, 0, $params{rotation} // 0), rotation => Slic3r::Pointf3->new(0, 0, $params{rotation} // 0),
scaling_factor => Slic3r::Pointf3->new($params{scale} // 1, $params{scale} // 1, $params{scale} // 1), scaling_factor => Slic3r::Pointf3->new($params{scale} // 1, $params{scale} // 1, $params{scale} // 1),
# old transform # old transform
# rotation => $params{rotation} // 0, # rotation => $params{rotation} // 0,
# scaling_factor => $params{scale} // 1, # scaling_factor => $params{scale} // 1,
); );
}
return $model; return $model;
} }
sub init_print { sub init_print {
my ($models, %params) = @_; 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; my $config = Slic3r::Config->new;
$config->apply($params{config}) if $params{config}; $config->apply($params{config}) if $params{config};
$config->set('gcode_comments', 1) if $ENV{SLIC3R_TESTS_GCODE}; $config->set('gcode_comments', 1) if $ENV{SLIC3R_TESTS_GCODE};
my $print = Slic3r::Print->new; 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; die "Unknown model in test" if !defined $model;
if (defined $params{duplicate} && $params{duplicate} > 1) { if (defined $params{duplicate} && $params{duplicate} > 1) {
$model->duplicate($params{duplicate} // 1, $print->config->min_object_distance); $model->duplicate($params{duplicate} // 1, $config->min_object_distance);
} }
$model->arrange_objects($print->config->min_object_distance); $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)); $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}) { foreach my $model_object (@{$model->objects}) {
$model_object->ensure_on_bed;
$print->auto_assign_extruders($model_object); $print->auto_assign_extruders($model_object);
$print->add_model_object($model_object);
} }
}
# Call apply_config_perl_tests_only one more time, so that the layer height profiles are updated over all PrintObjects. $print->apply($model, $config);
$print->apply_config_perl_tests_only($config);
$print->validate; $print->validate;
# We return a proxy object in order to keep $models alive as required by the Print API. # We return a proxy object in order to keep $models alive as required by the Print API.
return Slic3r::Test::Print->new( return Slic3r::Test::Print->new(
print => $print, print => $print,
models => $models, model => $model,
); );
} }
@ -250,7 +256,7 @@ sub add_facet {
package Slic3r::Test::Print; package Slic3r::Test::Print;
use Moo; use Moo;
has 'print' => (is => 'ro', required => 1, handles => [qw(process apply_config_perl_tests_only)]); has 'print' => (is => 'ro', required => 1, handles => [qw(process apply)]);
has 'models' => (is => 'ro', required => 1); has 'model' => (is => 'ro', required => 1);
1; 1;

BIN
resources/icons/row.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
resources/icons/table.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

View file

@ -579,7 +579,7 @@ void CLI::print_help(bool include_print_options, PrinterTechnology printer_techn
#endif /* SLIC3R_GUI */ #endif /* SLIC3R_GUI */
<< std::endl << std::endl
<< "https://github.com/prusa3d/PrusaSlicer" << std::endl << 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 << std::endl
<< "Actions:" << std::endl; << "Actions:" << std::endl;
cli_actions_config_def.print_cli_help(boost::nowide::cout, false); cli_actions_config_def.print_cli_help(boost::nowide::cout, false);

View file

@ -41,6 +41,7 @@
static int arduino_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m) static int arduino_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
{ {
unsigned char buf[32]; unsigned char buf[32];
(void)p;
/* Signature byte reads are always 3 bytes. */ /* 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) static int prusa_init_external_flash(PROGRAMMER * pgm)
{ {
// Note: send/receive as in _the firmare_ send & receives // Note: send/receive as in _the firmare_ send & receives
const char entry_magic_send [] = "start\n"; const char entry_magic_send[] = "start\n";
const char entry_magic_receive[] = "w25x20cl_enter\n"; const unsigned char entry_magic_receive[] = "w25x20cl_enter\n";
const char entry_magic_cfm [] = "w25x20cl_cfm\n"; const char entry_magic_cfm[] = "w25x20cl_cfm\n";
const size_t buffer_len = 32; // Should be large enough for the above messages const size_t buffer_len = 32; // Should be large enough for the above messages
int res; int res;
@ -94,7 +95,7 @@ static int prusa_init_external_flash(PROGRAMMER * pgm)
// 1. receive the "start" command // 1. receive the "start" command
recv_size = sizeof(entry_magic_send) - 1; 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) { 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); 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; return -1;
@ -111,7 +112,7 @@ static int prusa_init_external_flash(PROGRAMMER * pgm)
// 3. Receive the entry confirmation command // 3. Receive the entry confirmation command
recv_size = sizeof(entry_magic_cfm) - 1; 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) { 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); 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; 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 // 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): // 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) { if (serial_send(&pgm->fd, cleanup_newlines, sizeof(cleanup_newlines) - 1) < 0) {
return -1; return -1;
} }

View file

@ -341,7 +341,7 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype,
avr_tpi_setup_rw(pgm, mem, 0, TPI_NVMCMD_NO_OPERATION); avr_tpi_setup_rw(pgm, mem, 0, TPI_NVMCMD_NO_OPERATION);
/* load bytes */ /* load bytes */
for (lastaddr = i = 0; i < mem->size; i++) { for (lastaddr = i = 0; i < (unsigned)mem->size; i++) {
RETURN_IF_CANCEL(); RETURN_IF_CANCEL();
if (vmem == NULL || if (vmem == NULL ||
(vmem->tags[i] & TAG_ALLOCATED) != 0) (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 */ /* quickly scan number of pages to be written to first */
for (pageaddr = 0, npages = 0; for (pageaddr = 0, npages = 0;
pageaddr < mem->size; pageaddr < (unsigned)mem->size;
pageaddr += mem->page_size) { pageaddr += mem->page_size) {
/* check whether this page must be read */ /* check whether this page must be read */
for (i = pageaddr; for (i = pageaddr;
@ -391,7 +391,7 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype,
} }
for (pageaddr = 0, failure = 0, nread = 0; for (pageaddr = 0, failure = 0, nread = 0;
!failure && pageaddr < mem->size; !failure && pageaddr < (unsigned)mem->size;
pageaddr += mem->page_size) { pageaddr += mem->page_size) {
RETURN_IF_CANCEL(); RETURN_IF_CANCEL();
/* check whether this page must be read */ /* 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(); RETURN_IF_CANCEL();
if (vmem == NULL || if (vmem == NULL ||
(vmem->tags[i] & TAG_ALLOCATED) != 0) (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]; writeop = mem->op[AVR_OP_WRITE_HI];
else else
writeop = mem->op[AVR_OP_WRITE_LO]; 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]) { else if (mem->paged && mem->op[AVR_OP_LOADPAGE_LO]) {
if (addr & 0x01) if (addr & 0x01)
writeop = mem->op[AVR_OP_LOADPAGE_HI]; writeop = mem->op[AVR_OP_LOADPAGE_HI];
else else
writeop = mem->op[AVR_OP_LOADPAGE_LO]; writeop = mem->op[AVR_OP_LOADPAGE_LO];
caddr = addr / 2; caddr = (unsigned short)(addr / 2);
} }
else { else {
writeop = mem->op[AVR_OP_WRITE]; writeop = mem->op[AVR_OP_WRITE];
caddr = addr; caddr = (unsigned short)addr;
} }
if (writeop == NULL) { if (writeop == NULL) {
@ -723,7 +723,7 @@ int avr_write_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
gettimeofday (&tv, NULL); gettimeofday (&tv, NULL);
prog_time = (tv.tv_sec * 1000000) + tv.tv_usec; prog_time = (tv.tv_sec * 1000000) + tv.tv_usec;
} while ((r != data) && } 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 */ /* 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(); RETURN_IF_CANCEL();
if ((m->tags[i] & TAG_ALLOCATED) != 0 || if ((m->tags[i] & TAG_ALLOCATED) != 0 ||
(m->tags[i + 1] & 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 */ /* quickly scan number of pages to be written to first */
for (pageaddr = 0, npages = 0; for (pageaddr = 0, npages = 0;
pageaddr < wsize; pageaddr < (unsigned)wsize;
pageaddr += m->page_size) { pageaddr += m->page_size) {
/* check whether this page must be written to */ /* check whether this page must be written to */
for (i = pageaddr; 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; for (pageaddr = 0, failure = 0, nwritten = 0;
!failure && pageaddr < wsize; !failure && pageaddr < (unsigned)wsize;
pageaddr += m->page_size) { pageaddr += m->page_size) {
RETURN_IF_CANCEL(); RETURN_IF_CANCEL();
/* check whether this page must be written to */ /* 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; page_tainted = 0;
flush_page = 0; flush_page = 0;
for (i=0; i<wsize; i++) { for (i = 0; i < (unsigned)wsize; i++) {
RETURN_IF_CANCEL(); RETURN_IF_CANCEL();
data = m->buf[i]; data = m->buf[i];
report_progress(i, wsize, NULL); report_progress(i, wsize, NULL);

View file

@ -676,7 +676,7 @@ static int avr910_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
avr910_set_addr(pgm, addr / rd_size); avr910_set_addr(pgm, addr / rd_size);
while (addr < max_addr) { while (addr < max_addr) {
if ((max_addr - addr) < blocksize) { if ((max_addr - addr) < (unsigned)blocksize) {
blocksize = max_addr - addr; blocksize = max_addr - addr;
} }
cmd[1] = (blocksize >> 8) & 0xff; cmd[1] = (blocksize >> 8) & 0xff;

View file

@ -1,5 +1,5 @@
/* WARN: This file is auto-generated from `avrdude-slic3r.conf` */ /* 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, 0x0a, 0x23, 0x0a, 0x23, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
0x20, 0x61, 0x20, 0x62, 0x61, 0x73, 0x69, 0x63, 0x20, 0x6d, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x62, 0x61, 0x73, 0x69, 0x63, 0x20, 0x6d, 0x69, 0x6e,
0x69, 0x6d, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 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, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x0a,
0, 0 0, 0
}; };
size_t avrdude_slic3r_conf_size = 14178; const size_t avrdude_slic3r_conf_size = 14178;
size_t avrdude_slic3r_conf_size_yy = 14180; const size_t avrdude_slic3r_conf_size_yy = 14180;

View file

@ -93,7 +93,7 @@ void AvrDude::priv::unset_handlers()
int AvrDude::priv::run_one(const std::vector<std::string> &args) { 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 }; std::string command_line { PACKAGE };
for (const auto &arg : args) { for (const auto &arg : args) {
@ -105,7 +105,7 @@ int AvrDude::priv::run_one(const std::vector<std::string> &args) {
HandlerGuard guard(*this); 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()); 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; auto &message_fn = self->p->message_fn;
if (message_fn) { if (message_fn) {
message_fn(msg, sizeof(msg)); message_fn(msg, sizeof(msg));
message_fn(what, std::strlen(what)); message_fn(what, (unsigned)std::strlen(what));
message_fn("\n", 1); message_fn("\n", 1);
} }

View file

@ -64,6 +64,8 @@ int avrdude_main(int argc, char * argv []);
#include <windows.h> #include <windows.h>
#include <unistd.h> #include <unistd.h>
#define strdup _strdup
#ifdef UNICODE #ifdef UNICODE
#error "UNICODE should not be defined for avrdude bits on Windows" #error "UNICODE should not be defined for avrdude bits on Windows"
#endif #endif

View file

@ -358,7 +358,7 @@ AVRMEM * avr_locate_mem(AVRPART * p, char * desc)
int matches; int matches;
int l; int l;
l = strlen(desc); l = (int)strlen(desc);
matches = 0; matches = 0;
match = NULL; match = NULL;
for (ln=lfirst(p->mem); ln; ln=lnext(ln)) { 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); prefix);
px = prefix; px = prefix;
i = strlen(prefix) + 5; i = (int)strlen(prefix) + 5;
buf = (char *)malloc(i); buf = (char *)malloc(i);
if (buf == NULL) { if (buf == NULL) {
/* ugh, this is not important enough to bail, just ignore it */ /* ugh, this is not important enough to bail, just ignore it */

View file

@ -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); avrdude_message(MSG_DEBUG, "%s: buspirate_recv_bin():\n", progname);
dump_mem(MSG_DEBUG, buf, len); dump_mem(MSG_DEBUG, buf, len);
return len; return (int)len;
} }
static int buspirate_expect_bin(struct programmer_t *pgm, 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) static int buspirate_is_prompt(const char *str)
{ {
int strlen_str = strlen(str); int strlen_str = (int)strlen(str);
/* Prompt ends with '>' or '> ' /* Prompt ends with '>' or '> '
* all other input probably ends with '\n' */ * all other input probably ends with '\n' */
return (str[strlen_str - 1] == '>' || str[strlen_str - 2] == '>'); return (str[strlen_str - 1] == '>' || str[strlen_str - 2] == '>');

View file

@ -675,7 +675,7 @@ static int butterfly_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
butterfly_set_addr(pgm, addr / rd_size); butterfly_set_addr(pgm, addr / rd_size);
} }
while (addr < max_addr) { while (addr < max_addr) {
if ((max_addr - addr) < blocksize) { if ((max_addr - addr) < (unsigned)blocksize) {
blocksize = max_addr - addr; blocksize = max_addr - addr;
}; };
cmd[1] = (blocksize >> 8) & 0xff; cmd[1] = (blocksize >> 8) & 0xff;

View file

@ -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 << "/* WARN: This file is auto-generated from `" << filename << "` */" << std::endl;
std::cout << "unsigned char " << symbol << "[] = {"; std::cout << "const unsigned char " << symbol << "[] = {";
char c; char c;
std::cout << std::hex; std::cout << std::hex;
@ -34,8 +34,8 @@ int main(int argc, char const *argv[])
std::cout << "\n 0, 0\n};\n"; std::cout << "\n 0, 0\n};\n";
std::cout << std::dec; std::cout << std::dec;
std::cout << "size_t " << symbol << "_size = " << size << ";" << std::endl; std::cout << "const 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_yy = " << size + 2 << ";" << std::endl;
return 0; return 0;
} }

View file

@ -240,7 +240,7 @@ TOKEN * string(char * text)
return NULL; /* yyerror already called */ return NULL; /* yyerror already called */
} }
len = strlen(text); len = (int)strlen(text);
tkn->value.type = V_STR; tkn->value.type = V_STR;
tkn->value.string = (char *) malloc(len+1); 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; 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); extern void yy_delete_buffer(YY_BUFFER_STATE b);
int read_config_builtin() 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* // 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 // 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) { if (buffer == NULL) {
avrdude_message(MSG_INFO, "%s: read_config_builtin: Failed to initialize parsing buffer\n", progname); avrdude_message(MSG_INFO, "%s: read_config_builtin: Failed to initialize parsing buffer\n", progname);
return -1; return -1;

View file

@ -3640,7 +3640,7 @@ static int parse_cmdbits(OPCODE * op)
break; break;
} }
len = strlen(s); len = (int)strlen(s);
if (len == 0) { if (len == 0) {
yyerror("invalid bit specifier \"\""); yyerror("invalid bit specifier \"\"");

View file

@ -1493,7 +1493,7 @@ static int parse_cmdbits(OPCODE * op)
break; break;
} }
len = strlen(s); len = (int)strlen(s);
if (len == 0) { if (len == 0) {
yyerror("invalid bit specifier \"\""); yyerror("invalid bit specifier \"\"");

View file

@ -264,7 +264,7 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
unsigned char cksum; unsigned char cksum;
int rc; int rc;
len = strlen(rec); len = (int)strlen(rec);
offset = 1; offset = 1;
cksum = 0; cksum = 0;
@ -274,7 +274,7 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
for (i=0; i<2; i++) for (i=0; i<2; i++)
buf[i] = rec[offset++]; buf[i] = rec[offset++];
buf[i] = 0; buf[i] = 0;
ihex->reclen = strtoul(buf, &e, 16); ihex->reclen = (unsigned char)strtoul(buf, &e, 16);
if (e == buf || *e != 0) if (e == buf || *e != 0)
return -1; return -1;
@ -294,7 +294,7 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
for (i=0; i<2; i++) for (i=0; i<2; i++)
buf[i] = rec[offset++]; buf[i] = rec[offset++];
buf[i] = 0; buf[i] = 0;
ihex->rectyp = strtoul(buf, &e, 16); ihex->rectyp = (unsigned char)strtoul(buf, &e, 16);
if (e == buf || *e != 0) if (e == buf || *e != 0)
return -1; return -1;
@ -308,7 +308,7 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
for (i=0; i<2; i++) for (i=0; i<2; i++)
buf[i] = rec[offset++]; buf[i] = rec[offset++];
buf[i] = 0; buf[i] = 0;
ihex->data[j] = strtoul(buf, &e, 16); ihex->data[j] = (char)strtoul(buf, &e, 16);
if (e == buf || *e != 0) if (e == buf || *e != 0)
return -1; return -1;
cksum += ihex->data[j]; cksum += ihex->data[j];
@ -320,7 +320,7 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
for (i=0; i<2; i++) for (i=0; i<2; i++)
buf[i] = rec[offset++]; buf[i] = rec[offset++];
buf[i] = 0; buf[i] = 0;
ihex->cksum = strtoul(buf, &e, 16); ihex->cksum = (char)strtoul(buf, &e, 16);
if (e == buf || *e != 0) if (e == buf || *e != 0)
return -1; return -1;
@ -361,7 +361,7 @@ static int ihex2b(char * infile, FILE * inf,
while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) { while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) {
lineno++; lineno++;
len = strlen(buffer); len = (int)strlen(buffer);
if (buffer[len-1] == '\n') if (buffer[len-1] == '\n')
buffer[--len] = 0; buffer[--len] = 0;
if (buffer[0] != ':') if (buffer[0] != ':')
@ -388,7 +388,7 @@ static int ihex2b(char * infile, FILE * inf,
return -1; return -1;
} }
nextaddr = ihex.loadofs + baseaddr - fileoffset; 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", avrdude_message(MSG_INFO, "%s: ERROR: address 0x%04x out of range at line %d of %s\n",
progname, nextaddr+ihex.reclen, lineno, infile); progname, nextaddr+ihex.reclen, lineno, infile);
return -1; return -1;
@ -502,10 +502,11 @@ static int b2srec(unsigned char * inbuf, int bufsize,
cksum += n + addr_width + 1; 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; 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]); fprintf(outf, "%02X", buf[i]);
cksum += buf[i]; cksum += buf[i];
} }
@ -562,7 +563,7 @@ static int srec_readrec(struct ihexrec * srec, char * rec)
unsigned char cksum; unsigned char cksum;
int rc; int rc;
len = strlen(rec); len = (int)strlen(rec);
offset = 1; offset = 1;
cksum = 0; cksum = 0;
addr_width = 2; addr_width = 2;
@ -582,7 +583,7 @@ static int srec_readrec(struct ihexrec * srec, char * rec)
for (i=0; i<2; i++) for (i=0; i<2; i++)
buf[i] = rec[offset++]; buf[i] = rec[offset++];
buf[i] = 0; buf[i] = 0;
srec->reclen = strtoul(buf, &e, 16); srec->reclen = (char)strtoul(buf, &e, 16);
cksum += srec->reclen; cksum += srec->reclen;
srec->reclen -= (addr_width+1); srec->reclen -= (addr_width+1);
if (e == buf || *e != 0) 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++) for (i=0; i<addr_width*2; i++)
buf[i] = rec[offset++]; buf[i] = rec[offset++];
buf[i] = 0; buf[i] = 0;
srec->loadofs = strtoull(buf, &e, 16); srec->loadofs = strtoul(buf, &e, 16);
if (e == buf || *e != 0) if (e == buf || *e != 0)
return -1; return -1;
@ -608,7 +609,7 @@ static int srec_readrec(struct ihexrec * srec, char * rec)
for (i=0; i<2; i++) for (i=0; i<2; i++)
buf[i] = rec[offset++]; buf[i] = rec[offset++];
buf[i] = 0; buf[i] = 0;
srec->data[j] = strtoul(buf, &e, 16); srec->data[j] = (char)strtoul(buf, &e, 16);
if (e == buf || *e != 0) if (e == buf || *e != 0)
return -1; return -1;
cksum += srec->data[j]; cksum += srec->data[j];
@ -620,7 +621,7 @@ static int srec_readrec(struct ihexrec * srec, char * rec)
for (i=0; i<2; i++) for (i=0; i<2; i++)
buf[i] = rec[offset++]; buf[i] = rec[offset++];
buf[i] = 0; buf[i] = 0;
srec->cksum = strtoul(buf, &e, 16); srec->cksum = (char)strtoul(buf, &e, 16);
if (e == buf || *e != 0) if (e == buf || *e != 0)
return -1; return -1;
@ -650,7 +651,7 @@ static int srec2b(char * infile, FILE * inf,
while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) { while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) {
lineno++; lineno++;
len = strlen(buffer); len = (int)strlen(buffer);
if (buffer[len-1] == '\n') if (buffer[len-1] == '\n')
buffer[--len] = 0; buffer[--len] = 0;
if (buffer[0] != 0x53) if (buffer[0] != 0x53)
@ -729,7 +730,7 @@ static int srec2b(char * infile, FILE * inf,
return -1; return -1;
} }
nextaddr -= fileoffset; nextaddr -= fileoffset;
if (nextaddr + srec.reclen > bufsize) { if (nextaddr + srec.reclen > (unsigned)bufsize) {
avrdude_message(MSG_INFO, msg, progname, nextaddr+srec.reclen, "", avrdude_message(MSG_INFO, msg, progname, nextaddr+srec.reclen, "",
lineno, infile); lineno, infile);
return -1; return -1;
@ -1143,12 +1144,12 @@ static int fileio_rbin(struct fioparms * fio,
switch (fio->op) { switch (fio->op) {
case FIO_READ: case FIO_READ:
rc = fread(buf, 1, size, f); rc = (int)fread(buf, 1, size, f);
if (rc > 0) if (rc > 0)
memset(mem->tags, TAG_ALLOCATED, rc); memset(mem->tags, TAG_ALLOCATED, rc);
break; break;
case FIO_WRITE: case FIO_WRITE:
rc = fwrite(buf, 1, size, f); rc = (int)fwrite(buf, 1, size, f);
break; break;
default: default:
avrdude_message(MSG_INFO, "%s: fileio: invalid operation=%d\n", avrdude_message(MSG_INFO, "%s: fileio: invalid operation=%d\n",
@ -1190,7 +1191,7 @@ static int fileio_imm(struct fioparms * fio,
progname, p); progname, p);
return -1; return -1;
} }
mem->buf[loc] = b; mem->buf[loc] = (char)b;
mem->tags[loc++] = TAG_ALLOCATED; mem->tags[loc++] = TAG_ALLOCATED;
p = strtok(NULL, " ,"); p = strtok(NULL, " ,");
rc = loc; rc = loc;
@ -1452,7 +1453,7 @@ static int fmt_autodetect(char * fname, unsigned section)
} }
buf[MAX_LINE_LEN-1] = 0; buf[MAX_LINE_LEN-1] = 0;
len = strlen((char *)buf); len = (int)strlen((char *)buf);
if (buf[len-1] == '\n') if (buf[len-1] == '\n')
buf[--len] = 0; buf[--len] = 0;

View file

@ -444,7 +444,7 @@ lcreat ( void * liststruct, int elements )
l->poolsize = DEFAULT_POOLSIZE; l->poolsize = DEFAULT_POOLSIZE;
} }
else { 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); l->n_ln_pool = (l->poolsize-sizeof(NODEPOOL))/sizeof(LISTNODE);
@ -803,7 +803,7 @@ lget_n ( LISTID lid, unsigned int n )
CKLMAGIC(l); CKLMAGIC(l);
if ((n<1)||(n>lsize(l))) { if ((n < 1) || (n > (unsigned)lsize(l))) {
return NULL; return NULL;
} }
@ -844,7 +844,7 @@ lget_ln ( LISTID lid, unsigned int n )
CKLMAGIC(l); CKLMAGIC(l);
if ((n<1)||(n>lsize(l))) { if ((n < 1) || (n > (unsigned)lsize(l))) {
return NULL; return NULL;
} }
@ -952,7 +952,7 @@ lins_n ( LISTID lid, void * data_ptr, unsigned int n )
CKLMAGIC(l); CKLMAGIC(l);
if ((n<1)||(n>(l->num+1))) { if ((n < 1) || (n > (unsigned)(l->num+1))) {
return -1; return -1;
} }
@ -1193,7 +1193,7 @@ lrmv_n ( LISTID lid, unsigned int n )
CKLMAGIC(l); CKLMAGIC(l);
if ((n<1)||(n>l->num)) { if ((n < 1) || (n > (unsigned)l->num)) {
return NULL; return NULL;
} }

View file

@ -107,7 +107,7 @@ int avrdude_message(const int msglvl, const char *format, ...)
if (rc > 0 && rc < MSGBUFFER_SIZE) { if (rc > 0 && rc < MSGBUFFER_SIZE) {
avrdude_message_handler(msgbuffer, rc, avrdude_message_handler_user_p); avrdude_message_handler(msgbuffer, rc, avrdude_message_handler_user_p);
} else { } 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 // #endif
len = strlen(progname) + 2; len = (int)strlen(progname) + 2;
for (i=0; i<len; i++) for (i=0; i<len; i++)
progbuf[i] = ' '; progbuf[i] = ' ';
progbuf[i] = 0; progbuf[i] = 0;
@ -601,7 +601,7 @@ int avrdude_main(int argc, char * argv [])
bitclock = strtod(optarg, &e); bitclock = strtod(optarg, &e);
if (*e != 0) { if (*e != 0) {
/* trailing unit of measure present */ /* trailing unit of measure present */
int suffixlen = strlen(e); size_t suffixlen = strlen(e);
switch (suffixlen) { switch (suffixlen) {
case 2: case 2:
if ((e[0] != 'h' && e[0] != 'H') || e[1] != 'z') if ((e[0] != 'h' && e[0] != 'H') || e[1] != 'z')

View file

@ -217,7 +217,7 @@ const char * pinmask_to_str(const pinmask_t * const pinmask) {
* @param[in] size the number of entries in checklist * @param[in] size the number of entries in checklist
* @returns 0 if all pin definitions are valid, -1 otherwise * @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 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 rv = 0; // return value
int pinname; // loop counter through pinnames int pinname; // loop counter through pinnames

View file

@ -292,7 +292,7 @@ static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp)
if (hComPort == INVALID_HANDLE_VALUE) { if (hComPort == INVALID_HANDLE_VALUE) {
const char *error = last_error_string(0); const char *error = last_error_string(0);
avrdude_message(MSG_INFO, "%s: ser_open(): can't open device \"%s\": %s\n", progname, port, error); avrdude_message(MSG_INFO, "%s: ser_open(): can't open device \"%s\": %s\n", progname, port, error);
free(error); free((char *)error);
return -1; return -1;
} }
@ -460,10 +460,10 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t
serial_w32SetTimeOut(hComPort,500); 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); const char *error = last_error_string(0);
avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n", progname, error); avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n", progname, error);
free(error); free((char *)error);
return -1; 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); 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); const char *error = last_error_string(0);
avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, error); avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, error);
free(error); free((char *)error);
return -1; return -1;
} }
@ -642,7 +642,7 @@ static int ser_drain(union filedescriptor *fd, int display)
if (!readres) { if (!readres) {
const char *error = last_error_string(0); const char *error = last_error_string(0);
avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", progname, error); avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", progname, error);
free(error); free((char *)error);
return -1; return -1;
} }

View file

@ -308,8 +308,8 @@ static int serbb_open(PROGRAMMER *pgm, char *port)
progname, port); progname, port);
return -1; return -1;
} }
avrdude_message(MSG_DEBUG, "%s: ser_open(): opened comm port \"%s\", handle 0x%x\n", avrdude_message(MSG_DEBUG, "%s: ser_open(): opened comm port \"%s\", handle %p\n",
progname, port, (int)hComPort); progname, port, (void *)hComPort);
pgm->fd.pfd = (void *)hComPort; pgm->fd.pfd = (void *)hComPort;
@ -326,8 +326,8 @@ static void serbb_close(PROGRAMMER *pgm)
pgm->setpin(pgm, PIN_AVR_RESET, 1); pgm->setpin(pgm, PIN_AVR_RESET, 1);
CloseHandle (hComPort); CloseHandle (hComPort);
} }
avrdude_message(MSG_DEBUG, "%s: ser_close(): closed comm port handle 0x%x\n", avrdude_message(MSG_DEBUG, "%s: ser_close(): closed comm port handle %p\n",
progname, (int)hComPort); progname, (void *)hComPort);
hComPort = INVALID_HANDLE_VALUE; hComPort = INVALID_HANDLE_VALUE;
} }

View file

@ -821,7 +821,7 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
break; 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 /* build command block and avoid multiple send commands as it leads to a crash
of the silabs usb serial driver on mac os x */ of the silabs usb serial driver on mac os x */
i = 0; i = 0;
@ -834,7 +834,7 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
buf[i++] = block_size & 0x0f; buf[i++] = block_size & 0x0f;
buf[i++] = memtype; buf[i++] = memtype;
if (has_semicolon) { 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]; buf[i] = m->buf[addr + j];
if (buf[i] == ';') if (buf[i] == ';')
buf[i] |= (prusa3d_semicolon_workaround_round ? 0xf0 : 0x0f); buf[i] |= (prusa3d_semicolon_workaround_round ? 0xf0 : 0x0f);
@ -1088,7 +1088,7 @@ static int stk500_set_sck_period(PROGRAMMER * pgm, double v)
min = 8.0 / STK500_XTAL; min = 8.0 / STK500_XTAL;
max = 255 * min; max = 255 * min;
dur = v / min + 0.5; dur = (int)(v / min + 0.5);
if (v < min) { if (v < min) {
dur = 1; dur = 1;

View file

@ -130,58 +130,58 @@ struct jtagispentry
#define SZ_SPI_MULTI (USHRT_MAX - 1) #define SZ_SPI_MULTI (USHRT_MAX - 1)
}; };
static const struct jtagispentry jtagispcmds[] = { // static const struct jtagispentry jtagispcmds[] = {
/* generic */ // /* generic */
{ CMD_SET_PARAMETER, 2 }, // { CMD_SET_PARAMETER, 2 },
{ CMD_GET_PARAMETER, 3 }, // { CMD_GET_PARAMETER, 3 },
{ CMD_OSCCAL, 2 }, // { CMD_OSCCAL, 2 },
{ CMD_LOAD_ADDRESS, 2 }, // { CMD_LOAD_ADDRESS, 2 },
/* ISP mode */ // /* ISP mode */
{ CMD_ENTER_PROGMODE_ISP, 2 }, // { CMD_ENTER_PROGMODE_ISP, 2 },
{ CMD_LEAVE_PROGMODE_ISP, 2 }, // { CMD_LEAVE_PROGMODE_ISP, 2 },
{ CMD_CHIP_ERASE_ISP, 2 }, // { CMD_CHIP_ERASE_ISP, 2 },
{ CMD_PROGRAM_FLASH_ISP, 2 }, // { CMD_PROGRAM_FLASH_ISP, 2 },
{ CMD_READ_FLASH_ISP, SZ_READ_FLASH_EE }, // { CMD_READ_FLASH_ISP, SZ_READ_FLASH_EE },
{ CMD_PROGRAM_EEPROM_ISP, 2 }, // { CMD_PROGRAM_EEPROM_ISP, 2 },
{ CMD_READ_EEPROM_ISP, SZ_READ_FLASH_EE }, // { CMD_READ_EEPROM_ISP, SZ_READ_FLASH_EE },
{ CMD_PROGRAM_FUSE_ISP, 3 }, // { CMD_PROGRAM_FUSE_ISP, 3 },
{ CMD_READ_FUSE_ISP, 4 }, // { CMD_READ_FUSE_ISP, 4 },
{ CMD_PROGRAM_LOCK_ISP, 3 }, // { CMD_PROGRAM_LOCK_ISP, 3 },
{ CMD_READ_LOCK_ISP, 4 }, // { CMD_READ_LOCK_ISP, 4 },
{ CMD_READ_SIGNATURE_ISP, 4 }, // { CMD_READ_SIGNATURE_ISP, 4 },
{ CMD_READ_OSCCAL_ISP, 4 }, // { CMD_READ_OSCCAL_ISP, 4 },
{ CMD_SPI_MULTI, SZ_SPI_MULTI }, // { CMD_SPI_MULTI, SZ_SPI_MULTI },
/* all HV modes */ // /* all HV modes */
{ CMD_SET_CONTROL_STACK, 2 }, // { CMD_SET_CONTROL_STACK, 2 },
/* HVSP mode */ // /* HVSP mode */
{ CMD_ENTER_PROGMODE_HVSP, 2 }, // { CMD_ENTER_PROGMODE_HVSP, 2 },
{ CMD_LEAVE_PROGMODE_HVSP, 2 }, // { CMD_LEAVE_PROGMODE_HVSP, 2 },
{ CMD_CHIP_ERASE_HVSP, 2 }, // { CMD_CHIP_ERASE_HVSP, 2 },
{ CMD_PROGRAM_FLASH_HVSP, 2 }, // { CMD_PROGRAM_FLASH_HVSP, 2 },
{ CMD_READ_FLASH_HVSP, SZ_READ_FLASH_EE }, // { CMD_READ_FLASH_HVSP, SZ_READ_FLASH_EE },
{ CMD_PROGRAM_EEPROM_HVSP, 2 }, // { CMD_PROGRAM_EEPROM_HVSP, 2 },
{ CMD_READ_EEPROM_HVSP, SZ_READ_FLASH_EE }, // { CMD_READ_EEPROM_HVSP, SZ_READ_FLASH_EE },
{ CMD_PROGRAM_FUSE_HVSP, 2 }, // { CMD_PROGRAM_FUSE_HVSP, 2 },
{ CMD_READ_FUSE_HVSP, 3 }, // { CMD_READ_FUSE_HVSP, 3 },
{ CMD_PROGRAM_LOCK_HVSP, 2 }, // { CMD_PROGRAM_LOCK_HVSP, 2 },
{ CMD_READ_LOCK_HVSP, 3 }, // { CMD_READ_LOCK_HVSP, 3 },
{ CMD_READ_SIGNATURE_HVSP, 3 }, // { CMD_READ_SIGNATURE_HVSP, 3 },
{ CMD_READ_OSCCAL_HVSP, 3 }, // { CMD_READ_OSCCAL_HVSP, 3 },
/* PP mode */ // /* PP mode */
{ CMD_ENTER_PROGMODE_PP, 2 }, // { CMD_ENTER_PROGMODE_PP, 2 },
{ CMD_LEAVE_PROGMODE_PP, 2 }, // { CMD_LEAVE_PROGMODE_PP, 2 },
{ CMD_CHIP_ERASE_PP, 2 }, // { CMD_CHIP_ERASE_PP, 2 },
{ CMD_PROGRAM_FLASH_PP, 2 }, // { CMD_PROGRAM_FLASH_PP, 2 },
{ CMD_READ_FLASH_PP, SZ_READ_FLASH_EE }, // { CMD_READ_FLASH_PP, SZ_READ_FLASH_EE },
{ CMD_PROGRAM_EEPROM_PP, 2 }, // { CMD_PROGRAM_EEPROM_PP, 2 },
{ CMD_READ_EEPROM_PP, SZ_READ_FLASH_EE }, // { CMD_READ_EEPROM_PP, SZ_READ_FLASH_EE },
{ CMD_PROGRAM_FUSE_PP, 2 }, // { CMD_PROGRAM_FUSE_PP, 2 },
{ CMD_READ_FUSE_PP, 3 }, // { CMD_READ_FUSE_PP, 3 },
{ CMD_PROGRAM_LOCK_PP, 2 }, // { CMD_PROGRAM_LOCK_PP, 2 },
{ CMD_READ_LOCK_PP, 3 }, // { CMD_READ_LOCK_PP, 3 },
{ CMD_READ_SIGNATURE_PP, 3 }, // { CMD_READ_SIGNATURE_PP, 3 },
{ CMD_READ_OSCCAL_PP, 3 }, // { CMD_READ_OSCCAL_PP, 3 },
}; // };
/* /*
* From XML file: * From XML file:
@ -379,15 +379,15 @@ static void stk500v2_jtag3_teardown(PROGRAMMER * pgm)
} }
static unsigned short // static unsigned short
b2_to_u16(unsigned char *b) // b2_to_u16(unsigned char *b)
{ // {
unsigned short l; // unsigned short l;
l = b[0]; // l = b[0];
l += (unsigned)b[1] << 8; // l += (unsigned)b[1] << 8;
return l; // return l;
} // }
static int stk500v2_send_mk2(PROGRAMMER * pgm, unsigned char * data, size_t len) 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; return 0;
} }
static unsigned short get_jtagisp_return_size(unsigned char cmd) // static unsigned short get_jtagisp_return_size(unsigned char cmd)
{ // {
int i; // int i;
for (i = 0; i < sizeof jtagispcmds / sizeof jtagispcmds[0]; i++) // for (i = 0; i < sizeof jtagispcmds / sizeof jtagispcmds[0]; i++)
if (jtagispcmds[i].cmd == cmd) // if (jtagispcmds[i].cmd == cmd)
return jtagispcmds[i].size; // return jtagispcmds[i].size;
return 0; // return 0;
} // }
/* /*
* Send the data as a JTAG ICE mkII encapsulated ISP packet. * 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[0] = MESSAGE_START;
buf[1] = PDATA(pgm)->command_sequence; buf[1] = PDATA(pgm)->command_sequence;
buf[2] = len / 256; buf[2] = (char)(len / 256);
buf[3] = len % 256; buf[3] = len % 256;
buf[4] = TOKEN; buf[4] = TOKEN;
memcpy(buf+5, data, len); memcpy(buf+5, data, len);
@ -1128,7 +1128,8 @@ static int stk500v2_program_enable(PROGRAMMER * pgm, AVRPART * p)
{ {
unsigned char buf[16]; unsigned char buf[16];
char msg[100]; /* see remarks above about size needed */ char msg[100]; /* see remarks above about size needed */
int rv, tries; int rv;
// int tries;
PDATA(pgm)->lastpart = p; PDATA(pgm)->lastpart = p;
@ -1143,7 +1144,7 @@ static int stk500v2_program_enable(PROGRAMMER * pgm, AVRPART * p)
/* Activate AVR-style (low active) RESET */ /* Activate AVR-style (low active) RESET */
stk500v2_setparm_real(pgm, PARAM_RESET_POLARITY, 0x01); stk500v2_setparm_real(pgm, PARAM_RESET_POLARITY, 0x01);
tries = 0; // tries = 0;
// retry: // retry:
buf[0] = CMD_ENTER_PROGMODE_ISP; buf[0] = CMD_ENTER_PROGMODE_ISP;
buf[1] = p->timeout; 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) if (stk500v2_loadaddr(pgm, use_ext_addr | (paddr >> addrshift)) < 0)
return -1; return -1;
} else { } else {
buf[1] = addr; buf[1] = (char)addr;
} }
avrdude_message(MSG_NOTICE2, "%s: stk500hv_read_byte(): Sending read memory command: ", 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) if (stk500v2_loadaddr(pgm, use_ext_addr | (paddr >> addrshift)) < 0)
return -1; return -1;
} else { } else {
buf[1] = addr; buf[1] = (char)addr;
buf[2] = data; buf[2] = data;
if (mode == PPMODE) { if (mode == PPMODE) {
buf[3] = pulsewidth; buf[3] = pulsewidth;
@ -2298,7 +2299,7 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
unsigned int page_size, unsigned int page_size,
unsigned int addr, unsigned int n_bytes) 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 block_size, last_addr, addrshift, use_ext_addr;
unsigned int maxaddr = addr + n_bytes; unsigned int maxaddr = addr + n_bytes;
unsigned char commandbuf[10]; unsigned char commandbuf[10];
@ -2833,10 +2834,10 @@ static int stk500v2_set_fosc(PROGRAMMER * pgm, double v)
progname, v, unit, STK500V2_XTAL / 2e6); progname, v, unit, STK500V2_XTAL / 2e6);
fosc = STK500V2_XTAL / 2; fosc = STK500V2_XTAL / 2;
} else } else
fosc = (unsigned)v; fosc = (int)v;
for (idx = 0; idx < sizeof(ps) / sizeof(ps[0]); idx++) { 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 */ /* this prescaler value can handle our frequency */
prescale = idx + 1; prescale = idx + 1;
cmatch = (unsigned)(STK500V2_XTAL / (2 * fosc * ps[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; unsigned int oct, dac;
oct = 1.443 * log(v / 1039.0); oct = (unsigned)(1.443 * log(v / 1039.0));
dac = 2048 - (2078.0 * pow(2, (double)(10 + oct))) / v; dac = (unsigned)(2048.0 - (2078.0 * pow(2, (double)(10 + oct))) / v);
return stk500v2_setparm2(pgm, PARAM2_CLOCK_CONF, (oct << 12) | (dac << 2)); 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; unsigned int sck;
sck = ceil((16e6 / (2 * 1.0 / v)) - 1); sck = (unsigned)ceil((16e6 / (2 * 1.0 / v)) - 1);
if (sck >= 4096) if (sck >= 4096)
sck = 4095; sck = 4095;
@ -3093,7 +3094,7 @@ static int stk500v2_jtag3_set_sck_period(PROGRAMMER * pgm, double v)
else if (v > 1E-3) else if (v > 1E-3)
sck = 1; sck = 1;
else else
sck = 1.0 / (1000.0 * v); sck = (unsigned)(1.0 / (1000.0 * v));
value[0] = CMD_SET_SCK; value[0] = CMD_SET_SCK;
value[1] = sck & 0xff; 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) static int stk500v2_setparm(PROGRAMMER * pgm, unsigned char parm, unsigned char value)
{ {
unsigned char current_value; unsigned char current_value = 0;
int res; int res;
res = stk500v2_getparm(pgm, parm, &current_value); 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) static void stk500v2_display(PROGRAMMER * pgm, const char * p)
{ {
unsigned char maj, min, hdw, topcard, maj_s1, min_s1, maj_s2, min_s2; unsigned char maj = 0;
unsigned int rev; 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; const char *topcard_name, *pgmname;
switch (PDATA(pgm)->pgmtype) { 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) 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 char vtarget = 0;
unsigned int sck_stk600, clock_conf, dac, oct, varef; unsigned char vadjust = 0;
unsigned char vtarget_jtag[4]; 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; int prescale;
double f; double f;
const char *unit; const char *unit;
void *mycookie; // void *mycookie;
if (PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE_MKII) { if (PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE_MKII) {
return; return;
@ -3963,10 +3978,10 @@ static int stk600_xprog_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
b[0] = XPRG_CMD_WRITE_MEM; b[0] = XPRG_CMD_WRITE_MEM;
b[1] = memcode; b[1] = memcode;
b[2] = 0; /* pagemode: non-paged write */ b[2] = 0; /* pagemode: non-paged write */
b[3] = addr >> 24; b[3] = (char)(addr >> 24);
b[4] = addr >> 16; b[4] = (char)(addr >> 16);
b[5] = addr >> 8; b[5] = (char)(addr >> 8);
b[6] = addr; b[6] = (char)addr;
b[7] = 0; b[7] = 0;
b[8] = write_size; b[8] = write_size;
b[9] = data; b[9] = data;
@ -4011,10 +4026,10 @@ static int stk600_xprog_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
addr += mem->offset; addr += mem->offset;
b[0] = XPRG_CMD_READ_MEM; b[0] = XPRG_CMD_READ_MEM;
b[2] = addr >> 24; b[2] = (char)(addr >> 24);
b[3] = addr >> 16; b[3] = (char)(addr >> 16);
b[4] = addr >> 8; b[4] = (char)(addr >> 8);
b[5] = addr; b[5] = (char)addr;
b[6] = 0; b[6] = 0;
b[7] = 1; b[7] = 1;
if (stk600_xprog_command(pgm, b, 8, 3) < 0) { if (stk600_xprog_command(pgm, b, 8, 3) < 0) {

View file

@ -281,7 +281,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
maxsize = mem->size; maxsize = mem->size;
if (addr >= maxsize) { if (addr >= (unsigned long)maxsize) {
if (argc == 2) { if (argc == 2) {
/* wrap around */ /* wrap around */
addr = 0; 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 */ /* 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; len = maxsize - addr;
buf = malloc(len); buf = malloc(len);
@ -303,7 +303,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
return -1; 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]); rc = pgm->read_byte(pgm, p, mem, addr+i, &buf[i]);
if (rc != 0) { if (rc != 0) {
avrdude_message(MSG_INFO, "error reading %s address 0x%05lx of part %s\n", 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; 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", avrdude_message(MSG_INFO, "%s (write): address 0x%05lx is out of range for %s memory\n",
progname, addr, memtype); progname, addr, memtype);
return -1; return -1;
@ -373,7 +373,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
/* number of bytes to write at the specified address */ /* number of bytes to write at the specified address */
len = argc - 3; len = argc - 3;
if ((addr + len) > maxsize) { if ((addr + len) > (unsigned long)maxsize) {
avrdude_message(MSG_INFO, "%s (write): selected address and # bytes exceed " avrdude_message(MSG_INFO, "%s (write): selected address and # bytes exceed "
"range for %s memory\n", "range for %s memory\n",
progname, memtype); progname, memtype);
@ -386,8 +386,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
return -1; return -1;
} }
for (i=3; i<argc; i++) { for (i = 3; i < (unsigned long)argc; i++) {
buf[i-3] = strtoul(argv[i], &e, 0); buf[i-3] = (char)strtoul(argv[i], &e, 0);
if (*e || (e == argv[i])) { if (*e || (e == argv[i])) {
avrdude_message(MSG_INFO, "%s (write): can't parse byte \"%s\"\n", avrdude_message(MSG_INFO, "%s (write): can't parse byte \"%s\"\n",
progname, argv[i]); progname, argv[i]);
@ -397,7 +397,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
} }
pgm->err_led(pgm, OFF); 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]); rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]);
if (rc) { if (rc) {
@ -462,7 +462,7 @@ static int cmd_send(PROGRAMMER * pgm, struct avrpart * p,
/* load command bytes */ /* load command bytes */
for (i=1; i<argc; i++) { 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])) { if (*e || (e == argv[i])) {
avrdude_message(MSG_INFO, "%s (send): can't parse byte \"%s\"\n", avrdude_message(MSG_INFO, "%s (send): can't parse byte \"%s\"\n",
progname, argv[i]); progname, argv[i]);
@ -789,7 +789,7 @@ static int tokenize(char * s, char *** argv)
char * nbuf; char * nbuf;
char ** av; char ** av;
slen = strlen(s); slen = (int)strlen(s);
/* /*
* initialize allow for 20 arguments, use realloc to grow this if * 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); nexttok(r, &q, &r);
strcpy(nbuf, q); strcpy(nbuf, q);
bufv[n] = nbuf; bufv[n] = nbuf;
len = strlen(q); len = (int)strlen(q);
l += len + 1; l += len + 1;
nbuf += len + 1; nbuf += len + 1;
nbuf[0] = 0; nbuf[0] = 0;
@ -841,7 +841,7 @@ static int tokenize(char * s, char *** argv)
q = (char *)&av[n+1]; q = (char *)&av[n+1];
memcpy(q, buf, l); memcpy(q, buf, l);
for (i=0; i<n; i++) { for (i=0; i<n; i++) {
offset = bufv[i] - buf; offset = (int)(bufv[i] - buf);
av[i] = q + offset; av[i] = q + offset;
} }
av[i] = NULL; av[i] = NULL;
@ -862,7 +862,7 @@ static int do_cmd(PROGRAMMER * pgm, struct avrpart * p,
int hold; int hold;
int len; int len;
len = strlen(argv[0]); len = (int)strlen(argv[0]);
hold = -1; hold = -1;
for (i=0; i<NCMDS; i++) { for (i=0; i<NCMDS; i++) {
if (strcasecmp(argv[0], cmd[i].name) == 0) { if (strcasecmp(argv[0], cmd[i].name) == 0) {

View file

@ -10,5 +10,5 @@ if(libigl_FOUND)
target_link_libraries(libigl INTERFACE igl::core) target_link_libraries(libigl INTERFACE igl::core)
else() else()
message(STATUS "IGL NOT found, using bundled version...") 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() endif()

View file

@ -10,10 +10,6 @@
#include "boost/multiprecision/integer.hpp" #include "boost/multiprecision/integer.hpp"
#include "boost/rational.hpp" #include "boost/rational.hpp"
//#include "../tools/Int128.hpp"
//#include "gte/Mathematics/GteMinimumAreaBox2.h"
//#include "../tools/libnfpglue.hpp" //#include "../tools/libnfpglue.hpp"
//#include "../tools/nfp_svgnest_glue.hpp" //#include "../tools/nfp_svgnest_glue.hpp"
@ -183,7 +179,7 @@ TEST(GeometryAlgorithms, Distance) {
Segment seg(p1, p3); 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 result = pointlike::horizontalDistance(p2, seg);
@ -396,7 +392,7 @@ TEST(GeometryAlgorithms, ArrangeRectanglesLoose)
{ {
using namespace libnest2d; 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 = { std::vector<Rectangle> rects = {
{80, 80}, {80, 80},
{60, 90}, {60, 90},
@ -454,14 +450,14 @@ void exportSVG(std::vector<std::reference_wrapper<Item>>& result, const Bin& bin
std::string loc = "out"; std::string loc = "out";
static std::string svg_header = 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"> <!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"> <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"; )raw";
int i = idx; int i = idx;
auto r = result; auto r = result;
// for(auto r : result) { // for(auto r : result) {
std::fstream out(loc + std::to_string(i) + ".svg", std::fstream::out); std::fstream out(loc + std::to_string(i) + ".svg", std::fstream::out);
if(out.is_open()) { if(out.is_open()) {
out << svg_header; out << svg_header;
@ -487,8 +483,8 @@ R"raw(<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
} }
out.close(); out.close();
// i++; // i++;
// } // }
} }
} }
@ -556,11 +552,12 @@ TEST(GeometryAlgorithms, NestTest) {
ASSERT_LE(result.size(), 2); ASSERT_LE(result.size(), 2);
int partsum = std::accumulate(result.begin(), size_t partsum = std::accumulate(result.begin(),
result.end(), result.end(),
0, size_t(0),
[](int s, [](size_t s,
const decltype(result)::value_type &bin) { const decltype(
result)::value_type &bin) {
return s += bin.size(); return s += bin.size();
}); });
@ -728,7 +725,7 @@ std::vector<ItemPair> nfp_testdata = {
} }
}; };
std::vector<ItemPair> nfp_concave_testdata = { std::vector<ItemPair> nfp_concave_testdata = {
{ // ItemPair { // ItemPair
{ {
{ {
@ -935,67 +932,39 @@ template<class T> struct BoostGCD {
}; };
using Unit = int64_t; using Unit = int64_t;
using Ratio = boost::rational<boost::multiprecision::int128_t>;// Rational<boost::multiprecision::int256_t>; using Ratio = boost::rational<boost::multiprecision::int128_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;
//}
} }
TEST(RotatingCalipers, MinAreaBBCClk) { 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; }; auto u = [](ClipperLib::cInt n) { return n*1000000; };
PolygonImpl poly({ {u(0), u(0)}, {u(4), u(1)}, {u(2), u(4)}}); PolygonImpl poly({ {u(0), u(0)}, {u(4), u(1)}, {u(2), u(4)}});
long double arearef = refMinAreaBox(poly); long double arearef = refMinAreaBox(poly);
long double area = minAreaBoundingBox<PolygonImpl, Unit, Ratio>(poly).area(); long double area = minAreaBoundingBox<PolygonImpl, Unit, Ratio>(poly).area();
// double gtearea = gteMinAreaBox(poly);
ASSERT_LE(std::abs(area - arearef), 500e6 ); ASSERT_LE(std::abs(area - arearef), 500e6 );
// ASSERT_LE(std::abs(gtearea - arearef), 500 );
// ASSERT_DOUBLE_EQ(gtearea, arearef);
} }
TEST(RotatingCalipers, AllPrusaMinBB) { TEST(RotatingCalipers, AllPrusaMinBB) {
size_t idx = 0; // /size_t idx = 0;
long double err_epsilon = 500e6l; long double err_epsilon = 500e6l;
for(ClipperLib::Path rinput : PRINTER_PART_POLYGONS) { for(ClipperLib::Path rinput : PRINTER_PART_POLYGONS) {
// ClipperLib::Path rinput = PRINTER_PART_POLYGONS[idx]; // ClipperLib::Path rinput = PRINTER_PART_POLYGONS[idx];
// rinput.pop_back(); // rinput.pop_back();
// std::reverse(rinput.begin(), rinput.end()); // 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); PolygonImpl poly(rinput);
long double arearef = refMinAreaBox(poly); long double arearef = refMinAreaBox(poly);
auto bb = minAreaBoundingBox<PathImpl, Unit, Ratio>(rinput); auto bb = minAreaBoundingBox<PathImpl, Unit, Ratio>(rinput);
long double area = cast<long double>(bb.area()); long double area = cast<long double>(bb.area());
// double area = gteMinAreaBox(poly);
bool succ = std::abs(arearef - area) < err_epsilon; bool succ = std::abs(arearef - area) < err_epsilon;
std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: " // std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: "
<< arearef << " actual: " << area << std::endl; // << arearef << " actual: " << area << std::endl;
ASSERT_TRUE(succ); ASSERT_TRUE(succ);
} }
@ -1006,15 +975,14 @@ TEST(RotatingCalipers, AllPrusaMinBB) {
PolygonImpl poly(removeCollinearPoints<PathImpl, PointImpl, Unit>(rinput, 1000000)); PolygonImpl poly(removeCollinearPoints<PathImpl, PointImpl, Unit>(rinput, 1000000));
long double arearef = refMinAreaBox(poly); long double arearef = refMinAreaBox(poly);
auto bb = minAreaBoundingBox<PolygonImpl, Unit, Ratio>(poly); auto bb = minAreaBoundingBox<PolygonImpl, Unit, Ratio>(poly);
long double area = cast<long double>(bb.area()); long double area = cast<long double>(bb.area());
// double area = gteMinAreaBox(poly);
bool succ = std::abs(arearef - area) < err_epsilon; bool succ = std::abs(arearef - area) < err_epsilon;
std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: " // std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: "
<< arearef << " actual: " << area << std::endl; // << arearef << " actual: " << area << std::endl;
ASSERT_TRUE(succ); ASSERT_TRUE(succ);
} }

View file

@ -751,18 +751,18 @@ bool DynamicConfig::read_cli(int argc, char** argv, t_config_option_keys* extra,
} }
// Store the option value. // Store the option value.
const bool existing = this->has(opt_key); const bool existing = this->has(opt_key);
if (keys != nullptr && !existing) { if (keys != nullptr && ! existing) {
// Save the order of detected keys. // Save the order of detected keys.
keys->push_back(opt_key); keys->push_back(opt_key);
} }
ConfigOption *opt_base = this->option(opt_key, true); ConfigOption *opt_base = this->option(opt_key, true);
ConfigOptionVectorBase *opt_vector = opt_base->is_vector() ? static_cast<ConfigOptionVectorBase*>(opt_base) : nullptr; ConfigOptionVectorBase *opt_vector = opt_base->is_vector() ? static_cast<ConfigOptionVectorBase*>(opt_base) : nullptr;
if (opt_vector) { 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 // Vector values will be chained. Repeated use of a parameter will append the parameter or parameters
// to the end of the value. // to the end of the value.
if (!existing)
// remove the default values
opt_vector->deserialize("", true);
if (opt_base->type() == coBools) if (opt_base->type() == coBools)
static_cast<ConfigOptionBools*>(opt_base)->values.push_back(!no); static_cast<ConfigOptionBools*>(opt_base)->values.push_back(!no);
else else

View file

@ -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. // 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. // 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; 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; 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. // Get size of this vector.
virtual size_t size() const = 0; 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(); } size_t size() const override { return this->values.size(); }
bool empty() const override { return this->values.empty(); } bool empty() const override { return this->values.empty(); }

View file

@ -126,7 +126,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
Polygons surfaces_polygons = to_polygons(surfaces); Polygons surfaces_polygons = to_polygons(surfaces);
Polygons collapsed = diff( Polygons collapsed = diff(
surfaces_polygons, 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); true);
Polygons to_subtract; Polygons to_subtract;
to_subtract.reserve(collapsed.size() + number_polygons(surfaces)); to_subtract.reserve(collapsed.size() + number_polygons(surfaces));
@ -137,7 +137,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
surfaces_append( surfaces_append(
surfaces, surfaces,
intersection_ex( intersection_ex(
offset(collapsed, distance_between_surfaces), offset(collapsed, (float)distance_between_surfaces),
to_subtract, to_subtract,
true), true),
stInternalSolid); stInternalSolid);
@ -219,14 +219,14 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
f->z = layerm.layer()->print_z; f->z = layerm.layer()->print_z;
f->angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value)); f->angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
// Maximum length of the perimeter segment linking two infill lines. // 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. // 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; // f->layer_height = h;
// apply half spacing using this flow's own spacing and generate infill // apply half spacing using this flow's own spacing and generate infill
FillParams params; FillParams params;
params.density = 0.01 * density; params.density = float(0.01 * density);
// params.dont_adjust = true; // params.dont_adjust = true;
params.dont_adjust = false; params.dont_adjust = false;
Polylines polylines = f->fill_surface(&surface, params); 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 // so we can safely ignore the slight variation that might have
// been applied to $f->flow_spacing // been applied to $f->flow_spacing
} else { } 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. // Save into layer.

View file

@ -11,10 +11,16 @@
#include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem/operations.hpp> #include <boost/filesystem/operations.hpp>
#include <boost/nowide/fstream.hpp> #include <boost/nowide/fstream.hpp>
#include <boost/nowide/cstdio.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 <expat.h>
#include <Eigen/Dense> #include <Eigen/Dense>
#include "miniz_extension.hpp" #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 PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config";
const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.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_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 std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt";
const char* MODEL_TAG = "model"; const char* MODEL_TAG = "model";
@ -331,6 +338,7 @@ namespace Slic3r {
typedef std::map<int, ObjectMetadata> IdToMetadataMap; typedef std::map<int, ObjectMetadata> IdToMetadataMap;
typedef std::map<int, Geometry> IdToGeometryMap; typedef std::map<int, Geometry> IdToGeometryMap;
typedef std::map<int, std::vector<coordf_t>> IdToLayerHeightsProfileMap; 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; typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap;
// Version of the 3mf file // Version of the 3mf file
@ -347,6 +355,7 @@ namespace Slic3r {
CurrentConfig m_curr_config; CurrentConfig m_curr_config;
IdToMetadataMap m_objects_metadata; IdToMetadataMap m_objects_metadata;
IdToLayerHeightsProfileMap m_layer_heights_profiles; IdToLayerHeightsProfileMap m_layer_heights_profiles;
IdToLayerConfigRangesMap m_layer_config_ranges;
IdToSlaSupportPointsMap m_sla_support_points; IdToSlaSupportPointsMap m_sla_support_points;
std::string m_curr_metadata_name; std::string m_curr_metadata_name;
std::string m_curr_characters; 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 _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); 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_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_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); 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_curr_config.volume_id = -1;
m_objects_metadata.clear(); m_objects_metadata.clear();
m_layer_heights_profiles.clear(); m_layer_heights_profiles.clear();
m_layer_config_ranges.clear();
m_sla_support_points.clear(); m_sla_support_points.clear();
m_curr_metadata_name.clear(); m_curr_metadata_name.clear();
m_curr_characters.clear(); m_curr_characters.clear();
@ -546,9 +557,14 @@ namespace Slic3r {
if (boost::algorithm::iequals(name, LAYER_HEIGHTS_PROFILE_FILE)) 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); _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)) else if (boost::algorithm::iequals(name, SLA_SUPPORT_POINTS_FILE))
{ {
// extract 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()) if (obj_layer_heights_profile != m_layer_heights_profiles.end())
model_object->layer_height_profile = obj_layer_heights_profile->second; 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. // 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); 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()) { 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) 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) 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_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_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_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_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_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); 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; 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"). // 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. // 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! // 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; return false;
} }
vertices_count += its.vertices.size(); vertices_count += (int)its.vertices.size();
const Transform3d& matrix = volume->get_matrix(); const Transform3d& matrix = volume->get_matrix();
@ -1925,7 +2017,7 @@ namespace Slic3r {
// updates triangle offsets // updates triangle offsets
volume_it->second.first_triangle_id = triangles_count; 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; volume_it->second.last_triangle_id = triangles_count - 1;
for (size_t i = 0; i < its.indices.size(); ++ i) for (size_t i = 0; i < its.indices.size(); ++ i)
@ -2013,6 +2105,70 @@ namespace Slic3r {
return true; 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) bool _3MF_Exporter::_add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model)
{ {
std::string out = ""; std::string out = "";

View file

@ -106,6 +106,9 @@ struct AMFParserContext
// amf/material/metadata // amf/material/metadata
NODE_TYPE_OBJECT, // amf/object NODE_TYPE_OBJECT, // amf/object
// amf/object/metadata // 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_MESH, // amf/object/mesh
NODE_TYPE_VERTICES, // amf/object/mesh/vertices NODE_TYPE_VERTICES, // amf/object/mesh/vertices
NODE_TYPE_VERTEX, // amf/object/mesh/vertices/vertex NODE_TYPE_VERTEX, // amf/object/mesh/vertices/vertex
@ -260,7 +263,9 @@ void AMFParserContext::startElement(const char *name, const char **atts)
m_value[0] = get_attribute(atts, "type"); m_value[0] = get_attribute(atts, "type");
node_type_new = NODE_TYPE_METADATA; 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) if (m_path[1] == NODE_TYPE_OBJECT)
node_type_new = NODE_TYPE_MESH; node_type_new = NODE_TYPE_MESH;
} else if (strcmp(name, "instance") == 0) { } 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) else if (strcmp(name, "mirrorz") == 0)
node_type_new = NODE_TYPE_MIRRORZ; 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; break;
case 4: case 4:
if (m_path[3] == NODE_TYPE_VERTICES) { 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) } else if (strcmp(name, "triangle") == 0)
node_type_new = NODE_TYPE_TRIANGLE; 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; break;
case 5: case 5:
if (strcmp(name, "coordinates") == 0) { if (strcmp(name, "coordinates") == 0) {
@ -571,8 +584,13 @@ void AMFParserContext::endElement(const char * /* name */)
config = &m_material->config; config = &m_material->config;
else if (m_path[1] == NODE_TYPE_OBJECT && m_object) else if (m_path[1] == NODE_TYPE_OBJECT && m_object)
config = &m_object->config; 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; 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) if (config)
config->set_deserialize(opt_key, m_value[1]); 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) { } 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) if (end != nullptr)
*end = 0; *end = 0;
point(coord_idx) = atof(p); point(coord_idx) = float(atof(p));
if (++coord_idx == 5) { if (++coord_idx == 5) {
m_object->sla_support_points.push_back(sla::SupportPoint(point)); m_object->sla_support_points.push_back(sla::SupportPoint(point));
coord_idx = 0; coord_idx = 0;
@ -609,6 +627,16 @@ void AMFParserContext::endElement(const char * /* name */)
} }
m_object->sla_points_status = sla::PointsStatus::UserModified; 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) { else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume) {
if (strcmp(opt_key, "modifier") == 0) { if (strcmp(opt_key, "modifier") == 0) {
// Is this volume a modifier volume? // 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) //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; const std::vector<sla::SupportPoint>& sla_support_points = object->sla_support_points;
if (!sla_support_points.empty()) { if (!sla_support_points.empty()) {
// Store the SLA supports as a single semicolon separated list. // 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 << " </coordinates>\n";
stream << " </vertex>\n"; stream << " </vertex>\n";
} }
num_vertices += its.vertices.size(); num_vertices += (int)its.vertices.size();
} }
stream << " </vertices>\n"; stream << " </vertices>\n";
for (size_t i_volume = 0; i_volume < object->volumes.size(); ++i_volume) { for (size_t i_volume = 0; i_volume < object->volumes.size(); ++i_volume) {

View file

@ -1405,7 +1405,9 @@ void GCode::process_layer(
m_colorprint_heights.erase(m_colorprint_heights.begin()); m_colorprint_heights.erase(m_colorprint_heights.begin());
colorprint_change = true; 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"; gcode += "M600\n";

View file

@ -7,6 +7,9 @@
#include <utility> // for std::forward #include <utility> // for std::forward
#include <algorithm> #include <algorithm>
#include "libslic3r.h"
#include "Point.hpp"
namespace Slic3r { namespace Slic3r {
/// Handy little spin mutex for the cached meshes. /// 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>
static_assert(std::is_integral<X>::value && using enable_if_t = typename std::enable_if<B, T>::type;
std::is_integral<Y>::value && sizeof(X) >= sizeof(Y),
"");
return (x % y) ? x / y + 1 : x / y; // /////////////////////////////////////////////////////////////////////////////
// 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
{
//return static_cast<Tout>(std::round(v / SCALING_FACTOR));
return static_cast<Tout>(v / static_cast<Tin>(SCALING_FACTOR));
}
// 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 } // namespace Slic3r

View file

@ -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<> 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::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::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(); } template<> Slic3r::Points::const_iterator cend(const Slic3r::Points& pts, const PathTag&) { return pts.cend(); }
@ -71,37 +71,40 @@ using Rational = boost::rational<__int128>;
MinAreaBoundigBox::MinAreaBoundigBox(const Polygon &p, PolygonLevel pc) MinAreaBoundigBox::MinAreaBoundigBox(const Polygon &p, PolygonLevel pc)
{ {
const Polygon& chull = pc == pcConvex ? p : libnest2d::sl::convexHull(p); const Polygon &chull = pc == pcConvex ? p :
libnest2d::sl::convexHull(p);
libnest2d::RotatedBox<Point, Unit> box = libnest2d::RotatedBox<Point, Unit> box =
libnest2d::minAreaBoundingBox<Polygon, Unit, Rational>(chull); libnest2d::minAreaBoundingBox<Polygon, Unit, Rational>(chull);
m_right = box.right_extent(); m_right = libnest2d::cast<long double>(box.right_extent());
m_bottom = box.bottom_extent(); m_bottom = libnest2d::cast<long double>(box.bottom_extent());
m_axis = box.axis(); m_axis = box.axis();
} }
MinAreaBoundigBox::MinAreaBoundigBox(const ExPolygon &p, PolygonLevel pc) MinAreaBoundigBox::MinAreaBoundigBox(const ExPolygon &p, PolygonLevel pc)
{ {
const ExPolygon& chull = pc == pcConvex ? p : libnest2d::sl::convexHull(p); const ExPolygon &chull = pc == pcConvex ? p :
libnest2d::sl::convexHull(p);
libnest2d::RotatedBox<Point, Unit> box = libnest2d::RotatedBox<Point, Unit> box =
libnest2d::minAreaBoundingBox<ExPolygon, Unit, Rational>(chull); libnest2d::minAreaBoundingBox<ExPolygon, Unit, Rational>(chull);
m_right = box.right_extent(); m_right = libnest2d::cast<long double>(box.right_extent());
m_bottom = box.bottom_extent(); m_bottom = libnest2d::cast<long double>(box.bottom_extent());
m_axis = box.axis(); m_axis = box.axis();
} }
MinAreaBoundigBox::MinAreaBoundigBox(const Points &pts, PolygonLevel pc) MinAreaBoundigBox::MinAreaBoundigBox(const Points &pts, PolygonLevel pc)
{ {
const Points& chull = pc == pcConvex ? pts : libnest2d::sl::convexHull(pts); const Points &chull = pc == pcConvex ? pts :
libnest2d::sl::convexHull(pts);
libnest2d::RotatedBox<Point, Unit> box = libnest2d::RotatedBox<Point, Unit> box =
libnest2d::minAreaBoundingBox<Points, Unit, Rational>(chull); libnest2d::minAreaBoundingBox<Points, Unit, Rational>(chull);
m_right = box.right_extent(); m_right = libnest2d::cast<long double>(box.right_extent());
m_bottom = box.bottom_extent(); m_bottom = libnest2d::cast<long double>(box.bottom_extent());
m_axis = box.axis(); m_axis = box.axis();
} }
@ -109,18 +112,20 @@ double MinAreaBoundigBox::angle_to_X() const
{ {
double ret = std::atan2(m_axis.y(), m_axis.x()); double ret = std::atan2(m_axis.y(), m_axis.x());
auto s = std::signbit(ret); auto s = std::signbit(ret);
if(s) ret += 2 * PI; if (s) ret += 2 * PI;
return -ret; return -ret;
} }
long double MinAreaBoundigBox::width() const 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 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 MinAreaBoundigBox::area() const
@ -138,5 +143,4 @@ void remove_collinear_points(ExPolygon &p)
{ {
p = libnest2d::removeCollinearPoints<ExPolygon>(p, Unit(0)); p = libnest2d::removeCollinearPoints<ExPolygon>(p, Unit(0));
} }
} // namespace Slic3r
}

View file

@ -631,7 +631,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
assert(this->config.id() == rhs.config.id()); assert(this->config.id() == rhs.config.id());
this->sla_support_points = rhs.sla_support_points; this->sla_support_points = rhs.sla_support_points;
this->sla_points_status = rhs.sla_points_status; 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->layer_height_profile = rhs.layer_height_profile;
this->origin_translation = rhs.origin_translation; this->origin_translation = rhs.origin_translation;
m_bounding_box = rhs.m_bounding_box; m_bounding_box = rhs.m_bounding_box;
@ -670,7 +670,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
assert(this->config.id() == rhs.config.id()); assert(this->config.id() == rhs.config.id());
this->sla_support_points = std::move(rhs.sla_support_points); this->sla_support_points = std::move(rhs.sla_support_points);
this->sla_points_status = std::move(rhs.sla_points_status); 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->layer_height_profile = std::move(rhs.layer_height_profile);
this->origin_translation = std::move(rhs.origin_translation); this->origin_translation = std::move(rhs.origin_translation);
m_bounding_box = std::move(rhs.m_bounding_box); 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(); Vec3d shift = this->mesh().bounding_box().center();
if (!shift.isApprox(Vec3d::Zero())) if (!shift.isApprox(Vec3d::Zero()))
{ {
const_cast<TriangleMesh*>(m_mesh.get())->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2)); if (m_mesh)
const_cast<TriangleMesh*>(m_convex_hull.get())->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2)); 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); 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())) if (!mv_old.get_matrix().isApprox(mv_new.get_matrix()))
return true; return true;
++i_old; ++ i_old;
++ i_new; ++ i_new;
} }
for (; i_old < model_object_old.volumes.size(); ++ i_old) { for (; i_old < model_object_old.volumes.size(); ++ i_old) {

View file

@ -160,8 +160,8 @@ public:
ModelVolumePtrs volumes; ModelVolumePtrs volumes;
// Configuration parameters specific to a single ModelObject, overriding the global Slic3r settings. // Configuration parameters specific to a single ModelObject, overriding the global Slic3r settings.
ModelConfig config; ModelConfig config;
// Variation of a layer thickness for spans of Z coordinates. // Variation of a layer thickness for spans of Z coordinates + optional parameter overrides.
t_layer_height_ranges layer_height_ranges; t_layer_config_ranges layer_config_ranges;
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers. // 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. // The pairs of <z, layer_height> are packed into a 1D array.
std::vector<coordf_t> layer_height_profile; std::vector<coordf_t> layer_height_profile;

View file

@ -63,9 +63,9 @@ std::string toString(const Model& model, bool holes = true) {
ExPolygons expolys = tmpmesh.horizontal_projection(); ExPolygons expolys = tmpmesh.horizontal_projection();
for(auto& expoly_complex : expolys) { 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; if(tmp.empty()) continue;
auto expoly = tmp.front(); ExPolygon expoly = tmp.front();
expoly.contour.make_clockwise(); expoly.contour.make_clockwise();
for(auto& h : expoly.holes) h.make_counter_clockwise(); for(auto& h : expoly.holes) h.make_counter_clockwise();
@ -610,7 +610,7 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model,
if(tolerance > EPSILON) { if(tolerance > EPSILON) {
Polygons pp { p }; Polygons pp { p };
pp = p.simplify(double(scaled(tolerance))); pp = p.simplify(scaled<double>(tolerance));
if (!pp.empty()) p = pp.front(); if (!pp.empty()) p = pp.front();
} }
@ -633,8 +633,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model,
if(item.vertexCount() > 3) { if(item.vertexCount() > 3) {
item.rotation(Geometry::rotation_diff_z(rotation0, objinst->get_rotation())); item.rotation(Geometry::rotation_diff_z(rotation0, objinst->get_rotation()));
item.translation({ item.translation({
ClipperLib::cInt(objinst->get_offset(X)/SCALING_FACTOR), scaled<ClipperLib::cInt>(objinst->get_offset(X)),
ClipperLib::cInt(objinst->get_offset(Y)/SCALING_FACTOR) scaled<ClipperLib::cInt>(objinst->get_offset(Y))
}); });
ret.emplace_back(objinst, item); ret.emplace_back(objinst, item);
} }
@ -658,8 +658,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model,
Item item(std::move(pn)); Item item(std::move(pn));
item.rotation(wti.rotation), item.rotation(wti.rotation),
item.translation({ item.translation({
ClipperLib::cInt(wti.pos(0)/SCALING_FACTOR), scaled<ClipperLib::cInt>(wti.pos(0)),
ClipperLib::cInt(wti.pos(1)/SCALING_FACTOR) scaled<ClipperLib::cInt>(wti.pos(1))
}); });
ret.emplace_back(nullptr, item); ret.emplace_back(nullptr, item);
} }
@ -822,7 +822,9 @@ bool arrange(Model &model, // The model with the geometries
auto& cfn = stopcondition; 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, auto binbb = Box({libnest2d::Coord{bbb.min(0)} - md,
libnest2d::Coord{bbb.min(1)} - md}, libnest2d::Coord{bbb.min(1)} - md},
@ -916,7 +918,9 @@ void find_new_position(const Model &model,
BoundingBox bbb(bed); 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, auto binbb = Box({libnest2d::Coord{bbb.min(0)} - md,
libnest2d::Coord{bbb.min(1)} - md}, libnest2d::Coord{bbb.min(1)} - md},

View file

@ -12,6 +12,8 @@
//#include "PrintExport.hpp" //#include "PrintExport.hpp"
#include <float.h>
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
#include <unordered_set> #include <unordered_set>
@ -41,36 +43,6 @@ void Print::clear()
m_model.clear_objects(); 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() PrintRegion* Print::add_region()
{ {
m_regions.emplace_back(new PrintRegion(this)); m_regions.emplace_back(new PrintRegion(this));
@ -335,7 +307,7 @@ unsigned int Print::num_object_instances() const
{ {
unsigned int instances = 0; unsigned int instances = 0;
for (const PrintObject *print_object : m_objects) for (const PrintObject *print_object : m_objects)
instances += print_object->copies().size(); instances += (unsigned int)print_object->copies().size();
return instances; return instances;
} }
@ -358,198 +330,6 @@ double Print::max_allowed_layer_height() const
return nozzle_diameter_max; 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 // 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. // 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. // 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) static inline bool transform3d_lower(const Transform3d &lhs, const Transform3d &rhs)
{ {
typedef Transform3d::Scalar T; 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()); 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) Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &config_in)
{ {
#ifdef _DEBUG #ifdef _DEBUG
@ -724,6 +535,50 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
// Handle changes to regions config defaults // Handle changes to regions config defaults
m_default_region_config.apply_only(config, region_diff, true); 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 { struct ModelObjectStatus {
enum Status { enum Status {
Unknown, Unknown,
@ -732,9 +587,10 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
Moved, Moved,
Deleted, Deleted,
}; };
ModelObjectStatus(ObjectID id, Status status = Unknown) : id(id), status(status) {} ModelObjectStatus(ModelID id, Status status = Unknown) : id(id), status(status) {}
ObjectID id; ModelID id;
Status status; Status status;
LayerRanges layer_ranges;
// Search by id. // Search by id.
bool operator<(const ModelObjectStatus &rhs) const { return id < rhs.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())); auto it_status = model_object_status.find(ModelObjectStatus(model_object.id()));
assert(it_status != model_object_status.end()); assert(it_status != model_object_status.end());
assert(it_status->status != ModelObjectStatus::Deleted); 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) if (it_status->status == ModelObjectStatus::New)
// PrintObject instances will be added in the next loop. // PrintObject instances will be added in the next loop.
continue; continue;
// Update the ModelObject instance, possibly invalidate the linked PrintObjects. // Update the ModelObject instance, possibly invalidate the linked PrintObjects.
assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved); 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. // 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 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 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_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); bool support_enforcers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER);
if (model_parts_differ || modifiers_differ || if (model_parts_differ || modifiers_differ ||
model_object.origin_translation != model_object_new.origin_translation || 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. // 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())); auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
for (auto it = range.first; it != range.second; ++ it) { for (auto it = range.first; it != range.second; ++ it) {
@ -915,7 +773,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
//FIXME What to do with m_material_id? //FIXME What to do with m_material_id?
model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::MODEL_PART); model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::MODEL_PART);
model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::PARAMETER_MODIFIER); model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::PARAMETER_MODIFIER);
// 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.name = model_object_new.name;
model_object.input_file = model_object_new.input_file; model_object.input_file = model_object_new.input_file;
model_object.clear_instances(); model_object.clear_instances();
@ -1027,19 +886,27 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
PrintRegionConfig this_region_config; PrintRegionConfig this_region_config;
bool this_region_config_set = false; bool this_region_config_set = false;
for (PrintObject *print_object : m_objects) { 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()) { if (region_id < print_object->region_volumes.size()) {
for (int volume_id : print_object->region_volumes[region_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_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 (this_region_config_set) {
// If the new config for this volume differs from the other // If the new config for this volume differs from the other
// volume configs currently associated to this region, it means // volume configs currently associated to this region, it means
// the region subdivision does not make sense anymore. // 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. // Regions were split. Reset this print_object.
goto print_object_end; goto print_object_end;
} else { } else {
this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, volume, num_extruders); 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) { for (size_t i = 0; i < region_id; ++ i) {
const PrintRegion &region_other = *m_regions[i]; const PrintRegion &region_other = *m_regions[i];
if (region_other.m_refcnt != 0 && region_other.config().equals(this_region_config)) if (region_other.m_refcnt != 0 && region_other.config().equals(this_region_config))
// Regions were merged. Reset this print_object. // 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()); update_apply_status(print_object->invalidate_all_steps());
// Decrease the references to regions from this volume. // Decrease the references to regions from this volume.
int ireg = 0; 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()) if (! volumes.empty())
-- m_regions[ireg]->m_refcnt; -- m_regions[ireg]->m_refcnt;
++ ireg; ++ ireg;
@ -1076,20 +943,32 @@ 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) { for (size_t idx_print_object = 0; idx_print_object < m_objects.size(); ++ idx_print_object) {
PrintObject &print_object0 = *m_objects[idx_print_object]; PrintObject &print_object0 = *m_objects[idx_print_object];
const ModelObject &model_object = *print_object0.model_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) { 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]; PrintObject &print_object = *m_objects[i];
bool fresh = print_object.region_volumes.empty(); bool fresh = print_object.region_volumes.empty();
unsigned int volume_id = 0; unsigned int volume_id = 0;
unsigned int idx_region_in_object = 0;
for (const ModelVolume *volume : model_object.volumes) { for (const ModelVolume *volume : model_object.volumes) {
if (! volume->is_model_part() && ! volume->is_modifier()) { if (! volume->is_model_part() && ! volume->is_modifier()) {
++ volume_id; ++ volume_id;
continue; continue;
} }
// 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; int region_id = -1;
if (&print_object == &print_object0) { if (&print_object == &print_object0) {
// Get the config applied to this volume. // Get the config applied to this volume.
PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, *volume, num_extruders); 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. // Find an existing print region with the same config.
int idx_empty_slot = -1; int idx_empty_slot = -1;
for (int i = 0; i < (int)m_regions.size(); ++ i) { for (int i = 0; i < (int)m_regions.size(); ++ i) {
@ -1111,14 +990,15 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
m_regions[region_id]->set_config(std::move(config)); m_regions[region_id]->set_config(std::move(config));
} }
} }
map_volume_to_region[volume_id] = region_id; regions_in_object.emplace_back(region_id);
} else } else
region_id = map_volume_to_region[volume_id]; region_id = regions_in_object[idx_region_in_object ++];
// Assign volume to a region. // Assign volume to a region.
if (fresh) { if (fresh) {
if (region_id >= print_object.region_volumes.size() || print_object.region_volumes[region_id].empty()) if (region_id >= print_object.region_volumes.size() || print_object.region_volumes[region_id].empty())
++ m_regions[region_id]->m_refcnt; ++ m_regions[region_id]->m_refcnt;
print_object.add_region_volume(region_id, volume_id); print_object.add_region_volume(region_id, volume_id, it_range->first);
}
} }
++ volume_id; ++ volume_id;
} }
@ -1175,9 +1055,9 @@ std::string Print::validate() const
Polygon convex_hull0 = offset( Polygon convex_hull0 = offset(
print_object->model_object()->convex_hull_2d( print_object->model_object()->convex_hull_2d(
Geometry::assemble_transform(Vec3d::Zero(), rotation, model_instance0->get_scaling_factor(), model_instance0->get_mirror())), 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. // 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; Polygon convex_hull = convex_hull0;
convex_hull.translate(copy); convex_hull.translate(copy);
if (! intersection(convex_hulls_other, convex_hull).empty()) if (! intersection(convex_hulls_other, convex_hull).empty())
@ -1227,7 +1107,7 @@ std::string Print::validate() const
bool has_custom_layering = false; bool has_custom_layering = false;
std::vector<std::vector<coordf_t>> layer_height_profiles; std::vector<std::vector<coordf_t>> layer_height_profiles;
for (const PrintObject *object : m_objects) { 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) { if (has_custom_layering) {
layer_height_profiles.assign(m_objects.size(), std::vector<coordf_t>()); layer_height_profiles.assign(m_objects.size(), std::vector<coordf_t>());
break; break;
@ -1436,8 +1316,8 @@ Flow Print::brim_flow() const
return Flow::new_from_config_width( return Flow::new_from_config_width(
frPerimeter, frPerimeter,
width, width,
m_config.nozzle_diameter.get_at(m_regions.front()->config().perimeter_extruder-1), (float)m_config.nozzle_diameter.get_at(m_regions.front()->config().perimeter_extruder-1),
this->skirt_first_layer_height(), (float)this->skirt_first_layer_height(),
0 0
); );
} }
@ -1458,8 +1338,8 @@ Flow Print::skirt_flow() const
return Flow::new_from_config_width( return Flow::new_from_config_width(
frPerimeter, frPerimeter,
width, width,
m_config.nozzle_diameter.get_at(m_objects.front()->config().support_material_extruder-1), (float)m_config.nozzle_diameter.get_at(m_objects.front()->config().support_material_extruder-1),
this->skirt_first_layer_height(), (float)this->skirt_first_layer_height(),
0 0
); );
} }
@ -1636,18 +1516,18 @@ void Print::_make_skirt()
// The skirt will touch the brim if the brim is extruded. // 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()); 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. // 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. // 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.); std::vector<coordf_t> extruded_length(extruders.size(), 0.);
for (int i = n_skirts, extruder_idx = 0; i > 0; -- i) { for (int i = n_skirts, extruder_idx = 0; i > 0; -- i) {
this->throw_if_canceled(); this->throw_if_canceled();
// Offset the skirt outside. // Offset the skirt outside.
distance += coord_t(scale_(spacing)); distance += float(scale_(spacing));
// Generate the skirt centerline. // Generate the skirt centerline.
Polygon loop; 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); Geometry::simplify_polygons(loops, scale_(0.05), &loops);
if (loops.empty()) if (loops.empty())
break; break;
@ -1658,9 +1538,9 @@ void Print::_make_skirt()
eloop.paths.emplace_back(ExtrusionPath( eloop.paths.emplace_back(ExtrusionPath(
ExtrusionPath( ExtrusionPath(
erSkirt, 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, 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(); eloop.paths.back().polyline = loop.split_at_first_point();
m_skirt.append(eloop); m_skirt.append(eloop);
@ -1786,7 +1666,7 @@ void Print::_make_wipe_tower()
// Insert the new support layer. // Insert the new support layer.
double height = lt.print_z - m_wipe_tower_data.tool_ordering.layer_tools()[i-1].print_z; 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. //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; ++ it_layer;
} }
} }
@ -1813,19 +1693,19 @@ void Print::_make_wipe_tower()
WipeTowerPrusaMM::parse_material(m_config.filament_type.get_at(i).c_str()), WipeTowerPrusaMM::parse_material(m_config.filament_type.get_at(i).c_str()),
m_config.temperature.get_at(i), m_config.temperature.get_at(i),
m_config.first_layer_temperature.get_at(i), m_config.first_layer_temperature.get_at(i),
m_config.filament_loading_speed.get_at(i), (float)m_config.filament_loading_speed.get_at(i),
m_config.filament_loading_speed_start.get_at(i), (float)m_config.filament_loading_speed_start.get_at(i),
m_config.filament_unloading_speed.get_at(i), (float)m_config.filament_unloading_speed.get_at(i),
m_config.filament_unloading_speed_start.get_at(i), (float)m_config.filament_unloading_speed_start.get_at(i),
m_config.filament_toolchange_delay.get_at(i), (float)m_config.filament_toolchange_delay.get_at(i),
m_config.filament_cooling_moves.get_at(i), m_config.filament_cooling_moves.get_at(i),
m_config.filament_cooling_initial_speed.get_at(i), (float)m_config.filament_cooling_initial_speed.get_at(i),
m_config.filament_cooling_final_speed.get_at(i), (float)m_config.filament_cooling_final_speed.get_at(i),
m_config.filament_ramming_parameters.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>( 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 // 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) // 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 for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers
if (!layer_tools.has_wipe_tower) continue; if (!layer_tools.has_wipe_tower) continue;
bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front(); 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) { 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) { 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 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: // 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: // 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); 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: // 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 // 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); first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back(), volume_to_wipe);
current_extruder_id = extruder_id; current_extruder_id = extruder_id;
} }

View file

@ -80,8 +80,8 @@ private: // Prevents erroneous use by other classes.
typedef PrintObjectBaseWithState<Print, PrintObjectStep, posCount> Inherited; typedef PrintObjectBaseWithState<Print, PrintObjectStep, posCount> Inherited;
public: public:
// vector of (vectors of volume ids), indexed by region_id // vector of (layer height ranges and vectors of volume ids), indexed by region_id
std::vector<std::vector<int>> region_volumes; 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 // 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 // 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)); } BoundingBox bounding_box() const { return BoundingBox(Point(0,0), to_2d(this->size)); }
// adds region_id, too, if necessary // 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()) if (region_id >= region_volumes.size())
region_volumes.resize(region_id + 1); 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 is the *total* layer count (including support layers)
// this value is not supposed to be compared with Layer::id // this value is not supposed to be compared with Layer::id
@ -141,8 +141,9 @@ public:
void slice(); void slice();
// Helpers to slice support enforcer / blocker meshes by the support generator. // Helpers to slice support enforcer / blocker meshes by the support generator.
std::vector<ExPolygons> slice_support_enforcers() const; std::vector<ExPolygons> slice_support_volumes(const ModelVolumeType &model_volume_type) const;
std::vector<ExPolygons> slice_support_blockers() 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: protected:
// to be called from Print only. // to be called from Print only.
@ -165,7 +166,7 @@ protected:
void update_slicing_parameters(); void update_slicing_parameters();
static PrintObjectConfig object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders); 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: private:
void make_perimeters(); void make_perimeters();
@ -201,9 +202,11 @@ private:
LayerPtrs m_layers; LayerPtrs m_layers;
SupportLayerPtrs m_support_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_region(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_modifiers(size_t region_id, const std::vector<float> &z) const;
std::vector<ExPolygons> _slice_volume(const std::vector<float> &z, const ModelVolume &volume) 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 struct WipeTowerData
@ -291,11 +294,6 @@ public:
ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override; 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; 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. // 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). // If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r).

View file

@ -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 // Translate meshes so that our toolpath generation algorithms work with smaller
// XY coordinates; this translation is an optimization and not strictly required. // 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. // 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 // 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). // (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() 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 bool PrintObject::has_support_material() const
@ -1354,10 +1359,12 @@ PrintObjectConfig PrintObject::object_config_from_model_object(const PrintObject
return config; 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; PrintRegionConfig config = default_region_config;
normalize_and_apply_config(config, volume.get_object()->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); normalize_and_apply_config(config, volume.config);
if (! volume.material_id().empty()) if (! volume.material_id().empty())
normalize_and_apply_config(config, volume.material()->config); 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()); 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; PrintConfig print_config;
PrintObjectConfig object_config; PrintObjectConfig object_config;
PrintRegionConfig default_region_config; PrintRegionConfig default_region_config;
print_config .apply(full_config, true); print_config.apply(full_config, true);
object_config.apply(full_config, true); object_config.apply(full_config, true);
default_region_config.apply(full_config, true); default_region_config.apply(full_config, true);
size_t num_extruders = print_config.nozzle_diameter.size(); size_t num_extruders = print_config.nozzle_diameter.size();
object_config = object_config_from_model_object(object_config, model_object, num_extruders); object_config = object_config_from_model_object(object_config, model_object, num_extruders);
std::vector<unsigned int> object_extruders; std::vector<unsigned int> object_extruders;
for (const ModelVolume *model_volume : model_object.volumes) for (const ModelVolume* model_volume : model_object.volumes)
if (model_volume->is_model_part()) if (model_volume->is_model_part()) {
PrintRegion::collect_object_printing_extruders( PrintRegion::collect_object_printing_extruders(
print_config, print_config,
region_config_from_model_volume(default_region_config, *model_volume, num_extruders), region_config_from_model_volume(default_region_config, nullptr, *model_volume, num_extruders),
object_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); sort_remove_duplicates(object_extruders);
if (object_max_z <= 0.f) 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); return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders);
} }
@ -1432,9 +1448,9 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
if (layer_height_profile.empty()) { if (layer_height_profile.empty()) {
if (0) if (0)
// if (this->layer_height_profile.empty()) // 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 else
layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_height_ranges); layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges); // #ys_FIXME_experiment
updated = true; updated = true;
} }
return updated; 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. // 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_volumes = 0;
size_t num_modifiers = 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 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]; const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
if (model_volume->is_model_part()) { if (model_volume->is_model_part()) {
map_volume_to_region[volume_id] = region_id; if (last_volume_id == volume_id) {
if (single_volume_region == -2) has_z_ranges = true;
} else {
last_volume_id = volume_id;
if (all_volumes_single_region == -2)
// first model volume met // first model volume met
single_volume_region = region_id; all_volumes_single_region = region_id;
else if (single_volume_region != region_id) else if (all_volumes_single_region != region_id)
// multiple volumes met and they are not equal // multiple volumes met and they are not equal
single_volume_region = -1; all_volumes_single_region = -1;
++ num_volumes; ++ num_volumes;
}
} else if (model_volume->is_modifier()) } else if (model_volume->is_modifier())
++ num_modifiers; ++ num_modifiers;
} }
@ -1514,13 +1536,13 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
// Slice all non-modifier volumes. // Slice all non-modifier volumes.
bool clipped = false; bool clipped = false;
bool upscaled = 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. // 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. // 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) { for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id; BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id;
// slicing in parallel // 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(); m_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " start"; 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) for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id)
@ -1541,13 +1563,27 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
}; };
std::vector<SlicedVolume> sliced_volumes; std::vector<SlicedVolume> sliced_volumes;
sliced_volumes.reserve(num_volumes); sliced_volumes.reserve(num_volumes);
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
for (int volume_id : this->region_volumes[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]; const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
if (model_volume->is_model_part()) { if (model_volume->is_model_part()) {
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - volume " << volume_id; 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 // 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. // Second clip the volumes in the order they are presented at the user interface.
@ -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) { for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - region " << region_id; BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - region " << region_id;
// slicing in parallel // 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(); m_print->throw_if_canceled();
if (expolygons_by_layer.empty()) if (expolygons_by_layer.empty())
continue; continue;
@ -1619,7 +1655,7 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
Layer *layer = m_layers[layer_id]; Layer *layer = m_layers[layer_id];
LayerRegion *layerm = layer->m_regions[region_id]; LayerRegion *layerm = layer->m_regions[region_id];
LayerRegion *other_layerm = layer->m_regions[other_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; continue;
Polygons other_slices = to_polygons(other_layerm->slices); Polygons other_slices = to_polygons(other_layerm->slices);
ExPolygons my_parts = intersection_ex(other_slices, to_polygons(expolygons_by_layer[layer_id])); 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"; 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()) { if (region_id < this->region_volumes.size()) {
for (int volume_id : this->region_volumes[region_id]) { 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_id]; const ModelVolume *volume = this->model_object()->volumes[volume_and_range.second];
if (modifier ? volume->is_modifier() : volume->is_model_part()) if (volume->is_model_part())
volumes.emplace_back(volume); 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<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_volumes(const ModelVolumeType &model_volume_type) const
{ {
std::vector<const ModelVolume*> volumes; std::vector<const ModelVolume*> volumes;
for (const ModelVolume *volume : this->model_object()->volumes) for (const ModelVolume *volume : this->model_object()->volumes)
if (volume->is_support_enforcer()) if (volume->type() == model_volume_type)
volumes.emplace_back(volume); volumes.emplace_back(volume);
std::vector<float> zs; std::vector<float> zs;
zs.reserve(this->layers().size()); zs.reserve(this->layers().size());
for (const Layer *l : this->layers()) for (const Layer *l : this->layers())
zs.emplace_back((float)l->slice_z); zs.emplace_back((float)l->slice_z);
return this->_slice_volumes(zs, volumes); return this->slice_volumes(zs, volumes);
} }
std::vector<ExPolygons> PrintObject::slice_support_blockers() const std::vector<ExPolygons> PrintObject::slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const
{
std::vector<const ModelVolume*> volumes;
for (const ModelVolume *volume : this->model_object()->volumes)
if (volume->is_support_blocker())
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> PrintObject::_slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const
{ {
std::vector<ExPolygons> layers; std::vector<ExPolygons> layers;
if (! volumes.empty()) { if (! volumes.empty()) {
@ -1828,11 +1945,12 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
return layers; 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; std::vector<ExPolygons> layers;
if (! z.empty()) {
// Compose mesh. // Compose mesh.
//FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them. //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()); TriangleMesh mesh(volume.mesh());
mesh.transform(volume.get_matrix(), true); mesh.transform(volume.get_matrix(), true);
if (mesh.repaired) { if (mesh.repaired) {
@ -1853,9 +1971,45 @@ std::vector<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &z,
mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback); mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
m_print->throw_if_canceled(); m_print->throw_if_canceled();
} }
}
return layers; 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() std::string PrintObject::_fix_slicing_errors()
{ {
// Collect layers with 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? //Should the pw not be half of the current value?
float pw = FLT_MAX; float pw = FLT_MAX;
for (const LayerRegion *layerm : layer->m_regions) 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 // Append such thick perimeters to the areas that need support
polygons_append(overhangs, offset2(perimeters, -pw, +pw)); polygons_append(overhangs, offset2(perimeters, -pw, +pw));
} }

View file

@ -5,6 +5,7 @@
#include "SLABoostAdapter.hpp" #include "SLABoostAdapter.hpp"
#include "ClipperUtils.hpp" #include "ClipperUtils.hpp"
#include "Tesselate.hpp" #include "Tesselate.hpp"
#include "MTUtils.hpp"
// For debugging: // For debugging:
//#include <fstream> //#include <fstream>
@ -203,7 +204,7 @@ void offset(ExPolygon& sh, coord_t distance) {
} }
ClipperOffset offs; ClipperOffset offs;
offs.ArcTolerance = 0.01*scaled(1.0); offs.ArcTolerance = scaled<double>(0.01);
Paths result; Paths result;
offs.AddPath(ctour, jtRound, etClosedPolygon); offs.AddPath(ctour, jtRound, etClosedPolygon);
offs.AddPaths(holes, jtRound, etClosedPolygon); offs.AddPaths(holes, jtRound, etClosedPolygon);
@ -351,7 +352,7 @@ Contour3D round_edges(const ExPolygon& base_plate,
double x2 = xx*xx; double x2 = xx*xx;
double stepy = std::sqrt(r2 - x2); double stepy = std::sqrt(r2 - x2);
offset(ob, s*scaled(xx)); offset(ob, s * scaled(xx));
wh = ceilheight_mm - radius_mm + stepy; wh = ceilheight_mm - radius_mm + stepy;
Contour3D pwalls; Contour3D pwalls;
@ -375,7 +376,7 @@ Contour3D round_edges(const ExPolygon& base_plate,
double xx = radius_mm - i*stepx; double xx = radius_mm - i*stepx;
double x2 = xx*xx; double x2 = xx*xx;
double stepy = std::sqrt(r2 - x2); double stepy = std::sqrt(r2 - x2);
offset(ob, s*scaled(xx)); offset(ob, s * scaled(xx));
wh = ceilheight_mm - radius_mm - stepy; wh = ceilheight_mm - radius_mm - stepy;
Contour3D pwalls; 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 dx = x(c) - x(cc), dy = y(c) - y(cc);
double l = std::sqrt(dx * dx + dy * dy); double l = std::sqrt(dx * dx + dy * dy);
double nx = dx / l, ny = dy / l; 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++]; ExPolygon& expo = punion[idx++];
BoundingBox querybb(expo); BoundingBox querybb(expo);
@ -492,7 +493,7 @@ ExPolygons concave_hull(const ExPolygons& polys, double max_dist_mm = 50,
ctour.reserve(3); ctour.reserve(3);
ctour.emplace_back(cc); 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) ));
ctour.emplace_back(c + Point( y(d), -x(d) )); ctour.emplace_back(c + Point( y(d), -x(d) ));
offset(r, scaled(1.)); offset(r, scaled(1.));
@ -529,14 +530,14 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
ExPolygons tmp; tmp.reserve(count); ExPolygons tmp; tmp.reserve(count);
for(ExPolygons& o : out) for(ExPolygons& o : out)
for(ExPolygon& e : o) { 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)); for(ExPolygon& ep : exss) tmp.emplace_back(std::move(ep));
} }
ExPolygons utmp = unify(tmp); ExPolygons utmp = unify(tmp);
for(auto& o : utmp) { 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()); output.insert(output.end(), smp.begin(), smp.end());
} }
} }

View file

@ -668,7 +668,7 @@ void SLAPrint::process()
double ilhd = m_material_config.initial_layer_height.getFloat(); double ilhd = m_material_config.initial_layer_height.getFloat();
auto ilh = float(ilhd); auto ilh = float(ilhd);
auto ilhs = scaled(ilhd); coord_t ilhs = scaled(ilhd);
const size_t objcount = m_objects.size(); const size_t objcount = m_objects.size();
static const unsigned min_objstatus = 0; // where the per object operations start static const unsigned min_objstatus = 0; // where the per object operations start
@ -696,15 +696,13 @@ void SLAPrint::process()
double lhd = m_objects.front()->m_config.layer_height.getFloat(); double lhd = m_objects.front()->m_config.layer_height.getFloat();
float lh = float(lhd); float lh = float(lhd);
auto lhs = scaled(lhd); coord_t lhs = scaled(lhd);
auto && bb3d = mesh.bounding_box();
auto &&bb3d = mesh.bounding_box();
double minZ = bb3d.min(Z) - po.get_elevation(); double minZ = bb3d.min(Z) - po.get_elevation();
double maxZ = bb3d.max(Z); double maxZ = bb3d.max(Z);
auto minZf = float(minZ); auto minZf = float(minZ);
coord_t minZs = scaled(minZ);
auto minZs = scaled(minZ); coord_t maxZs = scaled(maxZ);
auto maxZs = scaled(maxZ);
po.m_slice_index.clear(); po.m_slice_index.clear();
@ -722,8 +720,9 @@ void SLAPrint::process()
if(slindex_it == po.m_slice_index.end()) if(slindex_it == po.m_slice_index.end())
//TRN To be shown at the status bar on SLA slicing error. //TRN To be shown at the status bar on SLA slicing error.
throw std::runtime_error(L("Slicing had to be stopped " throw std::runtime_error(
"due to an internal 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.clear();
po.m_model_height_levels.reserve(po.m_slice_index.size()); po.m_model_height_levels.reserve(po.m_slice_index.size());
@ -1013,9 +1012,6 @@ void SLAPrint::process()
using ClipperPolygons = std::vector<ClipperPolygon>; using ClipperPolygons = std::vector<ClipperPolygon>;
namespace sl = libnest2d::shapelike; // For algorithms 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 // Set up custom union and diff functions for clipper polygons
auto polyunion = [] (const ClipperPolygons& subjects) 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 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 auto width = scaled<double>(m_printer_config.display_width.getFloat());
const double height = scaled(m_printer_config.display_height.getFloat()); const auto height = scaled<double>(m_printer_config.display_height.getFloat());
const double display_area = width*height; const double display_area = width*height;
// get polygons for all instances in the object // get polygons for all instances in the object
@ -1123,11 +1119,6 @@ void SLAPrint::process()
sl::translate(poly, ClipperPoint{instances[i].shift(X), sl::translate(poly, ClipperPoint{instances[i].shift(X),
instances[i].shift(Y)}); 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)); polygons.emplace_back(std::move(poly));
} }
} }

View file

@ -153,24 +153,33 @@ SlicingParameters SlicingParameters::create_from_config(
return params; 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. // 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( std::vector<coordf_t> layer_height_profile_from_ranges(
const SlicingParameters &slicing_params, 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. // 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; 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()) if (slicing_params.first_object_layer_height_fixed())
ranges_non_overlapping.push_back(std::pair<t_layer_height_range,coordf_t>( ranges_non_overlapping.push_back(std::pair<t_layer_height_range,coordf_t>(
t_layer_height_range(0., slicing_params.first_object_layer_height), t_layer_height_range(0., slicing_params.first_object_layer_height),
slicing_params.first_object_layer_height)); slicing_params.first_object_layer_height));
// The height ranges are sorted lexicographically by low / high layer boundaries. // 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 lo = it_range->first.first;
coordf_t hi = std::min(it_range->first.second, slicing_params.object_print_z_height()); 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()) if (! ranges_non_overlapping.empty())
// Trim current low with the last high. // Trim current low with the last high.
lo = std::max(lo, ranges_non_overlapping.back().first.second); 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. // Fill layer_height_profile by heights ensuring a prescribed maximum cusp height.
std::vector<coordf_t> layer_height_profile_adaptive( std::vector<coordf_t> layer_height_profile_adaptive(
const SlicingParameters &slicing_params, const SlicingParameters &slicing_params,
const t_layer_height_ranges &layer_height_ranges, const t_layer_config_ranges & /* layer_config_ranges */,
const ModelVolumePtrs &volumes) const ModelVolumePtrs &volumes)
{ {
// 1) Initialize the SlicingAdaptive class with the object meshes. // 1) Initialize the SlicingAdaptive class with the object meshes.

View file

@ -11,6 +11,8 @@
#include "libslic3r.h" #include "libslic3r.h"
#include "Utils.hpp" #include "Utils.hpp"
#include "PrintConfig.hpp"
namespace Slic3r 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::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( extern std::vector<coordf_t> layer_height_profile_from_ranges(
const SlicingParameters &slicing_params, 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( extern std::vector<coordf_t> layer_height_profile_adaptive(
const SlicingParameters &slicing_params, const SlicingParameters &slicing_params,
const t_layer_height_ranges &layer_height_ranges, const t_layer_config_ranges &layer_config_ranges,
const ModelVolumePtrs &volumes); const ModelVolumePtrs &volumes);

View file

@ -829,7 +829,7 @@ namespace SupportMaterialInternal {
assert(expansion_scaled >= 0.f); assert(expansion_scaled >= 0.f);
for (const ExtrusionPath &ep : loop.paths) for (const ExtrusionPath &ep : loop.paths)
if (ep.role() == erOverhangPerimeter && ! ep.polyline.empty()) { 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.is_closed()) {
if (ep.size() >= 3) { if (ep.size() >= 3) {
// This is a complete loop. // 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. // Expand the bases of the support columns in the 1st layer.
columns_base->polygons = diff( columns_base->polygons = diff(
offset(columns_base->polygons, inflate_factor_1st_layer), 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) if (contacts != nullptr)
columns_base->polygons = diff(columns_base->polygons, interface_polygons); columns_base->polygons = diff(columns_base->polygons, interface_polygons);
} }
@ -3226,7 +3226,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// TODO: use brim ordering algorithm // TODO: use brim ordering algorithm
Polygons to_infill_polygons = to_polygons(to_infill); Polygons to_infill_polygons = to_polygons(to_infill);
// TODO: use offset2_ex() // 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( extrusion_entities_append_paths(
base_layer.extrusions, base_layer.extrusions,
to_polylines(std::move(to_infill_polygons)), to_polylines(std::move(to_infill_polygons)),

View file

@ -15,6 +15,8 @@
#define ENABLE_RENDER_STATISTICS 0 #define ENABLE_RENDER_STATISTICS 0
// Shows an imgui dialog with camera related data // Shows an imgui dialog with camera related data
#define ENABLE_CAMERA_STATISTICS 0 #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
//==================== //====================

View file

@ -547,9 +547,9 @@ TriangleMesh TriangleMesh::convex_hull_3d() const
#if REALfloat #if REALfloat
qhull.runQhull("", 3, (int)this->its.vertices.size(), (const realT*)(this->its.vertices.front().data()), "Qt"); qhull.runQhull("", 3, (int)this->its.vertices.size(), (const realT*)(this->its.vertices.front().data()), "Qt");
#else #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: // 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) for (int i = 0; i < 3; ++ i)
src_vertices.emplace_back(v(i)); src_vertices.emplace_back(v(i));
qhull.runQhull("", 3, (int)src_vertices.size() / 3, src_vertices.data(), "Qt"); qhull.runQhull("", 3, (int)src_vertices.size() / 3, src_vertices.data(), "Qt");

View file

@ -167,7 +167,7 @@ template<class T> size_t next_highest_power_of_2(T v,
extern std::string xml_escape(std::string text); 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 // 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 // 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" #warning "GCC version < 5, faking std::is_trivially_copyable"

View file

@ -61,20 +61,6 @@ typedef double coordf_t;
#define SLIC3R_NOEXCEPT noexcept #define SLIC3R_NOEXCEPT noexcept
#endif #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, ...) inline std::string debug_out_path(const char *name, ...)
{ {
char buffer[2048]; char buffer[2048];

View file

@ -22,6 +22,10 @@
static const size_t MAX_SIZE = sizeof(char) * 255; static const size_t MAX_SIZE = sizeof(char) * 255;
static const int MAX_SAFE_INT = (unsigned int) -1 >> 1; static const int MAX_SAFE_INT = (unsigned int) -1 >> 1;
#ifdef _WIN32
#define strdup _strdup
#endif
/** /**
* Define comparison operators, storing the * Define comparison operators, storing the
* ASCII code per each symbol in hexadecimal notation. * 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((int)l < 0 || (int)l > MAX_SAFE_INT) return -1;
if (len < 0) len = l - begin + 1; if (len < 0) len = (int)l - begin + 1;
if (begin + len > (int)l) len = l - begin; if (begin + len > (int)l) len = (int)l - begin;
memmove(str + begin, str + begin + len, l - len + 1 - begin); memmove(str + begin, str + begin + len, l - len + 1 - begin);
return len; return len;
@ -104,7 +108,7 @@ parse_int (const char *s) {
static char * static char *
parse_slice (char *buf, char sep) { parse_slice (char *buf, char sep) {
char *pr, *part; char *pr, *part;
int plen; size_t plen;
/* Find separator in buf */ /* Find separator in buf */
pr = strchr(buf, sep); pr = strchr(buf, sep);
@ -210,8 +214,9 @@ semver_parse_version (const char *str, semver_t *ver) {
static int static int
compare_prerelease (char *x, char *y) { compare_prerelease (char *x, char *y) {
char *lastx, *lasty, *xptr, *yptr, *endptr; char *lastx, *lasty, *xptr, *yptr, *endptr;
int xlen, ylen, xisnum, yisnum, xnum, ynum; size_t xlen, ylen, xn, yn, min;
int xn, yn, min, res; int xisnum, yisnum, xnum, ynum;
int res;
if (x == NULL && y == NULL) return 0; if (x == NULL && y == NULL) return 0;
if (y == NULL && x) return -1; if (y == NULL && x) return -1;
if (x == NULL && y) return 1; if (x == NULL && y) return 1;
@ -572,7 +577,7 @@ semver_clean (char *s) {
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (contains(s[i], VALID_CHARS, mlen) == 0) { if (contains(s[i], VALID_CHARS, mlen) == 0) {
res = strcut(s, i, 1); res = strcut(s, (int)i, 1);
if(res == -1) return -1; if(res == -1) return -1;
--len; --i; --len; --i;
} }

View file

@ -81,6 +81,8 @@ set(SLIC3R_GUI_SOURCES
GUI/GUI_ObjectManipulation.hpp GUI/GUI_ObjectManipulation.hpp
GUI/GUI_ObjectSettings.cpp GUI/GUI_ObjectSettings.cpp
GUI/GUI_ObjectSettings.hpp GUI/GUI_ObjectSettings.hpp
GUI/GUI_ObjectLayers.cpp
GUI/GUI_ObjectLayers.hpp
GUI/LambdaObjectDialog.cpp GUI/LambdaObjectDialog.cpp
GUI/LambdaObjectDialog.hpp GUI/LambdaObjectDialog.hpp
GUI/Tab.cpp GUI/Tab.cpp

View file

@ -628,12 +628,12 @@ void Bed3D::render_prusa_shader(bool transparent) const
if (position_id != -1) if (position_id != -1)
{ {
glsafe(::glEnableVertexAttribArray(position_id)); 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) if (tex_coords_id != -1)
{ {
glsafe(::glEnableVertexAttribArray(tex_coords_id)); 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())); glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_triangles.get_vertices_count()));

View file

@ -44,8 +44,8 @@ public:
const float* get_vertices_data() const; 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_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_vertex_data_size() const { return (unsigned int)(5 * sizeof(float)); }
unsigned int get_position_offset() const { return 0; } size_t get_position_offset() const { return 0; }
unsigned int get_tex_coords_offset() const { return (unsigned int)(3 * sizeof(float)); } 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(); } unsigned int get_vertices_count() const { return (unsigned int)m_vertices.size(); }
#else #else
const float* get_vertices() const { return m_vertices.data(); } const float* get_vertices() const { return m_vertices.data(); }

View file

@ -54,10 +54,9 @@ void AppConfig::set_defaults()
if (get("preset_update").empty()) if (get("preset_update").empty())
set("preset_update", "1"); 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. // remove old 'use_legacy_opengl' parameter from this config, if present
// github.com/prusa3d/PrusaSlicer/issues/233 if (!get("use_legacy_opengl").empty())
if (get("use_legacy_opengl").empty()) erase("", "use_legacy_opengl");
set("use_legacy_opengl", "0");
#if __APPLE__ #if __APPLE__
if (get("use_retina_opengl").empty()) if (get("use_retina_opengl").empty())

View file

@ -53,10 +53,7 @@ void BedShapeDialog::on_dpi_changed(const wxRect &suggested_rect)
void BedShapePanel::build_panel(ConfigOptionPoints* default_pt) void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
{ {
// on_change(nullptr); auto sbsizer = new wxStaticBoxSizer(wxVERTICAL, this, _(L("Shape")));
auto box = new wxStaticBox(this, wxID_ANY, _(L("Shape")));
auto sbsizer = new wxStaticBoxSizer(box, wxVERTICAL);
// shape options // shape options
m_shape_options_book = new wxChoicebook(this, wxID_ANY, wxDefaultPosition, m_shape_options_book = new wxChoicebook(this, wxID_ANY, wxDefaultPosition,
@ -92,12 +89,14 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
Line line{ "", "" }; Line line{ "", "" };
line.full_width = 1; line.full_width = 1;
line.widget = [this](wxWindow* parent) { line.widget = [this](wxWindow* parent) {
auto btn = new wxButton(parent, wxID_ANY, _(L("Load shape from STL...")), wxDefaultPosition, wxDefaultSize); 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);
auto sizer = new wxBoxSizer(wxHORIZONTAL); wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(btn); sizer->Add(shape_sizer, 1, wxEXPAND);
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) shape_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
{ {
load_stl(); load_stl();
})); }));
@ -106,7 +105,7 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
}; };
optgroup->append_line(line); optgroup->append_line(line);
Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent e) Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent& e)
{ {
update_shape(); update_shape();
})); }));
@ -117,7 +116,7 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
// main sizer // main sizer
auto top_sizer = new wxBoxSizer(wxHORIZONTAL); auto top_sizer = new wxBoxSizer(wxHORIZONTAL);
top_sizer->Add(sbsizer, 0, wxEXPAND | wxLeft | wxTOP | wxBOTTOM, 10); top_sizer->Add(sbsizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 10);
if (m_canvas) if (m_canvas)
top_sizer->Add(m_canvas, 1, wxEXPAND | wxALL, 10) ; top_sizer->Add(m_canvas, 1, wxEXPAND | wxALL, 10) ;
@ -135,7 +134,6 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
// Create a panel for a rectangular / circular / custom bed shape. // Create a panel for a rectangular / circular / custom bed shape.
ConfigOptionsGroupShp BedShapePanel::init_shape_options_page(const wxString& title) 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; ConfigOptionsGroupShp optgroup;
optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Settings"))); optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Settings")));
@ -234,7 +232,7 @@ void BedShapePanel::set_shape(ConfigOptionPoints* points)
// This is a custom bed shape, use the polygon provided. // This is a custom bed shape, use the polygon provided.
m_shape_options_book->SetSelection(SHAPE_CUSTOM); m_shape_options_book->SetSelection(SHAPE_CUSTOM);
// Copy the polygon to the canvas, make a copy of the array. // Copy the polygon to the canvas, make a copy of the array.
m_canvas->m_bed_shape = points->values; m_loaded_bed_shape = points->values;
update_shape(); update_shape();
} }

View file

@ -171,7 +171,7 @@ void BonjourDialog::on_reply(BonjourReplyEvent &e)
// Filter replies based on selected technology // Filter replies based on selected technology
const auto model = e.reply.txt_data.find("model"); const auto model = e.reply.txt_data.find("model");
const bool sl1 = model != e.reply.txt_data.end() && model->second == "SL1"; 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; return;
} }

View file

@ -24,7 +24,7 @@ namespace GUI {
const double Camera::DefaultDistance = 1000.0; const double Camera::DefaultDistance = 1000.0;
double Camera::FrustrumMinZSize = 50.0; double Camera::FrustrumMinZSize = 50.0;
double Camera::FrustrumZMargin = 10.0; double Camera::FrustrumZMargin = 10.0;
double Camera::FovMinDeg = 5.0; double Camera::FovMinDeg = 0.5;
double Camera::FovMaxDeg = 75.0; double Camera::FovMaxDeg = 75.0;
Camera::Camera() Camera::Camera()

View file

@ -330,8 +330,8 @@ PagePrinters::PagePrinters(ConfigWizard *parent, wxString title, wxString shortn
const auto families = vendor.families(); const auto families = vendor.families();
for (const auto &family : families) { for (const auto &family : families) {
const auto filter = [&](const VendorProfile::PrinterModel &model) { const auto filter = [&](const VendorProfile::PrinterModel &model) {
return (model.technology == ptFFF && technology & T_FFF return ((model.technology == ptFFF && technology & T_FFF)
|| model.technology == ptSLA && technology & T_SLA) || (model.technology == ptSLA && technology & T_SLA))
&& model.family == family; && model.family == family;
}; };
@ -810,7 +810,7 @@ void ConfigWizardIndex::on_paint(wxPaintEvent & evt)
const Item& item = items[i]; const Item& item = items[i];
unsigned x = em_w/2 + item.indent * em_w; 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); 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); } else if (i < item_active) { dc.DrawBitmap(bullet_black.bmp(), x, y + yoff_icon, false); }

View file

@ -113,11 +113,19 @@ wxString Field::get_tooltip_text(const wxString& default_string)
wxString tooltip_text(""); wxString tooltip_text("");
wxString tooltip = _(m_opt.tooltip); wxString tooltip = _(m_opt.tooltip);
edit_tooltip(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) if (tooltip.length() > 0)
tooltip_text = tooltip + "\n" + _(L("default value")) + "\t: " + tooltip_text = tooltip + "\n" + _(L("default value")) + "\t: " +
(boost::iends_with(m_opt_id, "_gcode") ? "\n" : "") + default_string + (boost::iends_with(opt_id, "_gcode") ? "\n" : "") + default_string +
(boost::iends_with(m_opt_id, "_gcode") ? "" : "\n") + (boost::iends_with(opt_id, "_gcode") ? "" : "\n") +
_(L("parameter name")) + "\t: " + m_opt_id; _(L("parameter name")) + "\t: " + opt_id;
return tooltip_text; return tooltip_text;
} }

View file

@ -442,8 +442,7 @@ void FirmwareDialog::priv::avr109_lookup_port(Avr109Pid usb_pid)
auto ports = Utils::scan_serial_ports_extended(); auto ports = Utils::scan_serial_ports_extended();
ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) { ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) {
return port.id_vendor != USB_VID_PRUSA || return port.id_vendor != USB_VID_PRUSA ||
port.id_product != usb_pid.boot && (port.id_product != usb_pid.boot && port.id_product != usb_pid.app);
port.id_product != usb_pid.app;
}), ports.end()); }), ports.end());
if (ports.size() == 0) { if (ports.size() == 0) {

View file

@ -198,8 +198,7 @@ void GLCanvas3D::Shader::_reset()
#endif // !ENABLE_TEXTURES_FROM_SVG #endif // !ENABLE_TEXTURES_FROM_SVG
GLCanvas3D::LayersEditing::LayersEditing() GLCanvas3D::LayersEditing::LayersEditing()
: m_use_legacy_opengl(false) : m_enabled(false)
, m_enabled(false)
, m_z_texture_id(0) , m_z_texture_id(0)
, m_model_object(nullptr) , m_model_object(nullptr)
, m_object_max_z(0.f) , 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 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; return 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;
} }
bool GLCanvas3D::LayersEditing::is_enabled() const 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. //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. // 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_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 scale_y = bar_rect.get_height() / m_object_max_z;
float x = bar_rect.get_left() + (float)m_slicing_parameters->layer_height * scale_x; 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, void GLCanvas3D::LegendTexture::fill_color_print_legend_values(const GCodePreviewData& preview_data, const GLCanvas3D& canvas,
std::vector<std::pair<double, double>>& cp_legend_values) 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; auto& config = wxGetApp().preset_bundle->project_config;
const std::vector<double>& color_print_values = config.option<ConfigOptionFloats>("colorprint_heights")->values; 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_cursor_type(Standard)
, m_color_by("volume") , m_color_by("volume")
, m_reload_delayed(false) , m_reload_delayed(false)
#if ENABLE_RENDER_PICKING_PASS
, m_show_picking_texture(false)
#endif // ENABLE_RENDER_PICKING_PASS
, m_render_sla_auxiliaries(true) , m_render_sla_auxiliaries(true)
{ {
if (m_canvas != nullptr) { if (m_canvas != nullptr) {
@ -1255,7 +1255,7 @@ void GLCanvas3D::post_event(wxEvent &&event)
wxPostEvent(m_canvas, event); wxPostEvent(m_canvas, event);
} }
bool GLCanvas3D::init(bool useVBOs, bool use_legacy_opengl) bool GLCanvas3D::init(bool useVBOs)
{ {
if (m_initialized) if (m_initialized)
return true; return true;
@ -1313,7 +1313,6 @@ bool GLCanvas3D::init(bool useVBOs, bool use_legacy_opengl)
return false; return false;
m_use_VBOs = useVBOs; 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 // 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() // we defer the geometry finalization of volumes until the first call to render()
@ -1634,6 +1633,10 @@ void GLCanvas3D::render()
_picking_pass(); _picking_pass();
} }
#if ENABLE_RENDER_PICKING_PASS
if (!m_picking_enabled || !m_show_picking_texture)
{
#endif // ENABLE_RENDER_PICKING_PASS
// draw scene // draw scene
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
_render_background(); _render_background();
@ -1663,6 +1666,9 @@ void GLCanvas3D::render()
_render_current_gizmo(); _render_current_gizmo();
_render_selection_sidebar_hints(); _render_selection_sidebar_hints();
#if ENABLE_RENDER_PICKING_PASS
}
#endif // ENABLE_RENDER_PICKING_PASS
#if ENABLE_SHOW_CAMERA_TARGET #if ENABLE_SHOW_CAMERA_TARGET
_render_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 'k': { m_camera.select_next_type(); m_dirty = true; break; }
case 'O': case 'O':
case 'o': { set_camera_zoom(-1.0); break; } 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':
case 'z': { m_selection.is_empty() ? zoom_to_volumes() : zoom_to_selection(); break; } case 'z': { m_selection.is_empty() ? zoom_to_volumes() : zoom_to_selection(); break; }
default: { evt.Skip(); 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() void GLCanvas3D::update_ui_from_settings()
{ {
m_camera.set_type(wxGetApp().app_config->get("use_perspective_camera")); 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 void GLCanvas3D::_render_selection_sidebar_hints() const
{ {
if (m_use_VBOs) m_selection.render_sidebar_hints(m_sidebar_field, m_shader);
m_shader.start_using();
m_selection.render_sidebar_hints(m_sidebar_field);
if (m_use_VBOs)
m_shader.stop_using();
} }

View file

@ -12,6 +12,7 @@
#include "Camera.hpp" #include "Camera.hpp"
#include "Selection.hpp" #include "Selection.hpp"
#include "Gizmos/GLGizmosManager.hpp" #include "Gizmos/GLGizmosManager.hpp"
#include "GUI_ObjectLayers.hpp"
#include <float.h> #include <float.h>
@ -199,7 +200,6 @@ class GLCanvas3D
static const float THICKNESS_BAR_WIDTH; static const float THICKNESS_BAR_WIDTH;
static const float THICKNESS_RESET_BUTTON_HEIGHT; static const float THICKNESS_RESET_BUTTON_HEIGHT;
bool m_use_legacy_opengl;
bool m_enabled; bool m_enabled;
Shader m_shader; Shader m_shader;
unsigned int m_z_texture_id; unsigned int m_z_texture_id;
@ -252,7 +252,6 @@ class GLCanvas3D
void select_object(const Model &model, int object_id); void select_object(const Model &model, int object_id);
bool is_allowed() const; bool is_allowed() const;
void set_use_legacy_opengl(bool use_legacy_opengl);
bool is_enabled() const; bool is_enabled() const;
void set_enabled(bool enabled); void set_enabled(bool enabled);
@ -481,6 +480,10 @@ private:
GCodePreviewVolumeIndex m_gcode_preview_volume_index; 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 #if ENABLE_RENDER_STATISTICS
RenderStats m_render_stats; RenderStats m_render_stats;
#endif // ENABLE_RENDER_STATISTICS #endif // ENABLE_RENDER_STATISTICS
@ -494,7 +497,7 @@ public:
wxGLCanvas* get_wxglcanvas() { return m_canvas; } wxGLCanvas* get_wxglcanvas() { return m_canvas; }
const wxGLCanvas* get_wxglcanvas() const { 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 post_event(wxEvent &&event);
void set_as_dirty(); void set_as_dirty();
@ -608,6 +611,7 @@ public:
void reset_all_gizmos() { m_gizmos.reset_all_states(); } void reset_all_gizmos() { m_gizmos.reset_all_states(); }
void handle_sidebar_focus_event(const std::string& opt_key, bool focus_on); 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(); void update_ui_from_settings();

View file

@ -192,7 +192,6 @@ GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info;
GLCanvas3DManager::GLCanvas3DManager() GLCanvas3DManager::GLCanvas3DManager()
: m_context(nullptr) : m_context(nullptr)
, m_gl_initialized(false) , m_gl_initialized(false)
, m_use_legacy_opengl(false)
, m_use_VBOs(false) , m_use_VBOs(false)
{ {
} }
@ -268,8 +267,7 @@ void GLCanvas3DManager::init_gl()
{ {
glewInit(); glewInit();
const AppConfig* config = GUI::get_app_config(); const AppConfig* config = GUI::get_app_config();
m_use_legacy_opengl = (config == nullptr) || (config->get("use_legacy_opengl") == "1"); m_use_VBOs = s_gl_info.is_version_greater_or_equal_to(2, 0);
m_use_VBOs = !m_use_legacy_opengl && s_gl_info.is_version_greater_or_equal_to(2, 0);
m_gl_initialized = true; m_gl_initialized = true;
if (GLEW_EXT_texture_compression_s3tc) if (GLEW_EXT_texture_compression_s3tc)
s_compressed_textures_supported = true; s_compressed_textures_supported = true;
@ -325,16 +323,14 @@ bool GLCanvas3DManager::init(GLCanvas3D& canvas)
if (!m_gl_initialized) if (!m_gl_initialized)
init_gl(); init_gl();
return canvas.init(m_use_VBOs, m_use_legacy_opengl); return canvas.init(m_use_VBOs);
} }
void GLCanvas3DManager::detect_multisample(int* attribList) void GLCanvas3DManager::detect_multisample(int* attribList)
{ {
int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER; int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER;
const AppConfig* app_config = GUI::get_app_config(); const AppConfig* app_config = GUI::get_app_config();
bool enable_multisample = app_config != nullptr bool enable_multisample = wxVersion >= 30003;
&& app_config->get("use_legacy_opengl") != "1"
&& wxVersion >= 30003;
s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? MS_Enabled : MS_Disabled; 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 // Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows

View file

@ -75,7 +75,6 @@ private:
wxGLContext* m_context; wxGLContext* m_context;
static GLInfo s_gl_info; static GLInfo s_gl_info;
bool m_gl_initialized; bool m_gl_initialized;
bool m_use_legacy_opengl;
bool m_use_VBOs; bool m_use_VBOs;
static EMultisampleState s_multisample; static EMultisampleState s_multisample;
static bool s_compressed_textures_supported; static bool s_compressed_textures_supported;

View file

@ -68,7 +68,8 @@ namespace GUI {
if (!is_dragging()) if (!is_dragging())
return; 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; float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
Size cnv_size = canvas.get_canvas_size(); Size cnv_size = canvas.get_canvas_size();
@ -96,6 +97,11 @@ namespace GUI {
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glLoadIdentity()); 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(::glPushAttrib(GL_ENABLE_BIT));
glsafe(::glLineStipple(4, 0xAAAA)); glsafe(::glLineStipple(4, 0xAAAA));

View file

@ -141,6 +141,18 @@ GUI_App::GUI_App()
, m_imgui(new ImGuiWrapper()) , 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() bool GUI_App::OnInit()
{ {
try { try {
@ -922,6 +934,11 @@ ObjectList* GUI_App::obj_list()
return sidebar().obj_list(); return sidebar().obj_list();
} }
ObjectLayers* GUI_App::obj_layers()
{
return sidebar().obj_layers();
}
Plater* GUI_App::plater() Plater* GUI_App::plater()
{ {
return plater_; return plater_;

View file

@ -95,6 +95,7 @@ public:
bool initialized() const { return m_initialized; } bool initialized() const { return m_initialized; }
GUI_App(); GUI_App();
~GUI_App();
static unsigned get_colour_approx_luma(const wxColour &colour); static unsigned get_colour_approx_luma(const wxColour &colour);
static bool dark_mode(); static bool dark_mode();
@ -155,6 +156,7 @@ public:
ObjectManipulation* obj_manipul(); ObjectManipulation* obj_manipul();
ObjectSettings* obj_settings(); ObjectSettings* obj_settings();
ObjectList* obj_list(); ObjectList* obj_list();
ObjectLayers* obj_layers();
Plater* plater(); Plater* plater();
std::vector<ModelObject*> *model_objects(); std::vector<ModelObject*> *model_objects();

View file

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

View file

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

View file

@ -1,6 +1,7 @@
#include "libslic3r/libslic3r.h" #include "libslic3r/libslic3r.h"
#include "GUI_ObjectList.hpp" #include "GUI_ObjectList.hpp"
#include "GUI_ObjectManipulation.hpp" #include "GUI_ObjectManipulation.hpp"
#include "GUI_ObjectLayers.hpp"
#include "GUI_App.hpp" #include "GUI_App.hpp"
#include "I18N.hpp" #include "I18N.hpp"
@ -152,8 +153,8 @@ ObjectList::ObjectList(wxWindow* parent) :
wxAcceleratorTable accel(6, entries); wxAcceleratorTable accel(6, entries);
SetAcceleratorTable(accel); 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) { this->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->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->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->remove(); }, wxID_DELETE);
} }
@ -361,6 +362,7 @@ DynamicPrintConfig& ObjectList::get_item_config(const wxDataViewItem& item) cons
assert(obj_idx >= 0 || ((type & itVolume) && vol_idx >=0)); assert(obj_idx >= 0 || ((type & itVolume) && vol_idx >=0));
return type & itVolume ?(*m_objects)[obj_idx]->volumes[vol_idx]->config : 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; (*m_objects)[obj_idx]->config;
} }
@ -446,17 +448,24 @@ void ObjectList::update_extruder_in_config(const wxDataViewItem& item)
{ {
if (m_prevent_update_extruder_in_config) if (m_prevent_update_extruder_in_config)
return; 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); const int obj_idx = m_objects_model->GetIdByItem(item);
m_config = &(*m_objects)[obj_idx]->config; m_config = &(*m_objects)[obj_idx]->config;
} }
else { 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); const int volume_id = m_objects_model->GetVolumeIdByItem(item);
if (obj_idx < 0 || volume_id < 0) if (obj_idx < 0 || volume_id < 0)
return; return;
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config; m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
} }
else if (item_type & itLayer)
m_config = &get_item_config(item);
}
wxVariant variant; wxVariant variant;
m_objects_model->GetValue(variant, item, 1); m_objects_model->GetValue(variant, item, 1);
@ -465,7 +474,7 @@ void ObjectList::update_extruder_in_config(const wxDataViewItem& item)
if (!m_config || selection.empty()) if (!m_config || selection.empty())
return; 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)); m_config->set_key_value("extruder", new ConfigOptionInt(extruder));
// update scene // update scene
@ -574,9 +583,75 @@ void ObjectList::selection_changed()
wxPostEvent(this, event); 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(); 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) void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes)
{ {
if ((obj_idx < 0) || ((int)m_objects->size() <= obj_idx)) 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(); const wxPoint pt = get_mouse_position_in_control();
HitTest(pt, item, col); HitTest(pt, item, col);
if (!item) 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 // after Yosemite OS X version, HitTest return undefined item
item = GetSelection(); item = GetSelection();
if (item) if (item)
@ -703,10 +778,11 @@ void ObjectList::show_context_menu()
if (item) if (item)
{ {
const ItemType type = m_objects_model->GetItemType(item); const ItemType type = m_objects_model->GetItemType(item);
if (!(type & (itObject | itVolume | itInstance))) if (!(type & (itObject | itVolume | itLayer | itInstance)))
return; return;
wxMenu* menu = type & itInstance ? &m_menu_instance : wxMenu* menu = type & itInstance ? &m_menu_instance :
type & itLayer ? &m_menu_layer :
m_objects_model->GetParent(item) != wxDataViewItem(0) ? &m_menu_part : m_objects_model->GetParent(item) != wxDataViewItem(0) ? &m_menu_part :
printer_technology() == ptFFF ? &m_menu_object : &m_menu_sla_object; 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__ #ifndef __WXOSX__
void ObjectList::key_event(wxKeyEvent& event) void ObjectList::key_event(wxKeyEvent& event)
{ {
@ -732,9 +824,9 @@ void ObjectList::key_event(wxKeyEvent& event)
else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/)) else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/))
select_item_all_children(); select_item_all_children();
else if (wxGetKeyState(wxKeyCode('C')) && wxGetKeyState(WXK_CONTROL)) else if (wxGetKeyState(wxKeyCode('C')) && wxGetKeyState(WXK_CONTROL))
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY)); copy();
else if (wxGetKeyState(wxKeyCode('V')) && wxGetKeyState(WXK_CONTROL)) else if (wxGetKeyState(wxKeyCode('V')) && wxGetKeyState(WXK_CONTROL))
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE)); paste();
else else
event.Skip(); 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) 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); assert(m_config);
auto opt_keys = m_config->keys(); auto opt_keys = m_config->keys();
@ -1144,6 +1246,12 @@ wxMenuItem* ObjectList::append_menu_item_split(wxMenu* menu)
[this]() { return is_splittable(); }, wxGetApp().plater()); [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_) wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
{ {
MenuWithSeparators* menu = dynamic_cast<MenuWithSeparators*>(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); append_menu_item_scale_selection_to_fit_print_volume(menu);
// Split object to parts // 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(); menu->AppendSeparator();
// rest of a object_menu will be added later in: // 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_fix_through_netfabb(menu);
append_menu_item_export_stl(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 // Append change part type
menu->AppendSeparator(); menu->AppendSeparator();
@ -1587,38 +1699,52 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
ItemType type; ItemType type;
m_objects_model->GetItemInfo(item, type, obj_idx, idx); m_objects_model->GetItemInfo(item, type, obj_idx, idx);
if (type == itUndef) if (type & itUndef)
return; return;
if (type == itSettings) if (type & itSettings)
del_settings_from_config(); del_settings_from_config(m_objects_model->GetParent(item));
else if (type == itInstanceRoot && obj_idx != -1) else if (type & itInstanceRoot && obj_idx != -1)
del_instances_from_object(obj_idx); 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) else if (idx == -1)
return; return;
else if (!del_subobject_from_object(obj_idx, idx, type)) else if (!del_subobject_from_object(obj_idx, idx, type))
return; return;
// If last volume item with warning was deleted, unmark object item // 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->DeleteWarningIcon(m_objects_model->GetParent(item));
m_objects_model->Delete(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(); const bool is_layer_settings = m_objects_model->GetItemType(parent_item) == itLayer;
if (opt_keys.size() == 1 && opt_keys[0] == "extruder")
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; return;
int extruder = -1; int extruder = -1;
if (m_config->has("extruder")) if (m_config->has("extruder"))
extruder = m_config->option<ConfigOptionInt>("extruder")->value; 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(); m_config->clear();
if (extruder >= 0) if (extruder >= 0)
m_config->set_key_value("extruder", new ConfigOptionInt(extruder)); 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) 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); 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) bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, const int type)
{ {
if (obj_idx == 1000) if (obj_idx == 1000)
@ -1738,6 +1882,70 @@ void ObjectList::split()
changed_object(obj_idx); 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) bool ObjectList::get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume)
{ {
auto obj_idx = get_selected_obj_idx(); 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_manipulations = false;
bool update_and_show_settings = false; bool update_and_show_settings = false;
bool update_and_show_layers = false;
const auto item = GetSelection(); const auto item = GetSelection();
@ -1829,36 +2038,47 @@ void ObjectList::part_selection_changed()
update_and_show_manipulations = true; update_and_show_manipulations = true;
} }
else { else {
auto parent = m_objects_model->GetParent(item); obj_idx = m_objects_model->GetObjectIdByItem(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); const ItemType type = m_objects_model->GetItemType(item);
if (m_objects_model->GetItemType(item) == itSettings) { if (type & itSettings) {
if (m_objects_model->GetParent(parent) == wxDataViewItem(0)) { 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")); og_name = _(L("Object Settings to modify"));
m_config = &(*m_objects)[obj_idx]->config; m_config = &(*m_objects)[obj_idx]->config;
} }
else { else if (parent_type & itVolume) {
og_name = _(L("Part Settings to modify")); og_name = _(L("Part Settings to modify"));
auto main_parent = m_objects_model->GetParent(parent); volume_id = m_objects_model->GetVolumeIdByItem(parent);
obj_idx = m_objects_model->GetIdByItem(main_parent);
const auto volume_id = m_objects_model->GetVolumeIdByItem(parent);
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config; 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; update_and_show_settings = true;
} }
else if (m_objects_model->GetItemType(item) == itVolume) { else if (type & itVolume) {
og_name = _(L("Part manipulation")); og_name = _(L("Part manipulation"));
volume_id = m_objects_model->GetVolumeIdByItem(item); volume_id = m_objects_model->GetVolumeIdByItem(item);
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config; m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
update_and_show_manipulations = true; update_and_show_manipulations = true;
} }
else if (m_objects_model->GetItemType(item) == itInstance) { else if (type & itInstance) {
og_name = _(L("Instance manipulation")); og_name = _(L("Instance manipulation"));
update_and_show_manipulations = true; update_and_show_manipulations = true;
// fill m_config by object's values // 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) if (update_and_show_settings)
wxGetApp().obj_settings()->get_og()->set_name(" " + og_name + " "); 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(); Sidebar& panel = wxGetApp().sidebar();
panel.Freeze(); panel.Freeze();
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false);
wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations); wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations);
wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings); wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings);
wxGetApp().obj_layers() ->UpdateAndShow(update_and_show_layers);
wxGetApp().sidebar().show_info_sizer(); wxGetApp().sidebar().show_info_sizer();
panel.Layout(); panel.Layout();
@ -1928,6 +2155,9 @@ void ObjectList::add_object_to_list(size_t obj_idx)
Expand(item); Expand(item);
} }
// Add layers if it has
add_layer_root_item(item);
#ifndef __WXOSX__ #ifndef __WXOSX__
selection_changed(); selection_changed();
#endif //__WXMSW__ #endif //__WXMSW__
@ -2074,16 +2304,196 @@ void ObjectList::remove()
wxDataViewItemArray sels; wxDataViewItemArray sels;
GetSelections(sels); GetSelections(sels);
wxDataViewItem parent = wxDataViewItem(0);
for (auto& item : sels) for (auto& item : sels)
{ {
if (m_objects_model->GetParent(item) == wxDataViewItem(0)) if (m_objects_model->GetParent(item) == wxDataViewItem(0))
delete_from_model_and_list(itObject, m_objects_model->GetIdByItem(item), -1); delete_from_model_and_list(itObject, m_objects_model->GetIdByItem(item), -1);
else { 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)); select_item(m_objects_model->GetParent(item));
del_subobject_item(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() void ObjectList::init_objects()
@ -2113,11 +2523,12 @@ void ObjectList::update_selections()
m_selection_mode = smInstance; m_selection_mode = smInstance;
// We doesn't update selection if SettingsItem for the current object/part is selected // 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(); const auto item = GetSelection();
if (selection.is_single_full_object()) { 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; return;
sels.Add(m_objects_model->GetItemById(selection.get_object_idx())); 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) 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); const ItemType& type = m_objects_model->GetItemType(item);
if ( type == itInstanceRoot || m_objects_model->GetParent(item) == wxDataViewItem(0) ) { const int obj_idx = m_objects_model->GetObjectIdByItem(item);
wxDataViewItem obj_item = type == itInstanceRoot ? m_objects_model->GetParent(item) : item;
selection.add_object(m_objects_model->GetIdByItem(obj_item), as_single_selection);
return;
}
if (type == itVolume) { 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); const int vol_idx = m_objects_model->GetVolumeIdByItem(item);
selection.add_volume(obj_idx, vol_idx, std::max(instance_idx, 0), as_single_selection); selection.add_volume(obj_idx, vol_idx, std::max(instance_idx, 0), as_single_selection);
} }
else if (type == itInstance) { 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); const int inst_idx = m_objects_model->GetInstanceIdByItem(item);
selection.add_instance(obj_idx, inst_idx, as_single_selection); 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 // stores current instance idx before to clear the selection
@ -2261,7 +2668,7 @@ void ObjectList::update_selections_on_canvas()
if (sel_cnt == 1) { if (sel_cnt == 1) {
wxDataViewItem item = GetSelection(); 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); add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, true);
else else
add_to_selection(item, selection, instance_idx, true); add_to_selection(item, selection, instance_idx, true);
@ -2324,11 +2731,13 @@ void ObjectList::select_item_all_children()
} }
else { else {
const auto item = GetSelection(); const auto item = GetSelection();
// Some volume(instance) is selected => select all volumes(instances) inside the current object const ItemType item_type = m_objects_model->GetItemType(item);
if (m_objects_model->GetItemType(item) & (itVolume | itInstance)) // 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_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); SetSelections(sels);
@ -2347,8 +2756,9 @@ void ObjectList::update_selection_mode()
} }
const ItemType type = m_objects_model->GetItemType(GetSelection()); const ItemType type = m_objects_model->GetItemType(GetSelection());
m_selection_mode = type&itSettings ? smUndef : m_selection_mode = type & itSettings ? smUndef :
type&itVolume ? smVolume : smInstance; type & itLayer ? smLayer :
type & itVolume ? smVolume : smInstance;
} }
// check last selected item. If is it possible to select it // 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); 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 * So, show information about it
*/ */
const ItemType type = m_objects_model->GetItemType(m_last_selected_item); const ItemType type = m_objects_model->GetItemType(m_last_selected_item);
// check a case of a selection of the Parts from different Objects // check a case of a selection of the same type items from different Objects
bool impossible_multipart_selection = false; auto impossible_multi_selection = [type, this](const ItemType item_type, const SELECTION_MODE selection_mode) {
if (type & itVolume && m_selection_mode == smVolume) if (!(type & item_type && m_selection_mode & selection_mode))
{ return false;
wxDataViewItemArray sels; wxDataViewItemArray sels;
GetSelections(sels); GetSelections(sels);
for (const auto& sel: sels) for (const auto& sel : sels)
if (sel != m_last_selected_item && if (sel != m_last_selected_item &&
m_objects_model->GetParent(sel) != m_objects_model->GetParent(m_last_selected_item)) m_objects_model->GetTopParent(sel) != m_objects_model->GetTopParent(m_last_selected_item))
{ return true;
impossible_multipart_selection = true;
break;
}
}
if (impossible_multipart_selection || return false;
};
if (impossible_multi_selection(itVolume, smVolume) ||
impossible_multi_selection(itLayer, smLayer ) ||
type & itSettings || 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 // 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" + msg_str = wxString::Format( _(L("Unsupported selection")) + "\n\n" +
_(L("You started your selection with %s Item.")) + "\n" + _(L("You started your selection with %s Item.")) + "\n" +
@ -2422,7 +2836,7 @@ void ObjectList::fix_multiselection_conflicts()
wxDataViewItemArray sels; wxDataViewItemArray sels;
GetSelections(sels); GetSelections(sels);
if (m_selection_mode == smVolume) if (m_selection_mode & (smVolume|smLayer))
{ {
// identify correct parent of the initial selected item // 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()); 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 wxDataViewItemArray children; // selected volumes from current parent
m_objects_model->GetChildren(parent, children); m_objects_model->GetChildren(parent, children);
const ItemType item_type = m_selection_mode & smVolume ? itVolume : itLayer;
for (const auto child : children) 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); sels.Add(child);
// If some part is selected, unselect all items except of selected parts of the current object // 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; 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() void ObjectList::update_object_menu()
{ {
append_menu_items_add_volume(&m_menu_object); append_menu_items_add_volume(&m_menu_object);
@ -2772,7 +3269,8 @@ void ObjectList::msw_rescale()
for (MenuWithSeparators* menu : { &m_menu_object, for (MenuWithSeparators* menu : { &m_menu_object,
&m_menu_part, &m_menu_part,
&m_menu_sla_object, &m_menu_sla_object,
&m_menu_instance }) &m_menu_instance,
&m_menu_layer })
msw_rescale_menu(menu); msw_rescale_menu(menu);
Layout(); Layout();

View file

@ -33,6 +33,10 @@ typedef std::map< std::string, std::vector< std::pair<std::string, std::string>
typedef std::vector<ModelVolume*> ModelVolumePtrs; 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 { namespace GUI {
wxDECLARE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent); wxDECLARE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent);
@ -64,9 +68,10 @@ class ObjectList : public wxDataViewCtrl
{ {
enum SELECTION_MODE enum SELECTION_MODE
{ {
smUndef, smUndef = 0,
smVolume, smVolume = 1,
smInstance smInstance = 2,
smLayer = 4
} m_selection_mode {smUndef}; } m_selection_mode {smUndef};
struct dragged_item_data struct dragged_item_data
@ -119,13 +124,18 @@ class ObjectList : public wxDataViewCtrl
MenuWithSeparators m_menu_part; MenuWithSeparators m_menu_part;
MenuWithSeparators m_menu_sla_object; MenuWithSeparators m_menu_sla_object;
MenuWithSeparators m_menu_instance; MenuWithSeparators m_menu_instance;
wxMenuItem* m_menu_item_split { nullptr }; MenuWithSeparators m_menu_layer;
wxMenuItem* m_menu_item_split_part { nullptr };
wxMenuItem* m_menu_item_settings { nullptr }; wxMenuItem* m_menu_item_settings { nullptr };
wxMenuItem* m_menu_item_split_instances { nullptr }; wxMenuItem* m_menu_item_split_instances { nullptr };
ObjectDataViewModel *m_objects_model{ nullptr };
DynamicPrintConfig *m_config {nullptr};
std::vector<ModelObject*> *m_objects{ nullptr };
std::vector<wxBitmap*> m_bmp_vector; std::vector<wxBitmap*> m_bmp_vector;
t_layer_config_ranges m_layer_config_ranges_cache;
int m_selected_object_id = -1; int m_selected_object_id = -1;
bool m_prevent_list_events = false; // We use this flag to avoid circular event handling Select() bool m_prevent_list_events = false; // We use this flag to avoid circular event handling Select()
// happens to fire a wxEVT_LIST_ITEM_SELECTED on OSX, whose event handler // happens to fire a wxEVT_LIST_ITEM_SELECTED on OSX, whose event handler
@ -153,11 +163,11 @@ public:
std::map<std::string, wxBitmap> CATEGORY_ICON; std::map<std::string, wxBitmap> CATEGORY_ICON;
ObjectDataViewModel *m_objects_model{ nullptr }; ObjectDataViewModel* GetModel() const { return m_objects_model; }
DynamicPrintConfig *m_config {nullptr}; DynamicPrintConfig* config() const { return m_config; }
std::vector<ModelObject*>* objects() const { return m_objects; }
std::vector<ModelObject*> *m_objects{ nullptr };
ModelObject* object(const int obj_idx) const ;
void create_objects_ctrl(); void create_objects_ctrl();
void create_popup_menus(); void create_popup_menus();
@ -192,6 +202,9 @@ public:
void key_event(wxKeyEvent& event); void key_event(wxKeyEvent& event);
#endif /* __WXOSX__ */ #endif /* __WXOSX__ */
void copy();
void paste();
void get_settings_choice(const wxString& category_name); void get_settings_choice(const wxString& category_name);
void get_freq_settings_choice(const wxString& bundle_name); void get_freq_settings_choice(const wxString& bundle_name);
void update_settings_item(); void update_settings_item();
@ -199,6 +212,7 @@ public:
wxMenu* append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type); wxMenu* append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type);
void append_menu_items_add_volume(wxMenu* menu); void append_menu_items_add_volume(wxMenu* menu);
wxMenuItem* append_menu_item_split(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_settings(wxMenu* menu);
wxMenuItem* append_menu_item_change_type(wxMenu* menu); wxMenuItem* append_menu_item_change_type(wxMenu* menu);
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent); 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 load_generic_subobject(const std::string& type_name, const ModelVolumeType type);
void del_object(const int obj_idx); void del_object(const int obj_idx);
void del_subobject_item(wxDataViewItem& item); 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_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); bool del_subobject_from_object(const int obj_idx, const int idx, const int type);
void split(); 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 get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume);
bool is_splittable(); bool is_splittable();
bool selected_instances_of_same_object(); bool selected_instances_of_same_object();
@ -265,6 +286,14 @@ public:
// Remove objects/sub-object from the list // Remove objects/sub-object from the list
void remove(); 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(); void init_objects();
bool multiple_selection() const ; bool multiple_selection() const ;
@ -286,6 +315,8 @@ public:
void last_volume_is_deleted(const int obj_idx); void last_volume_is_deleted(const int obj_idx);
bool has_multi_part_objects(); bool has_multi_part_objects();
void update_settings_items(); 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 update_object_menu();
void instances_to_separated_object(const int obj_idx, const std::set<int>& inst_idx); 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 fix_through_netfabb();
void update_item_error_icon(const int obj_idx, int vol_idx) const ; 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_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes);
void paste_objects_into_list(const std::vector<size_t>& object_idxs); void paste_objects_into_list(const std::vector<size_t>& object_idxs);

View file

@ -68,10 +68,12 @@ void ObjectSettings::update_settings_list()
m_settings_list_sizer->Clear(true); m_settings_list_sizer->Clear(true);
auto objects_ctrl = wxGetApp().obj_list(); auto objects_ctrl = wxGetApp().obj_list();
auto objects_model = wxGetApp().obj_list()->m_objects_model; auto objects_model = wxGetApp().obj_list()->GetModel();
auto config = wxGetApp().obj_list()->m_config; auto config = wxGetApp().obj_list()->config();
const auto item = objects_ctrl->GetSelection(); 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() && if (item && !objects_ctrl->multiple_selection() &&
config && objects_model->IsSettingsItem(item)) config && objects_model->IsSettingsItem(item))
{ {
@ -119,7 +121,8 @@ void ObjectSettings::update_settings_list()
} }
for (auto& cat : cat_options) { 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; continue;
auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), _(cat.first), config, false, extra_column); 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) { optgroup->m_on_change = [](const t_config_option_key& opt_id, const boost::any& value) {
wxGetApp().obj_list()->changed_object(); }; 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) for (auto& opt : cat.second)
{ {
if (opt == "extruder") if (opt == "extruder" || is_layers_range_settings && opt == "layer_height")
continue; continue;
Option option = optgroup->get_option(opt); Option option = optgroup->get_option(opt);
option.opt.width = 12; option.opt.width = 12;
if (is_extriders_cat) if (is_extruders_cat)
option.opt.max = wxGetApp().extruders_cnt(); option.opt.max = wxGetApp().extruders_cnt();
optgroup->append_single_option_line(option); optgroup->append_single_option_line(option);
} }

View file

@ -541,6 +541,26 @@ void Preview::on_checkbox_shells(wxCommandEvent& evt)
refresh_print(); 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() void Preview::create_double_slider()
{ {
m_slider = new DoubleSlider(this, wxID_ANY, 0, 0, 0, 100); m_slider = new DoubleSlider(this, wxID_ANY, 0, 0, 0, 100);
@ -553,21 +573,11 @@ void Preview::create_double_slider()
Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) { Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) {
auto& config = wxGetApp().preset_bundle->project_config; wxGetApp().preset_bundle->project_config.option<ConfigOptionFloats>("colorprint_heights")->values = m_slider->GetTicksValues();
((config.option<ConfigOptionFloats>("colorprint_heights"))->values) = (m_slider->GetTicksValues());
m_schedule_background_process(); m_schedule_background_process();
const wxString& choise = !config.option<ConfigOptionFloats>("colorprint_heights")->values.empty() ? _(L("Color Print")) : update_view_type();
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(); reload_print();
}); });
} }
@ -787,9 +797,14 @@ void Preview::load_print_as_fff(bool keep_z_range)
// Load the real G-code preview. // Load the real G-code preview.
m_canvas->load_gcode_preview(*m_gcode_preview_data, colors); m_canvas->load_gcode_preview(*m_gcode_preview_data, colors);
m_loaded = true; 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. // Load the initial preview based on slices, not the final G-code.
m_canvas->load_preview(colors, color_print_values); m_canvas->load_preview(colors, color_print_values);
}
show_hide_ui_elements(gcode_preview_data_valid ? "full" : "simple"); show_hide_ui_elements(gcode_preview_data_valid ? "full" : "simple");
// recalculates zs and update sliders accordingly // recalculates zs and update sliders accordingly
std::vector<double> zs = m_canvas->get_current_print_zs(true); std::vector<double> zs = m_canvas->get_current_print_zs(true);

View file

@ -127,6 +127,8 @@ public:
void move_double_slider(wxKeyEvent& evt); void move_double_slider(wxKeyEvent& evt);
void edit_double_slider(wxKeyEvent& evt); void edit_double_slider(wxKeyEvent& evt);
void update_view_type();
private: private:
bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model); bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model);

View file

@ -15,48 +15,6 @@
namespace Slic3r { namespace Slic3r {
namespace GUI { 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::Offset = 10.0;
const double GLGizmoCut::Margin = 20.0; const double GLGizmoCut::Margin = 20.0;
const std::array<float, 3> GLGizmoCut::GrabberColor = { 1.0, 0.5, 0.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); m_imgui->begin(_(L("Cut")), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
ImGui::PushItemWidth(m_imgui->scaled(5.0f)); 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 upper part")), m_keep_upper);
m_imgui->checkbox(_(L("Keep lower part")), m_keep_lower); m_imgui->checkbox(_(L("Keep lower part")), m_keep_lower);

View file

@ -259,6 +259,10 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const
void GLGizmoSlaSupports::on_render_for_picking(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)); glsafe(::glEnable(GL_DEPTH_TEST));
render_points(selection, true); render_points(selection, true);
} }

View file

@ -326,9 +326,9 @@ bool ImGuiWrapper::combo(const wxString& label, const std::vector<std::string>&
int selection_out = -1; int selection_out = -1;
bool res = false; 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)) { 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)) { if (ImGui::Selectable(options[i].c_str(), i == selection)) {
selection_out = i; selection_out = i;
} }

View file

@ -154,6 +154,9 @@ void KBShortcutsDialog::fill_shortcuts()
plater_shortcuts.push_back(Shortcut("I", L("Zoom in"))); plater_shortcuts.push_back(Shortcut("I", L("Zoom in")));
plater_shortcuts.push_back(Shortcut("O", L("Zoom out"))); plater_shortcuts.push_back(Shortcut("O", L("Zoom out")));
plater_shortcuts.push_back(Shortcut("ESC", L("Unselect gizmo / Clear selection"))); 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))); m_full_shortcuts.push_back(std::make_pair(_(L("Plater Shortcuts")), std::make_pair(plater_shortcuts, szRight)));

View file

@ -320,6 +320,17 @@ Line OptionsGroup::create_single_option_line(const Option& option) const {
return retval; 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) void OptionsGroup::on_set_focus(const std::string& opt_key)
{ {
if (m_set_focus != nullptr) if (m_set_focus != nullptr)

View file

@ -160,6 +160,8 @@ public:
m_show_modified_btns = show; 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, OptionsGroup( wxWindow* _parent, const wxString& title, bool is_tab_opt = false,
column_t extra_clmn = nullptr) : column_t extra_clmn = nullptr) :
m_parent(_parent), title(title), m_parent(_parent), title(title),

View file

@ -50,6 +50,7 @@
#include "GUI_App.hpp" #include "GUI_App.hpp"
#include "GUI_ObjectList.hpp" #include "GUI_ObjectList.hpp"
#include "GUI_ObjectManipulation.hpp" #include "GUI_ObjectManipulation.hpp"
#include "GUI_ObjectLayers.hpp"
#include "GUI_Utils.hpp" #include "GUI_Utils.hpp"
#include "wxExtensions.hpp" #include "wxExtensions.hpp"
#include "MainFrame.hpp" #include "MainFrame.hpp"
@ -615,10 +616,11 @@ struct Sidebar::priv
PresetComboBox *combo_printer; PresetComboBox *combo_printer;
wxBoxSizer *sizer_params; wxBoxSizer *sizer_params;
FreqChangedParams *frequently_changed_parameters; FreqChangedParams *frequently_changed_parameters{ nullptr };
ObjectList *object_list; ObjectList *object_list{ nullptr };
ObjectManipulation *object_manipulation; ObjectManipulation *object_manipulation{ nullptr };
ObjectSettings *object_settings; ObjectSettings *object_settings{ nullptr };
ObjectLayers *object_layers{ nullptr };
ObjectInfo *object_info; ObjectInfo *object_info;
SlicedInfo *sliced_info; SlicedInfo *sliced_info;
@ -627,10 +629,26 @@ struct Sidebar::priv
wxButton *btn_send_gcode; wxButton *btn_send_gcode;
priv(Plater *plater) : plater(plater) {} priv(Plater *plater) : plater(plater) {}
~priv();
void show_preset_comboboxes(); 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() void Sidebar::priv::show_preset_comboboxes()
{ {
const bool showSLA = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA; const bool showSLA = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA;
@ -738,6 +756,11 @@ Sidebar::Sidebar(Plater *parent)
p->object_settings->Hide(); p->object_settings->Hide();
p->sizer_params->Add(p->object_settings->get_sizer(), 0, wxEXPAND | wxTOP, margin_5); 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 // Info boxes
p->object_info = new ObjectInfo(p->scrolled); p->object_info = new ObjectInfo(p->scrolled);
p->sliced_info = new SlicedInfo(p->scrolled); p->sliced_info = new SlicedInfo(p->scrolled);
@ -930,6 +953,7 @@ void Sidebar::msw_rescale()
p->object_list->msw_rescale(); p->object_list->msw_rescale();
p->object_manipulation->msw_rescale(); p->object_manipulation->msw_rescale();
p->object_settings->msw_rescale(); p->object_settings->msw_rescale();
p->object_layers->msw_rescale();
p->object_info->msw_rescale(); p->object_info->msw_rescale();
@ -951,6 +975,11 @@ ObjectSettings* Sidebar::obj_settings()
return p->object_settings; return p->object_settings;
} }
ObjectLayers* Sidebar::obj_layers()
{
return p->object_layers;
}
wxScrolledWindow* Sidebar::scrolled_panel() wxScrolledWindow* Sidebar::scrolled_panel()
{ {
return p->scrolled; return p->scrolled;
@ -1264,6 +1293,7 @@ struct Plater::priv
Preview *preview; Preview *preview;
BackgroundSlicingProcess background_process; BackgroundSlicingProcess background_process;
bool suppressed_backround_processing_update { false };
// A class to handle UI jobs like arranging and optimizing rotation. // A class to handle UI jobs like arranging and optimizing rotation.
// These are not instant jobs, the user has to be informed about their // 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; static const std::regex pattern_prusa;
priv(Plater *q, MainFrame *main_frame); priv(Plater *q, MainFrame *main_frame);
~priv();
void update(bool force_full_scene_refresh = false); void update(bool force_full_scene_refresh = false);
void select_view(const std::string& direction); void select_view(const std::string& direction);
@ -1705,7 +1736,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
panels.push_back(preview); panels.push_back(preview);
this->background_process_timer.SetOwner(this->q, 0); 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(); update();
@ -1795,6 +1830,12 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
this->take_snapshot(_(L("New Project"))); this->take_snapshot(_(L("New Project")));
} }
Plater::priv::~priv()
{
if (config != nullptr)
delete config;
}
void Plater::priv::update(bool force_full_scene_refresh) void Plater::priv::update(bool force_full_scene_refresh)
{ {
// the following line, when enabled, causes flickering on NVIDIA graphics cards // 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(); object->ensure_on_bed();
// print.auto_assign_extruders(object);
// print.add_model_object(object);
} }
#ifdef AUTOPLACEMENT_ON_LOAD #ifdef AUTOPLACEMENT_ON_LOAD
@ -2957,8 +2995,14 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
// update plater with new config // update plater with new config
wxGetApp().plater()->on_config_change(wxGetApp().preset_bundle->full_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) 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) 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); [this]() { return can_split() && wxGetApp().get_mode() > comSimple; }, q);
object_menu.AppendSeparator(); 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() // "Add (volumes)" popupmenu will be added later in append_menu_items_add_volume()
return true; return true;
@ -4000,6 +4048,9 @@ void Plater::reslice()
} }
else if (!p->background_process.empty() && !p->background_process.idle()) else if (!p->background_process.empty() && !p->background_process.idle())
p->show_action_buttons(true); p->show_action_buttons(true);
// update type of preview
p->preview->update_view_type();
} }
void Plater::reslice_SLA_supports(const ModelObject &object) 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(); this->p->schedule_background_process();
} }
void Plater::schedule_background_process() void Plater::schedule_background_process(bool schedule/* = true*/)
{ {
if (schedule)
this->p->schedule_background_process(); 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); } 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(); GetParent()->Layout();
} }
const Camera& Plater::get_camera() const
{
return p->camera;
}
bool Plater::can_delete() const { return p->can_delete(); } bool Plater::can_delete() const { return p->can_delete(); }
bool Plater::can_delete_all() const { return p->can_delete_all(); } bool Plater::can_delete_all() const { return p->can_delete_all(); }
bool Plater::can_increase_instances() const { return p->can_increase_instances(); } bool Plater::can_increase_instances() const { return p->can_increase_instances(); }
@ -4338,4 +4410,15 @@ bool Plater::can_copy_to_clipboard() const
return true; 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 }} // namespace Slic3r::GUI

View file

@ -33,6 +33,7 @@ class MainFrame;
class ConfigOptionsGroup; class ConfigOptionsGroup;
class ObjectManipulation; class ObjectManipulation;
class ObjectSettings; class ObjectSettings;
class ObjectLayers;
class ObjectList; class ObjectList;
class GLCanvas3D; class GLCanvas3D;
@ -93,6 +94,7 @@ public:
ObjectManipulation* obj_manipul(); ObjectManipulation* obj_manipul();
ObjectList* obj_list(); ObjectList* obj_list();
ObjectSettings* obj_settings(); ObjectSettings* obj_settings();
ObjectLayers* obj_layers();
wxScrolledWindow* scrolled_panel(); wxScrolledWindow* scrolled_panel();
wxPanel* presets_panel(); wxPanel* presets_panel();
@ -175,7 +177,9 @@ public:
void reslice_SLA_supports(const ModelObject &object); void reslice_SLA_supports(const ModelObject &object);
void changed_object(int obj_idx); void changed_object(int obj_idx);
void changed_objects(const std::vector<size_t>& object_idxs); 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 fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
void send_gcode(); void send_gcode();
@ -221,11 +225,23 @@ public:
void msw_rescale(); void msw_rescale();
const Camera& get_camera() const;
private: private:
struct priv; struct priv;
std::unique_ptr<priv> p; std::unique_ptr<priv> p;
friend class SuppressBackgroundProcessingUpdate;
}; };
class SuppressBackgroundProcessingUpdate
{
public:
SuppressBackgroundProcessingUpdate();
~SuppressBackgroundProcessingUpdate();
private:
bool m_was_running;
};
}} }}

View file

@ -97,16 +97,6 @@ void PreferencesDialog::build()
option = Option (def,"show_incompatible_presets"); option = Option (def,"show_incompatible_presets");
m_optgroup->append_single_option_line(option); 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__ #if __APPLE__
def.label = L("Use Retina resolution for the 3D scene"); def.label = L("Use Retina resolution for the 3D scene");
def.type = coBool; def.type = coBool;
@ -150,8 +140,7 @@ void PreferencesDialog::build()
void PreferencesDialog::accept() void PreferencesDialog::accept()
{ {
if (m_values.find("no_defaults") != m_values.end() || if (m_values.find("no_defaults") != m_values.end()) {
m_values.find("use_legacy_opengl") != m_values.end()) {
warning_catcher(this, wxString::Format(_(L("You need to restart %s to make the changes effective.")), SLIC3R_APP_NAME)); warning_catcher(this, wxString::Format(_(L("You need to restart %s to make the changes effective.")), SLIC3R_APP_NAME));
} }

View file

@ -824,11 +824,25 @@ const Preset* PresetCollection::get_selected_preset_parent() const
if (this->get_selected_idx() == -1) if (this->get_selected_idx() == -1)
// This preset collection has no preset activated yet. Only the get_edited_preset() is valid. // This preset collection has no preset activated yet. Only the get_edited_preset() is valid.
return nullptr; 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()) 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); 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 const Preset* PresetCollection::get_preset_parent(const Preset& child) const

View file

@ -6,7 +6,8 @@
#include "GUI_ObjectManipulation.hpp" #include "GUI_ObjectManipulation.hpp"
#include "GUI_ObjectList.hpp" #include "GUI_ObjectList.hpp"
#include "Gizmos/GLGizmoBase.hpp" #include "Gizmos/GLGizmoBase.hpp"
#include "slic3r/GUI/3DScene.hpp" #include "3DScene.hpp"
#include "Camera.hpp"
#include <GL/glew.h> #include <GL/glew.h>
@ -347,6 +348,9 @@ void Selection::clear()
// resets the cache in the sidebar // resets the cache in the sidebar
wxGetApp().obj_manipul()->reset_cache(); 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. // Update the selection based on the new instance IDs.
@ -1086,21 +1090,27 @@ void Selection::render_center(bool gizmo_is_dragging) const
} }
#endif // ENABLE_RENDER_SELECTION_CENTER #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()) if (sidebar_field.empty())
return; return;
if (!boost::starts_with(sidebar_field, "layer"))
{
shader.start_using();
glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glEnable(GL_LIGHTING)); glsafe(::glEnable(GL_LIGHTING));
}
glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
if (!boost::starts_with(sidebar_field, "layer"))
{
const Vec3d& center = get_bounding_box().center(); const Vec3d& center = get_bounding_box().center();
if (is_single_full_instance() && ! wxGetApp().obj_manipul()->get_world_coordinates()) if (is_single_full_instance() && !wxGetApp().obj_manipul()->get_world_coordinates())
{ {
glsafe(::glTranslated(center(0), center(1), center(2))); glsafe(::glTranslated(center(0), center(1), center(2)));
if (!boost::starts_with(sidebar_field, "position")) if (!boost::starts_with(sidebar_field, "position"))
@ -1143,6 +1153,7 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field) const
glsafe(::glMultMatrixd(orient_matrix.data())); glsafe(::glMultMatrixd(orient_matrix.data()));
} }
} }
}
if (boost::starts_with(sidebar_field, "position")) if (boost::starts_with(sidebar_field, "position"))
render_sidebar_position_hints(sidebar_field); render_sidebar_position_hints(sidebar_field);
@ -1152,10 +1163,16 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field) const
render_sidebar_scale_hints(sidebar_field); render_sidebar_scale_hints(sidebar_field);
else if (boost::starts_with(sidebar_field, "size")) else if (boost::starts_with(sidebar_field, "size"))
render_sidebar_size_hints(sidebar_field); render_sidebar_size_hints(sidebar_field);
else if (boost::starts_with(sidebar_field, "layer"))
render_sidebar_layers_hints(sidebar_field);
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
if (!boost::starts_with(sidebar_field, "layer"))
{
glsafe(::glDisable(GL_LIGHTING)); glsafe(::glDisable(GL_LIGHTING));
shader.stop_using();
}
} }
bool Selection::requires_local_axes() const 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); 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_support_points = src_object->sla_support_points;
dst_object->sla_points_status = src_object->sla_points_status; 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->layer_height_profile = src_object->layer_height_profile;
dst_object->origin_translation = src_object->origin_translation; 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); 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 void Selection::render_sidebar_position_hint(Axis axis) const
{ {
m_arrow.set_color(AXES_COLOR[axis], 3); m_arrow.set_color(AXES_COLOR[axis], 3);

View file

@ -11,8 +11,8 @@ typedef class GLUquadric GLUquadricObj;
#endif // ENABLE_RENDER_SELECTION_CENTER #endif // ENABLE_RENDER_SELECTION_CENTER
namespace Slic3r { namespace Slic3r {
class Shader;
namespace GUI { namespace GUI {
class TransformationType class TransformationType
{ {
public: public:
@ -305,7 +305,7 @@ public:
#if ENABLE_RENDER_SELECTION_CENTER #if ENABLE_RENDER_SELECTION_CENTER
void render_center(bool gizmo_is_dragging) const; void render_center(bool gizmo_is_dragging) const;
#endif // ENABLE_RENDER_SELECTION_CENTER #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; bool requires_local_axes() const;
@ -335,6 +335,7 @@ private:
void render_sidebar_rotation_hints(const std::string& sidebar_field) const; 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_scale_hints(const std::string& sidebar_field) const;
void render_sidebar_size_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_position_hint(Axis axis) const;
void render_sidebar_rotation_hint(Axis axis) const; void render_sidebar_rotation_hint(Axis axis) const;
void render_sidebar_scale_hint(Axis axis) const; void render_sidebar_scale_hint(Axis axis) const;

View file

@ -423,7 +423,7 @@ void Tab::update_changed_ui()
const ScalableBitmap *sys_icon = &m_bmp_value_lock; const ScalableBitmap *sys_icon = &m_bmp_value_lock;
const ScalableBitmap *icon = &m_bmp_value_revert; 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 *sys_tt = &m_tt_value_lock;
const wxString *tt = &m_tt_value_revert; 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 : modified_page ? &m_modified_label_clr :
&m_default_text_clr; &m_default_text_clr;
@ -2315,6 +2315,40 @@ void TabPrinter::build_unregular_pages()
auto optgroup = page->new_optgroup(_(L("Size"))); auto optgroup = page->new_optgroup(_(L("Size")));
optgroup->append_single_option_line("nozzle_diameter", extruder_idx); 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 = page->new_optgroup(_(L("Layer height limits")));
optgroup->append_single_option_line("min_layer_height", extruder_idx); optgroup->append_single_option_line("min_layer_height", extruder_idx);
optgroup->append_single_option_line("max_layer_height", extruder_idx); optgroup->append_single_option_line("max_layer_height", extruder_idx);
@ -2550,11 +2584,14 @@ void Tab::load_current_preset()
// Reload preset pages with the new configuration values. // Reload preset pages with the new configuration values.
reload_config(); reload_config();
m_bmp_non_system = m_presets->get_selected_preset_parent() ? &m_bmp_value_unlock : &m_bmp_white_bullet; const Preset* selected_preset_parent = m_presets->get_selected_preset_parent();
m_ttg_non_system = m_presets->get_selected_preset_parent() ? &m_ttg_value_unlock : &m_ttg_white_bullet_ns; m_is_default_preset = selected_preset_parent != nullptr && selected_preset_parent->is_default;
m_tt_non_system = m_presets->get_selected_preset_parent() ? &m_tt_value_unlock : &m_ttg_white_bullet_ns;
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 #if 0
// use CallAfter because some field triggers schedule on_change calls using CallAfter, // 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"), m_icon_descriptions.emplace_back(&m_bmp_value_lock, L("LOCKED LOCK"),
// TRN Description for "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"), m_icon_descriptions.emplace_back(&m_bmp_value_unlock, L("UNLOCKED LOCK"),
// TRN Description for "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" "the current option group.\n"
"Click the UNLOCKED LOCK icon to reset all settings for current option group to " "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"), m_icon_descriptions.emplace_back(&m_bmp_white_bullet, L("WHITE BULLET"),
// TRN Description for "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.")); "for the right button: \tindicates that the settings hasn't been modified."));
m_icon_descriptions.emplace_back(&m_bmp_value_revert, L("BACK ARROW"), 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() 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) // --- 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. // 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")); "for the current option group"));
m_ttg_value_unlock = _(L("UNLOCKED LOCK icon indicates that some settings were changed and are not equal " 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" "to the system (or default) values for the current option group.\n"
"Click to reset all settings for current option group to the system values.")); "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 preset.")); 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; m_ttg_non_system = &m_ttg_white_bullet_ns;
// Text to be shown on the "Undo user changes" button next to each input field. // 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 " 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) // --- 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. // 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 " m_tt_value_unlock = _(L("UNLOCKED LOCK icon indicates that the value was changed and is not equal "
"to the system value.\n" "to the system (or default) value.\n"
"Click to reset current value to the system value.")); "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_white_bullet_ns= _(L("WHITE BULLET icon indicates a non system preset."));
m_tt_non_system = &m_ttg_white_bullet_ns; m_tt_non_system = &m_ttg_white_bullet_ns;
// Text to be shown on the "Undo user changes" button next to each input field. // 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() void TabSLAMaterial::update()
{ {
if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF) 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++; // m_update_cnt++;
// ! something to update // ! something to update
// m_update_cnt--; // m_update_cnt--;
@ -3554,9 +3576,8 @@ void TabSLAPrint::reload_config()
void TabSLAPrint::update() void TabSLAPrint::update()
{ {
if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF) if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF)
return; // #ys_FIXME return;
// #ys_FIXME
m_update_cnt++; m_update_cnt++;
double head_penetration = m_config->opt_float("support_head_penetration"); double head_penetration = m_config->opt_float("support_head_penetration");

View file

@ -142,6 +142,12 @@ protected:
PresetDependencies m_compatible_printers; PresetDependencies m_compatible_printers;
PresetDependencies m_compatible_prints; 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_btn;
ScalableButton* m_undo_to_sys_btn; ScalableButton* m_undo_to_sys_btn;
ScalableButton* m_question_btn; ScalableButton* m_question_btn;

View file

@ -437,27 +437,69 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
m_type(type), m_type(type),
m_extruder(wxEmptyString) m_extruder(wxEmptyString)
{ {
if (type == itSettings) { if (type == itSettings)
m_name = "Settings to modified"; m_name = "Settings to modified";
} else if (type == itInstanceRoot)
else if (type == itInstanceRoot) {
m_name = _(L("Instances")); m_name = _(L("Instances"));
#ifdef __WXGTK__ else if (type == itInstance)
m_container = true; {
#endif //__WXGTK__
}
else if (type == itInstance) {
m_idx = parent->GetChildCount(); m_idx = parent->GetChildCount();
m_name = wxString::Format(_(L("Instance %d")), m_idx + 1); m_name = wxString::Format(_(L("Instance %d")), m_idx + 1);
set_action_icon(); 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() void ObjectDataViewModelNode::set_action_icon()
{ {
m_action_icon_name = m_type == itObject ? "advanced_plus" : m_action_icon_name = m_type & itObject ? "advanced_plus" :
m_type == itVolume ? "cog" : "set_separate_obj"; 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 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 // 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() ObjectDataViewModel::ObjectDataViewModel()
{ {
m_bitmap_cache = new Slic3r::GUI::BitmapCache; 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); wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
// because of istance_root is a last item of the object // get insertion position according to the existed Layers and/or Instances Items
int insert_position = root->GetChildCount() - 1; int insert_position = get_root_idx(root, itLayerRoot);
if (insert_position < 0 || root->GetNthChild(insert_position)->m_type != itInstanceRoot) if (insert_position < 0)
insert_position = -1; insert_position = get_root_idx(root, itInstanceRoot);
const bool obj_errors = root->m_bmp.IsOk(); const bool obj_errors = root->m_bmp.IsOk();
@ -619,15 +677,30 @@ wxDataViewItem ObjectDataViewModel::AddSettingsChild(const wxDataViewItem &paren
return child; 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_id = get_root_idx(parent_node, root_type);
const int inst_root_idx = parent_node->GetChildCount()-1;
if (inst_root_idx < 0 || parent_node->GetNthChild(inst_root_idx)->GetType() == itInstanceRoot) *root_node = inst_root_id < 0 ?
return inst_root_idx; 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) 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(); ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
if (!parent_node) return wxDataViewItem(0); if (!parent_node) return wxDataViewItem(0);
// Check and create/get instances root node // get InstanceRoot node
const int inst_root_id = get_istances_root_idx(parent_node); ObjectDataViewModelNode *inst_root_node { nullptr };
ObjectDataViewModelNode *inst_root_node = inst_root_id < 0 ? const bool appended = append_root_node(parent_node, &inst_root_node, itInstanceRoot);
new ObjectDataViewModelNode(parent_node, itInstanceRoot) :
parent_node->GetNthChild(inst_root_id);
const wxDataViewItem inst_root_item((void*)inst_root_node); const wxDataViewItem inst_root_item((void*)inst_root_node);
if (!inst_root_node) return wxDataViewItem(0);
if (inst_root_id < 0) { if (appended)
parent_node->Append(inst_root_node); ItemAdded(parent_item, inst_root_item);// notify control
// notify control
ItemAdded(parent_item, inst_root_item);
// if (num == 1) num++;
}
// Add instance nodes // Add instance nodes
ObjectDataViewModelNode *instance_node = nullptr; ObjectDataViewModelNode *instance_node = nullptr;
@ -665,6 +733,63 @@ wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &paren
return wxDataViewItem((void*)instance_node); 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) wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
{ {
auto ret_item = wxDataViewItem(0); auto ret_item = wxDataViewItem(0);
@ -679,9 +804,9 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_ // NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
// thus removing the node from it doesn't result in freeing it // thus removing the node from it doesn't result in freeing it
if (node_parent) { 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))); Delete(wxDataViewItem(node->GetNthChild(i)));
return parent; return parent;
} }
@ -690,7 +815,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
auto idx = node->GetIdx(); auto idx = node->GetIdx();
if (node->m_type == itVolume) { if (node->m_type & (itVolume|itLayer)) {
node_parent->m_volumes_cnt--; node_parent->m_volumes_cnt--;
DeleteSettings(item); DeleteSettings(item);
} }
@ -726,6 +851,22 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
delete node_parent; delete node_parent;
ret_item = wxDataViewItem(obj_node); 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 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__ #ifndef __WXGTK__
if (obj_node->GetChildCount() == 0) if (obj_node->GetChildCount() == 0)
obj_node->m_container = false; obj_node->m_container = false;
@ -735,7 +876,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
} }
// if there is last volume item after deleting, delete this last volume too // 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_cnt = 0;
int vol_idx = 0; int vol_idx = 0;
@ -817,7 +958,7 @@ wxDataViewItem ObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &par
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID(); ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
if (!parent_node) return ret_item; 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; if (inst_root_id < 0) return ret_item;
wxDataViewItemArray items; wxDataViewItemArray items;
@ -974,28 +1115,67 @@ wxDataViewItem ObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volume_id
return wxDataViewItem(0); return wxDataViewItem(0);
} }
wxDataViewItem ObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx) 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) { if (obj_idx >= m_objects.size() || obj_idx < 0) {
printf("Error! Out of objects range.\n"); printf("Error! Out of objects range.\n");
return wxDataViewItem(0); return wxDataViewItem(0);
} }
auto instances_item = GetInstanceRootItem(wxDataViewItem(m_objects[obj_idx])); auto item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), parent_type);
if (!instances_item) if (!item)
return wxDataViewItem(0); return wxDataViewItem(0);
auto parent = (ObjectDataViewModelNode*)instances_item.GetID();; auto parent = (ObjectDataViewModelNode*)item.GetID();
for (size_t i = 0; i < parent->GetChildCount(); i++) for (size_t i = 0; i < parent->GetChildCount(); i++)
if (parent->GetNthChild(i)->m_idx == inst_idx) if (parent->GetNthChild(i)->m_idx == sub_obj_idx)
return wxDataViewItem(parent->GetNthChild(i)); return wxDataViewItem(parent->GetNthChild(i));
return wxDataViewItem(0); 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 item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), itLayerRoot);
if (!item)
return wxDataViewItem(0);
auto parent = (ObjectDataViewModelNode*)item.GetID();
for (size_t i = 0; i < parent->GetChildCount(); i++)
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 int ObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) const
{ {
wxASSERT(item.IsOk()); if(!item.IsOk())
return -1;
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID(); ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
auto it = find(m_objects.begin(), m_objects.end(), node); 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); 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) void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx)
{ {
wxASSERT(item.IsOk()); wxASSERT(item.IsOk());
type = itUndef; type = itUndef;
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID(); 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; return;
idx = node->GetIdx(); idx = node->GetIdx();
@ -1044,9 +1239,10 @@ void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type
ObjectDataViewModelNode *parent_node = node->GetParent(); ObjectDataViewModelNode *parent_node = node->GetParent();
if (!parent_node) return; if (!parent_node) return;
if (type == itInstance)
parent_node = node->GetParent()->GetParent(); // get top parent (Object) node
if (!parent_node || parent_node->m_type != itObject) { type = itUndef; return; } while (parent_node->m_type != itObject)
parent_node = parent_node->GetParent();
auto it = find(m_objects.begin(), m_objects.end(), parent_node); auto it = find(m_objects.begin(), m_objects.end(), parent_node);
if (it != m_objects.end()) if (it != m_objects.end())
@ -1214,10 +1410,7 @@ wxDataViewItem ObjectDataViewModel::GetTopParent(const wxDataViewItem &item) con
ObjectDataViewModelNode *parent_node = node->GetParent(); ObjectDataViewModelNode *parent_node = node->GetParent();
while (parent_node->m_type != itObject) while (parent_node->m_type != itObject)
{ parent_node = parent_node->GetParent();
node = parent_node;
parent_node = node->GetParent();
}
return wxDataViewItem((void*)parent_node); return wxDataViewItem((void*)parent_node);
} }
@ -1318,6 +1511,11 @@ wxDataViewItem ObjectDataViewModel::GetInstanceRootItem(const wxDataViewItem &it
return GetItemByType(item, itInstanceRoot); return GetItemByType(item, itInstanceRoot);
} }
wxDataViewItem ObjectDataViewModel::GetLayerRootItem(const wxDataViewItem &item) const
{
return GetItemByType(item, itLayerRoot);
}
bool ObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const bool ObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const
{ {
if (!item.IsOk()) 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) 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 ); dc.SetPen(m_is_enabled_tick_manipulation ? DARK_GREY_PEN : LIGHT_GREY_PEN );
int height, width; int height, width;
get_size(&width, &height); get_size(&width, &height);
@ -2044,6 +2245,9 @@ void DoubleSlider::draw_ticks(wxDC& dc)
void DoubleSlider::draw_colored_band(wxDC& dc) void DoubleSlider::draw_colored_band(wxDC& dc)
{ {
if (!m_is_enabled_tick_manipulation)
return;
int height, width; int height, width;
get_size(&width, &height); get_size(&width, &height);
@ -2113,7 +2317,7 @@ void DoubleSlider::draw_one_layer_icon(wxDC& dc)
void DoubleSlider::draw_revert_icon(wxDC& dc) void DoubleSlider::draw_revert_icon(wxDC& dc)
{ {
if (m_ticks.empty()) if (m_ticks.empty() || !m_is_enabled_tick_manipulation)
return; return;
int width, height; int width, height;
@ -2218,7 +2422,7 @@ void DoubleSlider::OnLeftDown(wxMouseEvent& event)
m_selection == ssLower ? correct_lower_value() : correct_higher_value(); m_selection == ssLower ? correct_lower_value() : correct_higher_value();
if (!m_selection) m_selection = ssHigher; 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 // discard all color changes
SetLowerValue(m_min_value); SetLowerValue(m_min_value);
SetHigherValue(m_max_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));; m_mode_btns.push_back(new ModeButton(parent, wxID_ANY, button.second, button.first));;
#endif // __WXOSX__ #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()); Add(m_mode_btns.back());
} }
} }

View file

@ -20,6 +20,9 @@ namespace Slic3r {
enum class ModelVolumeType : int; enum class ModelVolumeType : int;
}; };
typedef double coordf_t;
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
#ifdef __WXMSW__ #ifdef __WXMSW__
void msw_rescale_menu(wxMenu* menu); void msw_rescale_menu(wxMenu* menu);
#else /* __WXMSW__ */ #else /* __WXMSW__ */
@ -164,7 +167,9 @@ enum ItemType {
itVolume = 2, itVolume = 2,
itInstanceRoot = 4, itInstanceRoot = 4,
itInstance = 8, itInstance = 8,
itSettings = 16 itSettings = 16,
itLayerRoot = 32,
itLayer = 64,
}; };
class ObjectDataViewModelNode; class ObjectDataViewModelNode;
@ -177,6 +182,7 @@ class ObjectDataViewModelNode
wxBitmap m_empty_bmp; wxBitmap m_empty_bmp;
size_t m_volumes_cnt = 0; size_t m_volumes_cnt = 0;
std::vector< std::string > m_opt_categories; std::vector< std::string > m_opt_categories;
t_layer_height_range m_layer_range = { 0.0f, 0.0f };
wxString m_name; wxString m_name;
wxBitmap& m_bmp = m_empty_bmp; wxBitmap& m_bmp = m_empty_bmp;
@ -229,6 +235,11 @@ public:
set_action_icon(); 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(ObjectDataViewModelNode* parent, const ItemType type);
~ObjectDataViewModelNode() ~ObjectDataViewModelNode()
@ -318,6 +329,7 @@ public:
ItemType GetType() const { return m_type; } ItemType GetType() const { return m_type; }
void SetIdx(const int& idx); void SetIdx(const int& idx);
int GetIdx() const { return m_idx; } int GetIdx() const { return m_idx; }
t_layer_height_range GetLayerRange() const { return m_layer_range; }
// use this function only for childrens // use this function only for childrens
void AssignAllVal(ObjectDataViewModelNode& from_node) void AssignAllVal(ObjectDataViewModelNode& from_node)
@ -388,6 +400,11 @@ public:
const bool create_frst_child = true); const bool create_frst_child = true);
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item); wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num); 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 Delete(const wxDataViewItem &item);
wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num); wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
void DeleteAll(); void DeleteAll();
@ -395,13 +412,18 @@ public:
void DeleteVolumeChildren(wxDataViewItem& parent); void DeleteVolumeChildren(wxDataViewItem& parent);
void DeleteSettings(const wxDataViewItem& parent); void DeleteSettings(const wxDataViewItem& parent);
wxDataViewItem GetItemById(int obj_idx); 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 GetItemByVolumeId(int obj_idx, int volume_idx);
wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_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 GetIdByItem(const wxDataViewItem& item) const;
int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const; int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
int GetObjectIdByItem(const wxDataViewItem& item) const; int GetObjectIdByItem(const wxDataViewItem& item) const;
int GetVolumeIdByItem(const wxDataViewItem& item) const; int GetVolumeIdByItem(const wxDataViewItem& item) const;
int GetInstanceIdByItem(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); void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx);
int GetRowByItem(const wxDataViewItem& item) const; int GetRowByItem(const wxDataViewItem& item) const;
bool IsEmpty() { return m_objects.empty(); } bool IsEmpty() { return m_objects.empty(); }
@ -450,6 +472,7 @@ public:
ItemType type) const; ItemType type) const;
wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const; wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const;
wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const; wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const;
wxDataViewItem GetLayerRootItem(const wxDataViewItem &item) const;
bool IsSettingsItem(const wxDataViewItem &item) const; bool IsSettingsItem(const wxDataViewItem &item) const;
void UpdateSettingsDigest( const wxDataViewItem &item, void UpdateSettingsDigest( const wxDataViewItem &item,
const std::vector<std::string>& categories); const std::vector<std::string>& categories);
@ -465,6 +488,7 @@ public:
wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type,
const bool is_marked = false); const bool is_marked = false);
void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false); void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const;
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View file

@ -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 auto ver_current = idx.find(vp.config_version);
const bool ver_current_found = ver_current != idx.end(); 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%") BOOST_LOG_TRIVIAL(debug) << boost::format("Vendor: %1%, version installed: %2%%3%, version cached: %4%")
% vp.name % vp.name
@ -418,6 +411,13 @@ Updates PresetUpdater::priv::get_config_updates() const
% (ver_current_found ? "" : " (not found in index!)") % (ver_current_found ? "" : " (not found in index!)")
% recommended->config_version.to_string(); % 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()) { if (ver_current_found && !ver_current->is_current_slic3r_supported()) {
BOOST_LOG_TRIVIAL(warning) << "Current Slic3r incompatible with installed bundle: " << bundle_path.string(); 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); updates.incompats.emplace_back(std::move(bundle_path), *ver_current, vp.name);
@ -459,12 +459,18 @@ Updates PresetUpdater::priv::get_config_updates() const
found = true; 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") 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() % idx.vendor()
% recommended->config_version.to_string(); % recommended->config_version.to_string();
} }
} }
}
return updates; return updates;
} }

View file

@ -89,7 +89,7 @@ plan tests => 8;
# we disable combination after infill has been generated # we disable combination after infill has been generated
$config->set('infill_every_layers', 1); $config->set('infill_every_layers', 1);
$print->apply_config_perl_tests_only($config); $print->apply($print->print->model->clone, $config);
$print->process; $print->process;
ok !(defined first { @{$_->get_region(0)->fill_surfaces} == 0 } ok !(defined first { @{$_->get_region(0)->fill_surfaces} == 0 }

View file

@ -34,24 +34,29 @@ use Slic3r::Test;
{ {
# this represents the aggregate config from presets # this represents the aggregate config from presets
my $config = Slic3r::Config::new_from_defaults; 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 # user adds one object to the plater
my $print = Slic3r::Test::init_print(my $model = Slic3r::Test::model('20mm_cube'), config => $config); my $print = Slic3r::Test::init_print(my $model = Slic3r::Test::model('20mm_cube'), config => $config);
# user sets a per-region option # user sets a per-region option
$print->print->objects->[0]->model_object->config->set('fill_density', 100); my $model2 = $model->clone;
$print->print->reload_object(0); $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'; 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 # user exports G-code, thus the default config is reapplied
$print->print->apply_config_perl_tests_only($config); $model2->get_object(0)->config->erase('fill_density');
$print->apply($model2, $config);
is $print->print->regions->[0]->config->fill_density, 100, 'apply_config() does not override per-object settings'; is $print->print->regions->[0]->config->fill_density, 20, 'region config is resetted';
# user assigns object extruders # user assigns object extruders
$print->print->objects->[0]->model_object->config->set('extruder', 3); $model2->get_object(0)->config->set('extruder', 3);
$print->print->objects->[0]->model_object->config->set('perimeter_extruder', 2); $model2->get_object(0)->config->set('perimeter_extruder', 2);
$print->print->reload_object(0); $print->apply($model2, $config);
is $print->print->regions->[0]->config->infill_extruder, 3, 'extruder setting is correctly expanded'; 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'; is $print->print->regions->[0]->config->perimeter_extruder, 2, 'extruder setting does not override explicitely specified extruders';

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