mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-21 13:47:59 -06:00
ENH: improve tree support
1. add a hook inside tree branches for improved strength 2. fix the issue that interface may fly as a mess (delete the logic where gap nodes can skip dropping down) 3. fix the issue that base nodes may fly as a mess (smoothing should skip polygon nodes, see Jira:STUDIO-4403) Change-Id: Ie9f2039813c2ca3127ed8913304cc455fec8e7ee (cherry picked from commit 83cef5f91d49ff3d275a89ec3df8b5f0fd573f8c)
This commit is contained in:
parent
a62bf3b838
commit
76f876a3c6
9 changed files with 476 additions and 330 deletions
|
@ -665,6 +665,8 @@ Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &c
|
|||
{ return _clipper(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
|
||||
Slic3r::Polygons diff_clipped(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
|
||||
{ return diff(subject, ClipperUtils::clip_clipper_polygons_with_subject_bbox(clip, get_extents(subject).inflated(SCALED_EPSILON)), do_safety_offset); }
|
||||
Slic3r::ExPolygons diff_clipped(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
|
||||
{ return diff_ex(subject, ClipperUtils::clip_clipper_polygons_with_subject_bbox(clip, get_extents(subject).inflated(SCALED_EPSILON)), do_safety_offset); }
|
||||
Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset)
|
||||
{ return _clipper(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); }
|
||||
Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
|
||||
|
|
|
@ -430,6 +430,7 @@ Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::ExPolygon
|
|||
// Optimized version clipping the "clipping" polygon using clip_clipper_polygon_with_subject_bbox().
|
||||
// To be used with complex clipping polygons, where majority of the clipping polygons are outside of the source polygon.
|
||||
Slic3r::Polygons diff_clipped(const Slic3r::Polygons &src, const Slic3r::Polygons &clipping, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::ExPolygons diff_clipped(const Slic3r::ExPolygons &src, const Slic3r::Polygons &clipping, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::Polygons diff(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
|
|
|
@ -306,6 +306,7 @@ protected:
|
|||
int type;
|
||||
coordf_t dist_to_top; // mm dist to top
|
||||
bool need_infill = false;
|
||||
bool need_extra_wall = false;
|
||||
AreaGroup(ExPolygon *a, int t, coordf_t d) : area(a), type(t), dist_to_top(d) {}
|
||||
};
|
||||
enum OverhangType { Detected = 0, Enforced };
|
||||
|
|
|
@ -3246,7 +3246,7 @@ void PrintConfigDef::init_fff_params()
|
|||
def->category = L("Support");
|
||||
def->tooltip = L("This setting specify the count of walls around tree support");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->mode = comDevelop;
|
||||
def->set_default_value(new ConfigOptionInt(1));
|
||||
|
||||
def = this->add("tree_support_brim_width", coFloat);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -11,6 +11,8 @@
|
|||
#include "Flow.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "Fill/Lightning/Generator.hpp"
|
||||
#include "TreeModelVolumes.hpp"
|
||||
#include "TreeSupport3D.hpp"
|
||||
|
||||
#ifndef SQ
|
||||
#define SQ(x) ((x)*(x))
|
||||
|
@ -244,7 +246,6 @@ public:
|
|||
, position(Point(0, 0))
|
||||
, obj_layer_nr(0)
|
||||
, support_roof_layers_below(0)
|
||||
, support_floor_layers_above(0)
|
||||
, to_buildplate(true)
|
||||
, parent(nullptr)
|
||||
, print_z(0.0)
|
||||
|
@ -258,7 +259,6 @@ public:
|
|||
, position(position)
|
||||
, obj_layer_nr(obj_layer_nr)
|
||||
, support_roof_layers_below(support_roof_layers_below)
|
||||
, support_floor_layers_above(0)
|
||||
, to_buildplate(to_buildplate)
|
||||
, parent(parent)
|
||||
, print_z(print_z_)
|
||||
|
@ -266,13 +266,16 @@ public:
|
|||
, dist_mm_to_top(dist_mm_to_top_)
|
||||
{
|
||||
if (parent) {
|
||||
parents.push_back(parent);
|
||||
type = parent->type;
|
||||
overhang = parent->overhang;
|
||||
if (dist_mm_to_top==0)
|
||||
dist_mm_to_top = parent->dist_mm_to_top + parent->height;
|
||||
parent->child = this;
|
||||
for (auto& neighbor : parent->merged_neighbours)
|
||||
for (auto& neighbor : parent->merged_neighbours) {
|
||||
neighbor->child = this;
|
||||
parents.push_back(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,10 +302,10 @@ public:
|
|||
mutable double radius = 0.0;
|
||||
mutable double max_move_dist = 0.0;
|
||||
NodeType type = eCircle;
|
||||
bool is_merged = false; // this node is generated by merging upper nodes
|
||||
bool is_corner = false;
|
||||
bool is_processed = false;
|
||||
const ExPolygon *overhang = nullptr; // when type==ePolygon, set this value to get original overhang area
|
||||
bool need_extra_wall = false;
|
||||
ExPolygon overhang; // when type==ePolygon, set this value to get original overhang area
|
||||
|
||||
/*!
|
||||
* \brief The direction of the skin lines above the tip of the branch.
|
||||
|
@ -321,7 +324,6 @@ public:
|
|||
* how far we need to extend that support roof downwards.
|
||||
*/
|
||||
int support_roof_layers_below;
|
||||
int support_floor_layers_above;
|
||||
int obj_layer_nr;
|
||||
|
||||
/*!
|
||||
|
@ -341,6 +343,7 @@ public:
|
|||
* the entire branch needs to be known.
|
||||
*/
|
||||
Node *parent;
|
||||
std::vector<Node*> parents;
|
||||
Node *child = nullptr;
|
||||
|
||||
/*!
|
||||
|
@ -387,6 +390,7 @@ public:
|
|||
InfillPattern interface_fill_pattern;
|
||||
InfillPattern contact_fill_pattern;
|
||||
bool with_sheath;
|
||||
bool independent_layer_height = false;
|
||||
const double thresh_big_overhang = SQ(scale_(10));
|
||||
};
|
||||
|
||||
|
@ -417,6 +421,7 @@ private:
|
|||
* \warning This class is NOT currently thread-safe and should not be accessed in OpenMP blocks
|
||||
*/
|
||||
std::shared_ptr<TreeSupportData> m_ts_data;
|
||||
std::unique_ptr<TreeSupport3D::TreeModelVolumes> m_model_volumes;
|
||||
PrintObject *m_object;
|
||||
const PrintObjectConfig* m_object_config;
|
||||
SlicingParameters m_slicing_params;
|
||||
|
@ -431,6 +436,7 @@ private:
|
|||
coordf_t MAX_BRANCH_RADIUS_FIRST_LAYER = 12.0;
|
||||
coordf_t MIN_BRANCH_RADIUS = 0.5;
|
||||
float tree_support_branch_diameter_angle = 5.0;
|
||||
coord_t m_min_radius = scale_(1); // in mm
|
||||
bool is_strong = false;
|
||||
bool is_slim = false;
|
||||
bool with_infill = false;
|
||||
|
@ -465,7 +471,7 @@ private:
|
|||
|
||||
void smooth_nodes(std::vector<std::vector<Node *>> &contact_nodes);
|
||||
|
||||
void adjust_layer_heights(std::vector<std::vector<Node*>>& contact_nodes);
|
||||
void smooth_nodes(std::vector<std::vector<Node*>>& contact_nodes, const TreeSupport3D::TreeSupportSettings& config);
|
||||
|
||||
/*! BBS: MusangKing: maximum layer height
|
||||
* \brief Optimize the generation of tree support by pre-planning the layer_heights
|
||||
|
@ -486,7 +492,7 @@ private:
|
|||
* \return For each layer, a list of points where the tree should connect
|
||||
* with the model.
|
||||
*/
|
||||
void generate_contact_points(std::vector<std::vector<Node*>>& contact_nodes);
|
||||
void generate_contact_points(std::vector<std::vector<Node*>>& contact_nodes, const std::vector<TreeSupport3D::SupportElements>& move_bounds);
|
||||
|
||||
/*!
|
||||
* \brief Add a node to the next layer.
|
||||
|
@ -500,7 +506,11 @@ private:
|
|||
Polygons contact_nodes_to_polygon(const std::vector<Node*>& contact_nodes, Polygons layer_contours, int layer_nr, std::vector<double>& radiis, std::vector<bool>& is_interface);
|
||||
void clear_contact_nodes(std::vector<std::vector<Node*>>& contact_nodes);
|
||||
coordf_t calc_branch_radius(coordf_t base_radius, size_t layers_to_top, size_t tip_layers, double diameter_angle_scale_factor);
|
||||
coordf_t calc_branch_radius(coordf_t base_radius, coordf_t mm_to_top, double diameter_angle_scale_factor);
|
||||
coordf_t calc_branch_radius(coordf_t base_radius, coordf_t mm_to_top, double diameter_angle_scale_factor, bool use_min_distance=true);
|
||||
ExPolygons get_avoidance(coordf_t radius, size_t obj_layer_nr);
|
||||
ExPolygons get_collision(coordf_t radius, size_t layer_nr);
|
||||
// get Polygons instead of ExPolygons
|
||||
Polygons get_collision_polys(coordf_t radius, size_t layer_nr);
|
||||
|
||||
// similar to SupportMaterial::trim_support_layers_by_object
|
||||
Polygons get_trim_support_regions(
|
||||
|
|
|
@ -321,9 +321,6 @@ void tree_supports_show_error(std::string_view message, bool critical)
|
|||
|
||||
/*!
|
||||
* \brief Precalculates all avoidances, that could be required.
|
||||
*
|
||||
* \param storage[in] Background storage to access meshes.
|
||||
* \param currently_processing_meshes[in] Indexes of all meshes that are processed in this iteration
|
||||
*/
|
||||
[[nodiscard]] static LayerIndex precalculate(const Print &print, const std::vector<Polygons> &overhangs, const TreeSupportSettings &config, const std::vector<size_t> &object_ids, TreeModelVolumes &volumes, std::function<void()> throw_on_cancel)
|
||||
{
|
||||
|
@ -833,7 +830,7 @@ inline SupportGeneratorLayer& layer_allocate(
|
|||
* \param move_bounds[out] Storage for the influence areas.
|
||||
* \param storage[in] Background storage, required for adding roofs.
|
||||
*/
|
||||
static void generate_initial_areas(
|
||||
void generate_initial_areas(
|
||||
const PrintObject &print_object,
|
||||
const TreeModelVolumes &volumes,
|
||||
const TreeSupportSettings &config,
|
||||
|
@ -3438,11 +3435,10 @@ static void extrude_branch(
|
|||
|
||||
#ifdef TREE_SUPPORT_ORGANIC_NUDGE_NEW
|
||||
// New version using per layer AABB trees of lines for nudging spheres away from an object.
|
||||
static void organic_smooth_branches_avoid_collisions(
|
||||
void organic_smooth_branches_avoid_collisions(
|
||||
const PrintObject &print_object,
|
||||
const TreeModelVolumes &volumes,
|
||||
const TreeSupportSettings &config,
|
||||
std::vector<SupportElements> &move_bounds,
|
||||
const std::vector<std::pair<SupportElement*, int>> &elements_with_link_down,
|
||||
const std::vector<size_t> &linear_data_layers,
|
||||
std::function<void()> throw_on_cancel)
|
||||
|
@ -3520,9 +3516,9 @@ static void organic_smooth_branches_avoid_collisions(
|
|||
link_down,
|
||||
// locked
|
||||
element.parents.empty() || (link_down == -1 && element.state.layer_idx > 0),
|
||||
unscaled<float>(config.getRadius(element.state)),
|
||||
element.state.radius<EPSILON? unscaled<float>(config.getRadius(element.state)):float(element.state.radius),
|
||||
// 3D position
|
||||
to_3d(unscaled<float>(element.state.result_on_layer), float(layer_z(slicing_params, element.state.layer_idx)))
|
||||
to_3d(unscaled<float>(element.state.result_on_layer), element.state.print_z<EPSILON? float(layer_z(slicing_params, element.state.layer_idx)):element.state.print_z)
|
||||
});
|
||||
// Update min_z coordinate to min_z of the tree below.
|
||||
CollisionSphere &collision_sphere = collision_spheres.back();
|
||||
|
@ -3569,12 +3565,14 @@ static void organic_smooth_branches_avoid_collisions(
|
|||
collision_sphere.prev_position = collision_sphere.position;
|
||||
std::atomic<size_t> num_moved{ 0 };
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, collision_spheres.size()),
|
||||
[&collision_spheres, &layer_collision_cache, &slicing_params, &move_bounds, &linear_data_layers, &num_moved, &throw_on_cancel](const tbb::blocked_range<size_t> range) {
|
||||
[&collision_spheres, &layer_collision_cache, &slicing_params, &linear_data_layers, &num_moved, &throw_on_cancel](const tbb::blocked_range<size_t> range) {
|
||||
for (size_t collision_sphere_id = range.begin(); collision_sphere_id < range.end(); ++ collision_sphere_id)
|
||||
if (CollisionSphere &collision_sphere = collision_spheres[collision_sphere_id]; ! collision_sphere.locked) {
|
||||
// Calculate collision of multiple 2D layers against a collision sphere.
|
||||
collision_sphere.last_collision_depth = - std::numeric_limits<double>::max();
|
||||
for (uint32_t layer_id = collision_sphere.layer_begin; layer_id != collision_sphere.layer_end; ++ layer_id) {
|
||||
if(layer_id>= layer_collision_cache.size())
|
||||
continue;
|
||||
double dz = (layer_id - collision_sphere.element.state.layer_idx) * slicing_params.layer_height;
|
||||
if (double r2 = sqr(collision_sphere.radius) - sqr(dz); r2 > 0) {
|
||||
if (const LayerCollisionCache &layer_collision_cache_item = layer_collision_cache[layer_id]; ! layer_collision_cache_item.empty()) {
|
||||
|
@ -3605,7 +3603,6 @@ static void organic_smooth_branches_avoid_collisions(
|
|||
}
|
||||
// Laplacian smoothing
|
||||
Vec2d avg{ 0, 0 };
|
||||
const SupportElements &above = move_bounds[collision_sphere.element.state.layer_idx + 1];
|
||||
const size_t offset_above = linear_data_layers[collision_sphere.element.state.layer_idx + 1];
|
||||
double weight = 0.;
|
||||
for (auto iparent : collision_sphere.element.parents) {
|
||||
|
@ -3615,7 +3612,7 @@ static void organic_smooth_branches_avoid_collisions(
|
|||
}
|
||||
if (collision_sphere.element_below_id != -1) {
|
||||
const size_t offset_below = linear_data_layers[collision_sphere.element.state.layer_idx - 1];
|
||||
const double w = weight; // config.getRadius(move_bounds[element.state.layer_idx - 1][below].state);
|
||||
const double w = weight;
|
||||
avg += w * to_2d(collision_spheres[offset_below + collision_sphere.element_below_id].prev_position.cast<double>());
|
||||
weight += w;
|
||||
}
|
||||
|
@ -3802,7 +3799,7 @@ indexed_triangle_set draw_branches(
|
|||
|
||||
throw_on_cancel();
|
||||
|
||||
organic_smooth_branches_avoid_collisions(print_object, volumes, config, move_bounds, elements_with_link_down, linear_data_layers, throw_on_cancel);
|
||||
organic_smooth_branches_avoid_collisions(print_object, volumes, config, elements_with_link_down, linear_data_layers, throw_on_cancel);
|
||||
|
||||
// Unmark all nodes.
|
||||
for (SupportElements &elements : move_bounds)
|
||||
|
@ -4010,13 +4007,17 @@ static void generate_support_areas(Print &print, TreeSupport* tree_support, cons
|
|||
generate_initial_areas(*print.get_object(mesh_idx), volumes, config, overhangs, move_bounds, top_contacts, layer_storage, throw_on_cancel);
|
||||
auto t_gen = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// save num of points to log
|
||||
for (size_t i = 0; i < move_bounds.size(); i++)
|
||||
BOOST_LOG_TRIVIAL(info) << "Number of points in move_bound: " << move_bounds[i].size() << " in layer " << i;
|
||||
|
||||
#ifdef TREESUPPORT_DEBUG_SVG
|
||||
for (size_t layer_idx = 0; layer_idx < move_bounds.size(); ++layer_idx) {
|
||||
Polygons polys;
|
||||
for (auto& area : move_bounds[layer_idx])
|
||||
append(polys, area.influence_area);
|
||||
if (auto begin = move_bounds[layer_idx].begin(); begin != move_bounds[layer_idx].end())
|
||||
SVG::export_expolygons(debug_out_path("treesupport-initial_areas-%d.svg", layer_idx),
|
||||
SVG::export_expolygons(debug_out_path("initial_areas-%d.svg", layer_idx),
|
||||
{ { { union_ex(volumes.getWallRestriction(config.getCollisionRadius(begin->state), layer_idx, begin->state.use_min_xy_dist)) },
|
||||
{ "wall_restricrictions", "gray", 0.5f } },
|
||||
{ { union_ex(polys) }, { "parent", "red", "black", "", scaled<coord_t>(0.1f), 0.5f } } });
|
||||
|
@ -4076,10 +4077,7 @@ static void generate_support_areas(Print &print, TreeSupport* tree_support, cons
|
|||
support_params.support_density = 0;
|
||||
SupportGeneratorLayersPtr 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);
|
||||
#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 layers_sorted = generate_support_layers(print_object, raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers);
|
||||
|
||||
// Don't fill in the tree supports, make them hollow with just a single sheath line.
|
||||
print.set_status(69, _L("Support: generate toolpath"));
|
||||
|
|
|
@ -145,7 +145,9 @@ struct SupportElementStateBits {
|
|||
|
||||
struct SupportElementState : public SupportElementStateBits
|
||||
{
|
||||
int type;
|
||||
int type=0;
|
||||
coordf_t radius=0;
|
||||
float print_z=0;
|
||||
|
||||
/*!
|
||||
* \brief The layer this support elements wants reach
|
||||
|
@ -586,10 +588,14 @@ void create_layer_pathing(const TreeModelVolumes& volumes, const TreeSupportSett
|
|||
|
||||
void create_nodes_from_area(const TreeModelVolumes& volumes, const TreeSupportSettings& config, std::vector<SupportElements>& move_bounds, std::function<void()> throw_on_cancel);
|
||||
|
||||
void organic_smooth_branches_avoid_collisions(const PrintObject& print_object, const TreeModelVolumes& volumes, const TreeSupportSettings& config, const std::vector<std::pair<SupportElement*, int>>& elements_with_link_down, const std::vector<size_t>& linear_data_layers, std::function<void()> throw_on_cancel);
|
||||
|
||||
indexed_triangle_set draw_branches(PrintObject& print_object, const TreeModelVolumes& volumes, const TreeSupportSettings& config, std::vector<SupportElements>& move_bounds, std::function<void()> throw_on_cancel);
|
||||
|
||||
void slice_branches(PrintObject& print_object, const TreeModelVolumes& volumes, const TreeSupportSettings& config, const std::vector<Polygons>& overhangs, std::vector<SupportElements>& move_bounds, const indexed_triangle_set& cummulative_mesh, SupportGeneratorLayersPtr& bottom_contacts, SupportGeneratorLayersPtr& top_contacts, SupportGeneratorLayersPtr& intermediate_layers, SupportGeneratorLayerStorage& layer_storage, std::function<void()> throw_on_cancel);
|
||||
|
||||
void generate_initial_areas(const PrintObject& print_object, const TreeModelVolumes& volumes, const TreeSupportSettings& config, const std::vector<Polygons>& overhangs, std::vector<SupportElements>& move_bounds, SupportGeneratorLayersPtr& top_contacts, SupportGeneratorLayerStorage& layer_storage, std::function<void()> throw_on_cancel);
|
||||
|
||||
} // namespace TreeSupport3D
|
||||
|
||||
void generate_tree_support_3D(PrintObject &print_object, TreeSupport* tree_support, std::function<void()> throw_on_cancel = []{});
|
||||
|
|
|
@ -64,7 +64,7 @@ static constexpr double RESOLUTION = 0.0125;
|
|||
static constexpr double SPARSE_INFILL_RESOLUTION = 0.04;
|
||||
#define SCALED_SPARSE_INFILL_RESOLUTION (SPARSE_INFILL_RESOLUTION / SCALING_FACTOR)
|
||||
|
||||
static constexpr double SUPPORT_RESOLUTION = 0.05;
|
||||
static constexpr double SUPPORT_RESOLUTION = 0.1;
|
||||
#define SCALED_SUPPORT_RESOLUTION (SUPPORT_RESOLUTION / SCALING_FACTOR)
|
||||
// Maximum perimeter length for the loop to apply the small perimeter speed.
|
||||
#define SMALL_PERIMETER_LENGTH ((6.5 / SCALING_FACTOR) * 2 * PI)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue