implemented alternative aligment path search, results are compared w.r. to number of moved seams

This commit is contained in:
PavelMikus 2022-05-04 16:46:29 +02:00
parent e595194f26
commit 3ebdff165c
2 changed files with 101 additions and 58 deletions

View File

@ -22,7 +22,7 @@
#include "libslic3r/Utils.hpp"
//#define DEBUG_FILES
#define DEBUG_FILES
#ifdef DEBUG_FILES
#include <boost/nowide/cstdio.hpp>
@ -295,7 +295,6 @@ struct GlobalModelInfo {
} else {
return 0.0f;
}
}
#ifdef DEBUG_FILES
@ -792,7 +791,8 @@ void debug_export_points(const std::vector<PrintObjectSeamData::LayerSeams> &la
+ std::to_string(color.z()) + ")";
visibility_svg.draw(scaled(Vec2f(point.position.head<2>())), visibility_fill);
Vec3i weight_color = value_to_rgbi(min_weight, max_weight, -comparator.compute_angle_penalty(point.local_ccw_angle));
Vec3i weight_color = value_to_rgbi(min_weight, max_weight,
-comparator.compute_angle_penalty(point.local_ccw_angle));
std::string weight_fill = "rgb(" + std::to_string(weight_color.x()) + "," + std::to_string(weight_color.y())
+ ","
+ std::to_string(weight_color.z()) + ")";
@ -1020,22 +1020,21 @@ void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po)
// If the closest point is good enough to replace current chosen seam, it is stored in potential_string_seams, returns true and updates last_point_pos
// Otherwise does nothing, returns false
// Used by align_seam_points().
bool SeamPlacer::find_next_seam_in_layer(
std::optional<std::pair<size_t, size_t>> SeamPlacer::find_next_seam_in_layer(
const std::vector<PrintObjectSeamData::LayerSeams> &layers,
std::pair<size_t, size_t> &last_point_indexes,
const std::pair<size_t, size_t> &prev_point_index,
const size_t layer_idx, const float slice_z,
const SeamPlacerImpl::SeamComparator &comparator,
std::vector<std::pair<size_t, size_t>> &seam_string) const {
const SeamPlacerImpl::SeamComparator &comparator) const {
using namespace SeamPlacerImpl;
const SeamCandidate &last_point = layers[last_point_indexes.first].points[last_point_indexes.second];
const SeamCandidate &last_point = layers[prev_point_index.first].points[prev_point_index.second];
Vec3f projected_position { last_point.position.x(), last_point.position.y(), slice_z };
std::vector<size_t> nearby_points_indices = find_nearby_points(*layers[layer_idx].points_tree, projected_position,
SeamPlacer::seam_align_tolerable_dist);
if (nearby_points_indices.empty()) {
return false;
return {};
}
size_t best_nearby_point_index = nearby_points_indices[0];
@ -1064,7 +1063,7 @@ bool SeamPlacer::find_next_seam_in_layer(
if (nearest_point.perimeter.finalized) {
//all points are from already finalized perimeter, skip
return false;
return {};
}
//from the nearest_point, deduce index of seam in the next layer
@ -1074,9 +1073,7 @@ bool SeamPlacer::find_next_seam_in_layer(
if (next_layer_seam.central_enforcer
&& (next_layer_seam.position - projected_position).squaredNorm()
< sqr(3 * SeamPlacer::seam_align_tolerable_dist)) {
last_point_indexes = std::pair<size_t, size_t> { layer_idx, nearest_point.perimeter.seam_index };
seam_string.push_back(last_point_indexes);
return true;
return {std::pair<size_t, size_t> {layer_idx, nearest_point.perimeter.seam_index}};
}
// Next compare nearest and nearby point. If they are similar pick nearest, Otherwise expect curvy lines on smooth surfaces like chimney of benchy model
@ -1084,24 +1081,22 @@ bool SeamPlacer::find_next_seam_in_layer(
if (comparator.are_similar(nearest_point, best_nearby_point)
&& comparator.is_first_not_much_worse(nearest_point, next_layer_seam)
&& comparator.are_similar(last_point, nearest_point)) {
last_point_indexes = std::pair<size_t, size_t> { layer_idx, nearest_point_index };
seam_string.push_back(last_point_indexes);
return true;
return {std::pair<size_t, size_t> {layer_idx, nearest_point_index}};
}
// If nearest point is not good enough, try it with the best nearby point.
if (comparator.is_first_not_much_worse(best_nearby_point, next_layer_seam)
&& comparator.are_similar(last_point, nearest_point)) {
last_point_indexes = std::pair<size_t, size_t> { layer_idx, best_nearby_point_index };
seam_string.push_back(last_point_indexes);
return true;
return {std::pair<size_t, size_t> {layer_idx, best_nearby_point_index}};
}
return false;
return {};
}
std::vector<std::pair<size_t, size_t>> SeamPlacer::find_seam_string(const PrintObject *po,
std::pair<size_t, size_t> start_seam,
const SeamPlacerImpl::SeamComparator &comparator) const {
std::pair<size_t, size_t> start_seam, const SeamPlacerImpl::SeamComparator &comparator,
std::optional<std::pair<size_t, size_t>> &out_best_moved_seam, size_t &out_moved_seams_count) const {
out_best_moved_seam.reset();
out_moved_seams_count = 0;
const std::vector<PrintObjectSeamData::LayerSeams> &layers = m_seam_per_object.find(po)->second.layers;
int layer_idx = start_seam.first;
int seam_index = start_seam.second;
@ -1109,14 +1104,28 @@ std::vector<std::pair<size_t, size_t>> SeamPlacer::find_seam_string(const PrintO
//initialize searching for seam string - cluster of nearby seams on previous and next layers
int skips = SeamPlacer::seam_align_tolerable_skips / 2;
int next_layer = layer_idx + 1;
std::pair<size_t, size_t> last_point_indexes = start_seam;
std::pair<size_t, size_t> prev_point_index = start_seam;
std::vector<std::pair<size_t, size_t>> seam_string { start_seam };
//find seams or potential seams in forward direction; there is a budget of skips allowed
while (skips >= 0 && next_layer < int(layers.size())) {
if (find_next_seam_in_layer(layers, last_point_indexes, next_layer,
float(po->get_layer(next_layer)->slice_z), comparator, seam_string)) {
//String added, last_point_pos updated, nothing to be done
auto maybe_next_seam = find_next_seam_in_layer(layers, prev_point_index, next_layer,
float(po->get_layer(next_layer)->slice_z), comparator);
if (maybe_next_seam.has_value()) {
std::pair<size_t, size_t> next_seam_coords = maybe_next_seam.value();
const auto &next_seam = layers[next_seam_coords.first].points[next_seam_coords.second];
bool is_moved = next_seam.perimeter.seam_index != next_seam_coords.second;
out_moved_seams_count += is_moved;
if (is_moved && (!out_best_moved_seam.has_value() ||
comparator.is_first_better(next_seam,
layers[out_best_moved_seam.value().first].points[out_best_moved_seam.value().second]))) {
out_best_moved_seam = { next_seam_coords };
}
seam_string.push_back(maybe_next_seam.value());
prev_point_index = seam_string.back();
//String added, prev_point_index updated
} else {
// Layer skipped, reduce number of available skips
skips--;
@ -1127,11 +1136,25 @@ std::vector<std::pair<size_t, size_t>> SeamPlacer::find_seam_string(const PrintO
//do additional check in back direction
next_layer = layer_idx - 1;
skips = SeamPlacer::seam_align_tolerable_skips / 2;
last_point_indexes = std::pair<size_t, size_t>(layer_idx, seam_index);
prev_point_index = std::pair<size_t, size_t>(layer_idx, seam_index);
while (skips >= 0 && next_layer >= 0) {
if (find_next_seam_in_layer(layers, last_point_indexes, next_layer,
float(po->get_layer(next_layer)->slice_z), comparator, seam_string)) {
//String added, last_point_pos updated, nothing to be done
auto maybe_next_seam = find_next_seam_in_layer(layers, prev_point_index, next_layer,
float(po->get_layer(next_layer)->slice_z), comparator);
if (maybe_next_seam.has_value()) {
std::pair<size_t, size_t> next_seam_coords = maybe_next_seam.value();
const auto &next_seam = layers[next_seam_coords.first].points[next_seam_coords.second];
bool is_moved = next_seam.perimeter.seam_index != next_seam_coords.second;
out_moved_seams_count += is_moved;
if (is_moved && (!out_best_moved_seam.has_value() ||
comparator.is_first_better(next_seam,
layers[out_best_moved_seam.value().first].points[out_best_moved_seam.value().second]))) {
out_best_moved_seam = { next_seam_coords };
}
seam_string.push_back(maybe_next_seam.value());
prev_point_index = seam_string.back();
//String added, prev_point_index updated
} else {
// Layer skipped, reduce number of available skips
skips--;
@ -1192,18 +1215,37 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl::
//align the seam points - start with the best, and check if they are aligned, if yes, skip, else start alignment
// Keeping the vectors outside, so with a bit of luck they will not get reallocated after couple of for loop iterations.
std::vector<std::pair<size_t, size_t>> seam_string;
std::vector<std::pair<size_t, size_t>> alternative_seam_string;
std::vector<Vec2f> observations;
std::vector<float> observation_points;
std::vector<float> weights;
for (const std::pair<size_t, size_t> &seam : seams) {
size_t layer_idx = seam.first;
size_t seam_index = seam.second;
int global_index = 0;
while (global_index < int(seams.size())) {
size_t layer_idx = seams[global_index].first;
size_t seam_index = seams[global_index].second;
global_index++;
const std::vector<SeamCandidate> &layer_perimeter_points = layers[layer_idx].points;
if (layer_perimeter_points[seam_index].perimeter.finalized) {
// This perimeter is already aligned, skip seam
continue;
} else {
seam_string = this->find_seam_string(po, seam, comparator);
std::optional<std::pair<size_t, size_t>> best_moved_seam;
size_t moved_seams_count;
seam_string = this->find_seam_string(po, { layer_idx, seam_index }, comparator, best_moved_seam,
moved_seams_count);
if (best_moved_seam.has_value()) {
size_t alternative_moved_seams_count;
alternative_seam_string = this->find_seam_string(po, best_moved_seam.value(), comparator,
best_moved_seam, alternative_moved_seams_count);
if (alternative_seam_string.size() >= SeamPlacer::seam_align_minimum_string_seams &&
alternative_moved_seams_count < moved_seams_count) {
seam_string = std::move(alternative_seam_string);
// finish loop. but repeat the alignment for the current seam, since it could be skipped due to alternative path being aligned.
global_index--;
}
}
if (seam_string.size() < seam_align_minimum_string_seams) {
//string NOT long enough to be worth aligning, skip
continue;
@ -1355,7 +1397,7 @@ void SeamPlacer::init(const Print &print) {
}
#ifdef DEBUG_FILES
debug_export_points(layers, po->bounding_box(), std::to_string(po->id().id),
debug_export_points(m_seam_per_object[po].layers, po->bounding_box(), std::to_string(po->id().id),
comparator);
#endif
}

View File

@ -129,7 +129,7 @@ public:
// When searching for seam clusters for alignment:
// following value describes, how much worse score can point have and still be picked into seam cluster instead of original seam point on the same layer
static constexpr float seam_align_score_tolerance = 0.25f;
static constexpr float seam_align_score_tolerance = 0.5f;
// seam_align_tolerable_dist - if next layer closes point is too far away, break string
static constexpr float seam_align_tolerable_dist = 1.0f;
// if the seam of the current layer is too far away, and the closest seam candidate is not very good, layer is skipped.
@ -156,13 +156,14 @@ private:
void align_seam_points(const PrintObject *po, const SeamPlacerImpl::SeamComparator &comparator);
std::vector<std::pair<size_t, size_t>> find_seam_string(const PrintObject *po,
std::pair<size_t, size_t> start_seam,
const SeamPlacerImpl::SeamComparator &comparator) const;
bool find_next_seam_in_layer(
const std::vector<PrintObjectSeamData::LayerSeams> &layers,
std::pair<size_t, size_t> &last_point_indexes,
const size_t layer_idx, const float slice_z,
const SeamPlacerImpl::SeamComparator &comparator,
std::vector<std::pair<size_t, size_t>> &seam_string) const;
std::optional<std::pair<size_t, size_t>> &out_best_moved_seam,
size_t& out_moved_seams_count) const;
std::optional<std::pair<size_t, size_t>> find_next_seam_in_layer(
const std::vector<PrintObjectSeamData::LayerSeams> &layers,
const std::pair<size_t, size_t> &prev_point_index,
const size_t layer_idx, const float slice_z,
const SeamPlacerImpl::SeamComparator &comparator) const;
};
} // namespace Slic3r