diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index eb6d80389..591e2cbfb 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1363,7 +1363,7 @@ static inline std::vector> mmu_segmentation_top_and_bott if (!zs.empty() && is_volume_sinking(painted, volume_trafo)) { std::vector zs_sinking = {0.f}; Slic3r::append(zs_sinking, zs); - slice_mesh_slabs(painted, zs_sinking, volume_trafo, max_top_layers > 0 ? &top : nullptr, max_bottom_layers > 0 ? &bottom : nullptr, throw_on_cancel_callback); + slice_mesh_slabs(painted, zs_sinking, volume_trafo, max_top_layers > 0 ? &top : nullptr, max_bottom_layers > 0 ? &bottom : nullptr, nullptr, throw_on_cancel_callback); if (top.size() > 0) top.erase(top.begin()); @@ -1377,7 +1377,7 @@ static inline std::vector> mmu_segmentation_top_and_bott bottom[0] = union_(bottom[0], bottom_slice); } } else - slice_mesh_slabs(painted, zs, volume_trafo, max_top_layers > 0 ? &top : nullptr, max_bottom_layers > 0 ? &bottom : nullptr, throw_on_cancel_callback); + slice_mesh_slabs(painted, zs, volume_trafo, max_top_layers > 0 ? &top : nullptr, max_bottom_layers > 0 ? &bottom : nullptr, nullptr, throw_on_cancel_callback); auto merge = [](std::vector &&src, std::vector &dst) { auto it_src = find_if(src.begin(), src.end(), [](const Polygons &p){ return ! p.empty(); }); if (it_src != src.end()) { diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index ec42606a8..2d5168e36 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -429,7 +429,7 @@ public: std::vector slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); } // Helpers to project custom facets on slices - void project_and_append_custom_facets(bool seam, EnforcerBlockerType type, std::vector& expolys) const; + void project_and_append_custom_facets(bool seam, EnforcerBlockerType type, std::vector& expolys, std::vector>* vertical_points=nullptr) const; //BBS BoundingBox get_first_layer_bbox(float& area, float& layer_height, std::string& name); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index e33128f67..1755d866d 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -3820,7 +3820,7 @@ static void project_triangles_to_slabs(ConstLayerPtrsAdaptor layers, const index } void PrintObject::project_and_append_custom_facets( - bool seam, EnforcerBlockerType type, std::vector& out) const + bool seam, EnforcerBlockerType type, std::vector& out, std::vector>* vertical_points) const { for (const ModelVolume* mv : this->model_object()->volumes) if (mv->is_model_part()) { @@ -3835,7 +3835,7 @@ void PrintObject::project_and_append_custom_facets( else { std::vector projected; // Support blockers or enforcers. Project downward facing painted areas upwards to their respective slicing plane. - slice_mesh_slabs(custom_facets, zs_from_layers(this->layers()), this->trafo_centered() * mv->get_matrix(), nullptr, &projected, [](){}); + slice_mesh_slabs(custom_facets, zs_from_layers(this->layers()), this->trafo_centered() * mv->get_matrix(), nullptr, &projected, vertical_points, [](){}); // Merge these projections with the output, layer by layer. assert(! projected.empty()); assert(out.empty() || out.size() == projected.size()); diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index b058d957a..0427088ad 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -976,7 +976,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_object->project_and_append_custom_facets(false, EnforcerBlockerType::ENFORCER, enforcers); + 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); if (is_auto(stype) && config_remove_small_overhangs) { @@ -2890,12 +2891,17 @@ void TreeSupport::drop_nodes() movement = move_to_neighbor_center; // otherwise move to neighbor center first } - if (vsize2_with_unscale(movement) > get_max_move_dist(&node,2)) - movement = normal(movement, scale_(get_max_move_dist(&node))); + if (node.is_sharp_tail && node.dist_mm_to_top < 3) { + movement = normal(node.skin_direction, scale_(get_max_move_dist(&node))); + } + else if (dist2_to_outer > 0) + movement = normal(direction_to_outer, scale_(get_max_move_dist(&node))); + else + movement = normal(move_to_neighbor_center, scale_(get_max_move_dist(&node))); next_layer_vertex += movement; - if (group_index == 0) { + if (group_index == 0 && 0) { // Avoid collisions. const coordf_t max_move_between_samples = get_max_move_dist(&node, 1) + radius_sample_resolution + EPSILON; // 100 micron extra for rounding errors. bool is_outside = move_out_expolys(avoidance_next, next_layer_vertex, radius_sample_resolution + EPSILON, max_move_between_samples); @@ -3363,6 +3369,21 @@ void TreeSupport::generate_contact_points() tbb::spin_mutex mtx; + // add vertical enforcer points + std::vector zs = zs_from_layers(m_object->layers()); + std::vector>> vertical_enforcer_points_by_layers(m_object->layer_count()); + for (auto& pt_and_normal : m_vertical_enforcer_points) { + auto pt = pt_and_normal.first; + auto normal = pt_and_normal.second; // normal seems useless + auto iter = std::lower_bound(zs.begin(), zs.end(), pt.z()); + if (iter != zs.end()) { + size_t layer_nr = iter - zs.begin(); + if (layer_nr > 0 && layer_nr < contact_nodes.size()) { + vertical_enforcer_points_by_layers[layer_nr].push_back({ to_2d(pt).cast(),scaled(to_2d(normal)) }); + } + } + } + int nonempty_layers = 0; tbb::concurrent_vector all_nodes; tbb::parallel_for(tbb::blocked_range(1, m_object->layers().size()), [&](const tbb::blocked_range& range) { @@ -3371,7 +3392,6 @@ void TreeSupport::generate_contact_points() break; Layer* layer = m_object->get_layer(layer_nr); auto& curr_nodes = contact_nodes[layer_nr-1]; - if (layer->loverhangs.empty()) continue; std::unordered_set already_inserted; auto bottom_z = m_object->get_layer(layer_nr)->bottom_z(); @@ -3472,6 +3492,13 @@ void TreeSupport::generate_contact_points() } } } + for (auto& pt_and_normal : vertical_enforcer_points_by_layers[layer_nr]) { + is_sharp_tail = true;// fake it as sharp tail point so the contact distance will be 0 + auto vertical_enforcer_point= pt_and_normal.first; + auto node=insert_point(vertical_enforcer_point, ExPolygon(), false); + if (node) + node->skin_direction = pt_and_normal.second; + } 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 @@ -3480,6 +3507,9 @@ void TreeSupport::generate_contact_points() #endif }} ); // end tbb::parallel_for + + + int nNodes = all_nodes.size(); avg_node_per_layer = nodes_angle = 0; if (nNodes > 0) { diff --git a/src/libslic3r/Support/TreeSupport.hpp b/src/libslic3r/Support/TreeSupport.hpp index 41b18f30a..981d68a40 100644 --- a/src/libslic3r/Support/TreeSupport.hpp +++ b/src/libslic3r/Support/TreeSupport.hpp @@ -260,7 +260,7 @@ private: coordf_t radius; size_t layer_nr; int recursions; - + }; struct RadiusLayerPairEquality { constexpr bool operator()(const RadiusLayerPair& _Left, const RadiusLayerPair& _Right) const { @@ -334,7 +334,7 @@ public: * generally considered OK as the functions are still logically const * (ie there is no difference in behaviour for the user betweeen * calculating the values each time vs caching the results). - * + * * coconut: previously stl::unordered_map is used which seems problematic with tbb::parallel_for. * So we change to tbb::concurrent_unordered_map */ @@ -414,6 +414,8 @@ public: enum OverhangType { Detected = 0, Enforced, SharpTail }; std::map overhang_types; + std::vector> m_vertical_enforcer_points; + private: /*! * \brief Generator for model collision, avoidance and internal guide volumes @@ -433,7 +435,6 @@ private: size_t m_highest_overhang_layer = 0; std::vector> m_spanning_trees; std::vector< std::unordered_map> m_mst_line_x_layer_contour_caches; - float DO_NOT_MOVER_UNDER_MM = 0.0; coordf_t base_radius = 0.0; const coordf_t MAX_BRANCH_RADIUS = 10.0; @@ -484,7 +485,7 @@ private: /*! BBS: MusangKing: maximum layer height * \brief Optimize the generation of tree support by pre-planning the layer_heights - * + * */ std::vector plan_layer_heights(); diff --git a/src/libslic3r/Support/TreeSupport3D.cpp b/src/libslic3r/Support/TreeSupport3D.cpp index 4a792a6ba..b01104e4f 100644 --- a/src/libslic3r/Support/TreeSupport3D.cpp +++ b/src/libslic3r/Support/TreeSupport3D.cpp @@ -4178,6 +4178,22 @@ static void generate_support_areas(Print &print, TreeSupport* tree_support, cons append(overhangs[i + num_raft_layers], polys); } } + // add vertical enforcer points + std::vector zs = zs_from_layers(print_object.layers()); + Polygon base_circle = make_circle(scale_(0.5), SUPPORT_TREE_CIRCLE_RESOLUTION); + for (auto &pt_and_normal :tree_support->m_vertical_enforcer_points) { + auto pt = pt_and_normal.first; + auto normal = pt_and_normal.second; // normal seems useless + auto iter = std::lower_bound(zs.begin(), zs.end(), pt.z()); + if (iter != zs.end()) { + size_t layer_nr = iter - zs.begin(); + if (layer_nr > 0 && layer_nr < print_object.layer_count()) { + Polygon circle = base_circle; + circle.translate(to_2d(pt).cast()); + overhangs[layer_nr + num_raft_layers].emplace_back(std::move(circle)); + } + } + } #else std::vector overhangs = generate_overhangs(config, *print.get_object(processing.second.front()), throw_on_cancel); #endif diff --git a/src/libslic3r/TriangleMeshSlicer.cpp b/src/libslic3r/TriangleMeshSlicer.cpp index 378c148ef..cec70d3b2 100644 --- a/src/libslic3r/TriangleMeshSlicer.cpp +++ b/src/libslic3r/TriangleMeshSlicer.cpp @@ -957,7 +957,6 @@ inline std::pair slice_slabs_make_lines( } slice_facet_with_slabs(vertices, indices, face_idx, neighbors, edge_ids, num_edges, zs, lines_top, lines_mutex_top); } - // BBS: add vertical faces option if (bottom && (fo == FaceOrientation::Down || fo == FaceOrientation::Degenerate)) { Vec3i neighbors = face_neighbors[face_idx]; // Reset neighborship of this triangle in case the other triangle is oriented backwards from this one. @@ -2063,6 +2062,7 @@ void slice_mesh_slabs( const Transform3d &trafo, std::vector *out_top, std::vector *out_bottom, + std::vector> *vertical_points, std::function throw_on_cancel) { BOOST_LOG_TRIVIAL(debug) << "slice_mesh_slabs to polygons"; @@ -2133,6 +2133,11 @@ void slice_mesh_slabs( // Is the triangle vertical or degenerate? assert(d == 0); fo = fa == fb || fa == fc || fb == fc ? FaceOrientation::Degenerate : FaceOrientation::Vertical; + if(vertical_points && fo==FaceOrientation::Vertical) + { + Vec3f normal = (fb - fa).cross(fc - fa).normalized(); + vertical_points->push_back({ (fa + fb + fc) / 3,normal }); + } } face_orientation[&tri - mesh.indices.data()] = fo; } @@ -2297,7 +2302,7 @@ void project_mesh( { std::vector top, bottom; std::vector zs { -1e10, 1e10 }; - slice_mesh_slabs(mesh, zs, trafo, out_top ? &top : nullptr, out_bottom ? &bottom : nullptr, throw_on_cancel); + slice_mesh_slabs(mesh, zs, trafo, out_top ? &top : nullptr, out_bottom ? &bottom : nullptr, nullptr, throw_on_cancel); if (out_top) *out_top = std::move(top.front()); if (out_bottom) @@ -2311,7 +2316,7 @@ Polygons project_mesh( { std::vector top, bottom; std::vector zs { -1e10, 1e10 }; - slice_mesh_slabs(mesh, zs, trafo, &top, &bottom, throw_on_cancel); + slice_mesh_slabs(mesh, zs, trafo, &top, &bottom, nullptr, throw_on_cancel); return union_(top.front(), bottom.back()); } diff --git a/src/libslic3r/TriangleMeshSlicer.hpp b/src/libslic3r/TriangleMeshSlicer.hpp index 1a8b64362..9883f50c2 100644 --- a/src/libslic3r/TriangleMeshSlicer.hpp +++ b/src/libslic3r/TriangleMeshSlicer.hpp @@ -107,6 +107,7 @@ void slice_mesh_slabs( const Transform3d &trafo, std::vector *out_top, std::vector *out_bottom, + std::vector> *vertical_points, std::function throw_on_cancel); // Project mesh upwards pointing surfaces / downwards pointing surfaces into 2D polygons.