mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-22 18:32:16 +00:00
SPE-2298: Fix crash caused by a numerical issue during testing if a Voronoi vertex is inside a corner of a polygon.
Cherry-picked from prusa3d/PrusaSlicer@669c931b77 Co-authored-by: Lukáš Hejl <hejl.lukas@gmail.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <Arachne/utils/PolygonsSegmentIndex.hpp>
|
||||
#include <MultiMaterialSegmentation.hpp>
|
||||
#include <Geometry.hpp>
|
||||
|
||||
#include "VoronoiUtils.hpp"
|
||||
#include "libslic3r.h"
|
||||
@@ -28,6 +29,7 @@ template SegmentCellRange<Point> VoronoiUtils::compute_segment_cell_range(const
|
||||
template SegmentCellRange<Point> VoronoiUtils::compute_segment_cell_range(const VoronoiDiagram::cell_type &, VD::SegmentIt, VD::SegmentIt);
|
||||
template SegmentCellRange<Point> VoronoiUtils::compute_segment_cell_range(const VoronoiDiagram::cell_type &, ColoredLinesConstIt, ColoredLinesConstIt);
|
||||
template SegmentCellRange<Point> VoronoiUtils::compute_segment_cell_range(const VoronoiDiagram::cell_type &, PolygonsSegmentIndexConstIt, PolygonsSegmentIndexConstIt);
|
||||
template PointCellRange<Point> VoronoiUtils::compute_point_cell_range(const VoronoiDiagram::cell_type &, PolygonsSegmentIndexConstIt, PolygonsSegmentIndexConstIt);
|
||||
template Points VoronoiUtils::discretize_parabola(const Point &, const Arachne::PolygonsSegmentIndex &, const Point &, const Point &, coord_t, float);
|
||||
template Arachne::PolygonsPointIndex VoronoiUtils::get_source_point_index(const VoronoiDiagram::cell_type &, PolygonsSegmentIndexConstIt, PolygonsSegmentIndexConstIt);
|
||||
|
||||
@@ -245,6 +247,62 @@ VoronoiUtils::compute_segment_cell_range(const VD::cell_type &cell, const Segmen
|
||||
return cell_range;
|
||||
}
|
||||
|
||||
template<typename SegmentIterator>
|
||||
typename boost::polygon::enable_if<
|
||||
typename boost::polygon::gtl_if<typename boost::polygon::is_segment_concept<
|
||||
typename boost::polygon::geometry_concept<typename std::iterator_traits<SegmentIterator>::value_type>::type>::type>::type,
|
||||
Geometry::PointCellRange<
|
||||
typename boost::polygon::segment_point_type<typename std::iterator_traits<SegmentIterator>::value_type>::type>>::type
|
||||
VoronoiUtils::compute_point_cell_range(const VD::cell_type &cell, const SegmentIterator segment_begin, const SegmentIterator segment_end)
|
||||
{
|
||||
using Segment = typename std::iterator_traits<SegmentIterator>::value_type;
|
||||
using Point = typename boost::polygon::segment_point_type<Segment>::type;
|
||||
using PointCellRange = PointCellRange<Point>;
|
||||
using CoordType = typename Point::coord_type;
|
||||
|
||||
const Point source_point = Geometry::VoronoiUtils::get_source_point(cell, segment_begin, segment_end);
|
||||
|
||||
// We want to ignore (by returning PointCellRange without assigned edge_begin and edge_end) cells outside the input polygon.
|
||||
PointCellRange cell_range(source_point);
|
||||
|
||||
const VD::edge_type *edge = cell.incident_edge();
|
||||
if (edge->is_infinite() || !is_in_range<CoordType>(*edge)) {
|
||||
// Ignore infinite edges, because they only occur outside the polygon.
|
||||
// Also ignore edges with endpoints that don't fit into CoordType, because such edges are definitely outside the polygon.
|
||||
return cell_range;
|
||||
}
|
||||
|
||||
const Arachne::PolygonsPointIndex source_point_idx = Geometry::VoronoiUtils::get_source_point_index(cell, segment_begin, segment_end);
|
||||
const Point edge_v0 = Geometry::VoronoiUtils::to_point(edge->vertex0()).template cast<CoordType>();
|
||||
const Point edge_v1 = Geometry::VoronoiUtils::to_point(edge->vertex1()).template cast<CoordType>();
|
||||
const Point edge_query_point = (edge_v0 == source_point) ? edge_v1 : edge_v0;
|
||||
|
||||
// Check if the edge has another endpoint inside the corner of the polygon.
|
||||
if (!Geometry::is_point_inside_polygon_corner(source_point_idx.prev().p(), source_point_idx.p(), source_point_idx.next().p(), edge_query_point)) {
|
||||
// If the endpoint isn't inside the corner of the polygon, it means that
|
||||
// the whole cell isn't inside the polygons, and we will ignore such cells.
|
||||
return cell_range;
|
||||
}
|
||||
|
||||
const Vec2i64 source_point_i64 = source_point.template cast<int64_t>();
|
||||
edge = cell.incident_edge();
|
||||
do {
|
||||
assert(edge->is_finite());
|
||||
|
||||
if (Vec2i64 v1 = Geometry::VoronoiUtils::to_point(edge->vertex1()); v1 == source_point_i64) {
|
||||
cell_range.edge_begin = edge->next();
|
||||
cell_range.edge_end = edge;
|
||||
} else {
|
||||
// FIXME @hejllukas: With Arachne, we don't support polygons with collinear edges,
|
||||
// because with collinear edges we have to handle secondary edges.
|
||||
// Such edges goes through the endpoints of the input segments.
|
||||
assert((Geometry::VoronoiUtils::to_point(edge->vertex0()) == source_point_i64 || edge->is_primary()) && "Point cells must end in the point! They cannot cross the point with an edge, because collinear edges are not allowed in the input.");
|
||||
}
|
||||
} while (edge = edge->next(), edge != cell.incident_edge());
|
||||
|
||||
return cell_range;
|
||||
}
|
||||
|
||||
Vec2i64 VoronoiUtils::to_point(const VD::vertex_type *vertex)
|
||||
{
|
||||
assert(vertex != nullptr);
|
||||
|
||||
Reference in New Issue
Block a user