mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-27 12:52:07 +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);
|
||||
|
||||
@@ -11,15 +11,28 @@ namespace Slic3r::Geometry {
|
||||
// Represent trapezoid Voronoi cell around segment.
|
||||
template<typename PT> struct SegmentCellRange
|
||||
{
|
||||
const PT segment_start_point; // The start point of the source segment of this cell.
|
||||
const PT segment_end_point; // The end point of the source segment of this cell.
|
||||
const PT source_segment_start_point; // The start point of the source segment of this cell.
|
||||
const PT source_segment_end_point; // The end point of the source segment of this cell.
|
||||
const VD::edge_type *edge_begin = nullptr; // The edge of the Voronoi diagram where the loop around the cell starts.
|
||||
const VD::edge_type *edge_end = nullptr; // The edge of the Voronoi diagram where the loop around the cell ends.
|
||||
|
||||
SegmentCellRange() = delete;
|
||||
explicit SegmentCellRange(const PT &source_segment_start_point, const PT &source_segment_end_point)
|
||||
: source_segment_start_point(source_segment_start_point), source_segment_end_point(source_segment_end_point)
|
||||
{}
|
||||
|
||||
bool is_valid() const { return edge_begin && edge_end && edge_begin != edge_end; }
|
||||
};
|
||||
|
||||
// Represent trapezoid Voronoi cell around point.
|
||||
template<typename PT> struct PointCellRange
|
||||
{
|
||||
const PT source_point; // The source point of this cell.
|
||||
const VD::edge_type *edge_begin = nullptr; // The edge of the Voronoi diagram where the loop around the cell starts.
|
||||
const VD::edge_type *edge_end = nullptr; // The edge of the Voronoi diagram where the loop around the cell ends.
|
||||
|
||||
SegmentCellRange() = delete;
|
||||
explicit SegmentCellRange(const PT &segment_start_point, const PT &segment_end_point)
|
||||
: segment_start_point(segment_start_point), segment_end_point(segment_end_point)
|
||||
{}
|
||||
PointCellRange() = delete;
|
||||
explicit PointCellRange(const PT &source_point) : source_point(source_point) {}
|
||||
|
||||
bool is_valid() const { return edge_begin && edge_end && edge_begin != edge_end; }
|
||||
};
|
||||
@@ -80,7 +93,7 @@ public:
|
||||
* are linked to the neighboring segments, so you can iterate over the
|
||||
* segments until you reach the last segment.
|
||||
*
|
||||
* Adapted from CuraEngine VoronoiUtils::computePointCellRange by Tim Kuipers @BagelOrb,
|
||||
* Adapted from CuraEngine VoronoiUtils::computeSegmentCellRange by Tim Kuipers @BagelOrb,
|
||||
* Jaime van Kessel @nallath, Remco Burema @rburema and @Ghostkeeper.
|
||||
*
|
||||
* @param cell The cell to compute the range of line segments for.
|
||||
@@ -96,6 +109,33 @@ public:
|
||||
typename boost::polygon::segment_point_type<typename std::iterator_traits<SegmentIterator>::value_type>::type>>::type
|
||||
compute_segment_cell_range(const VD::cell_type &cell, SegmentIterator segment_begin, SegmentIterator segment_end);
|
||||
|
||||
/**
|
||||
* Compute the range of line segments that surround a cell of the skeletal
|
||||
* graph that belongs to a point on the medial axis.
|
||||
*
|
||||
* This should only be used on cells that belong to a corner in the skeletal
|
||||
* graph, e.g. triangular cells, not trapezoid cells.
|
||||
*
|
||||
* The resulting line segments is just the first and the last segment. They
|
||||
* are linked to the neighboring segments, so you can iterate over the
|
||||
* segments until you reach the last segment.
|
||||
*
|
||||
* Adapted from CuraEngine VoronoiUtils::computePointCellRange by Tim Kuipers @BagelOrb
|
||||
* Jaime van Kessel @nallath, Remco Burema @rburema and @Ghostkeeper.
|
||||
*
|
||||
* @param cell The cell to compute the range of line segments for.
|
||||
* @param segment_begin Begin iterator for all edges of the input Polygons.
|
||||
* @param segment_end End iterator for all edges of the input Polygons.
|
||||
* @return Range of line segments that surround the cell.
|
||||
*/
|
||||
template<typename SegmentIterator>
|
||||
static 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
|
||||
compute_point_cell_range(const VD::cell_type &cell, SegmentIterator segment_begin, SegmentIterator segment_end);
|
||||
|
||||
template<typename T> static bool is_in_range(double value)
|
||||
{
|
||||
return double(std::numeric_limits<T>::lowest()) <= value && value <= double(std::numeric_limits<T>::max());
|
||||
|
||||
Reference in New Issue
Block a user