WIP VoronoiOffset: Squash merge of vb_voronoi_offset
Working contour offsetting, skeleton_edges_rough() to detect "important" skeleton edges. Radius of an inscribed circle along the "important" skeleton edges changes slowly, therefore these "important" skeleton edges signify oblong regions possibly needing a gap fill.
This commit is contained in:
parent
dc4bdad84a
commit
a116914fce
@ -417,7 +417,7 @@ namespace boost { namespace polygon {
|
||||
typedef coord_t coordinate_type;
|
||||
|
||||
static inline coordinate_type get(const Slic3r::Point& point, orientation_2d orient) {
|
||||
return (coordinate_type)point((orient == HORIZONTAL) ? 0 : 1);
|
||||
return static_cast<coordinate_type>(point((orient == HORIZONTAL) ? 0 : 1));
|
||||
}
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,16 +9,136 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace Voronoi {
|
||||
|
||||
using VD = Slic3r::Geometry::VoronoiDiagram;
|
||||
|
||||
inline const Point& contour_point(const VD::cell_type &cell, const Line &line)
|
||||
{ return ((cell.source_category() == boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT) ? line.a : line.b); }
|
||||
inline Point& contour_point(const VD::cell_type &cell, Line &line)
|
||||
{ return ((cell.source_category() == boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT) ? line.a : line.b); }
|
||||
|
||||
inline const Point& contour_point(const VD::cell_type &cell, const Lines &lines)
|
||||
{ return contour_point(cell, lines[cell.source_index()]); }
|
||||
inline Point& contour_point(const VD::cell_type &cell, Lines &lines)
|
||||
{ return contour_point(cell, lines[cell.source_index()]); }
|
||||
|
||||
inline Vec2d vertex_point(const VD::vertex_type &v) { return Vec2d(v.x(), v.y()); }
|
||||
inline Vec2d vertex_point(const VD::vertex_type *v) { return Vec2d(v->x(), v->y()); }
|
||||
|
||||
// "Color" stored inside the boost::polygon Voronoi vertex.
|
||||
enum class VertexCategory : unsigned char
|
||||
{
|
||||
// Voronoi vertex is on the input contour.
|
||||
// VD::vertex_type stores coordinates in double, though the coordinates shall match exactly
|
||||
// with the coordinates of the input contour when converted to int32_t.
|
||||
OnContour,
|
||||
// Vertex is inside the CCW input contour, holes are respected.
|
||||
Inside,
|
||||
// Vertex is outside the CCW input contour, holes are respected.
|
||||
Outside,
|
||||
// Not known yet.
|
||||
Unknown,
|
||||
};
|
||||
|
||||
// "Color" stored inside the boost::polygon Voronoi edge.
|
||||
// The Voronoi edge as represented by boost::polygon Voronoi module is really a half-edge,
|
||||
// the half-edges are classified based on the target vertex (VD::vertex_type::vertex1())
|
||||
enum class EdgeCategory : unsigned char
|
||||
{
|
||||
// This half-edge points onto the contour, this VD::edge_type::vertex1().color() is OnContour.
|
||||
PointsToContour,
|
||||
// This half-edge points inside, this VD::edge_type::vertex1().color() is Inside.
|
||||
PointsInside,
|
||||
// This half-edge points outside, this VD::edge_type::vertex1().color() is Outside.
|
||||
PointsOutside,
|
||||
// Not known yet.
|
||||
Unknown
|
||||
};
|
||||
|
||||
// "Color" stored inside the boost::polygon Voronoi cell.
|
||||
enum class CellCategory : unsigned char
|
||||
{
|
||||
// This Voronoi cell is split by an input segment to two halves, one is inside, the other is outside.
|
||||
Boundary,
|
||||
// This Voronoi cell is completely inside.
|
||||
Inside,
|
||||
// This Voronoi cell is completely outside.
|
||||
Outside,
|
||||
// Not known yet.
|
||||
Unknown
|
||||
};
|
||||
|
||||
inline VertexCategory vertex_category(const VD::vertex_type &v)
|
||||
{ return static_cast<VertexCategory>(v.color()); }
|
||||
inline VertexCategory vertex_category(const VD::vertex_type *v)
|
||||
{ return static_cast<VertexCategory>(v->color()); }
|
||||
inline void set_vertex_category(VD::vertex_type &v, VertexCategory c)
|
||||
{ v.color(static_cast<VD::vertex_type::color_type>(c)); }
|
||||
inline void set_vertex_category(VD::vertex_type *v, VertexCategory c)
|
||||
{ v->color(static_cast<VD::vertex_type::color_type>(c)); }
|
||||
|
||||
inline EdgeCategory edge_category(const VD::edge_type &e)
|
||||
{ return static_cast<EdgeCategory>(e.color()); }
|
||||
inline EdgeCategory edge_category(const VD::edge_type *e)
|
||||
{ return static_cast<EdgeCategory>(e->color()); }
|
||||
inline void set_edge_category(VD::edge_type &e, EdgeCategory c)
|
||||
{ e.color(static_cast<VD::edge_type::color_type>(c)); }
|
||||
inline void set_edge_category(VD::edge_type *e, EdgeCategory c)
|
||||
{ e->color(static_cast<VD::edge_type::color_type>(c)); }
|
||||
|
||||
inline CellCategory cell_category(const VD::cell_type &v)
|
||||
{ return static_cast<CellCategory>(v.color()); }
|
||||
inline CellCategory cell_category(const VD::cell_type *v)
|
||||
{ return static_cast<CellCategory>(v->color()); }
|
||||
inline void set_cell_category(const VD::cell_type &v, CellCategory c)
|
||||
{ v.color(static_cast<VD::cell_type::color_type>(c)); }
|
||||
inline void set_cell_category(const VD::cell_type *v, CellCategory c)
|
||||
{ v->color(static_cast<VD::cell_type::color_type>(c)); }
|
||||
|
||||
// Mark the "Color" of VD vertices, edges and cells as Unknown.
|
||||
void reset_inside_outside_annotations(VD &vd);
|
||||
|
||||
// Assign "Color" to VD vertices, edges and cells signifying whether the entity is inside or outside
|
||||
// the input polygons defined by Lines.
|
||||
void annotate_inside_outside(VD &vd, const Lines &lines);
|
||||
|
||||
// Returns a signed distance to Voronoi vertices from the input polygons.
|
||||
// (negative distances inside, positive distances outside).
|
||||
std::vector<double> signed_vertex_distances(const VD &vd, const Lines &lines);
|
||||
|
||||
static inline bool edge_offset_no_intersection(const Vec2d &intersection_point)
|
||||
{ return std::isnan(intersection_point.x()); }
|
||||
static inline bool edge_offset_has_intersection(const Vec2d &intersection_point)
|
||||
{ return ! edge_offset_no_intersection(intersection_point); }
|
||||
std::vector<Vec2d> edge_offset_contour_intersections(
|
||||
const VD &vd, const Lines &lines, const std::vector<double> &distances,
|
||||
double offset_distance);
|
||||
|
||||
std::vector<Vec2d> skeleton_edges_rough(
|
||||
const VD &vd,
|
||||
const Lines &lines,
|
||||
const double threshold_alpha);
|
||||
|
||||
Polygons offset(
|
||||
const Geometry::VoronoiDiagram &vd,
|
||||
const Lines &lines,
|
||||
const std::vector<double> &signed_vertex_distances,
|
||||
double offset_distance,
|
||||
double discretization_error);
|
||||
|
||||
// Offset a polygon or a set of polygons possibly with holes by traversing a Voronoi diagram.
|
||||
// The input polygons are stored in lines and lines are referenced by vd.
|
||||
// Outer curve will be extracted for a positive offset_distance,
|
||||
// inner curve will be extracted for a negative offset_distance.
|
||||
// Circular arches will be discretized to achieve discretization_error.
|
||||
Polygons voronoi_offset(
|
||||
const Geometry::VoronoiDiagram &vd,
|
||||
const Lines &lines,
|
||||
double offset_distance,
|
||||
double discretization_error);
|
||||
Polygons offset(
|
||||
const VD &vd,
|
||||
const Lines &lines,
|
||||
double offset_distance,
|
||||
double discretization_error);
|
||||
|
||||
} // namespace Voronoi
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <libslic3r/Polygon.hpp>
|
||||
#include <libslic3r/SVG.hpp>
|
||||
|
||||
#include "VoronoiOffset.hpp"
|
||||
|
||||
namespace boost { namespace polygon {
|
||||
|
||||
// The following code for the visualization of the boost Voronoi diagram is based on:
|
||||
@ -70,6 +72,7 @@ class voronoi_visual_utils {
|
||||
get_point_projection((*discretization)[0], segment);
|
||||
CT projection_end = sqr_segment_length *
|
||||
get_point_projection((*discretization)[1], segment);
|
||||
assert(projection_start != projection_end);
|
||||
|
||||
// Compute parabola parameters in the transformed space.
|
||||
// Parabola has next representation:
|
||||
@ -99,13 +102,16 @@ class voronoi_visual_utils {
|
||||
// furthest from the current line segment.
|
||||
CT mid_x = (new_y - cur_y) / (new_x - cur_x) * rot_y + rot_x;
|
||||
CT mid_y = parabola_y(mid_x, rot_x, rot_y);
|
||||
assert(mid_x != cur_x || mid_y != cur_y);
|
||||
assert(mid_x != new_x || mid_y != new_y);
|
||||
|
||||
// Compute maximum distance between the given parabolic arc
|
||||
// and line segment that discretize it.
|
||||
CT dist = (new_y - cur_y) * (mid_x - cur_x) -
|
||||
(new_x - cur_x) * (mid_y - cur_y);
|
||||
dist = dist * dist / ((new_y - cur_y) * (new_y - cur_y) +
|
||||
(new_x - cur_x) * (new_x - cur_x));
|
||||
CT div = (new_y - cur_y) * (new_y - cur_y) + (new_x - cur_x) * (new_x - cur_x);
|
||||
assert(div != 0);
|
||||
dist = dist * dist / div;
|
||||
if (dist <= max_dist_transformed) {
|
||||
// Distance between parabola and line segment is less than max_dist.
|
||||
point_stack.pop();
|
||||
@ -236,50 +242,39 @@ namespace Voronoi { namespace Internal {
|
||||
|
||||
inline void clip_infinite_edge(const Points &points, const std::vector<segment_type> &segments, const edge_type& edge, coordinate_type bbox_max_size, std::vector<point_type>* clipped_edge)
|
||||
{
|
||||
assert(edge.is_infinite());
|
||||
assert((edge.vertex0() == nullptr) != (edge.vertex1() == nullptr));
|
||||
|
||||
const cell_type& cell1 = *edge.cell();
|
||||
const cell_type& cell2 = *edge.twin()->cell();
|
||||
point_type origin, direction;
|
||||
// Infinite edges could not be created by two segment sites.
|
||||
assert(cell1.contains_point() || cell2.contains_point());
|
||||
if (! cell1.contains_point() && ! cell2.contains_point()) {
|
||||
printf("Error! clip_infinite_edge - infinite edge separates two segment cells\n");
|
||||
return;
|
||||
}
|
||||
point_type direction;
|
||||
if (cell1.contains_point() && cell2.contains_point()) {
|
||||
assert(! edge.is_secondary());
|
||||
point_type p1 = retrieve_point(points, segments, cell1);
|
||||
point_type p2 = retrieve_point(points, segments, cell2);
|
||||
origin.x((p1.x() + p2.x()) * 0.5);
|
||||
origin.y((p1.y() + p2.y()) * 0.5);
|
||||
if (edge.vertex0() == nullptr)
|
||||
std::swap(p1, p2);
|
||||
direction.x(p1.y() - p2.y());
|
||||
direction.y(p2.x() - p1.x());
|
||||
} else {
|
||||
origin = cell1.contains_segment() ? retrieve_point(points, segments, cell2) : retrieve_point(points, segments, cell1);
|
||||
assert(edge.is_secondary());
|
||||
segment_type segment = cell1.contains_segment() ? segments[cell1.source_index()] : segments[cell2.source_index()];
|
||||
coordinate_type dx = high(segment).x() - low(segment).x();
|
||||
coordinate_type dy = high(segment).y() - low(segment).y();
|
||||
if ((low(segment) == origin) ^ cell1.contains_point()) {
|
||||
direction.x(dy);
|
||||
direction.y(-dx);
|
||||
} else {
|
||||
direction.x(-dy);
|
||||
direction.y(dx);
|
||||
}
|
||||
direction.x(high(segment).y() - low(segment).y());
|
||||
direction.y(low(segment).x() - high(segment).x());
|
||||
}
|
||||
coordinate_type koef = bbox_max_size / (std::max)(fabs(direction.x()), fabs(direction.y()));
|
||||
if (edge.vertex0() == NULL) {
|
||||
clipped_edge->push_back(point_type(
|
||||
origin.x() - direction.x() * koef,
|
||||
origin.y() - direction.y() * koef));
|
||||
if (edge.vertex0() == nullptr) {
|
||||
clipped_edge->push_back(point_type(edge.vertex1()->x() + direction.x() * koef, edge.vertex1()->y() + direction.y() * koef));
|
||||
clipped_edge->push_back(point_type(edge.vertex1()->x(), edge.vertex1()->y()));
|
||||
} else {
|
||||
clipped_edge->push_back(
|
||||
point_type(edge.vertex0()->x(), edge.vertex0()->y()));
|
||||
}
|
||||
if (edge.vertex1() == NULL) {
|
||||
clipped_edge->push_back(point_type(
|
||||
origin.x() + direction.x() * koef,
|
||||
origin.y() + direction.y() * koef));
|
||||
} else {
|
||||
clipped_edge->push_back(
|
||||
point_type(edge.vertex1()->x(), edge.vertex1()->y()));
|
||||
clipped_edge->push_back(point_type(edge.vertex0()->x(), edge.vertex0()->y()));
|
||||
clipped_edge->push_back(point_type(edge.vertex0()->x() + direction.x() * koef, edge.vertex0()->y() + direction.y() * koef));
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,11 +302,16 @@ static inline void dump_voronoi_to_svg(
|
||||
const Lines &helper_lines = Lines(),
|
||||
double scale = 0)
|
||||
{
|
||||
const bool internalEdgesOnly = false;
|
||||
|
||||
BoundingBox bbox;
|
||||
bbox.merge(get_extents(points));
|
||||
bbox.merge(get_extents(lines));
|
||||
bbox.merge(get_extents(offset_curves));
|
||||
bbox.merge(get_extents(helper_lines));
|
||||
for (boost::polygon::voronoi_diagram<double>::const_vertex_iterator it = vd.vertices().begin(); it != vd.vertices().end(); ++it)
|
||||
if (! internalEdgesOnly || it->color() != Voronoi::Internal::EXTERNAL_COLOR)
|
||||
bbox.merge(Point(it->x(), it->y()));
|
||||
bbox.min -= (0.01 * bbox.size().cast<double>()).cast<coord_t>();
|
||||
bbox.max += (0.01 * bbox.size().cast<double>()).cast<coord_t>();
|
||||
|
||||
@ -321,15 +321,17 @@ static inline void dump_voronoi_to_svg(
|
||||
0.01
|
||||
* std::min(bbox.size().x(), bbox.size().y());
|
||||
else
|
||||
scale /= SCALING_FACTOR;
|
||||
scale *= SCALING_FACTOR;
|
||||
|
||||
const std::string inputSegmentPointColor = "lightseagreen";
|
||||
const coord_t inputSegmentPointRadius = coord_t(0.09 * scale);
|
||||
const coord_t inputSegmentPointRadius = std::max<coord_t>(1, coord_t(0.09 * scale));
|
||||
const std::string inputSegmentColor = "lightseagreen";
|
||||
const coord_t inputSegmentLineWidth = coord_t(0.03 * scale);
|
||||
|
||||
const std::string voronoiPointColor = "black";
|
||||
const coord_t voronoiPointRadius = coord_t(0.06 * scale);
|
||||
const std::string voronoiPointColorOutside = "red";
|
||||
const std::string voronoiPointColorInside = "blue";
|
||||
const coord_t voronoiPointRadius = std::max<coord_t>(1, coord_t(0.06 * scale));
|
||||
const std::string voronoiLineColorPrimary = "black";
|
||||
const std::string voronoiLineColorSecondary = "green";
|
||||
const std::string voronoiArcColor = "red";
|
||||
@ -341,7 +343,6 @@ static inline void dump_voronoi_to_svg(
|
||||
const std::string helperLineColor = "orange";
|
||||
const coord_t helperLineWidth = coord_t(0.04 * scale);
|
||||
|
||||
const bool internalEdgesOnly = false;
|
||||
const bool primaryEdgesOnly = false;
|
||||
|
||||
::Slic3r::SVG svg(path, bbox);
|
||||
@ -360,9 +361,11 @@ static inline void dump_voronoi_to_svg(
|
||||
Voronoi::Internal::point_type(double(it->b(0)), double(it->b(1)))));
|
||||
|
||||
// Color exterior edges.
|
||||
for (boost::polygon::voronoi_diagram<double>::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it)
|
||||
if (!it->is_finite())
|
||||
Voronoi::Internal::color_exterior(&(*it));
|
||||
if (internalEdgesOnly) {
|
||||
for (boost::polygon::voronoi_diagram<double>::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it)
|
||||
if (!it->is_finite())
|
||||
Voronoi::Internal::color_exterior(&(*it));
|
||||
}
|
||||
|
||||
// Draw the end points of the input polygon.
|
||||
for (Lines::const_iterator it = lines.begin(); it != lines.end(); ++it) {
|
||||
@ -376,8 +379,19 @@ static inline void dump_voronoi_to_svg(
|
||||
#if 1
|
||||
// Draw voronoi vertices.
|
||||
for (boost::polygon::voronoi_diagram<double>::const_vertex_iterator it = vd.vertices().begin(); it != vd.vertices().end(); ++it)
|
||||
if (! internalEdgesOnly || it->color() != Voronoi::Internal::EXTERNAL_COLOR)
|
||||
svg.draw(Point(coord_t(it->x()), coord_t(it->y())), voronoiPointColor, voronoiPointRadius);
|
||||
if (! internalEdgesOnly || it->color() != Voronoi::Internal::EXTERNAL_COLOR) {
|
||||
const std::string *color = nullptr;
|
||||
switch (Voronoi::vertex_category(*it)) {
|
||||
case Voronoi::VertexCategory::OnContour: color = &voronoiPointColor; break;
|
||||
case Voronoi::VertexCategory::Outside: color = &voronoiPointColorOutside; break;
|
||||
case Voronoi::VertexCategory::Inside: color = &voronoiPointColorInside; break;
|
||||
default: color = &voronoiPointColor; // assert(false);
|
||||
}
|
||||
Point pt(coord_t(it->x()), coord_t(it->y()));
|
||||
if (it->x() * pt.x() >= 0. && it->y() * pt.y() >= 0.)
|
||||
// Conversion to coord_t is valid.
|
||||
svg.draw(Point(coord_t(it->x()), coord_t(it->y())), *color, voronoiPointRadius);
|
||||
}
|
||||
|
||||
for (boost::polygon::voronoi_diagram<double>::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it) {
|
||||
if (primaryEdgesOnly && !it->is_primary())
|
||||
@ -401,8 +415,32 @@ static inline void dump_voronoi_to_svg(
|
||||
} else if (! it->is_primary())
|
||||
color = voronoiLineColorSecondary;
|
||||
}
|
||||
for (std::size_t i = 0; i + 1 < samples.size(); ++i)
|
||||
svg.draw(Line(Point(coord_t(samples[i].x()), coord_t(samples[i].y())), Point(coord_t(samples[i+1].x()), coord_t(samples[i+1].y()))), color, voronoiLineWidth);
|
||||
for (std::size_t i = 0; i + 1 < samples.size(); ++ i) {
|
||||
Vec2d a(samples[i].x(), samples[i].y());
|
||||
Vec2d b(samples[i+1].x(), samples[i+1].y());
|
||||
// Convert to coord_t.
|
||||
Point ia = a.cast<coord_t>();
|
||||
Point ib = b.cast<coord_t>();
|
||||
// Is the conversion possible? Do the resulting points fit into int32_t?
|
||||
auto in_range = [](const Point &ip, const Vec2d &p) { return p.x() * ip.x() >= 0. && p.y() * ip.y() >= 0.; };
|
||||
bool a_in_range = in_range(ia, a);
|
||||
bool b_in_range = in_range(ib, b);
|
||||
if (! a_in_range || ! b_in_range) {
|
||||
if (! a_in_range && ! b_in_range)
|
||||
// None fits, ignore.
|
||||
continue;
|
||||
// One fit, the other does not. Try to clip.
|
||||
Vec2d v = b - a;
|
||||
v.normalize();
|
||||
v *= bbox.size().cast<double>().norm();
|
||||
auto p = a_in_range ? Vec2d(a + v) : Vec2d(b - v);
|
||||
Point ip = p.cast<coord_t>();
|
||||
if (! in_range(ip, p))
|
||||
continue;
|
||||
(a_in_range ? ib : ia) = ip;
|
||||
}
|
||||
svg.draw(Line(ia, ib), color, voronoiLineWidth);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -228,6 +228,16 @@ ForwardIt binary_find_by_predicate(ForwardIt first, ForwardIt last, LowerThanKey
|
||||
return first != last && equal_to_key(*first) ? first : last;
|
||||
}
|
||||
|
||||
template<typename ContainerType, typename ValueType> inline bool contains(const ContainerType &c, const ValueType &v)
|
||||
{ return std::find(c.begin(), c.end(), v) != c.end(); }
|
||||
template<typename T> inline bool contains(const std::initializer_list<T> &il, const T &v)
|
||||
{ return std::find(il.begin(), il.end(), v) != il.end(); }
|
||||
|
||||
template<typename ContainerType, typename ValueType> inline bool one_of(const ValueType &v, const ContainerType &c)
|
||||
{ return contains(c, v); }
|
||||
template<typename T> inline bool one_of(const T& v, const std::initializer_list<T>& il)
|
||||
{ return contains(il, v); }
|
||||
|
||||
template<typename T>
|
||||
static inline T sqr(T x)
|
||||
{
|
||||
|
@ -38,6 +38,26 @@ TEST_CASE("Voronoi missing edges - points 12067", "[Voronoi]")
|
||||
{ -5, 0 }
|
||||
};
|
||||
|
||||
#if 0
|
||||
for (Point &p : pts) {
|
||||
Vec2d q = p.cast<double>();
|
||||
p.x() = scale_(p.x());
|
||||
p.y() = scale_(p.y());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// Try to rotate, maybe the issue is caused by incorrect handling of vertical or horizontal edges?
|
||||
double a = 0.18764587962597876897475f;
|
||||
double c = cos(a);
|
||||
double s = sin(a);
|
||||
for (Point &p : poly.points) {
|
||||
Vec2d q = p.cast<double>();
|
||||
p.x() = coord_t(q.x() * c + q.y() * s + 0.5);
|
||||
p.y() = coord_t(- q.x() * s + q.y() * c + 0.5);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Construction of the Voronoi Diagram.
|
||||
VD vd;
|
||||
construct_voronoi(pts.begin(), pts.end(), &vd);
|
||||
@ -133,33 +153,40 @@ TEST_CASE("Voronoi missing edges - Alessandro gapfill 12707", "[Voronoi]")
|
||||
{ { 41427551, 0}, { 42127548, 699996 } }
|
||||
};
|
||||
|
||||
Lines lines = to_lines(Polygon {
|
||||
{ 0, 10000000},
|
||||
{ 700000, 1}, // it has to be 1, higher number, zero or -1 work.
|
||||
{ 700000, 9000000},
|
||||
{ 9100000, 9000000},
|
||||
{ 9100000, 0},
|
||||
{10000000, 10000000}
|
||||
});
|
||||
Polygon poly {
|
||||
{ 0, 10000000},
|
||||
{ 700000, 1}, // it has to be 1, higher number, zero or -1 work.
|
||||
{ 700000, 9000000},
|
||||
{ 9100000, 9000000},
|
||||
{ 9100000, 0},
|
||||
{10000000, 10000000}
|
||||
};
|
||||
|
||||
#if 1
|
||||
// Try to rotate, maybe the issue is caused by incorrect handling of vertical or horizontal edges?
|
||||
double a = 0.18764587962597876897475f;
|
||||
double c = cos(a);
|
||||
double s = sin(a);
|
||||
for (Point &p : poly.points) {
|
||||
Vec2d q = p.cast<double>();
|
||||
p.x() = coord_t(q.x() * c + q.y() * s + 0.5);
|
||||
p.y() = coord_t(- q.x() * s + q.y() * c + 0.5);
|
||||
}
|
||||
#endif
|
||||
|
||||
Polygon poly;
|
||||
std::mt19937 gen;
|
||||
std::uniform_int_distribution<coord_t> dist(-100, 100);
|
||||
for (size_t i = 0; i < lines.size(); ++ i) {
|
||||
Line &l1 = lines[i];
|
||||
Line &l2 = lines[(i + 1) % lines.size()];
|
||||
REQUIRE(l1.b.x() == l2.a.x());
|
||||
REQUIRE(l1.b.y() == l2.a.y());
|
||||
for (Point &p : poly.points) {
|
||||
#if 0
|
||||
// Wiggle the points a bit to find out whether this fixes the voronoi diagram for this particular polygon.
|
||||
l1.b.x() = (l2.a.x() += dist(gen));
|
||||
l1.b.y() = (l2.a.y() += dist(gen));
|
||||
p.x() = (p.x() += dist(gen));
|
||||
p.y() = (p.y() += dist(gen));
|
||||
#endif
|
||||
poly.points.emplace_back(l1.a);
|
||||
}
|
||||
|
||||
REQUIRE(intersecting_edges({ poly }).empty());
|
||||
|
||||
Lines lines = to_lines(poly);
|
||||
VD vd;
|
||||
construct_voronoi(lines.begin(), lines.end(), &vd);
|
||||
|
||||
@ -169,6 +196,114 @@ TEST_CASE("Voronoi missing edges - Alessandro gapfill 12707", "[Voronoi]")
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("Voronoi weirdness", "[Voronoi]")
|
||||
{
|
||||
Polygon poly2 {
|
||||
{ 0, 0 },
|
||||
{ 70000000, 0 },
|
||||
{ 70000000, 1300000 },
|
||||
// { 70000001, 14000000 }
|
||||
{ 70700000, 14000000 }
|
||||
};
|
||||
|
||||
Polygon poly5 {
|
||||
{ 35058884, -25732145 },
|
||||
{ 35058884, -19586070 },
|
||||
{ 32753739, -20246796 },
|
||||
{ 28756244, -21010725 },
|
||||
{ 24657532, -21657939 },
|
||||
{ 20836260, -21960233 },
|
||||
{ 16115145, -22070742 },
|
||||
{ 11850152, -21839761 },
|
||||
{ 7646240, -21470177 },
|
||||
{ 3607605, -20786940 },
|
||||
{ 1280947, -20329742 },
|
||||
{ -292823, -19963790 },
|
||||
{ -3844469, -18809741 },
|
||||
{ -7237277, -17593723 },
|
||||
{ -10225900, -16143761 },
|
||||
{ -13030266, -14643721 },
|
||||
{ -15404294, -12977561 },
|
||||
{ -17601713, -11280712 },
|
||||
{ -19241930, -9435607 },
|
||||
{ -20714420, -7583739 },
|
||||
{ -21726144, -5664355 },
|
||||
{ -22579294, -3741947 },
|
||||
{ -22966684, -1786321 },
|
||||
{ -23200322, 170140 },
|
||||
{ -22966684, 2126602 },
|
||||
{ -22579296, 4082227 },
|
||||
{ -21726148, 6004637 },
|
||||
{ -20714424, 7924020 },
|
||||
{ -19241932, 9775888 },
|
||||
{ -17601717, 11620994 },
|
||||
{ -15404423, 13317749 },
|
||||
{ -13030276, 14984003 },
|
||||
{ -10225910, 16484042 },
|
||||
{ -7237288, 17934005 },
|
||||
{ -3844482, 19150025 },
|
||||
{ -292841, 20304074 },
|
||||
{ 1280949, 20670031 },
|
||||
{ 3607587, 21127226 },
|
||||
{ 7646218, 21810465 },
|
||||
{ 11850128, 22180055 },
|
||||
{ 16115122, 22411036 },
|
||||
{ 20836263, 22300531 },
|
||||
{ 24657513, 21998239 },
|
||||
{ 28756227, 21351025 },
|
||||
{ 32753725, 20587092 },
|
||||
{ 35058893, 19926309 },
|
||||
{ 35058893, 35000000 },
|
||||
{ -31657232, 35000000 },
|
||||
{ -31657202, -35000000 },
|
||||
{ 35058881, -35000000 }
|
||||
};
|
||||
|
||||
Polygon poly7 {
|
||||
{ 35058884, -25732145 },
|
||||
{ 35058884, -19586070 },
|
||||
{ -31657202, -35000000 },
|
||||
{ 35058881, -35000000 }
|
||||
};
|
||||
|
||||
// coord_t shift = 35058881;
|
||||
coord_t shift_ok = 17000000;
|
||||
coord_t shift = 35058881;
|
||||
Polygon poly {
|
||||
// <-4, 0>: bug
|
||||
// -5: ok
|
||||
// 1 - ok
|
||||
{ 0 + shift, -35000000 },
|
||||
{ 0 + shift, -25732145 },
|
||||
{ 0 + shift, -19586070 },
|
||||
{ -66716086 + shift, -35000000 }
|
||||
};
|
||||
|
||||
REQUIRE(intersecting_edges({ poly }).empty());
|
||||
REQUIRE(poly.area() > 0.);
|
||||
|
||||
#if 0
|
||||
// Try to rotate, maybe the issue is caused by incorrect handling of vertical or horizontal edges?
|
||||
double a = 0.18764587962597876897475f;
|
||||
double c = cos(a);
|
||||
double s = sin(a);
|
||||
for (Point &p : poly.points) {
|
||||
Vec2d q = p.cast<double>();
|
||||
p.x() = coord_t(q.x() * c + q.y() * s + 0.5);
|
||||
p.y() = coord_t(- q.x() * s + q.y() * c + 0.5);
|
||||
}
|
||||
#endif
|
||||
|
||||
VD vd;
|
||||
Lines lines = to_lines(poly);
|
||||
construct_voronoi(lines.begin(), lines.end(), &vd);
|
||||
|
||||
#ifdef VORONOI_DEBUG_OUT
|
||||
dump_voronoi_to_svg(debug_out_path("voronoi-weirdness.svg").c_str(),
|
||||
vd, Points(), lines);
|
||||
#endif
|
||||
}
|
||||
|
||||
// https://svn.boost.org/trac10/ticket/12903
|
||||
// division by zero reported, but this issue is most likely a non-issue, as it produces an infinity for the interval of validity
|
||||
// of the floating point calculation, therefore forcing a recalculation with extended accuracy.
|
||||
@ -1228,7 +1363,7 @@ TEST_CASE("Voronoi offset", "[VoronoiOffset]")
|
||||
for (const OffsetTest &ot : {
|
||||
OffsetTest { scale_(0.2), 1, 1 },
|
||||
OffsetTest { scale_(0.4), 1, 1 },
|
||||
OffsetTest { scale_(0.5), 1, 1 },
|
||||
OffsetTest { scale_(0.5), 1, 2 },
|
||||
OffsetTest { scale_(0.505), 1, 2 },
|
||||
OffsetTest { scale_(0.51), 1, 2 },
|
||||
OffsetTest { scale_(0.52), 1, 1 },
|
||||
@ -1237,21 +1372,21 @@ TEST_CASE("Voronoi offset", "[VoronoiOffset]")
|
||||
OffsetTest { scale_(0.55), 1, 0 }
|
||||
}) {
|
||||
|
||||
Polygons offsetted_polygons_out = voronoi_offset(vd, lines, ot.distance, scale_(0.005));
|
||||
REQUIRE(offsetted_polygons_out.size() == ot.num_outer);
|
||||
|
||||
#if 0
|
||||
Polygons offsetted_polygons_out = Slic3r::Voronoi::offset(vd, lines, ot.distance, scale_(0.005));
|
||||
#ifdef VORONOI_DEBUG_OUT
|
||||
dump_voronoi_to_svg(debug_out_path("voronoi-offset-out-%lf.svg", ot.distance).c_str(),
|
||||
vd, Points(), lines, offsetted_polygons_out);
|
||||
#endif
|
||||
REQUIRE(offsetted_polygons_out.size() == ot.num_outer);
|
||||
#endif
|
||||
|
||||
Polygons offsetted_polygons_in = voronoi_offset(vd, lines, - ot.distance, scale_(0.005));
|
||||
REQUIRE(offsetted_polygons_in.size() == ot.num_inner);
|
||||
|
||||
Polygons offsetted_polygons_in = Slic3r::Voronoi::offset(vd, lines, - ot.distance, scale_(0.005));
|
||||
#ifdef VORONOI_DEBUG_OUT
|
||||
dump_voronoi_to_svg(debug_out_path("voronoi-offset-in-%lf.svg", ot.distance).c_str(),
|
||||
vd, Points(), lines, offsetted_polygons_in);
|
||||
#endif
|
||||
REQUIRE(offsetted_polygons_in.size() == ot.num_inner);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1296,21 +1431,20 @@ TEST_CASE("Voronoi offset 2", "[VoronoiOffset]")
|
||||
OffsetTest { scale_(0.4), 2, 2 },
|
||||
OffsetTest { scale_(0.45), 2, 2 },
|
||||
OffsetTest { scale_(0.48), 2, 2 },
|
||||
//FIXME Exact intersections of an Offset curve with any Voronoi vertex are not handled correctly yet.
|
||||
// OffsetTest { scale_(0.5), 2, 2 },
|
||||
OffsetTest { scale_(0.5), 2, 4 },
|
||||
OffsetTest { scale_(0.505), 2, 4 },
|
||||
OffsetTest { scale_(0.7), 2, 0 },
|
||||
OffsetTest { scale_(0.8), 1, 0 }
|
||||
}) {
|
||||
|
||||
Polygons offsetted_polygons_out = voronoi_offset(vd, lines, ot.distance, scale_(0.005));
|
||||
Polygons offsetted_polygons_out = Slic3r::Voronoi::offset(vd, lines, ot.distance, scale_(0.005));
|
||||
#ifdef VORONOI_DEBUG_OUT
|
||||
dump_voronoi_to_svg(debug_out_path("voronoi-offset2-out-%lf.svg", ot.distance).c_str(),
|
||||
vd, Points(), lines, offsetted_polygons_out);
|
||||
#endif
|
||||
REQUIRE(offsetted_polygons_out.size() == ot.num_outer);
|
||||
|
||||
Polygons offsetted_polygons_in = voronoi_offset(vd, lines, - ot.distance, scale_(0.005));
|
||||
Polygons offsetted_polygons_in = Slic3r::Voronoi::offset(vd, lines, - ot.distance, scale_(0.005));
|
||||
#ifdef VORONOI_DEBUG_OUT
|
||||
dump_voronoi_to_svg(debug_out_path("voronoi-offset2-in-%lf.svg", ot.distance).c_str(),
|
||||
vd, Points(), lines, offsetted_polygons_in);
|
||||
@ -1360,14 +1494,13 @@ TEST_CASE("Voronoi offset 3", "[VoronoiOffset]")
|
||||
|
||||
VD vd;
|
||||
Lines lines = to_lines(poly);
|
||||
construct_voronoi(lines.begin(), lines.end(), &vd);
|
||||
construct_voronoi(lines.begin(), lines.end(), &vd);
|
||||
|
||||
for (const OffsetTest &ot : {
|
||||
OffsetTest { scale_(0.2), 2, 2 },
|
||||
OffsetTest { scale_(0.4), 2, 2 },
|
||||
OffsetTest { scale_(0.49), 2, 2 },
|
||||
//FIXME this fails
|
||||
// OffsetTest { scale_(0.5), 2, 2 },
|
||||
OffsetTest { scale_(0.5), 2, 2 },
|
||||
OffsetTest { scale_(0.51), 2, 2 },
|
||||
OffsetTest { scale_(0.56), 2, 2 },
|
||||
OffsetTest { scale_(0.6), 2, 2 },
|
||||
@ -1375,23 +1508,417 @@ TEST_CASE("Voronoi offset 3", "[VoronoiOffset]")
|
||||
OffsetTest { scale_(0.8), 1, 6 },
|
||||
OffsetTest { scale_(0.9), 1, 6 },
|
||||
OffsetTest { scale_(0.99), 1, 6 },
|
||||
//FIXME this fails
|
||||
// OffsetTest { scale_(1.0), 1, 6 },
|
||||
OffsetTest { scale_(1.0), 1, 0 },
|
||||
OffsetTest { scale_(1.01), 1, 0 },
|
||||
}) {
|
||||
|
||||
Polygons offsetted_polygons_out = voronoi_offset(vd, lines, ot.distance, scale_(0.005));
|
||||
Polygons offsetted_polygons_out = Slic3r::Voronoi::offset(vd, lines, ot.distance, scale_(0.005));
|
||||
#ifdef VORONOI_DEBUG_OUT
|
||||
dump_voronoi_to_svg(debug_out_path("voronoi-offset2-out-%lf.svg", ot.distance).c_str(),
|
||||
dump_voronoi_to_svg(debug_out_path("voronoi-offset3-out-%lf.svg", ot.distance).c_str(),
|
||||
vd, Points(), lines, offsetted_polygons_out);
|
||||
#endif
|
||||
REQUIRE(offsetted_polygons_out.size() == ot.num_outer);
|
||||
|
||||
Polygons offsetted_polygons_in = voronoi_offset(vd, lines, - ot.distance, scale_(0.005));
|
||||
Polygons offsetted_polygons_in = Slic3r::Voronoi::offset(vd, lines, - ot.distance, scale_(0.005));
|
||||
#ifdef VORONOI_DEBUG_OUT
|
||||
dump_voronoi_to_svg(debug_out_path("voronoi-offset2-in-%lf.svg", ot.distance).c_str(),
|
||||
dump_voronoi_to_svg(debug_out_path("voronoi-offset3-in-%lf.svg", ot.distance).c_str(),
|
||||
vd, Points(), lines, offsetted_polygons_in);
|
||||
#endif
|
||||
REQUIRE(offsetted_polygons_in.size() == ot.num_inner);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Voronoi offset with edge collapse", "[VoronoiOffset4]")
|
||||
{
|
||||
Polygons poly
|
||||
{
|
||||
// Outer contour
|
||||
{
|
||||
{ 434890, -64754575 },
|
||||
{ 541060, -64669076 },
|
||||
{ 585647, -64583538 },
|
||||
{ 576999, -64484233 },
|
||||
{ 485666, -64191173 },
|
||||
{ 1029323, -63646261 },
|
||||
{ 1416925, -63666243 },
|
||||
{ 1541532, -63643075 },
|
||||
{ 1541535, -63643075 },
|
||||
{ 1541535, -63643074 },
|
||||
{ 1552612, -63641015 },
|
||||
{ 1631609, -63568270 },
|
||||
{ 1678393, -63443639 },
|
||||
{ 1725519, -63219942 },
|
||||
{ 1770552, -62903321 },
|
||||
{ 1742544, -62755934 },
|
||||
{ 1758152, -62588378 },
|
||||
{ 1702289, -62474826 },
|
||||
{ 1638627, -62242058 },
|
||||
{ 1671281, -61938568 },
|
||||
{ 1792676, -61478332 },
|
||||
{ 1934894, -60760597 },
|
||||
{ 2160333, -60064089 },
|
||||
{ 2638183, -58972890 },
|
||||
{ 2933095, -58478536 },
|
||||
{ 3173586, -58159527 },
|
||||
{ 3557779, -57556727 },
|
||||
{ 3707088, -57158174 },
|
||||
{ 3758053, -56907139 },
|
||||
{ 3935932, -56278649 },
|
||||
{ 4077331, -56033426 },
|
||||
{ 4151386, -55768739 },
|
||||
{ 4293796, -55561683 },
|
||||
{ 4383089, -55387391 },
|
||||
{ 4614128, -55201443 },
|
||||
{ 5268755, -54333831 },
|
||||
{ 5547634, -53797296 },
|
||||
{ 5573864, -53639250 },
|
||||
{ 5736812, -53304157 },
|
||||
{ 6090973, -52066302 },
|
||||
{ 6148630, -51666664 },
|
||||
{ 6189511, -50974991 },
|
||||
{ 6244112, -50774489 },
|
||||
{ 6302489, -50761556 },
|
||||
{ 6511179, -50579861 },
|
||||
{ 6778128, -50398667 },
|
||||
{ 6896879, -50350264 },
|
||||
{ 7388259, -49913262 },
|
||||
{ 7630584, -49602449 },
|
||||
{ 7886846, -48987881 },
|
||||
{ 7871333, -48318666 },
|
||||
{ 7770349, -47841179 },
|
||||
{ 7570223, -47234733 },
|
||||
{ 7283115, -46705503 },
|
||||
{ 6842948, -46056539 },
|
||||
{ 6612732, -45760004 },
|
||||
{ 6150430, -44991494 },
|
||||
{ 5564326, -44168114 },
|
||||
{ 5193032, -43807544 },
|
||||
{ 4932097, -43489047 },
|
||||
{ 3857385, -42548846 },
|
||||
{ 3764745, -42081468 },
|
||||
{ 3539887, -41422273 },
|
||||
{ 3283048, -40803856 },
|
||||
{ 3005925, -40367981 },
|
||||
{ 3136185, -39834533 },
|
||||
{ 3333757, -38499972 },
|
||||
{ 3360660, -38183895 },
|
||||
{ 3353375, -38036005 },
|
||||
{ 3398808, -37582504 },
|
||||
{ 3604229, -37221781 },
|
||||
{ 3698079, -36962934 },
|
||||
{ 4000449, -36007804 },
|
||||
{ 4256811, -35016707 },
|
||||
{ 4405951, -34581428 },
|
||||
{ 4364534, -34178439 },
|
||||
{ 4124603, -33432250 },
|
||||
{ 3806159, -32765167 },
|
||||
{ 3359088, -32109020 },
|
||||
{ 2880790, -31317192 },
|
||||
{ 1548334, -30402139 },
|
||||
{ -7, -30131023 },
|
||||
{ -1548347, -30402139 },
|
||||
{ -2880803, -31317189 },
|
||||
{ -3359100, -32109018 },
|
||||
{ -3806173, -32765166 },
|
||||
{ -4124617, -33432248 },
|
||||
{ -4364548, -34178436 },
|
||||
{ -4405966, -34581423 },
|
||||
{ -4256825, -35016707 },
|
||||
{ -4000461, -36007800 },
|
||||
{ -3698093, -36962933 },
|
||||
{ -3604243, -37221781 },
|
||||
{ -3398823, -37582501 },
|
||||
{ -3353390, -38036003 },
|
||||
{ -3360675, -38183892 },
|
||||
{ -3333772, -38499972 },
|
||||
{ -3136200, -39834530 },
|
||||
{ -3005940, -40367980 },
|
||||
{ -3283062, -40803852 },
|
||||
{ -3539902, -41422273 },
|
||||
{ -3764761, -42081468 },
|
||||
{ -3857402, -42548846 },
|
||||
{ -4932112, -43489047 },
|
||||
{ -5193047, -43807544 },
|
||||
{ -5564341, -44168114 },
|
||||
{ -6150446, -44991494 },
|
||||
{ -6612748, -45760000 },
|
||||
{ -6842965, -46056536 },
|
||||
{ -7283130, -46705503 },
|
||||
{ -7570238, -47234733 },
|
||||
{ -7770365, -47841179 },
|
||||
{ -7871349, -48318666 },
|
||||
{ -7886860, -48987873 },
|
||||
{ -7630599, -49602451 },
|
||||
{ -7388277, -49913260 },
|
||||
{ -6896896, -50350264 },
|
||||
{ -6778145, -50398667 },
|
||||
{ -6511196, -50579862 },
|
||||
{ -6302504, -50761557 },
|
||||
{ -6244127, -50774488 },
|
||||
{ -6189527, -50974989 },
|
||||
{ -6148648, -51666664 },
|
||||
{ -6090990, -52066302 },
|
||||
{ -5736829, -53304157 },
|
||||
{ -5573882, -53639250 },
|
||||
{ -5547651, -53797296 },
|
||||
{ -5268772, -54333831 },
|
||||
{ -4614145, -55201443 },
|
||||
{ -4383106, -55387389 },
|
||||
{ -4293814, -55561683 },
|
||||
{ -4151404, -55768739 },
|
||||
{ -4077350, -56033423 },
|
||||
{ -3935952, -56278647 },
|
||||
{ -3758072, -56907137 },
|
||||
{ -3707107, -57158170 },
|
||||
{ -3557796, -57556727 },
|
||||
{ -3173605, -58159527 },
|
||||
{ -2933113, -58478536 },
|
||||
{ -2638201, -58972890 },
|
||||
{ -2295003, -59738435 },
|
||||
{ -2160353, -60064089 },
|
||||
{ -1978487, -60596626 },
|
||||
{ -1792695, -61478332 },
|
||||
{ -1671298, -61938574 },
|
||||
{ -1638646, -62242058 },
|
||||
{ -1702306, -62474826 },
|
||||
{ -1758168, -62588380 },
|
||||
{ -1742563, -62755934 },
|
||||
{ -1770570, -62903317 },
|
||||
{ -1725537, -63219946 },
|
||||
{ -1678412, -63443639 },
|
||||
{ -1631627, -63568270 },
|
||||
{ -1553479, -63640201 },
|
||||
{ -1416944, -63666243 },
|
||||
{ -998854, -63645714 },
|
||||
{ -485685, -64191173 },
|
||||
{ -577019, -64484225 },
|
||||
{ -585667, -64583538 },
|
||||
{ -541079, -64669076 },
|
||||
{ -434910, -64754575 },
|
||||
{ -294192, -64810609 },
|
||||
{ 294172, -64810609 },
|
||||
},
|
||||
// Hole 1
|
||||
{
|
||||
{ -842246, -45167428 },
|
||||
{ -1473641, -45154392 },
|
||||
{ -2181728, -45100161 },
|
||||
{ -2804308, -44985842 },
|
||||
{ -3100514, -44879269 },
|
||||
{ -3836807, -44802155 },
|
||||
{ -4035816, -44718913 },
|
||||
{ -4167175, -44583299 },
|
||||
{ -4496705, -44467674 },
|
||||
{ -4486674, -44382045 },
|
||||
{ -4343949, -44070577 },
|
||||
{ -3740991, -43494686 },
|
||||
{ -2701372, -43313358 },
|
||||
{ -1493599, -43312838 },
|
||||
{ -8, -43352868 },
|
||||
{ 1414575, -43313336 },
|
||||
{ 2701358, -43313358 },
|
||||
{ 3095462, -43374735 },
|
||||
{ 3740975, -43494686 },
|
||||
{ 4343934, -44070583 },
|
||||
{ 4486657, -44382044 },
|
||||
{ 4496688, -44467670 },
|
||||
{ 4167159, -44583300 },
|
||||
{ 4035800, -44718913 },
|
||||
{ 3836792, -44802155 },
|
||||
{ 3100498, -44879269 },
|
||||
{ 2804292, -44985842 },
|
||||
{ 2181712, -45100161 },
|
||||
{ 1473625, -45154389 },
|
||||
{ 842231, -45167428 },
|
||||
{ -8, -45232686 },
|
||||
},
|
||||
// Hole 2
|
||||
{
|
||||
{ 1657455, -63016679 },
|
||||
{ 1723196, -63056286 },
|
||||
{ 1541535, -63643074 },
|
||||
{ 1541532, -63643075 },
|
||||
{ 1030020, -63645562 },
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
VD vd;
|
||||
Lines lines = to_lines(poly);
|
||||
construct_voronoi(lines.begin(), lines.end(), &vd);
|
||||
|
||||
for (const OffsetTest &ot : {
|
||||
OffsetTest { scale_(0.2), 2, 2 },
|
||||
OffsetTest { scale_(0.4), 2, 2 },
|
||||
OffsetTest { scale_(0.49), 2, 3 },
|
||||
OffsetTest { scale_(0.51), 2, 2 },
|
||||
OffsetTest { scale_(0.56), 2, 2 },
|
||||
OffsetTest { scale_(0.6), 2, 2 },
|
||||
OffsetTest { scale_(0.7), 2, 2 },
|
||||
OffsetTest { scale_(0.8), 2, 2 },
|
||||
OffsetTest { scale_(0.9), 2, 2 },
|
||||
OffsetTest { scale_(0.99), 1, 2 },
|
||||
OffsetTest { scale_(1.0), 1, 2 },
|
||||
OffsetTest { scale_(1.01), 1, 2 },
|
||||
}) {
|
||||
|
||||
Polygons offsetted_polygons_out = Slic3r::Voronoi::offset(vd, lines, ot.distance, scale_(0.005));
|
||||
#ifdef VORONOI_DEBUG_OUT
|
||||
dump_voronoi_to_svg(debug_out_path("voronoi-offset3-out-%lf.svg", ot.distance).c_str(),
|
||||
vd, Points(), lines, offsetted_polygons_out);
|
||||
#endif
|
||||
REQUIRE(offsetted_polygons_out.size() == ot.num_outer);
|
||||
|
||||
Polygons offsetted_polygons_in = Slic3r::Voronoi::offset(vd, lines, - ot.distance, scale_(0.005));
|
||||
#ifdef VORONOI_DEBUG_OUT
|
||||
dump_voronoi_to_svg(debug_out_path("voronoi-offset3-in-%lf.svg", ot.distance).c_str(),
|
||||
vd, Points(), lines, offsetted_polygons_in);
|
||||
#endif
|
||||
REQUIRE(offsetted_polygons_in.size() == ot.num_inner);
|
||||
}
|
||||
}
|
||||
|
||||
// A sample extracted from file medallion_printable_fixed-teeth.stl from https://www.thingiverse.com/thing:1347129
|
||||
// This test for offset scale_(2.9) and bigger
|
||||
// triggers assert(r < std::max(d0, d1) + EPSILON) in function first_circle_segment_intersection_parameter.
|
||||
TEST_CASE("Voronoi offset 5", "[VoronoiOffset5]")
|
||||
{
|
||||
Polygons poly = {
|
||||
Polygon {
|
||||
{ 0 , -16077501 },
|
||||
{ 3015222 , -16142836 },
|
||||
{ 3072642 , -16138163 },
|
||||
{ 3094279 , -16105662 },
|
||||
{ 3110660 , -15140728 },
|
||||
{ 3157438 , -14105326 },
|
||||
{ 3338367 , -11081394 },
|
||||
{ 3443412 , -8381621 },
|
||||
{ 3472489 , -6084497 },
|
||||
{ 3445790 , -5962924 },
|
||||
{ 3061725 , -6003484 },
|
||||
{ 3030326 , -6030622 },
|
||||
{ 2989343 , -6270378 },
|
||||
{ 2903752 , -7368176 },
|
||||
{ 2856704 , -7740619 },
|
||||
{ 2795743 , -7978809 },
|
||||
{ 2729231 , -8098866 },
|
||||
{ 2666509 , -8131138 },
|
||||
{ 2614169 , -8112308 },
|
||||
{ 2561157 , -8032014 },
|
||||
{ 2488290 , -7479351 },
|
||||
{ 2453360 , -6911556 },
|
||||
{ 2456148 , -6463146 },
|
||||
{ 2546029 , -4580396 },
|
||||
{ 2688181 , -2593262 },
|
||||
{ 2717617 , -1700519 },
|
||||
{ 2682232 , -1128411 },
|
||||
{ 2631029 , -832886 },
|
||||
{ 2535941 , -504483 },
|
||||
{ 2399115 , -199303 },
|
||||
{ 2290997 , -171213 },
|
||||
{ 611824 , -132865 },
|
||||
{ 6419 , -375849 },
|
||||
{ -611825 , -132865 },
|
||||
{ -2377355 , -185241 },
|
||||
{ -2420740 , -231171 },
|
||||
{ -2535942 , -504484 },
|
||||
{ -2631030 , -832887 },
|
||||
{ -2684831 , -1150821 },
|
||||
{ -2714840 , -1586454 },
|
||||
{ -2688181 , -2593262 },
|
||||
{ -2546030 , -4580396 },
|
||||
{ -2456149 , -6463145 },
|
||||
{ -2453361 , -6911557 },
|
||||
{ -2488291 , -7479352 },
|
||||
{ -2561159 , -8032018 },
|
||||
{ -2614171 , -8112309 },
|
||||
{ -2666509 , -8131138 },
|
||||
{ -2729233 , -8098868 },
|
||||
{ -2795744 , -7978809 },
|
||||
{ -2856706 , -7740619 },
|
||||
{ -2903752 , -7368176 },
|
||||
{ -2989345 , -6270378 },
|
||||
{ -3030327 , -6030622 },
|
||||
{ -3061726 , -6003484 },
|
||||
{ -3445790 , -5962924 },
|
||||
{ -3472490 , -6084498 },
|
||||
{ -3468804 , -7244095 },
|
||||
{ -3399287 , -9714025 },
|
||||
{ -3338368 , -11081395 },
|
||||
{ -3141015 , -14446051 },
|
||||
{ -3094280 , -16105662 },
|
||||
{ -3072643 , -16138163 },
|
||||
{ -3008836 , -16143225 }
|
||||
}
|
||||
};
|
||||
double area = std::accumulate(poly.begin(), poly.end(), 0., [](double a, auto &poly){ return a + poly.area(); });
|
||||
REQUIRE(area > 0.);
|
||||
|
||||
VD vd;
|
||||
Lines lines = to_lines(poly);
|
||||
construct_voronoi(lines.begin(), lines.end(), &vd);
|
||||
|
||||
for (const OffsetTest &ot : {
|
||||
OffsetTest { scale_(2.8), 1, 1 },
|
||||
OffsetTest { scale_(2.9), 1, 1 },
|
||||
OffsetTest { scale_(3.0), 1, 1 },
|
||||
}) {
|
||||
|
||||
Polygons offsetted_polygons_out = Slic3r::Voronoi::offset(vd, lines, ot.distance, scale_(0.005));
|
||||
#ifdef VORONOI_DEBUG_OUT
|
||||
dump_voronoi_to_svg(debug_out_path("voronoi-offset5-out-%lf.svg", ot.distance).c_str(),
|
||||
vd, Points(), lines, offsetted_polygons_out);
|
||||
#endif
|
||||
REQUIRE(offsetted_polygons_out.size() == ot.num_outer);
|
||||
|
||||
Polygons offsetted_polygons_in = Slic3r::Voronoi::offset(vd, lines, - ot.distance, scale_(0.005));
|
||||
#ifdef VORONOI_DEBUG_OUT
|
||||
dump_voronoi_to_svg(debug_out_path("voronoi-offset5-in-%lf.svg", ot.distance).c_str(),
|
||||
vd, Points(), lines, offsetted_polygons_in);
|
||||
#endif
|
||||
REQUIRE(offsetted_polygons_in.size() == ot.num_inner);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Voronoi skeleton", "[VoronoiSkeleton]")
|
||||
{
|
||||
coord_t mm = coord_t(scale_(1.));
|
||||
Polygons poly = {
|
||||
Polygon {
|
||||
{ 0, 0 },
|
||||
{ 1, 0 },
|
||||
{ 1, 1 },
|
||||
{ 2, 1 },
|
||||
{ 2, 0 },
|
||||
{ 3, 0 },
|
||||
{ 3, 2 },
|
||||
{ 0, 2 }
|
||||
},
|
||||
Polygon {
|
||||
{ 0, - 1 - 2 },
|
||||
{ 3, - 1 - 2 },
|
||||
{ 3, - 1 - 0 },
|
||||
{ 2, - 1 - 0 },
|
||||
{ 2, - 1 - 1 },
|
||||
{ 1, - 1 - 1 },
|
||||
{ 1, - 1 - 0 },
|
||||
{ 0, - 1 - 0 }
|
||||
},
|
||||
};
|
||||
for (Polygon &p : poly)
|
||||
for (Point &pt : p.points)
|
||||
pt *= mm;
|
||||
|
||||
double area = std::accumulate(poly.begin(), poly.end(), 0., [](double a, auto &poly){ return a + poly.area(); });
|
||||
REQUIRE(area > 0.);
|
||||
|
||||
VD vd;
|
||||
Lines lines = to_lines(poly);
|
||||
construct_voronoi(lines.begin(), lines.end(), &vd);
|
||||
Slic3r::Voronoi::annotate_inside_outside(vd, lines);
|
||||
Slic3r::Voronoi::annotate_inside_outside(vd, lines);
|
||||
static constexpr double threshold_alpha = M_PI / 12.; // 30 degrees
|
||||
std::vector<Vec2d> skeleton_edges = Slic3r::Voronoi::skeleton_edges_rough(vd, lines, threshold_alpha);
|
||||
|
||||
REQUIRE(! skeleton_edges.empty());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user