Added SupportPointCause describing the reason for the support point

This commit is contained in:
PavelMikus 2023-01-20 16:37:54 +01:00 committed by Pavel Mikuš
parent c4bd071295
commit 821d2391b4
2 changed files with 93 additions and 54 deletions

View file

@ -23,6 +23,7 @@
#include <cstddef>
#include <cstdio>
#include <functional>
#include <optional>
#include <unordered_map>
#include <unordered_set>
#include <stack>
@ -68,7 +69,7 @@ public:
float len;
const ExtrusionEntity *origin_entity;
bool support_point_generated = false;
std::optional<SupportSpotsGenerator::SupportPointCause> support_point_generated = {};
float form_quality = 1.0f;
float curled_up_height = 0.0f;
@ -81,10 +82,6 @@ auto get_b(ExtrusionLine &&l) { return l.b; }
namespace SupportSpotsGenerator {
SupportPoint::SupportPoint(const Vec3f &position, float force, float spot_radius, const Vec2f &direction)
: position(position), force(force), spot_radius(spot_radius), direction(direction)
{}
using LD = AABBTreeLines::LinesDistancer<ExtrusionLine>;
struct SupportGridFilter
@ -270,21 +267,27 @@ std::vector<ExtrusionLine> check_extrusion_entity_stability(const ExtrusionEntit
float sign = (prev_layer_boundary.distance_from_lines<true>(curr_point.position) + 0.5f * flow_width) < 0.0f ? -1.0f : 1.0f;
curr_point.distance *= sign;
SupportPointCause potential_cause = SupportPointCause::FloatingExtrusion;
if (entity->role().is_bridge() && !entity->role().is_perimeter()) {
potential_cause = std::abs(curr_point.curvature) > 0.1 ? SupportPointCause::FloatingBridgeAnchor : SupportPointCause::LongBridge;
}
float max_bridge_len = params.bridge_distance /
((1.0f + std::abs(curr_point.curvature)) * (1.0f + std::abs(curr_point.curvature)));
((1.0f + std::abs(curr_point.curvature)) * (1.0f + std::abs(curr_point.curvature)) *
(1.0f + std::abs(curr_point.curvature)));
if (curr_point.distance > 2.0f * flow_width) {
line_out.form_quality = 0.8f;
bridged_distance += line_len;
if (bridged_distance > max_bridge_len) {
line_out.support_point_generated = true;
line_out.support_point_generated = potential_cause;
bridged_distance = 0.0f;
}
} else if (curr_point.distance > flow_width * (1.0 + std::clamp(curr_point.curvature, -0.30f, 0.20f))) {
bridged_distance += line_len;
line_out.form_quality = nearest_prev_layer_line.form_quality - 0.3f;
if (line_out.form_quality < 0 && bridged_distance > max_bridge_len) {
line_out.support_point_generated = true;
line_out.support_point_generated = potential_cause;
line_out.form_quality = 0.5f;
bridged_distance = 0.0f;
}
@ -349,11 +352,13 @@ public:
Vec3f sticking_centroid_accumulator = Vec3f::Zero();
Vec2f sticking_second_moment_of_area_accumulator = Vec2f::Zero();
float sticking_second_moment_of_area_covariance_accumulator{};
bool connected_to_bed = false;
ObjectPart() = default;
void add(const ObjectPart &other)
{
this->connected_to_bed = this->connected_to_bed || other.connected_to_bed;
this->volume_centroid_accumulator += other.volume_centroid_accumulator;
this->volume += other.volume;
this->sticking_area += other.sticking_area;
@ -416,7 +421,7 @@ public:
return elastic_section_modulus;
}
float is_stable_while_extruding(const SliceConnection &connection,
std::tuple<float, SupportPointCause> is_stable_while_extruding(const SliceConnection &connection,
const ExtrusionLine &extruded_line,
const Vec3f &extreme_point,
float layer_z,
@ -434,7 +439,7 @@ public:
// section for bed calculations
{
if (this->sticking_area < EPSILON) return 1.0f;
if (this->sticking_area < EPSILON) return {1.0f, SupportPointCause::UnstableFloatingPart};
Vec3f bed_centroid = this->sticking_centroid_accumulator / this->sticking_area;
float bed_yield_torque = -compute_elastic_section_modulus(line_dir, extreme_point, this->sticking_centroid_accumulator,
@ -475,16 +480,19 @@ public:
BOOST_LOG_TRIVIAL(debug) << "SSG: total_torque: " << bed_total_torque << " layer_z: " << layer_z;
#endif
if (bed_total_torque > 0) return bed_total_torque / bed_conflict_torque_arm;
if (bed_total_torque > 0) {
return {bed_total_torque / bed_conflict_torque_arm,
(this->connected_to_bed ? SupportPointCause::SeparationFromBed : SupportPointCause::UnstableFloatingPart)};
}
}
// section for weak connection calculations
{
if (connection.area < EPSILON) return 1.0f;
if (connection.area < EPSILON) return {1.0f, SupportPointCause::UnstableFloatingPart};
Vec3f conn_centroid = connection.centroid_accumulator / connection.area;
if (layer_z - conn_centroid.z() < 3.0f) { return -1.0f; }
if (layer_z - conn_centroid.z() < 3.0f) { return {-1.0f, SupportPointCause::WeakObjectPart}; }
float conn_yield_torque = compute_elastic_section_modulus(line_dir, extreme_point, connection.centroid_accumulator,
connection.second_moment_of_area_accumulator,
connection.second_moment_of_area_covariance_accumulator,
@ -514,7 +522,7 @@ public:
BOOST_LOG_TRIVIAL(debug) << "SSG: total_torque: " << conn_total_torque << " layer_z: " << layer_z;
#endif
return conn_total_torque / conn_conflict_torque_arm;
return {conn_total_torque / conn_conflict_torque_arm, SupportPointCause::WeakObjectPart};
}
}
};
@ -538,6 +546,7 @@ std::tuple<ObjectPart, float> build_object_part_from_slice(const LayerSlice &sli
new_object_part.volume_centroid_accumulator += to_3d(Vec2f((line.a + line.b) / 2.0f), slice_z) * volume;
if (l->bottom_z() < EPSILON) { // layer attached on bed
new_object_part.connected_to_bed = true;
float sticking_area = line.len * flow_width;
new_object_part.sticking_area += sticking_area;
Vec2f middle = Vec2f((line.a + line.b) / 2.0f);
@ -731,24 +740,25 @@ SupportPoints check_stability(const PrintObject *po, const PrintTryCancel& cance
// Function that is used when new support point is generated. It will update the ObjectPart stability, weakest conneciton info,
// and the support presence grid and add the point to the issues.
auto reckon_new_support_point = [&part, &weakest_conn, &supp_points, &supports_presence_grid, &params,
&layer_idx](const Vec3f &support_point, float force, const Vec2f &dir) {
&layer_idx](SupportPointCause cause, const Vec3f &support_point, float force,
const Vec2f &dir) {
// if position is taken and point is for global stability (force > 0) or we are too close to the bed, do not add
// This allows local support points (e.g. bridging) to be generated densely
// This allows local support points (e.g. bridging) to be generated densely
if ((supports_presence_grid.position_taken(support_point) && force > 0) || layer_idx <= 1) {
return;
}
float area = params.support_points_interface_radius * params.support_points_interface_radius * float(PI);
// add the stability effect of the point only if the spot is not taken, so that the densely created local support points do not add
// unrealistic amount of stability to the object (due to overlaping of local support points)
// add the stability effect of the point only if the spot is not taken, so that the densely created local support points do
// not add unrealistic amount of stability to the object (due to overlaping of local support points)
if (!(supports_presence_grid.position_taken(support_point))) {
part.add_support_point(support_point, area);
}
float radius = params.support_points_interface_radius;
supp_points.emplace_back(support_point, force, radius, dir);
supp_points.emplace_back(cause, support_point, force, radius, dir);
supports_presence_grid.take_position(support_point);
// The support point also increases the stability of the weakest connection of the object, which should be reflected
if (weakest_conn.area > EPSILON) { // Do not add it to the weakest connection if it is not valid - does not exist
weakest_conn.area += area;
@ -768,9 +778,11 @@ SupportPoints check_stability(const PrintObject *po, const PrintTryCancel& cance
const ExtrusionEntity *entity = fill_region->fills().entities[fill_idx];
if (entity->role() == ExtrusionRole::BridgeInfill) {
for (const ExtrusionLine &bridge :
check_extrusion_entity_stability(entity, fill_region, prev_layer_ext_perim_lines,prev_layer_boundary, params)) {
if (bridge.support_point_generated) {
reckon_new_support_point(create_support_point_position(bridge.b), -EPSILON, Vec2f::Zero());
check_extrusion_entity_stability(entity, fill_region, prev_layer_ext_perim_lines, prev_layer_boundary,
params)) {
if (bridge.support_point_generated.has_value()) {
reckon_new_support_point(*bridge.support_point_generated, create_support_point_position(bridge.b),
-EPSILON, Vec2f::Zero());
}
}
}
@ -783,10 +795,13 @@ SupportPoints check_stability(const PrintObject *po, const PrintTryCancel& cance
std::vector<ExtrusionLine> perims = check_extrusion_entity_stability(entity, perimeter_region,
prev_layer_ext_perim_lines,prev_layer_boundary, params);
for (const ExtrusionLine &perim : perims) {
if (perim.support_point_generated) {
reckon_new_support_point(create_support_point_position(perim.b), -EPSILON, Vec2f::Zero());
if (perim.support_point_generated.has_value()) {
reckon_new_support_point(*perim.support_point_generated, create_support_point_position(perim.b), -EPSILON,
Vec2f::Zero());
}
if (perim.is_external_perimeter()) {
current_slice_ext_perims_lines.push_back(perim);
}
if (perim.is_external_perimeter()) { current_slice_ext_perims_lines.push_back(perim); }
}
}
}
@ -795,7 +810,8 @@ SupportPoints check_stability(const PrintObject *po, const PrintTryCancel& cance
float unchecked_dist = params.min_distance_between_support_points + 1.0f;
for (const ExtrusionLine &line : current_slice_ext_perims_lines) {
if ((unchecked_dist + line.len < params.min_distance_between_support_points && line.curled_up_height < 0.3f) || line.len < EPSILON) {
if ((unchecked_dist + line.len < params.min_distance_between_support_points && line.curled_up_height < 0.3f) ||
line.len < EPSILON) {
unchecked_dist += line.len;
} else {
unchecked_dist = line.len;
@ -803,8 +819,10 @@ SupportPoints check_stability(const PrintObject *po, const PrintTryCancel& cance
auto [dist, nidx,
nearest_point] = current_slice_lines_distancer.distance_from_lines_extra<false>(pivot_site_search_point);
Vec3f support_point = create_support_point_position(nearest_point);
auto force = part.is_stable_while_extruding(weakest_conn, line, support_point, bottom_z, params);
if (force > 0) { reckon_new_support_point(support_point, force, (line.b - line.a).normalized()); }
auto [force, cause] = part.is_stable_while_extruding(weakest_conn, line, support_point, bottom_z, params);
if (force > 0) {
reckon_new_support_point(cause, support_point, force, (line.b - line.a).normalized());
}
}
}
current_layer_ext_perims_lines.insert(current_layer_ext_perims_lines.end(), current_slice_ext_perims_lines.begin(),
@ -827,13 +845,18 @@ void debug_export(SupportPoints support_points, std::string file_name)
}
for (size_t i = 0; i < support_points.size(); ++i) {
if (support_points[i].force <= 0) {
fprintf(fp, "v %f %f %f %f %f %f\n", support_points[i].position(0), support_points[i].position(1),
support_points[i].position(2), 0.0, 1.0, 0.0);
} else {
fprintf(fp, "v %f %f %f %f %f %f\n", support_points[i].position(0), support_points[i].position(1),
support_points[i].position(2), 1.0, 0.0, 0.0);
Vec3f color{1.0f, 1.0f, 1.0f};
switch (support_points[i].cause) {
case SupportPointCause::FloatingBridgeAnchor: color = {0.863281f, 0.109375f, 0.113281f}; break; //RED
case SupportPointCause::LongBridge: color = {0.960938f, 0.90625f, 0.0625f}; break; // YELLOW
case SupportPointCause::FloatingExtrusion: color = {0.921875f, 0.515625f, 0.101563f}; break; // ORANGE
case SupportPointCause::SeparationFromBed: color = {0.0f, 1.0f, 0.0}; break; // GREEN
case SupportPointCause::UnstableFloatingPart: color = {0.105469f, 0.699219f, 0.84375f}; break; // BLUE
case SupportPointCause::WeakObjectPart: color = {0.609375f, 0.210938f, 0.621094f}; break; // PURPLE
}
fprintf(fp, "v %f %f %f %f %f %f\n", support_points[i].position(0), support_points[i].position(1),
support_points[i].position(2), color[0], color[1], color[2]);
}
fclose(fp);
@ -841,9 +864,6 @@ void debug_export(SupportPoints support_points, std::string file_name)
}
#endif
// std::vector<size_t> quick_search(const PrintObject *po, const Params &params) {
// return {};
// }
SupportPoints full_search(const PrintObject *po, const PrintTryCancel& cancel_func, const Params &params)
{
SupportPoints supp_points = check_stability(po, cancel_func, params);

View file

@ -35,7 +35,6 @@ struct Params {
const float min_distance_between_support_points = 3.0f; //mm
const float support_points_interface_radius = 1.5f; // mm
const float connections_min_considerable_area = 1.5f; //mm^2
const float min_distance_to_allow_local_supports = 1.0f; //mm
std::string filament_type;
@ -52,6 +51,8 @@ struct Params {
return 0.018 * 1e6;
} else if (filament_type == "PET" || filament_type == "PETG") {
return 0.3 * 1e6;
} else if (filament_type == "ABS" || filament_type == "ASA") {
return 0.1 * 1e6; //TODO do measurements
} else { //PLA default value - defensive approach, PLA has quite low adhesion
return 0.018 * 1e6;
}
@ -63,30 +64,48 @@ struct Params {
}
};
// The support points are generated for two reasons:
// 1. Local extrusion support for extrusions that are printed in the air and would not
enum class SupportPointCause {
LongBridge, // point generated on bridge extrusion longer than the allowed length
FloatingBridgeAnchor, // point generated on unsupported bridge endpoint
FloatingExtrusion, // point generated on extrusion that does not hold on its own - huge overhangs
SeparationFromBed, // point generated for object parts that are connected to the bed, but the area is too low and there is risk of separation (brim may help)
UnstableFloatingPart, // point generated for object parts not connected to the bed, holded only by the other support points (brim will not help here)
WeakObjectPart // point generated when some part of the object is too weak to hold the upper part and may break (imagine hourglass)
};
// The support points can be sorted into two groups
// 1. Local extrusion support for extrusions that are printed in the air and would not
// withstand on their own (too long bridges, sharp turns in large overhang, concave bridge holes, etc.)
// These points have negative force (-EPSILON) and Vec2f::Zero() direction
// The algorithm still expects that these points will be supported and accounts for them in the global stability check
// 2. Global stability support points are generated at each spot, where the algorithm detects that extruding the current line
// may cause separation of the object part from the bed and/or its support spots or crack in the weak connection of the object parts
// The generated point's direction is the estimated falling direction of the object part, and the force is equal to te difference
// The algorithm still expects that these points will be supported and accounts for them in the global stability check.
// 2. Global stability support points are generated at each spot, where the algorithm detects that extruding the current line
// may cause separation of the object part from the bed and/or its support spots or crack in the weak connection of the object parts.
// The generated point's direction is the estimated falling direction of the object part, and the force is equal to te difference
// between forces that destabilize the object (extruder conflicts with curled filament, weight if instable center of mass, bed movements etc)
// and forces that stabilize the object (bed adhesion, other support spots adhesion, weight if stable center of mass)
// and forces that stabilize the object (bed adhesion, other support spots adhesion, weight if stable center of mass).
// Note that the force is only the difference - the amount needed to stabilize the object again.
struct SupportPoint {
SupportPoint(const Vec3f &position, float force, float spot_radius, const Vec2f &direction);
bool is_local_extrusion_support() const { return force < 0; }
struct SupportPoint
{
SupportPoint(SupportPointCause cause, const Vec3f &position, float force, float spot_radius, const Vec2f &direction)
: cause(cause), position(position), force(force), spot_radius(spot_radius), direction(direction)
{}
bool is_local_extrusion_support() const
{
return cause == SupportPointCause::LongBridge || cause == SupportPointCause::FloatingExtrusion;
}
bool is_global_object_support() const { return !is_local_extrusion_support(); }
//position is in unscaled coords. The z coordinate is aligned with the layers bottom_z coordiantes
SupportPointCause cause; // reason why this support point was generated. Used for the user alerts
// position is in unscaled coords. The z coordinate is aligned with the layers bottom_z coordiantes
Vec3f position;
// force that destabilizes the object to the point of falling/breaking. It is in g*mm/s^2 units
// values gathered from large XL print: Min : 0 | Max : 18713800 | Average : 1361186 | Median : 329103
// force that destabilizes the object to the point of falling/breaking. g*mm/s^2 units
// It is valid only for global_object_support. For local extrusion support points, the force is -EPSILON
// values gathered from large XL model: Min : 0 | Max : 18713800 | Average : 1361186 | Median : 329103
// For reference 18713800 is weight of 1.8 Kg object, 329103 is weight of 0.03 Kg
// The final printed object weight was approx 0.5 Kg
// The final sliced object weight was approx 0.5 Kg
float force;
// Expected spot size. The support point strength is calculated from the area defined by this value.
// Expected spot size. The support point strength is calculated from the area defined by this value.
// Currently equal to the support_points_interface_radius parameter above
float spot_radius;
// direction of the fall of the object (z part is neglected)