quick search simplified, removed expensive layer estimators
added explanations and comments
This commit is contained in:
parent
1955cd066e
commit
c14b4a5d2e
2 changed files with 36 additions and 97 deletions
|
@ -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 ¶ms) {
|
||||
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;
|
||||
|
|
|
@ -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) )
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue