update libslic3r

This commit is contained in:
QIDI TECH
2025-07-08 20:00:47 +08:00
parent bafe693d0a
commit e0d447172c
64 changed files with 2958 additions and 712 deletions

View File

@@ -118,9 +118,10 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa
}
return nullptr;
};
const bool istree = is_tree(config.support_type);
tbb::parallel_for(tbb::blocked_range<int>(0, int(intermediate_layers.size())),
[&bottom_contacts, &top_contacts, &top_interface_layers, &top_base_interface_layers, &intermediate_layers, &insert_layer, &support_params,
snug_supports, &interface_layers, &base_interface_layers](const tbb::blocked_range<int>& range) {
snug_supports, &interface_layers, &base_interface_layers, &istree](const tbb::blocked_range<int>& range) {
// Gather the top / bottom contact layers intersecting with num_interface_layers resp. num_interface_layers_only intermediate layers above / below
// this intermediate layer.
// Index of the first top contact layer intersecting the current intermediate layer.
@@ -139,27 +140,55 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa
Polygons polygons_bottom_contact_projected_interface;
Polygons polygons_bottom_contact_projected_base;
if (support_params.num_top_interface_layers > 0) {
// Top Z coordinate of a slab, over which we are collecting the top / bottom contact surfaces
coordf_t top_z = intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + int(support_params.num_top_interface_layers) - 1)]->print_z;
coordf_t top_inteface_z = std::numeric_limits<coordf_t>::max();
if (support_params.num_top_base_interface_layers > 0)
// Some top base interface layers will be generated.
top_inteface_z = support_params.num_top_interface_layers_only() == 0 ?
// Only base interface layers to generate.
- std::numeric_limits<coordf_t>::max() :
intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + int(support_params.num_top_interface_layers_only()) - 1)]->print_z;
// Move idx_top_contact_first up until above the current print_z.
idx_top_contact_first = idx_higher_or_equal(top_contacts, idx_top_contact_first, [&intermediate_layer](const SupportGeneratorLayer *layer){ return layer->print_z >= intermediate_layer.print_z; }); // - EPSILON
// Collect the top contact areas above this intermediate layer, below top_z.
for (int idx_top_contact = idx_top_contact_first; idx_top_contact < int(top_contacts.size()); ++ idx_top_contact) {
const SupportGeneratorLayer &top_contact_layer = *top_contacts[idx_top_contact];
//FIXME maybe this adds one interface layer in excess?
if (top_contact_layer.bottom_z - EPSILON > top_z)
break;
polygons_append(top_contact_layer.bottom_z - EPSILON > top_inteface_z ? polygons_top_contact_projected_base : polygons_top_contact_projected_interface,
// For snug supports, project the overhang polygons covering the whole overhang, so that they will merge without a gap with support polygons of the other layers.
// For grid supports, merging of support regions will be performed by the projection into grid.
snug_supports ? *top_contact_layer.overhang_polygons : top_contact_layer.polygons);
if (istree) {
// Top Z coordinate of a slab, over which we are collecting the top / bottom contact surfaces
coordf_t top_z = intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + int(support_params.num_top_interface_layers) - 1)]
->print_z;
coordf_t top_inteface_z = std::numeric_limits<coordf_t>::max();
if (support_params.num_top_base_interface_layers > 0)
// Some top base interface layers will be generated.
top_inteface_z =
support_params.num_top_interface_layers_only() == 0 ?
// Only base interface layers to generate.
-std::numeric_limits<coordf_t>::max() :
intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + int(support_params.num_top_interface_layers_only()) - 1)]
->print_z;
// Move idx_top_contact_first up until above the current print_z.
idx_top_contact_first = idx_higher_or_equal(top_contacts, idx_top_contact_first, [&intermediate_layer](const SupportGeneratorLayer *layer) {
return layer->print_z >= intermediate_layer.print_z;
}); // - EPSILON
// Collect the top contact areas above this intermediate layer, below top_z.
for (int idx_top_contact = idx_top_contact_first; idx_top_contact < int(top_contacts.size()); ++idx_top_contact) {
const SupportGeneratorLayer &top_contact_layer = *top_contacts[idx_top_contact];
// FIXME maybe this adds one interface layer in excess?
if (top_contact_layer.bottom_z - EPSILON > top_z) break;
polygons_append(top_contact_layer.bottom_z - EPSILON > top_inteface_z ? polygons_top_contact_projected_base :
polygons_top_contact_projected_interface,
// For snug supports, project the overhang polygons covering the whole overhang, so that they will merge without a gap with support
// polygons of the other layers. For grid supports, merging of support regions will be performed by the projection into grid.
snug_supports ? *top_contact_layer.overhang_polygons : top_contact_layer.polygons);
}
} else {
// Move idx_top_contact_first up until above the current print_z.
idx_top_contact_first = idx_higher_or_equal(top_contacts, idx_top_contact_first, [&intermediate_layer](const SupportGeneratorLayer *layer){ return layer->print_z >= intermediate_layer.print_z; }); // - EPSILON
// Collect the top contact areas above this intermediate layer, below top_z.
for (int idx_top_contact = idx_top_contact_first; idx_top_contact < int(top_contacts.size()); ++ idx_top_contact) {
const SupportGeneratorLayer &top_contact_layer = *top_contacts[idx_top_contact];
const bool is_top_contact = is_approx(top_contact_layer.bottom_z, intermediate_layers[num_intermediate - 1]->print_z);
if (is_top_contact) {
if (idx_intermediate_layer > num_intermediate - support_params.num_top_interface_layers)
polygons_append(polygons_top_contact_projected_interface, snug_supports ? *top_contact_layer.overhang_polygons : top_contact_layer.polygons);
else if (idx_intermediate_layer > num_intermediate - support_params.num_top_interface_layers - support_params.num_top_base_interface_layers)
polygons_append(polygons_top_contact_projected_base, snug_supports ? *top_contact_layer.overhang_polygons : top_contact_layer.polygons);
} else {
if (top_contact_layer.print_z - EPSILON <
intermediate_layers[std::min(int(idx_intermediate_layer + support_params.num_top_interface_layers - 1), num_intermediate - 1)]->print_z)
polygons_append(polygons_top_contact_projected_interface, snug_supports ? *top_contact_layer.overhang_polygons : top_contact_layer.polygons);
else if (top_contact_layer.print_z - EPSILON < intermediate_layers[std::min(int(idx_intermediate_layer + support_params.num_top_interface_layers -
1 + support_params.num_top_base_interface_layers),num_intermediate - 1)]->print_z)
polygons_append(polygons_top_contact_projected_base, snug_supports ? *top_contact_layer.overhang_polygons : top_contact_layer.polygons);
}
}
}
}
if (support_params.num_bottom_interface_layers > 0) {
@@ -208,16 +237,24 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa
}
});
tbb::parallel_for(tbb::blocked_range<int>(1, int(base_interface_layers.size())), [&base_interface_layers](const tbb::blocked_range<int> &range) {
for (int layer_id = range.begin(); layer_id < range.end(); ++layer_id) {
auto &base_interface_layer = base_interface_layers[layer_id];
if (!base_interface_layer) return;
auto &lower_layer = base_interface_layers[layer_id - 1];
if (!lower_layer) return;
if (base_interface_layer->polygons == lower_layer->polygons) base_interface_layer->up = true;
}
});
if (support_params.num_top_base_interface_layers > 1 && !istree)
tbb::parallel_for(tbb::blocked_range<int>(1, int(base_interface_layers.size())),
[&base_interface_layers, &top_contacts, &support_params, &intermediate_layers](const tbb::blocked_range<int> &range) {
for (int layer_id = range.begin(); layer_id < range.end(); ++layer_id) {
auto &base_interface_layer = base_interface_layers[layer_id];
if (!base_interface_layer) return;
for (const auto &contact : top_contacts) {
if (is_approx(contact->bottom_z,
intermediate_layers[std::min(layer_id - 1 + support_params.num_top_interface_layers, intermediate_layers.size() - 1)]
->print_z, 0.01) &&
overlaps(base_interface_layer->polygons, contact->polygons)) {
base_interface_layer->up = true;
break;
}
}
}
});
// Compress contact_out, remove the nullptr items.
// The parallel_for above may not have merged all the interface and base_interface layers
@@ -583,8 +620,9 @@ void tree_supports_generate_paths(
for (ExPolygon& expoly : closing_ex(polygons, float(SCALED_EPSILON), float(SCALED_EPSILON + 0.5 * flow.scaled_width()))) {
std::unique_ptr<ExtrusionEntityCollection> eec;
ExPolygons regions_to_draw_inner_wall{expoly};
double area = expoly.area();
if (support_params.tree_branch_diameter_double_wall_area_scaled > 0)
if (double area = expoly.area(); area > support_params.tree_branch_diameter_double_wall_area_scaled) {
if (area > support_params.tree_branch_diameter_double_wall_area_scaled) {
BOOST_LOG_TRIVIAL(debug)<< "TreeSupports: double wall area: " << area<< " > " << support_params.tree_branch_diameter_double_wall_area_scaled;
eec = std::make_unique<ExtrusionEntityCollection>();
// Don't reorder internal / external loops of the same island, always start with the internal loop.
@@ -655,12 +693,12 @@ void tree_supports_generate_paths(
}
}
}
if (d2min < sqr(flow.scaled_width() * 3.)) {
if (d2min < sqr(flow.scaled_width() * 3.) && Slic3r::area(regions_to_draw_inner_wall) + scale_(EPSILON) > area && !shrink_ex({expoly}, -2.*flow.scaled_width()).empty()) {
// Try to cut an anchor from the closest_contour.
// Both closest_contour and pl are CW oriented.
pl.points.emplace_back(closest_point.cast<coord_t>());
const ClipperLib_Z::Path &path = *closest_contour;
double remaining_length = anchor_length - (seam_pt - closest_point).norm();
double remaining_length = std::min(anchor_length - (seam_pt - closest_point).norm(), pl.length() / 12.);
int i = closest_point_idx;
int j = next_idx_modulo(i, *closest_contour);
Vec2d pi(path[i].x(), path[i].y());
@@ -1436,7 +1474,7 @@ void generate_support_toolpaths(
angles.push_back(support_params.interface_angle);
std::vector<float> interface_angles;
if (config.support_interface_pattern == smipRectilinearInterlaced)
if (config.support_interface_pattern == smipRectilinearInterlaced || config.support_interface_pattern == smipAuto)
interface_angles.push_back(support_params.base_angle);
interface_angles.push_back(support_params.interface_angle);

View File

@@ -33,19 +33,35 @@ struct SupportParameters {
num_top_interface_layers : object_config.support_interface_bottom_layers;
this->has_top_contacts = num_top_interface_layers > 0;
this->has_bottom_contacts = num_bottom_interface_layers > 0;
if (this->soluble_interface_non_soluble_base) {
// Try to support soluble dense interfaces with non-soluble dense interfaces.
this->num_top_base_interface_layers = num_top_interface_layers > 0 ? 2 : 0;
this->num_bottom_base_interface_layers = size_t(std::min(int(num_bottom_interface_layers) / 2, 2));
} else {
// QDS: if support interface and support base do not use the same filament, add a base layer to improve their adhesion
// Note: support materials (such as Supp.W) can't be used as support base now, so support interface and base are still using different filaments even if
// support_filament==0
bool differnt_support_interface_filament = object_config.support_interface_filament != 0 &&
object_config.support_interface_filament != object_config.support_filament;
this->num_top_base_interface_layers = differnt_support_interface_filament && num_top_interface_layers > 0 ? 2 : 0;
this->num_bottom_base_interface_layers = differnt_support_interface_filament ? 1 : 0;
}
if (is_tree(object_config.support_type)) {
if (this->soluble_interface_non_soluble_base) {
// Try to support soluble dense interfaces with non-soluble dense interfaces.
this->num_top_base_interface_layers = size_t(std::min(int(num_top_interface_layers) / 2, 2));
this->num_bottom_base_interface_layers = size_t(std::min(int(num_bottom_interface_layers) / 2, 2));
} else {
// QDS: if support interface and support base do not use the same filament, add a base layer to improve their adhesion
// Note: support materials (such as Supp.W) can't be used as support base now, so support interface and base are still using different filaments even if
// support_filament==0
bool differnt_support_interface_filament = object_config.support_interface_filament != 0 &&
object_config.support_interface_filament != object_config.support_filament;
this->num_top_base_interface_layers = differnt_support_interface_filament ? 1 : 0;
this->num_bottom_base_interface_layers = differnt_support_interface_filament ? 1 : 0;
}
} else {
if (this->soluble_interface_non_soluble_base) {
// Try to support soluble dense interfaces with non-soluble dense interfaces.
this->num_top_base_interface_layers = num_top_interface_layers > 0 ? 2 : 0;
this->num_bottom_base_interface_layers = size_t(std::min(int(num_bottom_interface_layers) / 2, 2));
} else {
// QDS: if support interface and support base do not use the same filament, add a base layer to improve their adhesion
// Note: support materials (such as Supp.W) can't be used as support base now, so support interface and base are still using different filaments even if
// support_filament==0
bool differnt_support_interface_filament = object_config.support_interface_filament != 0 &&
object_config.support_interface_filament != object_config.support_filament;
this->num_top_base_interface_layers = num_top_interface_layers > 0 ? differnt_support_interface_filament ? 2 : 1 : 0;
this->num_bottom_base_interface_layers = differnt_support_interface_filament ? 1 : 0;
}
}
}
this->first_layer_flow = Slic3r::support_material_1st_layer_flow(&object, float(slicing_params.first_print_layer_height));
this->support_material_flow = Slic3r::support_material_flow(&object, float(slicing_params.layer_height));
@@ -130,6 +146,7 @@ struct SupportParameters {
}
support_base_pattern = object_config.support_base_pattern;
if (support_base_pattern == smpLightning && !is_tree(object_config.support_type)) support_base_pattern = smpRectilinear;
if (support_base_pattern == smpDefault) {
if (is_tree(object_config.support_type))
support_base_pattern = support_style == smsTreeHybrid ? smpRectilinear : smpNone;

View File

@@ -876,25 +876,48 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
std::chrono::time_point<clock_> t0{ clock_::now() };
// main part of overhang detection can be parallel
tbb::concurrent_vector<ExPolygons> overhangs_all_layers(m_object->layer_count());
auto enforcers = m_object->slice_support_enforcers();
auto blockers = m_object->slice_support_blockers();
m_vertical_enforcer_points.clear();
m_object->project_and_append_custom_facets(false, EnforcerBlockerType::BLOCKER, blockers);
m_object->project_and_append_custom_facets(false, EnforcerBlockerType::ENFORCER, enforcers, &m_vertical_enforcer_points);
auto trim_tail_empty = [](auto &vec) {
auto rit = std::find_if(vec.rbegin(), vec.rend(), [](const auto &e) { return !e.empty(); });
if (rit != vec.rend()) {
vec.erase(rit.base(), vec.end());
} else {
vec.clear();
}
};
trim_tail_empty(enforcers);
trim_tail_empty(blockers);
tbb::parallel_for(tbb::blocked_range<size_t>(0, m_object->layer_count()),
[&](const tbb::blocked_range<size_t>& range) {
for (size_t layer_nr = range.begin(); layer_nr < range.end(); layer_nr++) {
if (m_object->print()->canceled())
break;
if (!is_auto(stype) && layer_nr > enforce_support_layers)
// FIXME the param enforce_support_layers is not set yet
if (!(is_auto(stype) || (enforce_support_layers > 0 && layer_nr >= enforce_support_layers) || (layer_nr < enforcers.size() && !enforcers[layer_nr].empty())))
continue;
Layer* layer = m_object->get_layer(layer_nr);
if (layer->lower_layer == nullptr) {
for (auto& slice : layer->lslices_extrudable) {
ExPolygons curr_polys = layer->lslices_extrudable;
if (layer_nr < blockers.size() && !blockers[layer_nr].empty())
curr_polys = diff_ex(curr_polys, offset_ex(union_(blockers[layer_nr]), scale_(radius_sample_resolution)));
for (auto& slice : curr_polys) {
auto bbox_size = get_extents(slice).size();
if (!((bbox_size.x() > length_thresh_well_supported || bbox_size.y() > length_thresh_well_supported))
&& g_config_support_sharp_tails) {
layer->sharp_tails.push_back(slice);
layer->sharp_tails_height.push_back(layer->height);
}
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
SVG::export_expolygons(debug_out_path("sharp_tail_orig_%.02f.svg", layer->print_z), {slice});
#endif
}
continue;
}
@@ -905,10 +928,32 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
coordf_t support_offset_scaled = scale_(lower_layer_offset);
ExPolygons& curr_polys = layer->lslices_extrudable;
ExPolygons& lower_polys = lower_layer->lslices_extrudable;
ExPolygons lower_layer_offseted = offset_ex(lower_polys, support_offset_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS);
// normal overhang
ExPolygons lower_layer_offseted = offset_ex(lower_polys, support_offset_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS);
overhangs_all_layers[layer_nr] = std::move(diff_ex(curr_polys, lower_layer_offseted));
// add enforcer
ExPolygons enforced_overhangs;
ExPolygons blocker;
if (!enforcers.empty())
enforced_overhangs = intersection_ex(diff_ex(layer->lslices_extrudable, lower_layer->lslices_extrudable), enforcers[layer_nr]);
if (is_auto(stype)) {
// normal overhang
overhangs_all_layers[layer_nr] = std::move(diff_ex(curr_polys, lower_layer_offseted));
// if is auto, add blocker first
if (layer_nr < blockers.size() && !blockers[layer_nr].empty()) {
// Arthur: union_ is a must because after mirroring, the blocker polygons are in left-hand coordinates, ie clockwise,
// which are not valid polygons, and will be removed by offset_ex. union_ can make these polygons right.
blocker = offset_ex(union_(blockers[layer_nr]), scale_(radius_sample_resolution));
if (!blocker.empty()) overhangs_all_layers[layer_nr] = diff_ex(overhangs_all_layers[layer_nr], blocker);
}
if (!enforced_overhangs.empty()) overhangs_all_layers[layer_nr] = union_ex(overhangs_all_layers[layer_nr], enforced_overhangs);
}
else if (layer_nr < enforcers.size() && lower_layer) {
if (!enforced_overhangs.empty()) {
// FIXME this is a hack to make enforcers work on steep overhangs. See STUDIO-7538.
enforced_overhangs = diff_ex(offset_ex(enforced_overhangs, enforcer_overhang_offset), lower_layer->lslices_extrudable);
overhangs_all_layers[layer_nr] = std::move(enforced_overhangs);
}
}
double duration{ std::chrono::duration_cast<second_>(clock_::now() - t0).count() };
if (duration > 30 || overhangs_all_layers[layer_nr].size() > 100) {
@@ -919,8 +964,11 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
}
if (is_auto(stype) && config_detect_sharp_tails)
{
ExPolygons curr = curr_polys;
if (!blocker.empty()) curr = diff_ex(curr, blocker);
if (!enforced_overhangs.empty()) curr = union_ex(curr, enforced_overhangs);
// QDS detect sharp tail
for (const ExPolygon& expoly : curr_polys) {
for (const ExPolygon& expoly : curr) {
bool is_sharp_tail = false;
// 1. nothing below
// this is a sharp tail region if it's floating and non-ignorable
@@ -1015,7 +1063,13 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
// QDS detect sharp tail
const ExPolygons& lower_layer_sharptails = lower_layer->sharp_tails;
const auto& lower_layer_sharptails_height = lower_layer->sharp_tails_height;
for (ExPolygon& expoly : layer->lslices_extrudable) {
ExPolygons curr_polys = layer->lslices_extrudable;
if (!blockers.empty() && layer_nr < blockers.size() && !blockers[layer_nr].empty())
curr_polys = diff_ex(curr_polys, offset_ex(union_(blockers[layer_nr]), scale_(radius_sample_resolution)));
if (!enforcers.empty() && layer_nr < enforcers.size() && !enforcers[layer_nr].empty())
curr_polys = union_ex(curr_polys, intersection_ex(diff_ex(layer->lslices_extrudable, lower_layer->lslices_extrudable), enforcers[layer_nr]));
for (ExPolygon& expoly : curr_polys) {
bool is_sharp_tail = false;
float accum_height = layer->height;
do {
@@ -1088,13 +1142,8 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
}
}
auto enforcers = m_object->slice_support_enforcers();
auto blockers = m_object->slice_support_blockers();
m_vertical_enforcer_points.clear();
m_object->project_and_append_custom_facets(false, EnforcerBlockerType::ENFORCER, enforcers, &m_vertical_enforcer_points);
m_object->project_and_append_custom_facets(false, EnforcerBlockerType::BLOCKER, blockers);
for (auto &cluster : overhangClusters) {
bool enforce_add = false;
// remove small overhangs
if (is_auto(stype) && config_remove_small_overhangs) {
// 3. check whether the small overhang is sharp tail
@@ -1106,6 +1155,16 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
break;
}
}
if (!enforcers.empty() && cluster.min_layer<enforcers.size()) {
for (size_t layer_id = cluster.min_layer; layer_id <= cluster.max_layer; layer_id++) {
if (layer_id >= enforcers.size()) break;
if (enforcers[layer_id].empty()) continue;
if (overlaps(to_expolygons(enforcers[layer_id]), cluster.layer_overhangs[layer_id])) {
enforce_add = true;
break;
}
}
}
cluster.check_small_overhang(extrusion_width_scaled, length_thresh_small_overhang, radius_thresh_small_overhang);
@@ -1121,11 +1180,15 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
#endif
}
if (!cluster.is_type(Small)) {
if (!cluster.is_type(Small) || enforce_add) {
cluster.check_polygon_node(m_support_params.thresh_big_overhang, m_ts_data->m_layer_outlines_below[cluster.min_layer - 1]);
for (auto it = cluster.layer_overhangs.begin(); it != cluster.layer_overhangs.end(); it++) {
int layer_nr = it->first;
ExPolygons overhangs = it->second;
if (cluster.is_type(Small)) {
if (layer_nr >= enforcers.size() || enforcers[layer_nr].empty() || !overlaps(to_expolygons(enforcers[layer_nr]), overhangs)) continue;
overhangs = intersection_ex(overhangs, enforcers[layer_nr]);
}
for (const auto &overhang : overhangs) add_overhang(m_object->get_layer(layer_nr), overhang, cluster.type);
}
}
@@ -1141,22 +1204,50 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
auto lower_layer = layer->lower_layer;
if (support_critical_regions_only && is_auto(stype)) {
layer->loverhangs.clear(); // remove oridinary overhangs, only keep cantilevers and sharp tails (added later)
layer->loverhangs_with_type.clear();
for (auto &cantilever : layer->cantilevers) add_overhang(layer, cantilever, OverhangType::Cantilever);
if (lower_layer == nullptr || enforcers.empty() || layer_nr >= enforcers.size() || enforcers[layer_nr].empty()) {
layer->loverhangs.clear();
layer->loverhangs_with_type.clear();
for (const auto &cantilever : layer->cantilevers) add_overhang(layer, cantilever, OverhangType::Cantilever);
} else {
ExPolygons enforced_overhangs = to_expolygons(enforcers[layer_nr]);
ExPolygons loverhangs_new;
std::vector<std::pair<ExPolygon, int>> loverhangs_with_type_new;
ExPolygons bigflat;
for (auto &overhang_part : layer->loverhangs_with_type) {
const auto &overhang = overhang_part.first;
auto type = overhang_part.second;
ExPolygons overhangs;
if (type & OverhangType::Cantilever || type & OverhangType::SharpTail)
overhangs = {overhang};
else if (overlaps(enforced_overhangs, overhang)) {
overhangs = intersection_ex(enforced_overhangs, overhang);
}
if (!overhangs.empty()) {
if (type & OverhangType::BigFlat)
append(bigflat, overhangs);
else
for (const auto &expoly : overhangs) {
loverhangs_new.emplace_back(expoly);
loverhangs_with_type_new.emplace_back(std::make_pair(expoly, type));
}
}
}
for (const auto &expoly : union_ex(bigflat)) {
loverhangs_new.emplace_back(expoly);
loverhangs_with_type_new.emplace_back(std::make_pair(expoly, OverhangType::BigFlat));
}
layer->loverhangs = std::move(loverhangs_new);
layer->loverhangs_with_type = std::move(loverhangs_with_type_new);
}
}
// add support for every 1mm height for sharp tails
ExPolygons sharp_tail_overhangs;
if (lower_layer == nullptr)
sharp_tail_overhangs = layer->sharp_tails;
else {
if (lower_layer){
ExPolygons lower_layer_expanded = offset_ex(lower_layer->lslices_extrudable, SCALED_RESOLUTION);
for (size_t i = 0; i < layer->sharp_tails_height.size();i++) {
ExPolygons areas = diff_clipped({ layer->sharp_tails[i]}, lower_layer_expanded);
float accum_height = layer->sharp_tails_height[i];
if (!areas.empty() && int(accum_height * 10) % 5 == 0) {
append(sharp_tail_overhangs, areas);
has_sharp_tails = true;
for (auto &area : areas)
add_overhang(layer, area, accum_height < EPSILON ? (OverhangType::SharpTail | OverhangType::SharpTailLowesst) : OverhangType::SharpTail);
@@ -1167,19 +1258,6 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
}
}
if (layer_nr < blockers.size()) {
// Arthur: union_ is a must because after mirroring, the blocker polygons are in left-hand coordinates, ie clockwise,
// which are not valid polygons, and will be removed by offset_ex. union_ can make these polygons right.
ExPolygons blocker = offset_ex(union_(blockers[layer_nr]), scale_(radius_sample_resolution));
auto old_overhangs_with_type = layer->loverhangs_with_type;
layer->loverhangs.clear();
layer->loverhangs_with_type.clear();
for (auto &poly : old_overhangs_with_type) {
ExPolygons polydiff = diff_ex(poly.first, blocker);
for (auto &diff : polydiff) add_overhang(layer, diff, OverhangType(poly.second));
}
}
if (max_bridge_length > 0 && layer->loverhangs.size() > 0 && lower_layer) {
// do not break bridge as the interface will be poor, see #4318
bool break_bridge = false;
@@ -1187,19 +1265,6 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
}
int nDetected = layer->loverhangs.size();
// enforcers now follow same logic as normal support. See STUDIO-3692
if (layer_nr < enforcers.size() && lower_layer) {
ExPolygons enforced_overhangs = intersection_ex(diff_ex(layer->lslices_extrudable, lower_layer->lslices_extrudable), enforcers[layer_nr]);
if (!enforced_overhangs.empty()) {
// FIXME this is a hack to make enforcers work on steep overhangs. See STUDIO-7538.
enforced_overhangs = diff_ex(offset_ex(enforced_overhangs, enforcer_overhang_offset), lower_layer->lslices_extrudable);
for (auto &poly : enforced_overhangs) add_overhang(layer, poly, OverhangType::Normal);
}
}
int nEnforced = layer->loverhangs.size();
//// add sharp tail overhangs
//append(layer->loverhangs, sharp_tail_overhangs);
//// fill overhang_types
//for (size_t i = 0; i < layer->loverhangs.size(); i++)
@@ -1654,7 +1719,7 @@ void TreeSupport::generate_toolpaths()
filler_interface->angle = Geometry::deg2rad(object_config.support_angle.value);
fill_params.dont_sort = true;
}
if (m_support_params.contact_fill_pattern = ipRectilinear) {
if (m_support_params.contact_fill_pattern == ipRectilinear) {
bool bridge_found = false;
for (size_t i = 0; i < m_support_params.num_top_interface_layers; i++) {
auto cur_ts_layer = m_object->get_support_layer(layer_id + i);
@@ -2818,6 +2883,8 @@ void TreeSupport::drop_nodes()
}
if (node.to_buildplate || parts.empty()) //It's outside, so make it go towards the build plate.
{
if (node.type ==eCircle && nodes_per_part[0][node.position])
p_node->position += Point(1, 1);
nodes_per_part[0][node.position] = p_node;
continue;
}
@@ -2852,6 +2919,8 @@ void TreeSupport::drop_nodes()
}
}
//Put it in the best one.
if (node.type == eCircle && nodes_per_part[closest_part + 1][node.position])
p_node->position += Point(1, 1);
nodes_per_part[closest_part + 1][node.position] = p_node; //Index + 1 because the 0th index is the outside part.
}
@@ -3047,6 +3116,9 @@ void TreeSupport::drop_nodes()
p_node->origin_area = node.overhang.area();
densify_polygon(p_node->overhang.contour, 2.);
}
if (m_support_params.num_top_interface_layers > 0 && obj_layer_nr_next > 0 && node.support_roof_layers_below == 1 &&
node.distance_to_top >= m_support_params.num_top_interface_layers)
overhangs_next = safe_offset_inc(overhangs_next, scale_(max_move_distance), get_collision(0, obj_layer_nr_next), scale_(MIN_BRANCH_RADIUS * 1.75), 0, 1);
for(auto& overhang:overhangs_next) {
if (overhang.empty()) continue;
if (overhang.area() > node.origin_area / 2. && overhang.area() > SQ(scale_(10.))) {
@@ -3060,7 +3132,8 @@ void TreeSupport::drop_nodes()
}
}
// if the part would fall straight to th buildplate, shrink it a little
if (overhang.area() > node.origin_area / 2. && overhang.area() > double(SQ(scale_(10.)))) {
if (node.support_roof_layers_below<0 && overhang.area() > node.origin_area / 2. &&
overhang.area() > double(SQ(scale_(10.)))) {
ExPolygons shrink_overhangs = union_ex(shrink_ex(safe_union({overhang}), double(scale_(max_move_distance / 2.))));
if (shrink_overhangs.size() == 1 && shrink_overhangs[0].area() > double(SQ(scale_(10.))) &&
!overlaps({overhang}, m_ts_data->m_layer_outlines_below[obj_layer_nr_next])) {

View File

@@ -61,7 +61,7 @@ struct TreeSupportMeshGroupSettings {
config.support_interface_top_layers.value) * this->layer_height :
0;
this->support_material_buildplate_only = config.support_on_build_plate_only;
this->support_xy_distance = scaled<coord_t>(config.support_object_xy_distance.value);
this->support_xy_distance = scaled<coord_t>(std::max(0.01, config.support_object_xy_distance.value));
this->support_xy_distance_1st_layer = scaled<coord_t>(config.support_object_first_layer_gap.value);
// Separation of interfaces, it is likely smaller than support_xy_distance.
this->support_xy_distance_overhang = std::min(this->support_xy_distance, scaled<coord_t>(0.5 * external_perimeter_width));