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:
SoftFever 2025-02-26 20:53:54 +08:00 committed by GitHub
commit 41584cfae3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
35 changed files with 2253 additions and 4614 deletions

View file

@ -7351,11 +7351,11 @@ msgstr ""
msgid ""
"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 "
"0 top z distance, 0 interface spacing, interlaced rectilinear pattern and disable "
"independent support layer height"
msgstr ""
"当使用支持界面的支持材料时,我们推荐以下设置:\n"
"0顶层z距离0接触层间距同心图案,并且禁用独立支撑层高"
"0顶层z距离0接触层间距交叠直线图案,并且禁用独立支撑层高"
msgid ""
"Enabling this option will modify the model's shape. If your print requires "

View file

@ -310,16 +310,16 @@ set(lisbslic3r_sources
Support/SupportLayer.hpp
Support/SupportMaterial.cpp
Support/SupportMaterial.hpp
Support/SupportParameters.hpp
Support/SupportSpotsGenerator.cpp
Support/SupportSpotsGenerator.hpp
Support/TreeSupport.hpp
Support/TreeSupport.cpp
Support/TreeSupport3D.cpp
Support/TreeSupport3D.hpp
Support/TreeSupportCommon.hpp
Support/TreeModelVolumes.cpp
Support/TreeSupport3D.cpp
Support/TreeModelVolumes.hpp
Support/TreeModelVolumes.cpp
Support/TreeSupportCommon.hpp
Support/SupportParameters.hpp
PrincipalComponents2D.cpp
PrincipalComponents2D.hpp
MinimumSpanningTree.hpp

View file

@ -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); }
Slic3r::Polygons diff_clipped(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
{ return diff(subject, ClipperUtils::clip_clipper_polygons_with_subject_bbox(clip, get_extents(subject).inflated(SCALED_EPSILON)), do_safety_offset); }
Slic3r::ExPolygons diff_clipped(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
{ return diff_ex(subject, ClipperUtils::clip_clipper_polygons_with_subject_bbox(clip, get_extents(subject).inflated(SCALED_EPSILON)), do_safety_offset); }
Slic3r::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)
{ 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)

View file

@ -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().
// To be used with complex clipping polygons, where majority of the clipping polygons are outside of the source polygon.
Slic3r::Polygons diff_clipped(const Slic3r::Polygons &src, const Slic3r::Polygons &clipping, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::ExPolygons diff_clipped(const Slic3r::ExPolygons &src, const Slic3r::Polygons &clipping, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::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::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);

View file

@ -57,7 +57,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
case ipOctagramSpiral: return new FillOctagramSpiral();
case ipAdaptiveCubic: 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();
// BBS: for internal solid infill only
case ipConcentricInternal: return new FillConcentricInternal();

View file

@ -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.
|| (layer_to_print.support_layer /* && layer_to_print.support_layer->has_extrusions() */)) {
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);
// 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);
}
double maximal_print_z = (last_extrusion_layer ? last_extrusion_layer->print_z() : 0.)
+ layer_to_print.layer()->height
+ std::max(0., extra_gap);

View file

@ -139,7 +139,7 @@ public:
// BBS
mutable ExPolygons sharp_tails;
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
// (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
// that the 1st lslice is not compensated by the Elephant foot compensation algorithm.
ExPolygons lslices;
ExPolygons lslices_extrudable; // BBS: the extrudable part of lslices used for tree support
std::vector<BoundingBox> lslices_bboxes;
// BBS
@ -278,7 +279,6 @@ public:
// for tree supports
ExPolygons base_areas;
ExPolygons overhang_areas;
// Is there any valid extrusion assigned to this LayerRegion?
@ -311,14 +311,13 @@ protected:
{
ExPolygon *area;
int type;
int interface_id = 0;
coordf_t dist_to_top; // mm dist to top
bool need_infill = false;
bool need_extra_wall = false;
AreaGroup(ExPolygon *a, int t, coordf_t d) : area(a), type(t), dist_to_top(d) {}
};
enum OverhangType { Detected = 0, Enforced };
std::vector<AreaGroup> area_groups;
std::map<const ExPolygon *, OverhangType> overhang_types;
};
template<typename LayerContainer>

View file

