diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 845c57b84..e06fde2ff 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -557,7 +557,7 @@ sub build { external_perimeter_extrusion_width infill_extrusion_width solid_infill_extrusion_width top_infill_extrusion_width support_material_extrusion_width infill_overlap bridge_flow_ratio - xy_size_compensation threads resolution + clip_multipart_objects xy_size_compensation threads resolution )); $self->{config}->set('print_settings_id', ''); @@ -750,6 +750,7 @@ sub build { } { my $optgroup = $page->new_optgroup('Other'); + $optgroup->append_single_option_line('clip_multipart_objects'); $optgroup->append_single_option_line('xy_size_compensation'); $optgroup->append_single_option_line('threads') if $Slic3r::have_threads; $optgroup->append_single_option_line('resolution'); diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 5ccd38b41..87d0398ca 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -425,7 +425,7 @@ sub write_gcode { # Wait for 1/4 seconds and try to rename once again. select(undef, undef, undef, 0.25); } - Slic3r::debugf "Faild to remove the output G-code file from $tempfile to $file. Is $tempfile locked?\n" if ($i == 5); + Slic3r::debugf "Failed to remove the output G-code file from $tempfile to $file. Is $tempfile locked?\n" if ($i == 5); } } diff --git a/slic3r.pl b/slic3r.pl index bb7006a25..c1371472f 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -497,6 +497,9 @@ $j --dont-arrange Don't arrange the objects on the build plate. The model coordinates define the absolute positions on the build plate. The option --print-center will be ignored. + --clip_multipart_objects When printing multi-material objects, this settings will make slic3r to clip the overlapping + object parts one by the other (2nd part will be clipped by the 1st, 3rd part will be clipped + by the 1st and 2nd etc). (default: $config->{clip_multipart_objects})"; --xy-size-compensation Grow/shrink objects by the configured absolute distance (mm, default: $config->{xy_size_compensation}) diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 8c002aab6..d7cb66d03 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -96,6 +96,12 @@ PrintConfigDef::PrintConfigDef() def->min = 0; def->default_value = new ConfigOptionFloat(0); + def = this->add("clip_multipart_objects", coBool); + def->label = "Clip multi-part objects"; + def->tooltip = "When printing multi-material objects, this settings will make slic3r to clip the overlapping object parts one by the other (2nd part will be clipped by the 1st, 3rd part will be clipped by the 1st and 2nd etc)."; + def->cli = "clip-multipart-objects!"; + def->default_value = new ConfigOptionBool(false); + def = this->add("complete_objects", coBool); def->label = "Complete individual objects"; def->tooltip = "When printing multiple objects or copies, this feature will complete each object before moving onto next one (and starting it from its bottom layer). This feature is useful to avoid the risk of ruined prints. Slic3r should warn and prevent you from extruder collisions, but beware."; diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 5ee787285..4ed822511 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -138,6 +138,7 @@ class StaticPrintConfig : public PrintConfigBase, public StaticConfig class PrintObjectConfig : public virtual StaticPrintConfig { public: + ConfigOptionBool clip_multipart_objects; ConfigOptionBool dont_support_bridges; ConfigOptionFloatOrPercent extrusion_width; ConfigOptionFloatOrPercent first_layer_height; @@ -175,6 +176,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig } virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) { + OPT_PTR(clip_multipart_objects); OPT_PTR(dont_support_bridges); OPT_PTR(extrusion_width); OPT_PTR(first_layer_height); diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 0f426005d..b601f77c6 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -221,7 +221,8 @@ PrintObject::invalidate_state_by_config_options(const std::vectorreset_layer_height_profile(); } - else if (*opt_key == "xy_size_compensation") { + else if (*opt_key == "clip_multipart_objects" + || *opt_key == "xy_size_compensation") { steps.insert(posSlice); } else if (*opt_key == "support_material" || *opt_key == "support_material_angle" @@ -1091,48 +1092,34 @@ end: for (size_t layer_id = 0; layer_id < layers.size(); ++ layer_id) { Layer *layer = this->layers[layer_id]; - // apply size compensation - if (this->config.xy_size_compensation.value != 0.) { - float delta = float(scale_(this->config.xy_size_compensation.value)); - if (layer->regions.size() == 1) { - // single region + // Apply size compensation and perform clipping of multi-part objects. + float delta = float(scale_(this->config.xy_size_compensation.value)); + bool scale = delta != 0.f; + bool clip = this->config.clip_multipart_objects.value || delta > 0.f; + if (layer->regions.size() == 1) { + if (scale) { + // Single region, growing or shrinking. LayerRegion *layerm = layer->regions.front(); layerm->slices.set(offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta), stInternal); - } else { - if (delta < 0) { - // multiple regions, shrinking - // we apply the offset to the combined shape, then intersect it - // with the original slices for each region - Polygons region_slices; - for (size_t region_id = 0; region_id < layer->regions.size(); ++ region_id) - polygons_append(region_slices, layer->regions[region_id]->slices.surfaces); - Polygons slices = offset(union_(region_slices), delta); - for (size_t region_id = 0; region_id < layer->regions.size(); ++ region_id) { - LayerRegion *layerm = layer->regions[region_id]; - layerm->slices.set(std::move(intersection_ex(slices, to_polygons(std::move(layerm->slices.surfaces)))), stInternal); - } - } else { - // multiple regions, growing - // this is an ambiguous case, since it's not clear how to grow regions where they are going to overlap - // so we give priority to the first one and so on - Polygons processed; - for (size_t region_id = 0;; ++ region_id) { - LayerRegion *layerm = layer->regions[region_id]; - ExPolygons slices = offset_ex(to_expolygons(layerm->slices.surfaces), delta); - if (region_id > 0) - // Trim by the slices of already processed regions. - slices = diff_ex(to_polygons(std::move(slices)), processed); - if (region_id + 1 == layer->regions.size()) { - layerm->slices.set(std::move(slices), stInternal); - break; - } - polygons_append(processed, slices); - layerm->slices.set(std::move(slices), stInternal); - } - } + } + } else if (scale || clip) { + // Multiple regions, growing, shrinking or just clipping one region by the other. + // When clipping the regions, priority is given to the first regions. + Polygons processed; + for (size_t region_id = 0; region_id < layer->regions.size(); ++ region_id) { + LayerRegion *layerm = layer->regions[region_id]; + ExPolygons slices = to_expolygons(std::move(layerm->slices.surfaces)); + if (scale) + slices = offset_ex(slices, delta); + if (region_id > 0 && clip) + // Trim by the slices of already processed regions. + slices = diff_ex(to_polygons(std::move(slices)), processed); + if (clip && region_id + 1 < layer->regions.size()) + // Collect the already processed regions to trim the to be processed regions. + polygons_append(processed, slices); + layerm->slices.set(std::move(slices), stInternal); } } - // Merge all regions' slices to get islands, chain them by a shortest path. layer->make_slices(); } diff --git a/xs/src/libslic3r/Surface.hpp b/xs/src/libslic3r/Surface.hpp index d64607ff5..147901334 100644 --- a/xs/src/libslic3r/Surface.hpp +++ b/xs/src/libslic3r/Surface.hpp @@ -107,6 +107,16 @@ inline ExPolygons to_expolygons(const Surfaces &src) return expolygons; } +inline ExPolygons to_expolygons(Surfaces &&src) +{ + ExPolygons expolygons; + expolygons.reserve(src.size()); + for (Surfaces::const_iterator it = src.begin(); it != src.end(); ++it) + expolygons.emplace_back(ExPolygon(std::move(it->expolygon))); + src.clear(); + return expolygons; +} + inline ExPolygons to_expolygons(const SurfacesPtr &src) { ExPolygons expolygons;