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
|
//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());
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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(
|
||||||
|
Loading…
Reference in New Issue
Block a user