@ -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)) {
std::vector<float> zs_sinking = {0.f};
Slic3r::append(zs_sinking, zs);
slice_mesh_slabs(painted, zs_sinking, volume_trafo, max_top_layers > 0 ? &top : nullptr, max_bottom_layers > 0 ? &bottom : nullptr, throw_on_cancel_callback);
slice_mesh_slabs(painted, zs_sinking, volume_trafo, max_top_layers > 0 ? &top : nullptr, max_bottom_layers > 0 ? &bottom : nullptr, nullptr, throw_on_cancel_callback);
MeshSlicingParams slicing_params;
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);
} 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 it_src = find_if(src.begin(), src.end(), [](const Polygons &p){ return ! p.empty(); });
if (it_src != src.end()) {

View file

@ -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",
"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",
"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",
"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",
@ -814,7 +814,7 @@ static std::vector<std::string> s_Preset_print_options {
"wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits",
"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_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",
"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",

View file

@ -1167,7 +1167,7 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
// 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)
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
print_object.config().support_style.value == smsDefault) &&
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
// 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
object->config().support_style == smsDefault)) {
float extrusion_width = std::min(

View file

@ -385,7 +385,7 @@ public:
size_t support_layer_count() const { return m_support_layers.size(); }
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;
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);
@ -427,7 +427,7 @@ public:
std::vector<Polygons> slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); }
// Helpers to project custom facets on slices
void project_and_append_custom_facets(bool seam, EnforcerBlockerType type, std::vector<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
BoundingBox get_first_layer_bbox(float& area, float& layer_height, std::string& name);

View file

@ -232,7 +232,7 @@ static t_config_enum_values s_keys_map_SupportMaterialStyle {
{ "tree_slim", smsTreeSlim },
{ "tree_strong", smsTreeStrong },
{ "tree_hybrid", smsTreeHybrid },
{ "organic", smsOrganic }
{ "organic", smsTreeOrganic }
};
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.
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->label = L("Pattern angle");
def->category = L("Support");
@ -5030,16 +5041,6 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
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);
// TRN PrintSettings: #lmFIXME
def->label = L("Branch Diameter Angle");
@ -5054,23 +5055,22 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(5));
def = this->add("tree_support_branch_diameter_double_wall", coFloat);
def->label = L("Branch Diameter with double walls");
def = this->add("tree_support_branch_diameter_organic", coFloat);
def->label = L("Tree support branch diameter");
def->category = L("Support");
// TRN PrintSettings: "Organic supports" > "Branch Diameter"
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->tooltip = L("This setting determines the initial diameter of support nodes.");
def->sidetext = L("mm");
def->min = 0;
def->max = 100.f;
def->min = 1.0;
def->max = 10;
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->label = L("Support wall loops");
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->max = 2;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(0));

View file

@ -132,7 +132,7 @@ enum SupportMaterialPattern {
};
enum SupportMaterialStyle {
smsDefault, smsGrid, smsSnug, smsTreeSlim, smsTreeStrong, smsTreeHybrid, smsOrganic,
smsDefault, smsGrid, smsSnug, smsTreeSlim, smsTreeStrong, smsTreeHybrid, smsTreeOrganic,
};
enum LongRectrationLevel
@ -840,6 +840,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionInt, support_threshold_angle))
((ConfigOptionFloatOrPercent, support_threshold_overlap))
((ConfigOptionFloat, support_object_xy_distance))
((ConfigOptionFloat, support_object_first_layer_gap))
((ConfigOptionFloat, xy_hole_compensation))
((ConfigOptionFloat, xy_contour_compensation))
((ConfigOptionBool, flush_into_objects))
@ -850,9 +851,8 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, tree_support_branch_distance))
((ConfigOptionFloat, tree_support_tip_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_diameter_angle))
((ConfigOptionFloat, tree_support_angle_slow))
((ConfigOptionInt, tree_support_wall_count))
((ConfigOptionBool, tree_support_adaptive_layer_height))

View file

