mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-15 10:31:48 +08:00
Added detection for a missing Voronoi vertex. If the missing Voronoi vertex is detected, try to resolve it by rotation input polygons.
This commit is contained in:
parent
adf2d21c67
commit
5db91f1944
@ -378,6 +378,52 @@ SkeletalTrapezoidation::SkeletalTrapezoidation(const Polygons& polys, const Bead
|
|||||||
constructFromPolygons(polys);
|
constructFromPolygons(polys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool detect_missing_voronoi_vertex(const Geometry::VoronoiDiagram &voronoi_diagram, const std::vector<SkeletalTrapezoidation::Segment> &segments) {
|
||||||
|
for (VoronoiUtils::vd_t::cell_type cell : voronoi_diagram.cells()) {
|
||||||
|
if (!cell.incident_edge())
|
||||||
|
continue; // There is no spoon
|
||||||
|
|
||||||
|
if (cell.contains_segment()) {
|
||||||
|
const SkeletalTrapezoidation::Segment &source_segment = VoronoiUtils::getSourceSegment(cell, segments);
|
||||||
|
const Point from = source_segment.from();
|
||||||
|
const Point to = source_segment.to();
|
||||||
|
|
||||||
|
// Find starting edge
|
||||||
|
// Find end edge
|
||||||
|
bool seen_possible_start = false;
|
||||||
|
bool after_start = false;
|
||||||
|
bool ending_edge_is_set_before_start = false;
|
||||||
|
VoronoiUtils::vd_t::edge_type *starting_vd_edge = nullptr;
|
||||||
|
VoronoiUtils::vd_t::edge_type *ending_vd_edge = nullptr;
|
||||||
|
VoronoiUtils::vd_t::edge_type *edge = cell.incident_edge();
|
||||||
|
do {
|
||||||
|
if (edge->is_infinite()) continue;
|
||||||
|
|
||||||
|
Vec2i64 v0 = VoronoiUtils::p(edge->vertex0());
|
||||||
|
Vec2i64 v1 = VoronoiUtils::p(edge->vertex1());
|
||||||
|
|
||||||
|
assert(!(v0 == to.cast<int64_t>() && v1 == from.cast<int64_t>()));
|
||||||
|
if (v0 == to.cast<int64_t>() && !after_start) { // Use the last edge which starts in source_segment.to
|
||||||
|
starting_vd_edge = edge;
|
||||||
|
seen_possible_start = true;
|
||||||
|
} else if (seen_possible_start) {
|
||||||
|
after_start = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v1 == from.cast<int64_t>() && (!ending_vd_edge || ending_edge_is_set_before_start)) {
|
||||||
|
ending_edge_is_set_before_start = !after_start;
|
||||||
|
ending_vd_edge = edge;
|
||||||
|
}
|
||||||
|
} while (edge = edge->next(), edge != cell.incident_edge());
|
||||||
|
|
||||||
|
if (!starting_vd_edge || !ending_vd_edge || starting_vd_edge == ending_vd_edge)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
|
void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
|
||||||
{
|
{
|
||||||
// Check self intersections.
|
// Check self intersections.
|
||||||
@ -399,8 +445,37 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
|
|||||||
Geometry::VoronoiDiagram voronoi_diagram;
|
Geometry::VoronoiDiagram voronoi_diagram;
|
||||||
construct_voronoi(segments.begin(), segments.end(), &voronoi_diagram);
|
construct_voronoi(segments.begin(), segments.end(), &voronoi_diagram);
|
||||||
|
|
||||||
for (vd_t::cell_type cell : voronoi_diagram.cells())
|
// Try to detect cases when some Voronoi vertex is missing.
|
||||||
{
|
// When any Voronoi vertex is missing, rotate input polygon and try again.
|
||||||
|
const bool has_missing_voronoi_vertex = detect_missing_voronoi_vertex(voronoi_diagram, segments);
|
||||||
|
const double fix_angle = PI / 6;
|
||||||
|
std::unordered_map<Point, Point, PointHash> vertex_mapping;
|
||||||
|
Polygons polys_copy = polys;
|
||||||
|
if (has_missing_voronoi_vertex) {
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "Detected missing Voronoi vertex, input polygons will be rotated back and forth.";
|
||||||
|
for (Polygon &poly : polys_copy)
|
||||||
|
poly.rotate(fix_angle);
|
||||||
|
|
||||||
|
assert(polys_copy.size() == polys.size());
|
||||||
|
for (size_t poly_idx = 0; poly_idx < polys.size(); ++poly_idx) {
|
||||||
|
assert(polys_copy[poly_idx].size() == polys[poly_idx].size());
|
||||||
|
for (size_t point_idx = 0; point_idx < polys[poly_idx].size(); ++point_idx)
|
||||||
|
vertex_mapping.insert({polys[poly_idx][point_idx], polys_copy[poly_idx][point_idx]});
|
||||||
|
}
|
||||||
|
|
||||||
|
segments.clear();
|
||||||
|
for (size_t poly_idx = 0; poly_idx < polys_copy.size(); poly_idx++)
|
||||||
|
for (size_t point_idx = 0; point_idx < polys_copy[poly_idx].size(); point_idx++)
|
||||||
|
segments.emplace_back(&polys_copy, poly_idx, point_idx);
|
||||||
|
|
||||||
|
voronoi_diagram.clear();
|
||||||
|
construct_voronoi(segments.begin(), segments.end(), &voronoi_diagram);
|
||||||
|
assert(!detect_missing_voronoi_vertex(voronoi_diagram, segments));
|
||||||
|
if (detect_missing_voronoi_vertex(voronoi_diagram, segments))
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Detected missing Voronoi vertex even after the rotation of input.";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (vd_t::cell_type cell : voronoi_diagram.cells()) {
|
||||||
if (!cell.incident_edge())
|
if (!cell.incident_edge())
|
||||||
continue; // There is no spoon
|
continue; // There is no spoon
|
||||||
|
|
||||||
@ -455,6 +530,16 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
|
|||||||
prev_edge->to->data.distance_to_boundary = 0;
|
prev_edge->to->data.distance_to_boundary = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_missing_voronoi_vertex) {
|
||||||
|
for (node_t &node : graph.nodes) {
|
||||||
|
// If a mapping exists between a rotated point and an original point, use this mapping. Otherwise, rotate a point in the opposite direction.
|
||||||
|
if (auto node_it = vertex_mapping.find(node.p); node_it != vertex_mapping.end())
|
||||||
|
node.p = node_it->second;
|
||||||
|
else
|
||||||
|
node.p.rotate(-fix_angle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
separatePointyQuadEndNodes();
|
separatePointyQuadEndNodes();
|
||||||
|
|
||||||
graph.fixNodeDuplication();
|
graph.fixNodeDuplication();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user