prefer enforcers over blockers, lower the threshold distance,
dynamic modification of segments count in alignment based on smoothnes
This commit is contained in:
parent
a41435d044
commit
44a388d560
@ -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());
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user