mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 04:25:57 +08:00
Sample only overhanging part of layer.
This commit is contained in:
parent
a3febc3b3d
commit
3906b7dafc
@ -135,37 +135,6 @@ Point intersection(const Point &p1, const Point &p2, const Point &cnt, double r2
|
||||
return {};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uniformly sample Polygon,
|
||||
/// Use first point and each next point is first crosing radius from last added
|
||||
/// </summary>
|
||||
/// <param name="p">Polygon to sample</param>
|
||||
/// <param name="dist2">Squared distance for sampling</param>
|
||||
/// <returns>Uniformly distributed points laying on input polygon
|
||||
/// with exception of first and last point(they are closer than dist2)</returns>
|
||||
Slic3r::Points sample(const Polygon &p, double dist2) {
|
||||
if (p.empty())
|
||||
return {};
|
||||
|
||||
Slic3r::Points r;
|
||||
r.push_back(p.front());
|
||||
const Point *prev_pt = nullptr;
|
||||
for (size_t prev_i = 0; prev_i < p.size(); prev_i++) {
|
||||
size_t curr_i = (prev_i != p.size() - 1) ? prev_i + 1 : 0;
|
||||
const Point &pt = p.points[curr_i];
|
||||
double p_dist2 = (r.back() - pt).cast<double>().squaredNorm();
|
||||
while (p_dist2 > dist2) { // line segment goes out of radius
|
||||
if (prev_pt == nullptr)
|
||||
prev_pt = &p.points[prev_i];
|
||||
r.push_back(intersection(*prev_pt, pt, r.back(), dist2));
|
||||
p_dist2 = (r.back() - pt).cast<double>().squaredNorm();
|
||||
prev_pt = &r.back();
|
||||
}
|
||||
prev_pt = nullptr;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
coord_t get_supported_radius(const LayerSupportPoint &p, float z_distance, const SupportPointGeneratorConfig &config
|
||||
) {
|
||||
// TODO: calculate support radius
|
||||
@ -265,8 +234,158 @@ Grid2D support_island(const LayerPart &part, float part_z, const SupportPointGen
|
||||
return part_grid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy parts from link to output
|
||||
/// </summary>
|
||||
/// <param name="part_links">Links between part of mesh</param>
|
||||
/// <returns>Collected polygons from links</returns>
|
||||
Polygons get_polygons(const PartLinks& part_links) {
|
||||
size_t cnt = 0;
|
||||
for (const PartLink &part_link : part_links)
|
||||
cnt += 1 + part_link.part_it->shape->holes.size();
|
||||
|
||||
Polygons out;
|
||||
out.reserve(cnt);
|
||||
for (const PartLink &part_link : part_links) {
|
||||
const ExPolygon &shape = *part_link.part_it->shape;
|
||||
out.emplace_back(shape.contour);
|
||||
append(out, shape.holes);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uniformly sample Polyline,
|
||||
/// Use first point and each next point is first crosing radius from last added
|
||||
/// </summary>
|
||||
/// <param name="b">Begin of polyline points to sample</param>
|
||||
/// <param name="e">End of polyline points to sample</param>
|
||||
/// <param name="dist2">Squared distance for sampling</param>
|
||||
/// <returns>Uniformly distributed points laying on input polygon
|
||||
/// with exception of first and last point(they are closer than dist2)</returns>
|
||||
Slic3r::Points sample(Points::const_iterator b, Points::const_iterator e, double dist2) {
|
||||
assert(e-b >= 2);
|
||||
if (e - b < 2)
|
||||
return {}; // at least one line(2 points)
|
||||
|
||||
// IMPROVE1: start of sampling e.g. center of Polyline
|
||||
// IMPROVE2: Random offset(To remove align of point between slices)
|
||||
// IMPROVE3: Sample small overhangs with memory for last sample(OR in center)
|
||||
Slic3r::Points r;
|
||||
r.push_back(*b);
|
||||
|
||||
Points::const_iterator prev_pt = e;
|
||||
for (Points::const_iterator it = b; it+1 < e; ++it){
|
||||
const Point &pt = *(it+1);
|
||||
double p_dist2 = (r.back() - pt).cast<double>().squaredNorm();
|
||||
while (p_dist2 > dist2) { // line segment goes out of radius
|
||||
if (prev_pt == e)
|
||||
prev_pt = it;
|
||||
r.push_back(intersection(*prev_pt, pt, r.back(), dist2));
|
||||
p_dist2 = (r.back() - pt).cast<double>().squaredNorm();
|
||||
prev_pt = r.end()-1; // r.back()
|
||||
}
|
||||
prev_pt = e;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool contain_point(const Point &p, const Points &sorted_points) {
|
||||
auto it = std::lower_bound(sorted_points.begin(), sorted_points.end(), p);
|
||||
if (it == sorted_points.end())
|
||||
return false;
|
||||
++it; // next point should be same as searched
|
||||
if (it == sorted_points.end())
|
||||
return false;
|
||||
return it->x() == p.x() && it->y() == p.y();
|
||||
};
|
||||
|
||||
bool exist_same_points(const ExPolygon &shape, const Points& prev_points) {
|
||||
auto shape_points = to_points(shape);
|
||||
return shape_points.end() !=
|
||||
std::find_if(shape_points.begin(), shape_points.end(), [&prev_points](const Point &p) {
|
||||
return contain_point(p, prev_points);
|
||||
});
|
||||
}
|
||||
|
||||
Points sample_overhangs(const LayerPart& part, double dist2) {
|
||||
const ExPolygon &shape = *part.shape;
|
||||
|
||||
// Collect previous expolygons by links collected in loop before
|
||||
Polygons prev_polygons = get_polygons(part.prev_parts);
|
||||
assert(!prev_polygons.empty());
|
||||
ExPolygons overhangs = diff_ex(shape, prev_polygons);
|
||||
if (overhangs.empty()) // above part is smaller in whole contour
|
||||
return {};
|
||||
|
||||
Points prev_points = to_points(prev_polygons);
|
||||
std::sort(prev_points.begin(), prev_points.end());
|
||||
|
||||
// TODO: solve case when shape and prev points has same point
|
||||
assert(!exist_same_points(shape, prev_points));
|
||||
|
||||
auto sample_overhang = [&prev_points, dist2](const Polygon &polygon, Points &samples) {
|
||||
const Points &pts = polygon.points;
|
||||
// first point which is not part of shape
|
||||
Points::const_iterator first_bad = pts.end();
|
||||
Points::const_iterator start_it = pts.end();
|
||||
for (auto it = pts.begin(); it != pts.end(); ++it) {
|
||||
const Point &p = *it;
|
||||
if (contain_point(p, prev_points)) {
|
||||
if (first_bad == pts.end()) {
|
||||
// remember begining
|
||||
first_bad = it;
|
||||
}
|
||||
if (start_it != pts.end()) {
|
||||
// finish sampling
|
||||
append(samples, sample(start_it, it, dist2));
|
||||
// prepare for new start
|
||||
start_it = pts.end();
|
||||
}
|
||||
} else if (start_it == pts.end()) {
|
||||
start_it = it;
|
||||
}
|
||||
}
|
||||
|
||||
// sample last segment
|
||||
if (start_it == pts.end()) { // tail is without points
|
||||
if (first_bad != pts.begin()) // only begining
|
||||
append(samples, sample(pts.begin(), first_bad, dist2));
|
||||
} else { // tail contain points
|
||||
if (first_bad == pts.begin()) { // only tail
|
||||
append(samples, sample(start_it, pts.end(), dist2));
|
||||
} else if (start_it == pts.begin()) { // whole polygon is overhang
|
||||
assert(first_bad == pts.end());
|
||||
Points pts2 = pts; // copy
|
||||
pts2.push_back(pts.front());
|
||||
append(samples, sample(pts2.begin(), pts2.end(), dist2));
|
||||
} else { // need connect begining and tail
|
||||
Points pts2;
|
||||
pts2.reserve((pts.end() - start_it) +
|
||||
(first_bad - pts.begin()));
|
||||
for (auto it = start_it; it < pts.end(); ++it)
|
||||
pts2.push_back(*it);
|
||||
for (auto it = pts.begin(); it < first_bad; ++it)
|
||||
pts2.push_back(*it);
|
||||
append(samples, sample(pts2.begin(), pts2.end(), dist2));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Points samples;
|
||||
for (const ExPolygon &overhang : overhangs) {
|
||||
sample_overhang(overhang.contour, samples);
|
||||
for (const Polygon &hole : overhang.holes) {
|
||||
sample_overhang(hole, samples);
|
||||
}
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#include "libslic3r/Execution/ExecutionSeq.hpp"
|
||||
|
||||
SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
|
||||
std::vector<ExPolygons> &&slices,
|
||||
std::vector<float> &&heights,
|
||||
@ -295,24 +414,24 @@ SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
|
||||
// CPU write caches due to synchronization primitves.
|
||||
throw_on_cancel();
|
||||
|
||||
const double sample_distance_in_mm = scale_(2);
|
||||
const double sample_distance_in_mm2 = sample_distance_in_mm * sample_distance_in_mm;
|
||||
|
||||
Layer &layer = result.layers[layer_id];
|
||||
const ExPolygons &islands = result.slices[layer_id];
|
||||
layer.parts.reserve(islands.size());
|
||||
for (const ExPolygon &island : islands)
|
||||
for (const ExPolygon &island : islands) {
|
||||
layer.parts.push_back(LayerPart{
|
||||
&island,
|
||||
get_extents(island.contour),
|
||||
sample(island.contour, sample_distance_in_mm2)
|
||||
get_extents(island.contour)
|
||||
// sample - only hangout part of expolygon could be known after linking
|
||||
});
|
||||
|
||||
}
|
||||
}, 32 /*gransize*/);
|
||||
|
||||
const double sample_distance_in_mm = scale_(2);
|
||||
const double sample_distance_in_mm2 = sample_distance_in_mm * sample_distance_in_mm;
|
||||
|
||||
// Link parts by intersections
|
||||
execution::for_each(ex_tbb, size_t(1), result.slices.size(),
|
||||
[&result, throw_on_cancel] (size_t layer_id) {
|
||||
execution::for_each(ex_seq, size_t(1), result.slices.size(),
|
||||
[&result, sample_distance_in_mm2, throw_on_cancel](size_t layer_id) {
|
||||
if ((layer_id % 2) == 0)
|
||||
// Don't call the following function too often as it flushes CPU write caches due to synchronization primitves.
|
||||
throw_on_cancel();
|
||||
@ -335,6 +454,14 @@ SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
|
||||
it_above->prev_parts.emplace_back(PartLink{it_below});
|
||||
it_below->next_parts.emplace_back(PartLink{it_above});
|
||||
}
|
||||
|
||||
if (it_above->prev_parts.empty())
|
||||
continue;
|
||||
|
||||
// IMPROVE: overhangs could be calculated with Z coordninate
|
||||
// soo one will know source shape of point and do not have to search this information
|
||||
// Get inspiration at https://github.com/Prusa-Development/PrusaSlicerPrivate/blob/e00c46f070ec3d6fc325640b0dd10511f8acf5f7/src/libslic3r/PerimeterGenerator.cpp#L399
|
||||
it_above->samples = sample_overhangs(*it_above, sample_distance_in_mm2);
|
||||
}
|
||||
}, 8 /* gransize */);
|
||||
return result;
|
||||
|
Loading…
x
Reference in New Issue
Block a user