mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-12 20:49:06 +08:00
workable version, some parameter tweaking probably still needed
This commit is contained in:
parent
e8f740dabb
commit
1a25058456
@ -254,6 +254,38 @@ struct GlobalModelInfo {
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
Polygons extract_perimeter_polygons(const Layer *layer) {
|
||||||
|
Polygons polygons;
|
||||||
|
for (const LayerRegion *layer_region : layer->regions()) {
|
||||||
|
for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
|
||||||
|
if (ex_entity->is_collection()) { //collection of inner, outer, and overhang perimeters
|
||||||
|
for (const ExtrusionEntity *perimeter : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
|
||||||
|
if (perimeter->role() == ExtrusionRole::erExternalPerimeter) {
|
||||||
|
Points p;
|
||||||
|
perimeter->collect_points(p);
|
||||||
|
polygons.push_back(Polygon(p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (polygons.empty()) {
|
||||||
|
Points p;
|
||||||
|
ex_entity->collect_points(p);
|
||||||
|
polygons.push_back(Polygon(p));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Points p;
|
||||||
|
ex_entity->collect_points(p);
|
||||||
|
polygons.push_back(Polygon(p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (polygons.empty()) {
|
||||||
|
polygons.push_back(Polygon { Point { 0, 0 } });
|
||||||
|
}
|
||||||
|
|
||||||
|
return polygons;
|
||||||
|
}
|
||||||
|
|
||||||
void process_perimeter_polygon(const Polygon &orig_polygon, coordf_t z_coord, std::vector<SeamCandidate> &result_vec,
|
void process_perimeter_polygon(const Polygon &orig_polygon, coordf_t z_coord, std::vector<SeamCandidate> &result_vec,
|
||||||
const GlobalModelInfo &global_model_info) {
|
const GlobalModelInfo &global_model_info) {
|
||||||
Polygon polygon = orig_polygon;
|
Polygon polygon = orig_polygon;
|
||||||
@ -416,7 +448,7 @@ void gather_global_model_info(GlobalModelInfo &result, const PrintObject *po) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct DefaultSeamComparator {
|
struct DefaultSeamComparator {
|
||||||
//is a better?
|
//is A better?
|
||||||
bool operator()(const SeamCandidate &a, const SeamCandidate &b) const {
|
bool operator()(const SeamCandidate &a, const SeamCandidate &b) const {
|
||||||
if (a.m_type > b.m_type) {
|
if (a.m_type > b.m_type) {
|
||||||
return true;
|
return true;
|
||||||
@ -425,25 +457,42 @@ struct DefaultSeamComparator {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (a.m_overhang > 0.2 && b.m_overhang < a.m_overhang) {
|
if (a.m_overhang > 0.5 && b.m_overhang < a.m_overhang) {
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (b.m_ccw_angle < -float(0.3 * PI) && a.m_ccw_angle > -float(0.3 * PI)){
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (*b.m_nearby_seam_points > *a.m_nearby_seam_points) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (b.m_visibility < 1.2*a.m_visibility) {
|
if (a.m_ccw_angle < -float(0.4 * PI) && b.m_ccw_angle > -float(0.4 * PI)) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<float> hysteresis_values { 3.0, 2.0, 1.6, 1.2, 1.0 };
|
||||||
|
|
||||||
|
for (float hysteresis : hysteresis_values) {
|
||||||
|
|
||||||
|
if (*a.m_nearby_seam_points > *b.m_nearby_seam_points * hysteresis) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*b.m_nearby_seam_points > *a.m_nearby_seam_points * hysteresis) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.m_visibility * hysteresis < b.m_visibility) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.m_visibility * hysteresis < a.m_visibility) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abs(a.m_ccw_angle) > abs(b.m_ccw_angle)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -469,33 +518,19 @@ for (const PrintObject *po : print.objects()) {
|
|||||||
[&](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) {
|
||||||
std::vector<SeamCandidate> &layer_candidates = m_perimeter_points_per_object[po][layer_idx];
|
std::vector<SeamCandidate> &layer_candidates = m_perimeter_points_per_object[po][layer_idx];
|
||||||
const auto layer = po->get_layer(layer_idx);
|
const Layer *layer = po->get_layer(layer_idx);
|
||||||
auto unscaled_z = layer->slice_z;
|
auto unscaled_z = layer->slice_z;
|
||||||
for (const LayerRegion *layer_region : layer->regions()) {
|
Polygons polygons = extract_perimeter_polygons(layer);
|
||||||
for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
|
|
||||||
Polygons polygons;
|
|
||||||
if (ex_entity->is_collection()) { //collection of inner, outer, and overhang perimeters
|
|
||||||
for (const ExtrusionEntity *perimeter :
|
|
||||||
static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
|
|
||||||
if (perimeter->role() == ExtrusionRole::erExternalPerimeter) {
|
|
||||||
perimeter->polygons_covered_by_width(polygons, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
polygons = ex_entity->polygons_covered_by_width();
|
|
||||||
}
|
|
||||||
for (const auto &poly : polygons) {
|
for (const auto &poly : polygons) {
|
||||||
process_perimeter_polygon(poly, unscaled_z, layer_candidates,
|
process_perimeter_polygon(poly, unscaled_z, layer_candidates,
|
||||||
global_model_info);
|
global_model_info);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
auto functor = SeamCandidateCoordinateFunctor { &layer_candidates };
|
auto functor = SeamCandidateCoordinateFunctor { &layer_candidates };
|
||||||
m_perimeter_points_trees_per_object[po][layer_idx] = (std::make_unique<SeamCandidatesTree>(
|
m_perimeter_points_trees_per_object[po][layer_idx] = (std::make_unique<SeamCandidatesTree>(
|
||||||
functor, layer_candidates.size()));
|
functor, layer_candidates.size()));
|
||||||
|
|
||||||
}
|
}
|
||||||
} );
|
}
|
||||||
|
);
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug)
|
BOOST_LOG_TRIVIAL(debug)
|
||||||
<< "SeamPlacer: gather and build KD tree with seam candidates: end";
|
<< "SeamPlacer: gather and build KD tree with seam candidates: end";
|
||||||
@ -548,6 +583,7 @@ for (const PrintObject *po : print.objects()) {
|
|||||||
<< "SeamPlacer: compute overhangs : end";
|
<< "SeamPlacer: compute overhangs : end";
|
||||||
|
|
||||||
for (size_t iteration = 0; iteration < seam_align_iterations; ++iteration) {
|
for (size_t iteration = 0; iteration < seam_align_iterations; ++iteration) {
|
||||||
|
|
||||||
if (iteration > 0) { //skip this in first iteration, no seam has been picked yet
|
if (iteration > 0) { //skip this in first iteration, no seam has been picked yet
|
||||||
BOOST_LOG_TRIVIAL(debug)
|
BOOST_LOG_TRIVIAL(debug)
|
||||||
<< "SeamPlacer: distribute seam positions to other layers : start";
|
<< "SeamPlacer: distribute seam positions to other layers : start";
|
||||||
@ -559,24 +595,58 @@ for (const PrintObject *po : print.objects()) {
|
|||||||
m_perimeter_points_per_object[po][layer_idx];
|
m_perimeter_points_per_object[po][layer_idx];
|
||||||
size_t current = 0;
|
size_t current = 0;
|
||||||
while (current < layer_perimeter_points.size()) {
|
while (current < layer_perimeter_points.size()) {
|
||||||
auto seam_position =
|
Vec3d seam_position =
|
||||||
layer_perimeter_points[layer_perimeter_points[current].m_seam_index].m_position;
|
layer_perimeter_points[layer_perimeter_points[current].m_seam_index].m_position;
|
||||||
|
|
||||||
size_t other_layer_idx_start = std::max(
|
int other_layer_idx_bottom = std::max(
|
||||||
(int) layer_idx - (int) seam_align_layer_dist, 0);
|
(int) layer_idx - (int) seam_align_layer_dist, 0);
|
||||||
size_t other_layer_idx_end = std::min(layer_idx + seam_align_layer_dist,
|
int other_layer_idx_top = std::min(layer_idx + seam_align_layer_dist,
|
||||||
m_perimeter_points_per_object[po].size() - 1);
|
m_perimeter_points_per_object[po].size() - 1);
|
||||||
|
|
||||||
for (size_t other_layer_idx = other_layer_idx_start;
|
Vec3d seam_projected_position = seam_position;
|
||||||
other_layer_idx <= other_layer_idx_end; ++other_layer_idx) {
|
for (int other_layer_idx = layer_idx + 1;
|
||||||
|
other_layer_idx <= other_layer_idx_top; ++other_layer_idx) {
|
||||||
size_t closest_point_idx = find_closest_point(
|
auto layer_z = po->get_layer(other_layer_idx)->slice_z;
|
||||||
|
seam_projected_position = Vec3d { seam_projected_position.x(),
|
||||||
|
seam_projected_position.y(),
|
||||||
|
layer_z };
|
||||||
|
size_t closest_point_index = find_closest_point(
|
||||||
*m_perimeter_points_trees_per_object[po][other_layer_idx],
|
*m_perimeter_points_trees_per_object[po][other_layer_idx],
|
||||||
seam_position);
|
seam_projected_position);
|
||||||
|
SeamCandidate &closest_point =
|
||||||
|
m_perimeter_points_per_object[po][other_layer_idx][closest_point_index];
|
||||||
|
double distance = (seam_projected_position - closest_point.m_position).norm();
|
||||||
|
|
||||||
m_perimeter_points_per_object[po][other_layer_idx][closest_point_idx].m_nearby_seam_points->fetch_add(
|
if (distance < seam_align_tolerable_dist) {
|
||||||
1, std::memory_order_relaxed);
|
closest_point.m_nearby_seam_points->fetch_add(1, std::memory_order_relaxed);
|
||||||
|
seam_projected_position = closest_point.m_position;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
seam_projected_position = seam_position;
|
||||||
|
if (layer_idx > 0) {
|
||||||
|
for (int other_layer_idx = layer_idx - 1;
|
||||||
|
other_layer_idx >= other_layer_idx_bottom; --other_layer_idx) {
|
||||||
|
auto layer_z = po->get_layer(other_layer_idx)->slice_z;
|
||||||
|
seam_projected_position = Vec3d { seam_projected_position.x(),
|
||||||
|
seam_projected_position.y(),
|
||||||
|
layer_z };
|
||||||
|
size_t closest_point_index = find_closest_point(
|
||||||
|
*m_perimeter_points_trees_per_object[po][other_layer_idx],
|
||||||
|
seam_projected_position);
|
||||||
|
SeamCandidate &closest_point =
|
||||||
|
m_perimeter_points_per_object[po][other_layer_idx][closest_point_index];
|
||||||
|
double distance = (seam_projected_position - closest_point.m_position).norm();
|
||||||
|
|
||||||
|
if (distance < seam_align_tolerable_dist) {
|
||||||
|
closest_point.m_nearby_seam_points->fetch_add(1, std::memory_order_relaxed);
|
||||||
|
seam_projected_position = closest_point.m_position;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
current += layer_perimeter_points[current].m_polygon_index_reverse + 1;
|
current += layer_perimeter_points[current].m_polygon_index_reverse + 1;
|
||||||
@ -586,6 +656,25 @@ for (const PrintObject *po : print.objects()) {
|
|||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug)
|
BOOST_LOG_TRIVIAL(debug)
|
||||||
<< "SeamPlacer: distribute seam positions to other layers : end";
|
<< "SeamPlacer: distribute seam positions to other layers : end";
|
||||||
|
|
||||||
|
Slic3r::CNumericLocalesSetter locales_setter;
|
||||||
|
FILE *fp = boost::nowide::fopen("seams.obj", "w");
|
||||||
|
if (fp == nullptr) {
|
||||||
|
BOOST_LOG_TRIVIAL(error)
|
||||||
|
<< "Couldn't open " << "seams.obj" << " for writing";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t layer_idx = 0; layer_idx < m_perimeter_points_per_object[po].size(); ++layer_idx) {
|
||||||
|
const auto &points = m_perimeter_points_per_object[po][layer_idx];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < points.size(); ++i)
|
||||||
|
fprintf(fp, "v %f %f %f %zu\n", points[i].m_position[0], points[i].m_position[1],
|
||||||
|
points[i].m_position[2],
|
||||||
|
points[i].m_nearby_seam_points.get()->load(std::memory_order_relaxed));
|
||||||
|
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug)
|
BOOST_LOG_TRIVIAL(debug)
|
||||||
@ -624,12 +713,6 @@ const auto &perimeter_points = m_perimeter_points_per_object[po][layer_index];
|
|||||||
|
|
||||||
const Point &fp = loop.first_point();
|
const Point &fp = loop.first_point();
|
||||||
|
|
||||||
//This is backup check, so that slicer does not crash if something weird is going on
|
|
||||||
if (perimeter_points.empty()) {
|
|
||||||
BOOST_LOG_TRIVIAL(error)
|
|
||||||
<< "SeamPlacer: Trying to place seam for index which does not contain any outer or overhang perimeter points, maybe new perimeter type option?";
|
|
||||||
loop.split_at(fp, true);
|
|
||||||
} else {
|
|
||||||
auto unscaled_p = unscale(fp);
|
auto unscaled_p = unscale(fp);
|
||||||
auto closest_perimeter_point_index = find_closest_point(perimeter_points_tree,
|
auto closest_perimeter_point_index = find_closest_point(perimeter_points_tree,
|
||||||
Vec3d { unscaled_p.x(), unscaled_p.y(), unscaled_z });
|
Vec3d { unscaled_p.x(), unscaled_p.y(), unscaled_z });
|
||||||
@ -643,7 +726,6 @@ if (perimeter_points.empty()) {
|
|||||||
// Insert it.
|
// Insert it.
|
||||||
loop.split_at(seam_point, true);
|
loop.split_at(seam_point, true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_FILES
|
#ifdef DEBUG_FILES
|
||||||
Slic3r::CNumericLocalesSetter locales_setter;
|
Slic3r::CNumericLocalesSetter locales_setter;
|
||||||
|
@ -80,12 +80,13 @@ public:
|
|||||||
using SeamCandidatesTree =
|
using SeamCandidatesTree =
|
||||||
KDTreeIndirect<3, coordf_t, SeamPlacerImpl::SeamCandidateCoordinateFunctor>;
|
KDTreeIndirect<3, coordf_t, SeamPlacerImpl::SeamCandidateCoordinateFunctor>;
|
||||||
static constexpr size_t ray_count_per_object = 200000;
|
static constexpr size_t ray_count_per_object = 200000;
|
||||||
static constexpr double considered_hits_distance = 3.0;
|
static constexpr double considered_hits_distance = 4.0;
|
||||||
static constexpr float cosine_hemisphere_sampling_power = 1.5;
|
static constexpr float cosine_hemisphere_sampling_power = 1.5;
|
||||||
static constexpr float polygon_angles_arm_distance = 0.6;
|
static constexpr float polygon_angles_arm_distance = 0.6;
|
||||||
static constexpr float enforcer_blocker_sqr_distance_tolerance = 0.04;
|
static constexpr float enforcer_blocker_sqr_distance_tolerance = 0.2;
|
||||||
static constexpr size_t seam_align_iterations = 3;
|
static constexpr size_t seam_align_iterations = 10;
|
||||||
static constexpr size_t seam_align_layer_dist = 50;
|
static constexpr size_t seam_align_layer_dist = 30;
|
||||||
|
static constexpr float seam_align_tolerable_dist = 1;
|
||||||
//perimeter points per object per layer idx, and their corresponding KD trees
|
//perimeter points per object per layer idx, and their corresponding KD trees
|
||||||
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;
|
||||||
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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user