prefer enforcers over blockers, lower the threshold distance,

dynamic modification of segments count in alignment based on smoothnes
This commit is contained in:
PavelMikus 2022-08-02 17:10:21 +02:00 committed by Lukas Matena
parent a41435d044
commit 44a388d560
3 changed files with 41 additions and 46 deletions

View File

@ -467,7 +467,7 @@ Polygons extract_perimeter_polygons(const Layer *layer, const SeamPosition confi
//each SeamCandidate also contains pointer to shared Perimeter structure representing the polygon //each SeamCandidate also contains pointer to shared Perimeter structure representing the polygon
// if Custom Seam modifiers are present, oversamples the polygon if necessary to better fit user intentions // if Custom Seam modifiers are present, oversamples the polygon if necessary to better fit user intentions
void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const LayerRegion *region, void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const LayerRegion *region,
bool arachne_generated, const GlobalModelInfo &global_model_info, PrintObjectSeamData::LayerSeams &result) { const GlobalModelInfo &global_model_info, PrintObjectSeamData::LayerSeams &result) {
if (orig_polygon.size() == 0) { if (orig_polygon.size() == 0) {
return; return;
} }
@ -482,25 +482,6 @@ void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const
std::vector<float> polygon_angles = calculate_polygon_angles_at_vertices(polygon, lengths, std::vector<float> polygon_angles = calculate_polygon_angles_at_vertices(polygon, lengths,
SeamPlacer::polygon_local_angles_arm_distance); SeamPlacer::polygon_local_angles_arm_distance);
// resample smooth surfaces from arachne, so that alignment finds short path down, and does not create unnecesary curves
if (arachne_generated && std::all_of(polygon_angles.begin(), polygon_angles.end(), [](float angle) {
return compute_angle_penalty(angle) > SeamPlacer::sharp_angle_penalty_snapping_threshold;
})) {
float total_dist = std::accumulate(lengths.begin(), lengths.end(), 0.0f);
float avg_dist = total_dist / float(lengths.size());
if (avg_dist < SeamPlacer::seam_align_tolerable_dist * 2.0f){
coord_t sampling_dist = scaled(avg_dist*0.2f);
polygon.points = polygon.equally_spaced_points(sampling_dist);
lengths.clear();
for (size_t point_idx = 0; point_idx < polygon.size() - 1; ++point_idx) {
lengths.push_back((unscale(polygon[point_idx]) - unscale(polygon[point_idx + 1])).norm());
}
lengths.push_back(std::max((unscale(polygon[0]) - unscale(polygon[polygon.size() - 1])).norm(), 0.1));
polygon_angles = calculate_polygon_angles_at_vertices(polygon, lengths, avg_dist);
}
}
result.perimeters.push_back( { }); result.perimeters.push_back( { });
Perimeter &perimeter = result.perimeters.back(); Perimeter &perimeter = result.perimeters.back();
@ -531,13 +512,14 @@ void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const
orig_point = true; orig_point = true;
} }
if (global_model_info.is_enforced(position, perimeter.flow_width)) { if (global_model_info.is_blocked(position, perimeter.flow_width * 0.5f)) {
type = EnforcedBlockedSeamPoint::Blocked;
}
if (global_model_info.is_enforced(position, perimeter.flow_width * 0.5f)) {
type = EnforcedBlockedSeamPoint::Enforced; type = EnforcedBlockedSeamPoint::Enforced;
} }
if (global_model_info.is_blocked(position, perimeter.flow_width)) {
type = EnforcedBlockedSeamPoint::Blocked;
}
some_point_enforced = some_point_enforced || type == EnforcedBlockedSeamPoint::Enforced; some_point_enforced = some_point_enforced || type == EnforcedBlockedSeamPoint::Enforced;
if (orig_point) { if (orig_point) {
@ -880,9 +862,9 @@ struct SeamComparator {
float weight(const SeamCandidate &a) const { float weight(const SeamCandidate &a) const {
if (setup == SeamPosition::spAligned && a.central_enforcer) { if (setup == SeamPosition::spAligned && a.central_enforcer) {
return 2.0f; return 10.0f;
} }
return a.visibility + angle_importance * compute_angle_penalty(a.local_ccw_angle) / (1.0f + angle_importance); return 1.0f / (0.1f + a.visibility + angle_importance * compute_angle_penalty(a.local_ccw_angle) / (1.0f + angle_importance));
} }
}; };
@ -907,8 +889,8 @@ void debug_export_points(const std::vector<PrintObjectSeamData::LayerSeams> &lay
min_vis = std::min(min_vis, point.visibility); min_vis = std::min(min_vis, point.visibility);
max_vis = std::max(max_vis, point.visibility); max_vis = std::max(max_vis, point.visibility);
min_weight = std::min(min_weight, -comparator.compute_angle_penalty(point.local_ccw_angle)); min_weight = std::min(min_weight, -compute_angle_penalty(point.local_ccw_angle));
max_weight = std::max(max_weight, -comparator.compute_angle_penalty(point.local_ccw_angle)); max_weight = std::max(max_weight, -compute_angle_penalty(point.local_ccw_angle));
} }
@ -929,7 +911,7 @@ void debug_export_points(const std::vector<PrintObjectSeamData::LayerSeams> &lay
visibility_svg.draw(scaled(Vec2f(point.position.head<2>())), visibility_fill); visibility_svg.draw(scaled(Vec2f(point.position.head<2>())), visibility_fill);
Vec3i weight_color = value_to_rgbi(min_weight, max_weight, Vec3i weight_color = value_to_rgbi(min_weight, max_weight,
-comparator.compute_angle_penalty(point.local_ccw_angle)); -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::string weight_fill = "rgb(" + std::to_string(weight_color.x()) + "," + std::to_string(weight_color.y())
+ "," + ","
+ std::to_string(weight_color.z()) + ")"; + std::to_string(weight_color.z()) + ")";
@ -1090,13 +1072,11 @@ public:
void SeamPlacer::gather_seam_candidates(const PrintObject *po, void SeamPlacer::gather_seam_candidates(const PrintObject *po,
const SeamPlacerImpl::GlobalModelInfo &global_model_info, const SeamPosition configured_seam_preference) { const SeamPlacerImpl::GlobalModelInfo &global_model_info, const SeamPosition configured_seam_preference) {
using namespace SeamPlacerImpl; using namespace SeamPlacerImpl;
bool arachne_generated = po->config().perimeter_generator == PerimeterGeneratorType::Arachne;
PrintObjectSeamData &seam_data = m_seam_per_object.emplace(po, PrintObjectSeamData { }).first->second; PrintObjectSeamData &seam_data = m_seam_per_object.emplace(po, PrintObjectSeamData { }).first->second;
seam_data.layers.resize(po->layer_count()); seam_data.layers.resize(po->layer_count());
tbb::parallel_for(tbb::blocked_range<size_t>(0, po->layers().size()), tbb::parallel_for(tbb::blocked_range<size_t>(0, po->layers().size()),
[po, configured_seam_preference, arachne_generated, &global_model_info, &seam_data] [po, configured_seam_preference, &global_model_info, &seam_data]
(tbb::blocked_range<size_t> r) { (tbb::blocked_range<size_t> r) {
for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) { for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) {
PrintObjectSeamData::LayerSeams &layer_seams = seam_data.layers[layer_idx]; PrintObjectSeamData::LayerSeams &layer_seams = seam_data.layers[layer_idx];
@ -1107,7 +1087,7 @@ void SeamPlacer::gather_seam_candidates(const PrintObject *po,
Polygons polygons = extract_perimeter_polygons(layer, configured_seam_preference, regions); Polygons polygons = extract_perimeter_polygons(layer, configured_seam_preference, regions);
for (size_t poly_index = 0; poly_index < polygons.size(); ++poly_index) { for (size_t poly_index = 0; poly_index < polygons.size(); ++poly_index) {
process_perimeter_polygon(polygons[poly_index], unscaled_z, process_perimeter_polygon(polygons[poly_index], unscaled_z,
regions[poly_index], arachne_generated, global_model_info, layer_seams); regions[poly_index], global_model_info, layer_seams);
} }
auto functor = SeamCandidateCoordinateFunctor { layer_seams.points }; auto functor = SeamCandidateCoordinateFunctor { layer_seams.points };
seam_data.layers[layer_idx].points_tree = seam_data.layers[layer_idx].points_tree =
@ -1393,36 +1373,38 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl::
//repeat the alignment for the current seam, since it could be skipped due to alternative path being aligned. //repeat the alignment for the current seam, since it could be skipped due to alternative path being aligned.
global_index--; global_index--;
// gather all positions of seams and their weights (weights are derived as negative penalty, they are made positive in next step) // gather all positions of seams and their weights
observations.resize(seam_string.size()); observations.resize(seam_string.size());
observation_points.resize(seam_string.size()); observation_points.resize(seam_string.size());
weights.resize(seam_string.size()); weights.resize(seam_string.size());
//gather points positions and weights //gather points positions and weights
float total_length = 0.0f; float sharp_length = 0.0f;
Vec3f last_point_pos = layers[seam_string[0].first].points[seam_string[0].second].position; Vec3f last_point_pos = layers[seam_string[0].first].points[seam_string[0].second].position;
for (size_t index = 0; index < seam_string.size(); ++index) { for (size_t index = 0; index < seam_string.size(); ++index) {
Vec3f pos = layers[seam_string[index].first].points[seam_string[index].second].position; const SeamCandidate &point = layers[seam_string[index].first].points[seam_string[index].second];
total_length += (last_point_pos - pos).norm(); Vec3f pos = point.position;
last_point_pos = pos;
observations[index] = pos.head<2>(); observations[index] = pos.head<2>();
observation_points[index] = pos.z(); observation_points[index] = pos.z();
weights[index] = comparator.weight(layers[seam_string[index].first].points[seam_string[index].second]); weights[index] = comparator.weight(point);
float angle_penalty = compute_angle_penalty(point.local_ccw_angle);
float dist = (last_point_pos - pos).norm();
sharp_length += dist * 1.0f / (0.1f + 0.7f*angle_penalty);
bool is_enforced = point.type == EnforcedBlockedSeamPoint::Enforced;
if (is_enforced) sharp_length+= dist;
last_point_pos = pos;
} }
// Curve Fitting // Curve Fitting
size_t number_of_segments = std::max(size_t(1), size_t number_of_segments = std::max(size_t(1),
size_t(total_length / SeamPlacer::seam_align_mm_per_segment)); size_t(sharp_length / SeamPlacer::seam_align_sharp_mm_per_segment));
auto curve = Geometry::fit_cubic_bspline(observations, observation_points, weights, number_of_segments); auto curve = Geometry::fit_cubic_bspline(observations, observation_points, weights, number_of_segments);
// Do alignment - compute fitted point for each point in the string from its Z coord, and store the position into // Do alignment - compute fitted point for each point in the string from its Z coord, and store the position into
// Perimeter structure of the point; also set flag aligned to true // Perimeter structure of the point; also set flag aligned to true
for (size_t index = 0; index < seam_string.size(); ++index) { for (size_t index = 0; index < seam_string.size(); ++index) {
const auto &pair = seam_string[index]; const auto &pair = seam_string[index];
const float t = const float t = std::min(1.0f, weights[index] / 10.0f);
compute_angle_penalty(layers[pair.first].points[pair.second].local_ccw_angle)
< SeamPlacer::sharp_angle_penalty_snapping_threshold
? 0.8f : 0.0f;
Vec3f current_pos = layers[pair.first].points[pair.second].position; Vec3f current_pos = layers[pair.first].points[pair.second].position;
Vec2f fitted_pos = curve.get_fitted_value(current_pos.z()); Vec2f fitted_pos = curve.get_fitted_value(current_pos.z());

View File

@ -150,8 +150,8 @@ public:
static constexpr float seam_align_tolerable_dist = 1.0f; static constexpr float seam_align_tolerable_dist = 1.0f;
// minimum number of seams needed in cluster to make alignment happen // minimum number of seams needed in cluster to make alignment happen
static constexpr size_t seam_align_minimum_string_seams = 6; static constexpr size_t seam_align_minimum_string_seams = 6;
// millimeters covered by spline; determines number of splines for the given string // millimeters of sharp corners covered by spline; determines number of splines for the given string
static constexpr size_t seam_align_mm_per_segment = 4.0f; static constexpr float seam_align_sharp_mm_per_segment = 4.0f;
//The following data structures hold all perimeter points for all PrintObject. //The following data structures hold all perimeter points for all PrintObject.
std::unordered_map<const PrintObject*, PrintObjectSeamData> m_seam_per_object; std::unordered_map<const PrintObject*, PrintObjectSeamData> m_seam_per_object;

View File

@ -175,6 +175,19 @@ PiecewiseFittedCurve<Dimension, NumberType, Kernel> fit_curve(
return result; return result;
} }
template<int Dimension, typename NumberType>
PiecewiseFittedCurve<Dimension, NumberType, LinearKernel<NumberType>>
fit_linear_spline(
const std::vector<Vec<Dimension, NumberType>> &observations,
std::vector<NumberType> observation_points,
std::vector<NumberType> weights,
size_t segments_count,
size_t endpoints_level_of_freedom = 0) {
return fit_curve<LinearKernel<NumberType>>(observations, observation_points, weights, segments_count,
endpoints_level_of_freedom);
}
template<int Dimension, typename NumberType> template<int Dimension, typename NumberType>
PiecewiseFittedCurve<Dimension, NumberType, CubicBSplineKernel<NumberType>> PiecewiseFittedCurve<Dimension, NumberType, CubicBSplineKernel<NumberType>>
fit_cubic_bspline( fit_cubic_bspline(