mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-15 14:36:02 +08:00
Refactoring and cleanup of BridgeDetector
This commit is contained in:
parent
3f0fea7585
commit
bc35063a57
@ -5,24 +5,6 @@
|
|||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class BridgeDirectionComparator {
|
|
||||||
public:
|
|
||||||
std::map<double,double> dir_coverage; // angle => score
|
|
||||||
|
|
||||||
BridgeDirectionComparator(double _extrusion_width)
|
|
||||||
: extrusion_width(_extrusion_width)
|
|
||||||
{};
|
|
||||||
|
|
||||||
// the best direction is the one causing most lines to be bridged (thus most coverage)
|
|
||||||
bool operator() (double a, double b) {
|
|
||||||
// Initial sort by coverage only - comparator must obey strict weak ordering
|
|
||||||
return (this->dir_coverage[a] > this->dir_coverage[b]);
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
double extrusion_width;
|
|
||||||
};
|
|
||||||
|
|
||||||
BridgeDetector::BridgeDetector(const ExPolygon &_expolygon, const ExPolygonCollection &_lower_slices,
|
BridgeDetector::BridgeDetector(const ExPolygon &_expolygon, const ExPolygonCollection &_lower_slices,
|
||||||
coord_t _extrusion_width)
|
coord_t _extrusion_width)
|
||||||
: expolygon(_expolygon), lower_slices(_lower_slices), extrusion_width(_extrusion_width),
|
: expolygon(_expolygon), lower_slices(_lower_slices), extrusion_width(_extrusion_width),
|
||||||
@ -59,6 +41,8 @@ BridgeDetector::BridgeDetector(const ExPolygon &_expolygon, const ExPolygonColle
|
|||||||
bool
|
bool
|
||||||
BridgeDetector::detect_angle()
|
BridgeDetector::detect_angle()
|
||||||
{
|
{
|
||||||
|
// Do nothing if the bridging region is completely in the air
|
||||||
|
// and there are no anchors available at the layer below.
|
||||||
if (this->_edges.empty() || this->_anchors.empty()) return false;
|
if (this->_edges.empty() || this->_anchors.empty()) return false;
|
||||||
|
|
||||||
/* Outset the bridge expolygon by half the amount we used for detecting anchors;
|
/* Outset the bridge expolygon by half the amount we used for detecting anchors;
|
||||||
@ -70,6 +54,9 @@ BridgeDetector::detect_angle()
|
|||||||
bridge in several directions and then sum the length of lines having both
|
bridge in several directions and then sum the length of lines having both
|
||||||
endpoints within anchors */
|
endpoints within anchors */
|
||||||
|
|
||||||
|
// generate the list of candidate angles
|
||||||
|
std::vector<BridgeDirection> candidates;
|
||||||
|
{
|
||||||
// we test angles according to configured resolution
|
// we test angles according to configured resolution
|
||||||
std::vector<double> angles;
|
std::vector<double> angles;
|
||||||
for (int i = 0; i <= PI/this->resolution; ++i)
|
for (int i = 0; i <= PI/this->resolution; ++i)
|
||||||
@ -106,24 +93,26 @@ BridgeDetector::detect_angle()
|
|||||||
if (Slic3r::Geometry::directions_parallel(angles.front(), angles.back(), min_resolution))
|
if (Slic3r::Geometry::directions_parallel(angles.front(), angles.back(), min_resolution))
|
||||||
angles.pop_back();
|
angles.pop_back();
|
||||||
|
|
||||||
BridgeDirectionComparator bdcomp(this->extrusion_width);
|
for (auto angle : angles)
|
||||||
std::map<double,double> dir_avg_length;
|
candidates.push_back(BridgeDirection(angle));
|
||||||
|
}
|
||||||
|
|
||||||
double line_increment = this->extrusion_width;
|
double line_increment = this->extrusion_width;
|
||||||
bool have_coverage = false;
|
bool have_coverage = false;
|
||||||
for (std::vector<double>::const_iterator angle = angles.begin(); angle != angles.end(); ++angle) {
|
for (BridgeDirection &candidate : candidates) {
|
||||||
Polygons my_clip_area = clip_area;
|
Polygons my_clip_area = clip_area;
|
||||||
ExPolygons my_anchors = this->_anchors;
|
ExPolygons my_anchors = this->_anchors;
|
||||||
|
|
||||||
// rotate everything - the center point doesn't matter
|
// rotate everything - the center point doesn't matter
|
||||||
for (Polygons::iterator it = my_clip_area.begin(); it != my_clip_area.end(); ++it)
|
for (Polygon &p : my_clip_area)
|
||||||
it->rotate(-*angle, Point(0,0));
|
p.rotate(-candidate.angle, Point(0,0));
|
||||||
for (ExPolygons::iterator it = my_anchors.begin(); it != my_anchors.end(); ++it)
|
for (ExPolygon &e : my_anchors)
|
||||||
it->rotate(-*angle, Point(0,0));
|
e.rotate(-candidate.angle, Point(0,0));
|
||||||
|
|
||||||
// generate lines in this direction
|
// generate lines in this direction
|
||||||
BoundingBox bb;
|
BoundingBox bb;
|
||||||
for (ExPolygons::const_iterator it = my_anchors.begin(); it != my_anchors.end(); ++it)
|
for (const ExPolygon &e : my_anchors)
|
||||||
bb.merge((Points)*it);
|
bb.merge((Points)e);
|
||||||
|
|
||||||
Lines lines;
|
Lines lines;
|
||||||
for (coord_t y = bb.min.y; y <= bb.max.y; y += line_increment)
|
for (coord_t y = bb.min.y; y <= bb.max.y; y += line_increment)
|
||||||
@ -143,44 +132,39 @@ BridgeDetector::detect_angle()
|
|||||||
|
|
||||||
std::vector<double> lengths;
|
std::vector<double> lengths;
|
||||||
double total_length = 0;
|
double total_length = 0;
|
||||||
for (Lines::const_iterator line = clipped_lines.begin(); line != clipped_lines.end(); ++line) {
|
for (const Line &line : clipped_lines) {
|
||||||
double len = line->length();
|
const double len = line.length();
|
||||||
lengths.push_back(len);
|
lengths.push_back(len);
|
||||||
total_length += len;
|
total_length += len;
|
||||||
}
|
}
|
||||||
if (total_length) have_coverage = true;
|
if (total_length) have_coverage = true;
|
||||||
|
|
||||||
// sum length of bridged lines
|
// sum length of bridged lines
|
||||||
bdcomp.dir_coverage[*angle] = total_length;
|
candidate.coverage = total_length;
|
||||||
|
|
||||||
/* The following produces more correct results in some cases and more broken in others.
|
/* The following produces more correct results in some cases and more broken in others.
|
||||||
TODO: investigate, as it looks more reliable than line clipping. */
|
TODO: investigate, as it looks more reliable than line clipping. */
|
||||||
// $directions_coverage{$angle} = sum(map $_->area, @{$self->coverage($angle)}) // 0;
|
// $directions_coverage{$angle} = sum(map $_->area, @{$self->coverage($angle)}) // 0;
|
||||||
|
|
||||||
// max length of bridged lines
|
// max length of bridged lines
|
||||||
dir_avg_length[*angle] = !lengths.empty()
|
if (!lengths.empty())
|
||||||
? *std::max_element(lengths.begin(), lengths.end())
|
candidate.max_length = *std::max_element(lengths.begin(), lengths.end());
|
||||||
: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if no direction produced coverage, then there's no bridge direction
|
// if no direction produced coverage, then there's no bridge direction
|
||||||
if (!have_coverage) return false;
|
if (!have_coverage) return false;
|
||||||
|
|
||||||
// sort directions by coverage - most coverage first
|
// sort directions by coverage - most coverage first
|
||||||
std::sort(angles.begin(), angles.end(), bdcomp);
|
std::sort(candidates.begin(), candidates.end());
|
||||||
this->angle = angles.front();
|
|
||||||
|
|
||||||
// if any other direction is within extrusion width of coverage, prefer it if shorter
|
// if any other direction is within extrusion width of coverage, prefer it if shorter
|
||||||
// TODO: There are two options here - within width of the angle with most coverage, or within width of the currently perferred?
|
// TODO: There are two options here - within width of the angle with most coverage, or within width of the currently perferred?
|
||||||
double most_coverage_angle = this->angle;
|
size_t i_best = 0;
|
||||||
for (std::vector<double>::const_iterator angle = angles.begin() + 1;
|
for (size_t i = 1; i < candidates.size() && candidates[i_best].coverage - candidates[i].coverage < this->extrusion_width; ++ i)
|
||||||
angle != angles.end() && bdcomp.dir_coverage[most_coverage_angle] - bdcomp.dir_coverage[*angle] < this->extrusion_width;
|
if (candidates[i].max_length < candidates[i_best].max_length)
|
||||||
++angle
|
i_best = i;
|
||||||
) {
|
|
||||||
if (dir_avg_length[*angle] < dir_avg_length[this->angle]) {
|
this->angle = candidates[i_best].angle;
|
||||||
this->angle = *angle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->angle >= PI) this->angle -= PI;
|
if (this->angle >= PI) this->angle -= PI;
|
||||||
|
|
||||||
|
@ -31,6 +31,19 @@ private:
|
|||||||
Polylines _edges;
|
Polylines _edges;
|
||||||
// Closed polygons representing the supporting areas.
|
// Closed polygons representing the supporting areas.
|
||||||
ExPolygons _anchors;
|
ExPolygons _anchors;
|
||||||
|
|
||||||
|
class BridgeDirection {
|
||||||
|
public:
|
||||||
|
BridgeDirection(double a = -1.) : angle(a), coverage(0.), max_length(0.) {}
|
||||||
|
// the best direction is the one causing most lines to be bridged (thus most coverage)
|
||||||
|
bool operator<(const BridgeDirection &other) const {
|
||||||
|
// Initial sort by coverage only - comparator must obey strict weak ordering
|
||||||
|
return this->coverage > other.coverage;
|
||||||
|
};
|
||||||
|
double angle;
|
||||||
|
double coverage;
|
||||||
|
double max_length;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user