unification of curling estimation - first step, but does not compile yet
This commit is contained in:
parent
dd7777f648
commit
89f012acb1
@ -88,6 +88,126 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ExtendedPoint
|
||||||
|
{
|
||||||
|
ExtendedPoint(Vec2d position, float distance = 0.0, size_t nearest_prev_layer_line = size_t(-1), float curvature = 0.0, float quality = 1.0)
|
||||||
|
: position(position), distance(distance), nearest_prev_layer_line(nearest_prev_layer_line), curvature(curvature), quality(quality)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Vec2d position;
|
||||||
|
float distance;
|
||||||
|
size_t nearest_prev_layer_line;
|
||||||
|
float curvature;
|
||||||
|
float quality;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<bool SCALED_INPUT, bool ADD_INTERSECTIONS, bool PREV_LAYER_BOUNDARY_ONLY, bool CONCAVITY_RESETS_CURVATURE, typename P, typename L>
|
||||||
|
std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P> &extrusion_points,
|
||||||
|
const AABBTreeLines::LinesDistancer<L> &unscaled_prev_layer,
|
||||||
|
float flow_width)
|
||||||
|
{
|
||||||
|
if (extrusion_points.empty()) return {};
|
||||||
|
float boundary_offset = PREV_LAYER_BOUNDARY_ONLY ? 0.5 * flow_width : 0.0f;
|
||||||
|
CurvatureEstimator cestim;
|
||||||
|
float min_malformation_dist = 0.2 * flow_width;
|
||||||
|
float peak_malformation_dist = 0.6 * flow_width;
|
||||||
|
|
||||||
|
std::vector<ExtendedPoint> points;
|
||||||
|
points.reserve(extrusion_points.size() * (ADD_INTERSECTIONS ? 1.5 : 1));
|
||||||
|
auto maybe_unscale = [](const P &p) { return SCALED_INPUT ? unscaled(p) : p.template cast<double>(); };
|
||||||
|
|
||||||
|
{
|
||||||
|
ExtendedPoint start_point{maybe_unscale(extrusion_points.begin())};
|
||||||
|
auto [distance, nearest_line, x] = unscaled_prev_layer.signed_distance_from_lines_extra(start_point.position) + boundary_offset;
|
||||||
|
start_point.distance = distance;
|
||||||
|
start_point.nearest_prev_layer_line = nearest_line;
|
||||||
|
points.push_back(start_point);
|
||||||
|
}
|
||||||
|
for (size_t i = 1; i < extrusion_points.size(); i++) {
|
||||||
|
ExtendedPoint next_point{maybe_unscale(extrusion_points[i])};
|
||||||
|
auto [distance, nearest_line, x] = unscaled_prev_layer.signed_distance_from_lines_extra(next_point.position) + boundary_offset;
|
||||||
|
next_point.distance = distance;
|
||||||
|
next_point.nearest_prev_layer_line = nearest_line;
|
||||||
|
|
||||||
|
if (ADD_INTERSECTIONS) {
|
||||||
|
const ExtendedPoint &prev_point = points.back();
|
||||||
|
if ((prev_point.distance < min_malformation_dist) != (next_point.distance < min_malformation_dist)) { // one in air, one not
|
||||||
|
auto intersections = unscaled_prev_layer.intersections_with_line<true>(L{prev_point.position, next_point.position});
|
||||||
|
for (const auto &intersection : intersections) { points.push_back({intersection, boundary_offset, 1.0}); }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PREV_LAYER_BOUNDARY_ONLY && prev_point.distance > min_malformation_dist &&
|
||||||
|
next_point.distance > min_malformation_dist) { // both in air
|
||||||
|
double line_len = (prev_point.position - next_point.position).norm();
|
||||||
|
if (line_len > 3.0) {
|
||||||
|
double a0 = std::clamp((boundary_offset + prev_point.distance) / line_len, 0.0, 1.0);
|
||||||
|
double a1 = std::clamp((boundary_offset + next_point.distance) / line_len, 0.0, 1.0);
|
||||||
|
double t0 = std::min(a0, a1);
|
||||||
|
double t1 = std::max(a0, a1);
|
||||||
|
|
||||||
|
auto p0 = prev_point.position + t0 * (next_point.position - prev_point.position);
|
||||||
|
auto [p0_dist, p0_near_l, p0_x] = unscaled_prev_layer.signed_distance_from_lines(p0) + boundary_offset;
|
||||||
|
points.push_back(ExtendedPoint{p0, p0_dist, p0_near_l});
|
||||||
|
|
||||||
|
auto p1 = prev_point.position + t1 * (next_point.position - prev_point.position);
|
||||||
|
auto [p1_dist, p1_near_l, p1_x] = unscaled_prev_layer.signed_distance_from_lines(p1) + boundary_offset;
|
||||||
|
points.push_back(ExtendedPoint{p1, p1_dist, p1_near_l});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
points.push_back(next_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int point_idx = 0; point_idx < points.size(); ++point_idx) {
|
||||||
|
ExtendedPoint &a = points[point_idx];
|
||||||
|
ExtendedPoint &prev = points[point_idx > 0 ? point_idx - 1 : point_idx];
|
||||||
|
|
||||||
|
int prev_point_idx = point_idx;
|
||||||
|
while (prev_point_idx > 0) {
|
||||||
|
prev_point_idx--;
|
||||||
|
if ((a.position - points[prev_point_idx].position).squaredNorm() > EPSILON) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
int next_point_index = point_idx;
|
||||||
|
while (next_point_index < int(points.size()) - 1) {
|
||||||
|
next_point_index++;
|
||||||
|
if ((a.position - points[next_point_index].position).squaredNorm() > EPSILON) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prev_point_idx != point_idx && next_point_index != point_idx) {
|
||||||
|
float distance = (prev.position - a.position).norm();
|
||||||
|
float alfa = angle(a.position - points[prev_point_idx].position, points[next_point_index].position - a.position);
|
||||||
|
if (alfa > 0.95 * 0.5 * PI) {
|
||||||
|
alfa = 0; // Ignore very sharp corners.. The curling problem happens mostly on rounded surfaces, not sudden sharp turns
|
||||||
|
}
|
||||||
|
cestim.add_point(distance, alfa);
|
||||||
|
if (CONCAVITY_RESETS_CURVATURE && alfa < 0.0) { cestim.reset(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.distance < min_malformation_dist) {
|
||||||
|
a.quality = 1.0;
|
||||||
|
cestim.reset();
|
||||||
|
} else {
|
||||||
|
float distance_quality = std::min(1.0f, std::abs(a.distance - peak_malformation_dist) /
|
||||||
|
(peak_malformation_dist - min_malformation_dist));
|
||||||
|
distance_quality = distance_quality * distance_quality;
|
||||||
|
|
||||||
|
float curvature_penalty = 0.0f;
|
||||||
|
a.curvature = cestim.get_curvature();
|
||||||
|
float curvature = std::abs(a.curvature);
|
||||||
|
if (curvature > 1.0f) {
|
||||||
|
curvature_penalty = 1.0f;
|
||||||
|
} else if (curvature > 0.1f) {
|
||||||
|
curvature_penalty = sqrt(1.0 - distance_quality) * curvature;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.quality = std::clamp(distance_quality - curvature_penalty, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
struct ProcessedPoint
|
struct ProcessedPoint
|
||||||
{
|
{
|
||||||
Point p;
|
Point p;
|
||||||
@ -98,129 +218,32 @@ class ExtrusionQualityEstimator
|
|||||||
{
|
{
|
||||||
std::unordered_map<const PrintObject *, AABBTreeLines::LinesDistancer<Linef>> prev_layer_boundaries;
|
std::unordered_map<const PrintObject *, AABBTreeLines::LinesDistancer<Linef>> prev_layer_boundaries;
|
||||||
std::unordered_map<const PrintObject *, AABBTreeLines::LinesDistancer<Linef>> next_layer_boundaries;
|
std::unordered_map<const PrintObject *, AABBTreeLines::LinesDistancer<Linef>> next_layer_boundaries;
|
||||||
CurvatureEstimator cestim;
|
|
||||||
const PrintObject *current_object;
|
const PrintObject *current_object;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void reset_for_next_extrusion() { cestim.reset(); }
|
|
||||||
|
|
||||||
void set_current_object(const PrintObject *object) { current_object = object; }
|
void set_current_object(const PrintObject *object) { current_object = object; }
|
||||||
|
|
||||||
void prepare_for_new_layer(const Layer *layer)
|
void prepare_for_new_layer(const Layer *layer)
|
||||||
{
|
{
|
||||||
if (layer == nullptr) return;
|
if (layer == nullptr) return;
|
||||||
const PrintObject *object = layer->object();
|
const PrintObject *object = layer->object();
|
||||||
prev_layer_boundaries[object] = next_layer_boundaries[object];
|
prev_layer_boundaries[object] = next_layer_boundaries[object];
|
||||||
next_layer_boundaries[object] = AABBTreeLines::LinesDistancer<Linef>{to_unscaled_linesf(layer->lslices)};
|
next_layer_boundaries[object] = AABBTreeLines::LinesDistancer<Linef>{to_unscaled_linesf(layer->lslices)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ProcessedPoint> estimate_extrusion_quality(const ExtrusionPath &path)
|
std::vector<ProcessedPoint> estimate_extrusion_quality(const ExtrusionPath &path)
|
||||||
{
|
{
|
||||||
struct ExtendedPoint
|
std::vector<ExtendedPoint> extended_points =
|
||||||
{
|
estimate_points_properties<true, true, true, false>(path.polyline.points, prev_layer_boundaries[current_object], path.width);
|
||||||
ExtendedPoint(const Vec2d &pos, float dist, float quality) : position(pos), distance(dist), quality(quality) {}
|
|
||||||
|
|
||||||
Vec2d position;
|
std::vector<ProcessedPoint> processed_points;
|
||||||
float distance;
|
processed_points.reserve(extended_points.size());
|
||||||
float quality;
|
for (size_t i = 0; i < extended_points.size(); i++) {
|
||||||
};
|
Point position = scaled(extended_points[i].position);
|
||||||
|
float speed_factor = std::min(extended_points[i].quality, extended_points[i+1].quality);
|
||||||
float flow_width = path.width;
|
processed_points.push_back({position, speed_factor});
|
||||||
float min_malformation_dist = 0.2 * flow_width;
|
|
||||||
float peak_malformation_dist = 0.6 * flow_width;
|
|
||||||
|
|
||||||
const Points &original_points = path.polyline.points;
|
|
||||||
std::vector<ExtendedPoint> points;
|
|
||||||
|
|
||||||
const auto& prev_layer_boundary = prev_layer_boundaries[current_object];
|
|
||||||
|
|
||||||
float distance = prev_layer_boundary.signed_distance_from_lines(unscaled(original_points[0])) + 0.5 * flow_width;
|
|
||||||
points.push_back({unscaled(original_points[0]), distance, 1.0f});
|
|
||||||
for (size_t i = 1; i < original_points.size(); i++) {
|
|
||||||
Vec2d next_point_pos = unscaled(original_points[i]);
|
|
||||||
float distance_of_next = prev_layer_boundary.signed_distance_from_lines(next_point_pos) + 0.5 * flow_width;
|
|
||||||
if ((points.back().distance < min_malformation_dist) != (distance_of_next < min_malformation_dist)) { // one in air, one not
|
|
||||||
auto intersections = prev_layer_boundary.intersections_with_line<true>({points.back().position, next_point_pos});
|
|
||||||
for (const auto &intersection : intersections) { points.push_back({intersection, 0.5f * flow_width, 1.0}); }
|
|
||||||
points.push_back({next_point_pos, distance_of_next, 1.0});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (points.back().distance > min_malformation_dist && distance_of_next > min_malformation_dist) { // both in air
|
|
||||||
double line_len = (points.back().position - next_point_pos).norm();
|
|
||||||
if (line_len > 3.0) {
|
|
||||||
double a0 = std::clamp((0.5 * flow_width + points.back().distance) / line_len, 0.0, 1.0);
|
|
||||||
double a1 = std::clamp((0.5 * flow_width + distance_of_next) / line_len, 0.0, 1.0);
|
|
||||||
double t0 = std::min(a0, a1);
|
|
||||||
double t1 = std::max(a0, a1);
|
|
||||||
|
|
||||||
auto p0 = points.back().position + t0 * (next_point_pos - points.back().position);
|
|
||||||
auto p0_dist = prev_layer_boundary.signed_distance_from_lines(p0) + 0.5 * flow_width;
|
|
||||||
points.push_back({p0, float(p0_dist), 1.0});
|
|
||||||
auto p1 = points.back().position + t1 * (next_point_pos - points.back().position);
|
|
||||||
auto p1_dist = prev_layer_boundary.signed_distance_from_lines(p1) + 0.5 * flow_width;
|
|
||||||
points.push_back({p1, float(p1_dist), 1.0});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
points.push_back({next_point_pos, distance_of_next, 1.0});
|
|
||||||
}
|
}
|
||||||
|
return processed_points;
|
||||||
for (int point_idx = 0; point_idx < int(points.size()) - 1; ++point_idx) {
|
|
||||||
ExtendedPoint &a = points[point_idx];
|
|
||||||
ExtendedPoint &b = points[point_idx + 1];
|
|
||||||
|
|
||||||
float distance = std::min(a.distance, b.distance);
|
|
||||||
|
|
||||||
int prev_point_idx = point_idx;
|
|
||||||
while (prev_point_idx > 0) {
|
|
||||||
prev_point_idx--;
|
|
||||||
if ((b.position - points[prev_point_idx].position).squaredNorm() > EPSILON) { break; }
|
|
||||||
}
|
|
||||||
|
|
||||||
int next_point_index = point_idx;
|
|
||||||
while (next_point_index < int(points.size()) - 1) {
|
|
||||||
next_point_index++;
|
|
||||||
if ((b.position - points[next_point_index].position).squaredNorm() > EPSILON) { break; }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prev_point_idx != point_idx && next_point_index != point_idx) {
|
|
||||||
float distance = (b.position - a.position).norm();
|
|
||||||
float alfa = angle(b.position - points[prev_point_idx].position, points[next_point_index].position - b.position);
|
|
||||||
if (alfa > 0.9 * PI / 2.0) {
|
|
||||||
alfa = 0; // Ignore very sharp corners.. The curling problem happens mostly on rounded surfaces, not sudden sharp turns
|
|
||||||
}
|
|
||||||
cestim.add_point(distance, alfa);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (distance < min_malformation_dist) {
|
|
||||||
a.quality = 1.0;
|
|
||||||
cestim.reset();
|
|
||||||
} else {
|
|
||||||
float distance_quality = std::min(1.0f, std::abs(distance - peak_malformation_dist) /
|
|
||||||
(peak_malformation_dist - min_malformation_dist));
|
|
||||||
distance_quality = distance_quality * distance_quality;
|
|
||||||
|
|
||||||
float curvature_penalty = 0.0f;
|
|
||||||
float curvature = std::abs(cestim.get_curvature());
|
|
||||||
if (curvature > 1.0f) {
|
|
||||||
curvature_penalty = 1.0f;
|
|
||||||
} else if (curvature > 0.1f) {
|
|
||||||
curvature_penalty = sqrt(1.0 - distance_quality) * curvature;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.quality = std::clamp(distance_quality - curvature_penalty, 0.0f, 1.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (points.size() > 3) {
|
|
||||||
points[points.size() - 2].quality = points[points.size()-3].quality;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ProcessedPoint> result;
|
|
||||||
result.reserve(points.size());
|
|
||||||
for (const ExtendedPoint &p : points) { result.push_back({Point::new_scale(p.position), std::clamp(p.quality, 0.0f, 1.0f)}); }
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user