diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index 1a1fa6f70..8ab34ca34 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -132,7 +132,10 @@ sub thread_cleanup { # prevent destruction of shared objects no warnings 'redefine'; *Slic3r::Config::DESTROY = sub {}; + *Slic3r::Config::Full::DESTROY = sub {}; *Slic3r::Config::Print::DESTROY = sub {}; + *Slic3r::Config::PrintObject::DESTROY = sub {}; + *Slic3r::Config::PrintRegion::DESTROY = sub {}; *Slic3r::ExPolygon::DESTROY = sub {}; *Slic3r::ExPolygon::Collection::DESTROY = sub {}; *Slic3r::ExtrusionLoop::DESTROY = sub {}; diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index bd924448b..9f5de4f4b 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -15,16 +15,25 @@ our $Options = print_config_def(); { no strict 'refs'; for my $opt_key (keys %$Options) { - *{$opt_key} = sub { $_[0]->get($opt_key) }; + *{$opt_key} = sub { $_[0]->_get($opt_key) }; } } +sub _get { + my ($self, $opt_key) = @_; + use XXX; + if (!defined first { $_ eq $opt_key } @{$self->get_keys}) { + ZZZ $opt_key; + } + return $self->get($opt_key); +} + sub new_from_defaults { my $class = shift; my (@opt_keys) = @_; my $self = $class->new; - my $defaults = Slic3r::Config::Print->new; + my $defaults = Slic3r::Config::Full->new; if (@opt_keys) { $self->set($_, $defaults->get($_)) for @opt_keys; } else { @@ -309,7 +318,7 @@ sub validate { && !$self->default_acceleration; # general validation, quick and dirty - foreach my $opt_key (keys %$Options) { + foreach my $opt_key (@{$self->get_keys}) { my $opt = $Options->{$opt_key}; next unless defined $self->$opt_key; next unless defined $opt->{cli} && $opt->{cli} =~ /=(.+)$/; @@ -431,4 +440,16 @@ sub read_ini { return $ini; } +package Slic3r::Config::Print; +use parent 'Slic3r::Config'; + +package Slic3r::Config::PrintObject; +use parent 'Slic3r::Config'; + +package Slic3r::Config::PrintRegion; +use parent 'Slic3r::Config'; + +package Slic3r::Config::Full; +use parent 'Slic3r::Config'; + 1; diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index 1f27d143c..ce22d9c88 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -14,9 +14,9 @@ has 'layer' => ( is => 'ro', weak_ref => 1, required => 1, - handles => [qw(id slice_z print_z height config)], + handles => [qw(id slice_z print_z height object print)], ); -has 'region' => (is => 'ro', required => 1, handles => [qw(extruders)]); +has 'region' => (is => 'ro', required => 1, handles => [qw(config)]); has 'infill_area_threshold' => (is => 'lazy'); has 'overhang_width' => (is => 'lazy'); @@ -168,7 +168,7 @@ sub make_perimeters { @offsets = @{offset2(\@last, -(1.5*$pspacing - 1), +(0.5*$pspacing - 1))}; # look for gaps - if ($self->config->gap_fill_speed > 0 && $self->config->fill_density > 0) { + if ($self->print->config->gap_fill_speed > 0 && $self->config->fill_density > 0) { my $diff = diff_ex( offset(\@last, -0.5*$pspacing), offset(\@offsets, +0.5*$pspacing), @@ -277,8 +277,8 @@ sub make_perimeters { # we continue inwards after having finished the brim # TODO: add test for perimeter order @loops = reverse @loops - if $self->config->external_perimeters_first - || ($self->layer->id == 0 && $self->config->brim_width > 0); + if $self->print->config->external_perimeters_first + || ($self->layer->id == 0 && $self->print->config->brim_width > 0); # append perimeters $self->perimeters->append(@loops); diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 4c9b9d79e..d490597db 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -70,9 +70,9 @@ sub init_config { sub apply_config { my ($self, $config) = @_; - $self->config->apply($config); - $self->default_object_config->apply($config); - $self->default_region_config->apply($config); + $self->config->apply_dynamic($config); + $self->default_object_config->apply_dynamic($config); + $self->default_region_config->apply_dynamic($config); $self->init_config; } @@ -94,14 +94,14 @@ sub add_model_object { my $volume = $object->volumes->[$volume_id]; # get the config applied to this volume: start from our global defaults - my $config = Slic3r::Config::RegionConfig->new; + my $config = Slic3r::Config::PrintRegion->new; $config->apply($self->default_region_config); # override the defaults with per-object config and then with per-material config - $config->apply($object->config); + $config->apply_dynamic($object->config); if (defined $volume->material_id) { my $material_config = $object->model->materials->{ $volume->material_id }->config; - $config->apply($material_config); + $config->apply_dynamic($material_config); } # find an existing print region with the same config @@ -139,7 +139,7 @@ sub add_model_object { # apply config to print object $o->config->apply($self->default_object_config); - $o->config->apply($object->config); + $o->config->apply_dynamic($object->config); # store print object at the given position if (defined $obj_idx) { diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 2e9f3dfe0..600a0dcc8 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -13,7 +13,7 @@ has 'print' => (is => 'ro', weak_ref => 1, required => 1); has 'model_object' => (is => 'ro', required => 1); has 'region_volumes' => (is => 'rw', default => sub { [] }); # by region_id has 'copies' => (is => 'ro'); # Slic3r::Point objects in scaled G-code coordinates -has 'config' => (is => 'rw', required => 1); # Slic3r::Config::PrintObject +has 'config' => (is => 'ro', default => sub { Slic3r::Config::PrintObject->new }); has 'layer_height_ranges' => (is => 'rw', default => sub { [] }); # [ z_min, z_max, layer_height ] has 'size' => (is => 'rw'); # XYZ in scaled coordinates @@ -273,8 +273,8 @@ sub slice { } # simplify slices if required - if ($self->config->resolution) { - $self->_simplify_slices(scale($self->config->resolution)); + if ($self->print->config->resolution) { + $self->_simplify_slices(scale($self->print->config->resolution)); } } @@ -288,8 +288,11 @@ sub make_perimeters { # but we don't generate any extra perimeter if fill density is zero, as they would be floating # inside the object - infill_only_where_needed should be the method of choice for printing # hollow objects - if ($self->config->extra_perimeters && $self->config->perimeters > 0 && $self->config->fill_density > 0) { - for my $region_id (0 .. ($self->print->regions_count-1)) { + for my $region_id (0 .. ($self->print->regions_count-1)) { + my $region = $self->print->regions->[$region_id]; + my $region_perimeters = $region->config->perimeters; + + if ($region->config->extra_perimeters && $region_perimeters > 0 && $region->config->fill_density > 0) { for my $layer_id (0 .. $self->layer_count-2) { my $layerm = $self->layers->[$layer_id]->regions->[$region_id]; my $upper_layerm = $self->layers->[$layer_id+1]->regions->[$region_id]; @@ -298,7 +301,7 @@ sub make_perimeters { my $overlap = $perimeter_spacing; # one perimeter my $diff = diff( - offset([ map @{$_->expolygon}, @{$layerm->slices} ], -($self->config->perimeters * $perimeter_spacing)), + offset([ map @{$_->expolygon}, @{$layerm->slices} ], -($region_perimeters * $perimeter_spacing)), offset([ map @{$_->expolygon}, @{$upper_layerm->slices} ], -$overlap), ); next if !@$diff; @@ -322,8 +325,8 @@ sub make_perimeters { # of our slice $extra_perimeters++; my $hypothetical_perimeter = diff( - offset($slice->expolygon->arrayref, -($perimeter_spacing * ($self->config->perimeters + $extra_perimeters-1))), - offset($slice->expolygon->arrayref, -($perimeter_spacing * ($self->config->perimeters + $extra_perimeters))), + offset($slice->expolygon->arrayref, -($perimeter_spacing * ($region_perimeters + $extra_perimeters-1))), + offset($slice->expolygon->arrayref, -($perimeter_spacing * ($region_perimeters + $extra_perimeters))), ); last CYCLE if !@$hypothetical_perimeter; # no extra perimeter is possible @@ -339,7 +342,7 @@ sub make_perimeters { } Slic3r::parallelize( - threads => $self->config->threads, + threads => $self->print->config->threads, items => sub { 0 .. ($self->layer_count-1) }, thread_cb => sub { my $q = shift; @@ -376,7 +379,7 @@ sub detect_surfaces_type { ); # collapse very narrow parts (using the safety offset in the diff is not enough) - my $offset = $layerm->perimeter_flow->scaled_width / 10; + my $offset = $layerm->flow(FLOW_ROLE_PERIMETER)->scaled_width / 10; return map Slic3r::Surface->new(expolygon => $_, surface_type => $result_type), @{ offset2_ex($diff, -$offset, +$offset) }; }; @@ -609,8 +612,8 @@ sub discover_horizontal_shells { for (my $i = 0; $i < $self->layer_count; $i++) { my $layerm = $self->layers->[$i]->regions->[$region_id]; - if ($self->config->solid_infill_every_layers && $self->config->fill_density > 0 - && ($i % $self->config->solid_infill_every_layers) == 0) { + if ($layerm->config->solid_infill_every_layers && $layerm->config->fill_density > 0 + && ($i % $layerm->config->solid_infill_every_layers) == 0) { $_->surface_type(S_TYPE_INTERNALSOLID) for @{$layerm->fill_surfaces->filter_by_type(S_TYPE_INTERNAL)}; } @@ -632,8 +635,8 @@ sub discover_horizontal_shells { Slic3r::debugf "Layer %d has %s surfaces\n", $i, ($type == S_TYPE_TOP) ? 'top' : 'bottom'; my $solid_layers = ($type == S_TYPE_TOP) - ? $self->config->top_solid_layers - : $self->config->bottom_solid_layers; + ? $layerm->config->top_solid_layers + : $layerm->config->bottom_solid_layers; NEIGHBOR: for (my $n = ($type == S_TYPE_TOP) ? $i-1 : $i+1; abs($n - $i) <= $solid_layers-1; ($type == S_TYPE_TOP) ? $n-- : $n++) { @@ -668,7 +671,7 @@ sub discover_horizontal_shells { # get a triangle in $too_narrow; if we grow it below then the shell # would have a different shape from the external surface and we'd still # have the same angle, so the next shell would be grown even more and so on. - my $margin = 3 * $layerm->solid_infill_flow->scaled_width; # require at least this size + my $margin = 3 * $layerm->flow(FLOW_ROLE_SOLID_INFILL)->scaled_width; # require at least this size my $too_narrow = diff( $new_internal_solid, offset2($new_internal_solid, -$margin, +$margin, CLIPPER_OFFSET_SCALE, JT_MITER, 5), @@ -677,7 +680,7 @@ sub discover_horizontal_shells { # if some parts are going to collapse, use a different strategy according to fill density if (@$too_narrow) { - if ($self->config->fill_density > 0) { + if ($layerm->config->fill_density > 0) { # if we have internal infill, grow the collapsing parts and add the extra area to # the neighbor layer as well as to our original surfaces so that we support this # additional area in the next shell too @@ -741,13 +744,16 @@ sub discover_horizontal_shells { # combine fill surfaces across layers sub combine_infill { my $self = shift; - return unless $self->config->infill_every_layers > 1 && $self->config->fill_density > 0; - my $every = $self->config->infill_every_layers; + + return unless defined first { $_->config->infill_every_layers > 1 && $_->config->fill_density > 0 } @{$self->print->regions}; my $layer_count = $self->layer_count; my @layer_heights = map $self->layers->[$_]->height, 0 .. $layer_count-1; for my $region_id (0 .. ($self->print->regions_count-1)) { + my $region = $self->print->regions->[$region_id]; + my $every = $region->config->infill_every_layers; + # limit the number of combined layers to the maximum height allowed by this regions' nozzle my $nozzle_diameter = $self->print->regions->[$region_id]->extruders->{infill}->nozzle_diameter; @@ -805,7 +811,7 @@ sub combine_infill { + $layerms[-1]->perimeter_flow->scaled_width / 2 # Because fill areas for rectilinear and honeycomb are grown # later to overlap perimeters, we need to counteract that too. - + (($type == S_TYPE_INTERNALSOLID || $self->config->fill_pattern =~ /(rectilinear|honeycomb)/) + + (($type == S_TYPE_INTERNALSOLID || $region->config->fill_pattern =~ /(rectilinear|honeycomb)/) ? $layerms[-1]->solid_infill_flow->scaled_width * &Slic3r::INFILL_OVERLAP_OVER_SPACING : 0) )}, @$intersection; diff --git a/lib/Slic3r/Print/Region.pm b/lib/Slic3r/Print/Region.pm index 2b5d445de..4cb929e0b 100644 --- a/lib/Slic3r/Print/Region.pm +++ b/lib/Slic3r/Print/Region.pm @@ -8,7 +8,7 @@ use Slic3r::Flow ':roles'; # sharing the same config (including the same assigned extruder(s)) has 'print' => (is => 'ro', required => 1, weak_ref => 1); -has 'config' => (is => 'ro', required => 1); # Slic3r::Config::RegionConfig +has 'config' => (is => 'ro', default => sub { Slic3r::Config::PrintRegion->new}); sub flow { my ($self, $role, $layer_height, $bridge, $first_layer, $width) = @_; @@ -21,7 +21,7 @@ sub flow { if (!defined $config_width) { # get extrusion width from configuration # (might be an absolute value, or a percent value, or zero for auto) - if ($first_layer && $self->config->first_layer_extrusion_width != 0) { + if ($first_layer && $self->config->first_layer_extrusion_width ne '0') { $config_width = $self->config->first_layer_extrusion_width; } elsif ($role == FLOW_ROLE_PERIMETER) { $config_width = $self->config->perimeter_extrusion_width; @@ -40,9 +40,9 @@ sub flow { # to the flow role requested my $extruder; # 1-based if ($role == FLOW_ROLE_PERIMETER) { - $config_width = $self->config->perimeter_extruder; + $extruder = $self->config->perimeter_extruder; } elsif ($role == FLOW_ROLE_INFILL || $role == FLOW_ROLE_SOLID_INFILL || $role == FLOW_ROLE_TOP_SOLID_INFILL) { - $config_width = $self->config->infill_extruder; + $extruder = $self->config->infill_extruder; } else { die "Unknown role $role"; } diff --git a/xs/src/PrintConfig.hpp b/xs/src/PrintConfig.hpp index 0c9678206..4643c8b70 100644 --- a/xs/src/PrintConfig.hpp +++ b/xs/src/PrintConfig.hpp @@ -956,7 +956,6 @@ class PrintObjectConfig : public virtual StaticConfig if (opt_key == "support_material_speed") return &this->support_material_speed; if (opt_key == "support_material_threshold") return &this->support_material_threshold; - if (create) throw "Attempt to create non-existing option in StaticConfig object"; return NULL; }; }; @@ -1039,7 +1038,6 @@ class PrintRegionConfig : public virtual StaticConfig if (opt_key == "top_infill_extrusion_width") return &this->top_infill_extrusion_width; if (opt_key == "top_solid_layers") return &this->top_solid_layers; - if (create) throw "Attempt to create non-existing option in StaticConfig object"; return NULL; }; }; @@ -1332,7 +1330,6 @@ class PrintConfig : public virtual StaticConfig if (opt_key == "wipe") return &this->wipe; if (opt_key == "z_offset") return &this->z_offset; - if (create) throw "Attempt to create non-existing option in StaticConfig object"; return NULL; }; }; @@ -1345,7 +1342,15 @@ class DynamicPrintConfig : public DynamicConfig }; }; -class FullPrintConfig : public PrintObjectConfig, public PrintRegionConfig, public PrintConfig {}; +class FullPrintConfig : public PrintObjectConfig, public PrintRegionConfig, public PrintConfig { + ConfigOption* option(const t_config_option_key opt_key, bool create = false) { + ConfigOption* opt; + if ((opt = PrintObjectConfig::option(opt_key, create)) != NULL) return opt; + if ((opt = PrintRegionConfig::option(opt_key, create)) != NULL) return opt; + if ((opt = PrintConfig::option(opt_key, create)) != NULL) return opt; + return NULL; + }; +}; } diff --git a/xs/t/15_config.t b/xs/t/15_config.t index 699f115f8..4e8f6e68a 100644 --- a/xs/t/15_config.t +++ b/xs/t/15_config.t @@ -6,7 +6,7 @@ use warnings; use Slic3r::XS; use Test::More tests => 79; -foreach my $config (Slic3r::Config->new, Slic3r::Config::Print->new) { +foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) { $config->set('layer_height', 0.3); ok abs($config->get('layer_height') - 0.3) < 1e-4, 'set/get float'; is $config->serialize('layer_height'), '0.3', 'serialize float'; @@ -94,13 +94,13 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Print->new) { # test that no crash happens when using set_deserialize() with a key that hasn't been set() yet $config->set_deserialize('filament_diameter', '3'); - my $config2 = Slic3r::Config::Print->new; + my $config2 = Slic3r::Config::Full->new; $config2->apply_dynamic($config); is $config2->get('perimeters'), 2, 'apply_dynamic'; } { - my $config = Slic3r::Config::Print->new; + my $config = Slic3r::Config::Full->new; my $config2 = Slic3r::Config->new; $config2->apply_static($config); is $config2->get('perimeters'), Slic3r::Config::print_config_def()->{perimeters}{default}, 'apply_static and print_config_def'; diff --git a/xs/xsp/Config.xsp b/xs/xsp/Config.xsp index 80b00c116..5c3966e13 100644 --- a/xs/xsp/Config.xsp +++ b/xs/xsp/Config.xsp @@ -15,7 +15,8 @@ void set_deserialize(t_config_option_key opt_key, std::string str); std::string serialize(t_config_option_key opt_key); double get_abs_value(t_config_option_key opt_key); - double get_abs_value(t_config_option_key opt_key, double ratio_over); + %name{get_abs_value_over} + double get_abs_value(t_config_option_key opt_key, double ratio_over); void apply(DynamicPrintConfig* other) %code{% THIS->apply(*other, true); %}; void apply_static(PrintConfig* other) @@ -34,16 +35,17 @@ void set_deserialize(t_config_option_key opt_key, std::string str); std::string serialize(t_config_option_key opt_key); double get_abs_value(t_config_option_key opt_key); - double get_abs_value(t_config_option_key opt_key, double ratio_over); + %name{get_abs_value_over} + double get_abs_value(t_config_option_key opt_key, double ratio_over); void apply_dynamic(DynamicPrintConfig* other) %code{% THIS->apply(*other, true); %}; std::vector get_keys() %code{% THIS->keys(&RETVAL); %}; }; -%name{Slic3r::Config::Print} class PrintConfig { - PrintConfig(); - ~PrintConfig(); +%name{Slic3r::Config::PrintRegion} class PrintRegionConfig { + PrintRegionConfig(); + ~PrintRegionConfig(); bool has(t_config_option_key opt_key); SV* as_hash(); SV* get(t_config_option_key opt_key); @@ -51,16 +53,19 @@ void set_deserialize(t_config_option_key opt_key, std::string str); std::string serialize(t_config_option_key opt_key); double get_abs_value(t_config_option_key opt_key); - double get_abs_value(t_config_option_key opt_key, double ratio_over); + %name{get_abs_value_over} + double get_abs_value(t_config_option_key opt_key, double ratio_over); + void apply(PrintRegionConfig* other) + %code{% THIS->apply(*other, true); %}; void apply_dynamic(DynamicPrintConfig* other) %code{% THIS->apply(*other, true); %}; std::vector get_keys() %code{% THIS->keys(&RETVAL); %}; }; -%name{Slic3r::Config::Print} class PrintConfig { - PrintConfig(); - ~PrintConfig(); +%name{Slic3r::Config::PrintObject} class PrintObjectConfig { + PrintObjectConfig(); + ~PrintObjectConfig(); bool has(t_config_option_key opt_key); SV* as_hash(); SV* get(t_config_option_key opt_key); @@ -68,7 +73,30 @@ void set_deserialize(t_config_option_key opt_key, std::string str); std::string serialize(t_config_option_key opt_key); double get_abs_value(t_config_option_key opt_key); - double get_abs_value(t_config_option_key opt_key, double ratio_over); + %name{get_abs_value_over} + double get_abs_value(t_config_option_key opt_key, double ratio_over); + void apply(PrintObjectConfig* other) + %code{% THIS->apply(*other, true); %}; + void apply_dynamic(DynamicPrintConfig* other) + %code{% THIS->apply(*other, true); %}; + std::vector get_keys() + %code{% THIS->keys(&RETVAL); %}; +}; + +%name{Slic3r::Config::Full} class FullPrintConfig { + FullPrintConfig(); + ~FullPrintConfig(); + bool has(t_config_option_key opt_key); + SV* as_hash(); + SV* get(t_config_option_key opt_key); + void set(t_config_option_key opt_key, SV* value); + void set_deserialize(t_config_option_key opt_key, std::string str); + std::string serialize(t_config_option_key opt_key); + double get_abs_value(t_config_option_key opt_key); + %name{get_abs_value_over} + double get_abs_value(t_config_option_key opt_key, double ratio_over); + void apply(PrintObjectConfig* other) + %code{% THIS->apply(*other, true); %}; void apply_dynamic(DynamicPrintConfig* other) %code{% THIS->apply(*other, true); %}; std::vector get_keys() @@ -83,7 +111,8 @@ PROTOTYPES: DISABLE SV* print_config_def() CODE: - t_optiondef_map* def = &PrintConfigDef::def; + FullPrintConfig config; + t_optiondef_map* def = config.def; HV* options_hv = newHV(); for (t_optiondef_map::iterator oit = def->begin(); oit != def->end(); ++oit) { diff --git a/xs/xsp/my.map b/xs/xsp/my.map index 7c370ac10..666cbf616 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -2,7 +2,10 @@ std::vector T_STD_VECTOR_INT t_config_option_key T_STD_STRING DynamicPrintConfig* O_OBJECT +PrintObjectConfig* O_OBJECT +PrintRegionConfig* O_OBJECT PrintConfig* O_OBJECT +FullPrintConfig* O_OBJECT ZTable* O_OBJECT TriangleMesh* O_OBJECT Point* O_OBJECT diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index eb6302e7d..25c4c4d12 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -9,7 +9,10 @@ %typemap{AV*}; %typemap{Point*}; %typemap{DynamicPrintConfig*}; +%typemap{PrintObjectConfig*}; +%typemap{PrintRegionConfig*}; %typemap{PrintConfig*}; +%typemap{FullPrintConfig*}; %typemap{ExPolygon*}; %typemap{ExPolygonCollection*}; %typemap{Line*};