Fixed various bugs in reconstruction of polygon from vertical lines

This commit is contained in:
PavelMikus 2023-04-19 16:53:53 +02:00 committed by Pavel Mikuš
parent 4409743ea4
commit 3346b422a7
3 changed files with 133 additions and 109 deletions

View File

@ -16,6 +16,7 @@
#include <boost/log/trivial.hpp>
#include <functional>
#include <string>
#include <type_traits>
#include <unordered_set>
#include <vector>
@ -87,6 +88,7 @@ ThickPolylines FillEnsuring::fill_surface_arachne(const Surface *surface, const
polygon_sections[i].erase(std::remove_if(polygon_sections[i].begin(), polygon_sections[i].end(),
[](const Line &s) { return s.a == s.b; }),
polygon_sections[i].end());
std::sort(polygon_sections[i].begin(), polygon_sections[i].end(), [](const Line &a, const Line &b) { return a.a.y() < b.b.y(); });
}
struct Node{
@ -166,10 +168,88 @@ ThickPolylines FillEnsuring::fill_surface_arachne(const Surface *surface, const
polygon_sections[section_idx].erase(std::remove_if(polygon_sections[section_idx].begin(), polygon_sections[section_idx].end(),
[](const Line &s) { return s.a == s.b; }),
polygon_sections[section_idx].end());
std::sort(polygon_sections[section_idx].begin(), polygon_sections[section_idx].end(),
[](const Line &a, const Line &b) { return a.a.y() < b.b.y(); });
}
double squared_distance_limit_reconnection = 4 * double(scaled_spacing) * double(scaled_spacing);
ThickPolylines thick_polylines_out;
{
struct TracedPath {
ThickPolyline polyline;
const Line* origin_line;
};
std::vector<TracedPath> current_traced_paths;
for (const auto &polygon_slice : polygon_sections) {
std::unordered_set<const Line *> used_segments;
for (TracedPath &traced_path : current_traced_paths) {
ThickPolyline& traced_polyline = traced_path.polyline;
Point max_y = traced_polyline.last_point();
Point min_y = traced_polyline.points[traced_polyline.size() - 2];
if (max_y.y() < min_y.y())
std::swap(max_y, min_y);
auto candidates_begin = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), min_y,
[](const Point &low, const Line &seg) { return seg.b.y() > low.y(); });
auto candidates_end = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), max_y,
[](const Point &high, const Line &seg) { return seg.a.y() > high.y(); });
bool segment_added = false;
for (auto candidate = candidates_begin; candidate != candidates_end && !segment_added; candidate++) {
if (used_segments.find(&(*candidate)) != used_segments.end()) {
continue;
}
if ((traced_polyline.last_point() - candidate->a).cast<double>().squaredNorm() < squared_distance_limit_reconnection) {
traced_polyline.width.push_back(scaled_spacing);
traced_polyline.points.push_back(candidate->a);
traced_polyline.width.push_back(scaled_spacing);
traced_polyline.width.push_back(scaled_spacing);
traced_polyline.points.push_back(candidate->b);
traced_polyline.width.push_back(scaled_spacing);
used_segments.insert(&(*candidate));
segment_added = true;
} else if ((traced_polyline.last_point() - candidate->b).cast<double>().squaredNorm() <
squared_distance_limit_reconnection) {
traced_polyline.width.push_back(scaled_spacing);
traced_polyline.points.push_back(candidate->b);
traced_polyline.width.push_back(scaled_spacing);
traced_polyline.width.push_back(scaled_spacing);
traced_polyline.points.push_back(candidate->a);
traced_polyline.width.push_back(scaled_spacing);
used_segments.insert(&(*candidate));
segment_added = true;
}
}
if (!segment_added) {
// Zero overlapping segments. Finish the polyline.
thick_polylines_out.push_back(std::move(traced_polyline));
traced_polyline.clear();
}
}
current_traced_paths.erase(std::remove_if(current_traced_paths.begin(), current_traced_paths.end(),
[](const ThickPolyline &tp) { return tp.empty(); }),
current_traced_paths.end());
for (const Line &segment : polygon_slice) {
if (used_segments.find(&segment) == used_segments.end()) {
TracedPath &new_path = current_traced_paths.emplace_back();
new_path.polyline.points.push_back(segment.a);
new_path.polyline.width.push_back(scaled_spacing);
new_path.polyline.points.push_back(segment.b);
new_path.polyline.width.push_back(scaled_spacing);
new_path.polyline.endpoints = {true, true};
new_path.origin_line = &segment;
}
}
}
thick_polylines_out.insert(thick_polylines_out.end(), current_traced_paths.begin(), current_traced_paths.end());
}
Polygons reconstructed_area{};
// reconstruct polygon from polygon sections
{
@ -183,36 +263,37 @@ ThickPolylines FillEnsuring::fill_surface_arachne(const Surface *surface, const
for (const auto &polygon_slice : polygon_sections) {
std::unordered_set<const Line *> used_segments;
for (TracedPoly &traced_poly : current_traced_polys) {
auto maybe_first_overlap = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.lows.back(),
[](const Point &low, const Line &seg) { return seg.b.y() < low.y(); });
if (maybe_first_overlap != polygon_slice.begin()) {
maybe_first_overlap--;
}
if (maybe_first_overlap != polygon_slice.end() && // segment exists
segments_overlap(traced_poly.lows.back().y(), traced_poly.highs.back().y(), maybe_first_overlap->a.y(),
maybe_first_overlap->b.y())) // segment is overlapping
{
// Overlapping segment. In that case, add it
// to the traced polygon and add segment to used segments
if ((traced_poly.lows.back() - maybe_first_overlap->a).cast<double>().squaredNorm() <
squared_distance_limit_reconnection) {
traced_poly.lows.push_back(maybe_first_overlap->a);
auto candidates_begin = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.lows.back(),
[](const Point &low, const Line &seg) { return seg.b.y() > low.y(); });
auto candidates_end = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.highs.back(),
[](const Point &high, const Line &seg) { return seg.a.y() > high.y(); });
bool segment_added = false;
for (auto candidate = candidates_begin; candidate != candidates_end && !segment_added; candidate++) {
if (used_segments.find(&(*candidate)) != used_segments.end()) {
continue;
}
if ((traced_poly.lows.back() - candidates_begin->a).cast<double>().squaredNorm() < squared_distance_limit_reconnection) {
traced_poly.lows.push_back(candidates_begin->a);
} else {
traced_poly.lows.push_back(traced_poly.lows.back() + Point{scaled_spacing / 2, 0});
traced_poly.lows.push_back(maybe_first_overlap->a - Point{scaled_spacing / 2, 0});
traced_poly.lows.push_back(maybe_first_overlap->a);
traced_poly.lows.push_back(candidates_begin->a - Point{scaled_spacing / 2, 0});
traced_poly.lows.push_back(candidates_begin->a);
}
if ((traced_poly.highs.back() - maybe_first_overlap->b).cast<double>().squaredNorm() <
if ((traced_poly.highs.back() - candidates_begin->b).cast<double>().squaredNorm() <
squared_distance_limit_reconnection) {
traced_poly.highs.push_back(maybe_first_overlap->b);
traced_poly.highs.push_back(candidates_begin->b);
} else {
traced_poly.highs.push_back(traced_poly.highs.back() + Point{scaled_spacing / 2, 0});
traced_poly.highs.push_back(maybe_first_overlap->b - Point{scaled_spacing / 2, 0});
traced_poly.highs.push_back(maybe_first_overlap->b);
traced_poly.highs.push_back(candidates_begin->b - Point{scaled_spacing / 2, 0});
traced_poly.highs.push_back(candidates_begin->b);
}
used_segments.insert(&(*maybe_first_overlap));
} else {
segment_added = true;
used_segments.insert(&(*candidates_begin));
}
if (!segment_added) {
// Zero or multiple overlapping segments. Resolving this is nontrivial,
// so we just close this polygon and maybe open several new. This will hopefully happen much less often
traced_poly.lows.push_back(traced_poly.lows.back() + Point{scaled_spacing / 2, 0});
@ -246,69 +327,6 @@ ThickPolylines FillEnsuring::fill_surface_arachne(const Surface *surface, const
}
}
ThickPolylines thick_polylines_out;
{
ThickPolylines current_traced_paths;
for (const auto &polygon_slice : polygon_sections) {
std::unordered_set<const Line *> used_segments;
for (ThickPolyline &traced_path : current_traced_paths) {
auto maybe_overlap = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_path.last_point(),
[](const Point &low, const Line &seg) { return seg.a.y() < low.y(); });
if (maybe_overlap != polygon_slice.begin()) {
maybe_overlap--;
}
bool segment_added = false;
while (!segment_added && maybe_overlap != polygon_slice.end()) {
if ((traced_path.last_point() - maybe_overlap->a).cast<double>().squaredNorm() <
squared_distance_limit_reconnection) {
traced_path.width.push_back(scaled_spacing);
traced_path.points.push_back(maybe_overlap->a);
traced_path.width.push_back(scaled_spacing);
traced_path.width.push_back(scaled_spacing);
traced_path.points.push_back(maybe_overlap->b);
traced_path.width.push_back(scaled_spacing);
used_segments.insert(&(*maybe_overlap));
segment_added = true;
} else if ((traced_path.last_point() - maybe_overlap->b).cast<double>().squaredNorm() <
squared_distance_limit_reconnection) {
traced_path.width.push_back(scaled_spacing);
traced_path.points.push_back(maybe_overlap->b);
traced_path.width.push_back(scaled_spacing);
traced_path.width.push_back(scaled_spacing);
traced_path.points.push_back(maybe_overlap->a);
traced_path.width.push_back(scaled_spacing);
used_segments.insert(&(*maybe_overlap));
segment_added = true;
}
maybe_overlap++;
}
if (!segment_added) {
// Zero overlapping segments. Finish the polyline.
thick_polylines_out.push_back(std::move(traced_path));
traced_path.clear();
}
}
current_traced_paths.erase(std::remove_if(current_traced_paths.begin(), current_traced_paths.end(),
[](const ThickPolyline &tp) { return tp.empty(); }),
current_traced_paths.end());
for (const Line &segment : polygon_slice) {
if (used_segments.find(&segment) == used_segments.end()) {
ThickPolyline &new_path = current_traced_paths.emplace_back();
new_path.points.push_back(segment.a);
new_path.width.push_back(scaled_spacing);
new_path.points.push_back(segment.b);
new_path.width.push_back(scaled_spacing);
new_path.endpoints = {true,true};
}
}
}
thick_polylines_out.insert(thick_polylines_out.end(), current_traced_paths.begin(), current_traced_paths.end());
}
reconstructed_area = closing(reconstructed_area, float(SCALED_EPSILON), float(SCALED_EPSILON));
ExPolygons gaps_for_additional_filling = diff_ex(filled_area, reconstructed_area);
if (this->overlap != 0) {

View File

@ -5,6 +5,7 @@
#include "libslic3r/format.hpp"
#include "libslic3r/I18N.hpp"
#include "libslic3r/GCodeWriter.hpp"
#include "libslic3r/I18N.hpp"
#include "GCodeProcessor.hpp"
#include <boost/algorithm/string/case_conv.hpp>

View File

@ -2108,6 +2108,8 @@ void PrintObject::bridge_over_infill()
polygon_sections[i].erase(std::remove_if(polygon_sections[i].begin(), polygon_sections[i].end(),
[](const Line &s) { return s.a == s.b; }),
polygon_sections[i].end());
std::sort(polygon_sections[i].begin(), polygon_sections[i].end(),
[](const Line &a, const Line &b) { return a.a.y() < b.b.y(); });
}
// reconstruct polygon from polygon sections
@ -2121,36 +2123,39 @@ void PrintObject::bridge_over_infill()
for (const auto &polygon_slice : polygon_sections) {
std::unordered_set<const Line *> used_segments;
for (TracedPoly &traced_poly : current_traced_polys) {
auto maybe_first_overlap = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.lows.back(),
[](const Point &low, const Line &seg) { return seg.b.y() < low.y(); });
if (maybe_first_overlap != polygon_slice.begin()) {
maybe_first_overlap--;
}
if (maybe_first_overlap != polygon_slice.end() && // segment exists
segments_overlap(traced_poly.lows.back().y(), traced_poly.highs.back().y(), maybe_first_overlap->a.y(),
maybe_first_overlap->b.y())) // segment is overlapping
{
// Overlapping segment. In that case, add it
// to the traced polygon and add segment to used segments
if ((traced_poly.lows.back() - maybe_first_overlap->a).cast<double>().squaredNorm() <
36.0 * double(bridging_flow.scaled_spacing()) * bridging_flow.scaled_spacing()) {
traced_poly.lows.push_back(maybe_first_overlap->a);
} else {
traced_poly.lows.push_back(traced_poly.lows.back() + Point{bridging_flow.scaled_spacing() / 2, 0});
traced_poly.lows.push_back(maybe_first_overlap->a - Point{bridging_flow.scaled_spacing() / 2, 0});
traced_poly.lows.push_back(maybe_first_overlap->a);
auto candidates_begin = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.lows.back(),
[](const Point &low, const Line &seg) { return seg.b.y() > low.y(); });
auto candidates_end = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.highs.back(),
[](const Point &high, const Line &seg) { return seg.a.y() > high.y(); });
bool segment_added = false;
for (auto candidate = candidates_begin; candidate != candidates_end && !segment_added; candidate++) {
if (used_segments.find(&(*candidate)) != used_segments.end()) {
continue;
}
if ((traced_poly.highs.back() - maybe_first_overlap->b).cast<double>().squaredNorm() <
if ((traced_poly.lows.back() - candidate->a).cast<double>().squaredNorm() <
36.0 * double(bridging_flow.scaled_spacing()) * bridging_flow.scaled_spacing()) {
traced_poly.highs.push_back(maybe_first_overlap->b);
traced_poly.lows.push_back(candidate->a);
} else {
traced_poly.lows.push_back(traced_poly.lows.back() + Point{bridging_flow.scaled_spacing() / 2, 0});
traced_poly.lows.push_back(candidate->a - Point{bridging_flow.scaled_spacing() / 2, 0});
traced_poly.lows.push_back(candidate->a);
}
if ((traced_poly.highs.back() - candidate->b).cast<double>().squaredNorm() <
36.0 * double(bridging_flow.scaled_spacing()) * bridging_flow.scaled_spacing()) {
traced_poly.highs.push_back(candidate->b);
} else {
traced_poly.highs.push_back(traced_poly.highs.back() + Point{bridging_flow.scaled_spacing() / 2, 0});
traced_poly.highs.push_back(maybe_first_overlap->b - Point{bridging_flow.scaled_spacing() / 2, 0});
traced_poly.highs.push_back(maybe_first_overlap->b);
traced_poly.highs.push_back(candidate->b - Point{bridging_flow.scaled_spacing() / 2, 0});
traced_poly.highs.push_back(candidate->b);
}
used_segments.insert(&(*maybe_first_overlap));
} else {
segment_added = true;
used_segments.insert(&(*candidate));
}
if (!segment_added) {
// Zero overlapping segments, we just close this polygon
traced_poly.lows.push_back(traced_poly.lows.back() + Point{bridging_flow.scaled_spacing() / 2, 0});
traced_poly.highs.push_back(traced_poly.highs.back() + Point{bridging_flow.scaled_spacing() / 2, 0});