forked from bambulab/BambuStudio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathInternalBridgeDetector.cpp
144 lines (118 loc) · 4.66 KB
/
InternalBridgeDetector.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#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;
}
}