diff --git a/src/libslic3r/Support/TreeModelVolumes.cpp b/src/libslic3r/Support/TreeModelVolumes.cpp index f082115ea30..9c49c813a90 100644 --- a/src/libslic3r/Support/TreeModelVolumes.cpp +++ b/src/libslic3r/Support/TreeModelVolumes.cpp @@ -66,6 +66,7 @@ TreeModelVolumes::TreeModelVolumes( #endif // SLIC3R_TREESUPPORTS_PROGRESS m_machine_border{ calculateMachineBorderCollision(build_volume.polygon()) } { + m_bed_area = build_volume.polygon(); #if 0 std::unordered_map mesh_to_layeroutline_idx; for (size_t mesh_idx = 0; mesh_idx < storage.meshes.size(); ++ mesh_idx) { @@ -180,7 +181,8 @@ void TreeModelVolumes::precalculate(const PrintObject& print_object, const coord m_ignorable_radii.emplace_back(radius_eval); } - throw_on_cancel(); + if (throw_on_cancel) + throw_on_cancel(); // it may seem that the required avoidance can be of a smaller radius when going to model (no initial layer diameter for to model branches) // but as for every branch going towards the bp, the to model avoidance is required to check for possible merges with to model branches, this assumption is in-fact wrong. @@ -203,7 +205,8 @@ void TreeModelVolumes::precalculate(const PrintObject& print_object, const coord update_radius_until_layer(ceilRadius(config.recommendedMinRadius(current_layer) + m_current_min_xy_dist_delta)); } - throw_on_cancel(); + if (throw_on_cancel) + throw_on_cancel(); // Copy to deque to use in parallel for later. std::vector relevant_avoidance_radiis{ radius_until_layer.begin(), radius_until_layer.end() }; @@ -365,8 +368,7 @@ const Polygons& TreeModelVolumes::getPlaceableAreas(const coord_t orig_radius, L if (orig_radius == 0) // Placable areas for radius 0 are calculated in the general collision code. return this->getCollision(0, layer_idx, true); - else - const_cast(this)->calculatePlaceables(radius, layer_idx, throw_on_cancel); + const_cast(this)->calculatePlaceables(radius, layer_idx, throw_on_cancel); return getPlaceableAreas(orig_radius, layer_idx, throw_on_cancel); } @@ -461,7 +463,8 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex collision_areas_offsetted[layer_idx] = offset_value == 0 ? union_(collision_areas) : offset(union_ex(collision_areas), offset_value, ClipperLib::jtMiter, 1.2); - throw_on_cancel(); + if(throw_on_cancel) + throw_on_cancel(); } }); @@ -524,7 +527,8 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex dst = polygons_simplify(collisions, min_resolution, polygons_strictly_simple); } else append(dst, std::move(collisions)); - throw_on_cancel(); + if (throw_on_cancel) + throw_on_cancel(); } }); @@ -551,7 +555,8 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex dst = polygons_simplify(placable, min_resolution, polygons_strictly_simple); } else append(dst, placable); - throw_on_cancel(); + if (throw_on_cancel) + throw_on_cancel(); } }); } else { @@ -567,7 +572,8 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex } } #endif - throw_on_cancel(); + if (throw_on_cancel) + throw_on_cancel(); m_collision_cache.insert(std::move(data), radius); if (calculate_placable) m_placeable_areas_cache.insert(std::move(data_placeable), radius); @@ -597,7 +603,8 @@ void TreeModelVolumes::calculateCollisionHolefree(const std::vectorgetCollision(m_increase_until_radius, layer_idx, false)), 5 - increase_radius_ceil, ClipperLib::jtRound, m_min_resolution), m_min_resolution, polygons_strictly_simple)); - throw_on_cancel(); + if (throw_on_cancel) + throw_on_cancel(); } } m_collision_cache_holefree.insert(std::move(data)); @@ -640,7 +647,8 @@ void TreeModelVolumes::calculateAvoidance(const std::vector &ke avoidance_tasks.emplace_back(task); } - throw_on_cancel(); + if(throw_on_cancel) + throw_on_cancel(); tbb::parallel_for(tbb::blocked_range(0, avoidance_tasks.size(), 1), [this, &avoidance_tasks, &throw_on_cancel](const tbb::blocked_range &range) { @@ -685,7 +693,8 @@ void TreeModelVolumes::calculateAvoidance(const std::vector &ke latest_avoidance = diff(latest_avoidance, getPlaceableAreas(task.radius, layer_idx, throw_on_cancel)); latest_avoidance = polygons_simplify(latest_avoidance, m_min_resolution, polygons_strictly_simple); data.emplace_back(RadiusLayerPair{task.radius, layer_idx}, latest_avoidance); - throw_on_cancel(); + if (throw_on_cancel) + throw_on_cancel(); } #ifdef SLIC3R_TREESUPPORTS_PROGRESS { @@ -736,7 +745,8 @@ void TreeModelVolumes::calculatePlaceables(const coord_t radius, const LayerInde // xy_distance that cant support it. Making the area smaller by xy_distance fixes this. - (radius + m_current_min_xy_dist + m_current_min_xy_dist_delta), jtMiter, 1.2); - throw_on_cancel(); + if(throw_on_cancel) + throw_on_cancel(); } }); #ifdef SLIC3R_TREESUPPORTS_PROGRESS @@ -810,7 +820,8 @@ void TreeModelVolumes::calculateWallRestrictions(const std::vectorceilRadius(radius + m_current_min_xy_dist_delta) - m_current_min_xy_dist_delta; } + Polygon m_bed_area; + private: // Caching polygons for a range of layers. class LayerPolygonCache { diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index df81041213f..6d6e25ef2b5 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -669,6 +669,7 @@ static Point bounding_box_middle(const BoundingBox &bbox) TreeSupport::TreeSupport(PrintObject& object, const SlicingParameters &slicing_params) : m_object(&object), m_slicing_params(slicing_params), m_object_config(&object.config()) { + m_print_config = &m_object->print()->config(); m_raft_layers = slicing_params.base_raft_layers + slicing_params.interface_raft_layers; support_type = m_object_config->support_type; support_style = m_object_config->support_style; @@ -705,8 +706,7 @@ TreeSupport::TreeSupport(PrintObject& object, const SlicingParameters &slicing_p tree_support_branch_diameter_angle = 5.0;//is_slim ? 10.0 : 5.0; // by default tree support needs no infill, unless it's tree hybrid which contains normal nodes. with_infill = support_pattern != smpNone && support_pattern != smpDefault; - const PrintConfig& print_config = m_object->print()->config(); - m_machine_border.contour = get_bed_shape_with_excluded_area(print_config); + m_machine_border.contour = get_bed_shape_with_excluded_area(*m_print_config); Vec3d plate_offset = m_object->print()->get_plate_origin(); // align with the centered object in current plate (may not be the 1st plate, so need to add the plate offset) m_machine_border.translate(Point(scale_(plate_offset(0)), scale_(plate_offset(1))) - m_object->instances().front().shift); @@ -1404,10 +1404,9 @@ static void make_perimeter_and_infill(ExtrusionEntitiesPtr& dst, const Print& pr void TreeSupport::generate_toolpaths() { - const PrintConfig &print_config = m_object->print()->config(); const PrintObjectConfig &object_config = m_object->config(); coordf_t support_extrusion_width = m_support_params.support_extrusion_width; - coordf_t nozzle_diameter = print_config.nozzle_diameter.get_at(object_config.support_filament - 1); + coordf_t nozzle_diameter = m_print_config->nozzle_diameter.get_at(object_config.support_filament - 1); coordf_t layer_height = object_config.layer_height.value; const size_t wall_count = object_config.tree_support_wall_count.value; @@ -1882,7 +1881,7 @@ Polygons TreeSupport::contact_nodes_to_polygon(const std::vector& contact void TreeSupport::generate() { if (support_style == smsOrganic) { - generate_tree_support_3D(*m_object, this->throw_on_cancel); + generate_tree_support_3D(*m_object, this, this->throw_on_cancel); return; } diff --git a/src/libslic3r/Support/TreeSupport.hpp b/src/libslic3r/Support/TreeSupport.hpp index 17e146ddcd6..2ad8dc1cdb7 100644 --- a/src/libslic3r/Support/TreeSupport.hpp +++ b/src/libslic3r/Support/TreeSupport.hpp @@ -403,6 +403,13 @@ class TreeSupport std::unordered_map printZ_to_lightninglayer; std::function throw_on_cancel; + const PrintConfig* m_print_config; + /*! + * \brief Polygons representing the limits of the printable area of the + * machine + */ + ExPolygon m_machine_border; + private: /*! * \brief Generator for model collision, avoidance and internal guide volumes @@ -429,11 +436,6 @@ class TreeSupport bool with_infill = false; - /*! - * \brief Polygons representing the limits of the printable area of the - * machine - */ - ExPolygon m_machine_border; /*! * \brief Draws circles around each node of the tree into the final support. diff --git a/src/libslic3r/Support/TreeSupport3D.cpp b/src/libslic3r/Support/TreeSupport3D.cpp index fb4dcb2c9ab..98dc41f4864 100644 --- a/src/libslic3r/Support/TreeSupport3D.cpp +++ b/src/libslic3r/Support/TreeSupport3D.cpp @@ -7,8 +7,6 @@ // CuraEngine is released under the terms of the AGPLv3 or higher. #include "TreeSupport3D.hpp" -#include "TreeSupportCommon.hpp" -#include "SupportCommon.hpp" #include "../AABBTreeIndirect.hpp" #include "../BuildVolume.hpp" @@ -21,6 +19,9 @@ #include "../Polygon.hpp" #include "../Polyline.hpp" #include "../MutablePolygon.hpp" +#include "TreeSupportCommon.hpp" +#include "SupportCommon.hpp" +#include "TreeSupport.hpp" #include "libslic3r.h" #include @@ -34,6 +35,7 @@ #include #include +#include #if defined(TREE_SUPPORT_SHOW_ERRORS) && defined(_WIN32) #define TREE_SUPPORT_SHOW_ERRORS_WIN32 @@ -4106,13 +4108,14 @@ static void generate_support_areas(Print &print, const BuildVolume &build_volume continue; // Produce the support G-code. - // Used by both classic and tree supports. - SupportGeneratorLayersPtr raft_layers = generate_raft_base(print_object, support_params, print_object.slicing_parameters(), - top_contacts, interface_layers, base_interface_layers, intermediate_layers, layer_storage); -#if 1 //#ifdef SLIC3R_DEBUG - SupportGeneratorLayersPtr layers_sorted = -#endif // SLIC3R_DEBUG - generate_support_layers(print_object, raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers); + SupportGeneratorLayersPtr raft_layers = generate_raft_base(print_object, support_params, print_object.slicing_parameters(), top_contacts, interface_layers, base_interface_layers, intermediate_layers, layer_storage); + SupportGeneratorLayersPtr layers_sorted = generate_support_layers(print_object, raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers); + + // BBS: This is a hack to avoid the support being generated outside the bed area. See #4769. + tbb::parallel_for_each(layers_sorted.begin(), layers_sorted.end(), [&](SupportGeneratorLayer *layer) { + if (layer) layer->polygons = intersection(layer->polygons, volumes.m_bed_area); + }); + // Don't fill in the tree supports, make them hollow with just a single sheath line. generate_support_toolpaths(print_object.support_layers(), print_object.config(), support_params, print_object.slicing_parameters(), raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers); @@ -4363,9 +4366,10 @@ void organic_draw_branches( std::vector slices = slice_mesh(partial_mesh, slice_z, mesh_slicing_params, throw_on_cancel); bottom_contacts.clear(); //FIXME parallelize? - for (LayerIndex i = 0; i < LayerIndex(slices.size()); ++ i) - slices[i] = diff_clipped(slices[i], volumes.getCollision(0, layer_begin + i, true)); //FIXME parent_uses_min || draw_area.element->state.use_min_xy_dist); - + for (LayerIndex i = 0; i < LayerIndex(slices.size()); ++i) { + slices[i] = diff_clipped(slices[i], volumes.getCollision(0, layer_begin + i, true)); // FIXME parent_uses_min || draw_area.element->state.use_min_xy_dist); + slices[i] = intersection(slices[i], volumes.m_bed_area); + } size_t num_empty = 0; if (slices.front().empty()) { // Some of the initial layers are empty. @@ -4568,7 +4572,7 @@ void organic_draw_branches( } // namespace TreeSupport3D -void generate_tree_support_3D(PrintObject &print_object, std::function throw_on_cancel) +void generate_tree_support_3D(PrintObject &print_object, TreeSupport* tree_support, std::function throw_on_cancel) { size_t idx = 0; for (const PrintObject *po : print_object.print()->objects()) { @@ -4576,9 +4580,13 @@ void generate_tree_support_3D(PrintObject &print_object, std::function t break; ++idx; } - TreeSupport3D::generate_support_areas(*print_object.print(), - BuildVolume(Pointfs{ Vec2d{ -300., -300. }, Vec2d{ -300., +300. }, Vec2d{ +300., +300. }, Vec2d{ +300., -300. } }, 0.), { idx }, - throw_on_cancel); + + Points bedpts = tree_support->m_machine_border.contour.points; + Pointfs bedptsf; + std::transform(bedpts.begin(), bedpts.end(), std::back_inserter(bedptsf), [](const Point &p) { return unscale(p); }); + BuildVolume build_volume{ bedptsf, tree_support->m_print_config->printable_height }; + + TreeSupport3D::generate_support_areas(*print_object.print(), build_volume, { idx }, throw_on_cancel); } } // namespace Slic3r diff --git a/src/libslic3r/Support/TreeSupport3D.hpp b/src/libslic3r/Support/TreeSupport3D.hpp index 46e81412317..311df504b7e 100644 --- a/src/libslic3r/Support/TreeSupport3D.hpp +++ b/src/libslic3r/Support/TreeSupport3D.hpp @@ -310,7 +310,7 @@ void organic_draw_branches( } // namespace TreeSupport3D -void generate_tree_support_3D(PrintObject &print_object, std::function throw_on_cancel = []{}); +void generate_tree_support_3D(PrintObject &print_object, TreeSupport* tree_support, std::function throw_on_cancel = []{}); } // namespace Slic3r