mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-08 15:37:30 -06:00
Update the codes to 01.01.00.10 for the formal release
1. first formal version of macos 2. add the bambu networking plugin install logic 3. auto compute the wipe volume when filament change 4. add the logic of wiping into support 5. refine the GUI layout and icons, improve the gui apperance in lots of small places 6. serveral improve to support 7. support AMS auto-mapping 8. disable lots of unstable features: such as params table, media file download, HMS 9. fix serveral kinds of bugs 10. update the document of building 11. ...
This commit is contained in:
parent
e1528e4299
commit
e9e4d75877
267 changed files with 10326 additions and 32228 deletions
|
@ -9,15 +9,11 @@
|
|||
#include "SVG.hpp"
|
||||
#include "ShortestPath.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include <libnest2d/backends/libslic3r/geometries.hpp>
|
||||
|
||||
#define _L(s) Slic3r::I18N::translate(s)
|
||||
|
||||
#define SQUARE_SUPPORT 0
|
||||
#if SQUARE_SUPPORT
|
||||
#define CIRCLE_RESOLUTION 4 // 100 //The number of vertices in each circle.
|
||||
#else
|
||||
#define CIRCLE_RESOLUTION 100 //The number of vertices in each circle.
|
||||
#endif
|
||||
|
||||
#define MAX_BRANCH_RADIUS 10.0
|
||||
#define HEIGHT_TO_SWITCH_INFILL_DIRECTION 30 // change infill direction every 20mm
|
||||
#define DO_NOT_MOVER_UNDER_MM 5 // do not move contact points under 5mm
|
||||
|
@ -31,7 +27,7 @@
|
|||
#define TAU (2.0 * M_PI)
|
||||
#define NO_INDEX (std::numeric_limits<unsigned int>::max())
|
||||
|
||||
//#define SUPPORT_TREE_DEBUG_TO_SVG
|
||||
#define SUPPORT_TREE_DEBUG_TO_SVG
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
|
@ -225,14 +221,18 @@ static void draw_contours_and_nodes_to_svg
|
|||
bbox.max.x() = std::max(bbox.max.x(), (coord_t)scale_(10));
|
||||
bbox.max.y() = std::max(bbox.max.y(), (coord_t)scale_(10));
|
||||
|
||||
SVG svg(get_svg_filename(std::to_string(layer_nr), name_prefix), bbox);
|
||||
SVG svg;
|
||||
if(layer_nr>=0)
|
||||
svg.open(get_svg_filename(std::to_string(layer_nr), name_prefix), bbox);
|
||||
else
|
||||
svg.open(name_prefix, bbox);
|
||||
if (!svg.is_opened()) return;
|
||||
|
||||
// draw grid
|
||||
svg.draw_grid(bbox, "gray", coord_t(scale_(0.05)));
|
||||
|
||||
// draw overhang areas
|
||||
svg.draw(union_ex(overhangs), colors[0]);
|
||||
svg.draw_outline(union_ex(overhangs), colors[0]);
|
||||
svg.draw_outline(union_ex(overhangs_after_offset), colors[1]);
|
||||
svg.draw_outline(outlines_below, colors[2]);
|
||||
|
||||
|
@ -661,6 +661,8 @@ void TreeSupport::detect_object_overhangs()
|
|||
|
||||
// Create Tree Support Layers
|
||||
m_object->clear_tree_support_layers();
|
||||
m_object->clear_tree_support_preview_cache();
|
||||
|
||||
create_tree_support_layers();
|
||||
m_ts_data = m_object->alloc_tree_support_preview_cache();
|
||||
|
||||
|
@ -932,7 +934,7 @@ void TreeSupport::detect_object_overhangs()
|
|||
|
||||
|
||||
if (bridge_no_support && overhang_areas.size()>0) {
|
||||
m_object->remove_bridges_from_contacts(lower_layer, layer, extrusion_width_scaled, &overhang_areas, max_bridge_length);
|
||||
m_object->remove_bridges_from_contacts(lower_layer, layer, extrusion_width_scaled, &overhang_areas, max_bridge_length, true);
|
||||
}
|
||||
|
||||
TreeSupportLayer* ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers);
|
||||
|
@ -1081,9 +1083,6 @@ void TreeSupport::detect_object_overhangs()
|
|||
}
|
||||
}
|
||||
|
||||
total_overhang_area = 0;
|
||||
max_overhang_area = 0;
|
||||
total_overhang_layer_cnt = 0;
|
||||
for (int layer_nr = 0; layer_nr < m_object->layer_count(); layer_nr++) {
|
||||
if (m_object->print()->canceled())
|
||||
break;
|
||||
|
@ -1095,6 +1094,10 @@ void TreeSupport::detect_object_overhangs()
|
|||
ts_layer->overhang_areas = diff_ex(ts_layer->overhang_areas, offset_ex(blocker, scale_(radius_sample_resolution)));
|
||||
}
|
||||
|
||||
for (auto &area : ts_layer->overhang_areas) {
|
||||
ts_layer->overhang_types.emplace(&area, TreeSupportLayer::Detected);
|
||||
}
|
||||
|
||||
if (layer_nr < enforcers.size()) {
|
||||
Polygons& enforcer = enforcers[layer_nr];
|
||||
// coconut: enforcer can't do offset2_ex, otherwise faces with angle near 90 degrees can't have enforcers, which
|
||||
|
@ -1102,15 +1105,9 @@ void TreeSupport::detect_object_overhangs()
|
|||
//enforcer = std::move(offset2_ex(enforcer, -0.1 * extrusion_width_scaled, 0.1 * extrusion_width_scaled));
|
||||
for (const Polygon& poly : enforcer) {
|
||||
ts_layer->overhang_areas.emplace_back(poly);
|
||||
ts_layer->overhang_types.emplace(&ts_layer->overhang_areas.back(), TreeSupportLayer::Enforced);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ts_layer->overhang_areas.empty()) {
|
||||
float a = area(ts_layer->overhang_areas);
|
||||
total_overhang_area += a;
|
||||
max_overhang_area = std::max(max_overhang_area, a);
|
||||
total_overhang_layer_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
|
||||
|
@ -1825,17 +1822,25 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
|
|||
{
|
||||
const PrintObjectConfig &config = m_object->config();
|
||||
bool has_brim = m_object->print()->has_brim();
|
||||
bool has_infill = config.tree_support_with_infill.value;
|
||||
int bottom_gap_layers = round(m_slicing_params.gap_object_support / m_slicing_params.layer_height);
|
||||
const coordf_t branch_radius = config.tree_support_branch_diameter.value / 2;
|
||||
const coordf_t branch_radius_scaled = scale_(branch_radius);
|
||||
Polygon branch_circle; //Pre-generate a circle with correct diameter so that we don't have to recompute those (co)sines every time.
|
||||
|
||||
// Use square support if there are too many nodes per layer because circle support needs much longer time to compute
|
||||
// Hower circle support can be printed faster, so we prefer circle for fewer nodes case.
|
||||
const bool SQUARE_SUPPORT = avg_node_per_layer > 200;
|
||||
const int CIRCLE_RESOLUTION = SQUARE_SUPPORT ? 4 : 100; // The number of vertices in each circle.
|
||||
|
||||
|
||||
for (unsigned int i = 0; i < CIRCLE_RESOLUTION; i++)
|
||||
{
|
||||
#if SQUARE_SUPPORT
|
||||
double angle = (double)i / CIRCLE_RESOLUTION * TAU + TAU/8.0;
|
||||
#else
|
||||
double angle = (double)i / CIRCLE_RESOLUTION * TAU;
|
||||
#endif
|
||||
double angle;
|
||||
if (SQUARE_SUPPORT)
|
||||
angle = (double) i / CIRCLE_RESOLUTION * TAU + PI / 4.0 + nodes_angle;
|
||||
else
|
||||
angle = (double) i / CIRCLE_RESOLUTION * TAU;
|
||||
branch_circle.append(Point(cos(angle) * branch_radius_scaled, sin(angle) * branch_radius_scaled));
|
||||
}
|
||||
|
||||
|
@ -1850,7 +1855,6 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
|
|||
}
|
||||
|
||||
// generate areas
|
||||
const coordf_t circle_side_length = 2 * branch_radius * sin(M_PI / CIRCLE_RESOLUTION); //Side length of a regular polygon.
|
||||
const coordf_t layer_height = config.layer_height.value;
|
||||
const size_t top_interface_layers = config.support_interface_top_layers.value;
|
||||
const size_t bottom_interface_layers = config.support_interface_bottom_layers.value;
|
||||
|
@ -2024,16 +2028,12 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
|
|||
base_areas = std::move(diff_ex(base_areas, roof_areas));
|
||||
base_areas = std::move(diff_ex(base_areas, roof_1st_layer));
|
||||
|
||||
#if SQUARE_SUPPORT
|
||||
if (m_object->print()->config().enable_arc_fitting.value == false) {
|
||||
// simplify support contours if arc fitting is disabled
|
||||
if (SQUARE_SUPPORT) {
|
||||
// simplify support contours
|
||||
ExPolygons base_areas_simplified;
|
||||
for (auto& area : base_areas) {
|
||||
area.simplify(scale_(line_width / 2), &base_areas_simplified, SimplifyMethodDP);
|
||||
}
|
||||
for (auto &area : base_areas) { area.simplify(scale_(line_width / 2), &base_areas_simplified, SimplifyMethodDP); }
|
||||
base_areas = std::move(base_areas_simplified);
|
||||
}
|
||||
#endif
|
||||
//Subtract support floors. We can only compute floor_areas here instead of with roof_areas,
|
||||
// or we'll get much wider floor than necessary.
|
||||
if (bottom_interface_layers + bottom_gap_layers > 0)
|
||||
|
@ -2073,15 +2073,13 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
|
|||
}),
|
||||
expoly->holes.end());
|
||||
}
|
||||
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
|
||||
draw_contours_and_nodes_to_svg(layer_nr, base_areas, roof_areas, roof_1st_layer, {}, {}, "circles", { "base","roof","roof1st" });
|
||||
#endif
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
#if 1
|
||||
// move the holes to contour so they can be well supported
|
||||
|
||||
if (!has_infill) {
|
||||
// check if poly's contour intersects with expoly's contour
|
||||
auto intersects_contour = [](Polygon poly, ExPolygon expoly, Point &pt_on_poly, Point &pt_on_expoly, Point &pt_far_on_poly, float dist_thresh = 0.01) {
|
||||
float min_dist = std::numeric_limits<float>::max();
|
||||
|
@ -2099,18 +2097,15 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
|
|||
max_dist = dist2;
|
||||
pt_far_on_poly = from;
|
||||
}
|
||||
if (dist2 < dist_thresh) {
|
||||
return true;
|
||||
}
|
||||
if (dist2 < dist_thresh) { return true; }
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
std::map<const Polygon *, int> holeDepth;
|
||||
std::map<const Polygon *, Point> holeDiretions;
|
||||
std::map<const Polygon *, Point> holeFarPoints;
|
||||
for (int layer_nr = m_object->layer_count()-1; layer_nr >0; layer_nr--) {
|
||||
// polygon pointer: depth, direction, farPoint
|
||||
std::map<const Polygon *, std::tuple<int, Point, Point>> holePropagationInfos;
|
||||
for (int layer_nr = m_object->layer_count() - 1; layer_nr > 0; layer_nr--) {
|
||||
if (print->canceled()) break;
|
||||
m_object->print()->set_status(66, (boost::format(_L("Support: fix holes at layer %d")) % layer_nr).str());
|
||||
|
||||
|
@ -2127,47 +2122,88 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
|
|||
for (layer_nr_lower; layer_nr_lower >= 0; layer_nr_lower--) {
|
||||
if (!m_object->get_tree_support_layer(layer_nr_lower + m_raft_layers)->area_groups.empty()) break;
|
||||
}
|
||||
auto & area_groups_lower = m_object->get_tree_support_layer(layer_nr_lower + m_raft_layers)->area_groups;
|
||||
auto &area_groups_lower = m_object->get_tree_support_layer(layer_nr_lower + m_raft_layers)->area_groups;
|
||||
|
||||
for (const auto& area_group:ts_layer->area_groups){
|
||||
if (area_group.second == 1 || area_group.second == 2) continue;
|
||||
const auto base_area = area_group.first;
|
||||
for (const auto &hole : base_area->holes) {
|
||||
for (const auto &area_group : ts_layer->area_groups) {
|
||||
if (area_group.second != TreeSupportLayer::BaseType) continue;
|
||||
const auto area = area_group.first;
|
||||
for (const auto &hole : area->holes) {
|
||||
// auto hole_bbox = get_extents(hole).polygon();
|
||||
for (auto & area_group_lower: area_groups_lower) {
|
||||
if (area_group.second == 1 || area_group.second == 2) continue;
|
||||
for (auto &area_group_lower : area_groups_lower) {
|
||||
if (area_group.second != TreeSupportLayer::BaseType) continue;
|
||||
auto &base_area_lower = *area_group_lower.first;
|
||||
Point pt_on_poly, pt_on_expoly, pt_far_on_poly;
|
||||
// if a hole doesn't intersect with lower layer's contours, add a hole to lower layer and move it slightly to the contour
|
||||
if (base_area_lower.contour.contains(hole.points.front()) && !intersects_contour(hole, base_area_lower, pt_on_poly, pt_on_expoly, pt_far_on_poly)) {
|
||||
Polygon hole_lower = hole;
|
||||
Point direction = normal(pt_on_expoly - pt_on_poly, line_width_scaled/2);
|
||||
Point direction = normal(pt_on_expoly - pt_on_poly, line_width_scaled / 2);
|
||||
hole_lower.translate(direction);
|
||||
// note to expand a hole, we need to do negative offset
|
||||
auto hole_expanded = offset(hole_lower, -line_width_scaled / 4, ClipperLib::JoinType::jtSquare);
|
||||
if (!hole_expanded.empty()) {
|
||||
base_area_lower.holes.push_back(std::move(hole_expanded[0]));
|
||||
holeDepth.insert({&base_area_lower.holes.back(), 15});
|
||||
holeDiretions.insert({&base_area_lower.holes.back(), direction});
|
||||
holeFarPoints.insert({&base_area_lower.holes.back(), pt_far_on_poly});
|
||||
holePropagationInfos.insert({&base_area_lower.holes.back(), {25, direction, pt_far_on_poly}});
|
||||
}
|
||||
break;
|
||||
} else if (holeDepth.find(&hole) != holeDepth.end() && holeDepth[&hole] > 0 && base_area_lower.contour.contains(holeFarPoints[&hole])) {
|
||||
} else if (holePropagationInfos.find(&hole) != holePropagationInfos.end() && std::get<0>(holePropagationInfos[&hole]) > 0 &&
|
||||
base_area_lower.contour.contains(std::get<2>(holePropagationInfos[&hole]))) {
|
||||
Polygon hole_lower = hole;
|
||||
hole_lower.translate(holeDiretions[&hole]);
|
||||
Point farPoint = holeFarPoints[&hole] + holeDiretions[&hole];
|
||||
{
|
||||
base_area_lower.holes.push_back(std::move(hole_lower));
|
||||
holeDepth.insert({&base_area_lower.holes.back(), holeDepth[&hole]-1});
|
||||
holeDiretions.insert({&base_area_lower.holes.back(), holeDiretions[&hole]});
|
||||
holeFarPoints.insert({&base_area_lower.holes.back(), farPoint});
|
||||
auto && direction = std::get<1>(holePropagationInfos[&hole]);
|
||||
hole_lower.translate(direction);
|
||||
// note to shrink a hole, we need to do positive offset
|
||||
auto hole_expanded = offset(hole_lower, line_width_scaled / 2, ClipperLib::JoinType::jtSquare);
|
||||
Point farPoint = std::get<2>(holePropagationInfos[&hole]) + direction * 2;
|
||||
if (!hole_expanded.empty()) {
|
||||
base_area_lower.holes.push_back(std::move(hole_expanded[0]));
|
||||
holePropagationInfos.insert({&base_area_lower.holes.back(), {std::get<0>(holePropagationInfos[&hole]) - 1, direction, farPoint}});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
{
|
||||
// if roof1 interface is inside a hole, need to expand the interface
|
||||
for (auto &roof1 : ts_layer->roof_1st_layer) {
|
||||
//if (hole.contains(roof1.contour.points.front()) && hole.contains(roof1.contour.bounding_box().center()))
|
||||
bool is_inside_hole = std::all_of(roof1.contour.points.begin(), roof1.contour.points.end(), [&hole](Point &pt) { return hole.contains(pt); });
|
||||
if (is_inside_hole) {
|
||||
Polygon hole_reoriented = hole;
|
||||
if (roof1.contour.is_counter_clockwise())
|
||||
hole_reoriented.make_counter_clockwise();
|
||||
else if (roof1.contour.is_clockwise())
|
||||
hole_reoriented.make_clockwise();
|
||||
auto tmp = union_({roof1.contour}, {hole_reoriented});
|
||||
if (!tmp.empty()) roof1.contour = tmp[0];
|
||||
|
||||
// make sure 1) roof1 and object 2) roof1 and roof, won't intersect
|
||||
// Note: We can't replace roof1 directly, as we have recorded its address.
|
||||
// So instead we need to replace its members one by one.
|
||||
auto tmp1 = diff_ex(roof1, m_ts_data->get_collision((layer_nr == 0 && has_brim) ? config.brim_object_gap : m_ts_data->m_xy_distance, layer_nr));
|
||||
tmp1 = diff_ex(tmp1, ts_layer->roof_areas);
|
||||
if (!tmp1.empty()) {
|
||||
roof1.contour = std::move(tmp1[0].contour);
|
||||
roof1.holes = std::move(tmp1[0].holes);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
|
||||
for (int layer_nr = m_object->layer_count() - 1; layer_nr > 0; layer_nr--) {
|
||||
TreeSupportLayer* ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers);
|
||||
ExPolygons& base_areas = ts_layer->base_areas;
|
||||
ExPolygons& roof_areas = ts_layer->roof_areas;
|
||||
ExPolygons& roof_1st_layer = ts_layer->roof_1st_layer;
|
||||
ExPolygons& floor_areas = ts_layer->floor_areas;
|
||||
if (base_areas.empty() && roof_areas.empty() && roof_1st_layer.empty()) continue;
|
||||
char fname[10]; sprintf(fname, "%d_%.2f", layer_nr, ts_layer->print_z);
|
||||
draw_contours_and_nodes_to_svg(-1, base_areas, roof_areas, roof_1st_layer, {}, {}, get_svg_filename(fname, "circles"), {"base", "roof", "roof1st"});
|
||||
}
|
||||
#endif
|
||||
|
||||
TreeSupportLayerPtrs& ts_layers = m_object->tree_support_layers();
|
||||
|
@ -2257,6 +2293,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
|||
next_node->distance_to_top++;
|
||||
next_node->support_roof_layers_below--;
|
||||
next_node->print_z -= m_object->get_layer(layer_nr)->height;
|
||||
next_node->to_buildplate = !is_inside_ex(m_ts_data->m_layer_outlines[layer_nr], next_node->position);
|
||||
contact_nodes[layer_nr - 1].emplace_back(next_node);
|
||||
}
|
||||
}
|
||||
|
@ -2290,10 +2327,6 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
|||
for (Node* p_node : layer_contact_nodes)
|
||||
{
|
||||
const Node& node = *p_node;
|
||||
if (node.type == ePolygon) {
|
||||
// polygon node do not merge or move
|
||||
continue;
|
||||
}
|
||||
|
||||
if (support_on_buildplate_only && !node.to_buildplate) //Can't rest on model and unable to reach the build plate. Then we must drop the node and leave parts unsupported.
|
||||
{
|
||||
|
@ -2305,6 +2338,10 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
|||
nodes_per_part[0][node.position] = p_node;
|
||||
continue;
|
||||
}
|
||||
if (node.type == ePolygon) {
|
||||
// polygon node do not merge or move
|
||||
continue;
|
||||
}
|
||||
/* Find which part this node is located in and group the nodes in
|
||||
* the same part together. Since nodes have a radius and the
|
||||
* avoidance areas are offset by that radius, the set of parts may
|
||||
|
@ -2720,7 +2757,7 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
|
|||
coordf_t z_distance_top = m_slicing_params.gap_support_object;
|
||||
// BBS: add extra distance if thick bridge is enabled
|
||||
// Note: normal support uses print_z, but tree support uses integer layers, so we need to subtract layer_height
|
||||
if (!m_slicing_params.soluble_interface && g_config_thick_bridges) {
|
||||
if (!m_slicing_params.soluble_interface && m_object_config->thick_bridges) {
|
||||
z_distance_top += m_object->layers()[0]->regions()[0]->region().bridging_height_avg(m_object->print()->config()) - layer_height;
|
||||
}
|
||||
const size_t z_distance_top_layers = round_up_divide(scale_(z_distance_top), scale_(layer_height)) + 1; //Support must always be 1 layer below overhang.
|
||||
|
@ -2729,17 +2766,20 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
|
|||
coordf_t thresh_angle = config.support_threshold_angle.value < EPSILON ? 30.f : config.support_threshold_angle.value;
|
||||
coordf_t half_overhang_distance = scale_(tan(thresh_angle * M_PI / 180.0) * layer_height / 2);
|
||||
|
||||
m_highest_overhang_layer = 0;
|
||||
// fix bug of generating support for very thin objects
|
||||
if (m_object->layers().size() <= z_distance_top_layers + 1)
|
||||
return;
|
||||
|
||||
m_highest_overhang_layer = 0;
|
||||
int nonempty_layers = 0;
|
||||
std::vector<Slic3r::Vec3f> all_nodes;
|
||||
for (size_t layer_nr = 1; layer_nr < m_object->layers().size() - z_distance_top_layers; layer_nr++)
|
||||
{
|
||||
if (m_object->print()->canceled())
|
||||
break;
|
||||
|
||||
const ExPolygons &overhang = m_object->get_tree_support_layer(layer_nr + m_raft_layers + z_distance_top_layers)->overhang_areas;
|
||||
auto ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers + z_distance_top_layers);
|
||||
const ExPolygons &overhang = ts_layer->overhang_areas;
|
||||
auto & curr_nodes = contact_nodes[layer_nr];
|
||||
if (overhang.empty())
|
||||
continue;
|
||||
|
||||
|
@ -2757,7 +2797,7 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
|
|||
Node *contact_node = new Node(candidate, 0, (layer_nr + z_distance_top_layers) % 2, support_roof_layers, true, Node::NO_PARENT, print_z, height);
|
||||
contact_node->type = ePolygon;
|
||||
contact_node->overhang = &overhang_part;
|
||||
contact_nodes[layer_nr].emplace_back(contact_node);
|
||||
curr_nodes.emplace_back(contact_node);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2783,7 +2823,7 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
|
|||
constexpr size_t distance_to_top = 0;
|
||||
constexpr bool to_buildplate = true;
|
||||
Node* contact_node = new Node(candidate, distance_to_top, (layer_nr + z_distance_top_layers) % 2, support_roof_layers, to_buildplate, Node::NO_PARENT,print_z,height);
|
||||
contact_nodes[layer_nr].emplace_back(contact_node);
|
||||
curr_nodes.emplace_back(contact_node);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
|
@ -2793,38 +2833,81 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
|
|||
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 = { bbox.min, bounding_box_middle(bbox), bbox.max };
|
||||
Points candidates;
|
||||
if (ts_layer->overhang_types[&overhang_part] == TreeSupportLayer::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);
|
||||
constexpr size_t distance_to_top = 0;
|
||||
constexpr bool to_buildplate = true;
|
||||
Node * contact_node = new Node(candidate, distance_to_top, layer_nr % 2, support_roof_layers, to_buildplate, Node::NO_PARENT, print_z, height);
|
||||
contact_nodes[layer_nr].emplace_back(contact_node);
|
||||
curr_nodes.emplace_back(contact_node);
|
||||
}
|
||||
}
|
||||
|
||||
// add points at corners
|
||||
auto& points = overhang_part.contour.points;
|
||||
for (int i=0;i<points.size();i++)
|
||||
{
|
||||
auto pt = points[i];
|
||||
auto v1 = (pt - points[(i - 1 + points.size()) % points.size()]).normalized();
|
||||
auto v2 = (pt - points[(i + 1) % points.size()]).normalized();
|
||||
if (v1.dot(v2) > -0.7) {
|
||||
Node* contact_node = new Node(pt, 0, layer_nr % 2, support_roof_layers, true, Node::NO_PARENT, print_z, height);
|
||||
contact_nodes[layer_nr].emplace_back(contact_node);
|
||||
if (ts_layer->overhang_types[&overhang_part] == TreeSupportLayer::Detected) {
|
||||
// add points at corners
|
||||
auto &points = overhang_part.contour.points;
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
auto pt = points[i];
|
||||
auto v1 = (pt - points[(i - 1 + points.size()) % points.size()]).normalized();
|
||||
auto v2 = (pt - points[(i + 1) % points.size()]).normalized();
|
||||
if (v1.dot(v2) > -0.7) {
|
||||
Node *contact_node = new Node(pt, 0, layer_nr % 2, support_roof_layers, true, Node::NO_PARENT, print_z, height);
|
||||
curr_nodes.emplace_back(contact_node);
|
||||
}
|
||||
}
|
||||
} else if(ts_layer->overhang_types[&overhang_part] == TreeSupportLayer::Enforced){
|
||||
// remove close points in Enforcers
|
||||
auto above_nodes = contact_nodes[layer_nr - 1];
|
||||
if (!curr_nodes.empty() && !above_nodes.empty()) {
|
||||
for (auto it = curr_nodes.begin(); it != curr_nodes.end();) {
|
||||
bool is_duplicate = false;
|
||||
Slic3r::Vec3f curr_pt((*it)->position(0), (*it)->position(1), scale_((*it)->print_z));
|
||||
for (auto &pt : all_nodes) {
|
||||
auto dif = curr_pt - pt;
|
||||
if (dif.norm() < scale_(2)) {
|
||||
delete (*it);
|
||||
it = curr_nodes.erase(it);
|
||||
is_duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_duplicate) it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
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(layer_nr, overhang, m_ts_data->m_layer_outlines_below[layer_nr], {},
|
||||
contact_nodes[layer_nr], {}, "init_contact_points", { "overhang","outlines","" });
|
||||
#endif
|
||||
}
|
||||
int nNodes = all_nodes.size();
|
||||
avg_node_per_layer = nodes_angle = 0;
|
||||
if (nNodes > 0) {
|
||||
avg_node_per_layer = nNodes / nonempty_layers;
|
||||
// get orientation of nodes by line fitting
|
||||
// line: y=kx+b, where
|
||||
// k=tan(nodes_angle)=(n\sum{xy}-\sum{x}\sum{y})/(n\sum{x^2}-\sum{x}^2)
|
||||
float mx = 0, my = 0, mxy = 0, mx2 = 0;
|
||||
for (auto &pt : all_nodes) {
|
||||
float x = unscale_(pt(0));
|
||||
float y = unscale_(pt(1));
|
||||
mx += x;
|
||||
my += y;
|
||||
mxy += x * y;
|
||||
mx2 += x * x;
|
||||
}
|
||||
nodes_angle = atan2(nNodes * mxy - mx * my, nNodes * mx2 - SQ(mx));
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "avg_node_per_layer=" << avg_node_per_layer << ", nodes_angle=" << nodes_angle;
|
||||
}
|
||||
}
|
||||
|
||||
void TreeSupport::insert_dropped_node(std::vector<Node*>& nodes_layer, Node* p_node)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue