New parameter "support_material_min_diameter" to filter out

support overhangs with enclosing circle diameter smaller than
the new parameter.
This commit is contained in:
Vojtech Bubnik 2021-11-02 12:21:33 +01:00
parent 4e9f906848
commit e2169484a3
10 changed files with 104 additions and 4 deletions

View File

@ -141,6 +141,10 @@ Circle<Vector> smallest_enclosing_circle_welzl(const Points &points, const typen
}
// Randomized algorithm by Emo Welzl. The returned circle radius is inflated by SCALED_EPSILON.
inline CircleSqd smallest_enclosing_circle2_welzl(const Points &points)
{
return smallest_enclosing_circle2_welzl<Vec2d, Points>(points, SCALED_EPSILON);
}
inline Circled smallest_enclosing_circle_welzl(const Points &points)
{
return smallest_enclosing_circle_welzl<Vec2d, Points>(points, SCALED_EPSILON);

View File

@ -1,9 +1,13 @@
#include "BoundingBox.hpp"
#include "ClipperUtils.hpp"
#include "Exception.hpp"
#include "Geometry/Circle.hpp"
#include "Polygon.hpp"
#include "Polyline.hpp"
#include <algorithm>
#include <random>
namespace Slic3r {
Lines Polygon::lines() const
@ -437,6 +441,8 @@ bool remove_degenerate(Polygons &polys)
return modified;
}
// Remove polygons with absolute area smaller then threshold.
// Thus this function may fill holes of some polygons, which may not be what one expects.
bool remove_small(Polygons &polys, double min_area)
{
bool modified = false;
@ -454,6 +460,69 @@ bool remove_small(Polygons &polys, double min_area)
return modified;
}
// Remove polygons with minimum enclosing circle diameter smaller than min_diameter.
// Again, this function may fill holes of some polygons, which may not be what one expects.
void remove_with_small_diameter(Polygons &polygons, double min_diameter)
{
coord_t min_size = coord_t(min_diameter);
double min_diameter2 = min_diameter * min_diameter;
std::mt19937 g;
Points poly_shuffled;
size_t end = 0;
for (size_t i = 0; i < polygons.size(); ++ i) {
Polygon &poly = polygons[i];
bool keep = true;
if (poly.size() < 2) {
keep = false;
} else {
Point pmin = poly.front();
Point pmax = poly.points[1];
for (size_t k = 2; k < poly.size(); ++k) {
const Point& p = poly.points[k];
pmin = pmin.cwiseMin(p);
pmax = pmax.cwiseMax(p);
if (pmax.x() - pmin.x() > min_size || pmax.y() - pmin.y() > min_size) {
// Diameter of the polygon is certainly above min_diameter.
keep = true;
break;
}
}
if (! keep) {
// Measure diameter of a circumscribed circle around the polygon's bounding box.
Vec2d size = pmax.cast<double>() - pmin.cast<double>();
if (size.squaredNorm() > min_diameter2) {
// There is a chance that the diameter of a polygon is above min_diameter.
poly_shuffled = poly.points;
std::shuffle(poly_shuffled.begin(), poly_shuffled.end(), g);
if (Geometry::CircleSqd circle = Geometry::smallest_enclosing_circle2_welzl(poly_shuffled); circle.radius2 > 0.25 * min_diameter2)
keep = true;
}
}
}
#if 0
//FIXME implement smarter removal of holes: Holes shall not be removed if their outer contour was not removed.
if (!keep) {
if (poly.is_counter_clockwise()) {
// Remove the outer contour.
if (i < --end) {
std::swap(poly, polygons[end])
--i;
}
}
else
holes.emplace_back(std::move(poly));
}
#else
if (keep) {
if (end < i)
polygons[end] = std::move(poly);
++ end;
}
#endif
polygons.erase(polygons.begin() + end, polygons.end());
}
}
void remove_collinear(Polygon &poly)
{
if (poly.points.size() > 2) {

View File

@ -112,7 +112,12 @@ bool remove_sticks(Polygons &polys);
// Remove polygons with less than 3 edges.
bool remove_degenerate(Polygons &polys);
// Remove polygons with absolute area smaller then threshold.
// Thus this function may fill holes of some polygons, which may not be what one expects.
bool remove_small(Polygons &polys, double min_area);
// Remove polygons with minimum enclosing circle diameter smaller than min_diameter.
// Again, this function may fill holes of some polygons, which may not be what one expects.
void remove_with_small_diameter(Polygons& polygons, double min_diameter);
void remove_collinear(Polygon &poly);
void remove_collinear(Polygons &polys);

View File

@ -434,7 +434,7 @@ static std::vector<std::string> s_Preset_print_options {
"raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion",
"support_material_pattern", "support_material_with_sheath", "support_material_spacing", "support_material_closing_radius", "support_material_style",
"support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_bottom_interface_layers",
"support_material_interface_pattern", "support_material_interface_spacing", "support_material_interface_contact_loops",
"support_material_interface_pattern", "support_material_interface_spacing", "support_material_interface_contact_loops", "support_material_min_diameter",
"support_material_contact_distance", "support_material_bottom_contact_distance",
"support_material_buildplate_only", "dont_support_bridges", "thick_bridges", "notes", "complete_objects", "extruder_clearance_radius",
"extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "perimeter_extruder",

View File

@ -2670,6 +2670,18 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<SupportMaterialPattern>(smpRectilinear));
def = this->add("support_material_min_diameter", coFloat);
def->label = L("Minimum support size");
def->category = L("Support material");
def->tooltip = L("Minimum diameter of an overhang to be supported. "
"Increasing this value will filter out likely unneccessary supports of tiny overhangs protruding from an object body. "
"However filtering small overhangs may leave some long thin features unsupported, "
"requiring user intervention using the paint-on supports tool.");
def->sidetext = L("mm");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("support_material_spacing", coFloat);
def->label = L("Pattern spacing");
def->category = L("Support material");

View File

@ -492,6 +492,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, support_material_interface_spacing))
((ConfigOptionFloatOrPercent, support_material_interface_speed))
((ConfigOptionEnum<SupportMaterialPattern>, support_material_pattern))
((ConfigOptionFloat, support_material_min_diameter))
((ConfigOptionEnum<SupportMaterialInterfacePattern>, support_material_interface_pattern))
// Morphological closing of support areas. Only used for "sung" supports.
((ConfigOptionFloat, support_material_closing_radius))

View File

@ -554,6 +554,7 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "support_material_interface_contact_loops"
|| opt_key == "support_material_interface_extruder"
|| opt_key == "support_material_interface_spacing"
|| opt_key == "support_material_min_diameter"
|| opt_key == "support_material_pattern"
|| opt_key == "support_material_style"
|| opt_key == "support_material_xy_spacing"

View File

@ -1446,7 +1446,9 @@ static inline std::tuple<Polygons, Polygons, Polygons, float> detect_overhangs(
const PrintObjectConfig &object_config,
SupportAnnotations &annotations,
SlicesMarginCache &slices_margin,
const double gap_xy
const double gap_xy,
// Scaled, minimum diameter of a support island to be supported.
const double min_support_diameter
#ifdef SLIC3R_DEBUG
, size_t iRun
#endif // SLIC3R_DEBUG
@ -1601,6 +1603,10 @@ static inline std::tuple<Polygons, Polygons, Polygons, float> detect_overhangs(
SupportMaterialInternal::remove_bridges_from_contacts(
print_config, lower_layer, lower_layer_polygons, *layerm, fw, diff_polygons);
if (min_support_diameter > 0)
// Remove polygons with their circumscribed circle radius smaller than min_diameter.
remove_with_small_diameter(diff_polygons, min_support_diameter);
if (diff_polygons.empty())
continue;
@ -1995,6 +2001,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
tbb::parallel_for(tbb::blocked_range<size_t>(this->has_raft() ? 0 : 1, num_layers),
[this, &object, &annotations, &layer_storage, &layer_storage_mutex, &contact_out]
(const tbb::blocked_range<size_t>& range) {
const double min_support_diameter = scaled<double>(object.config().support_material_min_diameter.value);
for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id)
{
const Layer &layer = *object.layers()[layer_id];
@ -2002,7 +2009,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
SlicesMarginCache slices_margin;
auto [overhang_polygons, contact_polygons, enforcer_polygons, no_interface_offset] =
detect_overhangs(layer, layer_id, lower_layer_polygons, *m_print_config, *m_object_config, annotations, slices_margin, m_support_params.gap_xy
detect_overhangs(layer, layer_id, lower_layer_polygons, *m_print_config, *m_object_config, annotations, slices_margin, m_support_params.gap_xy, min_support_diameter
#ifdef SLIC3R_DEBUG
, iRun
#endif // SLIC3R_DEBUG

View File

@ -282,7 +282,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
bool have_support_soluble = have_support_material && config->opt_float("support_material_contact_distance") == 0;
auto support_material_style = config->opt_enum<SupportMaterialStyle>("support_material_style");
for (auto el : { "support_material_style", "support_material_pattern", "support_material_with_sheath",
"support_material_spacing", "support_material_angle",
"support_material_spacing", "support_material_angle", "support_material_min_diameter",
"support_material_interface_pattern", "support_material_interface_layers",
"dont_support_bridges", "support_material_extrusion_width", "support_material_contact_distance",
"support_material_xy_spacing" })

View File

@ -1535,6 +1535,7 @@ void TabPrint::build()
optgroup->append_single_option_line("support_material", category_path + "generate-support-material");
optgroup->append_single_option_line("support_material_auto", category_path + "auto-generated-supports");
optgroup->append_single_option_line("support_material_threshold", category_path + "overhang-threshold");
optgroup->append_single_option_line("support_material_min_diameter", category_path + "support-min-diameter");
optgroup->append_single_option_line("support_material_enforce_layers", category_path + "enforce-support-for-the-first");
optgroup->append_single_option_line("raft_first_layer_density", category_path + "raft-first-layer-density");
optgroup->append_single_option_line("raft_first_layer_expansion", category_path + "raft-first-layer-expansion");