144 lines
4.7 KiB
C++
144 lines
4.7 KiB
C++
|
#include "InternalBridgeDetector.hpp"
|
||
|
#include "ClipperUtils.hpp"
|
||
|
#include "Geometry.hpp"
|
||
|
#include <algorithm>
|
||
|
|
||
|
namespace Slic3r {
|
||
|
|
||
|
InternalBridgeDetector::InternalBridgeDetector(
|
||
|
ExPolygon _internal_bridge, const ExPolygons& _fill_no_overlap, coord_t _spacing) :
|
||
|
fill_no_overlap(_fill_no_overlap),
|
||
|
spacing(_spacing)
|
||
|
{
|
||
|
this->internal_bridge_infill.push_back(std::move(_internal_bridge));
|
||
|
initialize();
|
||
|
}
|
||
|
|
||
|
//#define INTERNAL_BRIDGE_DETECTOR_DEBUG_TO_SVG
|
||
|
|
||
|
void InternalBridgeDetector::initialize()
|
||
|
{
|
||
|
Polygons grown = offset(this->internal_bridge_infill, float(this->spacing));
|
||
|
this->m_anchor_regions = diff_ex(grown, offset(this->fill_no_overlap, 10.f));
|
||
|
|
||
|
#ifdef INTERNAL_BRIDGE_DETECTOR_DEBUG_TO_SVG
|
||
|
static int irun = 0;
|
||
|
BoundingBox bbox_svg;
|
||
|
|
||
|
bbox_svg.merge(get_extents(this->internal_bridge_infill));
|
||
|
bbox_svg.merge(get_extents(this->fill_no_overlap));
|
||
|
bbox_svg.merge(get_extents(this->m_anchor_regions));
|
||
|
{
|
||
|
std::stringstream stri;
|
||
|
stri << "InternalBridgeDetector_" << irun << ".svg";
|
||
|
SVG svg(stri.str(), bbox_svg);
|
||
|
svg.draw(to_polylines(this->internal_bridge_infill), "blue");
|
||
|
svg.draw(to_polylines(this->fill_no_overlap), "yellow");
|
||
|
svg.draw(to_polylines(m_anchor_regions), "red");
|
||
|
svg.Close();
|
||
|
}
|
||
|
++ irun;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
bool InternalBridgeDetector::detect_angle()
|
||
|
{
|
||
|
if (this->m_anchor_regions.empty())
|
||
|
return false;
|
||
|
|
||
|
std::vector<InternalBridgeDirection> candidates;
|
||
|
std::vector<double> angles = bridge_direction_candidates();
|
||
|
candidates.reserve(angles.size());
|
||
|
for (size_t i = 0; i < angles.size(); ++ i)
|
||
|
candidates.emplace_back(InternalBridgeDirection(angles[i]));
|
||
|
|
||
|
Polygons clip_area = offset(this->internal_bridge_infill, 0.5f * float(this->spacing));
|
||
|
|
||
|
bool have_coverage = false;
|
||
|
for (size_t i_angle = 0; i_angle < candidates.size(); ++ i_angle)
|
||
|
{
|
||
|
const double angle = candidates[i_angle].angle;
|
||
|
|
||
|
Lines lines;
|
||
|
{
|
||
|
BoundingBox bbox = get_extents_rotated(this->m_anchor_regions, - angle);
|
||
|
// Cover the region with line segments.
|
||
|
lines.reserve((bbox.max(1) - bbox.min(1) + this->spacing) / this->spacing);
|
||
|
double s = sin(angle);
|
||
|
double c = cos(angle);
|
||
|
|
||
|
for (coord_t y = bbox.min(1); y <= bbox.max(1); y += this->spacing)
|
||
|
lines.push_back(Line(
|
||
|
Point((coord_t)round(c * bbox.min(0) - s * y), (coord_t)round(c * y + s * bbox.min(0))),
|
||
|
Point((coord_t)round(c * bbox.max(0) - s * y), (coord_t)round(c * y + s * bbox.max(0)))));
|
||
|
}
|
||
|
|
||
|
double total_length = 0;
|
||
|
double anchored_length = 0;
|
||
|
double max_length = 0;
|
||
|
{
|
||
|
Lines clipped_lines = intersection_ln(lines, clip_area);
|
||
|
for (size_t i = 0; i < clipped_lines.size(); ++i) {
|
||
|
const Line &line = clipped_lines[i];
|
||
|
double len = line.length();
|
||
|
total_length += len;
|
||
|
if (expolygons_contain(this->m_anchor_regions, line.a) && expolygons_contain(this->m_anchor_regions, line.b)) {
|
||
|
// This line could be anchored.
|
||
|
anchored_length += len;
|
||
|
max_length = std::max(max_length, len);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (anchored_length == 0.)
|
||
|
continue;
|
||
|
|
||
|
have_coverage = true;
|
||
|
|
||
|
candidates[i_angle].coverage = anchored_length/total_length;
|
||
|
candidates[i_angle].max_length = max_length;
|
||
|
}
|
||
|
|
||
|
if (! have_coverage)
|
||
|
return false;
|
||
|
|
||
|
std::sort(candidates.begin(), candidates.end());
|
||
|
size_t i_best = 0;
|
||
|
this->angle = candidates[i_best].angle;
|
||
|
if (this->angle >= PI)
|
||
|
this->angle -= PI;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
std::vector<double> InternalBridgeDetector::bridge_direction_candidates() const
|
||
|
{
|
||
|
std::vector<double> angles;
|
||
|
for (int i = 0; i <= PI/this->resolution; ++i)
|
||
|
angles.push_back(i * this->resolution);
|
||
|
|
||
|
// we also test angles of each bridge contour
|
||
|
{
|
||
|
Lines lines = to_lines(this->internal_bridge_infill);
|
||
|
for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line)
|
||
|
angles.push_back(line->direction());
|
||
|
}
|
||
|
|
||
|
// remove duplicates
|
||
|
double min_resolution = PI/180.0;
|
||
|
std::sort(angles.begin(), angles.end());
|
||
|
for (size_t i = 1; i < angles.size(); ++i) {
|
||
|
if (Slic3r::Geometry::directions_parallel(angles[i], angles[i-1], min_resolution)) {
|
||
|
angles.erase(angles.begin() + i);
|
||
|
--i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Slic3r::Geometry::directions_parallel(angles.front(), angles.back(), min_resolution))
|
||
|
angles.pop_back();
|
||
|
|
||
|
return angles;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
}
|