A simple algorithm to follow the boundary of polygons

This commit is contained in:
Lukáš Hejl 2020-09-21 02:05:52 +02:00
parent e04c6a4d17
commit 7a4ba7d131
2 changed files with 112 additions and 3 deletions

View file

@ -176,6 +176,93 @@ namespace Slic3r {
return islands;
}
Matrix2d rotation_by_direction(const Point &direction)
{
Matrix2d rotation;
rotation.block<1, 2>(0, 0) = direction.cast<double>() / direction.cast<double>().norm();
rotation(1, 0) = -rotation(0, 1);
rotation(1, 1) = rotation(0, 0);
return rotation;
}
Polyline AvoidCrossingPerimeters2::travel_to(const GCode &gcodegen, const Point &point)
{
const Point &start = gcodegen.last_pos();
const Point &end = point;
const Point direction = end - start;
Matrix2d transform_to_x_axis = rotation_by_direction(direction);
Matrix2d transform_from_x_axis = transform_to_x_axis.transpose();
const Line travel_line((transform_to_x_axis * start.cast<double>()).cast<coord_t>(),
(transform_to_x_axis * end.cast<double>()).cast<coord_t>());
Polygons borders;
borders.reserve(gcodegen.layer()->lslices.size());
for (const ExPolygon &ex_polygon : gcodegen.layer()->lslices) {
borders.emplace_back(ex_polygon.contour);
for (const Polygon &hole : ex_polygon.holes) borders.emplace_back(hole);
}
std::vector<Intersection> intersections;
for (size_t border_idx = 0; border_idx < borders.size(); ++border_idx) {
const Polygon &border = borders[border_idx];
Lines border_lines = border.lines();
for (size_t line_idx = 0; line_idx < border_lines.size(); ++line_idx) {
const Line &border_line = border_lines[line_idx];
Line border_line_transformed((transform_to_x_axis * border_line.a.cast<double>()).cast<coord_t>(),
(transform_to_x_axis * border_line.b.cast<double>()).cast<coord_t>());
Point intersection_transformed;
if (travel_line.intersection(border_line_transformed, &intersection_transformed))
intersections.emplace_back(border_idx, line_idx, intersection_transformed);
}
}
// Sort intersections from the nearest to the farthest
std::sort(intersections.begin(), intersections.end());
// Polyline result(start, end);
Polyline result;
result.append(start);
for (auto it_first = intersections.begin(); it_first != intersections.end(); ++it_first) {
const Intersection &intersection_first = *it_first;
for (auto it_second = it_first + 1; it_second != intersections.end(); ++it_second) {
const Intersection &intersection_second = *it_second;
if (intersection_first.border_idx == intersection_second.border_idx) {
Lines border_lines = borders[intersection_first.border_idx].lines();
// Append the nearest intersection into the path
result.append((transform_from_x_axis * intersection_first.point.cast<double>()).cast<coord_t>());
// Append the path around the border into the path
for (size_t line_idx = intersection_first.line_idx; line_idx != intersection_second.line_idx;) {
result.append(border_lines[line_idx].b);
if (++line_idx == border_lines.size()) line_idx = 0;
}
// Append the farthest intersection into the path
result.append((transform_from_x_axis * intersection_second.point.cast<double>()).cast<coord_t>());
// Skip intersections in between
it_first = it_second;
break;
}
}
}
result.append(end);
return result;
}
std::string OozePrevention::pre_toolchange(GCode& gcodegen)
{

View file

@ -46,13 +46,13 @@ public:
bool disable_once;
AvoidCrossingPerimeters() : use_external_mp(false), use_external_mp_once(false), disable_once(true) {}
~AvoidCrossingPerimeters() {}
virtual ~AvoidCrossingPerimeters() = default;
void reset() { m_external_mp.reset(); m_layer_mp.reset(); }
void init_external_mp(const Print &print);
void init_layer_mp(const ExPolygons &islands) { m_layer_mp = Slic3r::make_unique<MotionPlanner>(islands); }
Polyline travel_to(const GCode &gcodegen, const Point &point);
virtual Polyline travel_to(const GCode &gcodegen, const Point &point);
private:
// For initializing the regions to avoid.
@ -62,6 +62,28 @@ private:
std::unique_ptr<MotionPlanner> m_layer_mp;
};
class AvoidCrossingPerimeters2 : public AvoidCrossingPerimeters
{
protected:
struct Intersection
{
size_t border_idx;
size_t line_idx;
Point point;
Intersection(size_t border_idx, size_t line_idx, Point point)
: border_idx(border_idx), line_idx(line_idx), point(point){};
inline bool operator<(const Intersection &other) const { return this->point.x() < other.point.x(); }
};
public:
AvoidCrossingPerimeters2() : AvoidCrossingPerimeters() {}
virtual ~AvoidCrossingPerimeters2() = default;
virtual Polyline travel_to(const GCode &gcodegen, const Point &point) override;
};
class OozePrevention {
public:
@ -326,7 +348,7 @@ private:
std::set<std::string> m_placeholder_parser_failed_templates;
OozePrevention m_ooze_prevention;
Wipe m_wipe;
AvoidCrossingPerimeters m_avoid_crossing_perimeters;
AvoidCrossingPerimeters2 m_avoid_crossing_perimeters;
bool m_enable_loop_clipping;
// If enabled, the G-code generator will put following comments at the ends
// of the G-code lines: _EXTRUDE_SET_SPEED, _WIPE, _BRIDGE_FAN_START, _BRIDGE_FAN_END