From c264969962b28fc7656cfe332c479deaa41b97e0 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sun, 25 Jan 2015 15:21:45 +0100 Subject: [PATCH] Bugfix: crash when rendering lines with zero length in 3D preview. #2569 --- lib/Slic3r/GUI/3DScene.pm | 3 ++- xs/src/libslic3r/ExtrusionEntity.cpp | 21 +++++++-------------- xs/src/libslic3r/ExtrusionEntity.hpp | 3 +-- xs/src/libslic3r/GUI/3DScene.cpp | 22 +++++++++++----------- xs/src/libslic3r/MultiPoint.cpp | 11 +++++++++++ xs/src/libslic3r/MultiPoint.hpp | 1 + xs/xsp/ExtrusionLoop.xsp | 3 +-- xs/xsp/Polyline.xsp | 1 + 8 files changed, 35 insertions(+), 30 deletions(-) diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index 1be93286b..97f8b3e63 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -1198,6 +1198,7 @@ sub _extrusionentity_to_verts { return; } elsif ($entity->isa('Slic3r::ExtrusionPath')) { my $polyline = $entity->polyline->clone; + $polyline->remove_duplicate_points; $polyline->translate(@$copy); $lines = $polyline->lines; $widths = [ map $entity->width, 0..$#$lines ]; @@ -1210,6 +1211,7 @@ sub _extrusionentity_to_verts { $closed = 1; foreach my $path (@$entity) { my $polyline = $path->polyline->clone; + $polyline->remove_duplicate_points; $polyline->translate(@$copy); my $path_lines = $polyline->lines; push @$lines, @$path_lines; @@ -1217,7 +1219,6 @@ sub _extrusionentity_to_verts { push @$heights, map $path->height, 0..$#$path_lines; } } - Slic3r::GUI::_3DScene::_extrusionentity_to_verts_do($lines, $widths, $heights, $closed, $top_z, $copy, $qverts, $tverts); } diff --git a/xs/src/libslic3r/ExtrusionEntity.cpp b/xs/src/libslic3r/ExtrusionEntity.cpp index 38a5b94ae..f4ef37c13 100644 --- a/xs/src/libslic3r/ExtrusionEntity.cpp +++ b/xs/src/libslic3r/ExtrusionEntity.cpp @@ -172,13 +172,6 @@ ExtrusionPath::grow() const return pp; } -ExtrusionLoop::operator Polygon() const -{ - Polygon polygon; - this->polygon(&polygon); - return polygon; -} - ExtrusionLoop* ExtrusionLoop::clone() const { @@ -188,8 +181,7 @@ ExtrusionLoop::clone() const bool ExtrusionLoop::make_clockwise() { - Polygon polygon = *this; - bool was_ccw = polygon.is_counter_clockwise(); + bool was_ccw = this->polygon().is_counter_clockwise(); if (was_ccw) this->reverse(); return was_ccw; } @@ -197,8 +189,7 @@ ExtrusionLoop::make_clockwise() bool ExtrusionLoop::make_counter_clockwise() { - Polygon polygon = *this; - bool was_cw = polygon.is_clockwise(); + bool was_cw = this->polygon().is_clockwise(); if (was_cw) this->reverse(); return was_cw; } @@ -223,13 +214,15 @@ ExtrusionLoop::last_point() const return this->paths.back().polyline.points.back(); // which coincides with first_point(), by the way } -void -ExtrusionLoop::polygon(Polygon* polygon) const +Polygon +ExtrusionLoop::polygon() const { + Polygon polygon; for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) { // for each polyline, append all points except the last one (because it coincides with the first one of the next polyline) - polygon->points.insert(polygon->points.end(), path->polyline.points.begin(), path->polyline.points.end()-1); + polygon.points.insert(polygon.points.end(), path->polyline.points.begin(), path->polyline.points.end()-1); } + return polygon; } double diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp index 4fba7fec7..323d935a1 100644 --- a/xs/src/libslic3r/ExtrusionEntity.hpp +++ b/xs/src/libslic3r/ExtrusionEntity.hpp @@ -92,14 +92,13 @@ class ExtrusionLoop : public ExtrusionEntity bool is_loop() const { return true; }; - operator Polygon() const; ExtrusionLoop* clone() const; bool make_clockwise(); bool make_counter_clockwise(); void reverse(); Point first_point() const; Point last_point() const; - void polygon(Polygon* polygon) const; + Polygon polygon() const; double length() const; bool split_at_vertex(const Point &point); void split_at(const Point &point); diff --git a/xs/src/libslic3r/GUI/3DScene.cpp b/xs/src/libslic3r/GUI/3DScene.cpp index 3266ae09d..d7513d2fe 100644 --- a/xs/src/libslic3r/GUI/3DScene.cpp +++ b/xs/src/libslic3r/GUI/3DScene.cpp @@ -2,25 +2,33 @@ namespace Slic3r { +// caller is responsible for supplying NO lines with zero length void _3DScene::_extrusionentity_to_verts_do(const Lines &lines, const std::vector &widths, const std::vector &heights, bool closed, double top_z, const Point ©, GLVertexArray* qverts, GLVertexArray* tverts) { + /* It looks like it's faster without reserving capacity... + // each segment has 4 quads, thus 16 vertices; + 2 caps + qverts->reserve_more(3 * 4 * (4 * lines.size() + 2)); + + // two triangles for each corner + tverts->reserve_more(3 * 3 * 2 * (lines.size() + 1)); + */ + Line prev_line; Pointf prev_b1, prev_b2; Vectorf3 prev_xy_left_normal, prev_xy_right_normal; // loop once more in case of closed loops bool first_done = false; - for (int i = 0; i <= lines.size(); ++i) { + for (size_t i = 0; i <= lines.size(); ++i) { if (i == lines.size()) i = 0; const Line &line = lines.at(i); if (i == 0 && first_done && !closed) break; double len = line.length(); - if (len == 0) continue; double unscaled_len = unscale(len); double bottom_z = top_z - heights.at(i); @@ -52,7 +60,6 @@ _3DScene::_extrusionentity_to_verts_do(const Lines &lines, const std::vector EPSILON) { - tverts->reserve_more(6); // top-right vertex triangle between previous line and this one { // use the normal going to the right calculated for the previous line @@ -82,7 +89,6 @@ _3DScene::_extrusionentity_to_verts_do(const Lines &lines, const std::vectorpush_vert(a1.x, a1.y, middle_z); } } else if (ccw < -EPSILON) { - tverts->reserve_more(6); // top-left vertex triangle between previous line and this one { // use the normal going to the left calculated for the previous line @@ -126,8 +132,6 @@ _3DScene::_extrusionentity_to_verts_do(const Lines &lines, const std::vectorreserve_more(4); - // normal pointing downwards qverts->push_norm(0,0,-1); qverts->push_vert(a.x, a.y, bottom_z); @@ -144,8 +148,6 @@ _3DScene::_extrusionentity_to_verts_do(const Lines &lines, const std::vectorpush_norm(xy_left_normal); qverts->push_vert(a2.x, a2.y, middle_z); } else if (i == lines.size()-1) { - qverts->reserve_more(4); - // normal pointing downwards qverts->push_norm(0,0,-1); qverts->push_vert(b.x, b.y, bottom_z); @@ -164,8 +166,6 @@ _3DScene::_extrusionentity_to_verts_do(const Lines &lines, const std::vectorreserve_more(16); - // bottom-right face { // normal going downwards @@ -228,7 +228,7 @@ _3DScene::_extrusionentity_to_verts_do(const Lines &lines, const std::vectorreserve_more(3 * mesh.facets_count()); + this->reserve_more(3 * 3 * mesh.facets_count()); for (int i = 0; i < mesh.stl.stats.number_of_facets; ++i) { stl_facet &facet = mesh.stl.facet_start[i]; diff --git a/xs/src/libslic3r/MultiPoint.cpp b/xs/src/libslic3r/MultiPoint.cpp index 61c84a802..614306e42 100644 --- a/xs/src/libslic3r/MultiPoint.cpp +++ b/xs/src/libslic3r/MultiPoint.cpp @@ -89,6 +89,17 @@ MultiPoint::bounding_box() const return BoundingBox(this->points); } +void +MultiPoint::remove_duplicate_points() +{ + for (size_t i = 1; i < this->points.size(); ++i) { + if (this->points.at(i).coincides_with(this->points.at(i-1))) { + this->points.erase(this->points.begin() + i); + --i; + } + } +} + Points MultiPoint::_douglas_peucker(const Points &points, const double tolerance) { diff --git a/xs/src/libslic3r/MultiPoint.hpp b/xs/src/libslic3r/MultiPoint.hpp index e87c5166e..12c500836 100644 --- a/xs/src/libslic3r/MultiPoint.hpp +++ b/xs/src/libslic3r/MultiPoint.hpp @@ -32,6 +32,7 @@ class MultiPoint int find_point(const Point &point) const; bool has_boundary_point(const Point &point) const; BoundingBox bounding_box() const; + void remove_duplicate_points(); static Points _douglas_peucker(const Points &points, const double tolerance); diff --git a/xs/xsp/ExtrusionLoop.xsp b/xs/xsp/ExtrusionLoop.xsp index a0f8de27c..0da0fe0d4 100644 --- a/xs/xsp/ExtrusionLoop.xsp +++ b/xs/xsp/ExtrusionLoop.xsp @@ -15,8 +15,7 @@ bool make_counter_clockwise(); Clone first_point(); Clone last_point(); - Clone polygon() - %code{% RETVAL = Polygon(*THIS); %}; + Clone polygon(); void append(ExtrusionPath* path) %code{% THIS->paths.push_back(*path); %}; double length(); diff --git a/xs/xsp/Polyline.xsp b/xs/xsp/Polyline.xsp index 3300f12c3..98cd44e94 100644 --- a/xs/xsp/Polyline.xsp +++ b/xs/xsp/Polyline.xsp @@ -37,6 +37,7 @@ %code{% THIS->split_at(*point, p1, p2); %}; bool is_straight(); Clone bounding_box(); + void remove_duplicate_points(); std::string wkt(); %{