computing smooth score instead of binary decision when picking seams

some basic documentation
This commit is contained in:
PavelMikus 2022-03-01 17:29:55 +01:00
parent 105b67c9a7
commit c72687c96c
2 changed files with 48 additions and 53 deletions

View file

@ -518,12 +518,6 @@ void pick_seam_point(std::vector<SeamCandidate> &perimeter_points, size_t start_
indices[index - start_index] = index; indices[index - start_index] = index;
} }
std::sort(indices.begin(), indices.end(),
[&](size_t left, size_t right) {
return std::abs(perimeter_points[left].local_ccw_angle - 0.1 * PI)
> std::abs(perimeter_points[right].local_ccw_angle - 0.1 * PI);
});
size_t seam_index = indices[0]; size_t seam_index = indices[0];
for (size_t index : indices) { for (size_t index : indices) {
if (comparator.is_first_better(perimeter_points[index], perimeter_points[seam_index])) { if (comparator.is_first_better(perimeter_points[index], perimeter_points[seam_index])) {
@ -580,17 +574,13 @@ void gather_global_model_info(GlobalModelInfo &result, const PrintObject *po) {
} }
struct DefaultSeamComparator { struct DefaultSeamComparator {
static constexpr float angle_clusters[] { -1.0, 0.4 * PI, 0.65 * PI, 0.9 * PI }; float compute_angle_penalty(float ccw_angle) const {
if (ccw_angle >= 0) {
return PI - ccw_angle;
} else {
return (PI - ccw_angle) * 1.1f;
}
const float get_angle_category(float ccw_angle) const {
float concave_bonus = ccw_angle < 0 ? 0.1 * PI : 0;
float abs_angle = abs(ccw_angle) + concave_bonus;
auto category = std::find_if_not(std::begin(angle_clusters), std::end(angle_clusters),
[&](float category_limit) {
return abs_angle > category_limit;
});
category--;
return *category;
} }
bool is_first_better(const SeamCandidate &a, const SeamCandidate &b) const { bool is_first_better(const SeamCandidate &a, const SeamCandidate &b) const {
@ -603,24 +593,12 @@ struct DefaultSeamComparator {
} }
//avoid overhangs //avoid overhangs
if (a.overhang > 0.3f && b.overhang < a.overhang) { if (a.overhang > 0.2f && b.overhang < a.overhang) {
return false; return false;
} }
{ //local angles return (a.visibility + 0.01) * compute_angle_penalty(a.local_ccw_angle) <
float a_local_category = get_angle_category(a.local_ccw_angle); (b.visibility + 0.01) * compute_angle_penalty(b.local_ccw_angle);
float b_local_category = get_angle_category(b.local_ccw_angle);
if (a_local_category > b_local_category) {
return true;
}
if (a_local_category < b_local_category) {
return false;
}
}
return a.visibility < b.visibility;
} }
bool is_first_not_much_worse(const SeamCandidate &a, const SeamCandidate &b) const { bool is_first_not_much_worse(const SeamCandidate &a, const SeamCandidate &b) const {
@ -633,24 +611,12 @@ struct DefaultSeamComparator {
} }
//avoid overhangs //avoid overhangs
if (a.overhang > 0.3f && b.overhang < a.overhang) { if (a.overhang > 0.2f && b.overhang < a.overhang) {
return false; return false;
} }
{ //local angles return (a.visibility + 0.01) * compute_angle_penalty(a.local_ccw_angle) * 0.8f <=
float a_local_category = get_angle_category(a.local_ccw_angle); (b.visibility + 0.01) * compute_angle_penalty(b.local_ccw_angle);
float b_local_category = get_angle_category(b.local_ccw_angle);
if (a_local_category > b_local_category) {
return true;
}
if (a_local_category < b_local_category) {
return false;
}
}
return (a.visibility <= b.visibility
|| (std::abs(a.visibility - b.visibility) < SeamPlacer::expected_hits_per_area / 17.0f));
} }
} }
; ;
@ -814,7 +780,15 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const Comparator &comp
std::sort(seams.begin(), seams.end(), std::sort(seams.begin(), seams.end(),
[&](const std::pair<size_t, size_t> &left, const std::pair<size_t, size_t> &right) { [&](const std::pair<size_t, size_t> &left, const std::pair<size_t, size_t> &right) {
return m_perimeter_points_per_object[po][left.first][left.second].visibility return m_perimeter_points_per_object[po][left.first][left.second].visibility
< m_perimeter_points_per_object[po][right.first][right.second].visibility; * (1.2 * PI
- std::abs(
m_perimeter_points_per_object[po][left.first][left.second].local_ccw_angle
- 0.2 * PI))
< m_perimeter_points_per_object[po][right.first][right.second].visibility
* (1.2 * PI
- std::abs(
m_perimeter_points_per_object[po][right.first][right.second].local_ccw_angle
- 0.2 * PI));
} }
); );
@ -889,7 +863,7 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const Comparator &comp
// //https://en.wikipedia.org/wiki/Exponential_smoothing // //https://en.wikipedia.org/wiki/Exponential_smoothing
// //inititalization // //inititalization
// float smoothing_factor = SeamPlacer::seam_align_strength; // float smoothing_factor = 0.8;
// std::pair<size_t, size_t> init = seam_string[0]; // std::pair<size_t, size_t> init = seam_string[0];
// Vec2f prev_pos_xy = m_perimeter_points_per_object[po][init.first][init.second].position.head<2>(); // Vec2f prev_pos_xy = m_perimeter_points_per_object[po][init.first][init.second].position.head<2>();
// for (const auto &pair : seam_string) { // for (const auto &pair : seam_string) {

View file

@ -34,32 +34,38 @@ enum class EnforcedBlockedSeamPoint {
Enforced = 2, Enforced = 2,
}; };
// struct representing single perimeter loop
struct Perimeter { struct Perimeter {
size_t start_index; size_t start_index;
size_t end_index; //inclusive! size_t end_index; //inclusive!
size_t seam_index; size_t seam_index;
// During alignment, a final position may be stored here. In that case, aligned is set to true.
// Note that final seam position is not limited to points of the perimeter loop. In theory it can be any position
bool aligned = false; bool aligned = false;
Vec3f final_seam_position; Vec3f final_seam_position;
}; };
//Struct over which all processing of perimeters is done. For each perimeter point, its respective candidate is created,
// then all the needed attributes are computed and finally, for each perimeter one point is chosen as seam.
// This seam position can be than further aligned
struct SeamCandidate { struct SeamCandidate {
SeamCandidate(const Vec3f &pos, std::shared_ptr<Perimeter> perimeter, SeamCandidate(const Vec3f &pos, std::shared_ptr<Perimeter> perimeter,
float local_ccw_angle, float local_ccw_angle,
EnforcedBlockedSeamPoint type) : EnforcedBlockedSeamPoint type) :
position(pos), perimeter(perimeter), visibility(0.0f), overhang(0.0f), higher_layer_overhang( position(pos), perimeter(perimeter), visibility(0.0f), overhang(0.0f), local_ccw_angle(
0.0f), local_ccw_angle(
local_ccw_angle), type(type) { local_ccw_angle), type(type) {
} }
const Vec3f position; const Vec3f position;
// pointer to Perimter loop of this point. It is shared across all points of the loop
const std::shared_ptr<Perimeter> perimeter; const std::shared_ptr<Perimeter> perimeter;
float visibility; float visibility;
float overhang; float overhang;
float higher_layer_overhang; // represents how much is the position covered by the upper layer, useful for local visibility
float local_ccw_angle; float local_ccw_angle;
EnforcedBlockedSeamPoint type; EnforcedBlockedSeamPoint type;
}; };
// struct to represent hits of the mesh during occulision raycasting.
struct HitInfo { struct HitInfo {
Vec3f position; Vec3f position;
Vec3f surface_normal; Vec3f surface_normal;
@ -90,22 +96,37 @@ class SeamPlacer {
public: public:
using SeamCandidatesTree = using SeamCandidatesTree =
KDTreeIndirect<3, float, SeamPlacerImpl::SeamCandidateCoordinateFunctor>; KDTreeIndirect<3, float, SeamPlacerImpl::SeamCandidateCoordinateFunctor>;
// Rough estimates of hits of the mesh during raycasting per surface circle defined by considered_area_radius
static constexpr float expected_hits_per_area = 600.0f; static constexpr float expected_hits_per_area = 600.0f;
// area considered when computing number of rays and then gathering visiblity info from the hits
static constexpr float considered_area_radius = 3.0f; static constexpr float considered_area_radius = 3.0f;
static constexpr float raycasting_decimation_target_error = 0.6f; // quadric error limit of quadric decimation function used on the mesh before raycasting
static constexpr float raycasting_decimation_target_error = 0.3f;
// cosine sampling power represents how prefered are forward directions when raycasting from given spot
// in this case, forward direction means towards the center of the mesh
static constexpr float cosine_hemisphere_sampling_power = 4.0f; static constexpr float cosine_hemisphere_sampling_power = 4.0f;
// arm length used during angles computation
static constexpr float polygon_local_angles_arm_distance = 0.6f; static constexpr float polygon_local_angles_arm_distance = 0.6f;
// If enforcer or blocker is closer to the seam candidate than this limit, the seam candidate is set to Blocer or Enforcer
static constexpr float enforcer_blocker_sqr_distance_tolerance = 0.2f; static constexpr float enforcer_blocker_sqr_distance_tolerance = 0.2f;
// When searching for seam clusters for alignment:
// seam_align_tolerable_dist - if seam is closer to the previous seam position projected to the current layer than this value,
//it belongs automaticaly to the cluster
static constexpr float seam_align_tolerable_dist = 1.0f; 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.
// this param limits the number of allowed skips
static constexpr size_t seam_align_tolerable_skips = 6; static constexpr size_t seam_align_tolerable_skips = 6;
// minimum number of seams needed in cluster to make alignemnt happen
static constexpr size_t seam_align_minimum_string_seams = 5; static constexpr size_t seam_align_minimum_string_seams = 5;
//perimeter points per object per layer idx, and their corresponding KD trees //The following data structures hold all perimeter points for all PrintObject. The structure is as follows:
// Map of PrintObjects (PO) -> vector of layers of PO -> vector of perimeter points of the given layer
std::unordered_map<const PrintObject*, std::vector<std::vector<SeamPlacerImpl::SeamCandidate>>> m_perimeter_points_per_object; std::unordered_map<const PrintObject*, std::vector<std::vector<SeamPlacerImpl::SeamCandidate>>> m_perimeter_points_per_object;
// Map of PrintObjects (PO) -> vector of layers of PO -> unique_ptr to KD tree of all points of the given layer
std::unordered_map<const PrintObject*, std::vector<std::unique_ptr<SeamCandidatesTree>>> m_perimeter_points_trees_per_object; std::unordered_map<const PrintObject*, std::vector<std::unique_ptr<SeamCandidatesTree>>> m_perimeter_points_trees_per_object;
void init(const Print &print); void init(const Print &print);