Organic supports: Adding bridge detection using the same algorithms

as the regular supports.
Partial fix to #9493
This commit is contained in:
Vojtech Bubnik 2023-02-09 16:47:57 +01:00
parent 957572fb8a
commit f1977b07be
4 changed files with 97 additions and 81 deletions

View File

@ -361,6 +361,8 @@ inline Slic3r::Polygons expand(const Slic3r::Polygon &polygon, const float del
{ assert(delta > 0); return offset(polygon, delta, joinType, miterLimit); } { assert(delta > 0); return offset(polygon, delta, joinType, miterLimit); }
inline Slic3r::Polygons expand(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) inline Slic3r::Polygons expand(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
{ assert(delta > 0); return offset(polygons, delta, joinType, miterLimit); } { assert(delta > 0); return offset(polygons, delta, joinType, miterLimit); }
inline Slic3r::Polygons expand(const Slic3r::ExPolygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
{ assert(delta > 0); return offset(polygons, delta, joinType, miterLimit); }
inline Slic3r::ExPolygons expand_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) inline Slic3r::ExPolygons expand_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
{ assert(delta > 0); return offset_ex(polygons, delta, joinType, miterLimit); } { assert(delta > 0); return offset_ex(polygons, delta, joinType, miterLimit); }
// Input polygons for shrinking shall be "normalized": There must be no overlap / intersections between the input polygons. // Input polygons for shrinking shall be "normalized": There must be no overlap / intersections between the input polygons.

View File

@ -1260,20 +1260,20 @@ namespace SupportMaterialInternal {
collect_bridging_perimeter_areas(*static_cast<const ExtrusionLoop*>(ee), expansion_scaled, out); collect_bridging_perimeter_areas(*static_cast<const ExtrusionLoop*>(ee), expansion_scaled, out);
} }
} }
}
static void remove_bridges_from_contacts( void remove_bridges_from_contacts(
const PrintConfig &print_config, const PrintConfig &print_config,
const Layer &lower_layer, const Layer &lower_layer,
const Polygons &lower_layer_polygons,
const LayerRegion &layerm, const LayerRegion &layerm,
float fw, float fw,
Polygons &contact_polygons) Polygons &contact_polygons)
{ {
// compute the area of bridging perimeters // compute the area of bridging perimeters
Polygons bridges; Polygons bridges;
{ {
// Surface supporting this layer, expanded by 0.5 * nozzle_diameter, as we consider this kind of overhang to be sufficiently supported. // Surface supporting this layer, expanded by 0.5 * nozzle_diameter, as we consider this kind of overhang to be sufficiently supported.
Polygons lower_grown_slices = expand(lower_layer_polygons, Polygons lower_grown_slices = expand(lower_layer.lslices,
//FIXME to mimic the decision in the perimeter generator, we should use half the external perimeter width. //FIXME to mimic the decision in the perimeter generator, we should use half the external perimeter width.
0.5f * float(scale_(print_config.nozzle_diameter.get_at(layerm.region().config().perimeter_extruder-1))), 0.5f * float(scale_(print_config.nozzle_diameter.get_at(layerm.region().config().perimeter_extruder-1))),
SUPPORT_SURFACES_OFFSET_PARAMETERS); SUPPORT_SURFACES_OFFSET_PARAMETERS);
@ -1340,7 +1340,6 @@ namespace SupportMaterialInternal {
{ { union_ex(contact_polygons) }, { "contact_polygons", "blue", 0.5f } }, { { union_ex(contact_polygons) }, { "contact_polygons", "blue", 0.5f } },
{ { union_ex(bridges) }, { "bridges", "red", "black", "", scaled<coord_t>(0.1f), 0.5f } } }); { { union_ex(bridges) }, { "bridges", "red", "black", "", scaled<coord_t>(0.1f), 0.5f } } });
#endif /* SLIC3R_DEBUG */ #endif /* SLIC3R_DEBUG */
}
} }
std::vector<Polygons> PrintObjectSupportMaterial::buildplate_covered(const PrintObject &object) const std::vector<Polygons> PrintObjectSupportMaterial::buildplate_covered(const PrintObject &object) const
@ -1558,8 +1557,7 @@ static inline std::tuple<Polygons, Polygons, Polygons, float> detect_overhangs(
if (object_config.dont_support_bridges) if (object_config.dont_support_bridges)
//FIXME Expensive, potentially not precise enough. Misses gap fill extrusions, which bridge. //FIXME Expensive, potentially not precise enough. Misses gap fill extrusions, which bridge.
SupportMaterialInternal::remove_bridges_from_contacts( remove_bridges_from_contacts(print_config, lower_layer, *layerm, fw, diff_polygons);
print_config, lower_layer, lower_layer_polygons, *layerm, fw, diff_polygons);
if (diff_polygons.empty()) if (diff_polygons.empty())
continue; continue;

View File

@ -147,6 +147,15 @@ struct SupportParameters {
bool with_sheath; bool with_sheath;
}; };
// Remove bridges from support contact areas.
// To be called if PrintObjectConfig::dont_support_bridges.
void remove_bridges_from_contacts(
const PrintConfig &print_config,
const Layer &lower_layer,
const LayerRegion &layerm,
float fw,
Polygons &contact_polygons);
// Generate raft layers, also expand the 1st support layer // Generate raft layers, also expand the 1st support layer
// in case there is no raft layer to improve support adhesion. // in case there is no raft layer to improve support adhesion.
SupportGeneratorLayersPtr generate_raft_base( SupportGeneratorLayersPtr generate_raft_base(

View File

@ -226,6 +226,7 @@ void tree_supports_show_error(std::string_view message, bool critical)
{ {
std::vector<Polygons> out(print_object.layer_count(), Polygons{}); std::vector<Polygons> out(print_object.layer_count(), Polygons{});
const PrintConfig &print_config = print_object.print()->config();
const PrintObjectConfig &config = print_object.config(); const PrintObjectConfig &config = print_object.config();
const bool support_auto = config.support_material.value && config.support_material_auto.value; const bool support_auto = config.support_material.value && config.support_material_auto.value;
const int support_enforce_layers = config.support_material_enforce_layers.value; const int support_enforce_layers = config.support_material_enforce_layers.value;
@ -242,7 +243,8 @@ void tree_supports_show_error(std::string_view message, bool critical)
size_t num_overhang_layers = support_auto ? out.size() : std::max(size_t(support_enforce_layers), enforcers_layers.size()); size_t num_overhang_layers = support_auto ? out.size() : std::max(size_t(support_enforce_layers), enforcers_layers.size());
tbb::parallel_for(tbb::blocked_range<LayerIndex>(1, num_overhang_layers), tbb::parallel_for(tbb::blocked_range<LayerIndex>(1, num_overhang_layers),
[&print_object, &enforcers_layers, &blockers_layers, support_auto, support_enforce_layers, support_threshold_auto, tan_threshold, enforcer_overhang_offset, &throw_on_cancel, &out] [&print_object, &config, &print_config, &enforcers_layers, &blockers_layers,
support_auto, support_enforce_layers, support_threshold_auto, tan_threshold, enforcer_overhang_offset, &throw_on_cancel, &out]
(const tbb::blocked_range<LayerIndex> &range) { (const tbb::blocked_range<LayerIndex> &range) {
for (LayerIndex layer_id = range.begin(); layer_id < range.end(); ++ layer_id) { for (LayerIndex layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
const Layer &current_layer = *print_object.get_layer(layer_id); const Layer &current_layer = *print_object.get_layer(layer_id);
@ -275,6 +277,11 @@ void tree_supports_show_error(std::string_view message, bool critical)
} }
if (! (enforced_layer || blockers_layers.empty() || blockers_layers[layer_id].empty())) if (! (enforced_layer || blockers_layers.empty() || blockers_layers[layer_id].empty()))
overhangs = diff(overhangs, blockers_layers[layer_id], ApplySafetyOffset::Yes); overhangs = diff(overhangs, blockers_layers[layer_id], ApplySafetyOffset::Yes);
if (config.dont_support_bridges) {
for (const LayerRegion *layerm : current_layer.regions())
remove_bridges_from_contacts(print_config, lower_layer, *layerm,
float(layerm->flow(frExternalPerimeter).scaled_width()), overhangs);
}
} }
//check_self_intersections(overhangs, "generate_overhangs1"); //check_self_intersections(overhangs, "generate_overhangs1");
if (! enforcers_layers.empty() && ! enforcers_layers[layer_id].empty()) { if (! enforcers_layers.empty() && ! enforcers_layers[layer_id].empty()) {