diff --git a/src/libslic3r/TreeModelVolumes.cpp b/src/libslic3r/TreeModelVolumes.cpp index e881451377..aa968d9960 100644 --- a/src/libslic3r/TreeModelVolumes.cpp +++ b/src/libslic3r/TreeModelVolumes.cpp @@ -63,7 +63,6 @@ TreeSupportMeshGroupSettings::TreeSupportMeshGroupSettings(const PrintObject &pr config.support_material_interface_layers.value) * this->layer_height : 0; this->support_material_buildplate_only = config.support_material_buildplate_only; -// this->support_xy_overrides_z = this->support_xy_distance = scaled(config.support_material_xy_spacing.get_abs_value(external_perimeter_width)); // Separation of interfaces, it is likely smaller than support_xy_distance. this->support_xy_distance_overhang = std::min(this->support_xy_distance, scaled(0.5 * external_perimeter_width)); @@ -163,15 +162,9 @@ TreeModelVolumes::TreeModelVolumes( } const TreeSupport::TreeSupportSettings config{ m_layer_outlines[m_current_outline_idx].first }; - if (! config.support_xy_overrides_z) { - m_current_min_xy_dist = config.xy_min_distance; - if (TreeSupport::TreeSupportSettings::soluble) - m_current_min_xy_dist = std::max(m_current_min_xy_dist, scaled(0.1)); - m_current_min_xy_dist_delta = std::max(config.xy_distance - m_current_min_xy_dist, coord_t(0)); - } else { - m_current_min_xy_dist = config.xy_distance; - m_current_min_xy_dist_delta = 0; - } + m_current_min_xy_dist = config.xy_min_distance; + m_current_min_xy_dist_delta = config.xy_distance - m_current_min_xy_dist; + assert(m_current_min_xy_dist_delta >= 0); m_increase_until_radius = config.increase_radius_until_radius; m_radius_0 = config.getRadius(0); @@ -436,12 +429,14 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex const int z_distance_top_layers = round_up_divide(settings.support_top_distance, layer_height); const LayerIndex max_required_layer = std::min(outlines.size(), max_layer_idx + std::max(coord_t(1), z_distance_top_layers)); const LayerIndex min_layer_bottom = std::max(0, min_layer_last - int(z_distance_bottom_layers)); - // technically this causes collision for the normal xy_distance to be larger by m_current_min_xy_dist_delta for all - // not currently processing meshes as this delta will be added at request time. - // avoiding this would require saving each collision for each outline_idx separately. - // and later for each avoidance... But avoidance calculation has to be for the whole scene and can NOT be done for each outline_idx separately and combined later. - // so avoiding this inaccuracy seems infeasible as it would require 2x the avoidance calculations => 0.5x the performance. - const coord_t xy_distance = outline_idx == m_current_outline_idx ? m_current_min_xy_dist : settings.support_xy_distance; + const coord_t xy_distance = outline_idx == m_current_outline_idx ? m_current_min_xy_dist : + // technically this causes collision for the normal xy_distance to be larger by m_current_min_xy_dist_delta for all + // not currently processing meshes as this delta will be added at request time. + // avoiding this would require saving each collision for each outline_idx separately. + // and later for each avoidance... But avoidance calculation has to be for the whole scene and can NOT be done for each outline_idx separately and combined later. + // so avoiding this inaccuracy seems infeasible as it would require 2x the avoidance calculations => 0.5x the performance. + //FIXME support_xy_distance is not corrected for "soluble" flag, see TreeSupportSettings constructor. + settings.support_xy_distance; // 1) Calculate offsets of collision areas in parallel. std::vector collision_areas_offsetted(max_required_layer + 1 - min_layer_bottom); diff --git a/src/libslic3r/TreeModelVolumes.hpp b/src/libslic3r/TreeModelVolumes.hpp index 3fd6ea79ed..f87204cf5e 100644 --- a/src/libslic3r/TreeModelVolumes.hpp +++ b/src/libslic3r/TreeModelVolumes.hpp @@ -64,10 +64,6 @@ struct TreeSupportMeshGroupSettings { // The thickness of the support floors. This controls the number of dense layers that are printed on top of places of a model on which support rests. coord_t support_bottom_height { scaled(1.) }; bool support_material_buildplate_only { false }; - // Support Distance Priority - // Whether the Support X/Y Distance overrides the Support Z Distance or vice versa. When X/Y overrides Z the X/Y distance can push away - // the support from the model, influencing the actual Z distance to the overhang. We can disable this by not applying the X/Y distance around overhangs. - bool support_xy_overrides_z { false }; // Support X/Y Distance // Distance of the support structure from the print in the X/Y directions. // minimum: 0, maximum warning: 1.5 * machine_nozzle_tip_outer_diameter @@ -75,7 +71,6 @@ struct TreeSupportMeshGroupSettings { // 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 - // Used if ! support_xy_overrides_z. coord_t support_xy_distance_overhang { scaled(0.2) }; // Support Top Distance // Distance from the top of the support to the print. diff --git a/src/libslic3r/TreeSupport.cpp b/src/libslic3r/TreeSupport.cpp index ef5432e2ad..01aec24a14 100644 --- a/src/libslic3r/TreeSupport.cpp +++ b/src/libslic3r/TreeSupport.cpp @@ -534,22 +534,22 @@ void TreeSupport::generateSupportAreas(Print &print, const BuildVolume &build_vo const TreeModelVolumes &volumes, const TreeSupport::TreeSupportSettings &config, const Polylines &polylines, LayerIndex layer_idx) { - const bool xy_overrides_z = config.support_xy_overrides_z; + const bool min_xy_dist = config.xy_distance > config.xy_min_distance; LineInformations result; // Also checks if the position is valid, if it is NOT, it deletes that point for (const Polyline &line : polylines) { LineInformation res_line; for (Point p : line) { - if (! contains(volumes.getAvoidance(config.getRadius(0), layer_idx, TreeModelVolumes::AvoidanceType::FastSafe, false, !xy_overrides_z), p)) + if (! contains(volumes.getAvoidance(config.getRadius(0), layer_idx, TreeModelVolumes::AvoidanceType::FastSafe, false, min_xy_dist), p)) res_line.emplace_back(p, LineStatus::TO_BP_SAFE); - else if (! contains(volumes.getAvoidance(config.getRadius(0), layer_idx, TreeModelVolumes::AvoidanceType::Fast, false, !xy_overrides_z), p)) + else if (! contains(volumes.getAvoidance(config.getRadius(0), layer_idx, TreeModelVolumes::AvoidanceType::Fast, false, min_xy_dist), p)) res_line.emplace_back(p, LineStatus::TO_BP); - else if (config.support_rests_on_model && ! contains(volumes.getAvoidance(config.getRadius(0), layer_idx, TreeModelVolumes::AvoidanceType::FastSafe, true, !xy_overrides_z), p)) + else if (config.support_rests_on_model && ! contains(volumes.getAvoidance(config.getRadius(0), layer_idx, TreeModelVolumes::AvoidanceType::FastSafe, true, min_xy_dist), p)) res_line.emplace_back(p, LineStatus::TO_MODEL_GRACIOUS_SAFE); - else if (config.support_rests_on_model && ! contains(volumes.getAvoidance(config.getRadius(0), layer_idx, TreeModelVolumes::AvoidanceType::Fast, true, !xy_overrides_z), p)) + else if (config.support_rests_on_model && ! contains(volumes.getAvoidance(config.getRadius(0), layer_idx, TreeModelVolumes::AvoidanceType::Fast, true, min_xy_dist), p)) res_line.emplace_back(p, LineStatus::TO_MODEL_GRACIOUS); - else if (config.support_rests_on_model && ! contains(volumes.getCollision(config.getRadius(0), layer_idx, !xy_overrides_z), p)) + else if (config.support_rests_on_model && ! contains(volumes.getCollision(config.getRadius(0), layer_idx, min_xy_dist), p)) res_line.emplace_back(p, LineStatus::TO_MODEL); else if (!res_line.empty()) { result.emplace_back(res_line); @@ -596,13 +596,14 @@ void TreeSupport::generateSupportAreas(Print &print, const BuildVolume &build_vo size_t current_layer, std::pair &p) { using AvoidanceType = TreeSupport::AvoidanceType; - if (! contains(volumes.getAvoidance(config.getRadius(0), current_layer - 1, p.second == LineStatus::TO_BP_SAFE ? AvoidanceType::FastSafe : AvoidanceType::Fast, false, !config.support_xy_overrides_z), p.first)) + const bool min_xy_dist = config.xy_distance > config.xy_min_distance; + if (! contains(volumes.getAvoidance(config.getRadius(0), current_layer - 1, p.second == LineStatus::TO_BP_SAFE ? AvoidanceType::FastSafe : AvoidanceType::Fast, false, min_xy_dist), p.first)) return true; if (config.support_rests_on_model && (p.second != LineStatus::TO_BP && p.second != LineStatus::TO_BP_SAFE)) return ! contains( p.second == LineStatus::TO_MODEL_GRACIOUS || p.second == LineStatus::TO_MODEL_GRACIOUS_SAFE ? - volumes.getAvoidance(config.getRadius(0), current_layer - 1, p.second == LineStatus::TO_MODEL_GRACIOUS_SAFE ? AvoidanceType::FastSafe : AvoidanceType::Fast, true, !config.support_xy_overrides_z) : - volumes.getCollision(config.getRadius(0), current_layer - 1, !config.support_xy_overrides_z), + volumes.getAvoidance(config.getRadius(0), current_layer - 1, p.second == LineStatus::TO_MODEL_GRACIOUS_SAFE ? AvoidanceType::FastSafe : AvoidanceType::Fast, true, min_xy_dist) : + volumes.getCollision(config.getRadius(0), current_layer - 1, min_xy_dist), p.first); return false; } @@ -1079,7 +1080,8 @@ void TreeSupport::generateInitialAreas( const size_t z_distance_delta = mesh_config.z_distance_top_layers + 1; // To ensure z_distance_top_layers are left empty between the overhang (zeroth empty layer), the support has to be added z_distance_top_layers+1 layers below - const bool xy_overrides_z = mesh_config.support_xy_overrides_z; + const bool min_xy_dist = mesh_config.xy_distance > mesh_config.xy_min_distance; + #if 0 if (mesh.overhang_areas.size() <= z_distance_delta) return; @@ -1095,7 +1097,7 @@ void TreeSupport::generateInitialAreas( //FIXME Vojtech: This is not sufficient for support enforcers to work. //FIXME There is no account for the support overhang angle. //FIXME There is no account for the width of the collision regions. - const coord_t extra_outset = std::max(coord_t(0), mesh_config.min_radius - mesh_config.support_line_width) + (xy_overrides_z ? 0 : mesh_config.support_line_width / 2) + const coord_t extra_outset = std::max(coord_t(0), mesh_config.min_radius - mesh_config.support_line_width) + (min_xy_dist ? mesh_config.support_line_width / 2 : 0) //FIXME this is a heuristic value for support enforcers to work. // + 10 * mesh_config.support_line_width; ; @@ -1113,7 +1115,7 @@ void TreeSupport::generateInitialAreas( std::mutex mutex_layer_storage, mutex_movebounds; tbb::parallel_for(tbb::blocked_range(1, num_support_layers - z_distance_delta), [this, &print_object, &overhangs, &mesh_config, &mesh_group_settings, &support_params, - z_distance_delta, xy_overrides_z, force_tip_to_roof, roof_enabled, support_roof_layers, extra_outset, circle_length_to_half_linewidth_change, connect_length, max_overhang_insert_lag, + z_distance_delta, min_xy_dist, force_tip_to_roof, roof_enabled, support_roof_layers, extra_outset, circle_length_to_half_linewidth_change, connect_length, max_overhang_insert_lag, &base_circle, &mutex_layer_storage, &mutex_movebounds, &top_contacts, &layer_storage, &already_inserted, &move_bounds, &base_radius](const tbb::blocked_range &range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) { @@ -1123,9 +1125,9 @@ void TreeSupport::generateInitialAreas( Polygons relevant_forbidden; { const Polygons &relevant_forbidden_raw = (mesh_config.support_rests_on_model ? - (SUPPORT_TREE_ONLY_GRACIOUS_TO_MODEL ? m_volumes.getAvoidance(mesh_config.getRadius(0), layer_idx, AvoidanceType::Fast, true, !xy_overrides_z) : - m_volumes.getCollision(mesh_config.getRadius(0), layer_idx, !xy_overrides_z)) : - m_volumes.getAvoidance(mesh_config.getRadius(0), layer_idx, AvoidanceType::Fast, false, !xy_overrides_z)); + (SUPPORT_TREE_ONLY_GRACIOUS_TO_MODEL ? m_volumes.getAvoidance(mesh_config.getRadius(0), layer_idx, AvoidanceType::Fast, true, min_xy_dist) : + m_volumes.getCollision(mesh_config.getRadius(0), layer_idx, min_xy_dist)) : + m_volumes.getAvoidance(mesh_config.getRadius(0), layer_idx, AvoidanceType::Fast, false, min_xy_dist)); // prevent rounding errors down the line, points placed directly on the line of the forbidden area may not be added otherwise. relevant_forbidden = offset(union_ex(relevant_forbidden_raw), scaled(0.005), jtMiter, 1.2); } @@ -1153,7 +1155,7 @@ void TreeSupport::generateInitialAreas( if (! already_inserted[insert_layer].count(p.first / ((mesh_config.min_radius + 1) / 10))) { // normalize the point a bit to also catch points which are so close that inserting it would achieve nothing already_inserted[insert_layer].emplace(p.first / ((mesh_config.min_radius + 1) / 10)); - SupportElement* elem = new SupportElement(dtt, insert_layer, p.first, to_bp, gracious, !xy_overrides_z, dont_move_until, roof, safe_radius, force_tip_to_roof, skip_ovalisation); + SupportElement* elem = new SupportElement(dtt, insert_layer, p.first, to_bp, gracious, min_xy_dist, dont_move_until, roof, safe_radius, force_tip_to_roof, skip_ovalisation); elem->area = new Polygons(); validate_range(circle); elem->area->emplace_back(std::move(circle)); @@ -1263,8 +1265,7 @@ void TreeSupport::generateInitialAreas( } // If the xy distance overrides the z distance, some support needs to be inserted further down. //=> Analyze which support points do not fit on this layer and check if they will fit a few layers down (while adding them an infinite amount of layers down would technically be closer the the setting description, it would not produce reasonable results. ) - if (xy_overrides_z) - { + if (! min_xy_dist) { LineInformations overhang_lines; { //Vojtech: Generate support heads at support_tree_branch_distance spacing by producing a zig-zag infill at support_tree_branch_distance spacing, @@ -1285,10 +1286,9 @@ void TreeSupport::generateInitialAreas( } validate_range(overhang_lines); } - for (size_t lag_ctr = 1; lag_ctr <= max_overhang_insert_lag && !overhang_lines.empty() && layer_idx - coord_t(lag_ctr) >= 1; lag_ctr++) { // get least restricted avoidance for layer_idx-lag_ctr - const Polygons &relevant_forbidden_below = (mesh_config.support_rests_on_model ? (SUPPORT_TREE_ONLY_GRACIOUS_TO_MODEL ? m_volumes.getAvoidance(mesh_config.getRadius(0), layer_idx - lag_ctr, AvoidanceType::Fast, true, !xy_overrides_z) : m_volumes.getCollision(mesh_config.getRadius(0), layer_idx - lag_ctr, !xy_overrides_z)) : m_volumes.getAvoidance(mesh_config.getRadius(0), layer_idx - lag_ctr, AvoidanceType::Fast, false, !xy_overrides_z)); + const Polygons &relevant_forbidden_below = (mesh_config.support_rests_on_model ? (SUPPORT_TREE_ONLY_GRACIOUS_TO_MODEL ? m_volumes.getAvoidance(mesh_config.getRadius(0), layer_idx - lag_ctr, AvoidanceType::Fast, true, min_xy_dist) : m_volumes.getCollision(mesh_config.getRadius(0), layer_idx - lag_ctr, min_xy_dist)) : m_volumes.getAvoidance(mesh_config.getRadius(0), layer_idx - lag_ctr, AvoidanceType::Fast, false, min_xy_dist)); // it is not required to offset the forbidden area here as the points wont change: If points here are not inside the forbidden area neither will they be later when placing these points, as these are the same points. auto evaluatePoint = [&](std::pair p) { return contains(relevant_forbidden_below, p.first); }; @@ -1344,9 +1344,9 @@ void TreeSupport::generateInitialAreas( { const Polygons &forbidden_next_raw = mesh_config.support_rests_on_model ? (SUPPORT_TREE_ONLY_GRACIOUS_TO_MODEL ? - m_volumes.getAvoidance(mesh_config.getRadius(0), layer_idx - (dtt_roof + 1), AvoidanceType::Fast, true, !xy_overrides_z) : - m_volumes.getCollision(mesh_config.getRadius(0), layer_idx - (dtt_roof + 1), !xy_overrides_z)) : - m_volumes.getAvoidance(mesh_config.getRadius(0), layer_idx - (dtt_roof + 1), AvoidanceType::Fast, false, !xy_overrides_z); + m_volumes.getAvoidance(mesh_config.getRadius(0), layer_idx - (dtt_roof + 1), AvoidanceType::Fast, true, min_xy_dist) : + m_volumes.getCollision(mesh_config.getRadius(0), layer_idx - (dtt_roof + 1), min_xy_dist)) : + m_volumes.getAvoidance(mesh_config.getRadius(0), layer_idx - (dtt_roof + 1), AvoidanceType::Fast, false, min_xy_dist); // prevent rounding errors down the line forbidden_next = offset(union_ex(forbidden_next_raw), scaled(0.005), jtMiter, 1.2); } diff --git a/src/libslic3r/TreeSupport.hpp b/src/libslic3r/TreeSupport.hpp index 661b239b9f..75c32e54db 100644 --- a/src/libslic3r/TreeSupport.hpp +++ b/src/libslic3r/TreeSupport.hpp @@ -374,10 +374,9 @@ public: increase_radius_until_layer(increase_radius_until_radius <= branch_radius ? tip_layers * (increase_radius_until_radius / branch_radius) : (increase_radius_until_radius - branch_radius) / (branch_radius * diameter_angle_scale_factor)), support_rests_on_model(! mesh_group_settings.support_material_buildplate_only), xy_distance(mesh_group_settings.support_xy_distance), + xy_min_distance(std::min(mesh_group_settings.support_xy_distance, mesh_group_settings.support_xy_distance_overhang)), bp_radius(mesh_group_settings.support_tree_bp_diameter / 2), diameter_scale_bp_radius(std::min(sin(0.7) * layer_height / branch_radius, 1.0 / (branch_radius / (support_line_width / 2.0)))), // Either 40? or as much as possible so that 2 lines will overlap by at least 50%, whichever is smaller. - support_xy_overrides_z(mesh_group_settings.support_xy_overrides_z), - xy_min_distance(support_xy_overrides_z ? xy_distance : mesh_group_settings.support_xy_distance_overhang), z_distance_top_layers(round_up_divide(mesh_group_settings.support_top_distance, layer_height)), z_distance_bottom_layers(round_up_divide(mesh_group_settings.support_bottom_distance, layer_height)), performance_interface_skip_layers(round_up_divide(mesh_group_settings.support_interface_skip_height, layer_height)), @@ -398,14 +397,15 @@ public: { layer_start_bp_radius = (bp_radius - branch_radius) / (branch_radius * diameter_scale_bp_radius); - // safeOffsetInc can only work in steps of the size xy_min_distance in the worst case => xy_min_distance has to be a bit larger than 0 in this worst case and should be large enough for performance to not suffer extremely - // When for all meshes the z bottom and top distance is more than one layer though the worst case is xy_min_distance + min_feature_size - // This is not the best solution, but the only one to ensure areas can not lag though walls at high maximum_move_distance. - if (soluble) - // If set to low rounding errors WILL cause errors. Best to keep it above 25. - xy_min_distance = std::max(scaled(0.1), xy_min_distance); + if (TreeSupport::TreeSupportSettings::soluble) { + // safeOffsetInc can only work in steps of the size xy_min_distance in the worst case => xy_min_distance has to be a bit larger than 0 in this worst case and should be large enough for performance to not suffer extremely + // When for all meshes the z bottom and top distance is more than one layer though the worst case is xy_min_distance + min_feature_size + // This is not the best solution, but the only one to ensure areas can not lag though walls at high maximum_move_distance. + xy_min_distance = std::max(xy_min_distance, scaled(0.1)); + xy_distance = std::max(xy_distance, xy_min_distance); + } + - xy_distance = std::max(xy_distance, xy_min_distance); // const std::unordered_map interface_map = { { "support_area_overwrite_interface_area", InterfacePreference::SUPPORT_AREA_OVERWRITES_INTERFACE }, { "interface_area_overwrite_support_area", InterfacePreference::INTERFACE_AREA_OVERWRITES_SUPPORT }, { "support_lines_overwrite_interface_area", InterfacePreference::SUPPORT_LINES_OVERWRITE_INTERFACE }, { "interface_lines_overwrite_support_area", InterfacePreference::INTERFACE_LINES_OVERWRITE_SUPPORT }, { "nothing", InterfacePreference::NOTHING } }; // interface_preference = interface_map.at(mesh_group_settings.get("support_interface_priority")); //FIXME this was the default @@ -494,10 +494,6 @@ public: * \brief Factor by which to increase the branch radius to reach the required bp_radius at layer 0. Note that this radius increase will not happen in the tip, to ensure the tip is structurally sound. */ double diameter_scale_bp_radius; - /*! - * \brief Should Z distance override X/Y distance, or the other way around. - */ - bool support_xy_overrides_z; /*! * \brief minimum xy_distance. Only relevant when Z overrides XY, otherwise equal to xy_distance- */ @@ -575,7 +571,7 @@ public: return branch_radius == other.branch_radius && tip_layers == other.tip_layers && diameter_angle_scale_factor == other.diameter_angle_scale_factor && layer_start_bp_radius == other.layer_start_bp_radius && bp_radius == other.bp_radius && diameter_scale_bp_radius == other.diameter_scale_bp_radius && min_radius == other.min_radius && xy_min_distance == other.xy_min_distance && // as a recalculation of the collision areas is required to set a new min_radius. xy_distance - xy_min_distance == other.xy_distance - other.xy_min_distance && // if the delta of xy_min_distance and xy_distance is different the collision areas have to be recalculated. support_rests_on_model == other.support_rests_on_model && increase_radius_until_layer == other.increase_radius_until_layer && min_dtt_to_model == other.min_dtt_to_model && max_to_model_radius_increase == other.max_to_model_radius_increase && maximum_move_distance == other.maximum_move_distance && maximum_move_distance_slow == other.maximum_move_distance_slow && z_distance_bottom_layers == other.z_distance_bottom_layers && support_line_width == other.support_line_width && - support_xy_overrides_z == other.support_xy_overrides_z && support_line_spacing == other.support_line_spacing && support_roof_line_width == other.support_roof_line_width && // can not be set on a per-mesh basis currently, so code to enable processing different roof line width in the same iteration seems useless. + support_line_spacing == other.support_line_spacing && support_roof_line_width == other.support_roof_line_width && // can not be set on a per-mesh basis currently, so code to enable processing different roof line width in the same iteration seems useless. support_bottom_offset == other.support_bottom_offset && support_wall_count == other.support_wall_count && support_pattern == other.support_pattern && roof_pattern == other.roof_pattern && // can not be set on a per-mesh basis currently, so code to enable processing different roof patterns in the same iteration seems useless. support_roof_angles == other.support_roof_angles && //support_infill_angles == other.support_infill_angles &&