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
// 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,
bool arachne_generated, const GlobalModelInfo &global_model_info, PrintObjectSeamData::LayerSeams &result) {
const GlobalModelInfo &global_model_info, PrintObjectSeamData::LayerSeams &result) {
if (orig_polygon.size() == 0) {
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,
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( { });
Perimeter &perimeter = result.perimeters.back();
@ -531,13 +512,14 @@ void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const
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;
}
if (global_model_info.is_blocked(position, perimeter.flow_width)) {
type = EnforcedBlockedSeamPoint::Blocked;
}
some_point_enforced = some_point_enforced || type == EnforcedBlockedSeamPoint::Enforced;
if (orig_point) {
@ -880,9 +862,9 @@ struct SeamComparator {
float weight(const SeamCandidate &a) const {
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);
max_vis = std::max(max_vis, point.visibility);
min_weight = std::min(min_weight, -comparator.compute_angle_penalty(point.local_ccw_angle));
max_weight = std::max(max_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, -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);
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::to_string(weight_color.z()) + ")";
@ -1090,13 +1072,11 @@ public:
void SeamPlacer::gather_seam_candidates(const PrintObject *po,
const SeamPlacerImpl::GlobalModelInfo &global_model_info, const SeamPosition configured_seam_preference) {
using namespace SeamPlacerImpl;
bool arachne_generated = po->config().perimeter_generator == PerimeterGeneratorType::Arachne;
PrintObjectSeamData &seam_data = m_seam_per_object.emplace(po, PrintObjectSeamData { }).first->second;
seam_data.layers.resize(po->layer_count());
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) {
for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++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);
for (size_t poly_index = 0; poly_index < polygons.size(); ++poly_index) {
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 };
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.
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());
observation_points.resize(seam_string.size());
weights.resize(seam_string.size());
//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;
for (size_t index = 0; index < seam_string.size(); ++index) {
Vec3f pos = layers[seam_string[index].first].points[seam_string[index].second].position;
total_length += (last_point_pos - pos).norm();
last_point_pos = pos;
const SeamCandidate &point = layers[seam_string[index].first].points[seam_string[index].second];
Vec3f pos = point.position;
observations[index] = pos.head<2>();
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
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);
// 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
for (size_t index = 0; index < seam_string.size(); ++index) {
const auto &pair = seam_string[index];
const float t =
compute_angle_penalty(layers[pair.first].points[pair.second].local_ccw_angle)
< SeamPlacer::sharp_angle_penalty_snapping_threshold
? 0.8f : 0.0f;
const float t = std::min(1.0f, weights[index] / 10.0f);
Vec3f current_pos = layers[pair.first].points[pair.second].position;
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;
// minimum number of seams needed in cluster to make alignment happen
static constexpr size_t seam_align_minimum_string_seams = 6;
// millimeters covered by spline; determines number of splines for the given string
static constexpr size_t seam_align_mm_per_segment = 4.0f;
// millimeters of sharp corners covered by spline; determines number of splines for the given string
static constexpr float seam_align_sharp_mm_per_segment = 4.0f;
//The following data structures hold all perimeter points for all PrintObject.
std::unordered_map<const PrintObject*, PrintObjectSeamData> m_seam_per_object;

View File

@ -175,6 +175,19 @@ PiecewiseFittedCurve<Dimension, NumberType, Kernel> fit_curve(
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>
PiecewiseFittedCurve<Dimension, NumberType, CubicBSplineKernel<NumberType>>
fit_cubic_bspline(