quick search simplified, removed expensive layer estimators

added explanations and comments
This commit is contained in:
PavelMikus 2022-04-12 13:58:01 +02:00
parent 1955cd066e
commit c14b4a5d2e
2 changed files with 36 additions and 97 deletions

View file

@ -33,12 +33,6 @@ bool Issues::empty() const {
namespace Impl {
struct LayerDescriptor {
Vec2f centroid { 0.0f, 0.0f };
size_t segments_count { 0 };
float perimeter_length { 0.0f };
};
struct EdgeGridWrapper {
EdgeGridWrapper(coord_t edge_width, ExPolygons ex_polys) :
ex_polys(ex_polys), edge_width(edge_width) {
@ -50,6 +44,7 @@ struct EdgeGridWrapper {
bool signed_distance(const Point &point, coordf_t point_width, coordf_t &dist_out) const {
coordf_t tmp_dist_out;
bool found = grid.signed_distance(point, edge_width, tmp_dist_out);
// decrease the distance by half of edge width of previous layer and half of flow width of current layer
dist_out = tmp_dist_out - edge_width / 2 - point_width / 2;
return found;
@ -115,7 +110,7 @@ EdgeGridWrapper compute_layer_edge_grid(const Layer *layer) {
Points perimeter_points { };
perimeter->collect_points(perimeter_points);
assert(perimeter->is_loop());
perimeter_points.pop_back();
perimeter_points.pop_back(); // EdgeGrid structure does not like repetition of the first/last point
ex_polygons.push_back(ExPolygon { perimeter_points });
} // ex_perimeter
} // perimeter
@ -166,17 +161,18 @@ Issues check_extrusion_entity_stability(const ExtrusionEntity *entity,
issues.add(check_extrusion_entity_stability(e, slice_z, layer_region, supported_grid, params));
}
} else { //single extrusion path, with possible varying parameters
//prepare stack of points on the extrusion path. If there are long segments, additional points might be pushed onto the stack during the algorithm.
std::stack<Point> points { };
for (const auto &p : entity->as_polyline().points) {
points.push(p);
}
float unsupported_distance = params.bridge_distance + 1.0f;
float curvature = 0;
float max_curvature = 0;
float unsupported_distance = params.bridge_distance + 1.0f; // initialize unsupported distance with larger than tolerable distance ->
// -> it prevents extruding perimeter start and short loops into air.
float curvature = 0; // current curvature of the unsupported part of the extrusion - it is accumulated value of signed ccw angles of continuously unsupported points.
float max_curvature = 0; // max curvature (in abs value) for the current unsupported segment.
Vec2f tmp = unscale(points.top()).cast<float>();
Vec3f prev_fpoint = Vec3f(tmp.x(), tmp.y(), slice_z);
Vec3f prev_fpoint = Vec3f(tmp.x(), tmp.y(), slice_z); // prev point of the path. Initialize with first point.
coordf_t flow_width = get_flow_width(layer_region, entity->role());
bool external_perimters_first = layer_region->region().config().external_perimeters_first;
@ -190,30 +186,33 @@ Issues check_extrusion_entity_stability(const ExtrusionEntity *entity,
Vec3f fpoint = Vec3f(tmp.x(), tmp.y(), slice_z);
coordf_t dist_from_prev_layer { 0 };
if (!supported_grid.signed_distance(point, flow_width, dist_from_prev_layer)) {
if (!supported_grid.signed_distance(point, flow_width, dist_from_prev_layer)) { // dist from prev layer not found, assume empty layer
issues.supports_nedded.push_back(fpoint);
continue;
unsupported_distance = 0;
curvature = 0;
max_curvature = 0;
}
if (dist_from_prev_layer > max_allowed_dist_from_prev_layer) { //unsupported
unsupported_distance += (fpoint - prev_fpoint).norm();
if (dist_from_prev_layer > max_allowed_dist_from_prev_layer) { //extrusion point is unsupported
unsupported_distance += (fpoint - prev_fpoint).norm(); // for algortihm simplicity, expect that the whole line between prev and current point is unsupported
if (!points.empty()) {
const Vec2f v1 = (fpoint - prev_fpoint).head<2>();
const Vec2f v2 = unscale(points.top()).cast<float>() - fpoint.head<2>();
float dot = v1(0) * v2(0) + v1(1) * v2(1);
float cross = v1(0) * v2(1) - v1(1) * v2(0);
float angle = float(atan2(float(cross), float(dot)));
float angle = float(atan2(float(cross), float(dot))); // ccw angle, TODO replace with angle func, once it gets into master
curvature += angle;
max_curvature = std::max(abs(curvature), max_curvature);
}
if (unsupported_distance
> params.bridge_distance
/ (1.0f + (max_curvature * params.bridge_distance_decrease_by_curvature_factor / PI))) {
if (unsupported_distance // if unsupported distance is larger than bridge distance linearly decreased by curvature, enforce supports.
> params.bridge_distance
/ (1.0f + (max_curvature * params.bridge_distance_decrease_by_curvature_factor / PI))) {
issues.supports_nedded.push_back(fpoint);
//DEBUG stuff TODO remove
std::cout << "SUPP: " << "udis: " << unsupported_distance << " curv: " << curvature << " max curv: "
<< max_curvature << std::endl;
std::cout << "max dist from layer: " << max_allowed_dist_from_prev_layer << " measured dist: "
@ -229,15 +228,17 @@ Issues check_extrusion_entity_stability(const ExtrusionEntity *entity,
max_curvature = 0;
}
// Estimation of short curvy segments which are not supported -> problems with curling
// Currently the curling issues are ignored
if (max_curvature / (PI * unsupported_distance) > params.limit_curvature) {
issues.curling_up.push_back(fpoint);
}
prev_fpoint = fpoint;
if (!points.empty()) {
if (!points.empty()) { //oversampling if necessary
Vec2f next = unscale(points.top()).cast<float>();
Vec2f reverse_v = fpoint.head<2>() - next;
Vec2f reverse_v = fpoint.head<2>() - next; // vector from next to current
float dist_to_next = reverse_v.norm();
reverse_v.normalize();
int new_points_count = dist_to_next / params.bridge_distance;
@ -259,10 +260,11 @@ Issues check_layer_stability(const PrintObject *po, size_t layer_idx, bool full_
return {};
}
const Layer *layer = po->get_layer(layer_idx);
//Prepare edge grid of previous layer, will be used to check if the extrusion path is supported
EdgeGridWrapper supported_grid = compute_layer_edge_grid(layer->lower_layer);
Issues issues { };
if (full_check) {
if (full_check) { // If full checkm check stability of perimeters, gap fills, and bridges.
for (const LayerRegion *layer_region : layer->regions()) {
for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
for (const ExtrusionEntity *perimeter : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
@ -282,7 +284,7 @@ Issues check_layer_stability(const PrintObject *po, size_t layer_idx, bool full_
} // ex_entity
} // region
} else { //check only external perimeters
} else { // If NOT full check, check only external perimeters
for (const LayerRegion *layer_region : layer->regions()) {
for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
for (const ExtrusionEntity *perimeter : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
@ -304,85 +306,24 @@ Issues check_layer_stability(const PrintObject *po, size_t layer_idx, bool full_
std::vector<size_t> quick_search(const PrintObject *po, const Params &params) {
using namespace Impl;
std::vector<LayerDescriptor> descriptors(po->layer_count());
tbb::parallel_for(tbb::blocked_range<size_t>(0, po->layer_count()),
size_t layer_count = po->layer_count();
std::vector<bool> layer_needs_supports(layer_count, false);
tbb::parallel_for(tbb::blocked_range<size_t>(1, layer_count),
[&](tbb::blocked_range<size_t> r) {
for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) {
const Layer *layer = po->get_layer(layer_idx);
LayerDescriptor &descriptor = descriptors[layer_idx];
size_t point_count { 0 };
for (const LayerRegion *layer_region : layer->regions()) {
for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
for (const ExtrusionEntity *perimeter : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
if (perimeter->role() == ExtrusionRole::erExternalPerimeter || perimeter->role() == ExtrusionRole::erOverhangPerimeter) {
assert(perimeter->is_loop());
descriptor.segments_count++;
const ExtrusionLoop *loop = static_cast<const ExtrusionLoop*>(perimeter);
for (const ExtrusionPath& path : loop->paths) {
Vec2f prev_pos = unscale(path.polyline.last_point()).cast<float>();
for (size_t p_idx = 0; p_idx < path.polyline.points.size(); ++p_idx) {
point_count++;
Vec2f point_pos = unscale(path.polyline.points[p_idx]).cast<float>();
descriptor.centroid += point_pos;
descriptor.perimeter_length += (point_pos - prev_pos).norm();
prev_pos = point_pos;
} //point
} //path
} // ex_perimeter
} // perimeter
} // ex_entity
} // region
descriptor.centroid /= float(point_count);
} // layer
} // thread
);
std::vector<size_t> suspicious_layers_indices { };
for (size_t desc_idx = 1; desc_idx < descriptors.size(); ++desc_idx) {
const LayerDescriptor &prev = descriptors[desc_idx - 1];
const LayerDescriptor &descriptor = descriptors[desc_idx];
if (descriptor.segments_count - prev.segments_count != 0
||
std::abs(descriptor.perimeter_length - prev.perimeter_length)
> params.perimeter_length_diff_tolerance ||
(descriptor.centroid - prev.centroid).norm() > params.centroid_offset_tolerance
) {
suspicious_layers_indices.push_back(desc_idx);
}
#ifdef DEBUG_FILES
std::cout << "SIS layer idx: " << desc_idx << " reg count: " << descriptor.segments_count << " len: "
<< descriptor.perimeter_length <<
" centroid: " << descriptor.centroid.x() << " | " << descriptor.centroid.y() << std::endl;
std::cout << "SIS diff: " << desc_idx << " reg count: "
<< (int(descriptor.segments_count) - int(prev.segments_count)) <<
" len: " << (descriptor.perimeter_length - prev.perimeter_length) <<
" centroid: " << (descriptor.centroid - prev.centroid).norm() << std::endl;
#endif
}
std::vector<bool> layer_needs_supports(suspicious_layers_indices.size(), false);
tbb::parallel_for(tbb::blocked_range<size_t>(0, suspicious_layers_indices.size()),
[&](tbb::blocked_range<size_t> r) {
for (size_t suspicious_index = r.begin(); suspicious_index < r.end(); ++suspicious_index) {
auto layer_issues = check_layer_stability(po, suspicious_layers_indices[suspicious_index],
auto layer_issues = check_layer_stability(po, layer_idx,
false, params);
if (!layer_issues.supports_nedded.empty()) {
layer_needs_supports[suspicious_index] = true;
layer_needs_supports[layer_idx] = true;
}
}
});
std::vector<size_t> problematic_layers;
for (size_t index = 0; index < suspicious_layers_indices.size(); ++index) {
for (size_t index = 0; index < layer_needs_supports.size(); ++index) {
if (layer_needs_supports[index]) {
problematic_layers.push_back(suspicious_layers_indices[index]);
problematic_layers.push_back(index);
}
}
return problematic_layers;

View file

@ -9,14 +9,12 @@ namespace SupportableIssues {
struct Params {
float bridge_distance = 10.0f;
float limit_curvature = 0.3f;
float limit_curvature = 0.3f; // used to detect curling issues, but they are currently not considered anyway
float max_unsupported_distance_factor = 0.0f;
// allow printing external perimeter in the air to some extent. it hopefully attaches to the internal perimeter.
float max_ex_perim_unsupported_distance_factor = 1.0f;
float bridge_distance_decrease_by_curvature_factor = 5.0f;
float perimeter_length_diff_tolerance = 8.0f;
float centroid_offset_tolerance = 1.0f;
float bridge_distance_decrease_by_curvature_factor = 5.0f; // allowed bridge distance = bridge_distance / ( 1 + this factor * (curvature / PI) )
};