From 86fbb9a095e30ce0f6fc998cf1b812e716ac7871 Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 23 Jan 2019 10:08:42 +0100 Subject: [PATCH 01/25] gyroid & 3Dhoneycomb: now 'connected lines' follow the perimeters --- src/libslic3r/Fill/Fill3DHoneycomb.cpp | 59 +++-- src/libslic3r/Fill/FillBase.cpp | 287 +++++++++++++++++++++++++ src/libslic3r/Fill/FillBase.hpp | 2 + src/libslic3r/Fill/FillGyroid.cpp | 99 +++++---- src/libslic3r/Point.hpp | 7 + 5 files changed, 377 insertions(+), 77 deletions(-) diff --git a/src/libslic3r/Fill/Fill3DHoneycomb.cpp b/src/libslic3r/Fill/Fill3DHoneycomb.cpp index 6a37e4369f..7da18d9e31 100644 --- a/src/libslic3r/Fill/Fill3DHoneycomb.cpp +++ b/src/libslic3r/Fill/Fill3DHoneycomb.cpp @@ -161,43 +161,38 @@ void Fill3DHoneycomb::_fill_surface_single( for (Polylines::iterator it = polylines.begin(); it != polylines.end(); ++ it) it->translate(bb.min(0), bb.min(1)); - // clip pattern to boundaries - polylines = intersection_pl(polylines, (Polygons)expolygon); - - // connect lines - if (! params.dont_connect && ! polylines.empty()) { // prevent calling leftmost_point() on empty collections - ExPolygon expolygon_off; - { - ExPolygons expolygons_off = offset_ex(expolygon, SCALED_EPSILON); - if (! expolygons_off.empty()) { - // When expanding a polygon, the number of islands could only shrink. Therefore the offset_ex shall generate exactly one expanded island for one input island. - assert(expolygons_off.size() == 1); - std::swap(expolygon_off, expolygons_off.front()); + // clip pattern to boundaries, keeping the polyline order & ordering the fragment to be able to join them easily + Polylines polylines_chained; + for (size_t idx_polyline = 0; idx_polyline < polylines.size(); ++idx_polyline) { + Polyline &poly_to_cut = polylines[idx_polyline]; + Polylines polylines_to_sort = intersection_pl(Polylines() = { poly_to_cut }, (Polygons)expolygon); + for (Polyline &polyline : polylines_to_sort) { + //TODO: replace by closest_index_point() + if (poly_to_cut.points.front().distance_to_square(polyline.points.front()) > poly_to_cut.points.front().distance_to_square(polyline.points.back())) { + polyline.reverse(); } } - Polylines chained = PolylineCollection::chained_path_from( - std::move(polylines), - PolylineCollection::leftmost_point(polylines), false); // reverse allowed - bool first = true; - for (Polylines::iterator it_polyline = chained.begin(); it_polyline != chained.end(); ++ it_polyline) { - if (! first) { - // Try to connect the lines. - Points &pts_end = polylines_out.back().points; - const Point &first_point = it_polyline->points.front(); - const Point &last_point = pts_end.back(); - // TODO: we should also check that both points are on a fill_boundary to avoid - // connecting paths on the boundaries of internal regions - if ((last_point - first_point).cast().norm() <= 1.5 * distance && - expolygon_off.contains(Line(last_point, first_point))) { - // Append the polyline. - pts_end.insert(pts_end.end(), it_polyline->points.begin(), it_polyline->points.end()); - continue; + if (polylines_to_sort.size() > 1) { + Point nearest = poly_to_cut.points.front(); + //Bubble sort + for (size_t idx_sort = polylines_to_sort.size() - 1; idx_sort > 0; idx_sort--) { + for (size_t idx_bubble = 0; idx_bubble < idx_sort; idx_bubble++) { + if (polylines_to_sort[idx_bubble + 1].points.front().distance_to_square(nearest) < polylines_to_sort[idx_bubble].points.front().distance_to_square(nearest)) { + iter_swap(polylines_to_sort.begin() + idx_bubble, polylines_to_sort.begin() + idx_bubble + 1); + } } } - // The lines cannot be connected. - polylines_out.emplace_back(std::move(*it_polyline)); - first = false; } + polylines_chained.insert(polylines_chained.end(), polylines_to_sort.begin(), polylines_to_sort.end()); + } + // connect lines if needed + if (!polylines_chained.empty()) { + if (params.dont_connect) { + polylines_out.insert(polylines_out.end(), polylines_chained.begin(), polylines_chained.end()); + } else { + this->connect_infill(polylines_chained, expolygon, polylines_out); + } + } } diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 7a99e84f71..df32ff1790 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -130,4 +130,291 @@ std::pair Fill::_infill_direction(const Surface *surface) const return std::pair(out_angle, out_shift); } + + + +/// cut poly between poly.point[idx_1] & poly.point[idx_1+1] +/// add p1+-width to one part and p2+-width to the other one. +/// add the "new" polyline to polylines (to part cut from poly) +/// p1 & p2 have to be between poly.point[idx_1] & poly.point[idx_1+1] +/// if idx_1 is ==0 or == size-1, then we don't need to create a new polyline. +void cut_polyline(Polyline &poly, Polylines &polylines, size_t idx_1, Point p1, Point p2) { + //reorder points + if (p1.distance_to_square(poly.points[idx_1]) > p2.distance_to_square(poly.points[idx_1])) { + Point temp = p2; + p2 = p1; + p1 = temp; + } + if (idx_1 == 0) { + poly.points.insert(poly.points.begin(), p2); + } else if (idx_1 == poly.points.size() - 1) { + poly.points.push_back(p1); + } else { + // create new polyline + Polyline new_poly; + //put points in new_poly + new_poly.points.push_back(p2); + new_poly.points.insert(new_poly.points.end(), poly.points.begin() + idx_1 + 1, poly.points.end()); + //erase&put points in poly + poly.points.erase(poly.points.begin() + idx_1 + 1, poly.points.end()); + poly.points.push_back(p1); + polylines.emplace_back(new_poly); + } +} + +/// the poly is like a polygon but with first_point != last_point (already removed) +void cut_polygon(Polyline &poly, size_t idx_1, Point p1, Point p2) { + //reorder points + if (p1.distance_to_square(poly.points[idx_1]) > p2.distance_to_square(poly.points[idx_1])) { + Point temp = p2; + p2 = p1; + p1 = temp; + } + //check if we need to rotate before cutting + if (idx_1 != poly.size() - 1) { + //put points in new_poly + poly.points.insert(poly.points.end(), poly.points.begin(), poly.points.begin() + idx_1 + 1); + poly.points.erase(poly.points.begin(), poly.points.begin() + idx_1 + 1); + } + //put points in poly + poly.points.push_back(p1); + poly.points.insert(poly.points.begin(), p2); +} + +/// check if the polyline from pts_to_check may be at 'width' distance of a point in polylines_blocker +/// it use equally_spaced_points with width/2 precision, so don't worry with pts_to_check number of points. +/// it use the given polylines_blocker points, be sure to put enough of them to be reliable. +/// complexity : N(pts_to_check.equally_spaced_points(width / 2)) x N(polylines_blocker.points) +bool collision(const Points &pts_to_check, const Polylines &polylines_blocker, const coordf_t width) { + //check if it's not too close to a polyline + coordf_t min_dist = width * width * 0.9 - SCALED_EPSILON; + Polyline better_polylines(pts_to_check); + Points better_pts = better_polylines.equally_spaced_points(width / 2); + for (const Point &p : better_pts) { + for (const Polyline &poly2 : polylines_blocker) { + for (const Point &p2 : poly2.points) { + if (p.distance_to_square(p2) < min_dist) { + return true; + } + } + } + } + return false; +} + +/// Try to find a path inside polylines that allow to go from p1 to p2. +/// width if the width of the extrusion +/// polylines_blockers are the array of polylines to check if the path isn't blocked by something. +/// complexity: N(polylines.points) + a collision check after that if we finded a path: N(2(p2-p1)/width) x N(polylines_blocker.points) +Points getFrontier(Polylines &polylines, const Point& p1, const Point& p2, const coord_t width, const Polylines &polylines_blockers) { + for (size_t idx_poly = 0; idx_poly < polylines.size(); ++idx_poly) { + Polyline &poly = polylines[idx_poly]; + if (poly.size() <= 1) continue; + + //loop? + if (poly.first_point() == poly.last_point()) { + //polygon : try to find a line for p1 & p2. + size_t idx_11, idx_12, idx_21, idx_22; + idx_11 = poly.closest_point_index(p1); + idx_12 = idx_11; + if (Line(poly.points[idx_11], poly.points[(idx_11 + 1) % (poly.points.size() - 1)]).distance_to(p1) < SCALED_EPSILON) { + idx_12 = (idx_11 + 1) % (poly.points.size() - 1); + } else if (Line(poly.points[(idx_11 > 0) ? (idx_11 - 1) : (poly.points.size() - 2)], poly.points[idx_11]).distance_to(p1) < SCALED_EPSILON) { + idx_11 = (idx_11 > 0) ? (idx_11 - 1) : (poly.points.size() - 2); + } else { + continue; + } + idx_21 = poly.closest_point_index(p2); + idx_22 = idx_21; + if (Line(poly.points[idx_21], poly.points[(idx_21 + 1) % (poly.points.size() - 1)]).distance_to(p2) < SCALED_EPSILON) { + idx_22 = (idx_21 + 1) % (poly.points.size() - 1); + } else if (Line(poly.points[(idx_21 > 0) ? (idx_21 - 1) : (poly.points.size() - 2)], poly.points[idx_21]).distance_to(p2) < SCALED_EPSILON) { + idx_21 = (idx_21 > 0) ? (idx_21 - 1) : (poly.points.size() - 2); + } else { + continue; + } + + + //edge case: on the same line + if (idx_11 == idx_21 && idx_12 == idx_22) { + if (collision(Points() = { p1, p2 }, polylines_blockers, width)) return Points(); + //break loop + poly.points.erase(poly.points.end() - 1); + cut_polygon(poly, idx_11, p1, p2); + return Points() = { Line(p1, p2).midpoint() }; + } + + //compute distance & array for the ++ path + Points ret_1_to_2; + double dist_1_to_2 = p1.distance_to(poly.points[idx_12]); + ret_1_to_2.push_back(poly.points[idx_12]); + size_t max = idx_12 <= idx_21 ? idx_21 : poly.points.size() - 2; + for (size_t i = idx_12 + 1; i < max; i++) { + dist_1_to_2 += poly.points[i - 1].distance_to(poly.points[i]); + ret_1_to_2.push_back(poly.points[i]); + } + if (idx_12 > idx_21) { + dist_1_to_2 += poly.points.back().distance_to(poly.points.front()); + ret_1_to_2.push_back(poly.points[0]); + for (size_t i = 1; i <= idx_21; i++) { + dist_1_to_2 += poly.points[i - 1].distance_to(poly.points[i]); + ret_1_to_2.push_back(poly.points[i]); + } + } + dist_1_to_2 += p2.distance_to(poly.points[idx_21]); + + //compute distance & array for the -- path + Points ret_2_to_1; + double dist_2_to_1 = p1.distance_to(poly.points[idx_11]); + ret_2_to_1.push_back(poly.points[idx_11]); + size_t min = idx_22 <= idx_11 ? idx_22 : 0; + for (size_t i = idx_11; i > min; i--) { + dist_2_to_1 += poly.points[i - 1].distance_to(poly.points[i]); + ret_2_to_1.push_back(poly.points[i - 1]); + } + if (idx_22 > idx_11) { + dist_2_to_1 += poly.points.back().distance_to(poly.points.front()); + ret_2_to_1.push_back(poly.points[poly.points.size() - 1]); + for (size_t i = poly.points.size() - 2; i > idx_22; i--) { + dist_2_to_1 += poly.points[i - 1].distance_to(poly.points[i]); + ret_2_to_1.push_back(poly.points[i - 1]); + } + } + dist_2_to_1 += p2.distance_to(poly.points[idx_22]); + + //choose between the two direction (keep the short one) + if (dist_1_to_2 < dist_2_to_1) { + if (collision(ret_1_to_2, polylines_blockers, width)) return Points(); + //break loop + poly.points.erase(poly.points.end() - 1); + //remove points + if (idx_12 <= idx_21) { + poly.points.erase(poly.points.begin() + idx_12, poly.points.begin() + idx_21 + 1); + cut_polygon(poly, idx_11, p1, p2); + } else { + poly.points.erase(poly.points.begin() + idx_12, poly.points.end()); + poly.points.erase(poly.points.begin(), poly.points.begin() + idx_21); + cut_polygon(poly, poly.points.size() - 1, p1, p2); + } + return ret_1_to_2; + } else { + if (collision(ret_2_to_1, polylines_blockers, width)) return Points(); + //break loop + poly.points.erase(poly.points.end() - 1); + //remove points + if (idx_22 <= idx_11) { + poly.points.erase(poly.points.begin() + idx_22, poly.points.begin() + idx_11 + 1); + cut_polygon(poly, idx_21, p1, p2); + } else { + poly.points.erase(poly.points.begin() + idx_22, poly.points.end()); + poly.points.erase(poly.points.begin(), poly.points.begin() + idx_11); + cut_polygon(poly, poly.points.size() - 1, p1, p2); + } + return ret_2_to_1; + } + } else { + //polyline : try to find a line for p1 & p2. + size_t idx_1, idx_2; + idx_1 = poly.closest_point_index(p1); + if (idx_1 < poly.points.size() - 1 && Line(poly.points[idx_1], poly.points[idx_1 + 1]).distance_to(p1) < SCALED_EPSILON) { + } else if (idx_1 > 0 && Line(poly.points[idx_1 - 1], poly.points[idx_1]).distance_to(p1) < SCALED_EPSILON) { + idx_1 = idx_1 - 1; + } else { + continue; + } + idx_2 = poly.closest_point_index(p2); + if (idx_2 < poly.points.size() - 1 && Line(poly.points[idx_2], poly.points[idx_2 + 1]).distance_to(p2) < SCALED_EPSILON) { + } else if (idx_2 > 0 && Line(poly.points[idx_2 - 1], poly.points[idx_2]).distance_to(p2) < SCALED_EPSILON) { + idx_2 = idx_2 - 1; + } else { + continue; + } + + //edge case: on the same line + if (idx_1 == idx_2) { + if (collision(Points() = { p1, p2 }, polylines_blockers, width)) return Points(); + cut_polyline(poly, polylines, idx_1, p1, p2); + return Points() = { Line(p1, p2).midpoint() }; + } + + //create ret array + size_t first_idx = idx_1; + size_t last_idx = idx_2 + 1; + if (idx_1 > idx_2) { + first_idx = idx_2; + last_idx = idx_1 + 1; + } + Points p_ret; + p_ret.insert(p_ret.end(), poly.points.begin() + first_idx + 1, poly.points.begin() + last_idx); + if (collision(p_ret, polylines_blockers, width)) return Points(); + //cut polyline + poly.points.erase(poly.points.begin() + first_idx + 1, poly.points.begin() + last_idx); + cut_polyline(poly, polylines, first_idx, p1, p2); + //order the returned array to be p1->p2 + if (idx_1 > idx_2) { + std::reverse(p_ret.begin(), p_ret.end()); + } + return p_ret; + } + + } + + return Points(); +} + +/// Connect the infill_ordered polylines, in this order, from the back point to the next front point. +/// It uses only the boundary polygons to do so, and can't pass two times at the same place. +/// It avoid passing over the infill_ordered's polylines (preventing local over-extrusion). +/// return the connected polylines in polylines_out. Can output polygons (stored as polylines with first_point = last_point). +/// complexity: worst: N(infill_ordered.points) x N(boundary.points) +/// typical: N(infill_ordered) x ( N(boundary.points) + N(infill_ordered.points) ) +void Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out) { + + //TODO: fallback to the quick & dirty old algorithm when n(points) is too high. + Polylines polylines_frontier = to_polylines(((Polygons)boundary)); + + Polylines polylines_blocker; + coord_t clip_size = scale_(this->spacing) * 2; + for (const Polyline &polyline : infill_ordered) { + if (polyline.length() > 1.8 * clip_size) { + polylines_blocker.push_back(polyline); + polylines_blocker.back().clip_end(clip_size); + polylines_blocker.back().clip_start(clip_size); + } + } + + + Polylines polylines_connected; + bool first = true; + for (const Polyline &polyline : infill_ordered) { + if (!first) { + // Try to connect the lines. + Points &pts_end = polylines_connected.back().points; + const Point &first_point = polyline.points.front(); + const Point &last_point = pts_end.back(); + + Points pts = getFrontier(polylines_frontier, last_point, first_point, scale_(this->spacing), polylines_blocker); + if (!pts.empty()) { + pts_end.insert(pts_end.end(), pts.begin(), pts.end()); + pts_end.insert(pts_end.end(), polyline.points.begin(), polyline.points.end()); + continue; + } + } + // The lines cannot be connected. + polylines_connected.emplace_back(std::move(polyline)); + + first = false; + } + + //try to create some loops if possible + for (Polyline &polyline : polylines_connected) { + Points pts = getFrontier(polylines_frontier, polyline.last_point(), polyline.first_point(), scale_(this->spacing), polylines_blocker); + if (!pts.empty()) { + polyline.points.insert(polyline.points.end(), pts.begin(), pts.end()); + polyline.points.insert(polyline.points.begin(), polyline.points.back()); + } + polylines_out.emplace_back(polyline); + } +} + } // namespace Slic3r diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index 8bf6c36898..b7f6b5b10b 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -109,6 +109,8 @@ protected: virtual std::pair _infill_direction(const Surface *surface) const; + void connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out); + public: static coord_t _adjust_solid_spacing(const coord_t width, const coord_t distance); diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index 04319bb268..9972e210c8 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -109,16 +109,20 @@ static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double std::swap(width,height); } - std::vector one_period = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); // creates one period of the waves, so it doesn't have to be recalculated all the time + std::vector one_period_odd = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); // creates one period of the waves, so it doesn't have to be recalculated all the time + flip = !flip; // even polylines are a bit shifted + std::vector one_period_even = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); Polylines result; - for (double y0 = lower_bound; y0 < upper_bound+EPSILON; y0 += 2*M_PI) // creates odd polylines - result.emplace_back(make_wave(one_period, width, height, y0, scaleFactor, z_cos, z_sin, vertical)); - - flip = !flip; // even polylines are a bit shifted - one_period = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); // updates the one period sample - for (double y0 = lower_bound + M_PI; y0 < upper_bound+EPSILON; y0 += 2*M_PI) // creates even polylines - result.emplace_back(make_wave(one_period, width, height, y0, scaleFactor, z_cos, z_sin, vertical)); + for (double y0 = lower_bound; y0 < upper_bound + EPSILON; y0 += M_PI) { + // creates odd polylines + result.emplace_back(make_wave(one_period_odd, width, height, y0, scaleFactor, z_cos, z_sin, vertical)); + // creates even polylines + y0 += M_PI; + if (y0 < upper_bound + EPSILON) { + result.emplace_back(make_wave(one_period_even, width, height, y0, scaleFactor, z_cos, z_sin, vertical)); + } + } return result; } @@ -141,7 +145,7 @@ void FillGyroid::_fill_surface_single( bb.merge(_align_to_grid(bb.min, Point(2.*M_PI*distance, 2.*M_PI*distance))); // generate pattern - Polylines polylines = make_gyroid_waves( + Polylines polylines_square = make_gyroid_waves( scale_(this->z), density_adjusted, this->spacing, @@ -149,46 +153,51 @@ void FillGyroid::_fill_surface_single( ceil(bb.size()(1) / distance) + 1.); // move pattern in place - for (Polyline &polyline : polylines) + for (Polyline &polyline : polylines_square) polyline.translate(bb.min(0), bb.min(1)); - // clip pattern to boundaries - polylines = intersection_pl(polylines, (Polygons)expolygon); - - // connect lines - if (! params.dont_connect && ! polylines.empty()) { // prevent calling leftmost_point() on empty collections - ExPolygon expolygon_off; - { - ExPolygons expolygons_off = offset_ex(expolygon, (float)SCALED_EPSILON); - if (! expolygons_off.empty()) { - // When expanding a polygon, the number of islands could only shrink. Therefore the offset_ex shall generate exactly one expanded island for one input island. - assert(expolygons_off.size() == 1); - std::swap(expolygon_off, expolygons_off.front()); - } - } - Polylines chained = PolylineCollection::chained_path_from( - std::move(polylines), - PolylineCollection::leftmost_point(polylines), false); // reverse allowed - bool first = true; - for (Polyline &polyline : chained) { - if (! first) { - // Try to connect the lines. - Points &pts_end = polylines_out.back().points; - const Point &first_point = polyline.points.front(); - const Point &last_point = pts_end.back(); - // TODO: we should also check that both points are on a fill_boundary to avoid - // connecting paths on the boundaries of internal regions - // TODO: avoid crossing current infill path - if ((last_point - first_point).cast().norm() <= 5 * distance && - expolygon_off.contains(Line(last_point, first_point))) { - // Append the polyline. - pts_end.insert(pts_end.end(), polyline.points.begin(), polyline.points.end()); - continue; + // clip pattern to boundaries, keeping the polyline order & ordering the fragment to be able to join them easily + //Polylines polylines = intersection_pl(polylines_square, (Polygons)expolygon); + Polylines polylines_chained; + for (size_t idx_polyline = 0; idx_polyline < polylines_square.size(); ++idx_polyline) { + Polyline &poly_to_cut = polylines_square[idx_polyline]; + Polylines polylines_to_sort = intersection_pl(Polylines() = { poly_to_cut }, (Polygons)expolygon); + for (Polyline &polyline : polylines_to_sort) { + //TODO: replace by closest_index_point() + if (idx_polyline % 2 == 0) { + if (poly_to_cut.points.front().distance_to_square(polyline.points.front()) > poly_to_cut.points.front().distance_to_square(polyline.points.back())) { + polyline.reverse(); + } + } else { + if (poly_to_cut.points.back().distance_to_square(polyline.points.front()) > poly_to_cut.points.back().distance_to_square(polyline.points.back())) { + polyline.reverse(); } } - // The lines cannot be connected. - polylines_out.emplace_back(std::move(polyline)); - first = false; + } + if (polylines_to_sort.size() > 1) { + Point nearest = poly_to_cut.points.front(); + if (idx_polyline % 2 != 0) { + nearest = poly_to_cut.points.back(); + } + //Bubble sort + for (size_t idx_sort = polylines_to_sort.size() - 1; idx_sort > 0; idx_sort--) { + for (size_t idx_bubble = 0; idx_bubble < idx_sort; idx_bubble++) { + if (polylines_to_sort[idx_bubble + 1].points.front().distance_to_square(nearest) < polylines_to_sort[idx_bubble].points.front().distance_to_square(nearest)) { + iter_swap(polylines_to_sort.begin() + idx_bubble, polylines_to_sort.begin() + idx_bubble + 1); + } + } + } + } + polylines_chained.insert(polylines_chained.end(), polylines_to_sort.begin(), polylines_to_sort.end()); + } + + if (!polylines_chained.empty()) { + + // connect lines + if (params.dont_connect) { + polylines_out.insert(polylines_out.end(), polylines_chained.begin(), polylines_chained.end()); + } else { + this->connect_infill(polylines_chained, expolygon, polylines_out); } } } diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 994f45e59d..2909147711 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -124,6 +124,13 @@ public: double ccw_angle(const Point &p1, const Point &p2) const; Point projection_onto(const MultiPoint &poly) const; Point projection_onto(const Line &line) const; + + double distance_to(const Point &point) const { return (point - *this).cast().norm(); } + double distance_to_square(const Point &point) const { + double dx = (point.x() - this->x()); + double dy = (point.y() - this->y()); + return dx*dx + dy*dy; + } }; namespace int128 { From 19df45c39deebbb9a9a1c4ebaad7b9c0fcb2b231 Mon Sep 17 00:00:00 2001 From: supermerill Date: Tue, 12 Feb 2019 00:13:44 +0100 Subject: [PATCH 02/25] bugfix gyroid & 3Dhoneycomb "connected lines" --- src/libslic3r/Fill/FillBase.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index df32ff1790..d7e17698e4 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -290,7 +290,9 @@ Points getFrontier(Polylines &polylines, const Point& p1, const Point& p2, const //remove points if (idx_12 <= idx_21) { poly.points.erase(poly.points.begin() + idx_12, poly.points.begin() + idx_21 + 1); - cut_polygon(poly, idx_11, p1, p2); + if (idx_12 != 0) { + cut_polygon(poly, idx_11, p1, p2); + } //else : already cut at the good place } else { poly.points.erase(poly.points.begin() + idx_12, poly.points.end()); poly.points.erase(poly.points.begin(), poly.points.begin() + idx_21); @@ -304,7 +306,9 @@ Points getFrontier(Polylines &polylines, const Point& p1, const Point& p2, const //remove points if (idx_22 <= idx_11) { poly.points.erase(poly.points.begin() + idx_22, poly.points.begin() + idx_11 + 1); - cut_polygon(poly, idx_21, p1, p2); + if (idx_22 != 0) { + cut_polygon(poly, idx_21, p1, p2); + } //else : already cut at the good place } else { poly.points.erase(poly.points.begin() + idx_22, poly.points.end()); poly.points.erase(poly.points.begin(), poly.points.begin() + idx_11); From b6936a46e3062c16d5aba0c3be526afb48ff7140 Mon Sep 17 00:00:00 2001 From: supermerill Date: Fri, 8 Mar 2019 18:29:51 +0100 Subject: [PATCH 03/25] bugfix "connected lines" for gyroid & 3Dhoney --- src/libslic3r/Fill/Fill3DHoneycomb.cpp | 2 +- src/libslic3r/Fill/FillBase.cpp | 120 ++++++++++++++++++++----- src/libslic3r/Fill/FillBase.hpp | 2 +- src/libslic3r/Fill/FillGyroid.cpp | 12 ++- 4 files changed, 111 insertions(+), 25 deletions(-) diff --git a/src/libslic3r/Fill/Fill3DHoneycomb.cpp b/src/libslic3r/Fill/Fill3DHoneycomb.cpp index 7da18d9e31..bb49583204 100644 --- a/src/libslic3r/Fill/Fill3DHoneycomb.cpp +++ b/src/libslic3r/Fill/Fill3DHoneycomb.cpp @@ -190,7 +190,7 @@ void Fill3DHoneycomb::_fill_surface_single( if (params.dont_connect) { polylines_out.insert(polylines_out.end(), polylines_chained.begin(), polylines_chained.end()); } else { - this->connect_infill(polylines_chained, expolygon, polylines_out); + this->connect_infill(polylines_chained, expolygon, polylines_out, params); } } diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index d7e17698e4..f9259eed93 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -145,10 +145,9 @@ void cut_polyline(Polyline &poly, Polylines &polylines, size_t idx_1, Point p1, p2 = p1; p1 = temp; } - if (idx_1 == 0) { - poly.points.insert(poly.points.begin(), p2); - } else if (idx_1 == poly.points.size() - 1) { - poly.points.push_back(p1); + if (idx_1 == poly.points.size() - 1) { + //shouldn't be possible. + poly.points.erase(poly.points.end() - 1); } else { // create new polyline Polyline new_poly; @@ -158,7 +157,11 @@ void cut_polyline(Polyline &poly, Polylines &polylines, size_t idx_1, Point p1, //erase&put points in poly poly.points.erase(poly.points.begin() + idx_1 + 1, poly.points.end()); poly.points.push_back(p1); - polylines.emplace_back(new_poly); + //safe test + if (poly.length() == 0) + poly.points = new_poly.points; + else + polylines.emplace_back(new_poly); } } @@ -187,13 +190,13 @@ void cut_polygon(Polyline &poly, size_t idx_1, Point p1, Point p2) { /// complexity : N(pts_to_check.equally_spaced_points(width / 2)) x N(polylines_blocker.points) bool collision(const Points &pts_to_check, const Polylines &polylines_blocker, const coordf_t width) { //check if it's not too close to a polyline - coordf_t min_dist = width * width * 0.9 - SCALED_EPSILON; + coordf_t min_dist_square = width * width * 0.9 - SCALED_EPSILON; Polyline better_polylines(pts_to_check); Points better_pts = better_polylines.equally_spaced_points(width / 2); for (const Point &p : better_pts) { for (const Polyline &poly2 : polylines_blocker) { for (const Point &p2 : poly2.points) { - if (p.distance_to_square(p2) < min_dist) { + if (p.distance_to_square(p2) < min_dist_square) { return true; } } @@ -206,7 +209,7 @@ bool collision(const Points &pts_to_check, const Polylines &polylines_blocker, c /// width if the width of the extrusion /// polylines_blockers are the array of polylines to check if the path isn't blocked by something. /// complexity: N(polylines.points) + a collision check after that if we finded a path: N(2(p2-p1)/width) x N(polylines_blocker.points) -Points getFrontier(Polylines &polylines, const Point& p1, const Point& p2, const coord_t width, const Polylines &polylines_blockers) { +Points getFrontier(Polylines &polylines, const Point& p1, const Point& p2, const coord_t width, const Polylines &polylines_blockers, coord_t max_size = -1) { for (size_t idx_poly = 0; idx_poly < polylines.size(); ++idx_poly) { Polyline &poly = polylines[idx_poly]; if (poly.size() <= 1) continue; @@ -248,7 +251,7 @@ Points getFrontier(Polylines &polylines, const Point& p1, const Point& p2, const Points ret_1_to_2; double dist_1_to_2 = p1.distance_to(poly.points[idx_12]); ret_1_to_2.push_back(poly.points[idx_12]); - size_t max = idx_12 <= idx_21 ? idx_21 : poly.points.size() - 2; + size_t max = idx_12 <= idx_21 ? idx_21+1 : poly.points.size(); for (size_t i = idx_12 + 1; i < max; i++) { dist_1_to_2 += poly.points[i - 1].distance_to(poly.points[i]); ret_1_to_2.push_back(poly.points[i]); @@ -275,13 +278,17 @@ Points getFrontier(Polylines &polylines, const Point& p1, const Point& p2, const if (idx_22 > idx_11) { dist_2_to_1 += poly.points.back().distance_to(poly.points.front()); ret_2_to_1.push_back(poly.points[poly.points.size() - 1]); - for (size_t i = poly.points.size() - 2; i > idx_22; i--) { + for (size_t i = poly.points.size() - 1; i > idx_22; i--) { dist_2_to_1 += poly.points[i - 1].distance_to(poly.points[i]); ret_2_to_1.push_back(poly.points[i - 1]); } } dist_2_to_1 += p2.distance_to(poly.points[idx_22]); + if (max_size < dist_2_to_1 && max_size < dist_1_to_2) { + return Points(); + } + //choose between the two direction (keep the short one) if (dist_1_to_2 < dist_2_to_1) { if (collision(ret_1_to_2, polylines_blockers, width)) return Points(); @@ -350,6 +357,14 @@ Points getFrontier(Polylines &polylines, const Point& p1, const Point& p2, const } Points p_ret; p_ret.insert(p_ret.end(), poly.points.begin() + first_idx + 1, poly.points.begin() + last_idx); + + coordf_t length = 0; + for (size_t i = 1; i < p_ret.size(); i++) length += p_ret[i - 1].distance_to(p_ret[i]); + + if (max_size < length) { + return Points(); + } + if (collision(p_ret, polylines_blockers, width)) return Points(); //cut polyline poly.points.erase(poly.points.begin() + first_idx + 1, poly.points.begin() + last_idx); @@ -372,7 +387,7 @@ Points getFrontier(Polylines &polylines, const Point& p1, const Point& p2, const /// return the connected polylines in polylines_out. Can output polygons (stored as polylines with first_point = last_point). /// complexity: worst: N(infill_ordered.points) x N(boundary.points) /// typical: N(infill_ordered) x ( N(boundary.points) + N(infill_ordered.points) ) -void Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out) { +void Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const FillParams ¶ms) { //TODO: fallback to the quick & dirty old algorithm when n(points) is too high. Polylines polylines_frontier = to_polylines(((Polygons)boundary)); @@ -380,26 +395,54 @@ void Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boun Polylines polylines_blocker; coord_t clip_size = scale_(this->spacing) * 2; for (const Polyline &polyline : infill_ordered) { - if (polyline.length() > 1.8 * clip_size) { + if (polyline.length() > 2.01 * clip_size) { polylines_blocker.push_back(polyline); polylines_blocker.back().clip_end(clip_size); polylines_blocker.back().clip_start(clip_size); } } + //length between two lines + coordf_t ideal_length = (1 / params.density) * this->spacing; - Polylines polylines_connected; + Polylines polylines_connected_first; bool first = true; for (const Polyline &polyline : infill_ordered) { if (!first) { // Try to connect the lines. - Points &pts_end = polylines_connected.back().points; - const Point &first_point = polyline.points.front(); + Points &pts_end = polylines_connected_first.back().points; const Point &last_point = pts_end.back(); + const Point &first_point = polyline.points.front(); + if (last_point.distance_to(first_point) < scale_(this->spacing) * 10) { + Points pts_frontier = getFrontier(polylines_frontier, last_point, first_point, scale_(this->spacing), polylines_blocker, (coord_t)scale_(ideal_length) * 2); + if (!pts_frontier.empty()) { + // The lines can be connected. + pts_end.insert(pts_end.end(), pts_frontier.begin(), pts_frontier.end()); + pts_end.insert(pts_end.end(), polyline.points.begin(), polyline.points.end()); + continue; + } + } + } + // The lines cannot be connected. + polylines_connected_first.emplace_back(std::move(polyline)); - Points pts = getFrontier(polylines_frontier, last_point, first_point, scale_(this->spacing), polylines_blocker); - if (!pts.empty()) { - pts_end.insert(pts_end.end(), pts.begin(), pts.end()); + first = false; + } + + Polylines polylines_connected; + first = true; + for (const Polyline &polyline : polylines_connected_first) { + if (!first) { + // Try to connect the lines. + Points &pts_end = polylines_connected.back().points; + const Point &last_point = pts_end.back(); + const Point &first_point = polyline.points.front(); + + Polylines before = polylines_frontier; + Points pts_frontier = getFrontier(polylines_frontier, last_point, first_point, scale_(this->spacing), polylines_blocker); + if (!pts_frontier.empty()) { + // The lines can be connected. + pts_end.insert(pts_end.end(), pts_frontier.begin(), pts_frontier.end()); pts_end.insert(pts_end.end(), polyline.points.begin(), polyline.points.end()); continue; } @@ -410,11 +453,46 @@ void Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boun first = false; } + //try to link to nearest point if possible + for (int idx1 = 0; idx1 < polylines_connected.size(); idx1++) { + size_t min_idx = 0; + coordf_t min_length = 0; + bool switch_id1 = false; + bool switch_id2 = false; + for (int idx2 = idx1 + 1; idx2 < polylines_connected.size(); idx2++) { + double last_first = polylines_connected[idx1].last_point().distance_to_square(polylines_connected[idx2].first_point()); + double first_first = polylines_connected[idx1].first_point().distance_to_square(polylines_connected[idx2].first_point()); + double first_last = polylines_connected[idx1].first_point().distance_to_square(polylines_connected[idx2].last_point()); + double last_last = polylines_connected[idx1].last_point().distance_to_square(polylines_connected[idx2].last_point()); + double min = std::min(std::min(last_first, last_last), std::min(first_first, first_last)); + if (min < min_length || min_length == 0) { + min_idx = idx2; + switch_id1 = (std::min(last_first, last_last) > std::min(first_first, first_last)); + switch_id2 = (std::min(last_first, first_first) > std::min(last_last, first_last)); + min_length = min; + } + } + if (min_idx > idx1 && min_idx < polylines_connected.size()){ + Points pts_frontier = getFrontier(polylines_frontier, + switch_id1 ? polylines_connected[idx1].first_point() : polylines_connected[idx1].last_point(), + switch_id2 ? polylines_connected[min_idx].last_point() : polylines_connected[min_idx].first_point(), + scale_(this->spacing), polylines_blocker); + if (!pts_frontier.empty()) { + if (switch_id1) polylines_connected[idx1].reverse(); + if (switch_id2) polylines_connected[min_idx].reverse(); + Points &pts_end = polylines_connected[idx1].points; + pts_end.insert(pts_end.end(), pts_frontier.begin(), pts_frontier.end()); + pts_end.insert(pts_end.end(), polylines_connected[min_idx].points.begin(), polylines_connected[min_idx].points.end()); + polylines_connected.erase(polylines_connected.begin() + min_idx); + } + } + } + //try to create some loops if possible for (Polyline &polyline : polylines_connected) { - Points pts = getFrontier(polylines_frontier, polyline.last_point(), polyline.first_point(), scale_(this->spacing), polylines_blocker); - if (!pts.empty()) { - polyline.points.insert(polyline.points.end(), pts.begin(), pts.end()); + Points pts_frontier = getFrontier(polylines_frontier, polyline.last_point(), polyline.first_point(), scale_(this->spacing), polylines_blocker); + if (!pts_frontier.empty()) { + polyline.points.insert(polyline.points.end(), pts_frontier.begin(), pts_frontier.end()); polyline.points.insert(polyline.points.begin(), polyline.points.back()); } polylines_out.emplace_back(polyline); diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index b7f6b5b10b..98717c41fe 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -109,7 +109,7 @@ protected: virtual std::pair _infill_direction(const Surface *surface) const; - void connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out); + void connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const FillParams ¶ms); public: static coord_t _adjust_solid_spacing(const coord_t width, const coord_t distance); diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index 9972e210c8..b8fe0ed727 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -191,13 +191,21 @@ void FillGyroid::_fill_surface_single( polylines_chained.insert(polylines_chained.end(), polylines_to_sort.begin(), polylines_to_sort.end()); } + size_t polylines_out_first_idx = polylines_out.size(); if (!polylines_chained.empty()) { - // connect lines if (params.dont_connect) { polylines_out.insert(polylines_out.end(), polylines_chained.begin(), polylines_chained.end()); } else { - this->connect_infill(polylines_chained, expolygon, polylines_out); + this->connect_infill(polylines_chained, expolygon, polylines_out, params); + } + } + + //remove too small bits (larger than longer); + for (size_t idx = polylines_out_first_idx; idx < polylines_out.size(); idx++) { + if (polylines_out[idx].length() < scale_(this->spacing * 3)) { + polylines_out.erase(polylines_out.begin() + idx); + idx--; } } } From b9901f1730cca7040bc1d863afc5d0a8963d75be Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Thu, 20 Jun 2019 00:27:22 +0200 Subject: [PATCH 04/25] Parametric tolerance for Gyroid infill --- src/libslic3r/Fill/FillGyroid.cpp | 57 ++++++++++++++++++------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index b8fe0ed727..7c6674556a 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -55,43 +55,52 @@ static inline Polyline make_wave( return polyline; } -static std::vector make_one_period(double width, double scaleFactor, double z_cos, double z_sin, bool vertical, bool flip) +static std::vector make_one_period(double width, double scaleFactor, double z_cos, double z_sin, bool vertical, bool flip, double tolerance) { std::vector points; - double dx = M_PI_4; // very coarse spacing to begin with + double dx = M_PI_2; // exact coordinates on main inflexion lobes double limit = std::min(2*M_PI, width); for (double x = 0.; x < limit + EPSILON; x += dx) { // so the last point is there too x = std::min(x, limit); - points.emplace_back(Vec2d(x,f(x, z_sin,z_cos, vertical, flip))); + points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip))); } - // now we will check all internal points and in case some are too far from the line connecting its neighbours, - // we will add one more point on each side: - const double tolerance = .1; - for (unsigned int i=1;i(scaleFactor) * std::abs(cross2(rp, lp) - cross2(rp - lp, tp)) / lrv.norm(); - if (dist_mm > tolerance) { // if the difference from straight line is more than this - double x = 0.5f * (points[i-1](0) + points[i](0)); - points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip))); - x = 0.5f * (points[i+1](0) + points[i](0)); - points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip))); - // we added the points to the end, but need them all in order - std::sort(points.begin(), points.end(), [](const Vec2d &lhs, const Vec2d &rhs){ return lhs < rhs; }); - // decrement i so we also check the first newly added point - --i; + // piecewise increase in resolution up to requested tolerance + for(;;) + { + size_t size = points.size(); + for (unsigned int i = 1;i < size; ++i) { + auto& lp = points[i-1]; // left point + auto& rp = points[i]; // right point + double x = lp(0) + (rp(0) - lp(0)) / 2; + double y = f(x, z_sin, z_cos, vertical, flip); + Vec2d ip = {x, y}; + if (std::abs(cross2(Vec2d(ip - lp), Vec2d(ip - rp))) > sqr(tolerance)) { + points.emplace_back(std::move(ip)); + } + } + + if (size == points.size()) + break; + else + { + // insert new points in order + std::sort(points.begin(), points.end(), + [](const Vec2d &lhs, const Vec2d &rhs) { return lhs(0) < rhs(0); }); } } + return points; } static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double line_spacing, double width, double height) { const double scaleFactor = scale_(line_spacing) / density_adjusted; + + // tolerance (in scaled units) + // TODO: should consider layer thickness + const double tolerance = line_spacing / 2 / unscale(scaleFactor); + //scale factor for 5% : 8 712 388 // 1z = 10^-6 mm ? const double z = gridZ / scaleFactor; @@ -109,9 +118,9 @@ static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double std::swap(width,height); } - std::vector one_period_odd = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); // creates one period of the waves, so it doesn't have to be recalculated all the time + std::vector one_period_odd = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip, tolerance); // creates one period of the waves, so it doesn't have to be recalculated all the time flip = !flip; // even polylines are a bit shifted - std::vector one_period_even = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); + std::vector one_period_even = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip, tolerance); Polylines result; for (double y0 = lower_bound; y0 < upper_bound + EPSILON; y0 += M_PI) { From 5932881291be0ef99abc72677fdf2507e9fd0fce Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 22 Jun 2019 15:59:54 +0200 Subject: [PATCH 05/25] Reduce reallocations and memory usage in gyroid --- src/libslic3r/Fill/FillGyroid.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index 7c6674556a..ecc1d54a0b 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -35,6 +35,7 @@ static inline Polyline make_wave( { std::vector points = one_period; double period = points.back()(0); + points.reserve(one_period.size() * floor(width / period)); points.pop_back(); int n = points.size(); do { @@ -44,6 +45,7 @@ static inline Polyline make_wave( // and construct the final polyline to return: Polyline polyline; + polyline.points.reserve(points.size()); for (auto& point : points) { point(1) += offset; point(1) = clamp(0., height, double(point(1))); @@ -60,6 +62,7 @@ static std::vector make_one_period(double width, double scaleFactor, doub std::vector points; double dx = M_PI_2; // exact coordinates on main inflexion lobes double limit = std::min(2*M_PI, width); + points.reserve(ceil(limit / tolerance / 3)); for (double x = 0.; x < limit + EPSILON; x += dx) { // so the last point is there too x = std::min(x, limit); points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip))); From e7616efc89462a278017ef3b1f2620f999a3e4e5 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 22 Jun 2019 18:56:44 +0200 Subject: [PATCH 06/25] Handle truncated gyroid patterns correctly When generating patterns which are less than a full wave, always generate the last point correctly. When extending a full wave to a line, fixup the last point to the real gyroid position instead of shifting the point. --- src/libslic3r/Fill/FillGyroid.cpp | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index ecc1d54a0b..c0b3bd907c 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -31,17 +31,22 @@ static inline double f(double x, double z_sin, double z_cos, bool vertical, bool static inline Polyline make_wave( const std::vector& one_period, double width, double height, double offset, double scaleFactor, - double z_cos, double z_sin, bool vertical) + double z_cos, double z_sin, bool vertical, bool flip) { std::vector points = one_period; double period = points.back()(0); - points.reserve(one_period.size() * floor(width / period)); - points.pop_back(); - int n = points.size(); - do { - points.emplace_back(Vec2d(points[points.size()-n](0) + period, points[points.size()-n](1))); - } while (points.back()(0) < width); - points.back()(0) = width; + if (width != period) // do not extend if already truncated + { + points.reserve(one_period.size() * floor(width / period)); + points.pop_back(); + + int n = points.size(); + do { + points.emplace_back(Vec2d(points[points.size()-n](0) + period, points[points.size()-n](1))); + } while (points.back()(0) < width - EPSILON); + + points.emplace_back(Vec2d(width, f(width, z_sin, z_cos, vertical, flip))); + } // and construct the final polyline to return: Polyline polyline; @@ -63,10 +68,11 @@ static std::vector make_one_period(double width, double scaleFactor, doub double dx = M_PI_2; // exact coordinates on main inflexion lobes double limit = std::min(2*M_PI, width); points.reserve(ceil(limit / tolerance / 3)); - for (double x = 0.; x < limit + EPSILON; x += dx) { // so the last point is there too - x = std::min(x, limit); + + for (double x = 0.; x < limit - EPSILON; x += dx) { points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip))); } + points.emplace_back(Vec2d(limit, f(limit, z_sin, z_cos, vertical, flip))); // piecewise increase in resolution up to requested tolerance for(;;) @@ -128,11 +134,11 @@ static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double for (double y0 = lower_bound; y0 < upper_bound + EPSILON; y0 += M_PI) { // creates odd polylines - result.emplace_back(make_wave(one_period_odd, width, height, y0, scaleFactor, z_cos, z_sin, vertical)); + result.emplace_back(make_wave(one_period_odd, width, height, y0, scaleFactor, z_cos, z_sin, vertical, flip)); // creates even polylines y0 += M_PI; if (y0 < upper_bound + EPSILON) { - result.emplace_back(make_wave(one_period_even, width, height, y0, scaleFactor, z_cos, z_sin, vertical)); + result.emplace_back(make_wave(one_period_even, width, height, y0, scaleFactor, z_cos, z_sin, vertical, flip)); } } From 1a846421530328c1190e1180929fdf5ae1496328 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Tue, 16 Jul 2019 01:15:00 +0200 Subject: [PATCH 07/25] Allow gyroid pattern rotation over Z --- src/libslic3r/Fill/FillGyroid.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index c0b3bd907c..1e1e35b9e7 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -152,7 +152,8 @@ void FillGyroid::_fill_surface_single( ExPolygon &expolygon, Polylines &polylines_out) { - // no rotation is supported for this infill pattern (yet) + expolygon.rotate(-this->angle); + BoundingBox bb = expolygon.contour.bounding_box(); // Density adjusted to have a good %of weight. double density_adjusted = std::max(0., params.density * 2.44); @@ -160,7 +161,7 @@ void FillGyroid::_fill_surface_single( coord_t distance = coord_t(scale_(this->spacing) / density_adjusted); // align bounding box to a multiple of our grid module - bb.merge(_align_to_grid(bb.min, Point(2.*M_PI*distance, 2.*M_PI*distance))); + bb.merge(_align_to_grid(bb.min, Point(2*M_PI*distance, 2*M_PI*distance))); // generate pattern Polylines polylines_square = make_gyroid_waves( @@ -169,16 +170,15 @@ void FillGyroid::_fill_surface_single( this->spacing, ceil(bb.size()(0) / distance) + 1., ceil(bb.size()(1) / distance) + 1.); - - // move pattern in place - for (Polyline &polyline : polylines_square) - polyline.translate(bb.min(0), bb.min(1)); // clip pattern to boundaries, keeping the polyline order & ordering the fragment to be able to join them easily - //Polylines polylines = intersection_pl(polylines_square, (Polygons)expolygon); Polylines polylines_chained; for (size_t idx_polyline = 0; idx_polyline < polylines_square.size(); ++idx_polyline) { + // shift the polyline to the grid origin Polyline &poly_to_cut = polylines_square[idx_polyline]; + poly_to_cut.translate(bb.min); + + // intersect Polylines polylines_to_sort = intersection_pl(Polylines() = { poly_to_cut }, (Polygons)expolygon); for (Polyline &polyline : polylines_to_sort) { //TODO: replace by closest_index_point() @@ -226,6 +226,12 @@ void FillGyroid::_fill_surface_single( idx--; } } + + // new paths must be rotated back + for (Polylines::iterator it = polylines_out.begin() + polylines_out_first_idx; + it != polylines_out.end(); ++it) { + it->rotate(this->angle); + } } } // namespace Slic3r From f8490fb4e0265a7c3ecd5292d1ae9716755fc56b Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Fri, 19 Jul 2019 12:59:57 +0200 Subject: [PATCH 08/25] Limit upper tolerance in Gyroid Do not reduce resolution more than necessary when using larger nozzles and/or higher layer heights. --- src/libslic3r/Fill/FillGyroid.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index 1e1e35b9e7..651abffd9c 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -106,9 +106,9 @@ static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double { const double scaleFactor = scale_(line_spacing) / density_adjusted; - // tolerance (in scaled units) - // TODO: should consider layer thickness - const double tolerance = line_spacing / 2 / unscale(scaleFactor); + // tolerance (in scaled units) - note: clamp the maximum tolerance + // as there's no benefit to reduce the definition with large nozzles + const double tolerance = std::min(line_spacing, 0.4) / 2 / unscale(scaleFactor); //scale factor for 5% : 8 712 388 // 1z = 10^-6 mm ? From da6c285f1f1bf8e1bdec8ec2998e3962842d6cc8 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Wed, 7 Aug 2019 21:45:23 +0200 Subject: [PATCH 09/25] Maximize gyroid printing speed angle Counter-rotate the default angle by 45' so that gyroid is kept at it's maximum printing speed by default. --- src/libslic3r/Fill/FillGyroid.cpp | 12 ++++++++---- src/libslic3r/Fill/FillGyroid.hpp | 5 +++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index 651abffd9c..b7f0f879b9 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -152,7 +152,9 @@ void FillGyroid::_fill_surface_single( ExPolygon &expolygon, Polylines &polylines_out) { - expolygon.rotate(-this->angle); + float infill_angle = this->angle + (CorrectionAngle * 2*M_PI) / 360.; + if(abs(infill_angle) >= EPSILON) + expolygon.rotate(-infill_angle); BoundingBox bb = expolygon.contour.bounding_box(); // Density adjusted to have a good %of weight. @@ -228,9 +230,11 @@ void FillGyroid::_fill_surface_single( } // new paths must be rotated back - for (Polylines::iterator it = polylines_out.begin() + polylines_out_first_idx; - it != polylines_out.end(); ++it) { - it->rotate(this->angle); + if(abs(infill_angle) >= EPSILON) { + for (Polylines::iterator it = polylines_out.begin() + polylines_out_first_idx; + it != polylines_out.end(); ++it) { + it->rotate(infill_angle); + } } } diff --git a/src/libslic3r/Fill/FillGyroid.hpp b/src/libslic3r/Fill/FillGyroid.hpp index 9c3cef940b..171a6b0345 100644 --- a/src/libslic3r/Fill/FillGyroid.hpp +++ b/src/libslic3r/Fill/FillGyroid.hpp @@ -16,6 +16,11 @@ public: // require bridge flow since most of this pattern hangs in air virtual bool use_bridge_flow() const { return false; } + // Correction applied to regular infill angle to maximize printing + // speed in default configuration (degrees) + static constexpr float CorrectionAngle = -45.; + + protected: virtual void _fill_surface_single( const FillParams ¶ms, From 90c85b7c8ab3397271761fa64a68b0bcce31da0b Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Wed, 7 Aug 2019 21:58:45 +0200 Subject: [PATCH 10/25] Move gyroid constants to the class declaration --- src/libslic3r/Fill/FillGyroid.cpp | 8 ++++---- src/libslic3r/Fill/FillGyroid.hpp | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index b7f0f879b9..ae96f1f90b 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -106,9 +106,9 @@ static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double { const double scaleFactor = scale_(line_spacing) / density_adjusted; - // tolerance (in scaled units) - note: clamp the maximum tolerance - // as there's no benefit to reduce the definition with large nozzles - const double tolerance = std::min(line_spacing, 0.4) / 2 / unscale(scaleFactor); + // tolerance in scaled units. clamp the maximum tolerance as there's + // no processing-speed benefit to do so beyond a certain point + const double tolerance = std::min(line_spacing, FillGyroid::PatternTolerance) / 2 / unscale(scaleFactor); //scale factor for 5% : 8 712 388 // 1z = 10^-6 mm ? @@ -158,7 +158,7 @@ void FillGyroid::_fill_surface_single( BoundingBox bb = expolygon.contour.bounding_box(); // Density adjusted to have a good %of weight. - double density_adjusted = std::max(0., params.density * 2.44); + double density_adjusted = std::max(0., params.density * DensityAdjust); // Distance between the gyroid waves in scaled coordinates. coord_t distance = coord_t(scale_(this->spacing) / density_adjusted); diff --git a/src/libslic3r/Fill/FillGyroid.hpp b/src/libslic3r/Fill/FillGyroid.hpp index 171a6b0345..261c0039e1 100644 --- a/src/libslic3r/Fill/FillGyroid.hpp +++ b/src/libslic3r/Fill/FillGyroid.hpp @@ -20,6 +20,12 @@ public: // speed in default configuration (degrees) static constexpr float CorrectionAngle = -45.; + // Density adjustment to have a good %of weight. + static constexpr double DensityAdjust = 2.44; + + // Gyroid upper resolution tolerance (mm^-2) + static constexpr double PatternTolerance = 0.4; + protected: virtual void _fill_surface_single( From 753b34a0d3cae8acd6fb6b65abad7631c9a4f5ec Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Thu, 8 Aug 2019 16:53:26 +0200 Subject: [PATCH 11/25] Make Gyroid::PatternTolerance match the description Move the division out of the switch in order to make the tolerance match the expected unit. --- src/libslic3r/Fill/FillGyroid.cpp | 6 +++--- src/libslic3r/Fill/FillGyroid.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index ae96f1f90b..341815e9bb 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -108,10 +108,10 @@ static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double // tolerance in scaled units. clamp the maximum tolerance as there's // no processing-speed benefit to do so beyond a certain point - const double tolerance = std::min(line_spacing, FillGyroid::PatternTolerance) / 2 / unscale(scaleFactor); + const double tolerance = std::min(line_spacing / 2, FillGyroid::PatternTolerance) / unscale(scaleFactor); - //scale factor for 5% : 8 712 388 - // 1z = 10^-6 mm ? + //scale factor for 5% : 8 712 388 + // 1z = 10^-6 mm ? const double z = gridZ / scaleFactor; const double z_sin = sin(z); const double z_cos = cos(z); diff --git a/src/libslic3r/Fill/FillGyroid.hpp b/src/libslic3r/Fill/FillGyroid.hpp index 261c0039e1..37babb25e3 100644 --- a/src/libslic3r/Fill/FillGyroid.hpp +++ b/src/libslic3r/Fill/FillGyroid.hpp @@ -24,7 +24,7 @@ public: static constexpr double DensityAdjust = 2.44; // Gyroid upper resolution tolerance (mm^-2) - static constexpr double PatternTolerance = 0.4; + static constexpr double PatternTolerance = 0.2; protected: From 189d7be93bfd67b4ce1691b19b174b87c39a1857 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Thu, 8 Aug 2019 17:04:15 +0200 Subject: [PATCH 12/25] Fix two warnings --- src/libslic3r/Fill/FillBase.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index f9259eed93..c4ad93be5a 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -454,12 +454,12 @@ void Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boun } //try to link to nearest point if possible - for (int idx1 = 0; idx1 < polylines_connected.size(); idx1++) { + for (size_t idx1 = 0; idx1 < polylines_connected.size(); idx1++) { size_t min_idx = 0; coordf_t min_length = 0; bool switch_id1 = false; bool switch_id2 = false; - for (int idx2 = idx1 + 1; idx2 < polylines_connected.size(); idx2++) { + for (size_t idx2 = idx1 + 1; idx2 < polylines_connected.size(); idx2++) { double last_first = polylines_connected[idx1].last_point().distance_to_square(polylines_connected[idx2].first_point()); double first_first = polylines_connected[idx1].first_point().distance_to_square(polylines_connected[idx2].first_point()); double first_last = polylines_connected[idx1].first_point().distance_to_square(polylines_connected[idx2].last_point()); From 21ee458de561762ba847e5d0afb19253e558998b Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 22 Aug 2019 09:47:44 +0200 Subject: [PATCH 13/25] Some Vojtech's beautification --- src/libslic3r/Fill/FillBase.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index c4ad93be5a..503e2c2c3c 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -130,15 +130,12 @@ std::pair Fill::_infill_direction(const Surface *surface) const return std::pair(out_angle, out_shift); } - - - /// cut poly between poly.point[idx_1] & poly.point[idx_1+1] /// add p1+-width to one part and p2+-width to the other one. /// add the "new" polyline to polylines (to part cut from poly) /// p1 & p2 have to be between poly.point[idx_1] & poly.point[idx_1+1] /// if idx_1 is ==0 or == size-1, then we don't need to create a new polyline. -void cut_polyline(Polyline &poly, Polylines &polylines, size_t idx_1, Point p1, Point p2) { +static void cut_polyline(Polyline &poly, Polylines &polylines, size_t idx_1, Point p1, Point p2) { //reorder points if (p1.distance_to_square(poly.points[idx_1]) > p2.distance_to_square(poly.points[idx_1])) { Point temp = p2; @@ -166,7 +163,7 @@ void cut_polyline(Polyline &poly, Polylines &polylines, size_t idx_1, Point p1, } /// the poly is like a polygon but with first_point != last_point (already removed) -void cut_polygon(Polyline &poly, size_t idx_1, Point p1, Point p2) { +static void cut_polygon(Polyline &poly, size_t idx_1, Point p1, Point p2) { //reorder points if (p1.distance_to_square(poly.points[idx_1]) > p2.distance_to_square(poly.points[idx_1])) { Point temp = p2; @@ -188,7 +185,7 @@ void cut_polygon(Polyline &poly, size_t idx_1, Point p1, Point p2) { /// it use equally_spaced_points with width/2 precision, so don't worry with pts_to_check number of points. /// it use the given polylines_blocker points, be sure to put enough of them to be reliable. /// complexity : N(pts_to_check.equally_spaced_points(width / 2)) x N(polylines_blocker.points) -bool collision(const Points &pts_to_check, const Polylines &polylines_blocker, const coordf_t width) { +static bool collision(const Points &pts_to_check, const Polylines &polylines_blocker, const coordf_t width) { //check if it's not too close to a polyline coordf_t min_dist_square = width * width * 0.9 - SCALED_EPSILON; Polyline better_polylines(pts_to_check); @@ -209,7 +206,7 @@ bool collision(const Points &pts_to_check, const Polylines &polylines_blocker, c /// width if the width of the extrusion /// polylines_blockers are the array of polylines to check if the path isn't blocked by something. /// complexity: N(polylines.points) + a collision check after that if we finded a path: N(2(p2-p1)/width) x N(polylines_blocker.points) -Points getFrontier(Polylines &polylines, const Point& p1, const Point& p2, const coord_t width, const Polylines &polylines_blockers, coord_t max_size = -1) { +static Points get_frontier(Polylines &polylines, const Point& p1, const Point& p2, const coord_t width, const Polylines &polylines_blockers, coord_t max_size = -1) { for (size_t idx_poly = 0; idx_poly < polylines.size(); ++idx_poly) { Polyline &poly = polylines[idx_poly]; if (poly.size() <= 1) continue; @@ -414,7 +411,7 @@ void Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boun const Point &last_point = pts_end.back(); const Point &first_point = polyline.points.front(); if (last_point.distance_to(first_point) < scale_(this->spacing) * 10) { - Points pts_frontier = getFrontier(polylines_frontier, last_point, first_point, scale_(this->spacing), polylines_blocker, (coord_t)scale_(ideal_length) * 2); + Points pts_frontier = get_frontier(polylines_frontier, last_point, first_point, scale_(this->spacing), polylines_blocker, (coord_t)scale_(ideal_length) * 2); if (!pts_frontier.empty()) { // The lines can be connected. pts_end.insert(pts_end.end(), pts_frontier.begin(), pts_frontier.end()); @@ -439,7 +436,7 @@ void Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boun const Point &first_point = polyline.points.front(); Polylines before = polylines_frontier; - Points pts_frontier = getFrontier(polylines_frontier, last_point, first_point, scale_(this->spacing), polylines_blocker); + Points pts_frontier = get_frontier(polylines_frontier, last_point, first_point, scale_(this->spacing), polylines_blocker); if (!pts_frontier.empty()) { // The lines can be connected. pts_end.insert(pts_end.end(), pts_frontier.begin(), pts_frontier.end()); @@ -473,7 +470,7 @@ void Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boun } } if (min_idx > idx1 && min_idx < polylines_connected.size()){ - Points pts_frontier = getFrontier(polylines_frontier, + Points pts_frontier = get_frontier(polylines_frontier, switch_id1 ? polylines_connected[idx1].first_point() : polylines_connected[idx1].last_point(), switch_id2 ? polylines_connected[min_idx].last_point() : polylines_connected[min_idx].first_point(), scale_(this->spacing), polylines_blocker); @@ -490,7 +487,7 @@ void Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boun //try to create some loops if possible for (Polyline &polyline : polylines_connected) { - Points pts_frontier = getFrontier(polylines_frontier, polyline.last_point(), polyline.first_point(), scale_(this->spacing), polylines_blocker); + Points pts_frontier = get_frontier(polylines_frontier, polyline.last_point(), polyline.first_point(), scale_(this->spacing), polylines_blocker); if (!pts_frontier.empty()) { polyline.points.insert(polyline.points.end(), pts_frontier.begin(), pts_frontier.end()); polyline.points.insert(polyline.points.begin(), polyline.points.back()); From 82bc243281e0c4e46e20a9bafecfa8d72c20936e Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 26 Sep 2019 16:33:55 +0200 Subject: [PATCH 14/25] Implemented possibility to set a resin cost --- src/admesh/stl.h | 2 +- src/libslic3r/PrintConfig.cpp | 28 ++++++++++++++++++++++++++ src/libslic3r/PrintConfig.hpp | 8 ++++++++ src/libslic3r/SLAPrint.cpp | 6 +++++- src/slic3r/GUI/Plater.cpp | 32 +++++++++++++++++++++++------- src/slic3r/GUI/Plater.hpp | 1 + src/slic3r/GUI/Preset.cpp | 4 ++++ src/slic3r/GUI/Tab.cpp | 37 +++++++++++++++++++++++++++++++++-- 8 files changed, 107 insertions(+), 11 deletions(-) diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 43999d365b..a6989ca6ed 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -90,7 +90,7 @@ struct stl_neighbors { struct stl_stats { stl_stats() { memset(&header, 0, 81); } - char header[81] = ""; + char header[81];// = ""; stl_type type = (stl_type)0; uint32_t number_of_facets = 0; stl_vertex max = stl_vertex::Zero(); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 1ce00f269d..a862a8fe3b 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2404,6 +2404,34 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->set_default_value(new ConfigOptionFloat(0.3)); + def = this->add("bottle_volume", coFloat); + def->label = L("Bottle volume"); + def->tooltip = L("Bottle volume"); + def->sidetext = L("ml"); + def->min = 50; + def->set_default_value(new ConfigOptionFloat(960.0)); + + def = this->add("bottle_weight", coFloat); + def->label = L("Bottle weight"); + def->tooltip = L("Bottle weight"); + def->sidetext = L("kg"); + def->min = 0; + def->set_default_value(new ConfigOptionFloat(1.0)); + + def = this->add("material_density", coFloat); + def->label = L("Density"); + def->tooltip = L("Density"); + def->sidetext = L("g/ml"); + def->min = 0; + def->set_default_value(new ConfigOptionFloat(0.960)); + + def = this->add("bottle_cost", coFloat); + def->label = L("Cost"); + def->tooltip = L("Cost"); + def->sidetext = L("money/bottle"); + def->min = 0; + def->set_default_value(new ConfigOptionFloat(0.0)); + def = this->add("faded_layers", coInt); def->label = L("Faded layers"); def->tooltip = L("Number of the layers needed for the exposure time fade from initial exposure time to the exposure time"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 6a19edf845..e92ddabac4 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1098,6 +1098,10 @@ class SLAMaterialConfig : public StaticPrintConfig STATIC_PRINT_CONFIG_CACHE(SLAMaterialConfig) public: ConfigOptionFloat initial_layer_height; + ConfigOptionFloat bottle_cost; + ConfigOptionFloat bottle_volume; + ConfigOptionFloat bottle_weight; + ConfigOptionFloat material_density; ConfigOptionFloat exposure_time; ConfigOptionFloat initial_exposure_time; ConfigOptionFloats material_correction; @@ -1105,6 +1109,10 @@ protected: void initialize(StaticCacheBase &cache, const char *base_ptr) { OPT_PTR(initial_layer_height); + OPT_PTR(bottle_cost); + OPT_PTR(bottle_volume); + OPT_PTR(bottle_weight); + OPT_PTR(material_density); OPT_PTR(exposure_time); OPT_PTR(initial_exposure_time); OPT_PTR(material_correction); diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 46d039c1f0..6048996524 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1620,7 +1620,11 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector steps; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 97c292703a..1042499b2d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -221,7 +221,7 @@ SlicedInfo::SlicedInfo(wxWindow *parent) : init_info_label(_(L("Used Filament (mm³)"))); init_info_label(_(L("Used Filament (g)"))); init_info_label(_(L("Used Material (unit)"))); - init_info_label(_(L("Cost"))); + init_info_label(_(L("Cost (money)"))); init_info_label(_(L("Estimated printing time"))); init_info_label(_(L("Number of tool changes"))); @@ -1117,12 +1117,10 @@ void Sidebar::show_info_sizer() } } -void Sidebar::show_sliced_info_sizer(const bool show) +void Sidebar::update_sliced_info_sizer() { - wxWindowUpdateLocker freeze_guard(this); - - p->sliced_info->Show(show); - if (show) { + if (p->sliced_info->IsShown(size_t(0))) + { if (p->plater->printer_technology() == ptSLA) { const SLAPrintStatistics& ps = p->plater->sla_print().print_statistics(); @@ -1138,7 +1136,18 @@ void Sidebar::show_sliced_info_sizer(const bool show) wxString::Format("%.2f", (ps.objects_used_material + ps.support_used_material) / 1000); p->sliced_info->SetTextAndShow(siMateril_unit, info_text, new_label); - p->sliced_info->SetTextAndShow(siCost, "N/A"/*wxString::Format("%.2f", ps.total_cost)*/); + wxString str_total_cost = "N/A"; + + DynamicPrintConfig* cfg = wxGetApp().get_tab(Preset::TYPE_SLA_MATERIAL)->get_config(); + if (cfg->option("bottle_cost")->getFloat() > 0.0 && + cfg->option("bottle_volume")->getFloat() > 0.0) + { + double material_cost = cfg->option("bottle_cost")->getFloat() / + cfg->option("bottle_volume")->getFloat(); + str_total_cost = wxString::Format("%.2f", material_cost*(ps.objects_used_material + ps.support_used_material) / 1000); + } + p->sliced_info->SetTextAndShow(siCost, str_total_cost); + wxString t_est = std::isnan(ps.estimated_print_time) ? "N/A" : get_time_dhms(float(ps.estimated_print_time)); p->sliced_info->SetTextAndShow(siEstimatedTime, t_est, _(L("Estimated printing time")) + " :"); @@ -1212,6 +1221,15 @@ void Sidebar::show_sliced_info_sizer(const bool show) p->sliced_info->SetTextAndShow(siMateril_unit, "N/A"); } } +} + +void Sidebar::show_sliced_info_sizer(const bool show) +{ + wxWindowUpdateLocker freeze_guard(this); + + p->sliced_info->Show(show); + if (show) + update_sliced_info_sizer(); Layout(); p->scrolled->Refresh(); diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 26dcb5ac32..dddad9d6c9 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -108,6 +108,7 @@ public: void update_objects_list_extruder_column(size_t extruders_count); void show_info_sizer(); void show_sliced_info_sizer(const bool show); + void update_sliced_info_sizer(); void enable_buttons(bool enable); void set_btn_label(const ActionButtonType btn_type, const wxString& label) const; bool show_reslice(bool show) const; diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index d2503d349d..f6164bc45f 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -500,6 +500,10 @@ const std::vector& Preset::sla_material_options() if (s_opts.empty()) { s_opts = { "initial_layer_height", + "bottle_cost", + "bottle_volume", + "bottle_weight", + "material_density", "exposure_time", "initial_exposure_time", "material_correction", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index c87626a483..cc0800bacd 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3398,8 +3398,41 @@ void TabSLAMaterial::build() auto page = add_options_page(_(L("Material")), "resin"); - auto optgroup = page->new_optgroup(_(L("Layers"))); -// optgroup->append_single_option_line("layer_height"); + auto optgroup = page->new_optgroup(_(L("Material"))); + optgroup->append_single_option_line("bottle_cost"); + optgroup->append_single_option_line("bottle_volume"); + optgroup->append_single_option_line("bottle_weight"); + optgroup->append_single_option_line("material_density"); + + optgroup->m_on_change = [this, optgroup](t_config_option_key opt_key, boost::any value) + { + DynamicPrintConfig new_conf = *m_config; + + if (opt_key == "bottle_volume") { + double new_bottle_weight = boost::any_cast(value)/(new_conf.option("material_density")->getFloat() * 1000); + new_conf.set_key_value("bottle_weight", new ConfigOptionFloat(new_bottle_weight)); + } + if (opt_key == "bottle_weight") { + double new_bottle_volume = boost::any_cast(value)*(new_conf.option("material_density")->getFloat() * 1000); + new_conf.set_key_value("bottle_volume", new ConfigOptionFloat(new_bottle_volume)); + } + if (opt_key == "material_density") { + double new_bottle_weight = new_conf.option("bottle_volume")->getFloat() * boost::any_cast(value) / 1000; + new_conf.set_key_value("bottle_weight", new ConfigOptionFloat(new_bottle_weight)); + } + + load_config(new_conf); + + update_dirty(); + on_value_change(opt_key, value); + + if (opt_key == "bottle_volume" || opt_key == "bottle_cost") { + wxGetApp().sidebar().update_sliced_info_sizer(); + wxGetApp().sidebar().Layout(); + } + }; + + optgroup = page->new_optgroup(_(L("Layers"))); optgroup->append_single_option_line("initial_layer_height"); optgroup = page->new_optgroup(_(L("Exposure"))); From c370fccd8b76b1c2f345812cd0f1cf15a3226860 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 27 Sep 2019 12:08:08 +0200 Subject: [PATCH 15/25] Changed default values. And bottle_volume is preferred to recalculation instead of bottle_weight --- src/libslic3r/PrintConfig.cpp | 4 ++-- src/slic3r/GUI/Tab.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index a862a8fe3b..f8f17d1c3a 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2409,7 +2409,7 @@ void PrintConfigDef::init_sla_params() def->tooltip = L("Bottle volume"); def->sidetext = L("ml"); def->min = 50; - def->set_default_value(new ConfigOptionFloat(960.0)); + def->set_default_value(new ConfigOptionFloat(1000.0)); def = this->add("bottle_weight", coFloat); def->label = L("Bottle weight"); @@ -2423,7 +2423,7 @@ void PrintConfigDef::init_sla_params() def->tooltip = L("Density"); def->sidetext = L("g/ml"); def->min = 0; - def->set_default_value(new ConfigOptionFloat(0.960)); + def->set_default_value(new ConfigOptionFloat(1.0)); def = this->add("bottle_cost", coFloat); def->label = L("Cost"); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index cc0800bacd..25604080e8 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3417,8 +3417,8 @@ void TabSLAMaterial::build() new_conf.set_key_value("bottle_volume", new ConfigOptionFloat(new_bottle_volume)); } if (opt_key == "material_density") { - double new_bottle_weight = new_conf.option("bottle_volume")->getFloat() * boost::any_cast(value) / 1000; - new_conf.set_key_value("bottle_weight", new ConfigOptionFloat(new_bottle_weight)); + double new_bottle_volume = new_conf.option("bottle_weight")->getFloat() * boost::any_cast(value) * 1000; + new_conf.set_key_value("bottle_volume", new ConfigOptionFloat(new_bottle_volume)); } load_config(new_conf); From 67f55d3b23c36021f543e74d90d53902a6effed6 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 7 Nov 2019 12:09:04 +0100 Subject: [PATCH 16/25] Change std::async to boost thread in Plater::priv::Job --- src/slic3r/GUI/Plater.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index cdd35b720c..e2ea9bc1a9 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -1439,7 +1440,7 @@ struct Plater::priv class Job : public wxEvtHandler { int m_range = 100; - std::future m_ftr; + boost::thread m_thread; priv * m_plater = nullptr; std::atomic m_running{false}, m_canceled{false}; bool m_finalized = false; @@ -1480,7 +1481,8 @@ struct Plater::priv // Do a full refresh of scene tree, including regenerating // all the GLVolumes. FIXME The update function shall just // reload the modified matrices. - if (!was_canceled()) plater().update((unsigned int)UpdateParams::FORCE_FULL_SCREEN_REFRESH); + if (!was_canceled()) + plater().update(unsigned(UpdateParams::FORCE_FULL_SCREEN_REFRESH)); } public: @@ -1509,9 +1511,9 @@ struct Plater::priv } Job(const Job &) = delete; - Job(Job &&) = default; + Job(Job &&) = delete; Job &operator=(const Job &) = delete; - Job &operator=(Job &&) = default; + Job &operator=(Job &&) = delete; virtual void process() = 0; @@ -1535,7 +1537,9 @@ struct Plater::priv wxBeginBusyCursor(); try { // Execute the job - m_ftr = std::async(std::launch::async, &Job::run, this); + boost::thread::attributes attrs; + attrs.set_stack_size((sizeof(void*) == 4) ? (2048 * 1024) : (4096 * 1024)); + m_thread = boost::thread(attrs, [this] { this->run(); }); } catch (std::exception &) { update_status(status_range(), _(L("ERROR: not enough resources to " @@ -1551,16 +1555,15 @@ struct Plater::priv // returned if the timeout has been reached and the job is still // running. Call cancel() before this fn if you want to explicitly // end the job. - bool join(int timeout_ms = 0) const + bool join(int timeout_ms = 0) { - if (!m_ftr.valid()) return true; - + if (!m_thread.joinable()) return true; + if (timeout_ms <= 0) - m_ftr.wait(); - else if (m_ftr.wait_for(std::chrono::milliseconds( - timeout_ms)) == std::future_status::timeout) + m_thread.join(); + else if (!m_thread.try_join_for(boost::chrono::milliseconds(timeout_ms))) return false; - + return true; } From ad0a38e4190ad022b609f294a54c010185b1f676 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 7 Nov 2019 12:57:40 +0100 Subject: [PATCH 17/25] Follow up, unify boost::thread usage. --- src/slic3r/CMakeLists.txt | 1 + src/slic3r/GUI/BackgroundSlicingProcess.cpp | 6 +---- src/slic3r/GUI/BackgroundSlicingProcess.hpp | 2 +- src/slic3r/GUI/Plater.cpp | 6 ++--- src/slic3r/Utils/Thread.hpp | 28 +++++++++++++++++++++ 5 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 src/slic3r/Utils/Thread.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 84a60da6ec..9ed7424c05 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -156,6 +156,7 @@ set(SLIC3R_GUI_SOURCES Utils/UndoRedo.hpp Utils/HexFile.cpp Utils/HexFile.hpp + Utils/Thread.hpp ) if (APPLE) diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 3f0d87c355..5ab65f340b 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -261,11 +261,7 @@ bool BackgroundSlicingProcess::start() if (m_state == STATE_INITIAL) { // The worker thread is not running yet. Start it. assert(! m_thread.joinable()); - boost::thread::attributes attrs; - // Duplicating the stack allocation size of Thread Building Block worker threads of the thread pool: - // allocate 4MB on a 64bit system, allocate 2MB on a 32bit system by default. - attrs.set_stack_size((sizeof(void*) == 4) ? (2048 * 1024) : (4096 * 1024)); - m_thread = boost::thread(attrs, [this]{this->thread_proc_safe();}); + m_thread = create_thread([this]{this->thread_proc_safe();}); // Wait until the worker thread is ready to execute the background processing task. m_condition.wait(lck, [this](){ return m_state == STATE_IDLE; }); } diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index bf8cbc2359..a603d52acc 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -6,12 +6,12 @@ #include #include -#include #include #include "libslic3r/Print.hpp" #include "slic3r/Utils/PrintHost.hpp" +#include "slic3r/Utils/Thread.hpp" namespace Slic3r { diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e2ea9bc1a9..da3a07a594 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -76,6 +75,7 @@ #include "../Utils/PrintHost.hpp" #include "../Utils/FixModelByWin10.hpp" #include "../Utils/UndoRedo.hpp" +#include "../Utils/Thread.hpp" #include // Needs to be last because reasons :-/ #include "WipeTowerDialog.hpp" @@ -1537,9 +1537,7 @@ struct Plater::priv wxBeginBusyCursor(); try { // Execute the job - boost::thread::attributes attrs; - attrs.set_stack_size((sizeof(void*) == 4) ? (2048 * 1024) : (4096 * 1024)); - m_thread = boost::thread(attrs, [this] { this->run(); }); + m_thread = create_thread([this] { this->run(); }); } catch (std::exception &) { update_status(status_range(), _(L("ERROR: not enough resources to " diff --git a/src/slic3r/Utils/Thread.hpp b/src/slic3r/Utils/Thread.hpp new file mode 100644 index 0000000000..e9c76d2aba --- /dev/null +++ b/src/slic3r/Utils/Thread.hpp @@ -0,0 +1,28 @@ +#ifndef THREAD_HPP +#define THREAD_HPP + +#include +#include + +namespace Slic3r { + +template +inline boost::thread create_thread(boost::thread::attributes &attrs, Fn &&fn) +{ + // Duplicating the stack allocation size of Thread Building Block worker + // threads of the thread pool: allocate 4MB on a 64bit system, allocate 2MB + // on a 32bit system by default. + + attrs.set_stack_size((sizeof(void*) == 4) ? (2048 * 1024) : (4096 * 1024)); + return boost::thread{attrs, std::forward(fn)}; +} + +template inline boost::thread create_thread(Fn &&fn) +{ + boost::thread::attributes attrs; + return create_thread(attrs, std::forward(fn)); +} + +} + +#endif // THREAD_HPP From 621b8426d3855a9b7c9c998a3d32a1adcb9fd284 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 11 Nov 2019 11:21:08 +0100 Subject: [PATCH 18/25] #3175 - Fixed compatibility with boost v 1.71 --- src/libslic3r/GCode.cpp | 21 +++++++++++++-------- src/slic3r/GUI/GUI_App.cpp | 14 ++++++++++---- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 63658e817f..61849e30d8 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -961,7 +961,7 @@ void GCode::_do_export(Print &print, FILE *file) // Write thumbnails using base64 encoding if (thumbnail_data != nullptr) { - const unsigned int max_row_length = 78; + const size_t max_row_length = 78; for (const ThumbnailData& data : *thumbnail_data) { @@ -972,19 +972,21 @@ void GCode::_do_export(Print &print, FILE *file) void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1); if (png_data != nullptr) { - _write_format(file, "\n;\n; thumbnail begin %dx%d\n", data.width, data.height); + std::string encoded; + encoded.resize(boost::beast::detail::base64::encoded_size(png_size)); + encoded.resize(boost::beast::detail::base64::encode((void*)&encoded[0], (const void*)png_data, png_size)); - std::string encoded = boost::beast::detail::base64_encode((const std::uint8_t*)png_data, png_size); + _write_format(file, "\n;\n; thumbnail begin %dx%d %d\n", data.width, data.height, encoded.size()); unsigned int row_count = 0; - while (encoded.length() > max_row_length) + while (encoded.size() > max_row_length) { _write_format(file, "; %s\n", encoded.substr(0, max_row_length).c_str()); encoded = encoded.substr(max_row_length); ++row_count; } - if (encoded.length() > 0) + if (encoded.size() > 0) _write_format(file, "; %s\n", encoded.c_str()); _write(file, "; thumbnail end\n;\n"); @@ -997,9 +999,12 @@ void GCode::_do_export(Print &print, FILE *file) size_t row_size = 4 * data.width; for (int r = (int)data.height - 1; r >= 0; --r) { - std::string encoded = boost::beast::detail::base64_encode((const std::uint8_t*)(data.pixels.data() + r * row_size), row_size); + std::string encoded; + encoded.resize(boost::beast::detail::base64::encoded_size(row_size)); + encoded.resize(boost::beast::detail::base64::encode((void*)&encoded[0], (const void*)(data.pixels.data() + r * row_size), row_size)); + unsigned int row_count = 0; - while (encoded.length() > max_row_length) + while (encoded.size() > max_row_length) { if (row_count == 0) _write_format(file, "; %s\n", encoded.substr(0, max_row_length).c_str()); @@ -1010,7 +1015,7 @@ void GCode::_do_export(Print &print, FILE *file) ++row_count; } - if (encoded.length() > 0) + if (encoded.size() > 0) { if (row_count == 0) _write_format(file, "; %s\n", encoded.c_str()); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 0b24e22157..bcfb9ad393 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1131,8 +1131,11 @@ void GUI_App::gcode_thumbnails_debug() boost::nowide::ofstream out_file(out_filename.c_str(), std::ios::binary); if (out_file.good()) { - std::string decoded = boost::beast::detail::base64_decode(row); - out_file.write(decoded.c_str(), decoded.length()); + std::string decoded; + decoded.resize(boost::beast::detail::base64::decoded_size(row.size())); + decoded.resize(boost::beast::detail::base64::decode((void*)&decoded[0], row.data(), row.size()).first); + + out_file.write(decoded.c_str(), decoded.size()); out_file.close(); } #else @@ -1147,8 +1150,11 @@ void GUI_App::gcode_thumbnails_debug() std::vector thumbnail(4 * width * height, 0); for (unsigned int r = 0; r < (unsigned int)rows.size(); ++r) { - std::string decoded_row = boost::beast::detail::base64_decode(rows[r]); - if ((unsigned int)decoded_row.length() == width * 4) + std::string decoded_row; + decoded_row.resize(boost::beast::detail::base64::decoded_size(rows[r].size())); + decoded_row.resize(boost::beast::detail::base64::decode((void*)&decoded_row[0], rows[r].data(), rows[r].size()).first); + + if ((unsigned int)decoded_row.size() == width * 4) { void* image_ptr = (void*)(thumbnail.data() + r * width * 4); ::memcpy(image_ptr, (const void*)decoded_row.c_str(), width * 4); From bbb4a20dcd12f109ac692a569d9762bb8e372ac1 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 11 Nov 2019 12:08:04 +0100 Subject: [PATCH 19/25] Disable Dark Mode on Mac OS for now in the Info.plist wxWidgets upgrade (or backport) is required first --- src/platform/osx/Info.plist.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/platform/osx/Info.plist.in b/src/platform/osx/Info.plist.in index f4e298180b..d09f015b9c 100644 --- a/src/platform/osx/Info.plist.in +++ b/src/platform/osx/Info.plist.in @@ -116,5 +116,7 @@ NSApplication NSHighResolutionCapable + NSRequiresAquaSystemAppearance + From 7a24f87c7f514d132c8b1e4d06ab2e13cc11991d Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 11 Nov 2019 15:44:12 +0100 Subject: [PATCH 20/25] Fix deps build on Mac Fix #2264 --- deps/deps-macos.cmake | 6 ++---- deps/deps-unix-common.cmake | 2 +- deps/deps-windows.cmake | 1 - 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/deps/deps-macos.cmake b/deps/deps-macos.cmake index fc08c62903..9e51735fd5 100644 --- a/deps/deps-macos.cmake +++ b/deps/deps-macos.cmake @@ -16,8 +16,8 @@ include("deps-unix-common.cmake") ExternalProject_Add(dep_boost EXCLUDE_FROM_ALL 1 - URL "https://dl.bintray.com/boostorg/release/1.71.0/source/boost_1_71_0.tar.gz" - URL_HASH SHA256=96b34f7468f26a141f6020efb813f1a2f3dfb9797ecf76a7d7cbd843cc95f5bd + URL "https://dl.bintray.com/boostorg/release/1.70.0/source/boost_1_70_0.tar.gz" + URL_HASH SHA256=882b48708d211a5f48e60b0124cf5863c1534cd544ecd0664bb534a4b5d506e9 BUILD_IN_SOURCE 1 CONFIGURE_COMMAND ./bootstrap.sh --with-toolset=clang @@ -90,8 +90,6 @@ ExternalProject_Add(dep_wxwidgets EXCLUDE_FROM_ALL 1 GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets" GIT_TAG v3.1.1-patched -# URL "https://github.com/wxWidgets/wxWidgets/releases/download/v3.1.2/wxWidgets-3.1.2.tar.bz2" -# URL_HASH SHA256=4cb8d23d70f9261debf7d6cfeca667fc0a7d2b6565adb8f1c484f9b674f1f27a BUILD_IN_SOURCE 1 # PATCH_COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/wxwidgets-pngprefix.h" src/png/pngprefix.h CONFIGURE_COMMAND env "CXXFLAGS=${DEP_WERRORS_SDK}" "CFLAGS=${DEP_WERRORS_SDK}" ./configure diff --git a/deps/deps-unix-common.cmake b/deps/deps-unix-common.cmake index eae319efc6..74582f601b 100644 --- a/deps/deps-unix-common.cmake +++ b/deps/deps-unix-common.cmake @@ -62,7 +62,7 @@ ExternalProject_Add(dep_qhull -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local ${DEP_CMAKE_OPTS} UPDATE_COMMAND "" - PATCH_COMMAND ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/qhull-mods.patch + PATCH_COMMAND patch -p1 < ${CMAKE_CURRENT_SOURCE_DIR}/qhull-mods.patch ) ExternalProject_Add(dep_blosc diff --git a/deps/deps-windows.cmake b/deps/deps-windows.cmake index 514a90a9ec..4aae07d4a9 100644 --- a/deps/deps-windows.cmake +++ b/deps/deps-windows.cmake @@ -227,7 +227,6 @@ ExternalProject_Add(dep_qhull -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_DEBUG_POSTFIX=d UPDATE_COMMAND "" - PATCH_COMMAND ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/qhull-mods.patch BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj INSTALL_COMMAND "" ) From e12512dec0c4ab141e41d0d62da7a2834fb578b6 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 11 Nov 2019 17:10:29 +0100 Subject: [PATCH 21/25] Fix: Rename DPI changed event to not clash with impl in wxwidgets --- src/slic3r/GUI/GUI_App.cpp | 2 +- src/slic3r/GUI/GUI_Utils.cpp | 2 +- src/slic3r/GUI/GUI_Utils.hpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index bcfb9ad393..7d37baa665 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -105,7 +105,7 @@ static void register_dpi_event() const auto rect = reinterpret_cast(lParam); const wxRect wxrect(wxPoint(rect->top, rect->left), wxPoint(rect->bottom, rect->right)); - DpiChangedEvent evt(EVT_DPI_CHANGED, dpi, wxrect); + DpiChangedEvent evt(EVT_DPI_CHANGED_SLICER, dpi, wxrect); win->GetEventHandler()->AddPendingEvent(evt); return true; diff --git a/src/slic3r/GUI/GUI_Utils.cpp b/src/slic3r/GUI/GUI_Utils.cpp index d5753f2ccf..5090382cef 100644 --- a/src/slic3r/GUI/GUI_Utils.cpp +++ b/src/slic3r/GUI/GUI_Utils.cpp @@ -55,7 +55,7 @@ void on_window_geometry(wxTopLevelWindow *tlw, std::function callback) #endif } -wxDEFINE_EVENT(EVT_DPI_CHANGED, DpiChangedEvent); +wxDEFINE_EVENT(EVT_DPI_CHANGED_SLICER, DpiChangedEvent); #ifdef _WIN32 template typename F::FN winapi_get_function(const wchar_t *dll, const char *fn_name) { diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index c47714e464..f7bebd5778 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -50,7 +50,7 @@ struct DpiChangedEvent : public wxEvent { } }; -wxDECLARE_EVENT(EVT_DPI_CHANGED, DpiChangedEvent); +wxDECLARE_EVENT(EVT_DPI_CHANGED_SLICER, DpiChangedEvent); template class DPIAware : public P { @@ -75,7 +75,7 @@ public: // recalc_font(); - this->Bind(EVT_DPI_CHANGED, [this](const DpiChangedEvent &evt) { + this->Bind(EVT_DPI_CHANGED_SLICER, [this](const DpiChangedEvent &evt) { m_scale_factor = (float)evt.dpi / (float)DPI_DEFAULT; m_new_font_point_size = get_default_font_for_dpi(evt.dpi).GetPointSize(); From 316832b23d6ac8347613896d7be73c77ebd35910 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 12 Nov 2019 09:14:42 +0100 Subject: [PATCH 22/25] Fixed out of printbed detection for non-printable objects leading to inconsistent volumes' color --- src/slic3r/GUI/3DScene.cpp | 12 ++++++------ src/slic3r/GUI/GLCanvas3D.cpp | 15 +-------------- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 086ba7a74a..bbfcabd36f 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -707,24 +707,24 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M print_volume.min(2) = -1e10; ModelInstance::EPrintVolumeState state = ModelInstance::PVS_Inside; - bool all_contained = true; bool contained_min_one = false; for (GLVolume* volume : this->volumes) { - if ((volume == nullptr) || !volume->printable || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || ((volume->composite_id.volume_id < 0) && !volume->shader_outside_printer_detection_enabled)) + if ((volume == nullptr) || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || ((volume->composite_id.volume_id < 0) && !volume->shader_outside_printer_detection_enabled)) continue; const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); bool contained = print_volume.contains(bb); - all_contained &= contained; + + volume->is_outside = !contained; + if (!volume->printable) + continue; if (contained) contained_min_one = true; - volume->is_outside = !contained; - if ((state == ModelInstance::PVS_Inside) && volume->is_outside) state = ModelInstance::PVS_Fully_Outside; @@ -735,7 +735,7 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M if (out_state != nullptr) *out_state = state; - return /*all_contained*/ contained_min_one; // #ys_FIXME_delete_after_testing + return contained_min_one; } void GLVolumeCollection::reset_outside_state() diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 99f61e51ed..e4a5f590d8 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2090,20 +2090,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, contained_min_one && !m_model->objects.empty() && state != ModelInstance::PVS_Partly_Outside)); - -// #ys_FIXME_delete_after_testing -// bool contained = m_volumes.check_outside_state(m_config, &state); -// if (!contained) -// { -// _set_warning_texture(WarningTexture::ObjectOutside, true); -// post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, state == ModelInstance::PVS_Fully_Outside)); -// } -// else -// { -// m_volumes.reset_outside_state(); -// _set_warning_texture(WarningTexture::ObjectOutside, false); -// post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, !m_model->objects.empty())); -// } } else { @@ -2887,6 +2873,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) volume_bbox.offset(1.0); if (volume_bbox.contains(m_mouse.scene_position)) { + m_volumes.volumes[volume_idx]->hover = GLVolume::HS_None; // The dragging operation is initiated. m_mouse.drag.move_volume_idx = volume_idx; m_selection.start_dragging(); From cc919c68b849a0b474f8b609ffe19f15dfbfbd88 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 12 Nov 2019 11:59:33 +0100 Subject: [PATCH 23/25] Use Linux-style paths when saving custom bed texture and model files into config --- src/slic3r/GUI/3DBed.cpp | 2 ++ src/slic3r/GUI/BedShapeDialog.cpp | 32 +++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 4185b66646..82b5122703 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -204,6 +204,7 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c std::string cst_texture(custom_texture); if (!cst_texture.empty()) { + std::replace(cst_texture.begin(), cst_texture.end(), '\\', '/'); if ((!boost::algorithm::iends_with(custom_texture, ".png") && !boost::algorithm::iends_with(custom_texture, ".svg")) || !boost::filesystem::exists(custom_texture)) cst_texture = ""; } @@ -212,6 +213,7 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c std::string cst_model(custom_model); if (!cst_model.empty()) { + std::replace(cst_model.begin(), cst_model.end(), '\\', '/'); if (!boost::algorithm::iends_with(custom_model, ".stl") || !boost::filesystem::exists(custom_model)) cst_model = ""; } diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index 5624ada9d2..e83904a91d 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -60,7 +60,9 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf { m_shape = default_pt.values; m_custom_texture = custom_texture.value.empty() ? NONE : custom_texture.value; + std::replace(m_custom_texture.begin(), m_custom_texture.end(), '\\', '/'); m_custom_model = custom_model.value.empty() ? NONE : custom_model.value; + std::replace(m_custom_model.begin(), m_custom_model.end(), '\\', '/'); auto sbsizer = new wxStaticBoxSizer(wxVERTICAL, this, _(L("Shape"))); sbsizer->GetStaticBox()->SetFont(wxGetApp().bold_font()); @@ -212,7 +214,18 @@ wxPanel* BedShapePanel::init_texture_panel() wxStaticText* lbl = dynamic_cast(e.GetEventObject()); if (lbl != nullptr) { - wxString tooltip_text = (m_custom_texture == NONE) ? "" : _(m_custom_texture); + bool exists = (m_custom_texture == NONE) || boost::filesystem::exists(m_custom_texture); + lbl->SetForegroundColour(exists ? wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) : wxColor(*wxRED)); + + wxString tooltip_text = ""; + if (m_custom_texture != NONE) + { + if (!exists) + tooltip_text += _(L("Not found: ")); + + tooltip_text += _(m_custom_texture); + } + wxToolTip* tooltip = lbl->GetToolTip(); if ((tooltip == nullptr) || (tooltip->GetTip() != tooltip_text)) lbl->SetToolTip(tooltip_text); @@ -280,7 +293,18 @@ wxPanel* BedShapePanel::init_model_panel() wxStaticText* lbl = dynamic_cast(e.GetEventObject()); if (lbl != nullptr) { - wxString tooltip_text = (m_custom_model == NONE) ? "" : _(m_custom_model); + bool exists = (m_custom_model == NONE) || boost::filesystem::exists(m_custom_model); + lbl->SetForegroundColour(exists ? wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) : wxColor(*wxRED)); + + wxString tooltip_text = ""; + if (m_custom_model != NONE) + { + if (!exists) + tooltip_text += _(L("Not found: ")); + + tooltip_text += _(m_custom_model); + } + wxToolTip* tooltip = lbl->GetToolTip(); if ((tooltip == nullptr) || (tooltip->GetTip() != tooltip_text)) lbl->SetToolTip(tooltip_text); @@ -521,6 +545,8 @@ void BedShapePanel::load_texture() return; } + std::replace(file_name.begin(), file_name.end(), '\\', '/'); + wxBusyCursor wait; m_custom_texture = file_name; @@ -544,6 +570,8 @@ void BedShapePanel::load_model() return; } + std::replace(file_name.begin(), file_name.end(), '\\', '/'); + wxBusyCursor wait; m_custom_model = file_name; From 46601f7e1e45262cb967df0ecc73f6c54eeeaff3 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 12 Nov 2019 12:05:13 +0100 Subject: [PATCH 24/25] Added missing boost libraries into CMakeLists.txt --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b6d40a0346..633ab3f19a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -256,7 +256,7 @@ if(NOT WIN32) # boost::process was introduced first in version 1.64.0 set(MINIMUM_BOOST_VERSION "1.64.0") endif() -set(_boost_components "system;filesystem;thread;log;locale;regex") +set(_boost_components "system;filesystem;thread;log;locale;regex;chrono;atomic;date_time") find_package(Boost ${MINIMUM_BOOST_VERSION} REQUIRED COMPONENTS ${_boost_components}) add_library(boost_libs INTERFACE) From 01d2728060a9c3be76c3eed0fd414ea21c49c821 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 12 Nov 2019 12:29:31 +0100 Subject: [PATCH 25/25] Added missing include --- src/slic3r/GUI/BedShapeDialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index e83904a91d..96a0a59cd5 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -12,6 +12,7 @@ #include "boost/nowide/iostream.hpp" #include +#include #include