mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-10 00:07:52 -06:00
WIP: Port latest support code from BBS (#8212)
This includes the latest changes from BBS, including vertical support painting. Huge PR, lots of tests are needed.
This commit is contained in:
commit
41584cfae3
35 changed files with 2253 additions and 4614 deletions
|
@ -7351,11 +7351,11 @@ msgstr ""
|
||||||
msgid ""
|
msgid ""
|
||||||
"When using support material for the support interface, We recommend the "
|
"When using support material for the support interface, We recommend the "
|
||||||
"following settings:\n"
|
"following settings:\n"
|
||||||
"0 top z distance, 0 interface spacing, concentric pattern and disable "
|
"0 top z distance, 0 interface spacing, interlaced rectilinear pattern and disable "
|
||||||
"independent support layer height"
|
"independent support layer height"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"当使用支持界面的支持材料时,我们推荐以下设置:\n"
|
"当使用支持界面的支持材料时,我们推荐以下设置:\n"
|
||||||
"0顶层z距离,0接触层间距,同心图案,并且禁用独立支撑层高"
|
"0顶层z距离,0接触层间距,交叠直线图案,并且禁用独立支撑层高"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Enabling this option will modify the model's shape. If your print requires "
|
"Enabling this option will modify the model's shape. If your print requires "
|
||||||
|
|
|
@ -310,16 +310,16 @@ set(lisbslic3r_sources
|
||||||
Support/SupportLayer.hpp
|
Support/SupportLayer.hpp
|
||||||
Support/SupportMaterial.cpp
|
Support/SupportMaterial.cpp
|
||||||
Support/SupportMaterial.hpp
|
Support/SupportMaterial.hpp
|
||||||
Support/SupportParameters.hpp
|
|
||||||
Support/SupportSpotsGenerator.cpp
|
Support/SupportSpotsGenerator.cpp
|
||||||
Support/SupportSpotsGenerator.hpp
|
Support/SupportSpotsGenerator.hpp
|
||||||
Support/TreeSupport.hpp
|
Support/TreeSupport.hpp
|
||||||
Support/TreeSupport.cpp
|
Support/TreeSupport.cpp
|
||||||
Support/TreeSupport3D.cpp
|
|
||||||
Support/TreeSupport3D.hpp
|
Support/TreeSupport3D.hpp
|
||||||
Support/TreeSupportCommon.hpp
|
Support/TreeSupport3D.cpp
|
||||||
Support/TreeModelVolumes.cpp
|
|
||||||
Support/TreeModelVolumes.hpp
|
Support/TreeModelVolumes.hpp
|
||||||
|
Support/TreeModelVolumes.cpp
|
||||||
|
Support/TreeSupportCommon.hpp
|
||||||
|
Support/SupportParameters.hpp
|
||||||
PrincipalComponents2D.cpp
|
PrincipalComponents2D.cpp
|
||||||
PrincipalComponents2D.hpp
|
PrincipalComponents2D.hpp
|
||||||
MinimumSpanningTree.hpp
|
MinimumSpanningTree.hpp
|
||||||
|
|
|
@ -664,6 +664,12 @@ Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &c
|
||||||
{ return _clipper(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
|
{ 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)
|
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); }
|
{ 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::ExPolygons diff_clipped(const Slic3r::ExPolygons & subject, const Slic3r::ExPolygons & 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)
|
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); }
|
{ 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)
|
Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
|
||||||
|
|
|
@ -433,6 +433,8 @@ Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::ExPolygon
|
||||||
// Optimized version clipping the "clipping" polygon using clip_clipper_polygon_with_subject_bbox().
|
// 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.
|
// 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::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::ExPolygons diff_clipped(const Slic3r::ExPolygons &src, const Slic3r::ExPolygons &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::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::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);
|
Slic3r::Polygons diff(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||||
|
|
|
@ -57,7 +57,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
|
||||||
case ipOctagramSpiral: return new FillOctagramSpiral();
|
case ipOctagramSpiral: return new FillOctagramSpiral();
|
||||||
case ipAdaptiveCubic: return new FillAdaptive::Filler();
|
case ipAdaptiveCubic: return new FillAdaptive::Filler();
|
||||||
case ipSupportCubic: return new FillAdaptive::Filler();
|
case ipSupportCubic: return new FillAdaptive::Filler();
|
||||||
case ipSupportBase: return new FillSupportBase();
|
case ipSupportBase: return new FillSupportBase(); // simply line fill
|
||||||
case ipLightning: return new FillLightning::Filler();
|
case ipLightning: return new FillLightning::Filler();
|
||||||
// BBS: for internal solid infill only
|
// BBS: for internal solid infill only
|
||||||
case ipConcentricInternal: return new FillConcentricInternal();
|
case ipConcentricInternal: return new FillConcentricInternal();
|
||||||
|
|
|
@ -1202,14 +1202,23 @@ std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObjec
|
||||||
// Allow empty support layers, as the support generator may produce no extrusions for non-empty support regions.
|
// Allow empty support layers, as the support generator may produce no extrusions for non-empty support regions.
|
||||||
|| (layer_to_print.support_layer /* && layer_to_print.support_layer->has_extrusions() */)) {
|
|| (layer_to_print.support_layer /* && layer_to_print.support_layer->has_extrusions() */)) {
|
||||||
double top_cd = object.config().support_top_z_distance;
|
double top_cd = object.config().support_top_z_distance;
|
||||||
double bottom_cd = object.config().support_bottom_z_distance;
|
double bottom_cd = object.config().support_bottom_z_distance == 0. ? top_cd : object.config().support_bottom_z_distance;
|
||||||
|
//if (!object.print()->config().independent_support_layer_height)
|
||||||
|
{ // the actual support gap may be larger than the configured one due to rounding to layer height for organic support, regardless of independent support layer height
|
||||||
|
top_cd = std::ceil(top_cd / object.config().layer_height) * object.config().layer_height;
|
||||||
|
bottom_cd = std::ceil(bottom_cd / object.config().layer_height) * object.config().layer_height;
|
||||||
|
}
|
||||||
double extra_gap = (layer_to_print.support_layer ? bottom_cd : top_cd);
|
double extra_gap = (layer_to_print.support_layer ? bottom_cd : top_cd);
|
||||||
|
|
||||||
// raft contact distance should not trigger any warning
|
// raft contact distance should not trigger any warning
|
||||||
if(last_extrusion_layer && last_extrusion_layer->support_layer)
|
if (last_extrusion_layer && last_extrusion_layer->support_layer) {
|
||||||
|
double raft_gap = object.config().raft_contact_distance.value;
|
||||||
|
//if (!object.print()->config().independent_support_layer_height)
|
||||||
|
{
|
||||||
|
raft_gap = std::ceil(raft_gap / object.config().layer_height) * object.config().layer_height;
|
||||||
|
}
|
||||||
extra_gap = std::max(extra_gap, object.config().raft_contact_distance.value);
|
extra_gap = std::max(extra_gap, object.config().raft_contact_distance.value);
|
||||||
|
}
|
||||||
double maximal_print_z = (last_extrusion_layer ? last_extrusion_layer->print_z() : 0.)
|
double maximal_print_z = (last_extrusion_layer ? last_extrusion_layer->print_z() : 0.)
|
||||||
+ layer_to_print.layer()->height
|
+ layer_to_print.layer()->height
|
||||||
+ std::max(0., extra_gap);
|
+ std::max(0., extra_gap);
|
||||||
|
|
|
@ -139,7 +139,7 @@ public:
|
||||||
// BBS
|
// BBS
|
||||||
mutable ExPolygons sharp_tails;
|
mutable ExPolygons sharp_tails;
|
||||||
mutable ExPolygons cantilevers;
|
mutable ExPolygons cantilevers;
|
||||||
mutable std::map<const ExPolygon*, float> sharp_tails_height;
|
mutable std::vector<float> sharp_tails_height;
|
||||||
|
|
||||||
// Collection of expolygons generated by slicing the possibly multiple meshes of the source geometry
|
// Collection of expolygons generated by slicing the possibly multiple meshes of the source geometry
|
||||||
// (with possibly differing extruder ID and slicing parameters) and merged.
|
// (with possibly differing extruder ID and slicing parameters) and merged.
|
||||||
|
@ -150,6 +150,7 @@ public:
|
||||||
// These lslices are also used to detect overhangs and overlaps between successive layers, therefore it is important
|
// These lslices are also used to detect overhangs and overlaps between successive layers, therefore it is important
|
||||||
// that the 1st lslice is not compensated by the Elephant foot compensation algorithm.
|
// that the 1st lslice is not compensated by the Elephant foot compensation algorithm.
|
||||||
ExPolygons lslices;
|
ExPolygons lslices;
|
||||||
|
ExPolygons lslices_extrudable; // BBS: the extrudable part of lslices used for tree support
|
||||||
std::vector<BoundingBox> lslices_bboxes;
|
std::vector<BoundingBox> lslices_bboxes;
|
||||||
|
|
||||||
// BBS
|
// BBS
|
||||||
|
@ -274,11 +275,10 @@ public:
|
||||||
ExPolygons support_islands;
|
ExPolygons support_islands;
|
||||||
// Extrusion paths for the support base and for the support interface and contacts.
|
// Extrusion paths for the support base and for the support interface and contacts.
|
||||||
ExtrusionEntityCollection support_fills;
|
ExtrusionEntityCollection support_fills;
|
||||||
SupportInnerType support_type = stInnerNormal;
|
SupportInnerType support_type = stInnerNormal;
|
||||||
|
|
||||||
// for tree supports
|
// for tree supports
|
||||||
ExPolygons base_areas;
|
ExPolygons base_areas;
|
||||||
ExPolygons overhang_areas;
|
|
||||||
|
|
||||||
|
|
||||||
// Is there any valid extrusion assigned to this LayerRegion?
|
// Is there any valid extrusion assigned to this LayerRegion?
|
||||||
|
@ -311,14 +311,13 @@ protected:
|
||||||
{
|
{
|
||||||
ExPolygon *area;
|
ExPolygon *area;
|
||||||
int type;
|
int type;
|
||||||
|
int interface_id = 0;
|
||||||
coordf_t dist_to_top; // mm dist to top
|
coordf_t dist_to_top; // mm dist to top
|
||||||
bool need_infill = false;
|
bool need_infill = false;
|
||||||
bool need_extra_wall = false;
|
bool need_extra_wall = false;
|
||||||
AreaGroup(ExPolygon *a, int t, coordf_t d) : area(a), type(t), dist_to_top(d) {}
|
AreaGroup(ExPolygon *a, int t, coordf_t d) : area(a), type(t), dist_to_top(d) {}
|
||||||
};
|
};
|
||||||
enum OverhangType { Detected = 0, Enforced };
|
|
||||||
std::vector<AreaGroup> area_groups;
|
std::vector<AreaGroup> area_groups;
|
||||||
std::map<const ExPolygon *, OverhangType> overhang_types;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename LayerContainer>
|
template<typename LayerContainer>
|
||||||
|
|
|
@ -1363,7 +1363,7 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
|
||||||
if (!zs.empty() && is_volume_sinking(painted, volume_trafo)) {
|
if (!zs.empty() && is_volume_sinking(painted, volume_trafo)) {
|
||||||
std::vector<float> zs_sinking = {0.f};
|
std::vector<float> zs_sinking = {0.f};
|
||||||
Slic3r::append(zs_sinking, zs);
|
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);
|
||||||
|
|
||||||
MeshSlicingParams slicing_params;
|
MeshSlicingParams slicing_params;
|
||||||
slicing_params.trafo = volume_trafo;
|
slicing_params.trafo = volume_trafo;
|
||||||
|
@ -1374,7 +1374,7 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
|
||||||
|
|
||||||
bottom[0] = union_(bottom[0], bottom_slice);
|
bottom[0] = union_(bottom[0], bottom_slice);
|
||||||
} else
|
} 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<Polygons> &&src, std::vector<Polygons> &dst) {
|
auto merge = [](std::vector<Polygons> &&src, std::vector<Polygons> &dst) {
|
||||||
auto it_src = find_if(src.begin(), src.end(), [](const Polygons &p){ return ! p.empty(); });
|
auto it_src = find_if(src.begin(), src.end(), [](const Polygons &p){ return ! p.empty(); });
|
||||||
if (it_src != src.end()) {
|
if (it_src != src.end()) {
|
||||||
|
|
|
@ -794,7 +794,7 @@ static std::vector<std::string> s_Preset_print_options {
|
||||||
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_noise_type", "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence",
|
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_noise_type", "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence",
|
||||||
"max_volumetric_extrusion_rate_slope", "max_volumetric_extrusion_rate_slope_segment_length","extrusion_rate_smoothing_external_perimeter_only",
|
"max_volumetric_extrusion_rate_slope", "max_volumetric_extrusion_rate_slope_segment_length","extrusion_rate_smoothing_external_perimeter_only",
|
||||||
"inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed",
|
"inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed",
|
||||||
"top_surface_speed", "support_speed", "support_object_xy_distance", "support_interface_speed",
|
"top_surface_speed", "support_speed", "support_object_xy_distance", "support_object_first_layer_gap", "support_interface_speed",
|
||||||
"bridge_speed", "internal_bridge_speed", "gap_infill_speed", "travel_speed", "travel_speed_z", "initial_layer_speed",
|
"bridge_speed", "internal_bridge_speed", "gap_infill_speed", "travel_speed", "travel_speed_z", "initial_layer_speed",
|
||||||
"outer_wall_acceleration", "initial_layer_acceleration", "top_surface_acceleration", "default_acceleration", "skirt_type", "skirt_loops", "skirt_speed","min_skirt_length", "skirt_distance", "skirt_start_angle", "skirt_height", "draft_shield",
|
"outer_wall_acceleration", "initial_layer_acceleration", "top_surface_acceleration", "default_acceleration", "skirt_type", "skirt_loops", "skirt_speed","min_skirt_length", "skirt_distance", "skirt_start_angle", "skirt_height", "draft_shield",
|
||||||
"brim_width", "brim_object_gap", "brim_type", "brim_ears_max_angle", "brim_ears_detection_length", "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap","enforce_support_layers",
|
"brim_width", "brim_object_gap", "brim_type", "brim_ears_max_angle", "brim_ears_detection_length", "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap","enforce_support_layers",
|
||||||
|
@ -814,7 +814,7 @@ static std::vector<std::string> s_Preset_print_options {
|
||||||
"wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits",
|
"wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits",
|
||||||
"flush_into_infill", "flush_into_objects", "flush_into_support",
|
"flush_into_infill", "flush_into_objects", "flush_into_support",
|
||||||
"tree_support_branch_angle", "tree_support_angle_slow", "tree_support_wall_count", "tree_support_top_rate", "tree_support_branch_distance", "tree_support_tip_diameter",
|
"tree_support_branch_angle", "tree_support_angle_slow", "tree_support_wall_count", "tree_support_top_rate", "tree_support_branch_distance", "tree_support_tip_diameter",
|
||||||
"tree_support_branch_diameter", "tree_support_branch_diameter_angle", "tree_support_branch_diameter_double_wall",
|
"tree_support_branch_diameter", "tree_support_branch_diameter_angle",
|
||||||
"detect_narrow_internal_solid_infill",
|
"detect_narrow_internal_solid_infill",
|
||||||
"gcode_add_line_number", "enable_arc_fitting", "precise_z_height", "infill_combination","infill_combination_max_layer_height", /*"adaptive_layer_height",*/
|
"gcode_add_line_number", "enable_arc_fitting", "precise_z_height", "infill_combination","infill_combination_max_layer_height", /*"adaptive_layer_height",*/
|
||||||
"support_bottom_interface_spacing", "enable_overhang_speed", "slowdown_for_curled_perimeters", "overhang_1_4_speed", "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed",
|
"support_bottom_interface_spacing", "enable_overhang_speed", "slowdown_for_curled_perimeters", "overhang_1_4_speed", "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed",
|
||||||
|
|
|
@ -1167,7 +1167,7 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
|
||||||
// Custom layering is not allowed for tree supports as of now.
|
// Custom layering is not allowed for tree supports as of now.
|
||||||
for (size_t print_object_idx = 0; print_object_idx < m_objects.size(); ++ print_object_idx)
|
for (size_t print_object_idx = 0; print_object_idx < m_objects.size(); ++ print_object_idx)
|
||||||
if (const PrintObject &print_object = *m_objects[print_object_idx];
|
if (const PrintObject &print_object = *m_objects[print_object_idx];
|
||||||
print_object.has_support_material() && is_tree(print_object.config().support_type.value) && (print_object.config().support_style.value == smsOrganic ||
|
print_object.has_support_material() && is_tree(print_object.config().support_type.value) && (print_object.config().support_style.value == smsTreeOrganic ||
|
||||||
// Orca: use organic as default
|
// Orca: use organic as default
|
||||||
print_object.config().support_style.value == smsDefault) &&
|
print_object.config().support_style.value == smsDefault) &&
|
||||||
print_object.model_object()->has_custom_layering()) {
|
print_object.model_object()->has_custom_layering()) {
|
||||||
|
@ -1340,7 +1340,7 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
|
||||||
|
|
||||||
// Prusa: Fixing crashes with invalid tip diameter or branch diameter
|
// Prusa: Fixing crashes with invalid tip diameter or branch diameter
|
||||||
// https://github.com/prusa3d/PrusaSlicer/commit/96b3ae85013ac363cd1c3e98ec6b7938aeacf46d
|
// https://github.com/prusa3d/PrusaSlicer/commit/96b3ae85013ac363cd1c3e98ec6b7938aeacf46d
|
||||||
if (is_tree(object->config().support_type.value) && (object->config().support_style == smsOrganic ||
|
if (is_tree(object->config().support_type.value) && (object->config().support_style == smsTreeOrganic ||
|
||||||
// Orca: use organic as default
|
// Orca: use organic as default
|
||||||
object->config().support_style == smsDefault)) {
|
object->config().support_style == smsDefault)) {
|
||||||
float extrusion_width = std::min(
|
float extrusion_width = std::min(
|
||||||
|
|
|
@ -385,7 +385,7 @@ public:
|
||||||
|
|
||||||
size_t support_layer_count() const { return m_support_layers.size(); }
|
size_t support_layer_count() const { return m_support_layers.size(); }
|
||||||
void clear_support_layers();
|
void clear_support_layers();
|
||||||
SupportLayer* get_support_layer(int idx) { return m_support_layers[idx]; }
|
SupportLayer* get_support_layer(int idx) { return idx<m_support_layers.size()? m_support_layers[idx]:nullptr; }
|
||||||
const SupportLayer* get_support_layer_at_printz(coordf_t print_z, coordf_t epsilon) const;
|
const SupportLayer* get_support_layer_at_printz(coordf_t print_z, coordf_t epsilon) const;
|
||||||
SupportLayer* get_support_layer_at_printz(coordf_t print_z, coordf_t epsilon);
|
SupportLayer* get_support_layer_at_printz(coordf_t print_z, coordf_t epsilon);
|
||||||
SupportLayer* add_support_layer(int id, int interface_id, coordf_t height, coordf_t print_z);
|
SupportLayer* add_support_layer(int id, int interface_id, coordf_t height, coordf_t print_z);
|
||||||
|
@ -427,7 +427,7 @@ public:
|
||||||
std::vector<Polygons> slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); }
|
std::vector<Polygons> slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); }
|
||||||
|
|
||||||
// Helpers to project custom facets on slices
|
// Helpers to project custom facets on slices
|
||||||
void project_and_append_custom_facets(bool seam, EnforcerBlockerType type, std::vector<Polygons>& expolys) const;
|
void project_and_append_custom_facets(bool seam, EnforcerBlockerType type, std::vector<Polygons>& expolys, std::vector<std::pair<Vec3f,Vec3f>>* vertical_points=nullptr) const;
|
||||||
|
|
||||||
//BBS
|
//BBS
|
||||||
BoundingBox get_first_layer_bbox(float& area, float& layer_height, std::string& name);
|
BoundingBox get_first_layer_bbox(float& area, float& layer_height, std::string& name);
|
||||||
|
|
|
@ -232,7 +232,7 @@ static t_config_enum_values s_keys_map_SupportMaterialStyle {
|
||||||
{ "tree_slim", smsTreeSlim },
|
{ "tree_slim", smsTreeSlim },
|
||||||
{ "tree_strong", smsTreeStrong },
|
{ "tree_strong", smsTreeStrong },
|
||||||
{ "tree_hybrid", smsTreeHybrid },
|
{ "tree_hybrid", smsTreeHybrid },
|
||||||
{ "organic", smsOrganic }
|
{ "organic", smsTreeOrganic }
|
||||||
};
|
};
|
||||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SupportMaterialStyle)
|
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SupportMaterialStyle)
|
||||||
|
|
||||||
|
@ -4618,6 +4618,17 @@ void PrintConfigDef::init_fff_params()
|
||||||
//Support with too small spacing may touch the object and difficult to remove.
|
//Support with too small spacing may touch the object and difficult to remove.
|
||||||
def->set_default_value(new ConfigOptionFloat(0.35));
|
def->set_default_value(new ConfigOptionFloat(0.35));
|
||||||
|
|
||||||
|
def = this->add("support_object_first_layer_gap", coFloat);
|
||||||
|
def->label = L("Support/object first layer gap");
|
||||||
|
def->category = L("Support");
|
||||||
|
def->tooltip = L("XY separation between an object and its support at the first layer.");
|
||||||
|
def->sidetext = L("mm");
|
||||||
|
def->min = 0;
|
||||||
|
def->max = 10;
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
//Support with too small spacing may touch the object and difficult to remove.
|
||||||
|
def->set_default_value(new ConfigOptionFloat(0.2));
|
||||||
|
|
||||||
def = this->add("support_angle", coFloat);
|
def = this->add("support_angle", coFloat);
|
||||||
def->label = L("Pattern angle");
|
def->label = L("Pattern angle");
|
||||||
def->category = L("Support");
|
def->category = L("Support");
|
||||||
|
@ -5030,16 +5041,6 @@ void PrintConfigDef::init_fff_params()
|
||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionFloat(5.));
|
def->set_default_value(new ConfigOptionFloat(5.));
|
||||||
|
|
||||||
def = this->add("tree_support_branch_diameter_organic", coFloat);
|
|
||||||
def->label = L("Tree support branch diameter");
|
|
||||||
def->category = L("Support");
|
|
||||||
def->tooltip = L("This setting determines the initial diameter of support nodes.");
|
|
||||||
def->sidetext = L("mm");
|
|
||||||
def->min = 1.0;
|
|
||||||
def->max = 10;
|
|
||||||
def->mode = comAdvanced;
|
|
||||||
def->set_default_value(new ConfigOptionFloat(2.));
|
|
||||||
|
|
||||||
def = this->add("tree_support_branch_diameter_angle", coFloat);
|
def = this->add("tree_support_branch_diameter_angle", coFloat);
|
||||||
// TRN PrintSettings: #lmFIXME
|
// TRN PrintSettings: #lmFIXME
|
||||||
def->label = L("Branch Diameter Angle");
|
def->label = L("Branch Diameter Angle");
|
||||||
|
@ -5054,23 +5055,22 @@ void PrintConfigDef::init_fff_params()
|
||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionFloat(5));
|
def->set_default_value(new ConfigOptionFloat(5));
|
||||||
|
|
||||||
def = this->add("tree_support_branch_diameter_double_wall", coFloat);
|
def = this->add("tree_support_branch_diameter_organic", coFloat);
|
||||||
def->label = L("Branch Diameter with double walls");
|
def->label = L("Tree support branch diameter");
|
||||||
def->category = L("Support");
|
def->category = L("Support");
|
||||||
// TRN PrintSettings: "Organic supports" > "Branch Diameter"
|
def->tooltip = L("This setting determines the initial diameter of support nodes.");
|
||||||
def->tooltip = L("Branches with area larger than the area of a circle of this diameter will be printed with double walls for stability. "
|
|
||||||
"Set this value to zero for no double walls.");
|
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->min = 0;
|
def->min = 1.0;
|
||||||
def->max = 100.f;
|
def->max = 10;
|
||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionFloat(3.));
|
def->set_default_value(new ConfigOptionFloat(2.));
|
||||||
|
|
||||||
def = this->add("tree_support_wall_count", coInt);
|
def = this->add("tree_support_wall_count", coInt);
|
||||||
def->label = L("Support wall loops");
|
def->label = L("Support wall loops");
|
||||||
def->category = L("Support");
|
def->category = L("Support");
|
||||||
def->tooltip = L("This setting specify the count of walls around support");
|
def->tooltip = L("This setting specifies the count of support walls in the range of [0,2]. 0 means auto.");
|
||||||
def->min = 0;
|
def->min = 0;
|
||||||
|
def->max = 2;
|
||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionInt(0));
|
def->set_default_value(new ConfigOptionInt(0));
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,7 @@ enum SupportMaterialPattern {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SupportMaterialStyle {
|
enum SupportMaterialStyle {
|
||||||
smsDefault, smsGrid, smsSnug, smsTreeSlim, smsTreeStrong, smsTreeHybrid, smsOrganic,
|
smsDefault, smsGrid, smsSnug, smsTreeSlim, smsTreeStrong, smsTreeHybrid, smsTreeOrganic,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum LongRectrationLevel
|
enum LongRectrationLevel
|
||||||
|
@ -840,6 +840,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||||
((ConfigOptionInt, support_threshold_angle))
|
((ConfigOptionInt, support_threshold_angle))
|
||||||
((ConfigOptionFloatOrPercent, support_threshold_overlap))
|
((ConfigOptionFloatOrPercent, support_threshold_overlap))
|
||||||
((ConfigOptionFloat, support_object_xy_distance))
|
((ConfigOptionFloat, support_object_xy_distance))
|
||||||
|
((ConfigOptionFloat, support_object_first_layer_gap))
|
||||||
((ConfigOptionFloat, xy_hole_compensation))
|
((ConfigOptionFloat, xy_hole_compensation))
|
||||||
((ConfigOptionFloat, xy_contour_compensation))
|
((ConfigOptionFloat, xy_contour_compensation))
|
||||||
((ConfigOptionBool, flush_into_objects))
|
((ConfigOptionBool, flush_into_objects))
|
||||||
|
@ -850,9 +851,8 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||||
((ConfigOptionFloat, tree_support_branch_distance))
|
((ConfigOptionFloat, tree_support_branch_distance))
|
||||||
((ConfigOptionFloat, tree_support_tip_diameter))
|
((ConfigOptionFloat, tree_support_tip_diameter))
|
||||||
((ConfigOptionFloat, tree_support_branch_diameter))
|
((ConfigOptionFloat, tree_support_branch_diameter))
|
||||||
((ConfigOptionFloat, tree_support_branch_diameter_angle))
|
|
||||||
((ConfigOptionFloat, tree_support_branch_diameter_double_wall))
|
|
||||||
((ConfigOptionFloat, tree_support_branch_angle))
|
((ConfigOptionFloat, tree_support_branch_angle))
|
||||||
|
((ConfigOptionFloat, tree_support_branch_diameter_angle))
|
||||||
((ConfigOptionFloat, tree_support_angle_slow))
|
((ConfigOptionFloat, tree_support_angle_slow))
|
||||||
((ConfigOptionInt, tree_support_wall_count))
|
((ConfigOptionInt, tree_support_wall_count))
|
||||||
((ConfigOptionBool, tree_support_adaptive_layer_height))
|
((ConfigOptionBool, tree_support_adaptive_layer_height))
|
||||||
|
|
|
@ -633,13 +633,9 @@ void PrintObject::generate_support_material()
|
||||||
if (this->set_started(posSupportMaterial)) {
|
if (this->set_started(posSupportMaterial)) {
|
||||||
this->clear_support_layers();
|
this->clear_support_layers();
|
||||||
|
|
||||||
if ((this->has_support() && m_layers.size() > 1) || (this->has_raft() && ! m_layers.empty())) {
|
if(!has_support() && !m_print->get_no_check_flag()) {
|
||||||
m_print->set_status(50, L("Generating support"));
|
|
||||||
|
|
||||||
this->_generate_support_material();
|
|
||||||
m_print->throw_if_canceled();
|
|
||||||
} else if(!m_print->get_no_check_flag()) {
|
|
||||||
// BBS: pop a warning if objects have significant amount of overhangs but support material is not enabled
|
// BBS: pop a warning if objects have significant amount of overhangs but support material is not enabled
|
||||||
|
// Note: we also need to pop warning if support is disabled and only raft is enabled
|
||||||
m_print->set_status(50, L("Checking support necessity"));
|
m_print->set_status(50, L("Checking support necessity"));
|
||||||
typedef std::chrono::high_resolution_clock clock_;
|
typedef std::chrono::high_resolution_clock clock_;
|
||||||
typedef std::chrono::duration<double, std::ratio<1> > second_;
|
typedef std::chrono::duration<double, std::ratio<1> > second_;
|
||||||
|
@ -669,6 +665,12 @@ void PrintObject::generate_support_material()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((this->has_support() && m_layers.size() > 1) || (this->has_raft() && !m_layers.empty())) {
|
||||||
|
m_print->set_status(50, L("Generating support"));
|
||||||
|
|
||||||
|
this->_generate_support_material();
|
||||||
|
m_print->throw_if_canceled();
|
||||||
|
}
|
||||||
this->set_done(posSupportMaterial);
|
this->set_done(posSupportMaterial);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -731,7 +733,8 @@ void PrintObject::simplify_extrusion_path()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->set_started(posSimplifySupportPath)) {
|
if (this->set_started(posSimplifySupportPath)) {
|
||||||
//BBS: share same progress
|
//BBS: disable circle simplification for support as it causes separation of support walls
|
||||||
|
#if 0
|
||||||
m_print->set_status(75, L("Optimizing toolpath"));
|
m_print->set_status(75, L("Optimizing toolpath"));
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Simplify extrusion path of support in parallel - start";
|
BOOST_LOG_TRIVIAL(debug) << "Simplify extrusion path of support in parallel - start";
|
||||||
tbb::parallel_for(
|
tbb::parallel_for(
|
||||||
|
@ -745,6 +748,7 @@ void PrintObject::simplify_extrusion_path()
|
||||||
);
|
);
|
||||||
m_print->throw_if_canceled();
|
m_print->throw_if_canceled();
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Simplify extrusion path of support in parallel - end";
|
BOOST_LOG_TRIVIAL(debug) << "Simplify extrusion path of support in parallel - end";
|
||||||
|
#endif
|
||||||
this->set_done(posSimplifySupportPath);
|
this->set_done(posSimplifySupportPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -843,14 +847,8 @@ void PrintObject::clear_support_layers()
|
||||||
std::shared_ptr<TreeSupportData> PrintObject::alloc_tree_support_preview_cache()
|
std::shared_ptr<TreeSupportData> PrintObject::alloc_tree_support_preview_cache()
|
||||||
{
|
{
|
||||||
if (!m_tree_support_preview_cache) {
|
if (!m_tree_support_preview_cache) {
|
||||||
const coordf_t layer_height = m_config.layer_height.value;
|
|
||||||
const coordf_t xy_distance = m_config.support_object_xy_distance.value;
|
const coordf_t xy_distance = m_config.support_object_xy_distance.value;
|
||||||
const double angle = m_config.tree_support_branch_angle.value * M_PI / 180.;
|
m_tree_support_preview_cache = std::make_shared<TreeSupportData>(*this, xy_distance, g_config_tree_support_collision_resolution);
|
||||||
const coordf_t max_move_distance
|
|
||||||
= (angle < M_PI / 2) ? (coordf_t)(tan(angle) * layer_height) : std::numeric_limits<coordf_t>::max();
|
|
||||||
const coordf_t radius_sample_resolution = g_config_tree_support_collision_resolution;
|
|
||||||
|
|
||||||
m_tree_support_preview_cache = std::make_shared<TreeSupportData>(*this, xy_distance, max_move_distance, radius_sample_resolution);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_tree_support_preview_cache;
|
return m_tree_support_preview_cache;
|
||||||
|
@ -1015,6 +1013,7 @@ bool PrintObject::invalidate_state_by_config_options(
|
||||||
|| opt_key == "support_base_pattern"
|
|| opt_key == "support_base_pattern"
|
||||||
|| opt_key == "support_style"
|
|| opt_key == "support_style"
|
||||||
|| opt_key == "support_object_xy_distance"
|
|| opt_key == "support_object_xy_distance"
|
||||||
|
|| opt_key == "support_object_first_layer_gap"
|
||||||
|| opt_key == "support_base_pattern_spacing"
|
|| opt_key == "support_base_pattern_spacing"
|
||||||
|| opt_key == "support_expansion"
|
|| opt_key == "support_expansion"
|
||||||
//|| opt_key == "independent_support_layer_height" // BBS
|
//|| opt_key == "independent_support_layer_height" // BBS
|
||||||
|
@ -1036,7 +1035,6 @@ bool PrintObject::invalidate_state_by_config_options(
|
||||||
|| opt_key == "tree_support_branch_diameter"
|
|| opt_key == "tree_support_branch_diameter"
|
||||||
|| opt_key == "tree_support_branch_diameter_organic"
|
|| opt_key == "tree_support_branch_diameter_organic"
|
||||||
|| opt_key == "tree_support_branch_diameter_angle"
|
|| opt_key == "tree_support_branch_diameter_angle"
|
||||||
|| opt_key == "tree_support_branch_diameter_double_wall"
|
|
||||||
|| opt_key == "tree_support_branch_angle"
|
|| opt_key == "tree_support_branch_angle"
|
||||||
|| opt_key == "tree_support_branch_angle_organic"
|
|| opt_key == "tree_support_branch_angle_organic"
|
||||||
|| opt_key == "tree_support_angle_slow"
|
|| opt_key == "tree_support_angle_slow"
|
||||||
|
@ -3935,91 +3933,8 @@ template void PrintObject::remove_bridges_from_contacts<Polygons>(
|
||||||
|
|
||||||
SupportNecessaryType PrintObject::is_support_necessary()
|
SupportNecessaryType PrintObject::is_support_necessary()
|
||||||
{
|
{
|
||||||
static const double super_overhang_area_threshold = SQ(scale_(5.0));
|
|
||||||
const double cantilevel_dist_thresh = scale_(6);
|
const double cantilevel_dist_thresh = scale_(6);
|
||||||
#if 0
|
|
||||||
double threshold_rad = (m_config.support_threshold_angle.value < EPSILON ? 30 : m_config.support_threshold_angle.value + 1) * M_PI / 180.;
|
|
||||||
int enforce_support_layers = m_config.enforce_support_layers;
|
|
||||||
// not fixing in extrusion width % PR b/c never called
|
|
||||||
const coordf_t extrusion_width = m_config.line_width.value;
|
|
||||||
const coordf_t extrusion_width_scaled = scale_(extrusion_width);
|
|
||||||
float max_bridge_length = scale_(m_config.max_bridge_length.value);
|
|
||||||
const bool bridge_no_support = max_bridge_length > 0;// config.bridge_no_support.value;
|
|
||||||
|
|
||||||
for (size_t layer_nr = enforce_support_layers + 1; layer_nr < this->layer_count(); layer_nr++) {
|
|
||||||
Layer* layer = m_layers[layer_nr];
|
|
||||||
Layer* lower_layer = layer->lower_layer;
|
|
||||||
|
|
||||||
coordf_t support_offset_scaled = extrusion_width_scaled * 0.9;
|
|
||||||
ExPolygons lower_layer_offseted = offset_ex(lower_layer->lslices, support_offset_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS);
|
|
||||||
|
|
||||||
// 1. check sharp tail
|
|
||||||
for (const LayerRegion* layerm : layer->regions()) {
|
|
||||||
for (const ExPolygon& expoly : layerm->raw_slices) {
|
|
||||||
// detect sharp tail
|
|
||||||
if (intersection_ex({ expoly }, lower_layer_offseted).empty())
|
|
||||||
return SharpTail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. check overhang area
|
|
||||||
ExPolygons super_overhang_expolys = std::move(diff_ex(layer->lslices, lower_layer_offseted));
|
|
||||||
super_overhang_expolys.erase(std::remove_if(
|
|
||||||
super_overhang_expolys.begin(),
|
|
||||||
super_overhang_expolys.end(),
|
|
||||||
[extrusion_width_scaled](ExPolygon& area) {
|
|
||||||
return offset_ex(area, -0.1 * extrusion_width_scaled).empty();
|
|
||||||
}),
|
|
||||||
super_overhang_expolys.end());
|
|
||||||
|
|
||||||
// remove bridge
|
|
||||||
if (bridge_no_support)
|
|
||||||
remove_bridges_from_contacts(lower_layer, layer, extrusion_width_scaled, &super_overhang_expolys, max_bridge_length);
|
|
||||||
|
|
||||||
Polygons super_overhang_polys = to_polygons(super_overhang_expolys);
|
|
||||||
|
|
||||||
|
|
||||||
super_overhang_polys.erase(std::remove_if(
|
|
||||||
super_overhang_polys.begin(),
|
|
||||||
super_overhang_polys.end(),
|
|
||||||
[extrusion_width_scaled](Polygon& area) {
|
|
||||||
return offset_ex(area, -0.1 * extrusion_width_scaled).empty();
|
|
||||||
}),
|
|
||||||
super_overhang_polys.end());
|
|
||||||
|
|
||||||
double super_overhang_area = 0.0;
|
|
||||||
for (Polygon& poly : super_overhang_polys) {
|
|
||||||
bool is_ccw = poly.is_counter_clockwise();
|
|
||||||
double area_ = poly.area();
|
|
||||||
if (is_ccw) {
|
|
||||||
if (area_ > super_overhang_area_threshold)
|
|
||||||
return LargeOverhang;
|
|
||||||
super_overhang_area += area_;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
super_overhang_area -= area_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if (super_overhang_area > super_overhang_area_threshold)
|
|
||||||
// return LargeOverhang;
|
|
||||||
|
|
||||||
// 3. check overhang distance
|
|
||||||
const double distance_threshold_scaled = extrusion_width_scaled * 2;
|
|
||||||
ExPolygons lower_layer_offseted_2 = offset_ex(lower_layer->lslices, distance_threshold_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS);
|
|
||||||
ExPolygons exceed_overhang = std::move(diff_ex(super_overhang_polys, lower_layer_offseted_2));
|
|
||||||
exceed_overhang.erase(std::remove_if(
|
|
||||||
exceed_overhang.begin(),
|
|
||||||
exceed_overhang.end(),
|
|
||||||
[extrusion_width_scaled](ExPolygon& area) {
|
|
||||||
// tolerance for 1 extrusion width offset
|
|
||||||
return offset_ex(area, -0.5 * extrusion_width_scaled).empty();
|
|
||||||
}),
|
|
||||||
exceed_overhang.end());
|
|
||||||
if (!exceed_overhang.empty())
|
|
||||||
return LargeOverhang;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
TreeSupport tree_support(*this, m_slicing_params);
|
TreeSupport tree_support(*this, m_slicing_params);
|
||||||
tree_support.support_type = SupportType::stTreeAuto; // need to set support type to fully utilize the power of feature detection
|
tree_support.support_type = SupportType::stTreeAuto; // need to set support type to fully utilize the power of feature detection
|
||||||
tree_support.detect_overhangs(true);
|
tree_support.detect_overhangs(true);
|
||||||
|
@ -4028,7 +3943,7 @@ SupportNecessaryType PrintObject::is_support_necessary()
|
||||||
return SharpTail;
|
return SharpTail;
|
||||||
else if (tree_support.has_cantilever && tree_support.max_cantilever_dist > cantilevel_dist_thresh)
|
else if (tree_support.has_cantilever && tree_support.max_cantilever_dist > cantilevel_dist_thresh)
|
||||||
return Cantilever;
|
return Cantilever;
|
||||||
#endif
|
|
||||||
return NoNeedSupp;
|
return NoNeedSupp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4219,7 +4134,7 @@ static void project_triangles_to_slabs(ConstLayerPtrsAdaptor layers, const index
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintObject::project_and_append_custom_facets(
|
void PrintObject::project_and_append_custom_facets(
|
||||||
bool seam, EnforcerBlockerType type, std::vector<Polygons>& out) const
|
bool seam, EnforcerBlockerType type, std::vector<Polygons>& out, std::vector<std::pair<Vec3f, Vec3f>>* vertical_points) const
|
||||||
{
|
{
|
||||||
for (const ModelVolume* mv : this->model_object()->volumes)
|
for (const ModelVolume* mv : this->model_object()->volumes)
|
||||||
if (mv->is_model_part()) {
|
if (mv->is_model_part()) {
|
||||||
|
@ -4234,7 +4149,7 @@ void PrintObject::project_and_append_custom_facets(
|
||||||
else {
|
else {
|
||||||
std::vector<Polygons> projected;
|
std::vector<Polygons> projected;
|
||||||
// Support blockers or enforcers. Project downward facing painted areas upwards to their respective slicing plane.
|
// 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.
|
// Merge these projections with the output, layer by layer.
|
||||||
assert(! projected.empty());
|
assert(! projected.empty());
|
||||||
assert(out.empty() || out.size() == projected.size());
|
assert(out.empty() || out.size() == projected.size());
|
||||||
|
|
|
@ -808,10 +808,11 @@ void PrintObject::slice()
|
||||||
std::string warning = fix_slicing_errors(this, m_layers, [this](){ m_print->throw_if_canceled(); }, firstLayerReplacedBy);
|
std::string warning = fix_slicing_errors(this, m_layers, [this](){ m_print->throw_if_canceled(); }, firstLayerReplacedBy);
|
||||||
m_print->throw_if_canceled();
|
m_print->throw_if_canceled();
|
||||||
//BBS: send warning message to slicing callback
|
//BBS: send warning message to slicing callback
|
||||||
if (!warning.empty()) {
|
// This warning is inaccurate, because the empty layers may have been replaced, or the model has supports.
|
||||||
BOOST_LOG_TRIVIAL(info) << warning;
|
//if (!warning.empty()) {
|
||||||
this->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, warning, PrintStateBase::SlicingReplaceInitEmptyLayers);
|
// BOOST_LOG_TRIVIAL(info) << warning;
|
||||||
}
|
// this->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, warning, PrintStateBase::SlicingReplaceInitEmptyLayers);
|
||||||
|
//}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Detect and process holes that should be converted to polyholes
|
// Detect and process holes that should be converted to polyholes
|
||||||
|
|
|
@ -1030,6 +1030,9 @@ void reorder_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const s
|
||||||
|
|
||||||
void chain_and_reorder_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const Point *start_near)
|
void chain_and_reorder_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const Point *start_near)
|
||||||
{
|
{
|
||||||
|
// this function crashes if there are empty elements in entities
|
||||||
|
entities.erase(std::remove_if(entities.begin(), entities.end(), [](ExtrusionEntity *entity) { return static_cast<ExtrusionEntityCollection *>(entity)->empty(); }),
|
||||||
|
entities.end());
|
||||||
reorder_extrusion_entities(entities, chain_extrusion_entities(entities, start_near));
|
reorder_extrusion_entities(entities, chain_extrusion_entities(entities, start_near));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ SlicingParameters SlicingParameters::create_from_config(
|
||||||
params.min_layer_height = std::min(params.min_layer_height, params.layer_height);
|
params.min_layer_height = std::min(params.min_layer_height, params.layer_height);
|
||||||
params.max_layer_height = std::max(params.max_layer_height, params.layer_height);
|
params.max_layer_height = std::max(params.max_layer_height, params.layer_height);
|
||||||
|
|
||||||
if (! soluble_interface || is_tree_slim(object_config.support_type.value, object_config.support_style.value)) {
|
if (! soluble_interface) {
|
||||||
params.gap_raft_object = object_config.raft_contact_distance.value;
|
params.gap_raft_object = object_config.raft_contact_distance.value;
|
||||||
//BBS
|
//BBS
|
||||||
params.gap_object_support = object_config.support_bottom_z_distance.value;
|
params.gap_object_support = object_config.support_bottom_z_distance.value;
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace Slic3r {
|
||||||
|
|
||||||
// how much we extend support around the actual contact area
|
// how much we extend support around the actual contact area
|
||||||
//FIXME this should be dependent on the nozzle diameter!
|
//FIXME this should be dependent on the nozzle diameter!
|
||||||
#define SUPPORT_MATERIAL_MARGIN 1.5
|
#define SUPPORT_MATERIAL_MARGIN 1.5
|
||||||
|
|
||||||
//#define SUPPORT_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 3.
|
//#define SUPPORT_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 3.
|
||||||
//#define SUPPORT_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 1.5
|
//#define SUPPORT_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 1.5
|
||||||
|
@ -140,10 +140,11 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa
|
||||||
if (! intermediate_layers.empty() && support_params.has_interfaces()) {
|
if (! intermediate_layers.empty() && support_params.has_interfaces()) {
|
||||||
// For all intermediate layers, collect top contact surfaces, which are not further than support_material_interface_layers.
|
// For all intermediate layers, collect top contact surfaces, which are not further than support_material_interface_layers.
|
||||||
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - start";
|
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - start";
|
||||||
const bool snug_supports = config.support_style.value == smsSnug;
|
const bool snug_supports = support_params.support_style == smsSnug;
|
||||||
const bool smooth_supports = config.support_style.value != smsGrid;
|
const bool smooth_supports = support_params.support_style != smsGrid;
|
||||||
SupportGeneratorLayersPtr &interface_layers = base_and_interface_layers.first;
|
SupportGeneratorLayersPtr &interface_layers = base_and_interface_layers.first;
|
||||||
SupportGeneratorLayersPtr &base_interface_layers = base_and_interface_layers.second;
|
SupportGeneratorLayersPtr &base_interface_layers = base_and_interface_layers.second;
|
||||||
|
|
||||||
interface_layers.assign(intermediate_layers.size(), nullptr);
|
interface_layers.assign(intermediate_layers.size(), nullptr);
|
||||||
if (support_params.has_base_interfaces())
|
if (support_params.has_base_interfaces())
|
||||||
base_interface_layers.assign(intermediate_layers.size(), nullptr);
|
base_interface_layers.assign(intermediate_layers.size(), nullptr);
|
||||||
|
@ -152,7 +153,7 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa
|
||||||
const auto closing_distance = smoothing_distance; // scaled<float>(config.support_material_closing_radius.value);
|
const auto closing_distance = smoothing_distance; // scaled<float>(config.support_material_closing_radius.value);
|
||||||
// Insert a new layer into base_interface_layers, if intersection with base exists.
|
// Insert a new layer into base_interface_layers, if intersection with base exists.
|
||||||
auto insert_layer = [&layer_storage, smooth_supports, closing_distance, smoothing_distance, minimum_island_radius](
|
auto insert_layer = [&layer_storage, smooth_supports, closing_distance, smoothing_distance, minimum_island_radius](
|
||||||
SupportGeneratorLayer &intermediate_layer, Polygons &bottom, Polygons &&top, SupportGeneratorLayer *top_interface_layer,
|
SupportGeneratorLayer &intermediate_layer, Polygons &bottom, Polygons &&top, SupportGeneratorLayer *top_interface_layer,
|
||||||
const Polygons *subtract, SupporLayerType type) -> SupportGeneratorLayer* {
|
const Polygons *subtract, SupporLayerType type) -> SupportGeneratorLayer* {
|
||||||
bool has_top_interface = top_interface_layer && ! top_interface_layer->polygons.empty();
|
bool has_top_interface = top_interface_layer && ! top_interface_layer->polygons.empty();
|
||||||
assert(! bottom.empty() || ! top.empty() || has_top_interface);
|
assert(! bottom.empty() || ! top.empty() || has_top_interface);
|
||||||
|
@ -194,7 +195,7 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa
|
||||||
};
|
};
|
||||||
tbb::parallel_for(tbb::blocked_range<int>(0, int(intermediate_layers.size())),
|
tbb::parallel_for(tbb::blocked_range<int>(0, int(intermediate_layers.size())),
|
||||||
[&bottom_contacts, &top_contacts, &top_interface_layers, &top_base_interface_layers, &intermediate_layers, &insert_layer, &support_params,
|
[&bottom_contacts, &top_contacts, &top_interface_layers, &top_base_interface_layers, &intermediate_layers, &insert_layer, &support_params,
|
||||||
snug_supports, &interface_layers, &base_interface_layers](const tbb::blocked_range<int>& range) {
|
snug_supports, &interface_layers, &base_interface_layers](const tbb::blocked_range<int>& range) {
|
||||||
// Gather the top / bottom contact layers intersecting with num_interface_layers resp. num_interface_layers_only intermediate layers above / below
|
// Gather the top / bottom contact layers intersecting with num_interface_layers resp. num_interface_layers_only intermediate layers above / below
|
||||||
// this intermediate layer.
|
// this intermediate layer.
|
||||||
// Index of the first top contact layer intersecting the current intermediate layer.
|
// Index of the first top contact layer intersecting the current intermediate layer.
|
||||||
|
@ -230,7 +231,7 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa
|
||||||
//FIXME maybe this adds one interface layer in excess?
|
//FIXME maybe this adds one interface layer in excess?
|
||||||
if (top_contact_layer.bottom_z - EPSILON > top_z)
|
if (top_contact_layer.bottom_z - EPSILON > top_z)
|
||||||
break;
|
break;
|
||||||
polygons_append(top_contact_layer.bottom_z - EPSILON > top_inteface_z ? polygons_top_contact_projected_base : polygons_top_contact_projected_interface,
|
polygons_append(top_contact_layer.bottom_z - EPSILON > top_inteface_z ? polygons_top_contact_projected_base : polygons_top_contact_projected_interface,
|
||||||
// For snug supports, project the overhang polygons covering the whole overhang, so that they will merge without a gap with support polygons of the other layers.
|
// For snug supports, project the overhang polygons covering the whole overhang, so that they will merge without a gap with support polygons of the other layers.
|
||||||
// For grid supports, merging of support regions will be performed by the projection into grid.
|
// For grid supports, merging of support regions will be performed by the projection into grid.
|
||||||
snug_supports ? *top_contact_layer.overhang_polygons : top_contact_layer.polygons);
|
snug_supports ? *top_contact_layer.overhang_polygons : top_contact_layer.polygons);
|
||||||
|
@ -242,7 +243,7 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa
|
||||||
coordf_t bottom_interface_z = - std::numeric_limits<coordf_t>::max();
|
coordf_t bottom_interface_z = - std::numeric_limits<coordf_t>::max();
|
||||||
if (support_params.num_bottom_base_interface_layers > 0)
|
if (support_params.num_bottom_base_interface_layers > 0)
|
||||||
// Some bottom base interface layers will be generated.
|
// Some bottom base interface layers will be generated.
|
||||||
bottom_interface_z = support_params.num_bottom_interface_layers_only() == 0 ?
|
bottom_interface_z = support_params.num_bottom_interface_layers_only() == 0 ?
|
||||||
// Only base interface layers to generate.
|
// Only base interface layers to generate.
|
||||||
std::numeric_limits<coordf_t>::max() :
|
std::numeric_limits<coordf_t>::max() :
|
||||||
intermediate_layers[std::max(0, idx_intermediate_layer - int(support_params.num_bottom_interface_layers_only()))]->bottom_z;
|
intermediate_layers[std::max(0, idx_intermediate_layer - int(support_params.num_bottom_interface_layers_only()))]->bottom_z;
|
||||||
|
@ -307,7 +308,7 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa
|
||||||
base_interface_layers = merge_remove_empty(base_interface_layers, top_base_interface_layers);
|
base_interface_layers = merge_remove_empty(base_interface_layers, top_base_interface_layers);
|
||||||
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - end";
|
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - end";
|
||||||
}
|
}
|
||||||
|
|
||||||
return base_and_interface_layers;
|
return base_and_interface_layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,19 +330,21 @@ SupportGeneratorLayersPtr generate_raft_base(
|
||||||
const BrimType brim_type = object.config().brim_type;
|
const BrimType brim_type = object.config().brim_type;
|
||||||
const bool brim_outer = brim_type == btOuterOnly || brim_type == btOuterAndInner;
|
const bool brim_outer = brim_type == btOuterOnly || brim_type == btOuterAndInner;
|
||||||
const bool brim_inner = brim_type == btInnerOnly || brim_type == btOuterAndInner;
|
const bool brim_inner = brim_type == btInnerOnly || brim_type == btOuterAndInner;
|
||||||
const auto brim_separation = scaled<float>(object.config().brim_object_gap.value + object.config().brim_width.value);
|
// BBS: the pattern of raft and brim are the same, thus the brim can be serpated by support raft.
|
||||||
|
const auto brim_object_gap = scaled<float>(object.config().brim_object_gap.value);
|
||||||
|
//const auto brim_object_gap = scaled<float>(object.config().brim_object_gap.value + object.config().brim_width.value);
|
||||||
for (const ExPolygon &ex : object.layers().front()->lslices) {
|
for (const ExPolygon &ex : object.layers().front()->lslices) {
|
||||||
if (brim_outer && brim_inner)
|
if (brim_outer && brim_inner)
|
||||||
polygons_append(brim, offset(ex, brim_separation));
|
polygons_append(brim, offset(ex, brim_object_gap));
|
||||||
else {
|
else {
|
||||||
if (brim_outer)
|
if (brim_outer)
|
||||||
polygons_append(brim, offset(ex.contour, brim_separation, ClipperLib::jtRound, float(scale_(0.1))));
|
polygons_append(brim, offset(ex.contour, brim_object_gap, ClipperLib::jtRound, float(scale_(0.1))));
|
||||||
else
|
else
|
||||||
brim.emplace_back(ex.contour);
|
brim.emplace_back(ex.contour);
|
||||||
if (brim_inner) {
|
if (brim_inner) {
|
||||||
Polygons holes = ex.holes;
|
Polygons holes = ex.holes;
|
||||||
polygons_reverse(holes);
|
polygons_reverse(holes);
|
||||||
holes = shrink(holes, brim_separation, ClipperLib::jtRound, float(scale_(0.1)));
|
holes = shrink(holes, brim_object_gap, ClipperLib::jtRound, float(scale_(0.1)));
|
||||||
polygons_reverse(holes);
|
polygons_reverse(holes);
|
||||||
polygons_append(brim, std::move(holes));
|
polygons_append(brim, std::move(holes));
|
||||||
} else
|
} else
|
||||||
|
@ -378,7 +381,7 @@ SupportGeneratorLayersPtr generate_raft_base(
|
||||||
polygons_append(interface_polygons, expand(interfaces->polygons, inflate_factor_fine, SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
polygons_append(interface_polygons, expand(interfaces->polygons, inflate_factor_fine, SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
||||||
if (base_interfaces != nullptr && ! base_interfaces->polygons.empty())
|
if (base_interfaces != nullptr && ! base_interfaces->polygons.empty())
|
||||||
polygons_append(interface_polygons, expand(base_interfaces->polygons, inflate_factor_fine, SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
polygons_append(interface_polygons, expand(base_interfaces->polygons, inflate_factor_fine, SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
||||||
|
|
||||||
// Output vector.
|
// Output vector.
|
||||||
SupportGeneratorLayersPtr raft_layers;
|
SupportGeneratorLayersPtr raft_layers;
|
||||||
|
|
||||||
|
@ -402,12 +405,12 @@ SupportGeneratorLayersPtr generate_raft_base(
|
||||||
}
|
}
|
||||||
if (! interface_polygons.empty()) {
|
if (! interface_polygons.empty()) {
|
||||||
// Merge the untrimmed columns base with the expanded raft interface, to be used for the support base and interface.
|
// Merge the untrimmed columns base with the expanded raft interface, to be used for the support base and interface.
|
||||||
base = union_(base, interface_polygons);
|
base = union_(base, interface_polygons);
|
||||||
}
|
}
|
||||||
// Do not add the raft contact layer, only add the raft layers below the contact layer.
|
// Do not add the raft contact layer, only add the raft layers below the contact layer.
|
||||||
// Insert the 1st layer.
|
// Insert the 1st layer.
|
||||||
{
|
{
|
||||||
SupportGeneratorLayer &new_layer = layer_storage.allocate_unguarded(slicing_params.base_raft_layers > 0 ? SupporLayerType::RaftBase : SupporLayerType::RaftInterface);
|
SupportGeneratorLayer &new_layer = layer_storage.allocate(slicing_params.base_raft_layers > 0 ? SupporLayerType::RaftBase : SupporLayerType::RaftInterface);
|
||||||
raft_layers.push_back(&new_layer);
|
raft_layers.push_back(&new_layer);
|
||||||
new_layer.print_z = slicing_params.first_print_layer_height;
|
new_layer.print_z = slicing_params.first_print_layer_height;
|
||||||
new_layer.height = slicing_params.first_print_layer_height;
|
new_layer.height = slicing_params.first_print_layer_height;
|
||||||
|
@ -441,7 +444,13 @@ SupportGeneratorLayersPtr generate_raft_base(
|
||||||
if (columns_base != nullptr) {
|
if (columns_base != nullptr) {
|
||||||
// Expand the bases of the support columns in the 1st layer.
|
// Expand the bases of the support columns in the 1st layer.
|
||||||
Polygons &raft = columns_base->polygons;
|
Polygons &raft = columns_base->polygons;
|
||||||
Polygons trimming = offset(object.layers().front()->lslices, (float)scale_(support_params.gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS);
|
Polygons trimming;
|
||||||
|
// BBS: if first layer of support is intersected with object island, it must have the same function as brim unless in nobrim mode.
|
||||||
|
// brim_object_gap is changed to 0 by default, it's no longer appropriate to use it to determine the gap of first layer support.
|
||||||
|
//if (object.has_brim())
|
||||||
|
// trimming = offset(object.layers().front()->lslices, (float)scale_(object.config().brim_object_gap.value), SUPPORT_SURFACES_OFFSET_PARAMETERS);
|
||||||
|
//else
|
||||||
|
trimming = offset(object.layers().front()->lslices, (float)scale_(support_params.gap_xy_first_layer), SUPPORT_SURFACES_OFFSET_PARAMETERS);
|
||||||
if (inflate_factor_1st_layer > SCALED_EPSILON) {
|
if (inflate_factor_1st_layer > SCALED_EPSILON) {
|
||||||
// Inflate in multiple steps to avoid leaking of the support 1st layer through object walls.
|
// Inflate in multiple steps to avoid leaking of the support 1st layer through object walls.
|
||||||
auto nsteps = std::max(5, int(ceil(inflate_factor_1st_layer / support_params.first_layer_flow.scaled_width())));
|
auto nsteps = std::max(5, int(ceil(inflate_factor_1st_layer / support_params.first_layer_flow.scaled_width())));
|
||||||
|
@ -536,10 +545,10 @@ static Polylines draw_perimeters(const ExPolygon &expoly, double clip_length)
|
||||||
return polylines;
|
return polylines;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void tree_supports_generate_paths(
|
void tree_supports_generate_paths(
|
||||||
ExtrusionEntitiesPtr &dst,
|
ExtrusionEntitiesPtr &dst,
|
||||||
const Polygons &polygons,
|
const Polygons &polygons,
|
||||||
const Flow &flow,
|
const Flow &flow,
|
||||||
const SupportParameters &support_params)
|
const SupportParameters &support_params)
|
||||||
{
|
{
|
||||||
// Offset expolygon inside, returns number of expolygons collected (0 or 1).
|
// Offset expolygon inside, returns number of expolygons collected (0 or 1).
|
||||||
|
@ -606,7 +615,7 @@ static inline void tree_supports_generate_paths(
|
||||||
// No hole remaining after an offset. Just copy the outer contour.
|
// No hole remaining after an offset. Just copy the outer contour.
|
||||||
append(out, std::move(contours));
|
append(out, std::move(contours));
|
||||||
} else {
|
} else {
|
||||||
// Negative offset. There is a chance, that the offsetted hole intersects the outer contour.
|
// Negative offset. There is a chance, that the offsetted hole intersects the outer contour.
|
||||||
// Subtract the offsetted holes from the offsetted contours.
|
// Subtract the offsetted holes from the offsetted contours.
|
||||||
ClipperLib_Z::Clipper clipper;
|
ClipperLib_Z::Clipper clipper;
|
||||||
clipper.ZFillFunction([](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top, const ClipperLib_Z::IntPoint &e2bot, const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt) {
|
clipper.ZFillFunction([](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top, const ClipperLib_Z::IntPoint &e2bot, const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt) {
|
||||||
|
@ -637,124 +646,126 @@ static inline void tree_supports_generate_paths(
|
||||||
ClipperLib_Z::Paths anchor_candidates;
|
ClipperLib_Z::Paths anchor_candidates;
|
||||||
for (ExPolygon& expoly : closing_ex(polygons, float(SCALED_EPSILON), float(SCALED_EPSILON + 0.5 * flow.scaled_width()))) {
|
for (ExPolygon& expoly : closing_ex(polygons, float(SCALED_EPSILON), float(SCALED_EPSILON + 0.5 * flow.scaled_width()))) {
|
||||||
std::unique_ptr<ExtrusionEntityCollection> eec;
|
std::unique_ptr<ExtrusionEntityCollection> eec;
|
||||||
|
ExPolygons regions_to_draw_inner_wall{expoly};
|
||||||
if (support_params.tree_branch_diameter_double_wall_area_scaled > 0)
|
if (support_params.tree_branch_diameter_double_wall_area_scaled > 0)
|
||||||
if (double area = expoly.area(); area > support_params.tree_branch_diameter_double_wall_area_scaled) {
|
if (double area = expoly.area(); area > support_params.tree_branch_diameter_double_wall_area_scaled) {
|
||||||
|
BOOST_LOG_TRIVIAL(debug)<< "TreeSupports: double wall area: " << area<< " > " << support_params.tree_branch_diameter_double_wall_area_scaled;
|
||||||
eec = std::make_unique<ExtrusionEntityCollection>();
|
eec = std::make_unique<ExtrusionEntityCollection>();
|
||||||
// Don't reoder internal / external loops of the same island, always start with the internal loop.
|
// Don't reorder internal / external loops of the same island, always start with the internal loop.
|
||||||
eec->no_sort = true;
|
eec->no_sort = true;
|
||||||
// Make the tree branch stable by adding another perimeter.
|
// Make the tree branch stable by adding another perimeter.
|
||||||
ExPolygons level2 = offset2_ex({ expoly }, -1.5 * flow.scaled_width(), 0.5 * flow.scaled_width());
|
ExPolygons level2 = offset2_ex({expoly}, -1.5 * flow.scaled_width(), 0.5 * flow.scaled_width());
|
||||||
if (level2.size() == 1) {
|
if (level2.size() > 0) {
|
||||||
Polylines polylines;
|
regions_to_draw_inner_wall = level2;
|
||||||
extrusion_entities_append_paths(eec->entities, draw_perimeters(expoly, clip_length), ExtrusionRole::erSupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height(),
|
extrusion_entities_append_paths(eec->entities, draw_perimeters(expoly, clip_length), ExtrusionRole::erSupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height(),
|
||||||
// Disable reversal of the path, always start with the anchor, always print CCW.
|
// Disable reversal of the path, always start with the anchor, always print CCW.
|
||||||
false);
|
false);
|
||||||
expoly = level2.front();
|
expoly = level2.front();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (ExPolygon &expoly : regions_to_draw_inner_wall)
|
||||||
|
{
|
||||||
|
// Try to produce one more perimeter to place the seam anchor.
|
||||||
|
// First genrate a 2nd perimeter loop as a source for anchor candidates.
|
||||||
|
// The anchor candidate points are annotated with an index of the source contour or with -1 if on intersection.
|
||||||
|
anchor_candidates.clear();
|
||||||
|
shrink_expolygon_with_contour_idx(expoly, flow.scaled_width(), DefaultJoinType, 1.2, anchor_candidates);
|
||||||
|
// Orient all contours CW.
|
||||||
|
for (auto &path : anchor_candidates)
|
||||||
|
if (ClipperLib_Z::Area(path) > 0) std::reverse(path.begin(), path.end());
|
||||||
|
|
||||||
// Try to produce one more perimeter to place the seam anchor.
|
// Draw the perimeters.
|
||||||
// First genrate a 2nd perimeter loop as a source for anchor candidates.
|
Polylines polylines;
|
||||||
// The anchor candidate points are annotated with an index of the source contour or with -1 if on intersection.
|
polylines.reserve(expoly.holes.size() + 1);
|
||||||
anchor_candidates.clear();
|
for (int idx_loop = 0; idx_loop < int(expoly.num_contours()); ++idx_loop) {
|
||||||
shrink_expolygon_with_contour_idx(expoly, flow.scaled_width(), DefaultJoinType, 1.2, anchor_candidates);
|
// Open the loop with a seam.
|
||||||
// Orient all contours CW.
|
const Polygon &loop = expoly.contour_or_hole(idx_loop);
|
||||||
for (auto &path : anchor_candidates)
|
Polyline pl(loop.points);
|
||||||
if (ClipperLib_Z::Area(path) > 0)
|
// Orient all contours CW, because the anchor will be added to the end of polyline while we want to start a loop with the anchor.
|
||||||
std::reverse(path.begin(), path.end());
|
if (idx_loop == 0)
|
||||||
|
// It is an outer contour.
|
||||||
// Draw the perimeters.
|
pl.reverse();
|
||||||
Polylines polylines;
|
pl.points.emplace_back(pl.points.front());
|
||||||
polylines.reserve(expoly.holes.size() + 1);
|
pl.clip_end(clip_length);
|
||||||
for (int idx_loop = 0; idx_loop < int(expoly.num_contours()); ++ idx_loop) {
|
if (pl.size() < 2) continue;
|
||||||
// Open the loop with a seam.
|
// Find the foot of the seam point on anchor_candidates. Only pick an anchor point that was created by offsetting the source contour.
|
||||||
const Polygon &loop = expoly.contour_or_hole(idx_loop);
|
ClipperLib_Z::Path *closest_contour = nullptr;
|
||||||
Polyline pl(loop.points);
|
Vec2d closest_point;
|
||||||
// Orient all contours CW, because the anchor will be added to the end of polyline while we want to start a loop with the anchor.
|
int closest_point_idx = -1;
|
||||||
if (idx_loop == 0)
|
double closest_point_t = 0.;
|
||||||
// It is an outer contour.
|
double d2min = std::numeric_limits<double>::max();
|
||||||
pl.reverse();
|
Vec2d seam_pt = pl.back().cast<double>();
|
||||||
pl.points.emplace_back(pl.points.front());
|
for (ClipperLib_Z::Path &path : anchor_candidates)
|
||||||
pl.clip_end(clip_length);
|
for (int i = 0; i < int(path.size()); ++i) {
|
||||||
if (pl.size() < 2)
|
int j = next_idx_modulo(i, path);
|
||||||
continue;
|
if (path[i].z() == idx_loop || path[j].z() == idx_loop) {
|
||||||
// Find the foot of the seam point on anchor_candidates. Only pick an anchor point that was created by offsetting the source contour.
|
Vec2d pi(path[i].x(), path[i].y());
|
||||||
ClipperLib_Z::Path *closest_contour = nullptr;
|
Vec2d pj(path[j].x(), path[j].y());
|
||||||
Vec2d closest_point;
|
Vec2d v = pj - pi;
|
||||||
int closest_point_idx = -1;
|
Vec2d w = seam_pt - pi;
|
||||||
double closest_point_t = 0.;
|
auto l2 = v.squaredNorm();
|
||||||
double d2min = std::numeric_limits<double>::max();
|
auto t = std::clamp((l2 == 0) ? 0 : v.dot(w) / l2, 0., 1.);
|
||||||
Vec2d seam_pt = pl.back().cast<double>();
|
if ((path[i].z() == idx_loop || t > EPSILON) && (path[j].z() == idx_loop || t < 1. - EPSILON)) {
|
||||||
for (ClipperLib_Z::Path &path : anchor_candidates)
|
// Closest point.
|
||||||
for (int i = 0; i < int(path.size()); ++ i) {
|
Vec2d fp = pi + v * t;
|
||||||
int j = next_idx_modulo(i, path);
|
double d2 = (fp - seam_pt).squaredNorm();
|
||||||
if (path[i].z() == idx_loop || path[j].z() == idx_loop) {
|
if (d2 < d2min) {
|
||||||
Vec2d pi(path[i].x(), path[i].y());
|
d2min = d2;
|
||||||
Vec2d pj(path[j].x(), path[j].y());
|
closest_contour = &path;
|
||||||
Vec2d v = pj - pi;
|
closest_point = fp;
|
||||||
Vec2d w = seam_pt - pi;
|
closest_point_idx = i;
|
||||||
auto l2 = v.squaredNorm();
|
closest_point_t = t;
|
||||||
auto t = std::clamp((l2 == 0) ? 0 : v.dot(w) / l2, 0., 1.);
|
}
|
||||||
if ((path[i].z() == idx_loop || t > EPSILON) && (path[j].z() == idx_loop || t < 1. - EPSILON)) {
|
|
||||||
// Closest point.
|
|
||||||
Vec2d fp = pi + v * t;
|
|
||||||
double d2 = (fp - seam_pt).squaredNorm();
|
|
||||||
if (d2 < d2min) {
|
|
||||||
d2min = d2;
|
|
||||||
closest_contour = &path;
|
|
||||||
closest_point = fp;
|
|
||||||
closest_point_idx = i;
|
|
||||||
closest_point_t = t;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (d2min < sqr(flow.scaled_width() * 3.)) {
|
||||||
if (d2min < sqr(flow.scaled_width() * 3.)) {
|
// Try to cut an anchor from the closest_contour.
|
||||||
// Try to cut an anchor from the closest_contour.
|
// Both closest_contour and pl are CW oriented.
|
||||||
// Both closest_contour and pl are CW oriented.
|
pl.points.emplace_back(closest_point.cast<coord_t>());
|
||||||
pl.points.emplace_back(closest_point.cast<coord_t>());
|
const ClipperLib_Z::Path &path = *closest_contour;
|
||||||
const ClipperLib_Z::Path &path = *closest_contour;
|
double remaining_length = anchor_length - (seam_pt - closest_point).norm();
|
||||||
double remaining_length = anchor_length - (seam_pt - closest_point).norm();
|
int i = closest_point_idx;
|
||||||
int i = closest_point_idx;
|
int j = next_idx_modulo(i, *closest_contour);
|
||||||
int j = next_idx_modulo(i, *closest_contour);
|
Vec2d pi(path[i].x(), path[i].y());
|
||||||
Vec2d pi(path[i].x(), path[i].y());
|
Vec2d pj(path[j].x(), path[j].y());
|
||||||
Vec2d pj(path[j].x(), path[j].y());
|
Vec2d v = pj - pi;
|
||||||
Vec2d v = pj - pi;
|
double l = v.norm();
|
||||||
double l = v.norm();
|
if (remaining_length < (1. - closest_point_t) * l) {
|
||||||
if (remaining_length < (1. - closest_point_t) * l) {
|
// Just trim the current line.
|
||||||
// Just trim the current line.
|
pl.points.emplace_back((closest_point + v * (remaining_length / l)).cast<coord_t>());
|
||||||
pl.points.emplace_back((closest_point + v * (remaining_length / l)).cast<coord_t>());
|
} else {
|
||||||
} else {
|
// Take the rest of the current line, continue with the other lines.
|
||||||
// Take the rest of the current line, continue with the other lines.
|
|
||||||
pl.points.emplace_back(path[j].x(), path[j].y());
|
|
||||||
pi = pj;
|
|
||||||
for (i = j; path[i].z() == idx_loop && remaining_length > 0; i = j, pi = pj) {
|
|
||||||
j = next_idx_modulo(i, path);
|
|
||||||
pj = Vec2d(path[j].x(), path[j].y());
|
|
||||||
v = pj - pi;
|
|
||||||
l = v.norm();
|
|
||||||
if (i == closest_point_idx) {
|
|
||||||
// Back at the first segment. Most likely this should not happen and we may end the anchor.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (remaining_length <= l) {
|
|
||||||
pl.points.emplace_back((pi + v * (remaining_length / l)).cast<coord_t>());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pl.points.emplace_back(path[j].x(), path[j].y());
|
pl.points.emplace_back(path[j].x(), path[j].y());
|
||||||
remaining_length -= l;
|
pi = pj;
|
||||||
|
for (i = j; path[i].z() == idx_loop && remaining_length > 0; i = j, pi = pj) {
|
||||||
|
j = next_idx_modulo(i, path);
|
||||||
|
pj = Vec2d(path[j].x(), path[j].y());
|
||||||
|
v = pj - pi;
|
||||||
|
l = v.norm();
|
||||||
|
if (i == closest_point_idx) {
|
||||||
|
// Back at the first segment. Most likely this should not happen and we may end the anchor.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (remaining_length <= l) {
|
||||||
|
pl.points.emplace_back((pi + v * (remaining_length / l)).cast<coord_t>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pl.points.emplace_back(path[j].x(), path[j].y());
|
||||||
|
remaining_length -= l;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Start with the anchor.
|
||||||
|
pl.reverse();
|
||||||
|
polylines.emplace_back(std::move(pl));
|
||||||
}
|
}
|
||||||
// Start with the anchor.
|
|
||||||
pl.reverse();
|
|
||||||
polylines.emplace_back(std::move(pl));
|
|
||||||
}
|
|
||||||
|
|
||||||
ExtrusionEntitiesPtr &out = eec ? eec->entities : dst;
|
ExtrusionEntitiesPtr &out = eec ? eec->entities : dst;
|
||||||
extrusion_entities_append_paths(out, std::move(polylines), ExtrusionRole::erSupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height(),
|
extrusion_entities_append_paths(out, std::move(polylines), ExtrusionRole::erSupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height(),
|
||||||
// Disable reversal of the path, always start with the anchor, always print CCW.
|
// Disable reversal of the path, always start with the anchor, always print CCW.
|
||||||
false);
|
false);
|
||||||
|
}
|
||||||
if (eec) {
|
if (eec) {
|
||||||
std::reverse(eec->entities.begin(), eec->entities.end());
|
std::reverse(eec->entities.begin(), eec->entities.end());
|
||||||
dst.emplace_back(eec.release());
|
dst.emplace_back(eec.release());
|
||||||
|
@ -762,20 +773,27 @@ static inline void tree_supports_generate_paths(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void fill_expolygons_with_sheath_generate_paths(
|
void fill_expolygons_with_sheath_generate_paths(
|
||||||
ExtrusionEntitiesPtr &dst,
|
ExtrusionEntitiesPtr &dst,
|
||||||
const Polygons &polygons,
|
const Polygons &polygons,
|
||||||
Fill *filler,
|
Fill *filler,
|
||||||
float density,
|
float density,
|
||||||
ExtrusionRole role,
|
ExtrusionRole role,
|
||||||
const Flow &flow,
|
const Flow &flow,
|
||||||
|
const SupportParameters& support_params,
|
||||||
bool with_sheath,
|
bool with_sheath,
|
||||||
bool no_sort)
|
bool no_sort)
|
||||||
{
|
{
|
||||||
if (polygons.empty())
|
if (polygons.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (! with_sheath) {
|
if (with_sheath) {
|
||||||
|
if (density == 0) {
|
||||||
|
tree_supports_generate_paths(dst, polygons, flow, support_params);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
fill_expolygons_generate_paths(dst, closing_ex(polygons, float(SCALED_EPSILON)), filler, density, role, flow);
|
fill_expolygons_generate_paths(dst, closing_ex(polygons, float(SCALED_EPSILON)), filler, density, role, flow);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -819,8 +837,8 @@ struct SupportGeneratorLayerExtruded
|
||||||
return layer == nullptr || layer->polygons.empty();
|
return layer == nullptr || layer->polygons.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_polygons_to_extrude(Polygons &&polygons) {
|
void set_polygons_to_extrude(Polygons &&polygons) {
|
||||||
if (m_polygons_to_extrude == nullptr)
|
if (m_polygons_to_extrude == nullptr)
|
||||||
m_polygons_to_extrude = std::make_unique<Polygons>(std::move(polygons));
|
m_polygons_to_extrude = std::make_unique<Polygons>(std::move(polygons));
|
||||||
else
|
else
|
||||||
*m_polygons_to_extrude = std::move(polygons);
|
*m_polygons_to_extrude = std::move(polygons);
|
||||||
|
@ -829,9 +847,9 @@ struct SupportGeneratorLayerExtruded
|
||||||
const Polygons& polygons_to_extrude() const { return (m_polygons_to_extrude == nullptr) ? layer->polygons : *m_polygons_to_extrude; }
|
const Polygons& polygons_to_extrude() const { return (m_polygons_to_extrude == nullptr) ? layer->polygons : *m_polygons_to_extrude; }
|
||||||
|
|
||||||
bool could_merge(const SupportGeneratorLayerExtruded &other) const {
|
bool could_merge(const SupportGeneratorLayerExtruded &other) const {
|
||||||
return ! this->empty() && ! other.empty() &&
|
return ! this->empty() && ! other.empty() &&
|
||||||
std::abs(this->layer->height - other.layer->height) < EPSILON &&
|
std::abs(this->layer->height - other.layer->height) < EPSILON &&
|
||||||
this->layer->bridging == other.layer->bridging;
|
this->layer->bridging == other.layer->bridging;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge regions, perform boolean union over the merged polygons.
|
// Merge regions, perform boolean union over the merged polygons.
|
||||||
|
@ -937,7 +955,7 @@ void LoopInterfaceProcessor::generate(SupportGeneratorLayerExtruded &top_contact
|
||||||
const Point* operator()(const Point &pt) const { return &pt; }
|
const Point* operator()(const Point &pt) const { return &pt; }
|
||||||
};
|
};
|
||||||
typedef ClosestPointInRadiusLookup<Point, PointAccessor> ClosestPointLookupType;
|
typedef ClosestPointInRadiusLookup<Point, PointAccessor> ClosestPointLookupType;
|
||||||
|
|
||||||
Polygons loops0;
|
Polygons loops0;
|
||||||
{
|
{
|
||||||
// find centerline of the external loop of the contours
|
// find centerline of the external loop of the contours
|
||||||
|
@ -1034,7 +1052,7 @@ void LoopInterfaceProcessor::generate(SupportGeneratorLayerExtruded &top_contact
|
||||||
for (int i = 1; i < n_contact_loops; ++ i)
|
for (int i = 1; i < n_contact_loops; ++ i)
|
||||||
polygons_append(loop_polygons,
|
polygons_append(loop_polygons,
|
||||||
opening(
|
opening(
|
||||||
loops0,
|
loops0,
|
||||||
i * flow.scaled_spacing() + 0.5f * flow.scaled_spacing(),
|
i * flow.scaled_spacing() + 0.5f * flow.scaled_spacing(),
|
||||||
0.5f * flow.scaled_spacing()));
|
0.5f * flow.scaled_spacing()));
|
||||||
// Clip such loops to the side oriented towards the object.
|
// Clip such loops to the side oriented towards the object.
|
||||||
|
@ -1094,7 +1112,7 @@ void LoopInterfaceProcessor::generate(SupportGeneratorLayerExtruded &top_contact
|
||||||
// Remove empty lines.
|
// Remove empty lines.
|
||||||
remove_degenerate(loop_lines);
|
remove_degenerate(loop_lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the contact infill area to the interface area
|
// add the contact infill area to the interface area
|
||||||
// note that growing loops by $circle_radius ensures no tiny
|
// note that growing loops by $circle_radius ensures no tiny
|
||||||
// extrusions are left inside the circles; however it creates
|
// extrusions are left inside the circles; however it creates
|
||||||
|
@ -1166,7 +1184,7 @@ static void modulate_extrusion_by_overlapping_layers(
|
||||||
// Split the extrusions by the overlapping layers, reduce their extrusion rate.
|
// Split the extrusions by the overlapping layers, reduce their extrusion rate.
|
||||||
// The last path_fragment is from this_layer.
|
// The last path_fragment is from this_layer.
|
||||||
std::vector<ExtrusionPathFragment> path_fragments(
|
std::vector<ExtrusionPathFragment> path_fragments(
|
||||||
n_overlapping_layers + 1,
|
n_overlapping_layers + 1,
|
||||||
ExtrusionPathFragment(extrusion_path_template->mm3_per_mm, extrusion_path_template->width, extrusion_path_template->height));
|
ExtrusionPathFragment(extrusion_path_template->mm3_per_mm, extrusion_path_template->width, extrusion_path_template->height));
|
||||||
// Don't use it, it will be released.
|
// Don't use it, it will be released.
|
||||||
extrusion_path_template = nullptr;
|
extrusion_path_template = nullptr;
|
||||||
|
@ -1218,7 +1236,7 @@ static void modulate_extrusion_by_overlapping_layers(
|
||||||
#endif /* SLIC3R_DEBUG */
|
#endif /* SLIC3R_DEBUG */
|
||||||
|
|
||||||
// End points of the original paths.
|
// End points of the original paths.
|
||||||
std::vector<std::pair<Point, Point>> path_ends;
|
std::vector<std::pair<Point, Point>> path_ends;
|
||||||
// Collect the paths of this_layer.
|
// Collect the paths of this_layer.
|
||||||
{
|
{
|
||||||
Polylines &polylines = path_fragments.back().polylines;
|
Polylines &polylines = path_fragments.back().polylines;
|
||||||
|
@ -1399,6 +1417,10 @@ SupportGeneratorLayersPtr generate_support_layers(
|
||||||
append(layers_sorted, intermediate_layers);
|
append(layers_sorted, intermediate_layers);
|
||||||
append(layers_sorted, interface_layers);
|
append(layers_sorted, interface_layers);
|
||||||
append(layers_sorted, base_interface_layers);
|
append(layers_sorted, base_interface_layers);
|
||||||
|
// remove dupliated layers
|
||||||
|
std::sort(layers_sorted.begin(), layers_sorted.end());
|
||||||
|
layers_sorted.erase(std::unique(layers_sorted.begin(), layers_sorted.end()), layers_sorted.end());
|
||||||
|
|
||||||
// Sort the layers lexicographically by a raising print_z and a decreasing height.
|
// Sort the layers lexicographically by a raising print_z and a decreasing height.
|
||||||
std::sort(layers_sorted.begin(), layers_sorted.end(), [](auto *l1, auto *l2) { return *l1 < *l2; });
|
std::sort(layers_sorted.begin(), layers_sorted.end(), [](auto *l1, auto *l2) { return *l1 < *l2; });
|
||||||
int layer_id = 0;
|
int layer_id = 0;
|
||||||
|
@ -1435,7 +1457,7 @@ SupportGeneratorLayersPtr generate_support_layers(
|
||||||
height_min = std::min(height_min, layer.height);
|
height_min = std::min(height_min, layer.height);
|
||||||
}
|
}
|
||||||
if (! empty) {
|
if (! empty) {
|
||||||
// Here the upper_layer and lower_layer pointers are left to null at the support layers,
|
// Here the upper_layer and lower_layer pointers are left to null at the support layers,
|
||||||
// as they are never used. These pointers are candidates for removal.
|
// as they are never used. These pointers are candidates for removal.
|
||||||
bool this_layer_contacts_only = num_top_contacts > 0 && num_top_contacts == num_interfaces;
|
bool this_layer_contacts_only = num_top_contacts > 0 && num_top_contacts == num_interfaces;
|
||||||
size_t this_layer_id_interface = layer_id_interface;
|
size_t this_layer_id_interface = layer_id_interface;
|
||||||
|
@ -1510,7 +1532,7 @@ void generate_support_toolpaths(
|
||||||
|
|
||||||
// Print the support base below the support columns, or the support base for the support columns plus the contacts.
|
// Print the support base below the support columns, or the support base for the support columns plus the contacts.
|
||||||
if (support_layer_id > 0) {
|
if (support_layer_id > 0) {
|
||||||
const Polygons &to_infill_polygons = (support_layer_id < slicing_params.base_raft_layers) ?
|
const Polygons &to_infill_polygons = (support_layer_id < slicing_params.base_raft_layers) ?
|
||||||
raft_layer.polygons :
|
raft_layer.polygons :
|
||||||
//FIXME misusing contact_polygons for support columns.
|
//FIXME misusing contact_polygons for support columns.
|
||||||
((raft_layer.contact_polygons == nullptr) ? Polygons() : *raft_layer.contact_polygons);
|
((raft_layer.contact_polygons == nullptr) ? Polygons() : *raft_layer.contact_polygons);
|
||||||
|
@ -1531,7 +1553,7 @@ void generate_support_toolpaths(
|
||||||
filler, float(support_params.support_density),
|
filler, float(support_params.support_density),
|
||||||
// Extrusion parameters
|
// Extrusion parameters
|
||||||
ExtrusionRole::erSupportMaterial, flow,
|
ExtrusionRole::erSupportMaterial, flow,
|
||||||
support_params.with_sheath, false);
|
support_params, support_params.with_sheath, false);
|
||||||
}
|
}
|
||||||
if (! tree_polygons.empty())
|
if (! tree_polygons.empty())
|
||||||
tree_supports_generate_paths(support_layer.support_fills.entities, tree_polygons, flow, support_params);
|
tree_supports_generate_paths(support_layer.support_fills.entities, tree_polygons, flow, support_params);
|
||||||
|
@ -1558,15 +1580,15 @@ void generate_support_toolpaths(
|
||||||
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
|
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
|
||||||
fill_expolygons_with_sheath_generate_paths(
|
fill_expolygons_with_sheath_generate_paths(
|
||||||
// Destination
|
// Destination
|
||||||
support_layer.support_fills.entities,
|
support_layer.support_fills.entities,
|
||||||
// Regions to fill
|
// Regions to fill
|
||||||
tree_polygons.empty() ? raft_layer.polygons : diff(raft_layer.polygons, tree_polygons),
|
tree_polygons.empty() ? raft_layer.polygons : diff(raft_layer.polygons, tree_polygons),
|
||||||
// Filler and its parameters
|
// Filler and its parameters
|
||||||
filler, density,
|
filler, density,
|
||||||
// Extrusion parameters
|
// Extrusion parameters
|
||||||
(support_layer_id < slicing_params.base_raft_layers) ? ExtrusionRole::erSupportMaterial : ExtrusionRole::erSupportMaterialInterface, flow,
|
(support_layer_id < slicing_params.base_raft_layers) ? ExtrusionRole::erSupportMaterial : ExtrusionRole::erSupportMaterialInterface, flow,
|
||||||
// sheath at first layer
|
// sheath at first layer
|
||||||
support_layer_id == 0, support_layer_id == 0);
|
support_params, support_layer_id == 0, support_layer_id == 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1610,12 +1632,12 @@ void generate_support_toolpaths(
|
||||||
// Pointer to the 1st layer interface filler.
|
// Pointer to the 1st layer interface filler.
|
||||||
auto filler_first_layer = filler_first_layer_ptr ? filler_first_layer_ptr.get() : filler_interface.get();
|
auto filler_first_layer = filler_first_layer_ptr ? filler_first_layer_ptr.get() : filler_interface.get();
|
||||||
// Filler for the 1st layer interface, if different from filler_interface.
|
// Filler for the 1st layer interface, if different from filler_interface.
|
||||||
auto filler_raft_contact_ptr = std::unique_ptr<Fill>(range.begin() == n_raft_layers && config.support_interface_top_layers.value == 0 ?
|
auto filler_raft_contact_ptr = std::unique_ptr<Fill>(range.begin() == n_raft_layers && config.support_interface_top_layers.value == 0 ?
|
||||||
Fill::new_from_type(support_params.raft_interface_fill_pattern) : nullptr);
|
Fill::new_from_type(support_params.raft_interface_fill_pattern) : nullptr);
|
||||||
// Pointer to the 1st layer interface filler.
|
// Pointer to the 1st layer interface filler.
|
||||||
auto filler_raft_contact = filler_raft_contact_ptr ? filler_raft_contact_ptr.get() : filler_interface.get();
|
auto filler_raft_contact = filler_raft_contact_ptr ? filler_raft_contact_ptr.get() : filler_interface.get();
|
||||||
// Filler for the base interface (to be used for soluble interface / non soluble base, to produce non soluble interface layer below soluble interface layer).
|
// Filler for the base interface (to be used for soluble interface / non soluble base, to produce non soluble interface layer below soluble interface layer).
|
||||||
auto filler_base_interface = std::unique_ptr<Fill>(base_interface_layers.empty() ? nullptr :
|
auto filler_base_interface = std::unique_ptr<Fill>(base_interface_layers.empty() ? nullptr :
|
||||||
Fill::new_from_type(support_params.interface_density > 0.95 || support_params.with_sheath ? ipRectilinear : ipSupportBase));
|
Fill::new_from_type(support_params.interface_density > 0.95 || support_params.with_sheath ? ipRectilinear : ipSupportBase));
|
||||||
auto filler_support = std::unique_ptr<Fill>(Fill::new_from_type(support_params.base_fill_pattern));
|
auto filler_support = std::unique_ptr<Fill>(Fill::new_from_type(support_params.base_fill_pattern));
|
||||||
filler_interface->set_bounding_box(bbox_object);
|
filler_interface->set_bounding_box(bbox_object);
|
||||||
|
@ -1630,7 +1652,7 @@ void generate_support_toolpaths(
|
||||||
{
|
{
|
||||||
SupportLayer &support_layer = *support_layers[support_layer_id];
|
SupportLayer &support_layer = *support_layers[support_layer_id];
|
||||||
LayerCache &layer_cache = layer_caches[support_layer_id];
|
LayerCache &layer_cache = layer_caches[support_layer_id];
|
||||||
const float support_interface_angle = config.support_style.value == smsGrid ?
|
const float support_interface_angle = (support_params.support_style == smsGrid || config.support_interface_pattern == smipRectilinear) ?
|
||||||
support_params.interface_angle : support_params.raft_interface_angle(support_layer.interface_id());
|
support_params.interface_angle : support_params.raft_interface_angle(support_layer.interface_id());
|
||||||
|
|
||||||
// Find polygons with the same print_z.
|
// Find polygons with the same print_z.
|
||||||
|
@ -1678,7 +1700,7 @@ void generate_support_toolpaths(
|
||||||
// to trim other layers.
|
// to trim other layers.
|
||||||
if (top_contact_layer.could_merge(interface_layer) && ! raft_layer)
|
if (top_contact_layer.could_merge(interface_layer) && ! raft_layer)
|
||||||
top_contact_layer.merge(std::move(interface_layer));
|
top_contact_layer.merge(std::move(interface_layer));
|
||||||
}
|
}
|
||||||
if ((config.support_interface_top_layers == 0 || config.support_interface_bottom_layers == 0) && support_params.can_merge_support_regions) {
|
if ((config.support_interface_top_layers == 0 || config.support_interface_bottom_layers == 0) && support_params.can_merge_support_regions) {
|
||||||
if (base_layer.could_merge(bottom_contact_layer))
|
if (base_layer.could_merge(bottom_contact_layer))
|
||||||
base_layer.merge(std::move(bottom_contact_layer));
|
base_layer.merge(std::move(bottom_contact_layer));
|
||||||
|
@ -1712,14 +1734,14 @@ void generate_support_toolpaths(
|
||||||
auto *filler = raft_contact ? filler_raft_contact : filler_interface.get();
|
auto *filler = raft_contact ? filler_raft_contact : filler_interface.get();
|
||||||
auto interface_flow = layer_ex.layer->bridging ?
|
auto interface_flow = layer_ex.layer->bridging ?
|
||||||
Flow::bridging_flow(layer_ex.layer->height, support_params.support_material_bottom_interface_flow.nozzle_diameter()) :
|
Flow::bridging_flow(layer_ex.layer->height, support_params.support_material_bottom_interface_flow.nozzle_diameter()) :
|
||||||
(raft_contact ? &support_params.raft_interface_flow :
|
(raft_contact ? &support_params.raft_interface_flow :
|
||||||
interface_as_base ? &support_params.support_material_flow : &support_params.support_material_interface_flow)
|
interface_as_base ? &support_params.support_material_flow : &support_params.support_material_interface_flow)
|
||||||
->with_height(float(layer_ex.layer->height));
|
->with_height(float(layer_ex.layer->height));
|
||||||
filler->angle = interface_as_base ?
|
filler->angle = interface_as_base ?
|
||||||
// If zero interface layers are configured, use the same angle as for the base layers.
|
// If zero interface layers are configured, use the same angle as for the base layers.
|
||||||
angles[support_layer_id % angles.size()] :
|
angles[support_layer_id % angles.size()] :
|
||||||
// Use interface angle for the interface layers.
|
// Use interface angle for the interface layers.
|
||||||
raft_contact ?
|
raft_contact ?
|
||||||
support_params.raft_interface_angle(support_layer.interface_id()) :
|
support_params.raft_interface_angle(support_layer.interface_id()) :
|
||||||
support_interface_angle;
|
support_interface_angle;
|
||||||
double density = raft_contact ? support_params.raft_interface_density : interface_as_base ? support_params.support_density : support_params.interface_density;
|
double density = raft_contact ? support_params.raft_interface_density : interface_as_base ? support_params.support_density : support_params.interface_density;
|
||||||
|
@ -1728,13 +1750,13 @@ void generate_support_toolpaths(
|
||||||
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
|
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
|
||||||
fill_expolygons_generate_paths(
|
fill_expolygons_generate_paths(
|
||||||
// Destination
|
// Destination
|
||||||
layer_ex.extrusions,
|
layer_ex.extrusions,
|
||||||
// Regions to fill
|
// Regions to fill
|
||||||
union_safety_offset_ex(layer_ex.polygons_to_extrude()),
|
union_safety_offset_ex(layer_ex.polygons_to_extrude()),
|
||||||
// Filler and its parameters
|
// Filler and its parameters
|
||||||
filler, float(density),
|
filler, float(density),
|
||||||
// Extrusion parameters
|
// Extrusion parameters
|
||||||
ExtrusionRole::erSupportMaterialInterface, interface_flow);
|
interface_as_base ? ExtrusionRole::erSupportMaterial : ExtrusionRole::erSupportMaterialInterface, interface_flow);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const bool top_interfaces = config.support_interface_top_layers.value != 0;
|
const bool top_interfaces = config.support_interface_top_layers.value != 0;
|
||||||
|
@ -1755,7 +1777,7 @@ void generate_support_toolpaths(
|
||||||
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_params.interface_density));
|
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_params.interface_density));
|
||||||
fill_expolygons_generate_paths(
|
fill_expolygons_generate_paths(
|
||||||
// Destination
|
// Destination
|
||||||
base_interface_layer.extrusions,
|
base_interface_layer.extrusions,
|
||||||
//base_layer_interface.extrusions,
|
//base_layer_interface.extrusions,
|
||||||
// Regions to fill
|
// Regions to fill
|
||||||
union_safety_offset_ex(base_interface_layer.polygons_to_extrude()),
|
union_safety_offset_ex(base_interface_layer.polygons_to_extrude()),
|
||||||
|
@ -1767,7 +1789,7 @@ void generate_support_toolpaths(
|
||||||
|
|
||||||
// Base support or flange.
|
// Base support or flange.
|
||||||
if (! base_layer.empty() && ! base_layer.polygons_to_extrude().empty()) {
|
if (! base_layer.empty() && ! base_layer.polygons_to_extrude().empty()) {
|
||||||
Fill *filler = filler_support.get();
|
Fill *filler = filler_support.get();
|
||||||
filler->angle = angles[support_layer_id % angles.size()];
|
filler->angle = angles[support_layer_id % angles.size()];
|
||||||
// We don't use $base_flow->spacing because we need a constant spacing
|
// We don't use $base_flow->spacing because we need a constant spacing
|
||||||
// value that guarantees that all layers are correctly aligned.
|
// value that guarantees that all layers are correctly aligned.
|
||||||
|
@ -1792,10 +1814,12 @@ void generate_support_toolpaths(
|
||||||
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
|
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
|
||||||
sheath = true;
|
sheath = true;
|
||||||
no_sort = true;
|
no_sort = true;
|
||||||
} else if (config.support_style == SupportMaterialStyle::smsOrganic ||
|
} else if (support_params.support_style == SupportMaterialStyle::smsTreeOrganic) {
|
||||||
// Orca: use organic as default
|
// if the tree supports are too tall, use double wall to make it stronger
|
||||||
config.support_style == smsDefault) {
|
SupportParameters support_params2 = support_params;
|
||||||
tree_supports_generate_paths(base_layer.extrusions, base_layer.polygons_to_extrude(), flow, support_params);
|
if (support_layer.print_z > 100.0)
|
||||||
|
support_params2.tree_branch_diameter_double_wall_area_scaled = 0.1;
|
||||||
|
tree_supports_generate_paths(base_layer.extrusions, base_layer.polygons_to_extrude(), flow, support_params2);
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
if (! done)
|
if (! done)
|
||||||
|
@ -1808,7 +1832,7 @@ void generate_support_toolpaths(
|
||||||
filler, density,
|
filler, density,
|
||||||
// Extrusion parameters
|
// Extrusion parameters
|
||||||
ExtrusionRole::erSupportMaterial, flow,
|
ExtrusionRole::erSupportMaterial, flow,
|
||||||
sheath, no_sort);
|
support_params, sheath, no_sort);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge base_interface_layers to base_layers to avoid unneccessary retractions
|
// Merge base_interface_layers to base_layers to avoid unneccessary retractions
|
||||||
|
@ -1912,7 +1936,7 @@ void PrintObjectSupportMaterial::clip_by_pillars(
|
||||||
|
|
||||||
coord_t pillar_size = scale_(PILLAR_SIZE);
|
coord_t pillar_size = scale_(PILLAR_SIZE);
|
||||||
coord_t pillar_spacing = scale_(PILLAR_SPACING);
|
coord_t pillar_spacing = scale_(PILLAR_SPACING);
|
||||||
|
|
||||||
// A regular grid of pillars, filling the 2D bounding box.
|
// A regular grid of pillars, filling the 2D bounding box.
|
||||||
Polygons grid;
|
Polygons grid;
|
||||||
{
|
{
|
||||||
|
@ -1922,7 +1946,7 @@ void PrintObjectSupportMaterial::clip_by_pillars(
|
||||||
pillar.points.push_back(Point(pillar_size, 0));
|
pillar.points.push_back(Point(pillar_size, 0));
|
||||||
pillar.points.push_back(Point(pillar_size, pillar_size));
|
pillar.points.push_back(Point(pillar_size, pillar_size));
|
||||||
pillar.points.push_back(Point(0, pillar_size));
|
pillar.points.push_back(Point(0, pillar_size));
|
||||||
|
|
||||||
// 2D bounding box of the projection of all contact polygons.
|
// 2D bounding box of the projection of all contact polygons.
|
||||||
BoundingBox bbox;
|
BoundingBox bbox;
|
||||||
for (LayersPtr::const_iterator it = top_contacts.begin(); it != top_contacts.end(); ++ it)
|
for (LayersPtr::const_iterator it = top_contacts.begin(); it != top_contacts.end(); ++ it)
|
||||||
|
@ -1936,30 +1960,30 @@ void PrintObjectSupportMaterial::clip_by_pillars(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add pillars to every layer
|
// add pillars to every layer
|
||||||
for my $i (0..n_support_z) {
|
for my $i (0..n_support_z) {
|
||||||
$shape->[$i] = [ @$grid ];
|
$shape->[$i] = [ @$grid ];
|
||||||
}
|
}
|
||||||
|
|
||||||
// build capitals
|
// build capitals
|
||||||
for my $i (0..n_support_z) {
|
for my $i (0..n_support_z) {
|
||||||
my $z = $support_z->[$i];
|
my $z = $support_z->[$i];
|
||||||
|
|
||||||
my $capitals = intersection(
|
my $capitals = intersection(
|
||||||
$grid,
|
$grid,
|
||||||
$contact->{$z} // [],
|
$contact->{$z} // [],
|
||||||
);
|
);
|
||||||
|
|
||||||
// work on one pillar at time (if any) to prevent the capitals from being merged
|
// work on one pillar at time (if any) to prevent the capitals from being merged
|
||||||
// but store the contact area supported by the capital because we need to make
|
// but store the contact area supported by the capital because we need to make
|
||||||
// sure nothing is left
|
// sure nothing is left
|
||||||
my $contact_supported_by_capitals = [];
|
my $contact_supported_by_capitals = [];
|
||||||
foreach my $capital (@$capitals) {
|
foreach my $capital (@$capitals) {
|
||||||
// enlarge capital tops
|
// enlarge capital tops
|
||||||
$capital = offset([$capital], +($pillar_spacing - $pillar_size)/2);
|
$capital = offset([$capital], +($pillar_spacing - $pillar_size)/2);
|
||||||
push @$contact_supported_by_capitals, @$capital;
|
push @$contact_supported_by_capitals, @$capital;
|
||||||
|
|
||||||
for (my $j = $i-1; $j >= 0; $j--) {
|
for (my $j = $i-1; $j >= 0; $j--) {
|
||||||
my $jz = $support_z->[$j];
|
my $jz = $support_z->[$j];
|
||||||
$capital = offset($capital, -$self->interface_flow->scaled_width/2);
|
$capital = offset($capital, -$self->interface_flow->scaled_width/2);
|
||||||
|
@ -1967,7 +1991,7 @@ void PrintObjectSupportMaterial::clip_by_pillars(
|
||||||
push @{ $shape->[$j] }, @$capital;
|
push @{ $shape->[$j] }, @$capital;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capitals will not generally cover the whole contact area because there will be
|
// Capitals will not generally cover the whole contact area because there will be
|
||||||
// remainders. For now we handle this situation by projecting such unsupported
|
// remainders. For now we handle this situation by projecting such unsupported
|
||||||
// areas to the ground, just like we would do with a normal support.
|
// areas to the ground, just like we would do with a normal support.
|
||||||
|
@ -1985,10 +2009,10 @@ void PrintObjectSupportMaterial::clip_by_pillars(
|
||||||
|
|
||||||
sub clip_with_shape {
|
sub clip_with_shape {
|
||||||
my ($self, $support, $shape) = @_;
|
my ($self, $support, $shape) = @_;
|
||||||
|
|
||||||
foreach my $i (keys %$support) {
|
foreach my $i (keys %$support) {
|
||||||
// don't clip bottom layer with shape so that we
|
// don't clip bottom layer with shape so that we
|
||||||
// can generate a continuous base flange
|
// can generate a continuous base flange
|
||||||
// also don't clip raft layers
|
// also don't clip raft layers
|
||||||
next if $i == 0;
|
next if $i == 0;
|
||||||
next if $i < $self->object_config->raft_layers;
|
next if $i < $self->object_config->raft_layers;
|
||||||
|
|
|
@ -50,6 +50,11 @@ SupportGeneratorLayersPtr generate_raft_base(
|
||||||
const SupportGeneratorLayersPtr &base_layers,
|
const SupportGeneratorLayersPtr &base_layers,
|
||||||
SupportGeneratorLayerStorage &layer_storage);
|
SupportGeneratorLayerStorage &layer_storage);
|
||||||
|
|
||||||
|
void tree_supports_generate_paths(ExtrusionEntitiesPtr &dst, const Polygons &polygons, const Flow &flow, const SupportParameters &support_params);
|
||||||
|
|
||||||
|
void fill_expolygons_with_sheath_generate_paths(
|
||||||
|
ExtrusionEntitiesPtr &dst, const Polygons &polygons, Fill *filler, float density, ExtrusionRole role, const Flow &flow, const SupportParameters& support_params, bool with_sheath, bool no_sort);
|
||||||
|
|
||||||
// returns sorted layers
|
// returns sorted layers
|
||||||
SupportGeneratorLayersPtr generate_support_layers(
|
SupportGeneratorLayersPtr generate_support_layers(
|
||||||
PrintObject &object,
|
PrintObject &object,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -6,6 +6,7 @@
|
||||||
#include "Slicing.hpp"
|
#include "Slicing.hpp"
|
||||||
#include "Fill/FillBase.hpp"
|
#include "Fill/FillBase.hpp"
|
||||||
#include "SupportLayer.hpp"
|
#include "SupportLayer.hpp"
|
||||||
|
#include "SupportParameters.hpp"
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class PrintObject;
|
class PrintObject;
|
||||||
|
@ -18,35 +19,6 @@ class PrintObjectConfig;
|
||||||
// the parameters of the raft to determine the 1st layer height and thickness.
|
// the parameters of the raft to determine the 1st layer height and thickness.
|
||||||
class PrintObjectSupportMaterial
|
class PrintObjectSupportMaterial
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
|
|
||||||
struct SupportParams {
|
|
||||||
Flow first_layer_flow;
|
|
||||||
Flow support_material_flow;
|
|
||||||
Flow support_material_interface_flow;
|
|
||||||
Flow support_material_bottom_interface_flow;
|
|
||||||
// Is merging of regions allowed? Could the interface & base support regions be printed with the same extruder?
|
|
||||||
bool can_merge_support_regions;
|
|
||||||
|
|
||||||
coordf_t support_layer_height_min;
|
|
||||||
// coordf_t support_layer_height_max;
|
|
||||||
|
|
||||||
coordf_t gap_xy;
|
|
||||||
|
|
||||||
float base_angle;
|
|
||||||
float interface_angle;
|
|
||||||
coordf_t interface_spacing;
|
|
||||||
coordf_t support_expansion;
|
|
||||||
coordf_t interface_density;
|
|
||||||
coordf_t support_spacing;
|
|
||||||
coordf_t support_density;
|
|
||||||
|
|
||||||
InfillPattern base_fill_pattern;
|
|
||||||
InfillPattern interface_fill_pattern;
|
|
||||||
InfillPattern contact_fill_pattern;
|
|
||||||
bool with_sheath;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PrintObjectSupportMaterial(const PrintObject *object, const SlicingParameters &slicing_params);
|
PrintObjectSupportMaterial(const PrintObject *object, const SlicingParameters &slicing_params);
|
||||||
|
|
||||||
|
@ -97,25 +69,7 @@ private:
|
||||||
SupportGeneratorLayersPtr &intermediate_layers,
|
SupportGeneratorLayersPtr &intermediate_layers,
|
||||||
const std::vector<Polygons> &layer_support_areas) const;
|
const std::vector<Polygons> &layer_support_areas) const;
|
||||||
|
|
||||||
// Generate raft layers, also expand the 1st support layer
|
|
||||||
// in case there is no raft layer to improve support adhesion.
|
|
||||||
SupportGeneratorLayersPtr generate_raft_base(
|
|
||||||
const PrintObject &object,
|
|
||||||
const SupportGeneratorLayersPtr &top_contacts,
|
|
||||||
const SupportGeneratorLayersPtr &interface_layers,
|
|
||||||
const SupportGeneratorLayersPtr &base_interface_layers,
|
|
||||||
const SupportGeneratorLayersPtr &base_layers,
|
|
||||||
SupportGeneratorLayerStorage &layer_storage) const;
|
|
||||||
|
|
||||||
// Turn some of the base layers into base interface layers.
|
|
||||||
// For soluble interfaces with non-soluble bases, print maximum two first interface layers with the base
|
|
||||||
// extruder to improve adhesion of the soluble filament to the base.
|
|
||||||
std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interface_layers(
|
|
||||||
const SupportGeneratorLayersPtr &bottom_contacts,
|
|
||||||
const SupportGeneratorLayersPtr &top_contacts,
|
|
||||||
SupportGeneratorLayersPtr &intermediate_layers,
|
|
||||||
SupportGeneratorLayerStorage &layer_storage) const;
|
|
||||||
|
|
||||||
|
|
||||||
// Trim support layers by an object to leave a defined gap between
|
// Trim support layers by an object to leave a defined gap between
|
||||||
// the support volume and the object.
|
// the support volume and the object.
|
||||||
|
@ -131,16 +85,6 @@ private:
|
||||||
void clip_with_shape();
|
void clip_with_shape();
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Produce the actual G-code.
|
|
||||||
void generate_toolpaths(
|
|
||||||
SupportLayerPtrs &support_layers,
|
|
||||||
const SupportGeneratorLayersPtr &raft_layers,
|
|
||||||
const SupportGeneratorLayersPtr &bottom_contacts,
|
|
||||||
const SupportGeneratorLayersPtr &top_contacts,
|
|
||||||
const SupportGeneratorLayersPtr &intermediate_layers,
|
|
||||||
const SupportGeneratorLayersPtr &interface_layers,
|
|
||||||
const SupportGeneratorLayersPtr &base_interface_layers) const;
|
|
||||||
|
|
||||||
// Following objects are not owned by SupportMaterial class.
|
// Following objects are not owned by SupportMaterial class.
|
||||||
const PrintObject *m_object;
|
const PrintObject *m_object;
|
||||||
const PrintConfig *m_print_config;
|
const PrintConfig *m_print_config;
|
||||||
|
@ -149,7 +93,7 @@ private:
|
||||||
// carrying information on a raft, 1st layer height, 1st object layer height, gap between the raft and object etc.
|
// carrying information on a raft, 1st layer height, 1st object layer height, gap between the raft and object etc.
|
||||||
SlicingParameters m_slicing_params;
|
SlicingParameters m_slicing_params;
|
||||||
// Various precomputed support parameters to be shared with external functions.
|
// Various precomputed support parameters to be shared with external functions.
|
||||||
SupportParams m_support_params;
|
SupportParameters m_support_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -1,53 +1,53 @@
|
||||||
#ifndef slic3r_SupportParameters_hpp_
|
#ifndef slic3r_SupportParameters_hpp_
|
||||||
#define slic3r_SupportParameters_hpp_
|
#define slic3r_SupportParameters_hpp_
|
||||||
|
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
#include "../libslic3r.h"
|
#include "../libslic3r.h"
|
||||||
#include "../Flow.hpp"
|
#include "../Flow.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class PrintObject;
|
|
||||||
enum InfillPattern : int;
|
|
||||||
|
|
||||||
struct SupportParameters {
|
struct SupportParameters {
|
||||||
SupportParameters(const PrintObject &object)
|
SupportParameters() = delete;
|
||||||
|
SupportParameters(const PrintObject& object)
|
||||||
{
|
{
|
||||||
const PrintConfig &print_config = object.print()->config();
|
const PrintConfig& print_config = object.print()->config();
|
||||||
const PrintObjectConfig &object_config = object.config();
|
const PrintObjectConfig& object_config = object.config();
|
||||||
const SlicingParameters &slicing_params = object.slicing_parameters();
|
const SlicingParameters& slicing_params = object.slicing_parameters();
|
||||||
|
|
||||||
this->soluble_interface = slicing_params.soluble_interface;
|
this->soluble_interface = slicing_params.soluble_interface;
|
||||||
this->soluble_interface_non_soluble_base =
|
this->soluble_interface_non_soluble_base =
|
||||||
// Zero z-gap between the overhangs and the support interface.
|
// Zero z-gap between the overhangs and the support interface.
|
||||||
slicing_params.soluble_interface &&
|
slicing_params.soluble_interface &&
|
||||||
// Interface extruder soluble.
|
// Interface extruder soluble.
|
||||||
object_config.support_interface_filament.value > 0 && print_config.filament_soluble.get_at(object_config.support_interface_filament.value - 1) &&
|
object_config.support_interface_filament.value > 0 && print_config.filament_soluble.get_at(object_config.support_interface_filament.value - 1) &&
|
||||||
// Base extruder: Either "print with active extruder" not soluble.
|
// Base extruder: Either "print with active extruder" not soluble.
|
||||||
(object_config.support_filament.value == 0 || ! print_config.filament_soluble.get_at(object_config.support_filament.value - 1));
|
(object_config.support_filament.value == 0 || ! print_config.filament_soluble.get_at(object_config.support_filament.value - 1));
|
||||||
|
|
||||||
{
|
{
|
||||||
int num_top_interface_layers = std::max(0, object_config.support_interface_top_layers.value);
|
this->num_top_interface_layers = std::max(0, object_config.support_interface_top_layers.value);
|
||||||
int num_bottom_interface_layers = object_config.support_interface_bottom_layers < 0 ?
|
this->num_bottom_interface_layers = object_config.support_interface_bottom_layers < 0 ?
|
||||||
num_top_interface_layers : object_config.support_interface_bottom_layers;
|
num_top_interface_layers : object_config.support_interface_bottom_layers;
|
||||||
this->has_top_contacts = num_top_interface_layers > 0;
|
this->has_top_contacts = num_top_interface_layers > 0;
|
||||||
this->has_bottom_contacts = num_bottom_interface_layers > 0;
|
this->has_bottom_contacts = num_bottom_interface_layers > 0;
|
||||||
this->num_top_interface_layers = this->has_top_contacts ? size_t(num_top_interface_layers - 1) : 0;
|
if (this->soluble_interface_non_soluble_base) {
|
||||||
this->num_bottom_interface_layers = this->has_bottom_contacts ? size_t(num_bottom_interface_layers - 1) : 0;
|
// Try to support soluble dense interfaces with non-soluble dense interfaces.
|
||||||
if (this->soluble_interface_non_soluble_base) {
|
this->num_top_base_interface_layers = size_t(std::min(int(num_top_interface_layers) / 2, 2));
|
||||||
// Try to support soluble dense interfaces with non-soluble dense interfaces.
|
this->num_bottom_base_interface_layers = size_t(std::min(int(num_bottom_interface_layers) / 2, 2));
|
||||||
this->num_top_base_interface_layers = size_t(std::min(num_top_interface_layers / 2, 2));
|
} else {
|
||||||
this->num_bottom_base_interface_layers = size_t(std::min(num_bottom_interface_layers / 2, 2));
|
// BBS: if support interface and support base do not use the same filament, add a base layer to improve their adhesion
|
||||||
} else {
|
// Note: support materials (such as Supp.W) can't be used as support base now, so support interface and base are still using different filaments even if
|
||||||
this->num_top_base_interface_layers = 0;
|
// support_filament==0
|
||||||
this->num_bottom_base_interface_layers = 0;
|
bool differnt_support_interface_filament = object_config.support_interface_filament != 0 &&
|
||||||
}
|
object_config.support_interface_filament != object_config.support_filament;
|
||||||
}
|
this->num_top_base_interface_layers = differnt_support_interface_filament ? 1 : 0;
|
||||||
|
this->num_bottom_base_interface_layers = differnt_support_interface_filament ? 1 : 0;
|
||||||
this->first_layer_flow = Slic3r::support_material_1st_layer_flow(&object, float(slicing_params.first_print_layer_height));
|
}
|
||||||
this->support_material_flow = Slic3r::support_material_flow(&object, float(slicing_params.layer_height));
|
}
|
||||||
this->support_material_interface_flow = Slic3r::support_material_interface_flow(&object, float(slicing_params.layer_height));
|
this->first_layer_flow = Slic3r::support_material_1st_layer_flow(&object, float(slicing_params.first_print_layer_height));
|
||||||
this->raft_interface_flow = support_material_interface_flow;
|
this->support_material_flow = Slic3r::support_material_flow(&object, float(slicing_params.layer_height));
|
||||||
|
this->support_material_interface_flow = Slic3r::support_material_interface_flow(&object, float(slicing_params.layer_height));
|
||||||
|
this->raft_interface_flow = support_material_interface_flow;
|
||||||
|
|
||||||
// Calculate a minimum support layer height as a minimum over all extruders, but not smaller than 10um.
|
// Calculate a minimum support layer height as a minimum over all extruders, but not smaller than 10um.
|
||||||
this->support_layer_height_min = scaled<coord_t>(0.01);
|
this->support_layer_height_min = scaled<coord_t>(0.01);
|
||||||
for (auto lh : print_config.min_layer_height.values)
|
for (auto lh : print_config.min_layer_height.values)
|
||||||
|
@ -69,10 +69,11 @@ struct SupportParameters {
|
||||||
external_perimeter_width = std::max(external_perimeter_width, coordf_t(region.flow(object, frExternalPerimeter, slicing_params.layer_height).width()));
|
external_perimeter_width = std::max(external_perimeter_width, coordf_t(region.flow(object, frExternalPerimeter, slicing_params.layer_height).width()));
|
||||||
bridge_flow_ratio += region.config().bridge_flow;
|
bridge_flow_ratio += region.config().bridge_flow;
|
||||||
}
|
}
|
||||||
this->gap_xy = object_config.support_object_xy_distance;//.get_abs_value(external_perimeter_width);
|
this->gap_xy = object_config.support_object_xy_distance.value;
|
||||||
|
this->gap_xy_first_layer = object_config.support_object_first_layer_gap.value;
|
||||||
bridge_flow_ratio /= object.num_printing_regions();
|
bridge_flow_ratio /= object.num_printing_regions();
|
||||||
|
|
||||||
this->support_material_bottom_interface_flow = slicing_params.soluble_interface || ! object_config.thick_bridges ?
|
this->support_material_bottom_interface_flow = slicing_params.soluble_interface || !object_config.thick_bridges ?
|
||||||
this->support_material_interface_flow.with_flow_ratio(bridge_flow_ratio) :
|
this->support_material_interface_flow.with_flow_ratio(bridge_flow_ratio) :
|
||||||
Flow::bridging_flow(bridge_flow_ratio * this->support_material_interface_flow.nozzle_diameter(), this->support_material_interface_flow.nozzle_diameter());
|
Flow::bridging_flow(bridge_flow_ratio * this->support_material_interface_flow.nozzle_diameter(), this->support_material_interface_flow.nozzle_diameter());
|
||||||
|
|
||||||
|
@ -85,33 +86,40 @@ struct SupportParameters {
|
||||||
// Object is printed with the same extruder as the support.
|
// Object is printed with the same extruder as the support.
|
||||||
this->can_merge_support_regions = true;
|
this->can_merge_support_regions = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double interface_spacing = object_config.support_interface_spacing.value + this->support_material_interface_flow.spacing();
|
|
||||||
this->interface_density = std::min(1., this->support_material_interface_flow.spacing() / interface_spacing);
|
this->base_angle = Geometry::deg2rad(float(object_config.support_angle.value));
|
||||||
|
this->interface_angle = Geometry::deg2rad(float(object_config.support_angle.value + 90.));
|
||||||
|
this->interface_spacing = object_config.support_interface_spacing.value + this->support_material_interface_flow.spacing();
|
||||||
|
this->interface_density = std::min(1., this->support_material_interface_flow.spacing() / this->interface_spacing);
|
||||||
double raft_interface_spacing = object_config.support_interface_spacing.value + this->raft_interface_flow.spacing();
|
double raft_interface_spacing = object_config.support_interface_spacing.value + this->raft_interface_flow.spacing();
|
||||||
this->raft_interface_density = std::min(1., this->raft_interface_flow.spacing() / raft_interface_spacing);
|
this->raft_interface_density = std::min(1., this->raft_interface_flow.spacing() / raft_interface_spacing);
|
||||||
double support_spacing = object_config.support_base_pattern_spacing.value + this->support_material_flow.spacing();
|
this->support_spacing = object_config.support_base_pattern_spacing.value + this->support_material_flow.spacing();
|
||||||
this->support_density = std::min(1., this->support_material_flow.spacing() / support_spacing);
|
this->support_density = std::min(1., this->support_material_flow.spacing() / this->support_spacing);
|
||||||
if (object_config.support_interface_top_layers.value == 0) {
|
if (object_config.support_interface_top_layers.value == 0) {
|
||||||
// No interface layers allowed, print everything with the base support pattern.
|
// No interface layers allowed, print everything with the base support pattern.
|
||||||
|
this->interface_spacing = this->support_spacing;
|
||||||
this->interface_density = this->support_density;
|
this->interface_density = this->support_density;
|
||||||
}
|
}
|
||||||
|
|
||||||
SupportMaterialPattern support_pattern = object_config.support_base_pattern;
|
SupportMaterialPattern support_pattern = object_config.support_base_pattern;
|
||||||
this->with_sheath = false;//object_config.support_material_with_sheath;
|
this->with_sheath = object_config.tree_support_wall_count > 0;
|
||||||
this->base_fill_pattern =
|
this->base_fill_pattern =
|
||||||
support_pattern == smpHoneycomb ? ipHoneycomb :
|
support_pattern == smpHoneycomb ? ipHoneycomb :
|
||||||
this->support_density > 0.95 || this->with_sheath ? ipRectilinear : ipSupportBase;
|
this->support_density > 0.95 || this->with_sheath ? ipRectilinear : ipSupportBase;
|
||||||
this->interface_fill_pattern = (this->interface_density > 0.95 ? ipRectilinear : ipSupportBase);
|
this->interface_fill_pattern = (this->interface_density > 0.95 ? ipRectilinear : ipSupportBase);
|
||||||
this->raft_interface_fill_pattern = this->raft_interface_density > 0.95 ? ipRectilinear : ipSupportBase;
|
this->raft_interface_fill_pattern = this->raft_interface_density > 0.95 ? ipRectilinear : ipSupportBase;
|
||||||
this->contact_fill_pattern =
|
if (object_config.support_interface_pattern == smipGrid)
|
||||||
|
this->contact_fill_pattern = ipGrid;
|
||||||
|
else if (object_config.support_interface_pattern == smipRectilinearInterlaced)
|
||||||
|
this->contact_fill_pattern = ipRectilinear;
|
||||||
|
else
|
||||||
|
this->contact_fill_pattern =
|
||||||
(object_config.support_interface_pattern == smipAuto && slicing_params.soluble_interface) ||
|
(object_config.support_interface_pattern == smipAuto && slicing_params.soluble_interface) ||
|
||||||
object_config.support_interface_pattern == smipConcentric ?
|
object_config.support_interface_pattern == smipConcentric ?
|
||||||
ipConcentric :
|
ipConcentric :
|
||||||
(this->interface_density > 0.95 ? ipRectilinear : ipSupportBase);
|
(this->interface_density > 0.95 ? ipRectilinear : ipSupportBase);
|
||||||
|
|
||||||
this->base_angle = Geometry::deg2rad(float(object_config.support_angle.value));
|
|
||||||
this->interface_angle = Geometry::deg2rad(float(object_config.support_angle.value + 90.));
|
|
||||||
this->raft_angle_1st_layer = 0.f;
|
this->raft_angle_1st_layer = 0.f;
|
||||||
this->raft_angle_base = 0.f;
|
this->raft_angle_base = 0.f;
|
||||||
this->raft_angle_interface = 0.f;
|
this->raft_angle_interface = 0.f;
|
||||||
|
@ -142,11 +150,36 @@ struct SupportParameters {
|
||||||
assert(slicing_params.interface_raft_layers == 0);
|
assert(slicing_params.interface_raft_layers == 0);
|
||||||
assert(slicing_params.raft_layers() == 0);
|
assert(slicing_params.raft_layers() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->tree_branch_diameter_double_wall_area_scaled = 0.25 * sqr(scaled<double>(object_config.tree_support_branch_diameter_double_wall.value)) * M_PI;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Both top / bottom contacts and interfaces are soluble.
|
const auto nozzle_diameter = print_config.nozzle_diameter.get_at(object_config.support_interface_filament - 1);
|
||||||
|
const coordf_t extrusion_width = object_config.line_width.get_abs_value(nozzle_diameter);
|
||||||
|
support_extrusion_width = object_config.support_line_width.get_abs_value(nozzle_diameter);
|
||||||
|
support_extrusion_width = support_extrusion_width > 0 ? support_extrusion_width : extrusion_width;
|
||||||
|
|
||||||
|
independent_layer_height = print_config.independent_support_layer_height;
|
||||||
|
|
||||||
|
// force double walls everywhere if wall count is larger than 1
|
||||||
|
tree_branch_diameter_double_wall_area_scaled = object_config.tree_support_wall_count.value > 1 ? 0.1 :
|
||||||
|
object_config.tree_support_wall_count.value == 0 ? 0.25 * sqr(scaled<double>(5.0)) * M_PI :
|
||||||
|
std::numeric_limits<double>::max();
|
||||||
|
|
||||||
|
support_style = object_config.support_style;
|
||||||
|
if (support_style != smsDefault) {
|
||||||
|
if ((support_style == smsSnug || support_style == smsGrid) && is_tree(object_config.support_type)) support_style = smsDefault;
|
||||||
|
if ((support_style == smsTreeSlim || support_style == smsTreeStrong || support_style == smsTreeHybrid || support_style == smsTreeOrganic) &&
|
||||||
|
!is_tree(object_config.support_type))
|
||||||
|
support_style = smsDefault;
|
||||||
|
}
|
||||||
|
if (support_style == smsDefault) {
|
||||||
|
if (is_tree(object_config.support_type)) {
|
||||||
|
// Orca: use organic as default
|
||||||
|
support_style = smsTreeOrganic;
|
||||||
|
} else {
|
||||||
|
support_style = smsGrid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Both top / bottom contacts and interfaces are soluble.
|
||||||
bool soluble_interface;
|
bool soluble_interface;
|
||||||
// Support contact & interface are soluble, but support base is non-soluble.
|
// Support contact & interface are soluble, but support base is non-soluble.
|
||||||
bool soluble_interface_non_soluble_base;
|
bool soluble_interface_non_soluble_base;
|
||||||
|
@ -181,23 +214,28 @@ struct SupportParameters {
|
||||||
Flow support_material_bottom_interface_flow;
|
Flow support_material_bottom_interface_flow;
|
||||||
// Flow at raft inteface & contact layers.
|
// Flow at raft inteface & contact layers.
|
||||||
Flow raft_interface_flow;
|
Flow raft_interface_flow;
|
||||||
|
coordf_t support_extrusion_width;
|
||||||
// Is merging of regions allowed? Could the interface & base support regions be printed with the same extruder?
|
// Is merging of regions allowed? Could the interface & base support regions be printed with the same extruder?
|
||||||
bool can_merge_support_regions;
|
bool can_merge_support_regions;
|
||||||
|
|
||||||
coordf_t support_layer_height_min;
|
coordf_t support_layer_height_min;
|
||||||
// coordf_t support_layer_height_max;
|
// coordf_t support_layer_height_max;
|
||||||
|
|
||||||
coordf_t gap_xy;
|
coordf_t gap_xy;
|
||||||
|
coordf_t gap_xy_first_layer;
|
||||||
|
|
||||||
float base_angle;
|
float base_angle;
|
||||||
float interface_angle;
|
float interface_angle;
|
||||||
|
coordf_t interface_spacing;
|
||||||
|
coordf_t support_expansion=0;
|
||||||
// Density of the top / bottom interface and contact layers.
|
// Density of the top / bottom interface and contact layers.
|
||||||
coordf_t interface_density;
|
coordf_t interface_density;
|
||||||
// Density of the raft interface and contact layers.
|
// Density of the raft interface and contact layers.
|
||||||
coordf_t raft_interface_density;
|
coordf_t raft_interface_density;
|
||||||
|
coordf_t support_spacing;
|
||||||
// Density of the base support layers.
|
// Density of the base support layers.
|
||||||
coordf_t support_density;
|
coordf_t support_density;
|
||||||
|
SupportMaterialStyle support_style = smsDefault;
|
||||||
|
|
||||||
// Pattern of the sparse infill including sparse raft layers.
|
// Pattern of the sparse infill including sparse raft layers.
|
||||||
InfillPattern base_fill_pattern;
|
InfillPattern base_fill_pattern;
|
||||||
|
@ -210,7 +248,7 @@ struct SupportParameters {
|
||||||
// Shall the sparse (base) layers be printed with a single perimeter line (sheath) for robustness?
|
// Shall the sparse (base) layers be printed with a single perimeter line (sheath) for robustness?
|
||||||
bool with_sheath;
|
bool with_sheath;
|
||||||
// Branches of organic supports with area larger than this threshold will be extruded with double lines.
|
// Branches of organic supports with area larger than this threshold will be extruded with double lines.
|
||||||
double tree_branch_diameter_double_wall_area_scaled;
|
double tree_branch_diameter_double_wall_area_scaled = 0.25 * sqr(scaled<double>(5.0)) * M_PI;;
|
||||||
|
|
||||||
float raft_angle_1st_layer;
|
float raft_angle_1st_layer;
|
||||||
float raft_angle_base;
|
float raft_angle_base;
|
||||||
|
@ -219,6 +257,9 @@ struct SupportParameters {
|
||||||
// Produce a raft interface angle for a given SupportLayer::interface_id()
|
// Produce a raft interface angle for a given SupportLayer::interface_id()
|
||||||
float raft_interface_angle(size_t interface_id) const
|
float raft_interface_angle(size_t interface_id) const
|
||||||
{ return this->raft_angle_interface + ((interface_id & 1) ? float(- M_PI / 4.) : float(+ M_PI / 4.)); }
|
{ return this->raft_angle_interface + ((interface_id & 1) ? float(- M_PI / 4.) : float(+ M_PI / 4.)); }
|
||||||
|
|
||||||
|
bool independent_layer_height = false;
|
||||||
|
const double thresh_big_overhang = Slic3r::sqr(scale_(10));
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -33,7 +33,7 @@ using namespace std::literals;
|
||||||
|
|
||||||
// or warning
|
// or warning
|
||||||
// had to use a define beacuse the macro processing inside macro BOOST_LOG_TRIVIAL()
|
// had to use a define beacuse the macro processing inside macro BOOST_LOG_TRIVIAL()
|
||||||
#define error_level_not_in_cache error
|
#define error_level_not_in_cache debug
|
||||||
|
|
||||||
//FIXME Machine border is currently ignored.
|
//FIXME Machine border is currently ignored.
|
||||||
static Polygons calculateMachineBorderCollision(Polygon machine_border)
|
static Polygons calculateMachineBorderCollision(Polygon machine_border)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -11,6 +11,8 @@
|
||||||
#include "Flow.hpp"
|
#include "Flow.hpp"
|
||||||
#include "PrintConfig.hpp"
|
#include "PrintConfig.hpp"
|
||||||
#include "Fill/Lightning/Generator.hpp"
|
#include "Fill/Lightning/Generator.hpp"
|
||||||
|
#include "TreeModelVolumes.hpp"
|
||||||
|
#include "TreeSupport3D.hpp"
|
||||||
|
|
||||||
#ifndef SQ
|
#ifndef SQ
|
||||||
#define SQ(x) ((x)*(x))
|
#define SQ(x) ((x)*(x))
|
||||||
|
@ -26,17 +28,158 @@ struct LayerHeightData
|
||||||
{
|
{
|
||||||
coordf_t print_z = 0;
|
coordf_t print_z = 0;
|
||||||
coordf_t height = 0;
|
coordf_t height = 0;
|
||||||
size_t next_layer_nr = 0;
|
size_t obj_layer_nr = 0;
|
||||||
LayerHeightData() = default;
|
LayerHeightData() = default;
|
||||||
LayerHeightData(coordf_t z, coordf_t h, size_t next_layer) : print_z(z), height(h), next_layer_nr(next_layer) {}
|
LayerHeightData(coordf_t z, coordf_t h, size_t obj_layer) : print_z(z), height(h), obj_layer_nr(obj_layer) {}
|
||||||
|
coordf_t bottom_z() {
|
||||||
|
return print_z - height;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TreeNode {
|
enum TreeNodeType {
|
||||||
Vec3f pos;
|
eCircle,
|
||||||
std::vector<int> children; // index of children in the storing vector
|
eSquare,
|
||||||
std::vector<int> parents; // index of parents in the storing vector
|
ePolygon
|
||||||
TreeNode(Point pt, float z) {
|
};
|
||||||
pos = { float(unscale_(pt.x())),float(unscale_(pt.y())),z };
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Represents the metadata of a node in the tree.
|
||||||
|
*/
|
||||||
|
struct SupportNode
|
||||||
|
{
|
||||||
|
static constexpr SupportNode* NO_PARENT = nullptr;
|
||||||
|
|
||||||
|
SupportNode()
|
||||||
|
: distance_to_top(0)
|
||||||
|
, position(Point(0, 0))
|
||||||
|
, obj_layer_nr(0)
|
||||||
|
, support_roof_layers_below(0)
|
||||||
|
, to_buildplate(true)
|
||||||
|
, parent(nullptr)
|
||||||
|
, print_z(0.0)
|
||||||
|
, height(0.0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// when dist_mm_to_top_==0, new node's dist_mm_to_top=parent->dist_mm_to_top + parent->height;
|
||||||
|
SupportNode(const Point position, const int distance_to_top, const int obj_layer_nr, const int support_roof_layers_below, const bool to_buildplate, SupportNode* parent,
|
||||||
|
coordf_t print_z_, coordf_t height_, coordf_t dist_mm_to_top_ = 0, coordf_t radius_ = 0)
|
||||||
|
: distance_to_top(distance_to_top)
|
||||||
|
, position(position)
|
||||||
|
, obj_layer_nr(obj_layer_nr)
|
||||||
|
, support_roof_layers_below(support_roof_layers_below)
|
||||||
|
, to_buildplate(to_buildplate)
|
||||||
|
, parent(parent)
|
||||||
|
, print_z(print_z_)
|
||||||
|
, height(height_)
|
||||||
|
, dist_mm_to_top(dist_mm_to_top_)
|
||||||
|
, radius(radius_)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
if (radius == 0 && parent->radius>0)
|
||||||
|
radius = parent->radius + (dist_mm_to_top - parent->dist_mm_to_top) * diameter_angle_scale_factor;
|
||||||
|
parent->child = this;
|
||||||
|
for (auto& neighbor : parent->merged_neighbours) {
|
||||||
|
neighbor->child = this;
|
||||||
|
parents.push_back(neighbor);
|
||||||
|
}
|
||||||
|
is_sharp_tail = parent->is_sharp_tail;
|
||||||
|
skin_direction = parent->skin_direction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG // Clear the delete node's data so if there's invalid access after, we may get a clue by inspecting that node.
|
||||||
|
~SupportNode()
|
||||||
|
{
|
||||||
|
parent = nullptr;
|
||||||
|
merged_neighbours.clear();
|
||||||
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief The number of layers to go to the top of this branch.
|
||||||
|
* Negative value means it's a virtual node between support and overhang, which doesn't need to be extruded.
|
||||||
|
*/
|
||||||
|
int distance_to_top;
|
||||||
|
coordf_t dist_mm_to_top = 0; // dist to bottom contact in mm
|
||||||
|
|
||||||
|
// all nodes will have same diameter_angle_scale_factor because it's defined by user
|
||||||
|
static double diameter_angle_scale_factor;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief The position of this node on the layer.
|
||||||
|
*/
|
||||||
|
Point position;
|
||||||
|
Point movement; // movement towards neighbor center or outline
|
||||||
|
mutable double radius = 0.0;
|
||||||
|
mutable double max_move_dist = 0.0;
|
||||||
|
TreeNodeType type = eCircle;
|
||||||
|
bool is_corner = false;
|
||||||
|
bool is_processed = false;
|
||||||
|
bool need_extra_wall = false;
|
||||||
|
bool is_sharp_tail = false;
|
||||||
|
bool valid = true;
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* This determines in which direction we should reduce the width of the
|
||||||
|
* branch.
|
||||||
|
*/
|
||||||
|
Point skin_direction;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief The number of support roof layers below this one.
|
||||||
|
*
|
||||||
|
* When a contact point is created, it is determined whether the mesh
|
||||||
|
* needs to be supported with support roof or not, since that is a
|
||||||
|
* per-mesh setting. This is stored in this variable in order to track
|
||||||
|
* how far we need to extend that support roof downwards.
|
||||||
|
*/
|
||||||
|
int support_roof_layers_below;
|
||||||
|
int obj_layer_nr;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Whether to try to go towards the build plate.
|
||||||
|
*
|
||||||
|
* If the node is inside the collision areas, it has no choice but to go
|
||||||
|
* towards the model. If it is not inside the collision areas, it must
|
||||||
|
* go towards the build plate to prevent a scar on the surface.
|
||||||
|
*/
|
||||||
|
bool to_buildplate;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief The originating node for this one, one layer higher.
|
||||||
|
*
|
||||||
|
* In order to prune branches that can't have any support (because they
|
||||||
|
* can't be on the model and the path to the buildplate isn't clear),
|
||||||
|
* the entire branch needs to be known.
|
||||||
|
*/
|
||||||
|
SupportNode* parent;
|
||||||
|
std::vector<SupportNode*> parents;
|
||||||
|
SupportNode* child = nullptr;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief All neighbours (on the same layer) that where merged into this node.
|
||||||
|
*
|
||||||
|
* In order to prune branches that can't have any support (because they
|
||||||
|
* can't be on the model and the path to the buildplate isn't clear),
|
||||||
|
* the entire branch needs to be known.
|
||||||
|
*/
|
||||||
|
std::list<SupportNode*> merged_neighbours;
|
||||||
|
|
||||||
|
coordf_t print_z;
|
||||||
|
coordf_t height;
|
||||||
|
|
||||||
|
bool operator==(const SupportNode& other) const
|
||||||
|
{
|
||||||
|
return position == other.position;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,12 +197,12 @@ public:
|
||||||
*
|
*
|
||||||
* \param xy_distance The required clearance between the model and the
|
* \param xy_distance The required clearance between the model and the
|
||||||
* tree branches.
|
* tree branches.
|
||||||
* \param max_move The maximum allowable movement between nodes on
|
|
||||||
* adjacent layers
|
|
||||||
* \param radius_sample_resolution Sample size used to round requested node radii.
|
* \param radius_sample_resolution Sample size used to round requested node radii.
|
||||||
* \param collision_resolution
|
|
||||||
*/
|
*/
|
||||||
TreeSupportData(const PrintObject& object, coordf_t max_move, coordf_t radius_sample_resolution, coordf_t collision_resolution);
|
TreeSupportData(const PrintObject& object, coordf_t xy_distance, coordf_t radius_sample_resolution);
|
||||||
|
~TreeSupportData() {
|
||||||
|
clear_nodes();
|
||||||
|
}
|
||||||
|
|
||||||
TreeSupportData(TreeSupportData&&) = default;
|
TreeSupportData(TreeSupportData&&) = default;
|
||||||
TreeSupportData& operator=(TreeSupportData&&) = default;
|
TreeSupportData& operator=(TreeSupportData&&) = default;
|
||||||
|
@ -98,9 +241,13 @@ public:
|
||||||
Polygons get_contours(size_t layer_nr) const;
|
Polygons get_contours(size_t layer_nr) const;
|
||||||
Polygons get_contours_with_holes(size_t layer_nr) const;
|
Polygons get_contours_with_holes(size_t layer_nr) const;
|
||||||
|
|
||||||
|
SupportNode* create_node(const Point position, const int distance_to_top, const int obj_layer_nr, const int support_roof_layers_below, const bool to_buildplate, SupportNode* parent,
|
||||||
|
coordf_t print_z_, coordf_t height_, coordf_t dist_mm_to_top_ = 0, coordf_t radius_ = 0);
|
||||||
|
void clear_nodes();
|
||||||
std::vector<LayerHeightData> layer_heights;
|
std::vector<LayerHeightData> layer_heights;
|
||||||
|
|
||||||
std::vector<TreeNode> tree_nodes;
|
std::vector<std::unique_ptr<SupportNode>> contact_nodes;
|
||||||
|
// ExPolygon m_machine_border;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*!
|
/*!
|
||||||
|
@ -110,7 +257,7 @@ private:
|
||||||
coordf_t radius;
|
coordf_t radius;
|
||||||
size_t layer_nr;
|
size_t layer_nr;
|
||||||
int recursions;
|
int recursions;
|
||||||
|
|
||||||
};
|
};
|
||||||
struct RadiusLayerPairEquality {
|
struct RadiusLayerPairEquality {
|
||||||
constexpr bool operator()(const RadiusLayerPair& _Left, const RadiusLayerPair& _Right) const {
|
constexpr bool operator()(const RadiusLayerPair& _Left, const RadiusLayerPair& _Right) const {
|
||||||
|
@ -146,6 +293,7 @@ private:
|
||||||
*/
|
*/
|
||||||
const ExPolygons& calculate_avoidance(const RadiusLayerPair& key) const;
|
const ExPolygons& calculate_avoidance(const RadiusLayerPair& key) const;
|
||||||
|
|
||||||
|
tbb::spin_mutex m_mutex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool is_slim = false;
|
bool is_slim = false;
|
||||||
|
@ -154,11 +302,7 @@ public:
|
||||||
*/
|
*/
|
||||||
coordf_t m_xy_distance;
|
coordf_t m_xy_distance;
|
||||||
|
|
||||||
/*!
|
double branch_scale_factor = 1.0; // tan(45 degrees)
|
||||||
* \brief The maximum distance that the centrepoint of a tree branch may
|
|
||||||
* move in consequtive layers
|
|
||||||
*/
|
|
||||||
coordf_t m_max_move;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Sample resolution for radius values.
|
* \brief Sample resolution for radius values.
|
||||||
|
@ -177,6 +321,8 @@ public:
|
||||||
// union contours of all layers below
|
// union contours of all layers below
|
||||||
std::vector<ExPolygons> m_layer_outlines_below;
|
std::vector<ExPolygons> m_layer_outlines_below;
|
||||||
|
|
||||||
|
std::vector<double> m_max_move_distances;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Caches for the collision, avoidance and internal model polygons
|
* \brief Caches for the collision, avoidance and internal model polygons
|
||||||
* at given radius and layer indices.
|
* at given radius and layer indices.
|
||||||
|
@ -185,7 +331,7 @@ public:
|
||||||
* generally considered OK as the functions are still logically const
|
* generally considered OK as the functions are still logically const
|
||||||
* (ie there is no difference in behaviour for the user betweeen
|
* (ie there is no difference in behaviour for the user betweeen
|
||||||
* calculating the values each time vs caching the results).
|
* calculating the values each time vs caching the results).
|
||||||
*
|
*
|
||||||
* coconut: previously stl::unordered_map is used which seems problematic with tbb::parallel_for.
|
* coconut: previously stl::unordered_map is used which seems problematic with tbb::parallel_for.
|
||||||
* So we change to tbb::concurrent_unordered_map
|
* So we change to tbb::concurrent_unordered_map
|
||||||
*/
|
*/
|
||||||
|
@ -215,6 +361,10 @@ public:
|
||||||
*/
|
*/
|
||||||
TreeSupport(PrintObject& object, const SlicingParameters &slicing_params);
|
TreeSupport(PrintObject& object, const SlicingParameters &slicing_params);
|
||||||
|
|
||||||
|
void move_bounds_to_contact_nodes(std::vector<TreeSupport3D::SupportElements> &move_bounds,
|
||||||
|
PrintObject &print_object,
|
||||||
|
const TreeSupport3D::TreeSupportSettings &config);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Create the areas that need support.
|
* \brief Create the areas that need support.
|
||||||
*
|
*
|
||||||
|
@ -224,180 +374,28 @@ public:
|
||||||
*/
|
*/
|
||||||
void generate();
|
void generate();
|
||||||
|
|
||||||
void detect_overhangs(bool detect_first_sharp_tail_only=false);
|
void detect_overhangs(bool check_support_necessity = false);
|
||||||
|
|
||||||
enum NodeType {
|
SupportNode* create_node(const Point position,
|
||||||
eCircle,
|
const int distance_to_top,
|
||||||
eSquare,
|
const int obj_layer_nr,
|
||||||
ePolygon
|
const int support_roof_layers_below,
|
||||||
};
|
const bool to_buildplate,
|
||||||
|
SupportNode* parent,
|
||||||
/*!
|
coordf_t print_z_,
|
||||||
* \brief Represents the metadata of a node in the tree.
|
coordf_t height_,
|
||||||
*/
|
coordf_t dist_mm_to_top_ = 0,
|
||||||
struct Node
|
coordf_t radius_ = 0)
|
||||||
{
|
{
|
||||||
static constexpr Node* NO_PARENT = nullptr;
|
return m_ts_data->create_node(position, distance_to_top, obj_layer_nr, support_roof_layers_below, to_buildplate, parent, print_z_, height_, dist_mm_to_top_, radius_);
|
||||||
|
}
|
||||||
Node()
|
|
||||||
: distance_to_top(0)
|
|
||||||
, 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)
|
|
||||||
, height(0.0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
// when dist_mm_to_top_==0, new node's dist_mm_to_top=parent->dist_mm_to_top + parent->height;
|
|
||||||
Node(const Point position, const int distance_to_top, const int obj_layer_nr, const int support_roof_layers_below, const bool to_buildplate, Node* parent,
|
|
||||||
coordf_t print_z_, coordf_t height_, coordf_t dist_mm_to_top_=0)
|
|
||||||
: distance_to_top(distance_to_top)
|
|
||||||
, 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_)
|
|
||||||
, height(height_)
|
|
||||||
, dist_mm_to_top(dist_mm_to_top_)
|
|
||||||
{
|
|
||||||
if (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)
|
|
||||||
neighbor->child = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG // Clear the delete node's data so if there's invalid access after, we may get a clue by inspecting that node.
|
|
||||||
~Node()
|
|
||||||
{
|
|
||||||
parent = nullptr;
|
|
||||||
merged_neighbours.clear();
|
|
||||||
}
|
|
||||||
#endif // DEBUG
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The number of layers to go to the top of this branch.
|
|
||||||
* Negative value means it's a virtual node between support and overhang, which doesn't need to be extruded.
|
|
||||||
*/
|
|
||||||
int distance_to_top;
|
|
||||||
coordf_t dist_mm_to_top = 0; // dist to bottom contact in mm
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The position of this node on the layer.
|
|
||||||
*/
|
|
||||||
Point position;
|
|
||||||
Point movement; // movement towards neighbor center or outline
|
|
||||||
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
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The direction of the skin lines above the tip of the branch.
|
|
||||||
*
|
|
||||||
* This determines in which direction we should reduce the width of the
|
|
||||||
* branch.
|
|
||||||
*/
|
|
||||||
bool skin_direction;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The number of support roof layers below this one.
|
|
||||||
*
|
|
||||||
* When a contact point is created, it is determined whether the mesh
|
|
||||||
* needs to be supported with support roof or not, since that is a
|
|
||||||
* per-mesh setting. This is stored in this variable in order to track
|
|
||||||
* how far we need to extend that support roof downwards.
|
|
||||||
*/
|
|
||||||
int support_roof_layers_below;
|
|
||||||
int support_floor_layers_above;
|
|
||||||
int obj_layer_nr;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Whether to try to go towards the build plate.
|
|
||||||
*
|
|
||||||
* If the node is inside the collision areas, it has no choice but to go
|
|
||||||
* towards the model. If it is not inside the collision areas, it must
|
|
||||||
* go towards the build plate to prevent a scar on the surface.
|
|
||||||
*/
|
|
||||||
bool to_buildplate;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The originating node for this one, one layer higher.
|
|
||||||
*
|
|
||||||
* In order to prune branches that can't have any support (because they
|
|
||||||
* can't be on the model and the path to the buildplate isn't clear),
|
|
||||||
* the entire branch needs to be known.
|
|
||||||
*/
|
|
||||||
Node *parent;
|
|
||||||
Node *child = nullptr;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief All neighbours (on the same layer) that where merged into this node.
|
|
||||||
*
|
|
||||||
* In order to prune branches that can't have any support (because they
|
|
||||||
* can't be on the model and the path to the buildplate isn't clear),
|
|
||||||
* the entire branch needs to be known.
|
|
||||||
*/
|
|
||||||
std::list<Node*> merged_neighbours;
|
|
||||||
|
|
||||||
coordf_t print_z;
|
|
||||||
coordf_t height;
|
|
||||||
|
|
||||||
bool operator==(const Node& other) const
|
|
||||||
{
|
|
||||||
return position == other.position;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SupportParams
|
|
||||||
{
|
|
||||||
Flow first_layer_flow;
|
|
||||||
Flow support_material_flow;
|
|
||||||
Flow support_material_interface_flow;
|
|
||||||
Flow support_material_bottom_interface_flow;
|
|
||||||
coordf_t support_extrusion_width;
|
|
||||||
// Is merging of regions allowed? Could the interface & base support regions be printed with the same extruder?
|
|
||||||
bool can_merge_support_regions;
|
|
||||||
|
|
||||||
coordf_t support_layer_height_min;
|
|
||||||
// coordf_t support_layer_height_max;
|
|
||||||
|
|
||||||
coordf_t gap_xy;
|
|
||||||
|
|
||||||
float base_angle;
|
|
||||||
float interface_angle;
|
|
||||||
coordf_t interface_spacing;
|
|
||||||
coordf_t interface_density;
|
|
||||||
coordf_t support_spacing;
|
|
||||||
coordf_t support_density;
|
|
||||||
|
|
||||||
InfillPattern base_fill_pattern;
|
|
||||||
InfillPattern interface_fill_pattern;
|
|
||||||
InfillPattern contact_fill_pattern;
|
|
||||||
bool with_sheath;
|
|
||||||
const double thresh_big_overhang = SQ(scale_(10));
|
|
||||||
};
|
|
||||||
|
|
||||||
int avg_node_per_layer = 0;
|
int avg_node_per_layer = 0;
|
||||||
float nodes_angle = 0;
|
float nodes_angle = 0;
|
||||||
bool has_overhangs = false;
|
|
||||||
bool has_sharp_tails = false;
|
bool has_sharp_tails = false;
|
||||||
bool has_cantilever = false;
|
bool has_cantilever = false;
|
||||||
double max_cantilever_dist = 0;
|
double max_cantilever_dist = 0;
|
||||||
SupportType support_type;
|
SupportType support_type;
|
||||||
SupportMaterialStyle support_style;
|
|
||||||
|
|
||||||
std::unique_ptr<FillLightning::Generator> generator;
|
std::unique_ptr<FillLightning::Generator> generator;
|
||||||
std::unordered_map<double, size_t> printZ_to_lightninglayer;
|
std::unordered_map<double, size_t> printZ_to_lightninglayer;
|
||||||
|
@ -410,6 +408,10 @@ public:
|
||||||
*/
|
*/
|
||||||
ExPolygon m_machine_border;
|
ExPolygon m_machine_border;
|
||||||
|
|
||||||
|
enum OverhangType { Detected = 0, Enforced, SharpTail };
|
||||||
|
std::map<const ExPolygon*, OverhangType> overhang_types;
|
||||||
|
std::vector<std::pair<Vec3f, Vec3f>> m_vertical_enforcer_points;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*!
|
/*!
|
||||||
* \brief Generator for model collision, avoidance and internal guide volumes
|
* \brief Generator for model collision, avoidance and internal guide volumes
|
||||||
|
@ -417,20 +419,29 @@ private:
|
||||||
* Lazily computes volumes as needed.
|
* Lazily computes volumes as needed.
|
||||||
* \warning This class is NOT currently thread-safe and should not be accessed in OpenMP blocks
|
* \warning This class is NOT currently thread-safe and should not be accessed in OpenMP blocks
|
||||||
*/
|
*/
|
||||||
|
std::vector<std::vector<SupportNode*>> contact_nodes;
|
||||||
std::shared_ptr<TreeSupportData> m_ts_data;
|
std::shared_ptr<TreeSupportData> m_ts_data;
|
||||||
|
std::unique_ptr<TreeSupport3D::TreeModelVolumes> m_model_volumes;
|
||||||
PrintObject *m_object;
|
PrintObject *m_object;
|
||||||
const PrintObjectConfig *m_object_config;
|
const PrintObjectConfig* m_object_config;
|
||||||
SlicingParameters m_slicing_params;
|
SlicingParameters m_slicing_params;
|
||||||
// Various precomputed support parameters to be shared with external functions.
|
// Various precomputed support parameters to be shared with external functions.
|
||||||
SupportParams m_support_params;
|
SupportParameters m_support_params;
|
||||||
size_t m_raft_layers = 0;
|
size_t m_raft_layers = 0; // number of raft layers, including raft base, raft interface, raft gap
|
||||||
size_t m_highest_overhang_layer = 0;
|
size_t m_highest_overhang_layer = 0;
|
||||||
std::vector<std::vector<MinimumSpanningTree>> m_spanning_trees;
|
std::vector<std::vector<MinimumSpanningTree>> m_spanning_trees;
|
||||||
std::vector< std::unordered_map<Line, bool, LineHash>> m_mst_line_x_layer_contour_caches;
|
std::vector< std::unordered_map<Line, bool, LineHash>> m_mst_line_x_layer_contour_caches;
|
||||||
coordf_t MAX_BRANCH_RADIUS = 10.0;
|
float DO_NOT_MOVER_UNDER_MM = 0.0;
|
||||||
coordf_t MAX_BRANCH_RADIUS_FIRST_LAYER = 12.0;
|
coordf_t base_radius = 0.0;
|
||||||
coordf_t MIN_BRANCH_RADIUS = 0.5;
|
const coordf_t MAX_BRANCH_RADIUS = 10.0;
|
||||||
float tree_support_branch_diameter_angle = 5.0;
|
const coordf_t MIN_BRANCH_RADIUS = 0.4;
|
||||||
|
const coordf_t MAX_BRANCH_RADIUS_FIRST_LAYER = 12.0;
|
||||||
|
const coordf_t MIN_BRANCH_RADIUS_FIRST_LAYER = 2.0;
|
||||||
|
double diameter_angle_scale_factor = tan(5.0*M_PI/180.0);
|
||||||
|
// minimum roof area (1 mm^2), area smaller than this value will not have interface
|
||||||
|
const double minimum_roof_area{SQ(scaled<double>(1.))};
|
||||||
|
float top_z_distance = 0.0;
|
||||||
|
|
||||||
bool is_strong = false;
|
bool is_strong = false;
|
||||||
bool is_slim = false;
|
bool is_slim = false;
|
||||||
bool with_infill = false;
|
bool with_infill = false;
|
||||||
|
@ -447,7 +458,7 @@ private:
|
||||||
* save the resulting support polygons to.
|
* save the resulting support polygons to.
|
||||||
* \param contact_nodes The nodes to draw as support.
|
* \param contact_nodes The nodes to draw as support.
|
||||||
*/
|
*/
|
||||||
void draw_circles(const std::vector<std::vector<Node*>>& contact_nodes);
|
void draw_circles();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Drops down the nodes of the tree support towards the build plate.
|
* \brief Drops down the nodes of the tree support towards the build plate.
|
||||||
|
@ -461,18 +472,16 @@ private:
|
||||||
* dropped down. The nodes are dropped to lower layers inside the same
|
* dropped down. The nodes are dropped to lower layers inside the same
|
||||||
* vector of layers.
|
* vector of layers.
|
||||||
*/
|
*/
|
||||||
void drop_nodes(std::vector<std::vector<Node *>> &contact_nodes);
|
void drop_nodes();
|
||||||
|
|
||||||
void smooth_nodes(std::vector<std::vector<Node *>> &contact_nodes);
|
void smooth_nodes();
|
||||||
|
|
||||||
void adjust_layer_heights(std::vector<std::vector<Node*>>& contact_nodes);
|
|
||||||
|
|
||||||
/*! BBS: MusangKing: maximum layer height
|
/*! BBS: MusangKing: maximum layer height
|
||||||
* \brief Optimize the generation of tree support by pre-planning the layer_heights
|
* \brief Optimize the generation of tree support by pre-planning the layer_heights
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
std::vector<LayerHeightData> plan_layer_heights(std::vector<std::vector<Node *>> &contact_nodes);
|
std::vector<LayerHeightData> plan_layer_heights();
|
||||||
/*!
|
/*!
|
||||||
* \brief Creates points where support contacts the model.
|
* \brief Creates points where support contacts the model.
|
||||||
*
|
*
|
||||||
|
@ -486,20 +495,27 @@ private:
|
||||||
* \return For each layer, a list of points where the tree should connect
|
* \return For each layer, a list of points where the tree should connect
|
||||||
* with the model.
|
* with the model.
|
||||||
*/
|
*/
|
||||||
void generate_contact_points(std::vector<std::vector<Node*>>& contact_nodes);
|
void generate_contact_points();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Add a node to the next layer.
|
* \brief Add a node to the next layer.
|
||||||
*
|
*
|
||||||
* If a node is already at that position in the layer, the nodes are merged.
|
* If a node is already at that position in the layer, the nodes are merged.
|
||||||
*/
|
*/
|
||||||
void insert_dropped_node(std::vector<Node*>& nodes_layer, Node* node);
|
void insert_dropped_node(std::vector<SupportNode*>& nodes_layer, SupportNode* node);
|
||||||
void create_tree_support_layers();
|
void create_tree_support_layers();
|
||||||
void generate_toolpaths();
|
void generate_toolpaths();
|
||||||
Polygons spanning_tree_to_polygon(const std::vector<MinimumSpanningTree>& spanning_trees, Polygons layer_contours, int layer_nr);
|
// get unscaled radius of node
|
||||||
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);
|
|
||||||
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, 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);
|
// get unscaled radius(mm) of node based on the distance mm to top
|
||||||
|
coordf_t calc_branch_radius(coordf_t base_radius, coordf_t mm_to_top, double diameter_angle_scale_factor, bool use_min_distance=true);
|
||||||
|
coordf_t calc_radius(coordf_t mm_to_top);
|
||||||
|
coordf_t get_radius(const SupportNode* node);
|
||||||
|
ExPolygons get_avoidance(coordf_t radius, size_t obj_layer_nr);
|
||||||
|
// layer's expolygon expanded by radius+m_xy_distance
|
||||||
|
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
|
// similar to SupportMaterial::trim_support_layers_by_object
|
||||||
Polygons get_trim_support_regions(
|
Polygons get_trim_support_regions(
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -47,8 +47,6 @@ struct SlicingParameters;
|
||||||
namespace TreeSupport3D
|
namespace TreeSupport3D
|
||||||
{
|
{
|
||||||
|
|
||||||
// The number of vertices in each circle.
|
|
||||||
static constexpr const size_t SUPPORT_TREE_CIRCLE_RESOLUTION = 25;
|
|
||||||
|
|
||||||
struct AreaIncreaseSettings
|
struct AreaIncreaseSettings
|
||||||
{
|
{
|
||||||
|
@ -139,6 +137,10 @@ struct SupportElementStateBits {
|
||||||
|
|
||||||
struct SupportElementState : public SupportElementStateBits
|
struct SupportElementState : public SupportElementStateBits
|
||||||
{
|
{
|
||||||
|
int type = 0;
|
||||||
|
coordf_t radius = 0;
|
||||||
|
float print_z = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief The layer this support elements wants reach
|
* \brief The layer this support elements wants reach
|
||||||
*/
|
*/
|
||||||
|
@ -306,7 +308,7 @@ void organic_draw_branches(
|
||||||
SupportGeneratorLayersPtr &intermediate_layers,
|
SupportGeneratorLayersPtr &intermediate_layers,
|
||||||
SupportGeneratorLayerStorage &layer_storage,
|
SupportGeneratorLayerStorage &layer_storage,
|
||||||
|
|
||||||
std::function<void()> throw_on_cancel);
|
std::function<void()> throw_on_cancel);
|
||||||
|
|
||||||
} // namespace TreeSupport3D
|
} // namespace TreeSupport3D
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
|
|
||||||
namespace Slic3r
|
namespace Slic3r
|
||||||
{
|
{
|
||||||
|
// The number of vertices in each circle.
|
||||||
|
static constexpr const size_t SUPPORT_TREE_CIRCLE_RESOLUTION = 25;
|
||||||
namespace TreeSupport3D
|
namespace TreeSupport3D
|
||||||
{
|
{
|
||||||
|
|
||||||
using LayerIndex = int;
|
using LayerIndex = int;
|
||||||
|
|
||||||
enum class InterfacePreference
|
enum class InterfacePreference
|
||||||
|
@ -40,18 +40,18 @@ struct TreeSupportMeshGroupSettings {
|
||||||
const PrintObjectConfig &config = print_object.config();
|
const PrintObjectConfig &config = print_object.config();
|
||||||
const SlicingParameters &slicing_params = print_object.slicing_parameters();
|
const SlicingParameters &slicing_params = print_object.slicing_parameters();
|
||||||
// const std::vector<unsigned int> printing_extruders = print_object.object_extruders();
|
// const std::vector<unsigned int> printing_extruders = print_object.object_extruders();
|
||||||
|
|
||||||
// Support must be enabled and set to Tree style.
|
// Support must be enabled and set to Tree style.
|
||||||
assert(config.enable_support || config.enforce_support_layers > 0);
|
//assert(config.support_material);
|
||||||
assert(is_tree(config.support_type));
|
//assert(config.support_material_style == smsTree || config.support_material_style == smsOrganic);
|
||||||
|
|
||||||
// Calculate maximum external perimeter width over all printing regions, taking into account the default layer height.
|
// Calculate maximum external perimeter width over all printing regions, taking into account the default layer height.
|
||||||
coordf_t external_perimeter_width = 0.;
|
coordf_t external_perimeter_width = 0.;
|
||||||
for (size_t region_id = 0; region_id < print_object.num_printing_regions(); ++ region_id) {
|
for (size_t region_id = 0; region_id < print_object.num_printing_regions(); ++ region_id) {
|
||||||
const PrintRegion ®ion = print_object.printing_region(region_id);
|
const PrintRegion ®ion = print_object.printing_region(region_id);
|
||||||
external_perimeter_width = std::max<coordf_t>(external_perimeter_width, region.flow(print_object, frExternalPerimeter, config.layer_height).width());
|
external_perimeter_width = std::max<coordf_t>(external_perimeter_width, region.flow(print_object, frExternalPerimeter, config.layer_height).width());
|
||||||
}
|
}
|
||||||
|
|
||||||
this->layer_height = scaled<coord_t>(config.layer_height.value);
|
this->layer_height = scaled<coord_t>(config.layer_height.value);
|
||||||
this->resolution = scaled<coord_t>(print_config.resolution.value);
|
this->resolution = scaled<coord_t>(print_config.resolution.value);
|
||||||
// Arache feature
|
// Arache feature
|
||||||
|
@ -69,56 +69,28 @@ struct TreeSupportMeshGroupSettings {
|
||||||
0;
|
0;
|
||||||
this->support_material_buildplate_only = config.support_on_build_plate_only;
|
this->support_material_buildplate_only = config.support_on_build_plate_only;
|
||||||
this->support_xy_distance = scaled<coord_t>(config.support_object_xy_distance.value);
|
this->support_xy_distance = scaled<coord_t>(config.support_object_xy_distance.value);
|
||||||
|
this->support_xy_distance_1st_layer = scaled<coord_t>(config.support_object_first_layer_gap.value);
|
||||||
// Separation of interfaces, it is likely smaller than support_xy_distance.
|
// Separation of interfaces, it is likely smaller than support_xy_distance.
|
||||||
this->support_xy_distance_overhang = std::min(this->support_xy_distance, scaled<coord_t>(0.5 * external_perimeter_width));
|
this->support_xy_distance_overhang = std::min(this->support_xy_distance, scaled<coord_t>(0.5 * external_perimeter_width));
|
||||||
this->support_top_distance = scaled<coord_t>(slicing_params.gap_support_object);
|
this->support_top_distance = scaled<coord_t>(slicing_params.gap_support_object);
|
||||||
this->support_bottom_distance = scaled<coord_t>(slicing_params.gap_object_support);
|
this->support_bottom_distance = scaled<coord_t>(slicing_params.gap_object_support);
|
||||||
// this->support_interface_skip_height =
|
|
||||||
// this->support_infill_angles =
|
|
||||||
this->support_roof_enable = config.support_interface_top_layers.value > 0;
|
this->support_roof_enable = config.support_interface_top_layers.value > 0;
|
||||||
this->support_roof_layers = this->support_roof_enable ? config.support_interface_top_layers.value : 0;
|
this->support_roof_layers = config.support_interface_top_layers.value;
|
||||||
this->support_floor_enable = config.support_interface_top_layers.value > 0 && config.support_interface_bottom_layers.value > 0;
|
this->support_floor_enable = config.support_interface_bottom_layers.value > 0;
|
||||||
this->support_floor_layers = this->support_floor_enable ? config.support_interface_bottom_layers.value : 0;
|
this->support_floor_layers = config.support_interface_bottom_layers.value;
|
||||||
// this->minimum_roof_area =
|
|
||||||
// this->support_roof_angles =
|
|
||||||
this->support_roof_pattern = config.support_interface_pattern;
|
this->support_roof_pattern = config.support_interface_pattern;
|
||||||
this->support_pattern = config.support_base_pattern;
|
this->support_pattern = config.support_base_pattern;
|
||||||
this->support_line_spacing = scaled<coord_t>(config.support_base_pattern_spacing.value);
|
this->support_line_spacing = scaled<coord_t>(config.support_base_pattern_spacing.value);
|
||||||
// this->support_bottom_offset =
|
this->support_wall_count = std::max(1, config.tree_support_wall_count.value); // at least 1 wall for organic tree support
|
||||||
// this->support_wall_count = config.support_material_with_sheath ? 1 : 0;
|
|
||||||
this->support_wall_count = 1;
|
|
||||||
this->support_roof_line_distance = scaled<coord_t>(config.support_interface_spacing.value) + this->support_roof_line_width;
|
this->support_roof_line_distance = scaled<coord_t>(config.support_interface_spacing.value) + this->support_roof_line_width;
|
||||||
// this->minimum_support_area =
|
|
||||||
// this->minimum_bottom_area =
|
|
||||||
// this->support_offset =
|
|
||||||
this->support_tree_branch_distance = scaled<coord_t>(config.tree_support_branch_distance_organic.value);
|
this->support_tree_branch_distance = scaled<coord_t>(config.tree_support_branch_distance_organic.value);
|
||||||
this->support_tree_angle = std::clamp<double>(config.tree_support_branch_angle_organic * M_PI / 180., 0., 0.5 * M_PI - EPSILON);
|
this->support_tree_angle = std::clamp<double>(config.tree_support_branch_angle_organic * M_PI / 180., 0., 0.5 * M_PI - EPSILON);
|
||||||
this->support_tree_angle_slow = std::clamp<double>(config.tree_support_angle_slow * M_PI / 180., 0., this->support_tree_angle - EPSILON);
|
this->support_tree_angle_slow = std::clamp<double>(config.tree_support_angle_slow * M_PI / 180., 0., this->support_tree_angle - EPSILON);
|
||||||
this->support_tree_branch_diameter = scaled<coord_t>(config.tree_support_branch_diameter_organic.value);
|
this->support_tree_branch_diameter = scaled<coord_t>(config.tree_support_branch_diameter_organic.value);
|
||||||
this->support_tree_branch_diameter_angle = std::clamp<double>(config.tree_support_branch_diameter_angle * M_PI / 180., 0., 0.5 * M_PI - EPSILON);
|
this->support_tree_branch_diameter_angle = std::clamp<double>(config.tree_support_branch_diameter_angle * M_PI / 180., 0., 0.5 * M_PI - EPSILON);
|
||||||
this->support_tree_top_rate = config.tree_support_top_rate.value; // percent
|
this->support_tree_top_rate = config.tree_support_top_rate.value; // percent
|
||||||
// this->support_tree_tip_diameter = this->support_line_width;
|
// this->support_tree_tip_diameter = this->support_line_width;
|
||||||
this->support_tree_tip_diameter = std::clamp(scaled<coord_t>(config.tree_support_tip_diameter.value), (coord_t)0, this->support_tree_branch_diameter);
|
this->support_tree_tip_diameter = std::clamp(scaled<coord_t>(config.tree_support_tip_diameter.value), (coord_t)0, this->support_tree_branch_diameter);
|
||||||
|
|
||||||
std::cout << "\n---------------\n"
|
|
||||||
<< "layer_height: " << layer_height << "\nresolution: " << resolution << "\nmin_feature_size: " << min_feature_size
|
|
||||||
<< "\nsupport_angle: " << support_angle << "\nconfig.support_threshold_angle: " << config.support_threshold_angle << "\nsupport_line_width: " << support_line_width
|
|
||||||
<< "\nsupport_roof_line_width: " << support_roof_line_width << "\nsupport_bottom_enable: " << support_bottom_enable
|
|
||||||
<< "\nsupport_bottom_height: " << support_bottom_height
|
|
||||||
<< "\nsupport_material_buildplate_only: " << support_material_buildplate_only
|
|
||||||
<< "\nsupport_xy_distance: " << support_xy_distance << "\nsupport_xy_distance_overhang: " << support_xy_distance_overhang
|
|
||||||
<< "\nsupport_top_distance: " << support_top_distance << "\nsupport_bottom_distance: " << support_bottom_distance
|
|
||||||
<< "\nsupport_roof_enable: " << support_roof_enable << "\nsupport_roof_layers: " << support_roof_layers
|
|
||||||
<< "\nsupport_floor_enable: " << support_floor_enable << "\nsupport_floor_layers: " << support_floor_layers
|
|
||||||
<< "\nsupport_roof_pattern: " << support_roof_pattern << "\nsupport_pattern: " << support_pattern
|
|
||||||
<< "\nsupport_line_spacing: " << support_line_spacing << "\nsupport_wall_count: " << support_wall_count
|
|
||||||
<< "\nsupport_roof_line_distance: " << support_roof_line_distance
|
|
||||||
<< "\nsupport_tree_branch_distance: " << support_tree_branch_distance
|
|
||||||
<< "\nsupport_tree_angle_slow: " << support_tree_angle_slow
|
|
||||||
<< "\nsupport_tree_branch_diameter: " << support_tree_branch_diameter
|
|
||||||
<< "\nsupport_tree_branch_diameter_angle: " << support_tree_branch_diameter_angle
|
|
||||||
<< "\nsupport_tree_top_rate: " << support_tree_top_rate << "\nsupport_tree_tip_diameter: " << support_tree_tip_diameter
|
|
||||||
<< "\n---------------\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
|
@ -158,6 +130,7 @@ struct TreeSupportMeshGroupSettings {
|
||||||
// Distance of the support structure from the print in the X/Y directions.
|
// Distance of the support structure from the print in the X/Y directions.
|
||||||
// minimum: 0, maximum warning: 1.5 * machine_nozzle_tip_outer_diameter
|
// minimum: 0, maximum warning: 1.5 * machine_nozzle_tip_outer_diameter
|
||||||
coord_t support_xy_distance { scaled<coord_t>(0.7) };
|
coord_t support_xy_distance { scaled<coord_t>(0.7) };
|
||||||
|
coord_t support_xy_distance_1st_layer { scaled<coord_t>(0.7) };
|
||||||
// Minimum Support X/Y Distance
|
// Minimum Support X/Y Distance
|
||||||
// Distance of the support structure from the overhang in the X/Y directions.
|
// Distance of the support structure from the overhang in the X/Y directions.
|
||||||
// minimum_value: 0, minimum warning": support_xy_distance - support_line_width * 2, maximum warning: support_xy_distance
|
// minimum_value: 0, minimum warning": support_xy_distance - support_line_width * 2, maximum warning: support_xy_distance
|
||||||
|
@ -766,6 +739,17 @@ private:
|
||||||
std::mutex m_mutex_layer_storage;
|
std::mutex m_mutex_layer_storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class LineStatus
|
||||||
|
{
|
||||||
|
INVALID,
|
||||||
|
TO_MODEL,
|
||||||
|
TO_MODEL_GRACIOUS,
|
||||||
|
TO_MODEL_GRACIOUS_SAFE,
|
||||||
|
TO_BP,
|
||||||
|
TO_BP_SAFE
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace TreeSupport3D
|
} // namespace TreeSupport3D
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -957,7 +957,6 @@ inline std::pair<SlabLines, SlabLines> slice_slabs_make_lines(
|
||||||
}
|
}
|
||||||
slice_facet_with_slabs<true>(vertices, indices, face_idx, neighbors, edge_ids, num_edges, zs, lines_top, lines_mutex_top);
|
slice_facet_with_slabs<true>(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)) {
|
if (bottom && (fo == FaceOrientation::Down || fo == FaceOrientation::Degenerate)) {
|
||||||
Vec3i32 neighbors = face_neighbors[face_idx];
|
Vec3i32 neighbors = face_neighbors[face_idx];
|
||||||
// Reset neighborship of this triangle in case the other triangle is oriented backwards from this one.
|
// 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,
|
const Transform3d &trafo,
|
||||||
std::vector<Polygons> *out_top,
|
std::vector<Polygons> *out_top,
|
||||||
std::vector<Polygons> *out_bottom,
|
std::vector<Polygons> *out_bottom,
|
||||||
|
std::vector<std::pair<Vec3f, Vec3f>> *vertical_points,
|
||||||
std::function<void()> throw_on_cancel)
|
std::function<void()> throw_on_cancel)
|
||||||
{
|
{
|
||||||
BOOST_LOG_TRIVIAL(debug) << "slice_mesh_slabs to polygons";
|
BOOST_LOG_TRIVIAL(debug) << "slice_mesh_slabs to polygons";
|
||||||
|
@ -2133,6 +2133,11 @@ void slice_mesh_slabs(
|
||||||
// Is the triangle vertical or degenerate?
|
// Is the triangle vertical or degenerate?
|
||||||
assert(d == 0);
|
assert(d == 0);
|
||||||
fo = fa == fb || fa == fc || fb == fc ? FaceOrientation::Degenerate : FaceOrientation::Vertical;
|
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;
|
face_orientation[&tri - mesh.indices.data()] = fo;
|
||||||
}
|
}
|
||||||
|
@ -2297,7 +2302,7 @@ void project_mesh(
|
||||||
{
|
{
|
||||||
std::vector<Polygons> top, bottom;
|
std::vector<Polygons> top, bottom;
|
||||||
std::vector<float> zs { -1e10, 1e10 };
|
std::vector<float> 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)
|
if (out_top)
|
||||||
*out_top = std::move(top.front());
|
*out_top = std::move(top.front());
|
||||||
if (out_bottom)
|
if (out_bottom)
|
||||||
|
@ -2311,7 +2316,7 @@ Polygons project_mesh(
|
||||||
{
|
{
|
||||||
std::vector<Polygons> top, bottom;
|
std::vector<Polygons> top, bottom;
|
||||||
std::vector<float> zs { -1e10, 1e10 };
|
std::vector<float> 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());
|
return union_(top.front(), bottom.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,6 +107,7 @@ void slice_mesh_slabs(
|
||||||
const Transform3d &trafo,
|
const Transform3d &trafo,
|
||||||
std::vector<Polygons> *out_top,
|
std::vector<Polygons> *out_top,
|
||||||
std::vector<Polygons> *out_bottom,
|
std::vector<Polygons> *out_bottom,
|
||||||
|
std::vector<std::pair<Vec3f, Vec3f>> *vertical_points,
|
||||||
std::function<void()> throw_on_cancel);
|
std::function<void()> throw_on_cancel);
|
||||||
|
|
||||||
// Project mesh upwards pointing surfaces / downwards pointing surfaces into 2D polygons.
|
// Project mesh upwards pointing surfaces / downwards pointing surfaces into 2D polygons.
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
#include "format.hpp"
|
#include "format.hpp"
|
||||||
#include "Platform.hpp"
|
#include "Platform.hpp"
|
||||||
|
@ -298,12 +299,13 @@ static std::atomic<bool> debug_out_path_called(false);
|
||||||
|
|
||||||
std::string debug_out_path(const char *name, ...)
|
std::string debug_out_path(const char *name, ...)
|
||||||
{
|
{
|
||||||
static constexpr const char *SLIC3R_DEBUG_OUT_PATH_PREFIX = "out/";
|
//static constexpr const char *SLIC3R_DEBUG_OUT_PATH_PREFIX = "out/";
|
||||||
|
auto svg_folder = boost::filesystem::path(g_data_dir) / "SVG/";
|
||||||
if (! debug_out_path_called.exchange(true)) {
|
if (! debug_out_path_called.exchange(true)) {
|
||||||
std::string path = boost::filesystem::system_complete(SLIC3R_DEBUG_OUT_PATH_PREFIX).string();
|
if (!boost::filesystem::exists(svg_folder)) {
|
||||||
if (!boost::filesystem::exists(path)) {
|
boost::filesystem::create_directory(svg_folder);
|
||||||
boost::filesystem::create_directory(path);
|
|
||||||
}
|
}
|
||||||
|
std::string path = boost::filesystem::system_complete(svg_folder).string();
|
||||||
printf("Debugging output files will be written to %s\n", path.c_str());
|
printf("Debugging output files will be written to %s\n", path.c_str());
|
||||||
}
|
}
|
||||||
char buffer[2048];
|
char buffer[2048];
|
||||||
|
@ -311,7 +313,13 @@ std::string debug_out_path(const char *name, ...)
|
||||||
va_start(args, name);
|
va_start(args, name);
|
||||||
std::vsprintf(buffer, name, args);
|
std::vsprintf(buffer, name, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return std::string(SLIC3R_DEBUG_OUT_PATH_PREFIX) + std::string(buffer);
|
|
||||||
|
std::string buf(buffer);
|
||||||
|
if (size_t pos = buf.find_first_of('/'); pos != std::string::npos) {
|
||||||
|
std::string sub_dir = buf.substr(0, pos);
|
||||||
|
std::filesystem::create_directory(svg_folder.string() + sub_dir);
|
||||||
|
}
|
||||||
|
return svg_folder.string() + std::string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace logging = boost::log;
|
namespace logging = boost::log;
|
||||||
|
|
|
@ -426,7 +426,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
||||||
auto support_type = config->opt_enum<SupportType>("support_type");
|
auto support_type = config->opt_enum<SupportType>("support_type");
|
||||||
auto support_style = config->opt_enum<SupportMaterialStyle>("support_style");
|
auto support_style = config->opt_enum<SupportMaterialStyle>("support_style");
|
||||||
std::set<int> enum_set_normal = { smsDefault, smsGrid, smsSnug };
|
std::set<int> enum_set_normal = { smsDefault, smsGrid, smsSnug };
|
||||||
std::set<int> enum_set_tree = { smsDefault, smsTreeSlim, smsTreeStrong, smsTreeHybrid, smsOrganic };
|
std::set<int> enum_set_tree = { smsDefault, smsTreeSlim, smsTreeStrong, smsTreeHybrid, smsTreeOrganic };
|
||||||
auto & set = is_tree(support_type) ? enum_set_tree : enum_set_normal;
|
auto & set = is_tree(support_type) ? enum_set_tree : enum_set_normal;
|
||||||
if (set.find(support_style) == set.end()) {
|
if (set.find(support_style) == set.end()) {
|
||||||
DynamicPrintConfig new_conf = *config;
|
DynamicPrintConfig new_conf = *config;
|
||||||
|
@ -600,14 +600,14 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||||
"support_interface_pattern", "support_interface_top_layers", "support_interface_bottom_layers",
|
"support_interface_pattern", "support_interface_top_layers", "support_interface_bottom_layers",
|
||||||
"bridge_no_support", "max_bridge_length", "support_top_z_distance", "support_bottom_z_distance",
|
"bridge_no_support", "max_bridge_length", "support_top_z_distance", "support_bottom_z_distance",
|
||||||
"support_type", "support_on_build_plate_only", "support_critical_regions_only","support_interface_not_for_body",
|
"support_type", "support_on_build_plate_only", "support_critical_regions_only","support_interface_not_for_body",
|
||||||
"support_object_xy_distance"/*, "independent_support_layer_height"*/})
|
"support_object_xy_distance","support_object_first_layer_gap"/*, "independent_support_layer_height"*/})
|
||||||
toggle_field(el, have_support_material);
|
toggle_field(el, have_support_material);
|
||||||
toggle_field("support_threshold_angle", have_support_material && is_auto(support_type));
|
toggle_field("support_threshold_angle", have_support_material && is_auto(support_type));
|
||||||
toggle_field("support_threshold_overlap", config->opt_int("support_threshold_angle") == 0 && have_support_material && is_auto(support_type));
|
toggle_field("support_threshold_overlap", config->opt_int("support_threshold_angle") == 0 && have_support_material && is_auto(support_type));
|
||||||
//toggle_field("support_closing_radius", have_support_material && support_style == smsSnug);
|
//toggle_field("support_closing_radius", have_support_material && support_style == smsSnug);
|
||||||
|
|
||||||
bool support_is_tree = config->opt_bool("enable_support") && is_tree(support_type);
|
bool support_is_tree = config->opt_bool("enable_support") && is_tree(support_type);
|
||||||
bool support_is_normal_tree = support_is_tree && support_style != smsOrganic &&
|
bool support_is_normal_tree = support_is_tree && support_style != smsTreeOrganic &&
|
||||||
// Orca: use organic as default
|
// Orca: use organic as default
|
||||||
support_style != smsDefault;
|
support_style != smsDefault;
|
||||||
bool support_is_organic = support_is_tree && !support_is_normal_tree;
|
bool support_is_organic = support_is_tree && !support_is_normal_tree;
|
||||||
|
@ -615,10 +615,10 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||||
for (auto el : {"tree_support_branch_angle", "tree_support_branch_distance", "tree_support_branch_diameter" })
|
for (auto el : {"tree_support_branch_angle", "tree_support_branch_distance", "tree_support_branch_diameter" })
|
||||||
toggle_line(el, support_is_normal_tree);
|
toggle_line(el, support_is_normal_tree);
|
||||||
// settings specific to normal trees
|
// settings specific to normal trees
|
||||||
for (auto el : {"tree_support_wall_count", "tree_support_auto_brim", "tree_support_brim_width", "tree_support_adaptive_layer_height"})
|
for (auto el : {"tree_support_auto_brim", "tree_support_brim_width", "tree_support_adaptive_layer_height"})
|
||||||
toggle_line(el, support_is_normal_tree);
|
toggle_line(el, support_is_normal_tree);
|
||||||
// settings specific to organic trees
|
// settings specific to organic trees
|
||||||
for (auto el : {"tree_support_branch_angle_organic", "tree_support_branch_distance_organic", "tree_support_branch_diameter_organic","tree_support_angle_slow","tree_support_tip_diameter", "tree_support_top_rate", "tree_support_branch_diameter_angle", "tree_support_branch_diameter_double_wall"})
|
for (auto el : {"tree_support_branch_angle_organic", "tree_support_branch_distance_organic", "tree_support_branch_diameter_organic","tree_support_angle_slow","tree_support_tip_diameter", "tree_support_top_rate", "tree_support_branch_diameter_angle"})
|
||||||
toggle_line(el, support_is_organic);
|
toggle_line(el, support_is_organic);
|
||||||
|
|
||||||
toggle_field("tree_support_brim_width", support_is_tree && !config->opt_bool("tree_support_auto_brim"));
|
toggle_field("tree_support_brim_width", support_is_tree && !config->opt_bool("tree_support_auto_brim"));
|
||||||
|
|
|
@ -2125,7 +2125,8 @@ bool GUI_App::OnInit()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return on_init_inner();
|
return on_init_inner();
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(fatal) << "OnInit Got Fatal error: " << e.what();
|
||||||
generic_exception_handle();
|
generic_exception_handle();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,10 +90,11 @@ std::map<std::string, std::vector<SimpleSettingData>> SettingsFactory::OBJECT_C
|
||||||
{ L("Support"), {{"brim_type", "",1},{"brim_width", "",2},{"brim_object_gap", "",3},
|
{ L("Support"), {{"brim_type", "",1},{"brim_width", "",2},{"brim_object_gap", "",3},
|
||||||
{"enable_support", "",4},{"support_type", "",5},{"support_threshold_angle", "",6}, {"support_threshold_overlap", "",6}, {"support_on_build_plate_only", "",7},
|
{"enable_support", "",4},{"support_type", "",5},{"support_threshold_angle", "",6}, {"support_threshold_overlap", "",6}, {"support_on_build_plate_only", "",7},
|
||||||
{"support_filament", "",8},{"support_interface_filament", "",9},{"support_expansion", "",24},{"support_style", "",25},
|
{"support_filament", "",8},{"support_interface_filament", "",9},{"support_expansion", "",24},{"support_style", "",25},
|
||||||
{"tree_support_brim_width", "",26}, {"tree_support_branch_angle", "",10},{"tree_support_branch_angle_organic","",10}, {"tree_support_wall_count", "",11},//tree support
|
{"tree_support_brim_width", "",26}, {"tree_support_branch_angle", "",10},{"tree_support_branch_angle_organic","",10}, {"tree_support_wall_count", "",11},{"tree_support_branch_diameter_angle", "",11},//tree support
|
||||||
{"support_top_z_distance", "",13},{"support_bottom_z_distance", "",12},{"support_base_pattern", "",14},{"support_base_pattern_spacing", "",15},
|
{"support_top_z_distance", "",13},{"support_bottom_z_distance", "",12},{"support_base_pattern", "",14},{"support_base_pattern_spacing", "",15},
|
||||||
{"support_interface_top_layers", "",16},{"support_interface_bottom_layers", "",17},{"support_interface_spacing", "",18},{"support_bottom_interface_spacing", "",19},
|
{"support_interface_top_layers", "",16},{"support_interface_bottom_layers", "",17},{"support_interface_spacing", "",18},{"support_bottom_interface_spacing", "",19},
|
||||||
{"support_object_xy_distance", "",20}, {"bridge_no_support", "",21},{"max_bridge_length", "",22},{"support_critical_regions_only", "",23},{"support_remove_small_overhang","",27}
|
{"support_object_xy_distance", "",20}, {"bridge_no_support", "",21},{"max_bridge_length", "",22},{"support_critical_regions_only", "",23},{"support_remove_small_overhang","",27},
|
||||||
|
{"support_object_first_layer_gap","",28}
|
||||||
}},
|
}},
|
||||||
{ L("Speed"), {{"support_speed", "",12}, {"support_interface_speed", "",13}
|
{ L("Speed"), {{"support_speed", "",12}, {"support_interface_speed", "",13}
|
||||||
}}
|
}}
|
||||||
|
@ -155,6 +156,7 @@ std::vector<SimpleSettingData> SettingsFactory::get_visible_options(const std::s
|
||||||
"tree_support_wall_count",
|
"tree_support_wall_count",
|
||||||
//support
|
//support
|
||||||
"support_top_z_distance", "support_base_pattern", "support_base_pattern_spacing", "support_interface_top_layers", "support_interface_bottom_layers", "support_interface_spacing", "support_bottom_interface_spacing", "support_object_xy_distance",
|
"support_top_z_distance", "support_base_pattern", "support_base_pattern_spacing", "support_interface_top_layers", "support_interface_bottom_layers", "support_interface_spacing", "support_bottom_interface_spacing", "support_object_xy_distance",
|
||||||
|
"support_object_first_layer_gap",
|
||||||
//adhesion
|
//adhesion
|
||||||
"brim_type", "brim_width", "brim_object_gap", "raft_layers"
|
"brim_type", "brim_width", "brim_object_gap", "raft_layers"
|
||||||
};*/
|
};*/
|
||||||
|
|
|
@ -1496,50 +1496,13 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||||
m_config_manipulation.apply(m_config, &new_conf);
|
m_config_manipulation.apply(m_config, &new_conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BBS popup a message to ask the user to set optimum parameters for tree support
|
|
||||||
if (opt_key == "support_type" || opt_key == "support_style") {
|
|
||||||
if (is_tree_slim(m_config->opt_enum<SupportType>("support_type"), m_config->opt_enum<SupportMaterialStyle>("support_style")) &&
|
|
||||||
!(m_config->opt_float("support_top_z_distance") == 0 && m_config->opt_int("support_interface_top_layers") == 0 && m_config->opt_int("tree_support_wall_count") == 2)) {
|
|
||||||
wxString msg_text = _L("We have added an experimental style \"Tree Slim\" that features smaller support volume but weaker strength.\n"
|
|
||||||
"We recommend using it with: 0 interface layers, 0 top distance, 2 walls.");
|
|
||||||
msg_text += "\n\n" + _L("Change these settings automatically? \n"
|
|
||||||
"Yes - Change these settings automatically\n"
|
|
||||||
"No - Do not change these settings for me");
|
|
||||||
MessageDialog dialog(wxGetApp().plater(), msg_text, "Suggestion", wxICON_WARNING | wxYES | wxNO);
|
|
||||||
DynamicPrintConfig new_conf = *m_config;
|
|
||||||
if (dialog.ShowModal() == wxID_YES) {
|
|
||||||
new_conf.set_key_value("support_top_z_distance", new ConfigOptionFloat(0));
|
|
||||||
new_conf.set_key_value("support_interface_top_layers", new ConfigOptionInt(0));
|
|
||||||
new_conf.set_key_value("tree_support_wall_count", new ConfigOptionInt(2));
|
|
||||||
m_config_manipulation.apply(m_config, &new_conf);
|
|
||||||
}
|
|
||||||
wxGetApp().plater()->update();
|
|
||||||
} else if ((m_config->opt_enum<SupportType>("support_type")==stTreeAuto && (m_config->opt_enum<SupportMaterialStyle>("support_style")==smsTreeStrong || m_config->opt_enum<SupportMaterialStyle>("support_style") == smsTreeHybrid)) &&
|
|
||||||
!((m_config->opt_float("support_top_z_distance") >=0.1 || is_support_filament(m_config->opt_int("support_interface_filament") - 1))
|
|
||||||
&& m_config->opt_int("support_interface_top_layers") >1) ) {
|
|
||||||
wxString msg_text = _L("For \"Tree Strong\" and \"Tree Hybrid\" styles, we recommend the following settings: at least 2 interface layers, at least 0.1mm top z distance or using support materials on interface.");
|
|
||||||
msg_text += "\n\n" + _L("Change these settings automatically? \n"
|
|
||||||
"Yes - Change these settings automatically\n"
|
|
||||||
"No - Do not change these settings for me");
|
|
||||||
MessageDialog dialog(wxGetApp().plater(), msg_text, "Suggestion", wxICON_WARNING | wxYES | wxNO);
|
|
||||||
DynamicPrintConfig new_conf = *m_config;
|
|
||||||
if (dialog.ShowModal() == wxID_YES) {
|
|
||||||
if (!is_support_filament(m_config->opt_int("support_interface_filament") - 1) && m_config->opt_float("support_top_z_distance") < 0.1)
|
|
||||||
new_conf.set_key_value("support_top_z_distance", new ConfigOptionFloat(0.2));
|
|
||||||
new_conf.set_key_value("support_interface_top_layers", new ConfigOptionInt(2));
|
|
||||||
m_config_manipulation.apply(m_config, &new_conf);
|
|
||||||
}
|
|
||||||
wxGetApp().plater()->update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BBS popup a message to ask the user to set optimum parameters for support interface if support materials are used
|
// BBS popup a message to ask the user to set optimum parameters for support interface if support materials are used
|
||||||
if (opt_key == "support_interface_filament") {
|
if (opt_key == "support_interface_filament") {
|
||||||
int interface_filament_id = m_config->opt_int("support_interface_filament") - 1; // the displayed id is based from 1, while internal id is based from 0
|
int interface_filament_id = m_config->opt_int("support_interface_filament") - 1; // the displayed id is based from 1, while internal id is based from 0
|
||||||
if (is_support_filament(interface_filament_id) && !(m_config->opt_float("support_top_z_distance") == 0 && m_config->opt_float("support_interface_spacing") == 0 &&
|
if (is_support_filament(interface_filament_id) && !(m_config->opt_float("support_top_z_distance") == 0 && m_config->opt_float("support_interface_spacing") == 0 &&
|
||||||
m_config->opt_enum<SupportMaterialInterfacePattern>("support_interface_pattern") == SupportMaterialInterfacePattern::smipConcentric)) {
|
m_config->opt_enum<SupportMaterialInterfacePattern>("support_interface_pattern") == SupportMaterialInterfacePattern::smipRectilinearInterlaced)) {
|
||||||
wxString msg_text = _L("When using support material for the support interface, We recommend the following settings:\n"
|
wxString msg_text = _L("When using support material for the support interface, We recommend the following settings:\n"
|
||||||
"0 top z distance, 0 interface spacing, concentric pattern and disable independent support layer height");
|
"0 top z distance, 0 interface spacing, interlaced rectilinear pattern and disable independent support layer height");
|
||||||
msg_text += "\n\n" + _L("Change these settings automatically? \n"
|
msg_text += "\n\n" + _L("Change these settings automatically? \n"
|
||||||
"Yes - Change these settings automatically\n"
|
"Yes - Change these settings automatically\n"
|
||||||
"No - Do not change these settings for me");
|
"No - Do not change these settings for me");
|
||||||
|
@ -1548,7 +1511,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||||
if (dialog.ShowModal() == wxID_YES) {
|
if (dialog.ShowModal() == wxID_YES) {
|
||||||
new_conf.set_key_value("support_top_z_distance", new ConfigOptionFloat(0));
|
new_conf.set_key_value("support_top_z_distance", new ConfigOptionFloat(0));
|
||||||
new_conf.set_key_value("support_interface_spacing", new ConfigOptionFloat(0));
|
new_conf.set_key_value("support_interface_spacing", new ConfigOptionFloat(0));
|
||||||
new_conf.set_key_value("support_interface_pattern", new ConfigOptionEnum<SupportMaterialInterfacePattern>(SupportMaterialInterfacePattern::smipConcentric));
|
new_conf.set_key_value("support_interface_pattern", new ConfigOptionEnum<SupportMaterialInterfacePattern>(SupportMaterialInterfacePattern::smipRectilinearInterlaced));
|
||||||
new_conf.set_key_value("independent_support_layer_height", new ConfigOptionBool(false));
|
new_conf.set_key_value("independent_support_layer_height", new ConfigOptionBool(false));
|
||||||
m_config_manipulation.apply(m_config, &new_conf);
|
m_config_manipulation.apply(m_config, &new_conf);
|
||||||
}
|
}
|
||||||
|
@ -2262,6 +2225,7 @@ void TabPrint::build()
|
||||||
optgroup = page->new_optgroup(L("Advanced"), L"param_advanced");
|
optgroup = page->new_optgroup(L("Advanced"), L"param_advanced");
|
||||||
optgroup->append_single_option_line("support_top_z_distance", "support#top-z-distance");
|
optgroup->append_single_option_line("support_top_z_distance", "support#top-z-distance");
|
||||||
optgroup->append_single_option_line("support_bottom_z_distance", "support#bottom-z-distance");
|
optgroup->append_single_option_line("support_bottom_z_distance", "support#bottom-z-distance");
|
||||||
|
optgroup->append_single_option_line("tree_support_wall_count");
|
||||||
optgroup->append_single_option_line("support_base_pattern", "support#base-pattern");
|
optgroup->append_single_option_line("support_base_pattern", "support#base-pattern");
|
||||||
optgroup->append_single_option_line("support_base_pattern_spacing", "support#base-pattern");
|
optgroup->append_single_option_line("support_base_pattern_spacing", "support#base-pattern");
|
||||||
optgroup->append_single_option_line("support_angle");
|
optgroup->append_single_option_line("support_angle");
|
||||||
|
@ -2274,8 +2238,9 @@ void TabPrint::build()
|
||||||
//optgroup->append_single_option_line("support_interface_loop_pattern");
|
//optgroup->append_single_option_line("support_interface_loop_pattern");
|
||||||
|
|
||||||
optgroup->append_single_option_line("support_object_xy_distance", "support");
|
optgroup->append_single_option_line("support_object_xy_distance", "support");
|
||||||
|
optgroup->append_single_option_line("support_object_first_layer_gap", "support");
|
||||||
optgroup->append_single_option_line("bridge_no_support", "support#base-pattern");
|
optgroup->append_single_option_line("bridge_no_support", "support#base-pattern");
|
||||||
optgroup->append_single_option_line("max_bridge_length", "support#base-pattern");
|
optgroup->append_single_option_line("max_bridge_length", "support#tree-support-only-options");
|
||||||
optgroup->append_single_option_line("independent_support_layer_height", "support");
|
optgroup->append_single_option_line("independent_support_layer_height", "support");
|
||||||
|
|
||||||
optgroup = page->new_optgroup(L("Tree supports"), L"param_support_tree");
|
optgroup = page->new_optgroup(L("Tree supports"), L"param_support_tree");
|
||||||
|
@ -2289,8 +2254,6 @@ void TabPrint::build()
|
||||||
optgroup->append_single_option_line("tree_support_branch_angle", "support#tree-support-only-options");
|
optgroup->append_single_option_line("tree_support_branch_angle", "support#tree-support-only-options");
|
||||||
optgroup->append_single_option_line("tree_support_branch_angle_organic", "support#tree-support-only-options");
|
optgroup->append_single_option_line("tree_support_branch_angle_organic", "support#tree-support-only-options");
|
||||||
optgroup->append_single_option_line("tree_support_angle_slow");
|
optgroup->append_single_option_line("tree_support_angle_slow");
|
||||||
optgroup->append_single_option_line("tree_support_branch_diameter_double_wall");
|
|
||||||
optgroup->append_single_option_line("tree_support_wall_count");
|
|
||||||
optgroup->append_single_option_line("tree_support_adaptive_layer_height");
|
optgroup->append_single_option_line("tree_support_adaptive_layer_height");
|
||||||
optgroup->append_single_option_line("tree_support_auto_brim");
|
optgroup->append_single_option_line("tree_support_auto_brim");
|
||||||
optgroup->append_single_option_line("tree_support_brim_width");
|
optgroup->append_single_option_line("tree_support_brim_width");
|
||||||
|
@ -2458,7 +2421,7 @@ void TabPrint::toggle_options()
|
||||||
if (auto choice = dynamic_cast<Choice*>(field)) {
|
if (auto choice = dynamic_cast<Choice*>(field)) {
|
||||||
auto def = print_config_def.get("support_style");
|
auto def = print_config_def.get("support_style");
|
||||||
std::vector<int> enum_set_normal = {smsDefault, smsGrid, smsSnug };
|
std::vector<int> enum_set_normal = {smsDefault, smsGrid, smsSnug };
|
||||||
std::vector<int> enum_set_tree = { smsDefault, smsTreeSlim, smsTreeStrong, smsTreeHybrid, smsOrganic };
|
std::vector<int> enum_set_tree = { smsDefault, smsTreeSlim, smsTreeStrong, smsTreeHybrid, smsTreeOrganic };
|
||||||
auto & set = is_tree(support_type) ? enum_set_tree : enum_set_normal;
|
auto & set = is_tree(support_type) ? enum_set_tree : enum_set_normal;
|
||||||
auto & opt = const_cast<ConfigOptionDef &>(field->m_opt);
|
auto & opt = const_cast<ConfigOptionDef &>(field->m_opt);
|
||||||
auto cb = dynamic_cast<ComboBox *>(choice->window);
|
auto cb = dynamic_cast<ComboBox *>(choice->window);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue