mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-15 18:58:00 -06:00
ENH: improve supporting sharp tails of tree support
1. sharp tails are supported by a sparse set of contact points which are easier to remove than previously dense surrounding support. Organic tree support also has this feature, including all other smart overhang detection techniques (small overhang and cantilever detection), with the cost of slightly longer time to detect overhangs. 2. improve supporting overhang contours by adding contact points along contours. jira: STUDIO-3876 2. remove some redundant data structure. Change-Id: If7f595348506a14aba2d0132d23f97d3539c1e1f (cherry picked from commit e3cce09b9db12ced2841045ffd337b1f35494e6c) (cherry picked from commit 507345deb193d895d0813fc913f00b0def7e62f9)
This commit is contained in:
parent
0b671e8852
commit
2577b9b3a6
5 changed files with 159 additions and 149 deletions
|
@ -11,6 +11,7 @@
|
|||
#include "ShortestPath.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include <libnest2d/backends/libslic3r/geometries.hpp>
|
||||
#include <libnest2d/placers/nfpplacer.hpp>
|
||||
#include "TreeSupport3D.hpp"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
@ -629,18 +630,15 @@ TreeSupport::TreeSupport(PrintObject& object, const SlicingParameters &slicing_p
|
|||
#define SUPPORT_SURFACES_OFFSET_PARAMETERS ClipperLib::jtSquare, 0.
|
||||
void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
|
||||
{
|
||||
// overhangs are already detected
|
||||
if (m_object->support_layer_count() >= m_object->layer_count())
|
||||
return;
|
||||
|
||||
bool tree_support_enable = m_object_config->enable_support.value && is_tree(m_object_config->support_type.value);
|
||||
if (!tree_support_enable && !check_support_necessity) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Tree support is disabled.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear and create Tree Support Layers
|
||||
m_object->clear_support_layers();
|
||||
m_object->clear_tree_support_preview_cache();
|
||||
create_tree_support_layers();
|
||||
if (!tree_support_enable && !check_support_necessity)
|
||||
return;
|
||||
|
||||
const PrintObjectConfig& config = m_object->config();
|
||||
SupportType stype = support_type;
|
||||
|
@ -764,6 +762,7 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
|
|||
Layer* layer = m_object->get_layer(layer_nr);
|
||||
// Filter out areas whose diameter that is smaller than extrusion_width, but we don't want to lose any details.
|
||||
layer->lslices_extrudable = intersection_ex(layer->lslices, offset2_ex(layer->lslices, -extrusion_width_scaled / 2, extrusion_width_scaled));
|
||||
layer->loverhangs.clear();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -771,6 +770,7 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
|
|||
typedef std::chrono::duration<double, std::ratio<1> > second_;
|
||||
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());
|
||||
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++) {
|
||||
|
@ -802,12 +802,11 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
|
|||
ExPolygons& lower_polys = lower_layer->lslices_extrudable;
|
||||
|
||||
// normal overhang
|
||||
SupportLayer* ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers);
|
||||
ExPolygons lower_layer_offseted = offset_ex(lower_polys, support_offset_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS);
|
||||
ts_layer->overhang_areas = std::move(diff_ex(curr_polys, lower_layer_offseted));
|
||||
overhangs_all_layers[layer_nr] = std::move(diff_ex(curr_polys, lower_layer_offseted));
|
||||
|
||||
double duration{ std::chrono::duration_cast<second_>(clock_::now() - t0).count() };
|
||||
if (duration > 30 || ts_layer->overhang_areas.size() > 100) {
|
||||
if (duration > 30 || overhangs_all_layers[layer_nr].size() > 100) {
|
||||
BOOST_LOG_TRIVIAL(info) << "detect_overhangs takes more than 30 secs, skip cantilever and sharp tails detection: layer_nr=" << layer_nr << " duration=" << duration;
|
||||
config_detect_sharp_tails = false;
|
||||
config_remove_small_overhangs = false;
|
||||
|
@ -825,18 +824,14 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
|
|||
}
|
||||
|
||||
if (is_sharp_tail) {
|
||||
ExPolygons overhang = diff_ex({ expoly }, lower_polys);
|
||||
layer->sharp_tails.push_back(expoly);
|
||||
layer->sharp_tails_height.push_back(layer->height);
|
||||
append(ts_layer->overhang_areas, overhang);
|
||||
layer->sharp_tails_height.push_back(0);
|
||||
|
||||
if (!overhang.empty()) {
|
||||
has_sharp_tails = true;
|
||||
has_sharp_tails = true;
|
||||
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
|
||||
SVG::export_expolygons(debug_out_path("sharp_tail_orig_%.02f.svg", layer->print_z), { expoly });
|
||||
SVG::export_expolygons(debug_out_path("sharp_tail_orig_%.02f.svg", layer->print_z), { expoly });
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -844,7 +839,7 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
|
|||
// check cantilever
|
||||
// lower_layer_offset may be very small, so we need to do max and then add 0.1
|
||||
lower_layer_offseted = offset_ex(lower_layer_offseted, scale_(std::max(extrusion_width - lower_layer_offset, 0.) + 0.1));
|
||||
for (ExPolygon& poly : ts_layer->overhang_areas) {
|
||||
for (ExPolygon& poly : overhangs_all_layers[layer_nr]) {
|
||||
auto cluster_boundary_ex = intersection_ex(poly, lower_layer_offseted);
|
||||
Polygons cluster_boundary = to_polygons(cluster_boundary_ex);
|
||||
if (cluster_boundary.empty()) continue;
|
||||
|
@ -879,7 +874,6 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
|
|||
break;
|
||||
|
||||
Layer* layer = m_object->get_layer(layer_nr);
|
||||
SupportLayer* ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers);
|
||||
Layer* lower_layer = layer->lower_layer;
|
||||
if (!lower_layer)
|
||||
continue;
|
||||
|
@ -941,43 +935,32 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
|
|||
} while (0);
|
||||
|
||||
if (is_sharp_tail) {
|
||||
ExPolygons overhang = diff_ex({ expoly }, lower_layer->lslices);
|
||||
layer->sharp_tails.push_back(expoly);
|
||||
layer->sharp_tails_height.push_back( accum_height);
|
||||
append(ts_layer->overhang_areas, overhang);
|
||||
|
||||
if (!overhang.empty())
|
||||
has_sharp_tails = true;
|
||||
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
|
||||
SVG::export_expolygons(debug_out_path("sharp_tail_%.02f.svg", layer->print_z), overhang);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// group overhang clusters
|
||||
for (size_t layer_nr = 0; layer_nr < m_object->layer_count(); layer_nr++) {
|
||||
if (m_object->print()->canceled())
|
||||
break;
|
||||
Layer* layer = m_object->get_layer(layer_nr);
|
||||
for (auto& overhang : overhangs_all_layers[layer_nr]) {
|
||||
OverhangCluster* cluster = find_and_insert_cluster(overhangClusters, overhang, layer_nr, extrusion_width_scaled);
|
||||
if (overlaps({ overhang }, layer->cantilevers))
|
||||
cluster->is_cantilever = true;
|
||||
}
|
||||
}
|
||||
|
||||
auto enforcers = m_object->slice_support_enforcers();
|
||||
auto blockers = m_object->slice_support_blockers();
|
||||
m_object->project_and_append_custom_facets(false, EnforcerBlockerType::ENFORCER, enforcers);
|
||||
m_object->project_and_append_custom_facets(false, EnforcerBlockerType::BLOCKER, blockers);
|
||||
|
||||
if (is_auto(stype) && config_remove_small_overhangs) {
|
||||
if (blockers.size() < m_object->layer_count())
|
||||
blockers.resize(m_object->layer_count());
|
||||
// group overhang clusters
|
||||
for (size_t layer_nr = 0; layer_nr < m_object->layer_count(); layer_nr++) {
|
||||
if (m_object->print()->canceled())
|
||||
break;
|
||||
if (layer_nr + m_raft_layers >= m_object->support_layer_count())
|
||||
break;
|
||||
SupportLayer* ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers);
|
||||
Layer* layer = m_object->get_layer(layer_nr);
|
||||
for (auto& overhang : ts_layer->overhang_areas) {
|
||||
OverhangCluster* cluster = find_and_insert_cluster(overhangClusters, overhang, layer_nr, extrusion_width_scaled);
|
||||
if (overlaps({ overhang }, layer->cantilevers))
|
||||
cluster->is_cantilever = true;
|
||||
}
|
||||
}
|
||||
// remove small overhangs
|
||||
for (auto& cluster : overhangClusters) {
|
||||
// 3. check whether the small overhang is sharp tail
|
||||
|
@ -1010,51 +993,66 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
|
|||
{ cluster.merged_poly,{"overhang", "blue", 0.5} },
|
||||
{ cluster.is_cantilever? layer1->cantilevers: offset_ex(cluster.merged_poly, -1 * extrusion_width_scaled), {cluster.is_cantilever ? "cantilever":"erode1","green",0.5}} });
|
||||
#endif
|
||||
|
||||
if (!cluster.is_small_overhang)
|
||||
continue;
|
||||
|
||||
for (auto it = cluster.layer_overhangs.begin(); it != cluster.layer_overhangs.end(); it++) {
|
||||
int layer_nr = it->first;
|
||||
auto p_overhang = it->second;
|
||||
blockers[layer_nr].push_back(p_overhang->contour);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
has_overhangs = false;
|
||||
for (auto& cluster : overhangClusters) {
|
||||
if (cluster.is_small_overhang) continue;
|
||||
// collect overhangs that's not small overhangs
|
||||
for (auto it = cluster.layer_overhangs.begin(); it != cluster.layer_overhangs.end(); it++) {
|
||||
int layer_nr = it->first;
|
||||
auto p_overhang = it->second;
|
||||
m_object->get_layer(layer_nr)->loverhangs.emplace_back(*p_overhang);
|
||||
}
|
||||
}
|
||||
|
||||
int layers_with_overhangs = 0;
|
||||
for (int layer_nr = 0; layer_nr < m_object->layer_count(); layer_nr++) {
|
||||
if (m_object->print()->canceled())
|
||||
break;
|
||||
|
||||
SupportLayer* ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers);
|
||||
auto layer = m_object->get_layer(layer_nr);
|
||||
auto lower_layer = layer->lower_layer;
|
||||
if (support_critical_regions_only && is_auto(stype)) {
|
||||
ts_layer->overhang_areas.clear();
|
||||
if (lower_layer == nullptr)
|
||||
ts_layer->overhang_areas = layer->sharp_tails;
|
||||
else
|
||||
ts_layer->overhang_areas = diff_ex(layer->sharp_tails, lower_layer->lslices);
|
||||
|
||||
append(ts_layer->overhang_areas, layer->cantilevers);
|
||||
// add support for every 1mm height for sharp tails
|
||||
ExPolygons sharp_tail_overhangs;
|
||||
if (lower_layer == nullptr)
|
||||
sharp_tail_overhangs = layer->sharp_tails;
|
||||
else {
|
||||
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;
|
||||
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
|
||||
SVG::export_expolygons(debug_out_path("sharp_tail_%.02f.svg", layer->print_z), areas);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (support_critical_regions_only && is_auto(stype)) {
|
||||
layer->loverhangs.clear(); // remove oridinary overhangs, only keep cantilevers and sharp tails (added later)
|
||||
append(layer->loverhangs, layer->cantilevers);
|
||||
}
|
||||
|
||||
if (layer_nr < blockers.size()) {
|
||||
Polygons& blocker = blockers[layer_nr];
|
||||
// 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.
|
||||
ts_layer->overhang_areas = diff_ex(ts_layer->overhang_areas, offset_ex(union_(blocker), scale_(radius_sample_resolution)));
|
||||
layer->loverhangs = diff_ex(layer->loverhangs, offset_ex(union_(blocker), scale_(radius_sample_resolution)));
|
||||
}
|
||||
|
||||
if (max_bridge_length > 0 && ts_layer->overhang_areas.size() > 0 && lower_layer) {
|
||||
if (max_bridge_length > 0 && layer->loverhangs.size() > 0 && lower_layer) {
|
||||
// do not break bridge for normal part in TreeHybrid, nor Tree Strong
|
||||
bool break_bridge = !(m_support_params.support_style == smsTreeHybrid && area(ts_layer->overhang_areas) > m_support_params.thresh_big_overhang)
|
||||
bool break_bridge = !(m_support_params.support_style == smsTreeHybrid && area(layer->loverhangs) > m_support_params.thresh_big_overhang)
|
||||
&& !(m_support_params.support_style==smsTreeStrong);
|
||||
m_object->remove_bridges_from_contacts(lower_layer, layer, extrusion_width_scaled, &ts_layer->overhang_areas, max_bridge_length, break_bridge);
|
||||
m_object->remove_bridges_from_contacts(lower_layer, layer, extrusion_width_scaled, &layer->loverhangs, max_bridge_length, break_bridge);
|
||||
}
|
||||
|
||||
int nDetected = ts_layer->overhang_areas.size();
|
||||
int nDetected = layer->loverhangs.size();
|
||||
// enforcers now follow same logic as normal support. See STUDIO-3692
|
||||
if (layer_nr < enforcers.size() && lower_layer) {
|
||||
float no_interface_offset = std::accumulate(layer->regions().begin(), layer->regions().end(), FLT_MAX,
|
||||
|
@ -1065,31 +1063,36 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
|
|||
ExPolygons enforcer_polygons = diff_ex(intersection_ex(layer->lslices, enforcer),
|
||||
// Inflate just a tiny bit to avoid intersection of the overhang areas with the object.
|
||||
expand(lower_layer_polygons, 0.05f * no_interface_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
||||
append(ts_layer->overhang_areas, enforcer_polygons);
|
||||
append(layer->loverhangs, enforcer_polygons);
|
||||
}
|
||||
}
|
||||
int nEnforced = ts_layer->overhang_areas.size();
|
||||
int nEnforced = layer->loverhangs.size();
|
||||
|
||||
// add sharp tail overhangs
|
||||
append(layer->loverhangs, sharp_tail_overhangs);
|
||||
|
||||
// fill overhang_types
|
||||
for (size_t i = 0; i < ts_layer->overhang_areas.size(); i++)
|
||||
ts_layer->overhang_types.emplace(&ts_layer->overhang_areas[i], i < nDetected ? SupportLayer::Detected :
|
||||
i < nEnforced ? SupportLayer::Enforced : SupportLayer::SharpTail);
|
||||
for (size_t i = 0; i < layer->loverhangs.size(); i++)
|
||||
overhang_types.emplace(&layer->loverhangs[i], i < nDetected ? OverhangType::Detected :
|
||||
i < nEnforced ? OverhangType::Enforced : OverhangType::SharpTail);
|
||||
|
||||
if (!ts_layer->overhang_areas.empty()) {
|
||||
has_overhangs = true;
|
||||
if (!layer->loverhangs.empty()) {
|
||||
layers_with_overhangs++;
|
||||
m_highest_overhang_layer = std::max(m_highest_overhang_layer, size_t(layer_nr));
|
||||
}
|
||||
if (!layer->cantilevers.empty()) has_cantilever = true;
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Tree support overhang detection done. " << layers_with_overhangs << " layers with overhangs.";
|
||||
|
||||
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
|
||||
for (const SupportLayer* layer : m_object->support_layers()) {
|
||||
if (layer->overhang_areas.empty() && (blockers.size()<=layer->id() || blockers[layer->id()].empty()))
|
||||
for (const Layer* layer : m_object->layers()) {
|
||||
if (layer->loverhangs.empty() && (blockers.size()<=layer->id() || blockers[layer->id()].empty()))
|
||||
continue;
|
||||
|
||||
SVG::export_expolygons(debug_out_path("overhang_areas_%.2f.svg", layer->print_z), {
|
||||
SVG::export_expolygons(debug_out_path("overhang_areas_%d_%.2f.svg",layer->id(), layer->print_z), {
|
||||
{ m_object->get_layer(layer->id())->lslices, {"lslices","yellow",0.5} },
|
||||
{ layer->overhang_areas, {"overhang","red",0.5} }
|
||||
{ layer->loverhangs, {"overhang","red",0.5} }
|
||||
});
|
||||
|
||||
if (enforcers.size() > layer->id()) {
|
||||
|
@ -1595,12 +1598,11 @@ void TreeSupport::generate()
|
|||
|
||||
// Generate overhang areas
|
||||
profiler.stage_start(STAGE_DETECT_OVERHANGS);
|
||||
m_object->print()->set_status(55, _u8L("Generating supports"));
|
||||
m_object->print()->set_status(55, _u8L("Generating support"));
|
||||
detect_overhangs();
|
||||
profiler.stage_finish(STAGE_DETECT_OVERHANGS);
|
||||
|
||||
if (!has_overhangs) return;
|
||||
|
||||
create_tree_support_layers();
|
||||
m_ts_data = m_object->alloc_tree_support_preview_cache();
|
||||
m_ts_data->is_slim = is_slim;
|
||||
|
||||
|
@ -1610,13 +1612,13 @@ void TreeSupport::generate()
|
|||
std::vector<TreeSupport3D::SupportElements> move_bounds(m_highest_overhang_layer + 1);
|
||||
profiler.stage_start(STAGE_GENERATE_CONTACT_NODES);
|
||||
m_object->print()->set_status(56, _u8L("Support: generate contact points"));
|
||||
generate_contact_points(contact_nodes, move_bounds);
|
||||
generate_contact_points(contact_nodes);
|
||||
profiler.stage_finish(STAGE_GENERATE_CONTACT_NODES);
|
||||
|
||||
|
||||
//Drop nodes to lower layers.
|
||||
profiler.stage_start(STAGE_DROP_DOWN_NODES);
|
||||
m_object->print()->set_status(60, _u8L("Generating supports"));
|
||||
m_object->print()->set_status(60, _u8L("Generating support"));
|
||||
drop_nodes(contact_nodes);
|
||||
profiler.stage_finish(STAGE_DROP_DOWN_NODES);
|
||||
|
||||
|
@ -1624,14 +1626,14 @@ void TreeSupport::generate()
|
|||
|
||||
//Generate support areas.
|
||||
profiler.stage_start(STAGE_DRAW_CIRCLES);
|
||||
m_object->print()->set_status(65, _u8L("Generating supports"));
|
||||
m_object->print()->set_status(65, _u8L("Generating support"));
|
||||
draw_circles(contact_nodes);
|
||||
profiler.stage_finish(STAGE_DRAW_CIRCLES);
|
||||
|
||||
|
||||
|
||||
profiler.stage_start(STAGE_GENERATE_TOOLPATHS);
|
||||
m_object->print()->set_status(69, _u8L("Generating supports"));
|
||||
m_object->print()->set_status(70, _u8L("Generating support"));
|
||||
generate_toolpaths();
|
||||
profiler.stage_finish(STAGE_GENERATE_TOOLPATHS);
|
||||
|
||||
|
@ -1922,7 +1924,6 @@ void TreeSupport::draw_circles(const std::vector<std::vector<SupportNode*>>& con
|
|||
coordf_t max_layers_above_roof = 0;
|
||||
coordf_t max_layers_above_roof1 = 0;
|
||||
int interface_id = 0;
|
||||
bool has_polygon_node = false;
|
||||
bool has_circle_node = false;
|
||||
bool need_extra_wall = false;
|
||||
ExPolygons collision_sharp_tails;
|
||||
|
@ -1943,6 +1944,7 @@ void TreeSupport::draw_circles(const std::vector<std::vector<SupportNode*>>& con
|
|||
BOOST_LOG_TRIVIAL(debug) << "circles at layer " << layer_nr << " contact nodes size=" << contact_nodes[layer_nr].size();
|
||||
//Draw the support areas and add the roofs appropriately to the support roof instead of normal areas.
|
||||
ts_layer->lslices.reserve(contact_nodes[layer_nr].size());
|
||||
ExPolygons area_poly; // the polygon node area which will be printed as normal support
|
||||
for (const SupportNode* p_node : contact_nodes[layer_nr])
|
||||
{
|
||||
if (print->canceled())
|
||||
|
@ -1959,9 +1961,9 @@ void TreeSupport::draw_circles(const std::vector<std::vector<SupportNode*>>& con
|
|||
else {
|
||||
area = offset_ex({ node.overhang }, scale_(m_ts_data->m_xy_distance));
|
||||
}
|
||||
if (node.type == ePolygon)
|
||||
has_polygon_node = true;
|
||||
area = diff_clipped(area, get_collision(node.is_sharp_tail && node.distance_to_top <= 0));
|
||||
if (node.type == ePolygon)
|
||||
area_poly = area;
|
||||
}
|
||||
else {
|
||||
Polygon circle(branch_circle);
|
||||
|
@ -2084,8 +2086,8 @@ void TreeSupport::draw_circles(const std::vector<std::vector<SupportNode*>>& con
|
|||
auto &area_groups = ts_layer->area_groups;
|
||||
for (auto& area : ts_layer->base_areas) {
|
||||
area_groups.emplace_back(&area, SupportLayer::BaseType, max_layers_above_base);
|
||||
area_groups.back().need_infill = has_polygon_node;
|
||||
// area_groups.back().need_extra_wall = need_extra_wall;
|
||||
area_groups.back().need_infill = overlaps({ area }, area_poly);
|
||||
area_groups.back().need_extra_wall = need_extra_wall;
|
||||
}
|
||||
for (auto& area : ts_layer->roof_areas) {
|
||||
area_groups.emplace_back(&area, SupportLayer::RoofType, max_layers_above_roof);
|
||||
|
@ -2423,13 +2425,14 @@ void TreeSupport::drop_nodes(std::vector<std::vector<SupportNode*>>& contact_nod
|
|||
continue;
|
||||
|
||||
int layer_nr_next = layer_heights[layer_nr].next_layer_nr;
|
||||
coordf_t print_z = layer_heights[layer_nr].print_z;
|
||||
coordf_t print_z_next = layer_heights[layer_nr_next].print_z;
|
||||
coordf_t height_next = layer_heights[layer_nr_next].height;
|
||||
|
||||
std::deque<std::pair<size_t, SupportNode*>> unsupported_branch_leaves; // All nodes that are leaves on this layer that would result in unsupported ('mid-air') branches.
|
||||
const Layer* ts_layer = m_object->get_support_layer(layer_nr);
|
||||
|
||||
m_object->print()->set_status(60 + int(10 * (1 - float(layer_nr) / contact_nodes.size())), _u8L("Generating supports"));// (boost::format(_u8L("Support: propagate branches at layer %d")) % layer_nr).str());
|
||||
m_object->print()->set_status(60 + int(10 * (1 - float(layer_nr) / contact_nodes.size())), _u8L("Generating support"));// (boost::format(_u8L("Support: propagate branches at layer %d")) % layer_nr).str());
|
||||
|
||||
Polygons layer_contours = std::move(m_ts_data->get_contours_with_holes(layer_nr));
|
||||
//std::unordered_map<Line, bool, LineHash>& mst_line_x_layer_contour_cache = m_mst_line_x_layer_contour_caches[layer_nr];
|
||||
|
@ -3034,7 +3037,7 @@ std::vector<LayerHeightData> TreeSupport::plan_layer_heights(std::vector<std::ve
|
|||
return layer_heights;
|
||||
}
|
||||
|
||||
void TreeSupport::generate_contact_points(std::vector<std::vector<SupportNode*>>& contact_nodes, const std::vector<TreeSupport3D::SupportElements>& move_bounds)
|
||||
void TreeSupport::generate_contact_points(std::vector<std::vector<SupportNode*>>& contact_nodes)
|
||||
{
|
||||
const PrintObjectConfig &config = m_object->config();
|
||||
const coordf_t point_spread = scale_(config.tree_support_branch_distance.value);
|
||||
|
@ -3092,8 +3095,8 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<SupportNode*>>
|
|||
// fix bug of generating support for very thin objects
|
||||
if (m_object->layers().size() <= z_distance_top_layers + 1)
|
||||
return;
|
||||
if (m_object->support_layer_count() <= m_raft_layers)
|
||||
return;
|
||||
//if (m_object->support_layer_count() <= m_raft_layers)
|
||||
// return;
|
||||
|
||||
int nonempty_layers = 0;
|
||||
tbb::concurrent_vector<Slic3r::Vec3f> all_nodes;
|
||||
|
@ -3101,10 +3104,10 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<SupportNode*>>
|
|||
for (size_t layer_nr = range.begin(); layer_nr < range.end(); layer_nr++) {
|
||||
if (m_object->print()->canceled())
|
||||
break;
|
||||
auto ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers);
|
||||
Layer* layer = m_object->get_layer(layer_nr);
|
||||
auto& curr_nodes = contact_nodes[layer_nr - 1];
|
||||
if (ts_layer->overhang_areas.empty()) continue;
|
||||
if (layer->loverhangs.empty()) continue;
|
||||
|
||||
std::unordered_set<Point, PointHash> already_inserted;
|
||||
auto print_z = m_object->get_layer(layer_nr)->print_z;
|
||||
auto bottom_z = m_object->get_layer(layer_nr)->bottom_z();
|
||||
|
@ -3138,9 +3141,9 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<SupportNode*>>
|
|||
return contact_node;
|
||||
};
|
||||
|
||||
for (const auto& area_type : ts_layer->overhang_types) {
|
||||
const auto& overhang_part = *area_type.first;
|
||||
is_sharp_tail = area_type.second == SupportLayer::SharpTail;
|
||||
for (const auto& overhang_part : layer->loverhangs) {
|
||||
const auto& overhang_type = this->overhang_types[&overhang_part];
|
||||
is_sharp_tail = overhang_type == OverhangType::SharpTail;
|
||||
BoundingBox overhang_bounds = get_extents(overhang_part);
|
||||
if (m_support_params.support_style == smsTreeHybrid && overhang_part.area() > m_support_params.thresh_big_overhang && !is_sharp_tail) {
|
||||
if (!overlaps({ overhang_part }, m_ts_data->m_layer_outlines_below[layer_nr - 1])) {
|
||||
|
@ -3169,55 +3172,42 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<SupportNode*>>
|
|||
}
|
||||
}
|
||||
}
|
||||
auto& move_bounds_layer = move_bounds[layer_nr];
|
||||
if (move_bounds_layer.empty()) {
|
||||
overhang_bounds.inflated(half_overhang_distance);
|
||||
bool added = false; //Did we add a point this way?
|
||||
|
||||
// add supports along contours
|
||||
libnest2d::placers::EdgeCache<ExPolygon> edge_cache(overhang_part);
|
||||
for (size_t i = 0; i < edge_cache.holeCount() + 1; i++) {
|
||||
double step = point_spread / (i == 0 ? edge_cache.circumference() : edge_cache.circumference(i - 1));
|
||||
double distance = 0;
|
||||
while (distance < 1) {
|
||||
auto pt = i == 0 ? edge_cache.coords(distance) : edge_cache.coords(i - 1, distance);
|
||||
SupportNode* contact_node = insert_point(pt, overhang_part);
|
||||
distance += step;
|
||||
}
|
||||
}
|
||||
|
||||
// don't add inner supports for sharp tails
|
||||
if (is_sharp_tail)
|
||||
continue;
|
||||
|
||||
// add inner supports
|
||||
overhang_bounds.inflated(-radius);
|
||||
ExPolygons overhang_inner = offset_ex(overhang_part, -radius);
|
||||
for (Point candidate : grid_points) {
|
||||
if (overhang_bounds.contains(candidate)) {
|
||||
// BBS: move_inside_expoly shouldn't be used if candidate is already inside, as it moves point to boundary and the inside is not well supported!
|
||||
bool is_inside = is_inside_ex(overhang_part, candidate);
|
||||
if (!is_inside) {
|
||||
constexpr coordf_t distance_inside = 0; // Move point towards the border of the polygon if it is closer than half the overhang distance: Catch points that
|
||||
// fall between overhang areas on constant surfaces.
|
||||
is_inside = move_inside_expoly(overhang_part, candidate, distance_inside, half_overhang_distance);
|
||||
}
|
||||
bool is_inside = is_inside_ex(overhang_inner, candidate);
|
||||
if (is_inside) {
|
||||
SupportNode* contact_node = insert_point(candidate, overhang_part);
|
||||
if (contact_node)
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!added) //If we didn't add any points due to bad luck, we want to add one anyway such that loose parts are also supported.
|
||||
{
|
||||
auto bbox = overhang_part.contour.bounding_box();
|
||||
Points candidates;
|
||||
if (ts_layer->overhang_types[&overhang_part] == SupportLayer::Detected)
|
||||
candidates = { bbox.min, bounding_box_middle(bbox), bbox.max };
|
||||
else
|
||||
candidates = { bounding_box_middle(bbox) };
|
||||
for (Point candidate : candidates) {
|
||||
if (!overhang_part.contains(candidate))
|
||||
move_inside_expoly(overhang_part, candidate);
|
||||
insert_point(candidate, overhang_part);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (auto& elem : move_bounds_layer) {
|
||||
SupportNode* contact_node = m_ts_data->create_node(elem.state.result_on_layer, -gap_layers, layer_nr-1, support_roof_layers + 1, elem.state.to_buildplate,
|
||||
SupportNode::NO_PARENT, print_z, height, z_distance_top);
|
||||
contact_node->overhang = ExPolygon(elem.influence_area.front());
|
||||
curr_nodes.emplace_back(contact_node);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (!curr_nodes.empty()) nonempty_layers++;
|
||||
for (auto node : curr_nodes) { all_nodes.emplace_back(node->position(0), node->position(1), scale_(node->print_z)); }
|
||||
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
|
||||
draw_contours_and_nodes_to_svg(debug_out_path("init_contact_points_%.2f.svg", print_z), ts_layer->overhang_areas, m_ts_data->m_layer_outlines_below[layer_nr], {},
|
||||
contact_nodes[layer_nr], contact_nodes[layer_nr - 1], { "overhang","outlines","" });
|
||||
draw_contours_and_nodes_to_svg(debug_out_path("init_contact_points_%.2f.svg", print_z), layer->loverhangs,layer->lslices, m_ts_data->m_layer_outlines_below[layer_nr],
|
||||
contact_nodes[layer_nr], contact_nodes[layer_nr - 1], { "overhang","lslices","outlines_below"});
|
||||
#endif
|
||||
}}
|
||||
); // end tbb::parallel_for
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue