diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 156a9f7e7da..5edf6e0b707 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -194,6 +194,7 @@ class PrintObject SlicingParameters slicing_parameters() const; void _slice(); + void _offsetHoles(float hole_delta, LayerRegion *layerm); std::string _fix_slicing_errors(); void _simplify_slices(double distance); void _prepare_infill(); diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index bb587a74acb..83c5d5c9ee4 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -2240,11 +2240,21 @@ PrintConfigDef::PrintConfigDef() def->category = L("Advanced"); def->tooltip = L("The object will be grown/shrunk in the XY plane by the configured value " "(negative = inwards, positive = outwards). This might be useful " - "for fine-tuning hole sizes."); + "for fine-tuning sizes."); def->sidetext = L("mm"); def->cli = "xy-size-compensation=f"; def->default_value = new ConfigOptionFloat(0); + def = this->add("hole_size_compensation", coFloat); + def->label = L("Holes"); + def->category = L("Advanced"); + def->tooltip = L("The convex holes will be grown in the XY plane by the configured value" + " (negative = inwards, positive = outwards, should be positive as the holes are always a bit smaller)." + " This might be useful for fine-tuning hole sizes."); + def->sidetext = L("mm"); + def->cli = "hole-size-compensation=f"; + def->default_value = new ConfigOptionFloat(0); + def = this->add("z_offset", coFloat); def->label = L("Z offset"); def->tooltip = L("This value will be added (or subtracted) from all the Z coordinates " diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 4c8c21e9793..31575304825 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -339,6 +339,7 @@ class PrintObjectConfig : public StaticPrintConfig ConfigOptionBool support_material_with_sheath; ConfigOptionFloatOrPercent support_material_xy_spacing; ConfigOptionFloat xy_size_compensation; + ConfigOptionFloat hole_size_compensation; ConfigOptionBool wipe_into_objects; protected: @@ -376,6 +377,7 @@ class PrintObjectConfig : public StaticPrintConfig OPT_PTR(support_material_threshold); OPT_PTR(support_material_with_sheath); OPT_PTR(xy_size_compensation); + OPT_PTR(hole_size_compensation); OPT_PTR(wipe_into_objects); } }; diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 575c030fd3f..03299bb8d77 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -169,7 +169,8 @@ bool PrintObject::invalidate_state_by_config_options(const std::vectorlayers[layer_id]; // Apply size compensation and perform clipping of multi-part objects. float delta = float(scale_(this->config.xy_size_compensation.value)); + float hole_delta = float(scale_(this->config.hole_size_compensation.value)); if (layer_id == 0) delta += float(scale_(this->config.elefant_foot_compensation.value)); bool scale = delta != 0.f; @@ -1585,7 +1587,8 @@ void PrintObject::_slice() LayerRegion *layerm = layer->regions.front(); layerm->slices.set(offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta), stInternal); } - } else if (scale || clip) { + _offsetHoles(hole_delta, layer->regions.front()); + } else if (scale || clip || hole_delta != 0.f) { // 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; @@ -1601,6 +1604,7 @@ void PrintObject::_slice() // Collect the already processed regions to trim the to be processed regions. polygons_append(processed, slices); layerm->slices.set(std::move(slices), stInternal); + _offsetHoles(hole_delta, layerm); } } // Merge all regions' slices to get islands, chain them by a shortest path. @@ -1610,6 +1614,45 @@ void PrintObject::_slice() BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - end"; } +void PrintObject::_offsetHoles(float hole_delta, LayerRegion *layerm) { + if (hole_delta != 0.f) { + ExPolygons& polys = to_expolygons(std::move(layerm->slices.surfaces)); + ExPolygons new_polys; + for (ExPolygon ex_poly : polys) { + ExPolygon new_ex_poly(ex_poly); + new_ex_poly.holes.clear(); + for (Polygon hole : ex_poly.holes) { + //check if convex to reduce it + // check whether first point forms a convex angle + bool ok = true; + ok = (hole.points.front().ccw_angle(hole.points.back(), *(hole.points.begin() + 1)) <= PI + 0.001); + + + // check whether points 1..(n-1) form convex angles + if (ok) + for (Points::const_iterator p = hole.points.begin() + 1; p != hole.points.end() - 1; ++p) { + ok = (p->ccw_angle(*(p - 1), *(p + 1)) <= PI + 0.001); + if (!ok) break; + } + + // check whether last point forms a convex angle + ok &= (hole.points.back().ccw_angle(*(hole.points.end() - 2), hole.points.front()) <= PI + 0.001); + + if (ok) { + for (Polygon newHole : offset(hole, hole_delta)) { + //reverse because it's a hole, not an object + newHole.make_clockwise(); + new_ex_poly.holes.push_back(newHole); + } + } else + new_ex_poly.holes.push_back(hole); + } + new_polys.push_back(new_ex_poly); + } + layerm->slices.set(std::move(new_polys), stInternal); + } +} + std::vector PrintObject::_slice_region(size_t region_id, const std::vector &z, bool modifier) { std::vector layers; diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index 9ac1f9a75b9..5e391bc0954 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -298,10 +298,11 @@ const std::vector& Preset::print_options() "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "over_bridge_flow_ratio", "clip_multipart_objects", "enforce_full_fill_volume", "external_infill_margin", "bridged_infill_margin", - "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", - "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "only_one_perimeter_top", "compatible_printers", - "compatible_printers_condition", "inherits", "infill_dense_layers", "infill_dense_density", "infill_dense_pattern", - "infill_dense_angle", "no_perimeter_unsupported", "min_perimeter_unsupported", "noperi_bridge_only" + "elefant_foot_compensation", "xy_size_compensation", "hole_size_compensation", "threads", "resolution", + "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", + "only_one_perimeter_top", "compatible_printers", "compatible_printers_condition", "inherits", + "infill_dense_layers", "infill_dense_density", "infill_dense_pattern", "infill_dense_angle", + "no_perimeter_unsupported", "min_perimeter_unsupported", "noperi_bridge_only" }; return s_opts; } diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index 7ab0262de4c..db28bf581e0 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -978,6 +978,7 @@ void TabPrint::build() line = { _(L("XY compensation")), "" }; line.append_option(optgroup->get_option("xy_size_compensation")); line.append_option(optgroup->get_option("elefant_foot_compensation")); + line.append_option(optgroup->get_option("hole_size_compensation")); optgroup->append_line(line); // # optgroup->append_single_option_line("threads"); optgroup->append_single_option_line("resolution");