WIP TreeSupports: Removed support_xy_distance_overhang,

replaced with condition that support_xy_distance >= support_xy_distance_overhang
This commit is contained in:
Vojtech Bubnik 2022-09-01 14:30:20 +02:00
parent 078d496eef
commit 19f0d94be3
4 changed files with 44 additions and 58 deletions

View file

@ -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<coord_t>(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<coord_t>(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<coord_t>(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<int>(settings.support_top_distance, layer_height);
const LayerIndex max_required_layer = std::min<LayerIndex>(outlines.size(), max_layer_idx + std::max(coord_t(1), z_distance_top_layers));
const LayerIndex min_layer_bottom = std::max<LayerIndex>(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<Polygons> collision_areas_offsetted(max_required_layer + 1 - min_layer_bottom);

View file

@ -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<coord_t>(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<coord_t>(0.2) };
// Support Top Distance
// Distance from the top of the support to the print.

View file

@ -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<Point, LineStatus> &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<size_t>(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<size_t> &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<float>(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<Point, LineStatus> 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<float>(0.005), jtMiter, 1.2);
}

View file

@ -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<coord_t>(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<coord_t>(0.1));
xy_distance = std::max(xy_distance, xy_min_distance);
}
xy_distance = std::max(xy_distance, xy_min_distance);
// const std::unordered_map<std::string, InterfacePreference> 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<std::string>("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 &&