From 3e0e537b7ae5fdcc7d9b2c854b70b2285e56c157 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Thu, 4 Jun 2020 15:34:23 +0200 Subject: [PATCH] Offset curve from a Voronoi diagram: Fixed distance calculation to a bisector of two segments. --- src/libslic3r/VoronoiOffset.cpp | 37 ++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/VoronoiOffset.cpp b/src/libslic3r/VoronoiOffset.cpp index acf693305..cd96e3cdc 100644 --- a/src/libslic3r/VoronoiOffset.cpp +++ b/src/libslic3r/VoronoiOffset.cpp @@ -206,15 +206,15 @@ Polygons voronoi_offset(const VD &vd, const Lines &lines, double offset_distance } else { // Finite edge has valid points at both sides. if (cell->contains_segment() && cell2->contains_segment()) { - // This edge is a bisector of two line segments. - d0 = std::hypot(v0->x() - line0.a.x(), v0->y() - line0.a.y()); - d1 = std::hypot(v0->x() - line0.b.x(), v0->y() - line0.b.y()); - if (d0 < d1) - d1 = std::hypot(v1->x() - line0.a.x(), v1->y() - line0.a.y()); - else { - d0 = d1; - d1 = std::hypot(v1->x() - line0.b.x(), v1->y() - line0.b.y()); - } + // This edge is a bisector of two line segments. Project v0, v1 onto one of the line segments. + Vec2d pt(line0.a.cast()); + Vec2d dir(line0.b.cast() - pt); + Vec2d vec0 = Vec2d(v0->x(), v0->y()) - pt; + Vec2d vec1 = Vec2d(v1->x(), v1->y()) - pt; + double l2 = dir.squaredNorm(); + assert(l2 > 0.); + d0 = (dir * (vec0.dot(dir) / l2) - vec0).norm(); + d1 = (dir * (vec1.dot(dir) / l2) - vec1).norm(); dmin = std::min(d0, d1); } else { assert(cell->contains_point() || cell2->contains_point()); @@ -303,6 +303,15 @@ Polygons voronoi_offset(const VD &vd, const Lines &lines, double offset_distance return nullptr; }; +#ifndef NDEBUG + auto dist_to_site = [&lines](const VD::cell_type &cell, const Vec2d &point) { + const Line &line = lines[cell.source_index()]; + return cell.contains_point() ? + (((cell.source_category() == boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT) ? line.a : line.b).cast() - point).norm() : + line.distance_to(point.cast()); + }; +#endif /* NDEBUG */ + // Track the offset curves. Polygons out; double angle_step = 2. * acos((offset_distance - discretization_error) / offset_distance); @@ -329,7 +338,15 @@ Polygons voronoi_offset(const VD &vd, const Lines &lines, double offset_distance const VD::cell_type *cell = edge->cell(); Vec2d p1 = detail::voronoi_edge_offset_point(vd, lines, vertex_dist, edge_dist, *edge, offset_distance); Vec2d p2 = detail::voronoi_edge_offset_point(vd, lines, vertex_dist, edge_dist, *next_edge, offset_distance); - if (cell->contains_point()) { +#ifndef NDEBUG + { + double err = dist_to_site(*cell, p1) - offset_distance; + assert(std::abs(err) < SCALED_EPSILON); + err = dist_to_site(*cell, p2) - offset_distance; + assert(std::abs(err) < SCALED_EPSILON); + } +#endif /* NDEBUG */ + if (cell->contains_point()) { // Discretize an arc from p1 to p2 with radius = offset_distance and discretization_error. // The arc should cover angle < PI. //FIXME we should be able to produce correctly oriented output curves based on the first edge taken!