@ -633,13 +633,9 @@ void PrintObject::generate_support_material()
if (this->set_started(posSupportMaterial)) {
this->clear_support_layers();
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();
} else if(!m_print->get_no_check_flag()) {
if(!has_support() && !m_print->get_no_check_flag()) {
// 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"));
typedef std::chrono::high_resolution_clock clock_;
typedef std::chrono::duration<double, std::ratio<1> > second_;
@ -669,6 +665,12 @@ void PrintObject::generate_support_material()
#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);
}
}
@ -731,7 +733,8 @@ void PrintObject::simplify_extrusion_path()
}
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"));
BOOST_LOG_TRIVIAL(debug) << "Simplify extrusion path of support in parallel - start";
tbb::parallel_for(
@ -745,6 +748,7 @@ void PrintObject::simplify_extrusion_path()
);
m_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Simplify extrusion path of support in parallel - end";
#endif
this->set_done(posSimplifySupportPath);
}
}
@ -843,14 +847,8 @@ void PrintObject::clear_support_layers()
std::shared_ptr<TreeSupportData> PrintObject::alloc_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 double angle = m_config.tree_support_branch_angle.value * M_PI / 180.;
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);
m_tree_support_preview_cache = std::make_shared<TreeSupportData>(*this, xy_distance, g_config_tree_support_collision_resolution);
}
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_style"
|| opt_key == "support_object_xy_distance"
|| opt_key == "support_object_first_layer_gap"
|| opt_key == "support_base_pattern_spacing"
|| opt_key == "support_expansion"
//|| 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_organic"
|| 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_organic"
|| opt_key == "tree_support_angle_slow"
@ -3935,91 +3933,8 @@ template void PrintObject::remove_bridges_from_contacts<Polygons>(
SupportNecessaryType PrintObject::is_support_necessary()
{
static const double super_overhang_area_threshold = SQ(scale_(5.0));
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);
tree_support.support_type = SupportType::stTreeAuto; // need to set support type to fully utilize the power of feature detection
tree_support.detect_overhangs(true);
@ -4028,7 +3943,7 @@ SupportNecessaryType PrintObject::is_support_necessary()
return SharpTail;
else if (tree_support.has_cantilever && tree_support.max_cantilever_dist > cantilevel_dist_thresh)
return Cantilever;
#endif
return NoNeedSupp;
}
@ -4219,7 +4134,7 @@ static void project_triangles_to_slabs(ConstLayerPtrsAdaptor layers, const index
}
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)
if (mv->is_model_part()) {
@ -4234,7 +4149,7 @@ void PrintObject::project_and_append_custom_facets(
else {
std::vector<Polygons> projected;
// Support blockers or enforcers. Project downward facing painted areas upwards to their respective slicing plane.
slice_mesh_slabs(custom_facets, zs_from_layers(this->layers()), this->trafo_centered() * mv->get_matrix(), nullptr, &projected, [](){});
slice_mesh_slabs(custom_facets, zs_from_layers(this->layers()), this->trafo_centered() * mv->get_matrix(), nullptr, &projected, vertical_points, [](){});
// Merge these projections with the output, layer by layer.
assert(! projected.empty());
assert(out.empty() || out.size() == projected.size());

View file

@ -808,10 +808,11 @@ void PrintObject::slice()
std::string warning = fix_slicing_errors(this, m_layers, [this](){ m_print->throw_if_canceled(); }, firstLayerReplacedBy);
m_print->throw_if_canceled();
//BBS: send warning message to slicing callback
if (!warning.empty()) {
BOOST_LOG_TRIVIAL(info) << warning;
this->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, warning, PrintStateBase::SlicingReplaceInitEmptyLayers);
}
// This warning is inaccurate, because the empty layers may have been replaced, or the model has supports.
//if (!warning.empty()) {
// BOOST_LOG_TRIVIAL(info) << warning;
// this->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, warning, PrintStateBase::SlicingReplaceInitEmptyLayers);
//}
#endif
// Detect and process holes that should be converted to polyholes

View file

@ -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)
{
// 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));
}

View file

@ -114,7 +114,7 @@ SlicingParameters SlicingParameters::create_from_config(
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);
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;
//BBS
params.gap_object_support = object_config.support_bottom_z_distance.value;

View file

@ -140,10 +140,11 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa
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.
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - start";
const bool snug_supports = config.support_style.value == smsSnug;
const bool smooth_supports = config.support_style.value != smsGrid;
const bool snug_supports = support_params.support_style == smsSnug;
const bool smooth_supports = support_params.support_style != smsGrid;
SupportGeneratorLayersPtr &interface_layers = base_and_interface_layers.first;
SupportGeneratorLayersPtr &base_interface_layers = base_and_interface_layers.second;
interface_layers.assign(intermediate_layers.size(), nullptr);
if (support_params.has_base_interfaces())
base_interface_layers.assign(intermediate_layers.size(), nullptr);
@ -329,19 +330,21 @@ SupportGeneratorLayersPtr generate_raft_base(
const BrimType brim_type = object.config().brim_type;
const bool brim_outer = brim_type == btOuterOnly || 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) {
if (brim_outer && brim_inner)
polygons_append(brim, offset(ex, brim_separation));
polygons_append(brim, offset(ex, brim_object_gap));
else {
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
brim.emplace_back(ex.contour);
if (brim_inner) {
Polygons holes = ex.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_append(brim, std::move(holes));
} else
@ -407,7 +410,7 @@ SupportGeneratorLayersPtr generate_raft_base(
// Do not add the raft contact layer, only add the raft layers below the contact 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);
new_layer.print_z = 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) {
// Expand the bases of the support columns in the 1st layer.
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) {
// 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())));
@ -536,7 +545,7 @@ static Polylines draw_perimeters(const ExPolygon &expoly, double clip_length)
return polylines;
}
static inline void tree_supports_generate_paths(
void tree_supports_generate_paths(
ExtrusionEntitiesPtr &dst,
const Polygons &polygons,
const Flow &flow,
@ -637,22 +646,25 @@ static inline void tree_supports_generate_paths(
ClipperLib_Z::Paths anchor_candidates;
for (ExPolygon& expoly : closing_ex(polygons, float(SCALED_EPSILON), float(SCALED_EPSILON + 0.5 * flow.scaled_width()))) {
std::unique_ptr<ExtrusionEntityCollection> eec;
ExPolygons regions_to_draw_inner_wall{expoly};
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) {
BOOST_LOG_TRIVIAL(debug)<< "TreeSupports: double wall area: " << area<< " > " << support_params.tree_branch_diameter_double_wall_area_scaled;
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;
// Make the tree branch stable by adding another perimeter.
ExPolygons level2 = offset2_ex({expoly}, -1.5 * flow.scaled_width(), 0.5 * flow.scaled_width());
if (level2.size() == 1) {
Polylines polylines;
if (level2.size() > 0) {
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(),
// Disable reversal of the path, always start with the anchor, always print CCW.
false);
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.
@ -660,8 +672,7 @@ static inline void tree_supports_generate_paths(
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());
if (ClipperLib_Z::Area(path) > 0) std::reverse(path.begin(), path.end());
// Draw the perimeters.
Polylines polylines;
@ -676,8 +687,7 @@ static inline void tree_supports_generate_paths(
pl.reverse();
pl.points.emplace_back(pl.points.front());
pl.clip_end(clip_length);
if (pl.size() < 2)
continue;
if (pl.size() < 2) continue;
// Find the foot of the seam point on anchor_candidates. Only pick an anchor point that was created by offsetting the source contour.
ClipperLib_Z::Path *closest_contour = nullptr;
Vec2d closest_point;
@ -755,6 +765,7 @@ static inline void tree_supports_generate_paths(
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.
false);
}
if (eec) {
std::reverse(eec->entities.begin(), eec->entities.end());
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,
const Polygons &polygons,
Fill *filler,
float density,
ExtrusionRole role,
const Flow &flow,
const SupportParameters& support_params,
bool with_sheath,
bool no_sort)
{
if (polygons.empty())
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);
return;
}
@ -1399,6 +1417,10 @@ SupportGeneratorLayersPtr generate_support_layers(
append(layers_sorted, intermediate_layers);
append(layers_sorted, 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.
std::sort(layers_sorted.begin(), layers_sorted.end(), [](auto *l1, auto *l2) { return *l1 < *l2; });
int layer_id = 0;
@ -1531,7 +1553,7 @@ void generate_support_toolpaths(
filler, float(support_params.support_density),
// Extrusion parameters
ExtrusionRole::erSupportMaterial, flow,
support_params.with_sheath, false);
support_params, support_params.with_sheath, false);
}
if (! tree_polygons.empty())
tree_supports_generate_paths(support_layer.support_fills.entities, tree_polygons, flow, support_params);
@ -1566,7 +1588,7 @@ void generate_support_toolpaths(
// Extrusion parameters
(support_layer_id < slicing_params.base_raft_layers) ? ExtrusionRole::erSupportMaterial : ExtrusionRole::erSupportMaterialInterface, flow,
// sheath at first layer
support_layer_id == 0, support_layer_id == 0);
support_params, support_layer_id == 0, support_layer_id == 0);
}
});
@ -1630,7 +1652,7 @@ void generate_support_toolpaths(
{
SupportLayer &support_layer = *support_layers[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());
// Find polygons with the same print_z.
@ -1734,7 +1756,7 @@ void generate_support_toolpaths(
// Filler and its parameters
filler, float(density),
// 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;
@ -1792,10 +1814,12 @@ void generate_support_toolpaths(
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
sheath = true;
no_sort = true;
} else if (config.support_style == SupportMaterialStyle::smsOrganic ||
// Orca: use organic as default
config.support_style == smsDefault) {
tree_supports_generate_paths(base_layer.extrusions, base_layer.polygons_to_extrude(), flow, support_params);
} else if (support_params.support_style == SupportMaterialStyle::smsTreeOrganic) {
// if the tree supports are too tall, use double wall to make it stronger
SupportParameters support_params2 = 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;
}
if (! done)
@ -1808,7 +1832,7 @@ void generate_support_toolpaths(
filler, density,
// Extrusion parameters
ExtrusionRole::erSupportMaterial, flow,
sheath, no_sort);
support_params, sheath, no_sort);
}
// Merge base_interface_layers to base_layers to avoid unneccessary retractions

View file

@ -50,6 +50,11 @@ SupportGeneratorLayersPtr generate_raft_base(
const SupportGeneratorLayersPtr &base_layers,
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
SupportGeneratorLayersPtr generate_support_layers(
PrintObject &object,

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,7 @@
#include "Slicing.hpp"
#include "Fill/FillBase.hpp"
#include "SupportLayer.hpp"
#include "SupportParameters.hpp"
namespace Slic3r {
class PrintObject;
@ -18,35 +19,6 @@ class PrintObjectConfig;
// the parameters of the raft to determine the 1st layer height and thickness.
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:
PrintObjectSupportMaterial(const PrintObject *object, const SlicingParameters &slicing_params);
@ -97,24 +69,6 @@ private:
SupportGeneratorLayersPtr &intermediate_layers,
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
@ -131,16 +85,6 @@ private:
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.
const PrintObject *m_object;
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.
SlicingParameters m_slicing_params;
// Various precomputed support parameters to be shared with external functions.
SupportParams m_support_params;
SupportParameters m_support_params;
};
} // namespace Slic3r

View file

@ -1,15 +1,13 @@
#ifndef slic3r_SupportParameters_hpp_
#define slic3r_SupportParameters_hpp_
#include <boost/log/trivial.hpp>
#include "../libslic3r.h"
#include "../Flow.hpp"
namespace Slic3r {
class PrintObject;
enum InfillPattern : int;
struct SupportParameters {
SupportParameters() = delete;
SupportParameters(const PrintObject& object)
{
const PrintConfig& print_config = object.print()->config();
@ -26,23 +24,25 @@ struct SupportParameters {
(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);
int num_bottom_interface_layers = object_config.support_interface_bottom_layers < 0 ?
this->num_top_interface_layers = std::max(0, object_config.support_interface_top_layers.value);
this->num_bottom_interface_layers = object_config.support_interface_bottom_layers < 0 ?
num_top_interface_layers : object_config.support_interface_bottom_layers;
this->has_top_contacts = num_top_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;
this->num_bottom_interface_layers = this->has_bottom_contacts ? size_t(num_bottom_interface_layers - 1) : 0;
if (this->soluble_interface_non_soluble_base) {
// Try to support soluble dense interfaces with non-soluble dense interfaces.
this->num_top_base_interface_layers = size_t(std::min(num_top_interface_layers / 2, 2));
this->num_bottom_base_interface_layers = size_t(std::min(num_bottom_interface_layers / 2, 2));
this->num_top_base_interface_layers = size_t(std::min(int(num_top_interface_layers) / 2, 2));
this->num_bottom_base_interface_layers = size_t(std::min(int(num_bottom_interface_layers) / 2, 2));
} else {
this->num_top_base_interface_layers = 0;
this->num_bottom_base_interface_layers = 0;
// BBS: if support interface and support base do not use the same filament, add a base layer to improve their adhesion
// 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
// support_filament==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));
@ -69,7 +69,8 @@ struct SupportParameters {
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;
}
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();
this->support_material_bottom_interface_flow = slicing_params.soluble_interface || !object_config.thick_bridges ?
@ -86,32 +87,39 @@ struct SupportParameters {
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();
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_density = std::min(1., this->support_material_flow.spacing() / support_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() / this->support_spacing);
if (object_config.support_interface_top_layers.value == 0) {
// No interface layers allowed, print everything with the base support pattern.
this->interface_spacing = this->support_spacing;
this->interface_density = this->support_density;
}
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 =
support_pattern == smpHoneycomb ? ipHoneycomb :
this->support_density > 0.95 || this->with_sheath ? 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;
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 == smipConcentric ?
ipConcentric :
(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_base = 0.f;
this->raft_angle_interface = 0.f;
@ -143,9 +151,34 @@ struct SupportParameters {
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;
}
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;
// Support contact & interface are soluble, but support base is non-soluble.
@ -181,6 +214,7 @@ struct SupportParameters {
Flow support_material_bottom_interface_flow;
// Flow at raft inteface & contact layers.
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?
bool can_merge_support_regions;
@ -188,16 +222,20 @@ struct SupportParameters {
// coordf_t support_layer_height_max;
coordf_t gap_xy;
coordf_t gap_xy_first_layer;
float base_angle;
float interface_angle;
coordf_t interface_spacing;
coordf_t support_expansion=0;
// Density of the top / bottom interface and contact layers.
coordf_t interface_density;
// Density of the raft interface and contact layers.
coordf_t raft_interface_density;
coordf_t support_spacing;
// Density of the base support layers.
coordf_t support_density;
SupportMaterialStyle support_style = smsDefault;
// Pattern of the sparse infill including sparse raft layers.
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?
bool with_sheath;
// 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_base;
@ -219,6 +257,9 @@ struct SupportParameters {
// Produce a raft interface angle for a given SupportLayer::interface_id()
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.)); }
bool independent_layer_height = false;
const double thresh_big_overhang = Slic3r::sqr(scale_(10));
};
} // namespace Slic3r

View file

@ -33,7 +33,7 @@ using namespace std::literals;
// or warning
// 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.
static Polygons calculateMachineBorderCollision(Polygon machine_border)

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,8 @@
#include "Flow.hpp"
#include "PrintConfig.hpp"
#include "Fill/Lightning/Generator.hpp"
#include "TreeModelVolumes.hpp"
#include "TreeSupport3D.hpp"
#ifndef SQ
#define SQ(x) ((x)*(x))
@ -26,17 +28,158 @@ struct LayerHeightData
{
coordf_t print_z = 0;
coordf_t height = 0;
size_t next_layer_nr = 0;
size_t obj_layer_nr = 0;
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 {
Vec3f pos;
std::vector<int> children; // index of children in the storing vector
std::vector<int> parents; // index of parents in the storing vector
TreeNode(Point pt, float z) {
pos = { float(unscale_(pt.x())),float(unscale_(pt.y())),z };
enum TreeNodeType {
eCircle,
eSquare,
ePolygon
};
/*!
* \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
* 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 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& operator=(TreeSupportData&&) = default;
@ -98,9 +241,13 @@ public:
Polygons get_contours(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<TreeNode> tree_nodes;
std::vector<std::unique_ptr<SupportNode>> contact_nodes;
// ExPolygon m_machine_border;
private:
/*!
@ -146,6 +293,7 @@ private:
*/
const ExPolygons& calculate_avoidance(const RadiusLayerPair& key) const;
tbb::spin_mutex m_mutex;
public:
bool is_slim = false;
@ -154,11 +302,7 @@ public:
*/
coordf_t m_xy_distance;
/*!
* \brief The maximum distance that the centrepoint of a tree branch may
* move in consequtive layers
*/
coordf_t m_max_move;
double branch_scale_factor = 1.0; // tan(45 degrees)
/*!
* \brief Sample resolution for radius values.
@ -177,6 +321,8 @@ public:
// union contours of all layers 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
* at given radius and layer indices.
@ -215,6 +361,10 @@ public:
*/
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.
*
@ -224,180 +374,28 @@ public:
*/
void generate();
void detect_overhangs(bool detect_first_sharp_tail_only=false);
void detect_overhangs(bool check_support_necessity = false);
enum NodeType {
eCircle,
eSquare,
ePolygon
};
/*!
* \brief Represents the metadata of a node in the tree.
*/
struct Node
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)
{
static constexpr Node* NO_PARENT = nullptr;
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;
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_);
}
}
#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;
float nodes_angle = 0;
bool has_overhangs = false;
bool has_sharp_tails = false;
bool has_cantilever = false;
double max_cantilever_dist = 0;
SupportType support_type;
SupportMaterialStyle support_style;
std::unique_ptr<FillLightning::Generator> generator;
std::unordered_map<double, size_t> printZ_to_lightninglayer;
@ -410,6 +408,10 @@ public:
*/
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:
/*!
* \brief Generator for model collision, avoidance and internal guide volumes
@ -417,20 +419,29 @@ private:
* Lazily computes volumes as needed.
* \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::unique_ptr<TreeSupport3D::TreeModelVolumes> m_model_volumes;
PrintObject *m_object;
const PrintObjectConfig* m_object_config;
SlicingParameters m_slicing_params;
// Various precomputed support parameters to be shared with external functions.
SupportParams m_support_params;
size_t m_raft_layers = 0;
SupportParameters m_support_params;
size_t m_raft_layers = 0; // number of raft layers, including raft base, raft interface, raft gap
size_t m_highest_overhang_layer = 0;
std::vector<std::vector<MinimumSpanningTree>> m_spanning_trees;
std::vector< std::unordered_map<Line, bool, LineHash>> m_mst_line_x_layer_contour_caches;
coordf_t MAX_BRANCH_RADIUS = 10.0;
coordf_t MAX_BRANCH_RADIUS_FIRST_LAYER = 12.0;
coordf_t MIN_BRANCH_RADIUS = 0.5;
float tree_support_branch_diameter_angle = 5.0;
float DO_NOT_MOVER_UNDER_MM = 0.0;
coordf_t base_radius = 0.0;
const coordf_t MAX_BRANCH_RADIUS = 10.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_slim = false;
bool with_infill = false;
@ -447,7 +458,7 @@ private:
* save the resulting support polygons to.
* \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.
@ -461,18 +472,16 @@ private:
* dropped down. The nodes are dropped to lower layers inside the same
* 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 adjust_layer_heights(std::vector<std::vector<Node*>>& contact_nodes);
void smooth_nodes();
/*! BBS: MusangKing: maximum layer height
* \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.
*
@ -486,20 +495,27 @@ private:
* \return For each layer, a list of points where the tree should connect
* with the model.
*/
void generate_contact_points(std::vector<std::vector<Node*>>& contact_nodes);
void generate_contact_points();
/*!
* \brief Add a node to the next layer.
*
* 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 generate_toolpaths();
Polygons spanning_tree_to_polygon(const std::vector<MinimumSpanningTree>& spanning_trees, Polygons layer_contours, int layer_nr);
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);
// get unscaled radius of node
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
Polygons get_trim_support_regions(

File diff suppressed because it is too large Load diff

View file

@ -47,8 +47,6 @@ struct SlicingParameters;
namespace TreeSupport3D
{
// The number of vertices in each circle.
static constexpr const size_t SUPPORT_TREE_CIRCLE_RESOLUTION = 25;
struct AreaIncreaseSettings
{
@ -139,6 +137,10 @@ struct SupportElementStateBits {
struct SupportElementState : public SupportElementStateBits
{
int type = 0;
coordf_t radius = 0;
float print_z = 0;
/*!
* \brief The layer this support elements wants reach
*/

View file

@ -17,10 +17,10 @@
namespace Slic3r
{
// The number of vertices in each circle.
static constexpr const size_t SUPPORT_TREE_CIRCLE_RESOLUTION = 25;
namespace TreeSupport3D
{
using LayerIndex = int;
enum class InterfacePreference
@ -42,8 +42,8 @@ struct TreeSupportMeshGroupSettings {
// const std::vector<unsigned int> printing_extruders = print_object.object_extruders();
// Support must be enabled and set to Tree style.
assert(config.enable_support || config.enforce_support_layers > 0);
assert(is_tree(config.support_type));
//assert(config.support_material);
//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.
coordf_t external_perimeter_width = 0.;
@ -69,28 +69,20 @@ struct TreeSupportMeshGroupSettings {
0;
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_1st_layer = scaled<coord_t>(config.support_object_first_layer_gap.value);
// 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_top_distance = scaled<coord_t>(slicing_params.gap_support_object);
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_layers = this->support_roof_enable ? config.support_interface_top_layers.value : 0;
this->support_floor_enable = config.support_interface_top_layers.value > 0 && config.support_interface_bottom_layers.value > 0;
this->support_floor_layers = this->support_floor_enable ? config.support_interface_bottom_layers.value : 0;
// this->minimum_roof_area =
// this->support_roof_angles =
this->support_roof_layers = config.support_interface_top_layers.value;
this->support_floor_enable = config.support_interface_bottom_layers.value > 0;
this->support_floor_layers = config.support_interface_bottom_layers.value;
this->support_roof_pattern = config.support_interface_pattern;
this->support_pattern = config.support_base_pattern;
this->support_line_spacing = scaled<coord_t>(config.support_base_pattern_spacing.value);
// this->support_bottom_offset =
// this->support_wall_count = config.support_material_with_sheath ? 1 : 0;
this->support_wall_count = 1;
this->support_wall_count = std::max(1, config.tree_support_wall_count.value); // at least 1 wall for organic tree support
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_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);
@ -99,26 +91,6 @@ struct TreeSupportMeshGroupSettings {
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 = 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.
// 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_1st_layer { scaled<coord_t>(0.7) };
// Minimum Support X/Y Distance
// 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
@ -766,6 +739,17 @@ private:
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 Slic3r

View file

@ -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);
}
// BBS: add vertical faces option
if (bottom && (fo == FaceOrientation::Down || fo == FaceOrientation::Degenerate)) {
Vec3i32 neighbors = face_neighbors[face_idx];
// Reset neighborship of this triangle in case the other triangle is oriented backwards from this one.
@ -2063,6 +2062,7 @@ void slice_mesh_slabs(
const Transform3d &trafo,
std::vector<Polygons> *out_top,
std::vector<Polygons> *out_bottom,
std::vector<std::pair<Vec3f, Vec3f>> *vertical_points,
std::function<void()> throw_on_cancel)
{
BOOST_LOG_TRIVIAL(debug) << "slice_mesh_slabs to polygons";
@ -2133,6 +2133,11 @@ void slice_mesh_slabs(
// Is the triangle vertical or degenerate?
assert(d == 0);
fo = fa == fb || fa == fc || fb == fc ? FaceOrientation::Degenerate : FaceOrientation::Vertical;
if(vertical_points && fo==FaceOrientation::Vertical)
{
Vec3f normal = (fb - fa).cross(fc - fa).normalized();
vertical_points->push_back({ (fa + fb + fc) / 3,normal });
}
}
face_orientation[&tri - mesh.indices.data()] = fo;
}
@ -2297,7 +2302,7 @@ void project_mesh(
{
std::vector<Polygons> top, bottom;
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)
*out_top = std::move(top.front());
if (out_bottom)
@ -2311,7 +2316,7 @@ Polygons project_mesh(
{
std::vector<Polygons> top, bottom;
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());
}

View file

@ -107,6 +107,7 @@ void slice_mesh_slabs(
const Transform3d &trafo,
std::vector<Polygons> *out_top,
std::vector<Polygons> *out_bottom,
std::vector<std::pair<Vec3f, Vec3f>> *vertical_points,
std::function<void()> throw_on_cancel);
// Project mesh upwards pointing surfaces / downwards pointing surfaces into 2D polygons.

View file

@ -6,6 +6,7 @@
#include <ctime>
#include <cstdarg>
#include <stdio.h>
#include <filesystem>
#include "format.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, ...)
{
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)) {
std::string path = boost::filesystem::system_complete(SLIC3R_DEBUG_OUT_PATH_PREFIX).string();
if (!boost::filesystem::exists(path)) {
boost::filesystem::create_directory(path);
if (!boost::filesystem::exists(svg_folder)) {
boost::filesystem::create_directory(svg_folder);
}
std::string path = boost::filesystem::system_complete(svg_folder).string();
printf("Debugging output files will be written to %s\n", path.c_str());
}
char buffer[2048];
@ -311,7 +313,13 @@ std::string debug_out_path(const char *name, ...)
va_start(args, name);
std::vsprintf(buffer, name, 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;

View file

@ -426,7 +426,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
auto support_type = config->opt_enum<SupportType>("support_type");
auto support_style = config->opt_enum<SupportMaterialStyle>("support_style");
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;
if (set.find(support_style) == set.end()) {
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",
"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_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("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_closing_radius", have_support_material && support_style == smsSnug);
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
support_style != smsDefault;
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" })
toggle_line(el, support_is_normal_tree);
// 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);
// 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_field("tree_support_brim_width", support_is_tree && !config->opt_bool("tree_support_auto_brim"));

View file

@ -2125,7 +2125,8 @@ bool GUI_App::OnInit()
{
try {
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();
return false;
}

View file

@ -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},
{"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},
{"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_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}
}}
@ -155,6 +156,7 @@ std::vector<SimpleSettingData> SettingsFactory::get_visible_options(const std::s
"tree_support_wall_count",
//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_object_first_layer_gap",
//adhesion
"brim_type", "brim_width", "brim_object_gap", "raft_layers"
};*/

View file

@ -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);
}
// 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
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
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"
"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"
"Yes - Change these settings automatically\n"
"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) {
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_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));
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->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("tree_support_wall_count");
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_angle");
@ -2274,8 +2238,9 @@ void TabPrint::build()
//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_first_layer_gap", "support");
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 = 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_organic", "support#tree-support-only-options");
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_auto_brim");
optgroup->append_single_option_line("tree_support_brim_width");
@ -2458,7 +2421,7 @@ void TabPrint::toggle_options()
if (auto choice = dynamic_cast<Choice*>(field)) {
auto def = print_config_def.get("support_style");
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 & opt = const_cast<ConfigOptionDef &>(field->m_opt);
auto cb = dynamic_cast<ComboBox *>(choice->window);