From 86fbb9a095e30ce0f6fc998cf1b812e716ac7871 Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 23 Jan 2019 10:08:42 +0100 Subject: [PATCH 01/80] 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 6a37e4369..7da18d9e3 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 7a99e84f7..df32ff179 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 8bf6c3689..b7f6b5b10 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 04319bb26..9972e210c 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 994f45e59..290914771 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/80] 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 df32ff179..d7e17698e 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/80] 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 7da18d9e3..bb4958320 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 d7e17698e..f9259eed9 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 b7f6b5b10..98717c41f 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 9972e210c..b8fe0ed72 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/80] 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 b8fe0ed72..7c6674556 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/80] 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 7c6674556..ecc1d54a0 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/80] 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 ecc1d54a0..c0b3bd907 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/80] 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 c0b3bd907..1e1e35b9e 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/80] 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 1e1e35b9e..651abffd9 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/80] 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 651abffd9..b7f0f879b 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 9c3cef940..171a6b034 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/80] 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 b7f0f879b..ae96f1f90 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 171a6b034..261c0039e 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/80] 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 ae96f1f90..341815e9b 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 261c0039e..37babb25e 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/80] 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 f9259eed9..c4ad93be5 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/80] 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 c4ad93be5..503e2c2c3 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 04f051ff61eefaaa42ecb4f08f3beec856d0cbf2 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 19 Sep 2019 14:58:04 +0200 Subject: [PATCH 14/80] Wipe tower now doesn't print sparse layers, it is instead lower than the object --- src/libslic3r/GCode.cpp | 46 +++++++++++++++++++++++++++++++---------- src/libslic3r/GCode.hpp | 3 ++- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 0ccc3ddf5..3ebf75c2e 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -274,7 +274,7 @@ static inline Point wipe_tower_point_to_object_point(GCode &gcodegen, const Vec2 return Point(scale_(wipe_tower_pt.x() - gcodegen.origin()(0)), scale_(wipe_tower_pt.y() - gcodegen.origin()(1))); } -std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id) const +std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z) const { if (new_extruder_id != -1 && new_extruder_id != tcr.new_tool) throw std::invalid_argument("Error: WipeTowerIntegration::append_tcr was asked to do a toolchange it didn't expect."); @@ -310,6 +310,12 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T gcode += gcodegen.unretract(); } + double current_z = gcodegen.writer().get_position().z(); + if (z == -1.) // in case no specific z was provided, print at current_z pos + z = current_z; + if (! is_approx(z, current_z)) + gcode += gcodegen.writer().travel_to_z(z, "Travel down to the last wipe tower layer."); + // Process the end filament gcode. std::string end_filament_gcode_str; @@ -376,16 +382,23 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T // A phony move to the end position at the wipe tower. gcodegen.writer().travel_to_xy(end_pos.cast()); gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos)); + if (! is_approx(z, current_z)) { + gcode += gcodegen.writer().retract(); + gcode += gcodegen.writer().travel_to_z(current_z, "Travel back up to the topmost object layer."); + gcode += gcodegen.writer().unretract(); + } - // Prepare a future wipe. - gcodegen.m_wipe.path.points.clear(); - if (new_extruder_id >= 0) { - // Start the wipe at the current position. - gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, end_pos)); - // Wipe end point: Wipe direction away from the closer tower edge to the further tower edge. - gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, - Vec2f((std::abs(m_left - end_pos.x()) < std::abs(m_right - end_pos.x())) ? m_right : m_left, - end_pos.y()))); + else { + // Prepare a future wipe. + gcodegen.m_wipe.path.points.clear(); + if (new_extruder_id >= 0) { + // Start the wipe at the current position. + gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, end_pos)); + // Wipe end point: Wipe direction away from the closer tower edge to the further tower edge. + gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, + Vec2f((std::abs(m_left - end_pos.x()) < std::abs(m_right - end_pos.x())) ? m_right : m_left, + end_pos.y()))); + } } // Let the planner know we are traveling between objects. @@ -511,7 +524,18 @@ std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id, if (m_layer_idx < (int)m_tool_changes.size()) { if (! (size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size())) throw std::runtime_error("Wipe tower generation failed, possibly due to empty first layer."); - gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][m_tool_change_idx++], extruder_id); + + + double wipe_tower_z = m_last_wipe_tower_print_z; + bool is_sparse_layer = (m_brim_done && m_tool_changes[m_layer_idx].size() == 1 && m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool); + + if (m_tool_change_idx == 0 && ! is_sparse_layer) + wipe_tower_z = m_last_wipe_tower_print_z + m_tool_changes[m_layer_idx].front().layer_height; + + if (! is_sparse_layer) { + gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][m_tool_change_idx++], extruder_id, wipe_tower_z); + m_last_wipe_tower_print_z = wipe_tower_z; + } } m_brim_done = true; } diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 72813810b..16fd20faa 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -110,7 +110,7 @@ public: private: WipeTowerIntegration& operator=(const WipeTowerIntegration&); - std::string append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id) const; + std::string append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z = -1.) const; // Postprocesses gcode: rotates and moves G1 extrusions and returns result std::string post_process_wipe_tower_moves(const WipeTower::ToolChangeResult& tcr, const Vec2f& translation, float angle) const; @@ -131,6 +131,7 @@ private: int m_tool_change_idx; bool m_brim_done; bool i_have_brim = false; + double m_last_wipe_tower_print_z = 0.f; }; class GCode { From abaebb489a33403e5d1fbca530691d2a29ce5252 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 19 Sep 2019 16:30:01 +0200 Subject: [PATCH 15/80] Added a config option to not print sparse layers on the wipe tower --- src/libslic3r/GCode.cpp | 22 +++++++++++++++------- src/libslic3r/Print.cpp | 1 + src/libslic3r/PrintConfig.cpp | 8 ++++++++ src/libslic3r/PrintConfig.hpp | 2 ++ src/slic3r/GUI/Preset.cpp | 2 +- src/slic3r/GUI/Tab.cpp | 1 + 6 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 3ebf75c2e..2210e40b2 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -313,8 +313,11 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T double current_z = gcodegen.writer().get_position().z(); if (z == -1.) // in case no specific z was provided, print at current_z pos z = current_z; - if (! is_approx(z, current_z)) + if (! is_approx(z, current_z)) { + gcode += gcodegen.writer().retract(); gcode += gcodegen.writer().travel_to_z(z, "Travel down to the last wipe tower layer."); + gcode += gcodegen.writer().unretract(); + } // Process the end filament gcode. @@ -526,13 +529,18 @@ std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id, throw std::runtime_error("Wipe tower generation failed, possibly due to empty first layer."); - double wipe_tower_z = m_last_wipe_tower_print_z; - bool is_sparse_layer = (m_brim_done && m_tool_changes[m_layer_idx].size() == 1 && m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool); + // Calculate where the wipe tower layer will be printed. -1 means that print z will not change, + // resulting in a wipe tower with sparse layers. + double wipe_tower_z = -1; + bool ignore_sparse = false; + if (gcodegen.config().wipe_tower_no_sparse_layers.value) { + wipe_tower_z = m_last_wipe_tower_print_z; + ignore_sparse = (m_brim_done && m_tool_changes[m_layer_idx].size() == 1 && m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool); + if (m_tool_change_idx == 0 && ! ignore_sparse) + wipe_tower_z = m_last_wipe_tower_print_z + m_tool_changes[m_layer_idx].front().layer_height; + } - if (m_tool_change_idx == 0 && ! is_sparse_layer) - wipe_tower_z = m_last_wipe_tower_print_z + m_tool_changes[m_layer_idx].front().layer_height; - - if (! is_sparse_layer) { + if (! ignore_sparse) { gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][m_tool_change_idx++], extruder_id, wipe_tower_z); m_last_wipe_tower_print_z = wipe_tower_z; } diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 4d8482743..8a5282b4b 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -143,6 +143,7 @@ bool Print::invalidate_state_by_config_options(const std::vectormode = comAdvanced; def->set_default_value(new ConfigOptionBool(true)); + def = this->add("wipe_tower_no_sparse_layers", coBool); + def->label = L("No sparse layers"); + def->tooltip = L("If enabled, the wipe tower will not be printed on layers with no toolchanges. " + "On layers with a toolchange, extruder will travel downward to print the wipe tower. " + "User is responsible for ensuring there is no collision with the print."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("support_material", coBool); def->label = L("Generate support material"); def->category = L("Support material"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 6a19edf84..20ab60e9a 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -648,6 +648,7 @@ public: ConfigOptionStrings start_filament_gcode; ConfigOptionBool single_extruder_multi_material; ConfigOptionBool single_extruder_multi_material_priming; + ConfigOptionBool wipe_tower_no_sparse_layers; ConfigOptionString toolchange_gcode; ConfigOptionFloat travel_speed; ConfigOptionBool use_firmware_retraction; @@ -718,6 +719,7 @@ protected: OPT_PTR(retract_speed); OPT_PTR(single_extruder_multi_material); OPT_PTR(single_extruder_multi_material_priming); + OPT_PTR(wipe_tower_no_sparse_layers); OPT_PTR(start_gcode); OPT_PTR(start_filament_gcode); OPT_PTR(toolchange_gcode); diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index d2503d349..853a803b7 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -385,7 +385,7 @@ const std::vector& Preset::print_options() "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "clip_multipart_objects", "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "single_extruder_multi_material_priming", - "compatible_printers", "compatible_printers_condition", "inherits" + "wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits" }; return s_opts; } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index c87626a48..5ecfb9a77 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1170,6 +1170,7 @@ void TabPrint::build() optgroup->append_single_option_line("wipe_tower_width"); optgroup->append_single_option_line("wipe_tower_rotation_angle"); optgroup->append_single_option_line("wipe_tower_bridging"); + optgroup->append_single_option_line("wipe_tower_no_sparse_layers"); optgroup->append_single_option_line("single_extruder_multi_material_priming"); optgroup = page->new_optgroup(_(L("Advanced"))); From 82bc243281e0c4e46e20a9bafecfa8d72c20936e Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 26 Sep 2019 16:33:55 +0200 Subject: [PATCH 16/80] 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 43999d365..a6989ca6e 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 1ce00f269..a862a8fe3 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 6a19edf84..e92ddabac 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 46d039c1f..604899652 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 97c292703..1042499b2 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 26dcb5ac3..dddad9d6c 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 d2503d349..f6164bc45 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 c87626a48..cc0800bac 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 17/80] 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 a862a8fe3..f8f17d1c3 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 cc0800bac..25604080e 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 b5e3899267b3ed2e2432048f804013bf21a2e54b Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 1 Oct 2019 11:41:37 +0200 Subject: [PATCH 18/80] Wipe tower: Sparse layers are not included in filament consumption in case that the 'no sparse layers' option is set --- src/libslic3r/GCode/WipeTower.cpp | 13 +++++++++---- src/libslic3r/GCode/WipeTower.hpp | 1 + src/libslic3r/Print.cpp | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index b35761b5f..fff03786f 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -471,6 +471,7 @@ WipeTower::WipeTower(const PrintConfig& config, const std::vectortoolchanges_depth() > WT_EPSILON; box_coordinates box = fill_box; for (int i=0;i<2;++i) { - if (m_layer_info->toolchanges_depth() < WT_EPSILON) { // there were no toolchanges on this layer + if (! toolchanges_on_layer) { if (i==0) box.expand(m_perimeter_width); else box.expand(-m_perimeter_width); } @@ -1192,9 +1194,12 @@ WipeTower::ToolChangeResult WipeTower::finish_layer() m_depth_traversed = m_wipe_tower_depth-m_perimeter_width; - // Ask our writer about how much material was consumed: - if (m_current_tool < m_used_filament_length.size()) - m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length(); + + // Ask our writer about how much material was consumed. + // Skip this in case the layer is sparse and config option to not print sparse layers is enabled. + if (! m_no_sparse_layers || toolchanges_on_layer) + if (m_current_tool < m_used_filament_length.size()) + m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length(); ToolChangeResult result; result.priming = false; diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index 5477aa609..ff3ec46e5 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -218,6 +218,7 @@ private: float m_parking_pos_retraction = 0.f; float m_extra_loading_move = 0.f; float m_bridging = 0.f; + bool m_no_sparse_layers = false; bool m_set_extruder_trimpot = false; bool m_adhesion = true; GCodeFlavor m_gcode_flavor; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 8a5282b4b..fcda80a67 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -143,7 +143,6 @@ bool Print::invalidate_state_by_config_options(const std::vector Date: Tue, 22 Oct 2019 16:02:31 +0200 Subject: [PATCH 19/80] Added tech ENABLE_THUMBNAIL_GENERATOR -> 1st installment of generation of thumbnail from plater (WIP) --- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/GCode.cpp | 5 ++ src/libslic3r/GCode/ThumbnailData.cpp | 31 +++++++++ src/libslic3r/GCode/ThumbnailData.hpp | 25 +++++++ src/libslic3r/Technologies.hpp | 10 +++ src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/GLCanvas3D.hpp | 7 ++ src/slic3r/GUI/Plater.cpp | 15 +++++ src/slic3r/GUI/ThumbnailGenerator.cpp | 97 +++++++++++++++++++++++++++ src/slic3r/GUI/ThumbnailGenerator.hpp | 37 ++++++++++ 10 files changed, 231 insertions(+) create mode 100644 src/libslic3r/GCode/ThumbnailData.cpp create mode 100644 src/libslic3r/GCode/ThumbnailData.hpp create mode 100644 src/slic3r/GUI/ThumbnailGenerator.cpp create mode 100644 src/slic3r/GUI/ThumbnailGenerator.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index cbaa24e9c..f7881e5ac 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -71,6 +71,8 @@ add_library(libslic3r STATIC Format/STL.hpp GCode/Analyzer.cpp GCode/Analyzer.hpp + GCode/ThumbnailData.cpp + GCode/ThumbnailData.hpp GCode/CoolingBuffer.cpp GCode/CoolingBuffer.hpp GCode/PostProcessor.cpp diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 3a72657c3..fa71ac796 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -945,6 +945,11 @@ void GCode::_do_export(Print &print, FILE *file) } print.throw_if_canceled(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + // Write some terse information on the slicing parameters. const PrintObject *first_object = print.objects().front(); const double layer_height = first_object->config().layer_height.value; diff --git a/src/libslic3r/GCode/ThumbnailData.cpp b/src/libslic3r/GCode/ThumbnailData.cpp new file mode 100644 index 000000000..17ccbdeb6 --- /dev/null +++ b/src/libslic3r/GCode/ThumbnailData.cpp @@ -0,0 +1,31 @@ +#include "libslic3r/libslic3r.h" +#include "ThumbnailData.hpp" + +#if ENABLE_THUMBNAIL_GENERATOR + +namespace Slic3r { + +void ThumbnailData::set(unsigned int w, unsigned int h) +{ + if (!pixels.empty()) + reset(); + + if ((w == 0) || (h == 0)) + return; + + width = w; + height = h; + // defaults to white texture + pixels = std::vector(width * height * 4, 255); +} + +void ThumbnailData::reset() +{ + width = 0; + height = 0; + pixels.clear(); +} + +} // namespace Slic3r + +#endif // ENABLE_THUMBNAIL_GENERATOR \ No newline at end of file diff --git a/src/libslic3r/GCode/ThumbnailData.hpp b/src/libslic3r/GCode/ThumbnailData.hpp new file mode 100644 index 000000000..193068ebe --- /dev/null +++ b/src/libslic3r/GCode/ThumbnailData.hpp @@ -0,0 +1,25 @@ +#ifndef slic3r_ThumbnailData_hpp_ +#define slic3r_ThumbnailData_hpp_ + +#if ENABLE_THUMBNAIL_GENERATOR + +#include + +namespace Slic3r { + +struct ThumbnailData +{ + unsigned int width; + unsigned int height; + std::vector pixels; + + ThumbnailData() { reset(); } + void set(unsigned int w, unsigned int h); + void reset(); +}; + +} // namespace Slic3r + +#endif // ENABLE_THUMBNAIL_GENERATOR + +#endif // slic3r_ThumbnailData_hpp_ \ No newline at end of file diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 51d092094..40e989bb2 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -32,4 +32,14 @@ #define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1) +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +//==================== +// 2.2.0.alpha1 techs +//==================== +#define ENABLE_2_2_0_ALPHA1 1 + +// Enable thumbnail generator +#define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_2_0_ALPHA1) +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + #endif // _technologies_h_ diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 17b76e629..0b2dd6702 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -136,6 +136,8 @@ set(SLIC3R_GUI_SOURCES GUI/ProgressStatusBar.cpp GUI/PrintHostDialogs.cpp GUI/PrintHostDialogs.hpp + GUI/ThumbnailGenerator.cpp + GUI/ThumbnailGenerator.hpp Utils/Http.cpp Utils/Http.hpp Utils/FixModelByWin10.cpp diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 2c2676ae7..2e7fc2d77 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -446,6 +446,13 @@ public: wxGLCanvas* get_wxglcanvas() { return m_canvas; } const wxGLCanvas* get_wxglcanvas() const { return m_canvas; } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + const GLVolumeCollection& get_volumes() const { return m_volumes; } +// GLVolumeCollection& get_volumes() { return m_volumes; } +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + bool init(); void post_event(wxEvent &&event); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index cca164ca3..4c44cce75 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -62,6 +62,11 @@ #include "GUI_Preview.hpp" #include "3DBed.hpp" #include "Camera.hpp" +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +#include "ThumbnailGenerator.hpp" +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #include "Tab.hpp" #include "PresetBundle.hpp" #include "BackgroundSlicingProcess.hpp" @@ -1373,6 +1378,11 @@ struct Plater::priv View3D* view3D; GLToolbar view_toolbar; Preview *preview; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + ThumbnailGenerator thumbnail_generator; +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ BackgroundSlicingProcess background_process; bool suppressed_backround_processing_update { false }; @@ -3060,6 +3070,11 @@ void Plater::priv::export_gcode(fs::path output_path, PrintHostJob upload_job) return; if (! output_path.empty()) { +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + thumbnail_generator.render_to_png_file(*view3D->get_canvas3d(), "C:/prusa/test/test.png", 256, 256, false); +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ background_process.schedule_export(output_path.string()); } else { background_process.schedule_upload(std::move(upload_job)); diff --git a/src/slic3r/GUI/ThumbnailGenerator.cpp b/src/slic3r/GUI/ThumbnailGenerator.cpp new file mode 100644 index 000000000..db823cc0b --- /dev/null +++ b/src/slic3r/GUI/ThumbnailGenerator.cpp @@ -0,0 +1,97 @@ +#include "libslic3r/libslic3r.h" +#include "ThumbnailGenerator.hpp" + +#if ENABLE_THUMBNAIL_GENERATOR + +#include "GLCanvas3D.hpp" +#include "3DScene.hpp" + +#include + +namespace Slic3r { +namespace GUI { + +void ThumbnailGenerator::reset() +{ + m_data.reset(); +} + +bool ThumbnailGenerator::render_to_png_file(const GLCanvas3D& canvas, const std::string& filename, unsigned int w, unsigned int h, bool printable_only) +{ + m_data.set(w, h); + render(canvas, printable_only); + + wxImage image(m_data.width, m_data.height); + image.InitAlpha(); + + for (unsigned int r = 0; r < m_data.height; ++r) + { + unsigned int rr = (m_data.height - 1 - r) * m_data.width; + for (unsigned int c = 0; c < m_data.width; ++c) + { + unsigned char* px = m_data.pixels.data() + 4 * (rr + c); +// unsigned char* px = m_data.pixels.data() + 4 * (r * m_data.width + c); + image.SetRGB((int)c, (int)r, px[0], px[1], px[2]); + image.SetAlpha((int)c, (int)r, px[3]); + } + } + + image.SaveFile(filename, wxBITMAP_TYPE_PNG); + + return true; +} + +void ThumbnailGenerator::render(const GLCanvas3D& canvas, bool printable_only) +{ + const GLVolumeCollection& volumes = canvas.get_volumes(); + + std::vector visible_volumes; + + for (const GLVolume* vol : volumes.volumes) + { + if (!printable_only || vol->printable) + visible_volumes.push_back(vol); + } + + if (visible_volumes.empty()) + return; + + BoundingBoxf3 box; + for (const GLVolume* vol : visible_volumes) + { + box.merge(vol->transformed_bounding_box()); + } + + Camera camera; + camera.zoom_to_box(box, m_data.width, m_data.height); + camera.apply_viewport(0, 0, m_data.width, m_data.height); + camera.apply_view_matrix(); + camera.apply_projection(box); + + glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); + render_objects(visible_volumes); + glsafe(::glReadPixels(0, 0, m_data.width, m_data.height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)m_data.pixels.data())); +} + +void ThumbnailGenerator::render_objects(const std::vector& volumes) const +{ + static const float orange[] = { 0.99f, 0.49f, 0.26f }; + static const float gray[] = { 0.64f, 0.64f, 0.64f }; + + glsafe(::glEnable(GL_LIGHTING)); + glsafe(::glEnable(GL_DEPTH_TEST)); + + for (const GLVolume* vol : volumes) + { + glsafe(::glColor3fv(vol->printable ? orange : gray)); + vol->render(); + } + + glsafe(::glDisable(GL_DEPTH_TEST)); + glsafe(::glDisable(GL_LIGHTING)); +} + +} // namespace GUI +} // namespace Slic3r + +#endif // ENABLE_THUMBNAIL_GENERATOR diff --git a/src/slic3r/GUI/ThumbnailGenerator.hpp b/src/slic3r/GUI/ThumbnailGenerator.hpp new file mode 100644 index 000000000..1c3aef76c --- /dev/null +++ b/src/slic3r/GUI/ThumbnailGenerator.hpp @@ -0,0 +1,37 @@ +#ifndef slic3r_GUI_ThumbnailGenerator_hpp_ +#define slic3r_GUI_ThumbnailGenerator_hpp_ + +#if ENABLE_THUMBNAIL_GENERATOR + +#include "../libslic3r/GCode/ThumbnailData.hpp" + +#include + +namespace Slic3r { + class GLVolume; +namespace GUI { + class GLCanvas3D; + + class ThumbnailGenerator + { + ThumbnailData m_data; + + public: + ThumbnailGenerator() { reset(); } + + void reset(); + + bool render_to_png_file(const GLCanvas3D& canvas, const std::string& filename, unsigned int w, unsigned int h, bool printable_only); + + private: + void render(const GLCanvas3D& canvas, bool printable_only); + void render_objects(const std::vector& volumes) const; + }; + +} // namespace GUI +} // namespace Slic3r + +#endif // ENABLE_THUMBNAIL_GENERATOR + +#endif // slic3r_GUI_ThumbnailGenerator_hpp_ + From 4d1153c866bef9af7525ea4e1e7616b8e4acc115 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 23 Oct 2019 13:31:24 +0200 Subject: [PATCH 20/80] ENABLE_THUMBNAIL_GENERATOR -> WIP: Refactoring and preparation for adding thumbnails to exported gcode and 3mf files --- src/libslic3r/Format/3mf.cpp | 103 ++++++++++++++++++++ src/libslic3r/Format/3mf.hpp | 13 +++ src/libslic3r/GCode.cpp | 49 +++++++++- src/libslic3r/GCode.hpp | 21 ++++ src/libslic3r/GCode/ThumbnailData.cpp | 19 ++-- src/libslic3r/GCode/ThumbnailData.hpp | 2 + src/libslic3r/Print.cpp | 16 +++ src/libslic3r/Print.hpp | 13 +++ src/slic3r/GUI/BackgroundSlicingProcess.cpp | 12 ++- src/slic3r/GUI/BackgroundSlicingProcess.hpp | 17 ++++ src/slic3r/GUI/GLCanvas3D.cpp | 6 ++ src/slic3r/GUI/Plater.cpp | 53 +++++++++- src/slic3r/GUI/Plater.hpp | 6 ++ src/slic3r/GUI/ThumbnailGenerator.cpp | 45 +++++---- src/slic3r/GUI/ThumbnailGenerator.hpp | 17 ++-- 15 files changed, 346 insertions(+), 46 deletions(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 47a8e5280..a981cca61 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -3,6 +3,11 @@ #include "../Utils.hpp" #include "../GCode.hpp" #include "../Geometry.hpp" +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +#include "../GCode/ThumbnailData.hpp" +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #include "../I18N.hpp" @@ -40,6 +45,11 @@ const std::string MODEL_EXTENSION = ".model"; const std::string MODEL_FILE = "3D/3dmodel.model"; // << this is the only format of the string which works with CURA const std::string CONTENT_TYPES_FILE = "[Content_Types].xml"; const std::string RELATIONSHIPS_FILE = "_rels/.rels"; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +const std::string THUMBNAIL_FILE = "Metadata/thumbnail.png"; +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config"; const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config"; const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt"; @@ -1806,11 +1816,32 @@ namespace Slic3r { typedef std::map IdToObjectDataMap; public: +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail = nullptr); +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ private: +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail); +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool _add_content_types_file_to_archive(mz_zip_archive& archive); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + bool _add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail); +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool _add_relationships_file_to_archive(mz_zip_archive& archive); bool _add_model_file_to_archive(mz_zip_archive& archive, const Model& model, IdToObjectDataMap &objects_data); bool _add_object_to_model_stream(std::stringstream& stream, unsigned int& object_id, ModelObject& object, BuildItemsList& build_items, VolumeToOffsetsMap& volumes_offsets); @@ -1823,13 +1854,33 @@ namespace Slic3r { bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data); }; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail) + { + clear_errors(); + return _save_model_to_file(filename, model, config, thumbnail); + } +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config) { clear_errors(); return _save_model_to_file(filename, model, config); } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail) +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config) +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ { mz_zip_archive archive; mz_zip_zero_struct(&archive); @@ -1848,6 +1899,21 @@ namespace Slic3r { return false; } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + if ((thumbnail != nullptr) && thumbnail->is_valid()) + { + // Adds the file Metadata/thumbnail.png. + if (!_add_thumbnail_file_to_archive(archive, *thumbnail)) + { + close_zip_writer(&archive); + boost::filesystem::remove(filename); + return false; + } + } +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + // Adds relationships file ("_rels/.rels"). // The content of this file is the same for each PrusaSlicer 3mf. // The relationshis file contains a reference to the geometry file "3D/3dmodel.model", the name was chosen to be compatible with CURA. @@ -1941,6 +2007,11 @@ namespace Slic3r { stream << "\n"; stream << " \n"; stream << " \n"; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + stream << " \n"; +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ stream << ""; std::string out = stream.str(); @@ -1954,12 +2025,28 @@ namespace Slic3r { return true; } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + bool _3MF_Exporter::_add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail) + { + // TODO -> add Metadata/thumbnail.png file containing thumbnail_data + + return true; + } +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + bool _3MF_Exporter::_add_relationships_file_to_archive(mz_zip_archive& archive) { std::stringstream stream; stream << "\n"; stream << "\n"; stream << " \n"; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + stream << " \n"; +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ stream << ""; std::string out = stream.str(); @@ -2453,13 +2540,29 @@ namespace Slic3r { return res; } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail) +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config) +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ { if ((path == nullptr) || (model == nullptr)) return false; _3MF_Exporter exporter; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + bool res = exporter.save_model_to_file(path, *model, config, thumbnail); +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool res = exporter.save_model_to_file(path, *model, config); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ if (!res) exporter.log_errors(); diff --git a/src/libslic3r/Format/3mf.hpp b/src/libslic3r/Format/3mf.hpp index f387192ab..0ce6eb742 100644 --- a/src/libslic3r/Format/3mf.hpp +++ b/src/libslic3r/Format/3mf.hpp @@ -22,13 +22,26 @@ namespace Slic3r { class Model; class DynamicPrintConfig; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + struct ThumbnailData; +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Load the content of a 3mf file into the given model and preset bundle. extern bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool check_version); // Save the given model and the config data contained in the given Print into a 3mf file. // The model could be modified during the export process if meshes are not repaired or have no shared vertices +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail = nullptr); +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ }; // namespace Slic3r diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 2d14155a3..13b417efa 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -6,6 +6,11 @@ #include "Geometry.hpp" #include "GCode/PrintExtents.hpp" #include "GCode/WipeTower.hpp" +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +#include "GCode/ThumbnailData.hpp" +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #include "ShortestPath.hpp" #include "Utils.hpp" @@ -652,7 +657,15 @@ std::vector>> GCode::collec return layers_to_print; } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, const ThumbnailData* thumbnail_data) +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_data) +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ { PROFILE_CLEAR(); @@ -678,7 +691,15 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ try { m_placeholder_parser_failed_templates.clear(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + this->_do_export(*print, file, thumbnail_data); +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ this->_do_export(*print, file); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ fflush(file); if (ferror(file)) { fclose(file); @@ -742,7 +763,15 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ PROFILE_OUTPUT(debug_out_path("gcode-export-profile.txt").c_str()); } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +void GCode::_do_export(Print& print, FILE* file, const ThumbnailData* thumbnail_data) +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void GCode::_do_export(Print &print, FILE *file) +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ { PROFILE_FUNC(); @@ -934,6 +963,21 @@ void GCode::_do_export(Print &print, FILE *file) // Write information on the generator. _write_format(file, "; %s\n\n", Slic3r::header_slic3r_generated().c_str()); + +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + // Write thumbnail + if ((thumbnail_data != nullptr) && thumbnail_data->is_valid()) + { + _write(file, "\n;\n; thumbnail begin\n"); + + // TODO -> export content of thumbnail_data.pixels + + _write(file, "; thumbnail end\n;\n\n"); + } +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + // Write notes (content of the Print Settings tab -> Notes) { std::list lines; @@ -949,11 +993,6 @@ void GCode::_do_export(Print &print, FILE *file) } print.throw_if_canceled(); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -#if ENABLE_THUMBNAIL_GENERATOR -#endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - // Write some terse information on the slicing parameters. const PrintObject *first_object = print.objects().front(); const double layer_height = first_object->config().layer_height.value; diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 45ff7eda6..4c5b92bf1 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -30,6 +30,11 @@ namespace Slic3r { // Forward declarations. class GCode; class GCodePreviewData; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +struct ThumbnailData; +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ class AvoidCrossingPerimeters { public: @@ -162,7 +167,15 @@ public: // throws std::runtime_exception on error, // throws CanceledException through print->throw_if_canceled(). +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, const ThumbnailData* thumbnail_data = nullptr); +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests. const Vec2d& origin() const { return m_origin; } @@ -190,7 +203,15 @@ public: static void append_full_config(const Print& print, std::string& str); protected: +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + void _do_export(Print& print, FILE* file, const ThumbnailData* thumbnail_data); +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void _do_export(Print &print, FILE *file); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif //ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Object and support extrusions of the same PrintObject at the same print_z. struct LayerToPrint diff --git a/src/libslic3r/GCode/ThumbnailData.cpp b/src/libslic3r/GCode/ThumbnailData.cpp index 17ccbdeb6..80165916b 100644 --- a/src/libslic3r/GCode/ThumbnailData.cpp +++ b/src/libslic3r/GCode/ThumbnailData.cpp @@ -7,16 +7,16 @@ namespace Slic3r { void ThumbnailData::set(unsigned int w, unsigned int h) { - if (!pixels.empty()) - reset(); - if ((w == 0) || (h == 0)) return; - width = w; - height = h; - // defaults to white texture - pixels = std::vector(width * height * 4, 255); + if ((width != w) || (height != h)) + { + width = w; + height = h; + // defaults to white texture + pixels = std::vector(width * height * 4, 255); + } } void ThumbnailData::reset() @@ -26,6 +26,11 @@ void ThumbnailData::reset() pixels.clear(); } +bool ThumbnailData::is_valid() const +{ + return (width != 0) && (height != 0) && ((unsigned int)pixels.size() == 4 * width * height); +} + } // namespace Slic3r #endif // ENABLE_THUMBNAIL_GENERATOR \ No newline at end of file diff --git a/src/libslic3r/GCode/ThumbnailData.hpp b/src/libslic3r/GCode/ThumbnailData.hpp index 193068ebe..9823ffd31 100644 --- a/src/libslic3r/GCode/ThumbnailData.hpp +++ b/src/libslic3r/GCode/ThumbnailData.hpp @@ -16,6 +16,8 @@ struct ThumbnailData ThumbnailData() { reset(); } void set(unsigned int w, unsigned int h); void reset(); + + bool is_valid() const; }; } // namespace Slic3r diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 88645df15..742a2a960 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1536,7 +1536,15 @@ void Print::process() // The export_gcode may die for various reasons (fails to process output_filename_format, // write error into the G-code, cannot execute post-processing scripts). // It is up to the caller to show an error message. +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, const ThumbnailData* thumbnail_data) +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ std::string Print::export_gcode(const std::string &path_template, GCodePreviewData *preview_data) +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ { // output everything to a G-code file // The following call may die if the output_filename_format template substitution fails. @@ -1553,7 +1561,15 @@ std::string Print::export_gcode(const std::string &path_template, GCodePreviewDa // The following line may die for multiple reasons. GCode gcode; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + gcode.do_export(this, path.c_str(), preview_data, thumbnail_data); +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ gcode.do_export(this, path.c_str(), preview_data); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ return path.c_str(); } diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 6d94a515f..8dc54ee1d 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -19,6 +19,11 @@ class PrintObject; class ModelObject; class GCode; class GCodePreviewData; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +struct ThumbnailData; +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Print step IDs for keeping track of the print state. enum PrintStep { @@ -305,7 +310,15 @@ public: void process() override; // Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file. // If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r). +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, const ThumbnailData* thumbnail_data = nullptr); +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ std::string export_gcode(const std::string &path_template, GCodePreviewData *preview_data); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // methods for handling state bool is_step_done(PrintStep step) const { return Inherited::is_step_done(step); } diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index a1db6884e..9d53d60b2 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -82,8 +82,16 @@ void BackgroundSlicingProcess::process_fff() assert(m_print == m_fff_print); m_print->process(); wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_slicing_completed_id)); - m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data); - if (this->set_step_started(bspsGCodeFinalize)) { +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data, m_thumbnail_data); +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + if (this->set_step_started(bspsGCodeFinalize)) { if (! m_export_path.empty()) { //FIXME localize the messages // Perform the final post-processing of the export path by applying the print statistics over the file name. diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index cf5edd55f..af20554df 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -17,6 +17,11 @@ namespace Slic3r { class DynamicPrintConfig; class GCodePreviewData; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +struct ThumbnailData; +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ class Model; class SLAPrint; @@ -49,6 +54,12 @@ public: void set_fff_print(Print *print) { m_fff_print = print; } void set_sla_print(SLAPrint *print) { m_sla_print = print; } void set_gcode_preview_data(GCodePreviewData *gpd) { m_gcode_preview_data = gpd; } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + void set_thumbnail_data(const ThumbnailData* data) { m_thumbnail_data = data; } +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + // The following wxCommandEvent will be sent to the UI thread / Platter window, when the slicing is finished // and the background processing will transition into G-code export. // The wxCommandEvent is sent to the UI thread asynchronously without waiting for the event to be processed. @@ -151,6 +162,12 @@ private: SLAPrint *m_sla_print = nullptr; // Data structure, to which the G-code export writes its annotations. GCodePreviewData *m_gcode_preview_data = nullptr; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + // Data structure, used to write thumbnail into gcode. + const ThumbnailData *m_thumbnail_data = nullptr; +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Temporary G-code, there is one defined for the BackgroundSlicingProcess, differentiated from the other processes by a process ID. std::string m_temp_output_path; // Output path provided by the user. The output path may be set even if the slicing is running, diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c55d64b47..4e72d1526 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2108,6 +2108,12 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re manip->set_dirty(); } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +//#if ENABLE_THUMBNAIL_GENERATOR +// wxGetApp().plater()->generate_thumbnail(256, 256, true); +//#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + // and force this canvas to be redrawn. m_dirty = true; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 4c44cce75..66fb72bbc 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1926,6 +1926,12 @@ struct Plater::priv bool can_mirror() const; bool can_reload_from_disk() const; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + void generate_thumbnail(unsigned int w, unsigned int h, bool printable_only); +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + void msw_rescale_object_menu(); // returns the path to project file with the given extension (none if extension == wxEmptyString) @@ -1993,6 +1999,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) background_process.set_fff_print(&fff_print); background_process.set_sla_print(&sla_print); background_process.set_gcode_preview_data(&gcode_preview_data); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + background_process.set_thumbnail_data(&thumbnail_generator.get_data()); +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ background_process.set_slicing_completed_event(EVT_SLICING_COMPLETED); background_process.set_finished_event(EVT_PROCESS_COMPLETED); // Default printer technology for default config. @@ -3037,6 +3048,16 @@ bool Plater::priv::restart_background_process(unsigned int state) ( ((state & UPDATE_BACKGROUND_PROCESS_FORCE_RESTART) != 0 && ! this->background_process.finished()) || (state & UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT) != 0 || (state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 ) ) { +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + if ((state & UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT) == 0) + { + // force update of thumbnail data, so that they can be inserted into the exported gcode + thumbnail_generator.generate(view3D->get_canvas3d()->get_volumes().volumes, 256, 256, true); + thumbnail_generator.save_to_png_file("C:/prusa/test/test.png"); + } +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // The print is valid and it can be started. if (this->background_process.start()) { this->statusbar()->set_cancel_callback([this]() { @@ -3070,11 +3091,6 @@ void Plater::priv::export_gcode(fs::path output_path, PrintHostJob upload_job) return; if (! output_path.empty()) { -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -#if ENABLE_THUMBNAIL_GENERATOR - thumbnail_generator.render_to_png_file(*view3D->get_canvas3d(), "C:/prusa/test/test.png", 256, 256, false); -#endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ background_process.schedule_export(output_path.string()); } else { background_process.schedule_upload(std::move(upload_job)); @@ -3604,6 +3620,15 @@ bool Plater::priv::init_object_menu() return true; } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +void Plater::priv::generate_thumbnail(unsigned int w, unsigned int h, bool printable_only) +{ + thumbnail_generator.generate(view3D->get_canvas3d()->get_volumes().volumes, w, h, printable_only); +} +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + void Plater::priv::msw_rescale_object_menu() { for (MenuWithSeparators* menu : { &object_menu, &sla_object_menu, &part_menu, &default_menu }) @@ -4642,7 +4667,16 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure(); const std::string path_u8 = into_u8(path); wxBusyCursor wait; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + p->generate_thumbnail(128, 128, false); + if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, &p->thumbnail_generator.get_data())) { +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) { +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Success p->statusbar()->set_status_text(wxString::Format(_(L("3MF file exported to %s")), path)); p->set_project_filename(path); @@ -5139,6 +5173,15 @@ void Plater::paste_from_clipboard() p->view3D->get_canvas3d()->get_selection().paste_from_clipboard(); } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +void Plater::generate_thumbnail(unsigned int w, unsigned int h, bool printable_only) +{ + p->generate_thumbnail(w, h, printable_only); +} +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + void Plater::msw_rescale() { p->preview->msw_rescale(); diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 00ceb89bc..b14cff65a 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -240,6 +240,12 @@ public: void copy_selection_to_clipboard(); void paste_from_clipboard(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + void generate_thumbnail(unsigned int w, unsigned int h, bool printable_only); +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + bool can_delete() const; bool can_delete_all() const; bool can_increase_instances() const; diff --git a/src/slic3r/GUI/ThumbnailGenerator.cpp b/src/slic3r/GUI/ThumbnailGenerator.cpp index db823cc0b..a50c5541c 100644 --- a/src/slic3r/GUI/ThumbnailGenerator.cpp +++ b/src/slic3r/GUI/ThumbnailGenerator.cpp @@ -3,9 +3,12 @@ #if ENABLE_THUMBNAIL_GENERATOR -#include "GLCanvas3D.hpp" +#include "Camera.hpp" #include "3DScene.hpp" +#include "GUI.hpp" +#include +#include #include namespace Slic3r { @@ -16,10 +19,18 @@ void ThumbnailGenerator::reset() m_data.reset(); } -bool ThumbnailGenerator::render_to_png_file(const GLCanvas3D& canvas, const std::string& filename, unsigned int w, unsigned int h, bool printable_only) +void ThumbnailGenerator::generate(const GLVolumePtrs& volumes, unsigned int w, unsigned int h, bool printable_only) { + std::cout << "Generated thumbnail " << w << "x" << h << std::endl; + m_data.set(w, h); - render(canvas, printable_only); + render_and_store(volumes, printable_only); +} + +bool ThumbnailGenerator::save_to_png_file(const std::string& filename) +{ + if (!m_data.is_valid()) + return false; wxImage image(m_data.width, m_data.height); image.InitAlpha(); @@ -30,24 +41,26 @@ bool ThumbnailGenerator::render_to_png_file(const GLCanvas3D& canvas, const std: for (unsigned int c = 0; c < m_data.width; ++c) { unsigned char* px = m_data.pixels.data() + 4 * (rr + c); -// unsigned char* px = m_data.pixels.data() + 4 * (r * m_data.width + c); image.SetRGB((int)c, (int)r, px[0], px[1], px[2]); image.SetAlpha((int)c, (int)r, px[3]); } } - image.SaveFile(filename, wxBITMAP_TYPE_PNG); + std::string path = filename; + if (!boost::iends_with(path, ".png")) + path = boost::filesystem::path(path).replace_extension(".png").string(); - return true; + return image.SaveFile(from_u8(path), wxBITMAP_TYPE_PNG); } -void ThumbnailGenerator::render(const GLCanvas3D& canvas, bool printable_only) +void ThumbnailGenerator::render_and_store(const GLVolumePtrs& volumes, bool printable_only) { - const GLVolumeCollection& volumes = canvas.get_volumes(); + static const float orange[] = { 0.99f, 0.49f, 0.26f }; + static const float gray[] = { 0.64f, 0.64f, 0.64f }; - std::vector visible_volumes; + GLVolumeConstPtrs visible_volumes; - for (const GLVolume* vol : volumes.volumes) + for (const GLVolume* vol : volumes) { if (!printable_only || vol->printable) visible_volumes.push_back(vol); @@ -69,19 +82,10 @@ void ThumbnailGenerator::render(const GLCanvas3D& canvas, bool printable_only) camera.apply_projection(box); glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); - render_objects(visible_volumes); - glsafe(::glReadPixels(0, 0, m_data.width, m_data.height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)m_data.pixels.data())); -} - -void ThumbnailGenerator::render_objects(const std::vector& volumes) const -{ - static const float orange[] = { 0.99f, 0.49f, 0.26f }; - static const float gray[] = { 0.64f, 0.64f, 0.64f }; - glsafe(::glEnable(GL_LIGHTING)); glsafe(::glEnable(GL_DEPTH_TEST)); - for (const GLVolume* vol : volumes) + for (const GLVolume* vol : visible_volumes) { glsafe(::glColor3fv(vol->printable ? orange : gray)); vol->render(); @@ -89,6 +93,7 @@ void ThumbnailGenerator::render_objects(const std::vector& volu glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_LIGHTING)); + glsafe(::glReadPixels(0, 0, m_data.width, m_data.height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)m_data.pixels.data())); } } // namespace GUI diff --git a/src/slic3r/GUI/ThumbnailGenerator.hpp b/src/slic3r/GUI/ThumbnailGenerator.hpp index 1c3aef76c..e632106cd 100644 --- a/src/slic3r/GUI/ThumbnailGenerator.hpp +++ b/src/slic3r/GUI/ThumbnailGenerator.hpp @@ -5,15 +5,15 @@ #include "../libslic3r/GCode/ThumbnailData.hpp" -#include - namespace Slic3r { class GLVolume; -namespace GUI { - class GLCanvas3D; + typedef std::vector GLVolumePtrs; + namespace GUI { class ThumbnailGenerator { + typedef std::vector GLVolumeConstPtrs; + ThumbnailData m_data; public: @@ -21,11 +21,14 @@ namespace GUI { void reset(); - bool render_to_png_file(const GLCanvas3D& canvas, const std::string& filename, unsigned int w, unsigned int h, bool printable_only); + void generate(const GLVolumePtrs& volumes, unsigned int w, unsigned int h, bool printable_only); + + const ThumbnailData& get_data() const { return m_data; } + + bool save_to_png_file(const std::string& filename); private: - void render(const GLCanvas3D& canvas, bool printable_only); - void render_objects(const std::vector& volumes) const; + void render_and_store(const GLVolumePtrs& volumes, bool printable_only); }; } // namespace GUI From 16fd2820db44a34acb4f7aee1295c8ce05996530 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 23 Oct 2019 16:01:23 +0200 Subject: [PATCH 21/80] ENABLE_THUMBNAIL_GENERATOR -> WIP: Added missing include and preparation for adding thumbnail to exported sla archive files --- src/libslic3r/SLA/SLARasterWriter.cpp | 16 +++++++++++++++- src/libslic3r/SLA/SLARasterWriter.hpp | 18 ++++++++++++++++++ src/libslic3r/SLAPrint.hpp | 12 ++++++++++++ src/slic3r/GUI/BackgroundSlicingProcess.cpp | 18 +++++++++++++++++- src/slic3r/GUI/GLCanvas3D.cpp | 6 ------ src/slic3r/GUI/Plater.cpp | 5 +++++ src/slic3r/GUI/ThumbnailGenerator.cpp | 2 ++ 7 files changed, 69 insertions(+), 8 deletions(-) diff --git a/src/libslic3r/SLA/SLARasterWriter.cpp b/src/libslic3r/SLA/SLARasterWriter.cpp index f80ce01ab..27ffb8392 100644 --- a/src/libslic3r/SLA/SLARasterWriter.cpp +++ b/src/libslic3r/SLA/SLARasterWriter.cpp @@ -28,7 +28,15 @@ RasterWriter::RasterWriter(const Raster::Resolution &res, : m_res(res), m_pxdim(pixdim), m_trafo(trafo), m_gamma(gamma) {} +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +void RasterWriter::save(const std::string& fpath, const ThumbnailData* thumbnail_data, const std::string& prjname) +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void RasterWriter::save(const std::string &fpath, const std::string &prjname) +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ { try { Zipper zipper(fpath); // zipper with no compression @@ -37,7 +45,13 @@ void RasterWriter::save(const std::string &fpath, const std::string &prjname) boost::filesystem::path(fpath).stem().string() : prjname; zipper.add_entry("config.ini"); - + +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + // TODO add thumbnail_data as thumbnail.png file +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + zipper << createIniContent(project); for(unsigned i = 0; i < m_layers_rst.size(); i++) diff --git a/src/libslic3r/SLA/SLARasterWriter.hpp b/src/libslic3r/SLA/SLARasterWriter.hpp index c231655d2..180ea3b8a 100644 --- a/src/libslic3r/SLA/SLARasterWriter.hpp +++ b/src/libslic3r/SLA/SLARasterWriter.hpp @@ -13,7 +13,17 @@ #include "SLARaster.hpp" +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +namespace Slic3r { +struct ThumbnailData; +namespace sla { +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ namespace Slic3r { namespace sla { +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // API to write the zipped sla output layers and metadata. // Implementation uses PNG raster output. @@ -111,7 +121,15 @@ public: } } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + void save(const std::string& fpath, const ThumbnailData* thumbnail_data = nullptr, const std::string& prjname = ""); +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void save(const std::string &fpath, const std::string &prjname = ""); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void set_statistics(const PrintStatistics &statistics); diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 2dc2a9040..0c6b93771 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -358,11 +358,23 @@ public: // Returns true if the last step was finished with success. bool finished() const override { return this->is_step_done(slaposSliceSupports) && this->Inherited::is_step_done(slapsRasterize); } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + inline void export_raster(const std::string& fpath, const ThumbnailData* thumbnail_data = nullptr, + const std::string& projectname = "") + { + if (m_printer) m_printer->save(fpath, thumbnail_data, projectname); + } +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ inline void export_raster(const std::string& fpath, const std::string& projectname = "") { if(m_printer) m_printer->save(fpath, projectname); } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ const PrintObjects& objects() const { return m_objects; } diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 9d53d60b2..6def49d69 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -117,7 +117,15 @@ void BackgroundSlicingProcess::process_sla() if (this->set_step_started(bspsGCodeFinalize)) { if (! m_export_path.empty()) { const std::string export_path = m_sla_print->print_statistics().finalize_output_path(m_export_path); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + m_sla_print->export_raster(export_path, m_thumbnail_data); +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ m_sla_print->export_raster(export_path); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ m_print->set_status(100, (boost::format(_utf8(L("Masked SLA file exported to %1%"))) % export_path).str()); } else if (! m_upload_job.empty()) { prepare_upload(); @@ -428,8 +436,16 @@ void BackgroundSlicingProcess::prepare_upload() m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string()); } else { m_upload_job.upload_data.upload_path = m_sla_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string()); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR + m_sla_print->export_raster(source_path.string(), m_thumbnail_data, m_upload_job.upload_data.upload_path.string()); +#else +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ m_sla_print->export_raster(source_path.string(), m_upload_job.upload_data.upload_path.string()); - } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + } m_print->set_status(100, (boost::format(_utf8(L("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue"))) % m_upload_job.printhost->get_host()).str()); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4e72d1526..c55d64b47 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2108,12 +2108,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re manip->set_dirty(); } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -//#if ENABLE_THUMBNAIL_GENERATOR -// wxGetApp().plater()->generate_thumbnail(256, 256, true); -//#endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - // and force this canvas to be redrawn. m_dirty = true; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 66fb72bbc..25331191b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3395,6 +3395,11 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) } else if (evt.status.flags & PrintBase::SlicingStatus::RELOAD_SLA_PREVIEW) { // Update the SLA preview. Only called if not RELOAD_SLA_SUPPORT_POINTS, as the block above will refresh the preview anyways. this->preview->reload_print(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +//#if ENABLE_THUMBNAIL_GENERATOR +// thumbnail_generator.generate(view3D->get_canvas3d()->get_volumes().volumes, 256, 256, true); +//#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } } diff --git a/src/slic3r/GUI/ThumbnailGenerator.cpp b/src/slic3r/GUI/ThumbnailGenerator.cpp index a50c5541c..37794dddf 100644 --- a/src/slic3r/GUI/ThumbnailGenerator.cpp +++ b/src/slic3r/GUI/ThumbnailGenerator.cpp @@ -11,6 +11,8 @@ #include #include +#include + namespace Slic3r { namespace GUI { From 77c52b748c3843aa1b29733022afeba5d3d0643d Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 23 Oct 2019 17:10:14 +0200 Subject: [PATCH 22/80] Zipper made available for modification after RasterWriter finishes. --- src/libslic3r/SLA/SLARasterWriter.cpp | 41 ++++++++++---------- src/libslic3r/SLA/SLARasterWriter.hpp | 22 ++--------- src/libslic3r/SLAPrint.hpp | 19 ++++------ src/libslic3r/Zipper.cpp | 5 +++ src/libslic3r/Zipper.hpp | 2 + src/slic3r/GUI/BackgroundSlicingProcess.cpp | 42 +++++++++++++-------- 6 files changed, 63 insertions(+), 68 deletions(-) diff --git a/src/libslic3r/SLA/SLARasterWriter.cpp b/src/libslic3r/SLA/SLARasterWriter.cpp index 27ffb8392..6ac86827e 100644 --- a/src/libslic3r/SLA/SLARasterWriter.cpp +++ b/src/libslic3r/SLA/SLARasterWriter.cpp @@ -28,47 +28,44 @@ RasterWriter::RasterWriter(const Raster::Resolution &res, : m_res(res), m_pxdim(pixdim), m_trafo(trafo), m_gamma(gamma) {} -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -#if ENABLE_THUMBNAIL_GENERATOR -void RasterWriter::save(const std::string& fpath, const ThumbnailData* thumbnail_data, const std::string& prjname) -#else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void RasterWriter::save(const std::string &fpath, const std::string &prjname) -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -#endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ { try { Zipper zipper(fpath); // zipper with no compression - - std::string project = prjname.empty()? - boost::filesystem::path(fpath).stem().string() : prjname; - + save(zipper, prjname); + zipper.finalize(); + } catch(std::exception& e) { + BOOST_LOG_TRIVIAL(error) << e.what(); + // Rethrow the exception + throw; + } +} + +void RasterWriter::save(Zipper &zipper, const std::string &prjname) +{ + try { + std::string project = + prjname.empty() ? + boost::filesystem::path(zipper.get_filename()).stem().string() : + prjname; + zipper.add_entry("config.ini"); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -#if ENABLE_THUMBNAIL_GENERATOR - // TODO add thumbnail_data as thumbnail.png file -#endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - zipper << createIniContent(project); - + for(unsigned i = 0; i < m_layers_rst.size(); i++) { if(m_layers_rst[i].rawbytes.size() > 0) { char lyrnum[6]; std::sprintf(lyrnum, "%.5d", i); auto zfilename = project + lyrnum + ".png"; - + // Add binary entry to the zipper zipper.add_entry(zfilename, m_layers_rst[i].rawbytes.data(), m_layers_rst[i].rawbytes.size()); } } - - zipper.finalize(); } catch(std::exception& e) { BOOST_LOG_TRIVIAL(error) << e.what(); // Rethrow the exception diff --git a/src/libslic3r/SLA/SLARasterWriter.hpp b/src/libslic3r/SLA/SLARasterWriter.hpp index 180ea3b8a..93a315c82 100644 --- a/src/libslic3r/SLA/SLARasterWriter.hpp +++ b/src/libslic3r/SLA/SLARasterWriter.hpp @@ -12,18 +12,9 @@ #include "libslic3r/PrintConfig.hpp" #include "SLARaster.hpp" +#include "libslic3r/Zipper.hpp" -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -#if ENABLE_THUMBNAIL_GENERATOR -namespace Slic3r { -struct ThumbnailData; -namespace sla { -#else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ namespace Slic3r { namespace sla { -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -#endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // API to write the zipped sla output layers and metadata. // Implementation uses PNG raster output. @@ -121,18 +112,11 @@ public: } } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -#if ENABLE_THUMBNAIL_GENERATOR - void save(const std::string& fpath, const ThumbnailData* thumbnail_data = nullptr, const std::string& prjname = ""); -#else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void save(const std::string &fpath, const std::string &prjname = ""); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -#endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + void save(Zipper &zipper, const std::string &prjname = ""); void set_statistics(const PrintStatistics &statistics); - + void set_config(const DynamicPrintConfig &cfg); }; diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 0c6b93771..8f386d407 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -7,6 +7,7 @@ #include "SLA/SLARasterWriter.hpp" #include "Point.hpp" #include "MTUtils.hpp" +#include "Zipper.hpp" #include namespace Slic3r { @@ -358,23 +359,17 @@ public: // Returns true if the last step was finished with success. bool finished() const override { return this->is_step_done(slaposSliceSupports) && this->Inherited::is_step_done(slapsRasterize); } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -#if ENABLE_THUMBNAIL_GENERATOR - inline void export_raster(const std::string& fpath, const ThumbnailData* thumbnail_data = nullptr, - const std::string& projectname = "") - { - if (m_printer) m_printer->save(fpath, thumbnail_data, projectname); - } -#else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ inline void export_raster(const std::string& fpath, const std::string& projectname = "") { if(m_printer) m_printer->save(fpath, projectname); } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -#endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + inline void export_raster(Zipper &zipper, + const std::string& projectname = "") + { + if(m_printer) m_printer->save(zipper, projectname); + } const PrintObjects& objects() const { return m_objects; } diff --git a/src/libslic3r/Zipper.cpp b/src/libslic3r/Zipper.cpp index 348be49cc..a5b53584d 100644 --- a/src/libslic3r/Zipper.cpp +++ b/src/libslic3r/Zipper.cpp @@ -217,4 +217,9 @@ void Zipper::finalize() m_impl->blow_up(); } +const std::string &Zipper::get_filename() const +{ + return m_impl->m_zipname; +} + } diff --git a/src/libslic3r/Zipper.hpp b/src/libslic3r/Zipper.hpp index a574de959..be1e69b5c 100644 --- a/src/libslic3r/Zipper.hpp +++ b/src/libslic3r/Zipper.hpp @@ -83,6 +83,8 @@ public: void finish_entry(); void finalize(); + + const std::string & get_filename() const; }; diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 6def49d69..39c6e47ef 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -107,25 +107,37 @@ void BackgroundSlicingProcess::process_fff() m_print->set_status(100, _utf8(L("Slicing complete"))); } this->set_step_done(bspsGCodeFinalize); - } + } } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +static void write_thumbnail(Zipper &zipper, const ThumbnailData &data) +{ + // TODO add thumbnail_data as thumbnail.png file to the zipper with + // void Zipper::add_entry(const std::string& name, const std::uint8_t* data, size_t l); +} +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + void BackgroundSlicingProcess::process_sla() { assert(m_print == m_sla_print); m_print->process(); if (this->set_step_started(bspsGCodeFinalize)) { if (! m_export_path.empty()) { - const std::string export_path = m_sla_print->print_statistics().finalize_output_path(m_export_path); + const std::string export_path = m_sla_print->print_statistics().finalize_output_path(m_export_path); + + Zipper zipper(export_path); + m_sla_print->export_raster(zipper); //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR - m_sla_print->export_raster(export_path, m_thumbnail_data); -#else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - m_sla_print->export_raster(export_path); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + if(m_thumbnail_data) write_thumbnail(zipper, *m_thumbnail_data); #endif // ENABLE_THUMBNAIL_GENERATOR //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + zipper.finalize(); + m_print->set_status(100, (boost::format(_utf8(L("Masked SLA file exported to %1%"))) % export_path).str()); } else if (! m_upload_job.empty()) { prepare_upload(); @@ -433,21 +445,21 @@ void BackgroundSlicingProcess::prepare_upload() throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed"))); } run_post_process_scripts(source_path.string(), m_fff_print->config()); - m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string()); + m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string()); } else { - m_upload_job.upload_data.upload_path = m_sla_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string()); + m_upload_job.upload_data.upload_path = m_sla_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string()); + + Zipper zipper{source_path.string()}; + m_sla_print->export_raster(zipper, m_upload_job.upload_data.upload_path.string()); //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR - m_sla_print->export_raster(source_path.string(), m_thumbnail_data, m_upload_job.upload_data.upload_path.string()); -#else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - m_sla_print->export_raster(source_path.string(), m_upload_job.upload_data.upload_path.string()); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + if (m_thumbnail_data) write_thumbnail(zipper, *m_thumbnail_data); #endif // ENABLE_THUMBNAIL_GENERATOR //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + zipper.finalize(); } - m_print->set_status(100, (boost::format(_utf8(L("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue"))) % m_upload_job.printhost->get_host()).str()); + m_print->set_status(100, (boost::format(_utf8(L("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue"))) % m_upload_job.printhost->get_host()).str()); m_upload_job.upload_data.source_path = std::move(source_path); From ad0a9cf4390944deff74a45de65df2604c89dd18 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 24 Oct 2019 08:46:39 +0200 Subject: [PATCH 23/80] ENABLE_THUMBNAIL_GENERATOR -> Add file thumbnail/thumbnail.png into sla output --- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 30 +++++++++++++++------ src/slic3r/GUI/Plater.cpp | 6 ++--- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 39c6e47ef..3ef32ad64 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -10,12 +10,23 @@ #include #include +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +#include +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + // Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx. #include "libslic3r/Print.hpp" #include "libslic3r/SLAPrint.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/GCode/PostProcessor.hpp" #include "libslic3r/GCode/PreviewData.hpp" +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +#include "libslic3r/GCode/ThumbnailData.hpp" +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #include "libslic3r/libslic3r.h" #include @@ -110,15 +121,18 @@ void BackgroundSlicingProcess::process_fff() } } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR -static void write_thumbnail(Zipper &zipper, const ThumbnailData &data) +static void write_thumbnail(Zipper& zipper, const ThumbnailData& data) { - // TODO add thumbnail_data as thumbnail.png file to the zipper with - // void Zipper::add_entry(const std::string& name, const std::uint8_t* data, size_t l); + size_t png_size = 0; + 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) + { + zipper.add_entry("thumbnail/thumbnail.png", (const std::uint8_t*)png_data, png_size); + mz_free(png_data); + } } #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void BackgroundSlicingProcess::process_sla() { @@ -130,11 +144,11 @@ void BackgroundSlicingProcess::process_sla() Zipper zipper(export_path); m_sla_print->export_raster(zipper); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + #if ENABLE_THUMBNAIL_GENERATOR - if(m_thumbnail_data) write_thumbnail(zipper, *m_thumbnail_data); + if (m_thumbnail_data!= nullptr) + write_thumbnail(zipper, *m_thumbnail_data); #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ zipper.finalize(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 25331191b..71249bd90 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3396,9 +3396,9 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) // Update the SLA preview. Only called if not RELOAD_SLA_SUPPORT_POINTS, as the block above will refresh the preview anyways. this->preview->reload_print(); //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -//#if ENABLE_THUMBNAIL_GENERATOR -// thumbnail_generator.generate(view3D->get_canvas3d()->get_volumes().volumes, 256, 256, true); -//#endif // ENABLE_THUMBNAIL_GENERATOR +#if ENABLE_THUMBNAIL_GENERATOR + thumbnail_generator.generate(view3D->get_canvas3d()->get_volumes().volumes, 256, 256, true); +#endif // ENABLE_THUMBNAIL_GENERATOR //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } } From 4517fcd997e0495045be6466bf11edad0ff9449c Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 24 Oct 2019 09:20:33 +0200 Subject: [PATCH 24/80] ENABLE_THUMBNAIL_GENERATOR -> Add file Metadata/thumbnail.png into 3mf output --- src/libslic3r/Format/3mf.cpp | 75 +++++++-------------- src/libslic3r/Format/3mf.hpp | 8 +-- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 2 +- 3 files changed, 26 insertions(+), 59 deletions(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index a981cca61..ff3cf777d 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -3,11 +3,9 @@ #include "../Utils.hpp" #include "../GCode.hpp" #include "../Geometry.hpp" -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR #include "../GCode/ThumbnailData.hpp" #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #include "../I18N.hpp" @@ -45,11 +43,9 @@ const std::string MODEL_EXTENSION = ".model"; const std::string MODEL_FILE = "3D/3dmodel.model"; // << this is the only format of the string which works with CURA const std::string CONTENT_TYPES_FILE = "[Content_Types].xml"; const std::string RELATIONSHIPS_FILE = "_rels/.rels"; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR const std::string THUMBNAIL_FILE = "Metadata/thumbnail.png"; #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config"; const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config"; const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt"; @@ -1816,32 +1812,22 @@ namespace Slic3r { typedef std::map IdToObjectDataMap; public: -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR - bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail = nullptr); + bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data = nullptr); #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ private: -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR - bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail); + bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data); #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool _add_content_types_file_to_archive(mz_zip_archive& archive); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR - bool _add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail); + bool _add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data); #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool _add_relationships_file_to_archive(mz_zip_archive& archive); bool _add_model_file_to_archive(mz_zip_archive& archive, const Model& model, IdToObjectDataMap &objects_data); bool _add_object_to_model_stream(std::stringstream& stream, unsigned int& object_id, ModelObject& object, BuildItemsList& build_items, VolumeToOffsetsMap& volumes_offsets); @@ -1854,33 +1840,25 @@ namespace Slic3r { bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data); }; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR - bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail) + bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data) { clear_errors(); - return _save_model_to_file(filename, model, config, thumbnail); + return _save_model_to_file(filename, model, config, thumbnail_data); } #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config) { clear_errors(); return _save_model_to_file(filename, model, config); } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR - bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail) + bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data) #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config) -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ { mz_zip_archive archive; mz_zip_zero_struct(&archive); @@ -1899,12 +1877,11 @@ namespace Slic3r { return false; } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR - if ((thumbnail != nullptr) && thumbnail->is_valid()) + if ((thumbnail_data != nullptr) && thumbnail_data->is_valid()) { // Adds the file Metadata/thumbnail.png. - if (!_add_thumbnail_file_to_archive(archive, *thumbnail)) + if (!_add_thumbnail_file_to_archive(archive, *thumbnail_data)) { close_zip_writer(&archive); boost::filesystem::remove(filename); @@ -1912,7 +1889,6 @@ namespace Slic3r { } } #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Adds relationships file ("_rels/.rels"). // The content of this file is the same for each PrusaSlicer 3mf. @@ -2007,11 +1983,9 @@ namespace Slic3r { stream << "\n"; stream << " \n"; stream << " \n"; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR stream << " \n"; #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ stream << ""; std::string out = stream.str(); @@ -2025,16 +1999,25 @@ namespace Slic3r { return true; } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR - bool _3MF_Exporter::_add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail) + bool _3MF_Exporter::_add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data) { - // TODO -> add Metadata/thumbnail.png file containing thumbnail_data + bool res = false; - return true; + size_t png_size = 0; + void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)thumbnail_data.pixels.data(), thumbnail_data.width, thumbnail_data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1); + if (png_data != nullptr) + { + res = mz_zip_writer_add_mem(&archive, THUMBNAIL_FILE.c_str(), (const void*)png_data, png_size, MZ_DEFAULT_COMPRESSION); + mz_free(png_data); + } + + if (!res) + add_error("Unable to add thumbnail file to archive"); + + return res; } #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool _3MF_Exporter::_add_relationships_file_to_archive(mz_zip_archive& archive) { @@ -2042,11 +2025,9 @@ namespace Slic3r { stream << "\n"; stream << "\n"; stream << " \n"; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR stream << " \n"; #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ stream << ""; std::string out = stream.str(); @@ -2540,29 +2521,21 @@ namespace Slic3r { return res; } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR - bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail) + bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data) #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config) -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ { if ((path == nullptr) || (model == nullptr)) return false; _3MF_Exporter exporter; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR - bool res = exporter.save_model_to_file(path, *model, config, thumbnail); + bool res = exporter.save_model_to_file(path, *model, config, thumbnail_data); #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool res = exporter.save_model_to_file(path, *model, config); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ if (!res) exporter.log_errors(); diff --git a/src/libslic3r/Format/3mf.hpp b/src/libslic3r/Format/3mf.hpp index 0ce6eb742..2e85b7f59 100644 --- a/src/libslic3r/Format/3mf.hpp +++ b/src/libslic3r/Format/3mf.hpp @@ -22,26 +22,20 @@ namespace Slic3r { class Model; class DynamicPrintConfig; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR struct ThumbnailData; #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Load the content of a 3mf file into the given model and preset bundle. extern bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool check_version); // Save the given model and the config data contained in the given Print into a 3mf file. // The model could be modified during the export process if meshes are not repaired or have no shared vertices -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR - extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail = nullptr); + extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data = nullptr); #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ }; // namespace Slic3r diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 3ef32ad64..67860138a 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -146,7 +146,7 @@ void BackgroundSlicingProcess::process_sla() m_sla_print->export_raster(zipper); #if ENABLE_THUMBNAIL_GENERATOR - if (m_thumbnail_data!= nullptr) + if ((m_thumbnail_data != nullptr) && m_thumbnail_data->is_valid()) write_thumbnail(zipper, *m_thumbnail_data); #endif // ENABLE_THUMBNAIL_GENERATOR From 5609f537979878673275ca30dd6e122e197b38ca Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 24 Oct 2019 10:06:31 +0200 Subject: [PATCH 25/80] ENABLE_THUMBNAIL_GENERATOR -> Add thumbnail data into gcode output --- src/libslic3r/GCode.cpp | 25 ++++++++----------------- src/libslic3r/GCode.hpp | 10 ---------- src/slic3r/GUI/Plater.cpp | 27 ++++++++++++++++++--------- 3 files changed, 26 insertions(+), 36 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 13b417efa..2ea8eae1d 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -6,11 +6,9 @@ #include "Geometry.hpp" #include "GCode/PrintExtents.hpp" #include "GCode/WipeTower.hpp" -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR #include "GCode/ThumbnailData.hpp" #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #include "ShortestPath.hpp" #include "Utils.hpp" @@ -657,15 +655,11 @@ std::vector>> GCode::collec return layers_to_print; } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, const ThumbnailData* thumbnail_data) #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_data) -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ { PROFILE_CLEAR(); @@ -691,15 +685,11 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ try { m_placeholder_parser_failed_templates.clear(); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR this->_do_export(*print, file, thumbnail_data); #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ this->_do_export(*print, file); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ fflush(file); if (ferror(file)) { fclose(file); @@ -763,15 +753,11 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ PROFILE_OUTPUT(debug_out_path("gcode-export-profile.txt").c_str()); } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR void GCode::_do_export(Print& print, FILE* file, const ThumbnailData* thumbnail_data) #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void GCode::_do_export(Print &print, FILE *file) -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ { PROFILE_FUNC(); @@ -964,19 +950,24 @@ void GCode::_do_export(Print &print, FILE *file) // Write information on the generator. _write_format(file, "; %s\n\n", Slic3r::header_slic3r_generated().c_str()); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR // Write thumbnail if ((thumbnail_data != nullptr) && thumbnail_data->is_valid()) { _write(file, "\n;\n; thumbnail begin\n"); - // TODO -> export content of thumbnail_data.pixels + size_t row_size = 4 * thumbnail_data->width; + for (int r = (int)thumbnail_data->height - 1; r >= 0 ; --r) + { + _write(file, "; "); + const void* data_ptr = thumbnail_data->pixels.data() + r * row_size; + ::fwrite((const void*)data_ptr, 1, row_size, file); + _write(file, "\n"); + } _write(file, "; thumbnail end\n;\n\n"); } #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Write notes (content of the Print Settings tab -> Notes) { diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 4c5b92bf1..8116d06fc 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -30,11 +30,9 @@ namespace Slic3r { // Forward declarations. class GCode; class GCodePreviewData; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR struct ThumbnailData; #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ class AvoidCrossingPerimeters { public: @@ -167,15 +165,11 @@ public: // throws std::runtime_exception on error, // throws CanceledException through print->throw_if_canceled(). -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, const ThumbnailData* thumbnail_data = nullptr); #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests. const Vec2d& origin() const { return m_origin; } @@ -203,15 +197,11 @@ public: static void append_full_config(const Print& print, std::string& str); protected: -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR void _do_export(Print& print, FILE* file, const ThumbnailData* thumbnail_data); #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void _do_export(Print &print, FILE *file); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif //ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Object and support extrusions of the same PrintObject at the same print_z. struct LayerToPrint diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 71249bd90..22edfcab2 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -87,6 +87,13 @@ using Slic3r::_3DScene; using Slic3r::Preset; using Slic3r::PrintHostJob; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENABLE_THUMBNAIL_GENERATOR +static const std::pair THUMBNAIL_SIZE_FFF = { 128, 128 }; +static const std::pair THUMBNAIL_SIZE_SLA = { 256, 256 }; +static const std::pair THUMBNAIL_SIZE_3MF = { 256, 256 }; +#endif // ENABLE_THUMBNAIL_GENERATOR +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ namespace Slic3r { namespace GUI { @@ -3052,9 +3059,11 @@ bool Plater::priv::restart_background_process(unsigned int state) #if ENABLE_THUMBNAIL_GENERATOR if ((state & UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT) == 0) { - // force update of thumbnail data, so that they can be inserted into the exported gcode - thumbnail_generator.generate(view3D->get_canvas3d()->get_volumes().volumes, 256, 256, true); - thumbnail_generator.save_to_png_file("C:/prusa/test/test.png"); + // update thumbnail data + if (this->printer_technology == ptFFF) + generate_thumbnail(THUMBNAIL_SIZE_FFF.first, THUMBNAIL_SIZE_FFF.second, true); + else if (this->printer_technology == ptSLA) + generate_thumbnail(THUMBNAIL_SIZE_SLA.first, THUMBNAIL_SIZE_SLA.second, true); } #endif // ENABLE_THUMBNAIL_GENERATOR //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@ -3397,7 +3406,11 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) this->preview->reload_print(); //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR - thumbnail_generator.generate(view3D->get_canvas3d()->get_volumes().volumes, 256, 256, true); + // update thumbnail data + if (this->printer_technology == ptFFF) + generate_thumbnail(THUMBNAIL_SIZE_FFF.first, THUMBNAIL_SIZE_FFF.second, true); + else if (this->printer_technology == ptSLA) + generate_thumbnail(THUMBNAIL_SIZE_SLA.first, THUMBNAIL_SIZE_SLA.second, true); #endif // ENABLE_THUMBNAIL_GENERATOR //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } @@ -4672,16 +4685,12 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure(); const std::string path_u8 = into_u8(path); wxBusyCursor wait; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR - p->generate_thumbnail(128, 128, false); + p->generate_thumbnail(THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, false); if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, &p->thumbnail_generator.get_data())) { #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) { -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Success p->statusbar()->set_status_text(wxString::Format(_(L("3MF file exported to %s")), path)); p->set_project_filename(path); From 6d5572ae4739cb2e21744e736c247c5990311fad Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 24 Oct 2019 10:25:40 +0200 Subject: [PATCH 26/80] ENABLE_THUMBNAIL_GENERATOR -> Code cleanup --- src/libslic3r/Print.cpp | 8 -------- src/libslic3r/Print.hpp | 6 ------ src/libslic3r/Technologies.hpp | 2 -- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 13 ++----------- src/slic3r/GUI/BackgroundSlicingProcess.hpp | 6 ------ src/slic3r/GUI/GLCanvas3D.hpp | 3 --- src/slic3r/GUI/Plater.cpp | 18 ------------------ src/slic3r/GUI/Plater.hpp | 2 -- src/slic3r/GUI/ThumbnailGenerator.hpp | 4 +++- 9 files changed, 5 insertions(+), 57 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 742a2a960..b2ed87ca0 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1536,15 +1536,11 @@ void Print::process() // The export_gcode may die for various reasons (fails to process output_filename_format, // write error into the G-code, cannot execute post-processing scripts). // It is up to the caller to show an error message. -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, const ThumbnailData* thumbnail_data) #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ std::string Print::export_gcode(const std::string &path_template, GCodePreviewData *preview_data) -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ { // output everything to a G-code file // The following call may die if the output_filename_format template substitution fails. @@ -1561,15 +1557,11 @@ std::string Print::export_gcode(const std::string &path_template, GCodePreviewDa // The following line may die for multiple reasons. GCode gcode; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR gcode.do_export(this, path.c_str(), preview_data, thumbnail_data); #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ gcode.do_export(this, path.c_str(), preview_data); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ return path.c_str(); } diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 8dc54ee1d..aedeeff18 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -19,11 +19,9 @@ class PrintObject; class ModelObject; class GCode; class GCodePreviewData; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR struct ThumbnailData; #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Print step IDs for keeping track of the print state. enum PrintStep { @@ -310,15 +308,11 @@ public: void process() override; // Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file. // If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r). -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, const ThumbnailData* thumbnail_data = nullptr); #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ std::string export_gcode(const std::string &path_template, GCodePreviewData *preview_data); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // methods for handling state bool is_step_done(PrintStep step) const { return Inherited::is_step_done(step); } diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 40e989bb2..4b351adb2 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -32,7 +32,6 @@ #define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1) -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //==================== // 2.2.0.alpha1 techs //==================== @@ -40,6 +39,5 @@ // Enable thumbnail generator #define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_2_0_ALPHA1) -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // _technologies_h_ diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 67860138a..cedeab910 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -10,11 +10,9 @@ #include #include -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR #include #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx. #include "libslic3r/Print.hpp" @@ -22,11 +20,9 @@ #include "libslic3r/Utils.hpp" #include "libslic3r/GCode/PostProcessor.hpp" #include "libslic3r/GCode/PreviewData.hpp" -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR #include "libslic3r/GCode/ThumbnailData.hpp" #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #include "libslic3r/libslic3r.h" #include @@ -93,15 +89,11 @@ void BackgroundSlicingProcess::process_fff() assert(m_print == m_fff_print); m_print->process(); wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_slicing_completed_id)); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data, m_thumbnail_data); #else -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ if (this->set_step_started(bspsGCodeFinalize)) { if (! m_export_path.empty()) { //FIXME localize the messages @@ -465,11 +457,10 @@ void BackgroundSlicingProcess::prepare_upload() Zipper zipper{source_path.string()}; m_sla_print->export_raster(zipper, m_upload_job.upload_data.upload_path.string()); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR - if (m_thumbnail_data) write_thumbnail(zipper, *m_thumbnail_data); + if ((m_thumbnail_data != nullptr) && m_thumbnail_data->is_valid()) + write_thumbnail(zipper, *m_thumbnail_data); #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ zipper.finalize(); } diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index af20554df..e51a4e961 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -17,11 +17,9 @@ namespace Slic3r { class DynamicPrintConfig; class GCodePreviewData; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR struct ThumbnailData; #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ class Model; class SLAPrint; @@ -54,11 +52,9 @@ public: void set_fff_print(Print *print) { m_fff_print = print; } void set_sla_print(SLAPrint *print) { m_sla_print = print; } void set_gcode_preview_data(GCodePreviewData *gpd) { m_gcode_preview_data = gpd; } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR void set_thumbnail_data(const ThumbnailData* data) { m_thumbnail_data = data; } #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // The following wxCommandEvent will be sent to the UI thread / Platter window, when the slicing is finished // and the background processing will transition into G-code export. @@ -162,12 +158,10 @@ private: SLAPrint *m_sla_print = nullptr; // Data structure, to which the G-code export writes its annotations. GCodePreviewData *m_gcode_preview_data = nullptr; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR // Data structure, used to write thumbnail into gcode. const ThumbnailData *m_thumbnail_data = nullptr; #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Temporary G-code, there is one defined for the BackgroundSlicingProcess, differentiated from the other processes by a process ID. std::string m_temp_output_path; // Output path provided by the user. The output path may be set even if the slicing is running, diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 2e7fc2d77..eb3c60bd1 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -446,12 +446,9 @@ public: wxGLCanvas* get_wxglcanvas() { return m_canvas; } const wxGLCanvas* get_wxglcanvas() const { return m_canvas; } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR const GLVolumeCollection& get_volumes() const { return m_volumes; } -// GLVolumeCollection& get_volumes() { return m_volumes; } #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool init(); void post_event(wxEvent &&event); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 22edfcab2..f9167cec9 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -62,11 +62,9 @@ #include "GUI_Preview.hpp" #include "3DBed.hpp" #include "Camera.hpp" -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR #include "ThumbnailGenerator.hpp" #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #include "Tab.hpp" #include "PresetBundle.hpp" #include "BackgroundSlicingProcess.hpp" @@ -87,13 +85,11 @@ using Slic3r::_3DScene; using Slic3r::Preset; using Slic3r::PrintHostJob; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR static const std::pair THUMBNAIL_SIZE_FFF = { 128, 128 }; static const std::pair THUMBNAIL_SIZE_SLA = { 256, 256 }; static const std::pair THUMBNAIL_SIZE_3MF = { 256, 256 }; #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ namespace Slic3r { namespace GUI { @@ -1385,11 +1381,9 @@ struct Plater::priv View3D* view3D; GLToolbar view_toolbar; Preview *preview; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR ThumbnailGenerator thumbnail_generator; #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ BackgroundSlicingProcess background_process; bool suppressed_backround_processing_update { false }; @@ -1933,11 +1927,9 @@ struct Plater::priv bool can_mirror() const; bool can_reload_from_disk() const; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR void generate_thumbnail(unsigned int w, unsigned int h, bool printable_only); #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void msw_rescale_object_menu(); @@ -2006,11 +1998,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) background_process.set_fff_print(&fff_print); background_process.set_sla_print(&sla_print); background_process.set_gcode_preview_data(&gcode_preview_data); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR background_process.set_thumbnail_data(&thumbnail_generator.get_data()); #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ background_process.set_slicing_completed_event(EVT_SLICING_COMPLETED); background_process.set_finished_event(EVT_PROCESS_COMPLETED); // Default printer technology for default config. @@ -3055,7 +3045,6 @@ bool Plater::priv::restart_background_process(unsigned int state) ( ((state & UPDATE_BACKGROUND_PROCESS_FORCE_RESTART) != 0 && ! this->background_process.finished()) || (state & UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT) != 0 || (state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 ) ) { -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR if ((state & UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT) == 0) { @@ -3066,7 +3055,6 @@ bool Plater::priv::restart_background_process(unsigned int state) generate_thumbnail(THUMBNAIL_SIZE_SLA.first, THUMBNAIL_SIZE_SLA.second, true); } #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // The print is valid and it can be started. if (this->background_process.start()) { this->statusbar()->set_cancel_callback([this]() { @@ -3404,7 +3392,6 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) } else if (evt.status.flags & PrintBase::SlicingStatus::RELOAD_SLA_PREVIEW) { // Update the SLA preview. Only called if not RELOAD_SLA_SUPPORT_POINTS, as the block above will refresh the preview anyways. this->preview->reload_print(); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR // update thumbnail data if (this->printer_technology == ptFFF) @@ -3412,7 +3399,6 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) else if (this->printer_technology == ptSLA) generate_thumbnail(THUMBNAIL_SIZE_SLA.first, THUMBNAIL_SIZE_SLA.second, true); #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } } @@ -3638,14 +3624,12 @@ bool Plater::priv::init_object_menu() return true; } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR void Plater::priv::generate_thumbnail(unsigned int w, unsigned int h, bool printable_only) { thumbnail_generator.generate(view3D->get_canvas3d()->get_volumes().volumes, w, h, printable_only); } #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void Plater::priv::msw_rescale_object_menu() { @@ -5187,14 +5171,12 @@ void Plater::paste_from_clipboard() p->view3D->get_canvas3d()->get_selection().paste_from_clipboard(); } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR void Plater::generate_thumbnail(unsigned int w, unsigned int h, bool printable_only) { p->generate_thumbnail(w, h, printable_only); } #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void Plater::msw_rescale() { diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index b14cff65a..7c671f669 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -240,11 +240,9 @@ public: void copy_selection_to_clipboard(); void paste_from_clipboard(); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #if ENABLE_THUMBNAIL_GENERATOR void generate_thumbnail(unsigned int w, unsigned int h, bool printable_only); #endif // ENABLE_THUMBNAIL_GENERATOR -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ bool can_delete() const; bool can_delete_all() const; diff --git a/src/slic3r/GUI/ThumbnailGenerator.hpp b/src/slic3r/GUI/ThumbnailGenerator.hpp index e632106cd..ae7509b3c 100644 --- a/src/slic3r/GUI/ThumbnailGenerator.hpp +++ b/src/slic3r/GUI/ThumbnailGenerator.hpp @@ -6,9 +6,11 @@ #include "../libslic3r/GCode/ThumbnailData.hpp" namespace Slic3r { + class GLVolume; typedef std::vector GLVolumePtrs; - namespace GUI { + +namespace GUI { class ThumbnailGenerator { From a1f2ecb285daebbac4271a6b145ead6433affcd7 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 24 Oct 2019 10:38:30 +0200 Subject: [PATCH 27/80] ENABLE_THUMBNAIL_GENERATOR -> Fixed color of non printable volumes into thumbnail --- src/slic3r/GUI/ThumbnailGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/ThumbnailGenerator.cpp b/src/slic3r/GUI/ThumbnailGenerator.cpp index 37794dddf..f2a74cae9 100644 --- a/src/slic3r/GUI/ThumbnailGenerator.cpp +++ b/src/slic3r/GUI/ThumbnailGenerator.cpp @@ -89,7 +89,7 @@ void ThumbnailGenerator::render_and_store(const GLVolumePtrs& volumes, bool prin for (const GLVolume* vol : visible_volumes) { - glsafe(::glColor3fv(vol->printable ? orange : gray)); + glsafe(::glColor3fv((vol->printable && !vol->is_outside) ? orange : gray)); vol->render(); } From a417da8fea69547009ddb5994c44ade60c5fa9ac Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 24 Oct 2019 11:08:39 +0200 Subject: [PATCH 28/80] ENABLE_THUMBNAIL_GENERATOR -> Fixed volumes visibility test to render them into thumbnail --- src/slic3r/GUI/ThumbnailGenerator.cpp | 34 ++++++--------------------- src/slic3r/GUI/ThumbnailGenerator.hpp | 2 -- 2 files changed, 7 insertions(+), 29 deletions(-) diff --git a/src/slic3r/GUI/ThumbnailGenerator.cpp b/src/slic3r/GUI/ThumbnailGenerator.cpp index f2a74cae9..634f9e61c 100644 --- a/src/slic3r/GUI/ThumbnailGenerator.cpp +++ b/src/slic3r/GUI/ThumbnailGenerator.cpp @@ -29,34 +29,14 @@ void ThumbnailGenerator::generate(const GLVolumePtrs& volumes, unsigned int w, u render_and_store(volumes, printable_only); } -bool ThumbnailGenerator::save_to_png_file(const std::string& filename) -{ - if (!m_data.is_valid()) - return false; - - wxImage image(m_data.width, m_data.height); - image.InitAlpha(); - - for (unsigned int r = 0; r < m_data.height; ++r) - { - unsigned int rr = (m_data.height - 1 - r) * m_data.width; - for (unsigned int c = 0; c < m_data.width; ++c) - { - unsigned char* px = m_data.pixels.data() + 4 * (rr + c); - image.SetRGB((int)c, (int)r, px[0], px[1], px[2]); - image.SetAlpha((int)c, (int)r, px[3]); - } - } - - std::string path = filename; - if (!boost::iends_with(path, ".png")) - path = boost::filesystem::path(path).replace_extension(".png").string(); - - return image.SaveFile(from_u8(path), wxBITMAP_TYPE_PNG); -} - void ThumbnailGenerator::render_and_store(const GLVolumePtrs& volumes, bool printable_only) { + auto is_visible = [] (const GLVolume& v) -> bool { + bool ret = v.printable; + ret &= (!v.shader_outside_printer_detection_enabled || !v.is_outside); + return ret; + }; + static const float orange[] = { 0.99f, 0.49f, 0.26f }; static const float gray[] = { 0.64f, 0.64f, 0.64f }; @@ -64,7 +44,7 @@ void ThumbnailGenerator::render_and_store(const GLVolumePtrs& volumes, bool prin for (const GLVolume* vol : volumes) { - if (!printable_only || vol->printable) + if (!printable_only || is_visible(*vol)) visible_volumes.push_back(vol); } diff --git a/src/slic3r/GUI/ThumbnailGenerator.hpp b/src/slic3r/GUI/ThumbnailGenerator.hpp index ae7509b3c..20087b79b 100644 --- a/src/slic3r/GUI/ThumbnailGenerator.hpp +++ b/src/slic3r/GUI/ThumbnailGenerator.hpp @@ -27,8 +27,6 @@ namespace GUI { const ThumbnailData& get_data() const { return m_data; } - bool save_to_png_file(const std::string& filename); - private: void render_and_store(const GLVolumePtrs& volumes, bool printable_only); }; From 29fd0ef7c6d2fdc1dcca6d599ba128d48615e232 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 24 Oct 2019 12:09:09 +0200 Subject: [PATCH 29/80] ENABLE_THUMBNAIL_GENERATOR -> Refactoring to simplify code --- src/slic3r/CMakeLists.txt | 2 -- src/slic3r/GUI/GLCanvas3D.cpp | 61 +++++++++++++++++++++++++++++++++++ src/slic3r/GUI/GLCanvas3D.hpp | 10 +++--- src/slic3r/GUI/Plater.cpp | 25 ++++++-------- src/slic3r/GUI/Plater.hpp | 4 --- 5 files changed, 76 insertions(+), 26 deletions(-) diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 0b2dd6702..17b76e629 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -136,8 +136,6 @@ set(SLIC3R_GUI_SOURCES GUI/ProgressStatusBar.cpp GUI/PrintHostDialogs.cpp GUI/PrintHostDialogs.hpp - GUI/ThumbnailGenerator.cpp - GUI/ThumbnailGenerator.hpp Utils/Http.cpp Utils/Http.hpp Utils/FixModelByWin10.cpp diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c55d64b47..8d16187cb 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -7,6 +7,9 @@ #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/PrintConfig.hpp" #include "libslic3r/GCode/PreviewData.hpp" +#if ENABLE_THUMBNAIL_GENERATOR +#include "libslic3r/GCode/ThumbnailData.hpp" +#endif // ENABLE_THUMBNAIL_GENERATOR #include "libslic3r/Geometry.hpp" #include "libslic3r/ExtrusionEntity.hpp" #include "libslic3r/Utils.hpp" @@ -1643,6 +1646,64 @@ void GLCanvas3D::render() #endif // ENABLE_RENDER_STATISTICS } +#if ENABLE_THUMBNAIL_GENERATOR +void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only) +{ + auto is_visible = [](const GLVolume& v) -> bool { + bool ret = v.printable; + ret &= (!v.shader_outside_printer_detection_enabled || !v.is_outside); + return ret; + }; + + static const float orange[] = { 0.99f, 0.49f, 0.26f }; + static const float gray[] = { 0.64f, 0.64f, 0.64f }; + + thumbnail_data.set(w, h); + + GLVolumePtrs visible_volumes; + + for (GLVolume* vol : m_volumes.volumes) + { + if (!printable_only || is_visible(*vol)) + visible_volumes.push_back(vol); + } + + if (visible_volumes.empty()) + return; + + BoundingBoxf3 box; + for (const GLVolume* vol : visible_volumes) + { + box.merge(vol->transformed_bounding_box()); + } + + Camera camera; + camera.zoom_to_box(box, thumbnail_data.width, thumbnail_data.height); + camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height); + camera.apply_view_matrix(); + camera.apply_projection(box); + + glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); + glsafe(::glEnable(GL_LIGHTING)); + glsafe(::glEnable(GL_DEPTH_TEST)); + + for (const GLVolume* vol : visible_volumes) + { + glsafe(::glColor3fv((vol->printable && !vol->is_outside) ? orange : gray)); + vol->render(); + } + + glsafe(::glDisable(GL_DEPTH_TEST)); + glsafe(::glDisable(GL_LIGHTING)); + glsafe(::glReadPixels(0, 0, thumbnail_data.width, thumbnail_data.height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data())); + + std::cout << "Generated thumbnail " << thumbnail_data.width << "x" << thumbnail_data.height << std::endl; + + // force a frame render to restore the default framebuffer + render(); +} +#endif // ENABLE_THUMBNAIL_GENERATOR + void GLCanvas3D::select_all() { m_selection.add_all(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index eb3c60bd1..611e9a932 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -36,6 +36,9 @@ class GLShader; class ExPolygon; class BackgroundSlicingProcess; class GCodePreviewData; +#if ENABLE_THUMBNAIL_GENERATOR +struct ThumbnailData; +#endif // ENABLE_THUMBNAIL_GENERATOR struct SlicingParameters; enum LayerHeightEditActionType : unsigned int; @@ -446,10 +449,6 @@ public: wxGLCanvas* get_wxglcanvas() { return m_canvas; } const wxGLCanvas* get_wxglcanvas() const { return m_canvas; } -#if ENABLE_THUMBNAIL_GENERATOR - const GLVolumeCollection& get_volumes() const { return m_volumes; } -#endif // ENABLE_THUMBNAIL_GENERATOR - bool init(); void post_event(wxEvent &&event); @@ -523,6 +522,9 @@ public: bool is_dragging() const { return m_gizmos.is_dragging() || m_moving; } void render(); +#if ENABLE_THUMBNAIL_GENERATOR + void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only); +#endif // ENABLE_THUMBNAIL_GENERATOR void select_all(); void deselect_all(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index f9167cec9..0ebd208fa 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -32,6 +32,9 @@ #include "libslic3r/Format/AMF.hpp" #include "libslic3r/Format/3mf.hpp" #include "libslic3r/GCode/PreviewData.hpp" +#if ENABLE_THUMBNAIL_GENERATOR +#include "libslic3r/GCode/ThumbnailData.hpp" +#endif // ENABLE_THUMBNAIL_GENERATOR #include "libslic3r/Model.hpp" #include "libslic3r/Polygon.hpp" #include "libslic3r/Print.hpp" @@ -62,9 +65,6 @@ #include "GUI_Preview.hpp" #include "3DBed.hpp" #include "Camera.hpp" -#if ENABLE_THUMBNAIL_GENERATOR -#include "ThumbnailGenerator.hpp" -#endif // ENABLE_THUMBNAIL_GENERATOR #include "Tab.hpp" #include "PresetBundle.hpp" #include "BackgroundSlicingProcess.hpp" @@ -1370,6 +1370,9 @@ struct Plater::priv Slic3r::Model model; PrinterTechnology printer_technology = ptFFF; Slic3r::GCodePreviewData gcode_preview_data; +#if ENABLE_THUMBNAIL_GENERATOR + Slic3r::ThumbnailData thumbnail_data; +#endif // ENABLE_THUMBNAIL_GENERATOR // GUI elements wxSizer* panel_sizer{ nullptr }; @@ -1381,9 +1384,6 @@ struct Plater::priv View3D* view3D; GLToolbar view_toolbar; Preview *preview; -#if ENABLE_THUMBNAIL_GENERATOR - ThumbnailGenerator thumbnail_generator; -#endif // ENABLE_THUMBNAIL_GENERATOR BackgroundSlicingProcess background_process; bool suppressed_backround_processing_update { false }; @@ -1999,7 +1999,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) background_process.set_sla_print(&sla_print); background_process.set_gcode_preview_data(&gcode_preview_data); #if ENABLE_THUMBNAIL_GENERATOR - background_process.set_thumbnail_data(&thumbnail_generator.get_data()); + background_process.set_thumbnail_data(&thumbnail_data); #endif // ENABLE_THUMBNAIL_GENERATOR background_process.set_slicing_completed_event(EVT_SLICING_COMPLETED); background_process.set_finished_event(EVT_PROCESS_COMPLETED); @@ -3627,7 +3627,7 @@ bool Plater::priv::init_object_menu() #if ENABLE_THUMBNAIL_GENERATOR void Plater::priv::generate_thumbnail(unsigned int w, unsigned int h, bool printable_only) { - thumbnail_generator.generate(view3D->get_canvas3d()->get_volumes().volumes, w, h, printable_only); + view3D->get_canvas3d()->render_thumbnail(thumbnail_data, w, h, printable_only); } #endif // ENABLE_THUMBNAIL_GENERATOR @@ -4671,7 +4671,7 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) wxBusyCursor wait; #if ENABLE_THUMBNAIL_GENERATOR p->generate_thumbnail(THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, false); - if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, &p->thumbnail_generator.get_data())) { + if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, &p->thumbnail_data)) { #else if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) { #endif // ENABLE_THUMBNAIL_GENERATOR @@ -5171,13 +5171,6 @@ void Plater::paste_from_clipboard() p->view3D->get_canvas3d()->get_selection().paste_from_clipboard(); } -#if ENABLE_THUMBNAIL_GENERATOR -void Plater::generate_thumbnail(unsigned int w, unsigned int h, bool printable_only) -{ - p->generate_thumbnail(w, h, printable_only); -} -#endif // ENABLE_THUMBNAIL_GENERATOR - void Plater::msw_rescale() { p->preview->msw_rescale(); diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 7c671f669..00ceb89bc 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -240,10 +240,6 @@ public: void copy_selection_to_clipboard(); void paste_from_clipboard(); -#if ENABLE_THUMBNAIL_GENERATOR - void generate_thumbnail(unsigned int w, unsigned int h, bool printable_only); -#endif // ENABLE_THUMBNAIL_GENERATOR - bool can_delete() const; bool can_delete_all() const; bool can_increase_instances() const; From d01532f4c682abd16a37cd0bff1f330911114d2b Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 24 Oct 2019 12:11:24 +0200 Subject: [PATCH 30/80] ENABLE_THUMBNAIL_GENERATOR -> Removed obsolete files --- src/slic3r/GUI/ThumbnailGenerator.cpp | 84 --------------------------- src/slic3r/GUI/ThumbnailGenerator.hpp | 40 ------------- 2 files changed, 124 deletions(-) delete mode 100644 src/slic3r/GUI/ThumbnailGenerator.cpp delete mode 100644 src/slic3r/GUI/ThumbnailGenerator.hpp diff --git a/src/slic3r/GUI/ThumbnailGenerator.cpp b/src/slic3r/GUI/ThumbnailGenerator.cpp deleted file mode 100644 index 634f9e61c..000000000 --- a/src/slic3r/GUI/ThumbnailGenerator.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "libslic3r/libslic3r.h" -#include "ThumbnailGenerator.hpp" - -#if ENABLE_THUMBNAIL_GENERATOR - -#include "Camera.hpp" -#include "3DScene.hpp" -#include "GUI.hpp" - -#include -#include -#include - -#include - -namespace Slic3r { -namespace GUI { - -void ThumbnailGenerator::reset() -{ - m_data.reset(); -} - -void ThumbnailGenerator::generate(const GLVolumePtrs& volumes, unsigned int w, unsigned int h, bool printable_only) -{ - std::cout << "Generated thumbnail " << w << "x" << h << std::endl; - - m_data.set(w, h); - render_and_store(volumes, printable_only); -} - -void ThumbnailGenerator::render_and_store(const GLVolumePtrs& volumes, bool printable_only) -{ - auto is_visible = [] (const GLVolume& v) -> bool { - bool ret = v.printable; - ret &= (!v.shader_outside_printer_detection_enabled || !v.is_outside); - return ret; - }; - - static const float orange[] = { 0.99f, 0.49f, 0.26f }; - static const float gray[] = { 0.64f, 0.64f, 0.64f }; - - GLVolumeConstPtrs visible_volumes; - - for (const GLVolume* vol : volumes) - { - if (!printable_only || is_visible(*vol)) - visible_volumes.push_back(vol); - } - - if (visible_volumes.empty()) - return; - - BoundingBoxf3 box; - for (const GLVolume* vol : visible_volumes) - { - box.merge(vol->transformed_bounding_box()); - } - - Camera camera; - camera.zoom_to_box(box, m_data.width, m_data.height); - camera.apply_viewport(0, 0, m_data.width, m_data.height); - camera.apply_view_matrix(); - camera.apply_projection(box); - - glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); - glsafe(::glEnable(GL_LIGHTING)); - glsafe(::glEnable(GL_DEPTH_TEST)); - - for (const GLVolume* vol : visible_volumes) - { - glsafe(::glColor3fv((vol->printable && !vol->is_outside) ? orange : gray)); - vol->render(); - } - - glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glDisable(GL_LIGHTING)); - glsafe(::glReadPixels(0, 0, m_data.width, m_data.height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)m_data.pixels.data())); -} - -} // namespace GUI -} // namespace Slic3r - -#endif // ENABLE_THUMBNAIL_GENERATOR diff --git a/src/slic3r/GUI/ThumbnailGenerator.hpp b/src/slic3r/GUI/ThumbnailGenerator.hpp deleted file mode 100644 index 20087b79b..000000000 --- a/src/slic3r/GUI/ThumbnailGenerator.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef slic3r_GUI_ThumbnailGenerator_hpp_ -#define slic3r_GUI_ThumbnailGenerator_hpp_ - -#if ENABLE_THUMBNAIL_GENERATOR - -#include "../libslic3r/GCode/ThumbnailData.hpp" - -namespace Slic3r { - - class GLVolume; - typedef std::vector GLVolumePtrs; - -namespace GUI { - - class ThumbnailGenerator - { - typedef std::vector GLVolumeConstPtrs; - - ThumbnailData m_data; - - public: - ThumbnailGenerator() { reset(); } - - void reset(); - - void generate(const GLVolumePtrs& volumes, unsigned int w, unsigned int h, bool printable_only); - - const ThumbnailData& get_data() const { return m_data; } - - private: - void render_and_store(const GLVolumePtrs& volumes, bool printable_only); - }; - -} // namespace GUI -} // namespace Slic3r - -#endif // ENABLE_THUMBNAIL_GENERATOR - -#endif // slic3r_GUI_ThumbnailGenerator_hpp_ - From 1baa3336633bd4b596179310c4e0306e94155e36 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 24 Oct 2019 12:30:19 +0200 Subject: [PATCH 31/80] ENABLE_THUMBNAIL_GENERATOR -> Fixed flickering of 3D view when generating thumbnail --- src/slic3r/GUI/GLCanvas3D.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 8d16187cb..a99b210ac 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1697,10 +1697,9 @@ void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, glsafe(::glDisable(GL_LIGHTING)); glsafe(::glReadPixels(0, 0, thumbnail_data.width, thumbnail_data.height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data())); - std::cout << "Generated thumbnail " << thumbnail_data.width << "x" << thumbnail_data.height << std::endl; - - // force a frame render to restore the default framebuffer - render(); + // restore the framebuffer size to avoid flickering on the 3D scene + const Size& cnv_size = get_canvas_size(); + m_camera.apply_viewport(0, 0, cnv_size.get_width(), cnv_size.get_height()); } #endif // ENABLE_THUMBNAIL_GENERATOR From 296d79abf7458719d51569fe785e519c32d57fec Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 24 Oct 2019 15:56:10 +0200 Subject: [PATCH 32/80] ENABLE_THUMBNAIL_GENERATOR -> Fixed thumbnail generation for SLA and 3mf --- src/libslic3r/SLAPrint.cpp | 5 +++++ src/slic3r/GUI/GLCanvas3D.cpp | 28 +++++++++++++++++++++++++--- src/slic3r/GUI/GLCanvas3D.hpp | 4 +++- src/slic3r/GUI/Plater.cpp | 27 ++++++++++++++++----------- 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 2a1ae74d7..2c080ec3d 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1372,7 +1372,12 @@ void SLAPrint::process() m_print_statistics.fast_layers_count = fast_layers; m_print_statistics.slow_layers_count = slow_layers; +#if ENABLE_THUMBNAIL_GENERATOR + // second argument set to -3 to differentiate it from the same call made into slice_supports() + m_report_status(*this, -3, "", SlicingStatus::RELOAD_SLA_PREVIEW); +#else m_report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); +#endif // ENABLE_THUMBNAIL_GENERATOR }; // Rasterizing the model objects, and their supports diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a99b210ac..914084bb6 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1647,7 +1647,7 @@ void GLCanvas3D::render() } #if ENABLE_THUMBNAIL_GENERATOR -void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only) +void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only) { auto is_visible = [](const GLVolume& v) -> bool { bool ret = v.printable; @@ -1664,8 +1664,11 @@ void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, for (GLVolume* vol : m_volumes.volumes) { - if (!printable_only || is_visible(*vol)) - visible_volumes.push_back(vol); + if (!vol->is_modifier && (!parts_only || (vol->composite_id.volume_id >= 0))) + { + if (!printable_only || is_visible(*vol)) + visible_volumes.push_back(vol); + } } if (visible_volumes.empty()) @@ -1697,6 +1700,25 @@ void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, glsafe(::glDisable(GL_LIGHTING)); glsafe(::glReadPixels(0, 0, thumbnail_data.width, thumbnail_data.height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data())); +#if 0 + // debug export of generated image + wxImage image(thumbnail_data.width, thumbnail_data.height); + image.InitAlpha(); + + for (unsigned int r = 0; r < thumbnail_data.height; ++r) + { + unsigned int rr = (thumbnail_data.height - 1 - r) * thumbnail_data.width; + for (unsigned int c = 0; c < thumbnail_data.width; ++c) + { + unsigned char* px = thumbnail_data.pixels.data() + 4 * (rr + c); + image.SetRGB((int)c, (int)r, px[0], px[1], px[2]); + image.SetAlpha((int)c, (int)r, px[3]); + } + } + + image.SaveFile("C:/test.png", wxBITMAP_TYPE_PNG); +#endif + // restore the framebuffer size to avoid flickering on the 3D scene const Size& cnv_size = get_canvas_size(); m_camera.apply_viewport(0, 0, cnv_size.get_width(), cnv_size.get_height()); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 611e9a932..5b06b6311 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -523,7 +523,9 @@ public: void render(); #if ENABLE_THUMBNAIL_GENERATOR - void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only); + // printable_only == false -> render also non printable volumes as grayed + // parts_only == false -> render also sla support and pad + void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only); #endif // ENABLE_THUMBNAIL_GENERATOR void select_all(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 0ebd208fa..008a6eaa3 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1928,7 +1928,7 @@ struct Plater::priv bool can_reload_from_disk() const; #if ENABLE_THUMBNAIL_GENERATOR - void generate_thumbnail(unsigned int w, unsigned int h, bool printable_only); + void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only); #endif // ENABLE_THUMBNAIL_GENERATOR void msw_rescale_object_menu(); @@ -3050,9 +3050,12 @@ bool Plater::priv::restart_background_process(unsigned int state) { // update thumbnail data if (this->printer_technology == ptFFF) - generate_thumbnail(THUMBNAIL_SIZE_FFF.first, THUMBNAIL_SIZE_FFF.second, true); + // for ptFFF we need to generate the thumbnail before the export of gcode starts + generate_thumbnail(this->thumbnail_data, THUMBNAIL_SIZE_FFF.first, THUMBNAIL_SIZE_FFF.second, true, true); else if (this->printer_technology == ptSLA) - generate_thumbnail(THUMBNAIL_SIZE_SLA.first, THUMBNAIL_SIZE_SLA.second, true); + // for ptSLA generate thumbnail without supports and pad (not yet calculated) + // to render also supports and pad see on_slicing_update() + generate_thumbnail(this->thumbnail_data, THUMBNAIL_SIZE_SLA.first, THUMBNAIL_SIZE_SLA.second, true, true); } #endif // ENABLE_THUMBNAIL_GENERATOR // The print is valid and it can be started. @@ -3392,13 +3395,14 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) } else if (evt.status.flags & PrintBase::SlicingStatus::RELOAD_SLA_PREVIEW) { // Update the SLA preview. Only called if not RELOAD_SLA_SUPPORT_POINTS, as the block above will refresh the preview anyways. this->preview->reload_print(); +/* #if ENABLE_THUMBNAIL_GENERATOR // update thumbnail data - if (this->printer_technology == ptFFF) - generate_thumbnail(THUMBNAIL_SIZE_FFF.first, THUMBNAIL_SIZE_FFF.second, true); - else if (this->printer_technology == ptSLA) - generate_thumbnail(THUMBNAIL_SIZE_SLA.first, THUMBNAIL_SIZE_SLA.second, true); + // for ptSLA generate the thumbnail after supports and pad have been calculated to have them rendered + if ((this->printer_technology == ptSLA) && (evt.status.percent == -3)) + generate_thumbnail(this->thumbnail_data, THUMBNAIL_SIZE_SLA.first, THUMBNAIL_SIZE_SLA.second, true, false); #endif // ENABLE_THUMBNAIL_GENERATOR +*/ } } @@ -3625,9 +3629,9 @@ bool Plater::priv::init_object_menu() } #if ENABLE_THUMBNAIL_GENERATOR -void Plater::priv::generate_thumbnail(unsigned int w, unsigned int h, bool printable_only) +void Plater::priv::generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only) { - view3D->get_canvas3d()->render_thumbnail(thumbnail_data, w, h, printable_only); + view3D->get_canvas3d()->render_thumbnail(data, w, h, printable_only, parts_only); } #endif // ENABLE_THUMBNAIL_GENERATOR @@ -4670,8 +4674,9 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) const std::string path_u8 = into_u8(path); wxBusyCursor wait; #if ENABLE_THUMBNAIL_GENERATOR - p->generate_thumbnail(THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, false); - if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, &p->thumbnail_data)) { + ThumbnailData thumbnail_data; + p->generate_thumbnail(thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, false, true); + if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, &thumbnail_data)) { #else if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) { #endif // ENABLE_THUMBNAIL_GENERATOR From f7d3cf063bdae284989286ef84e07869c42b9382 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 25 Oct 2019 08:19:02 +0200 Subject: [PATCH 33/80] ENABLE_THUMBNAIL_GENERATOR -> Added a comment --- src/slic3r/GUI/Plater.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 008a6eaa3..60a90f1f1 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3395,6 +3395,8 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) } else if (evt.status.flags & PrintBase::SlicingStatus::RELOAD_SLA_PREVIEW) { // Update the SLA preview. Only called if not RELOAD_SLA_SUPPORT_POINTS, as the block above will refresh the preview anyways. this->preview->reload_print(); + + // uncomment the following lines if you want to render into the thumbnail also supports and pad for SLA printer /* #if ENABLE_THUMBNAIL_GENERATOR // update thumbnail data From 982ed95a3560a9e7212efa7c0eaf5f764a2096ea Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 25 Oct 2019 08:57:13 +0200 Subject: [PATCH 34/80] ENABLE_THUMBNAIL_GENERATOR -> Save thumbnail size into gcode --- src/libslic3r/GCode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 2ea8eae1d..c96468415 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -954,7 +954,7 @@ void GCode::_do_export(Print &print, FILE *file) // Write thumbnail if ((thumbnail_data != nullptr) && thumbnail_data->is_valid()) { - _write(file, "\n;\n; thumbnail begin\n"); + _write_format(file, "\n;\n; thumbnail begin %dx%d\n", thumbnail_data->width, thumbnail_data->height); size_t row_size = 4 * thumbnail_data->width; for (int r = (int)thumbnail_data->height - 1; r >= 0 ; --r) From 843251c91fd802a9a27e71b9e03c2e2bb5c518c5 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 25 Oct 2019 09:04:58 +0200 Subject: [PATCH 35/80] ENABLE_THUMBNAIL_GENERATOR -> Do not render wipe tower into thumbnail --- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 914084bb6..703321c3c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1664,7 +1664,7 @@ void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, for (GLVolume* vol : m_volumes.volumes) { - if (!vol->is_modifier && (!parts_only || (vol->composite_id.volume_id >= 0))) + if (!vol->is_modifier && !vol->is_wipe_tower && (!parts_only || (vol->composite_id.volume_id >= 0))) { if (!printable_only || is_visible(*vol)) visible_volumes.push_back(vol); From de60b403471bbfc510c54dae78757131e5de3ed2 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 25 Oct 2019 12:18:10 +0200 Subject: [PATCH 36/80] ENABLE_THUMBNAIL_GENERATOR -> Thumbnail data saved into gcode using base64 encoding + debug code to extract thumbnails from gcode --- src/libslic3r/GCode.cpp | 12 ++--- src/slic3r/GUI/GUI_App.cpp | 86 ++++++++++++++++++++++++++++++++++++ src/slic3r/GUI/GUI_App.hpp | 5 +++ src/slic3r/GUI/MainFrame.cpp | 5 +++ 4 files changed, 102 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index c96468415..db493270a 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -21,6 +21,9 @@ #include #include #include +#if ENABLE_THUMBNAIL_GENERATOR +#include +#endif // ENABLE_THUMBNAIL_GENERATOR #include #include @@ -951,18 +954,15 @@ void GCode::_do_export(Print &print, FILE *file) _write_format(file, "; %s\n\n", Slic3r::header_slic3r_generated().c_str()); #if ENABLE_THUMBNAIL_GENERATOR - // Write thumbnail + // Write thumbnail using base64 encoding if ((thumbnail_data != nullptr) && thumbnail_data->is_valid()) { _write_format(file, "\n;\n; thumbnail begin %dx%d\n", thumbnail_data->width, thumbnail_data->height); size_t row_size = 4 * thumbnail_data->width; - for (int r = (int)thumbnail_data->height - 1; r >= 0 ; --r) + for (int r = (int)thumbnail_data->height - 1; r >= 0; --r) { - _write(file, "; "); - const void* data_ptr = thumbnail_data->pixels.data() + r * row_size; - ::fwrite((const void*)data_ptr, 1, row_size, file); - _write(file, "\n"); + _write_format(file, "; %s\n", boost::beast::detail::base64_encode((const std::uint8_t*)(thumbnail_data->pixels.data() + r * row_size), row_size).c_str()); } _write(file, "; thumbnail end\n;\n\n"); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index b5e70c0a1..0b2244d65 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -51,6 +51,10 @@ #include #endif // __WXMSW__ +#if ENABLE_THUMBNAIL_GENERATOR +#include +#endif // ENABLE_THUMBNAIL_GENERATOR + namespace Slic3r { namespace GUI { @@ -1082,6 +1086,88 @@ bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage return res; } +#if ENABLE_THUMBNAIL_GENERATOR +void GUI_App::gcode_thumbnails_debug() +{ + const std::string BEGIN_MASK = "; thumbnail begin"; + const std::string END_MASK = "; thumbnail end"; + std::string gcode_line; + bool reading_image = false; + unsigned int width = 0; + unsigned int height = 0; + + wxFileDialog dialog(GetTopWindow(), _(L("Select a gcode file:")), "", "", "G-code files (*.gcode)|*.gcode;*.GCODE;", wxFD_OPEN | wxFD_FILE_MUST_EXIST); + if (dialog.ShowModal() != wxID_OK) + return; + + std::string in_filename = into_u8(dialog.GetPath()); + std::string out_path = boost::filesystem::path(in_filename).remove_filename().append(L"thumbnail").string(); + + boost::nowide::ifstream file(in_filename.c_str()); + std::vector rows; + if (file.good()) + { + while (std::getline(file, gcode_line)) + { + if (file.good()) + { + if (boost::starts_with(gcode_line, BEGIN_MASK)) + { + reading_image = true; + gcode_line = gcode_line.substr(BEGIN_MASK.length() + 1); + std::string::size_type x_pos = gcode_line.find('x'); + std::string width_str = gcode_line.substr(0, x_pos); + width = (unsigned int)::atoi(width_str.c_str()); + std::string height_str = gcode_line.substr(x_pos + 1); + height = (unsigned int)::atoi(height_str.c_str()); + } + else if (reading_image && boost::starts_with(gcode_line, END_MASK)) + { + if ((unsigned int)rows.size() == height) + { + 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) + { + void* image_ptr = (void*)(thumbnail.data() + r * width * 4); + ::memcpy(image_ptr, (const void*)decoded_row.c_str(), width * 4); + } + } + + wxImage image(width, height); + image.InitAlpha(); + + for (unsigned int r = 0; r < height; ++r) + { + unsigned int rr = r * width; + for (unsigned int c = 0; c < width; ++c) + { + unsigned char* px = thumbnail.data() + 4 * (rr + c); + image.SetRGB((int)c, (int)r, px[0], px[1], px[2]); + image.SetAlpha((int)c, (int)r, px[3]); + } + } + + image.SaveFile(out_path + std::to_string(width) + "x" + std::to_string(height) + ".png", wxBITMAP_TYPE_PNG); + } + + reading_image = false; + width = 0; + height = 0; + rows.clear(); + } + else if (reading_image) + rows.push_back(gcode_line.substr(2)); + } + } + + file.close(); + } +} +#endif // ENABLE_THUMBNAIL_GENERATOR + void GUI_App::window_pos_save(wxTopLevelWindow* window, const std::string &name) { if (name.empty()) { return; } diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index c5ddc0152..f9f907e42 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -189,6 +189,11 @@ public: void open_web_page_localized(const std::string &http_address); bool run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage start_page = ConfigWizard::SP_WELCOME); +#if ENABLE_THUMBNAIL_GENERATOR + // temporary and debug only -> extract thumbnails from selected gcode and save them as png files + void gcode_thumbnails_debug(); +#endif // ENABLE_THUMBNAIL_GENERATOR + private: bool on_init_inner(); void window_pos_save(wxTopLevelWindow* window, const std::string &name); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 6f39db86d..56eda2c0d 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -682,6 +682,11 @@ void MainFrame::init_menubar() helpMenu->AppendSeparator(); append_menu_item(helpMenu, wxID_ANY, _(L("Keyboard Shortcuts")) + sep + "&?", _(L("Show the list of the keyboard shortcuts")), [this](wxCommandEvent&) { wxGetApp().keyboard_shortcuts(); }); +#if ENABLE_THUMBNAIL_GENERATOR + helpMenu->AppendSeparator(); + append_menu_item(helpMenu, wxID_ANY, _(L("DEBUG gcode thumbnails")), _(L("DEBUG ONLY - read the selected gcode file and generates png for the contained thumbnails")), + [this](wxCommandEvent&) { wxGetApp().gcode_thumbnails_debug(); }); +#endif // ENABLE_THUMBNAIL_GENERATOR } // menubar From 2d5c28d6d16b05cde3112b3ee4e92db634c975e0 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 25 Oct 2019 13:59:13 +0200 Subject: [PATCH 37/80] ENABLE_THUMBNAIL_GENERATOR -> Allow for multiple thumbnails into gcode and sl1 files --- src/libslic3r/GCode.cpp | 28 ++++++++++------ src/libslic3r/GCode.hpp | 4 +-- src/libslic3r/Print.cpp | 2 +- src/libslic3r/Print.hpp | 2 +- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 22 +++++++++--- src/slic3r/GUI/BackgroundSlicingProcess.hpp | 6 ++-- src/slic3r/GUI/Plater.cpp | 37 ++++++++++++++++----- 7 files changed, 70 insertions(+), 31 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index db493270a..92f733787 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -659,7 +659,7 @@ std::vector>> GCode::collec } #if ENABLE_THUMBNAIL_GENERATOR -void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, const ThumbnailData* thumbnail_data) +void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, const std::vector* thumbnail_data) #else void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_data) #endif // ENABLE_THUMBNAIL_GENERATOR @@ -757,7 +757,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ } #if ENABLE_THUMBNAIL_GENERATOR -void GCode::_do_export(Print& print, FILE* file, const ThumbnailData* thumbnail_data) +void GCode::_do_export(Print& print, FILE* file, const std::vector* thumbnail_data) #else void GCode::_do_export(Print &print, FILE *file) #endif // ENABLE_THUMBNAIL_GENERATOR @@ -954,18 +954,24 @@ void GCode::_do_export(Print &print, FILE *file) _write_format(file, "; %s\n\n", Slic3r::header_slic3r_generated().c_str()); #if ENABLE_THUMBNAIL_GENERATOR - // Write thumbnail using base64 encoding - if ((thumbnail_data != nullptr) && thumbnail_data->is_valid()) + // Write thumbnails using base64 encoding + if (thumbnail_data != nullptr) { - _write_format(file, "\n;\n; thumbnail begin %dx%d\n", thumbnail_data->width, thumbnail_data->height); - - size_t row_size = 4 * thumbnail_data->width; - for (int r = (int)thumbnail_data->height - 1; r >= 0; --r) + for (const ThumbnailData& data : *thumbnail_data) { - _write_format(file, "; %s\n", boost::beast::detail::base64_encode((const std::uint8_t*)(thumbnail_data->pixels.data() + r * row_size), row_size).c_str()); - } + if (data.is_valid()) + { + _write_format(file, "\n;\n; thumbnail begin %dx%d\n", data.width, data.height); - _write(file, "; thumbnail end\n;\n\n"); + size_t row_size = 4 * data.width; + for (int r = (int)data.height - 1; r >= 0; --r) + { + _write_format(file, "; %s\n", boost::beast::detail::base64_encode((const std::uint8_t*)(data.pixels.data() + r * row_size), row_size).c_str()); + } + + _write(file, "; thumbnail end\n;\n\n"); + } + } } #endif // ENABLE_THUMBNAIL_GENERATOR diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 8116d06fc..3183e8883 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -166,7 +166,7 @@ public: // throws std::runtime_exception on error, // throws CanceledException through print->throw_if_canceled(). #if ENABLE_THUMBNAIL_GENERATOR - void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, const ThumbnailData* thumbnail_data = nullptr); + void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, const std::vector* thumbnail_data = nullptr); #else void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr); #endif // ENABLE_THUMBNAIL_GENERATOR @@ -198,7 +198,7 @@ public: protected: #if ENABLE_THUMBNAIL_GENERATOR - void _do_export(Print& print, FILE* file, const ThumbnailData* thumbnail_data); + void _do_export(Print& print, FILE* file, const std::vector* thumbnail_data); #else void _do_export(Print &print, FILE *file); #endif //ENABLE_THUMBNAIL_GENERATOR diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index b2ed87ca0..74e541451 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1537,7 +1537,7 @@ void Print::process() // write error into the G-code, cannot execute post-processing scripts). // It is up to the caller to show an error message. #if ENABLE_THUMBNAIL_GENERATOR -std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, const ThumbnailData* thumbnail_data) +std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, const std::vector* thumbnail_data) #else std::string Print::export_gcode(const std::string &path_template, GCodePreviewData *preview_data) #endif // ENABLE_THUMBNAIL_GENERATOR diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index aedeeff18..7e7f875b0 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -309,7 +309,7 @@ public: // Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file. // If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r). #if ENABLE_THUMBNAIL_GENERATOR - std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, const ThumbnailData* thumbnail_data = nullptr); + std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, const std::vector* thumbnail_data = nullptr); #else std::string export_gcode(const std::string &path_template, GCodePreviewData *preview_data); #endif // ENABLE_THUMBNAIL_GENERATOR diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index cedeab910..18f593d77 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -120,7 +120,7 @@ static void write_thumbnail(Zipper& zipper, const ThumbnailData& data) 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) { - zipper.add_entry("thumbnail/thumbnail.png", (const std::uint8_t*)png_data, png_size); + zipper.add_entry("thumbnail/thumbnail" + std::to_string(data.width) + "x" + std::to_string(data.height) + ".png", (const std::uint8_t*)png_data, png_size); mz_free(png_data); } } @@ -138,8 +138,14 @@ void BackgroundSlicingProcess::process_sla() m_sla_print->export_raster(zipper); #if ENABLE_THUMBNAIL_GENERATOR - if ((m_thumbnail_data != nullptr) && m_thumbnail_data->is_valid()) - write_thumbnail(zipper, *m_thumbnail_data); + if (m_thumbnail_data != nullptr) + { + for (const ThumbnailData& data : *m_thumbnail_data) + { + if (data.is_valid()) + write_thumbnail(zipper, data); + } + } #endif // ENABLE_THUMBNAIL_GENERATOR zipper.finalize(); @@ -458,8 +464,14 @@ void BackgroundSlicingProcess::prepare_upload() Zipper zipper{source_path.string()}; m_sla_print->export_raster(zipper, m_upload_job.upload_data.upload_path.string()); #if ENABLE_THUMBNAIL_GENERATOR - if ((m_thumbnail_data != nullptr) && m_thumbnail_data->is_valid()) - write_thumbnail(zipper, *m_thumbnail_data); + if (m_thumbnail_data != nullptr) + { + for (const ThumbnailData& data : *m_thumbnail_data) + { + if (data.is_valid()) + write_thumbnail(zipper, data); + } + } #endif // ENABLE_THUMBNAIL_GENERATOR zipper.finalize(); } diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index e51a4e961..bf8cbc235 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -53,7 +53,7 @@ public: void set_sla_print(SLAPrint *print) { m_sla_print = print; } void set_gcode_preview_data(GCodePreviewData *gpd) { m_gcode_preview_data = gpd; } #if ENABLE_THUMBNAIL_GENERATOR - void set_thumbnail_data(const ThumbnailData* data) { m_thumbnail_data = data; } + void set_thumbnail_data(const std::vector* data) { m_thumbnail_data = data; } #endif // ENABLE_THUMBNAIL_GENERATOR // The following wxCommandEvent will be sent to the UI thread / Platter window, when the slicing is finished @@ -159,8 +159,8 @@ private: // Data structure, to which the G-code export writes its annotations. GCodePreviewData *m_gcode_preview_data = nullptr; #if ENABLE_THUMBNAIL_GENERATOR - // Data structure, used to write thumbnail into gcode. - const ThumbnailData *m_thumbnail_data = nullptr; + // Data structures, used to write thumbnails into gcode. + const std::vector* m_thumbnail_data = nullptr; #endif // ENABLE_THUMBNAIL_GENERATOR // Temporary G-code, there is one defined for the BackgroundSlicingProcess, differentiated from the other processes by a process ID. std::string m_temp_output_path; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 60a90f1f1..ccfa46abe 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -86,8 +86,8 @@ using Slic3r::Preset; using Slic3r::PrintHostJob; #if ENABLE_THUMBNAIL_GENERATOR -static const std::pair THUMBNAIL_SIZE_FFF = { 128, 128 }; -static const std::pair THUMBNAIL_SIZE_SLA = { 256, 256 }; +static const std::vector < std::pair> THUMBNAIL_SIZE_FFF = { { 240, 320 }, { 220, 165 }, { 16, 16 } }; +static const std::vector> THUMBNAIL_SIZE_SLA = { { 800, 480 } }; static const std::pair THUMBNAIL_SIZE_3MF = { 256, 256 }; #endif // ENABLE_THUMBNAIL_GENERATOR @@ -1371,7 +1371,7 @@ struct Plater::priv PrinterTechnology printer_technology = ptFFF; Slic3r::GCodePreviewData gcode_preview_data; #if ENABLE_THUMBNAIL_GENERATOR - Slic3r::ThumbnailData thumbnail_data; + std::vector thumbnail_data; #endif // ENABLE_THUMBNAIL_GENERATOR // GUI elements @@ -3050,12 +3050,26 @@ bool Plater::priv::restart_background_process(unsigned int state) { // update thumbnail data if (this->printer_technology == ptFFF) - // for ptFFF we need to generate the thumbnail before the export of gcode starts - generate_thumbnail(this->thumbnail_data, THUMBNAIL_SIZE_FFF.first, THUMBNAIL_SIZE_FFF.second, true, true); + { + // for ptFFF we need to generate the thumbnails before the export of gcode starts + this->thumbnail_data.clear(); + for (const std::pair& size : THUMBNAIL_SIZE_FFF) + { + this->thumbnail_data.push_back(ThumbnailData()); + generate_thumbnail(this->thumbnail_data.back(), size.first, size.second, true, true); + } + } else if (this->printer_technology == ptSLA) - // for ptSLA generate thumbnail without supports and pad (not yet calculated) + { + // for ptSLA generate thumbnails without supports and pad (not yet calculated) // to render also supports and pad see on_slicing_update() - generate_thumbnail(this->thumbnail_data, THUMBNAIL_SIZE_SLA.first, THUMBNAIL_SIZE_SLA.second, true, true); + this->thumbnail_data.clear(); + for (const std::pair& size : THUMBNAIL_SIZE_SLA) + { + this->thumbnail_data.push_back(ThumbnailData()); + generate_thumbnail(this->thumbnail_data.back(), size.first, size.second, true, true); + } + } } #endif // ENABLE_THUMBNAIL_GENERATOR // The print is valid and it can be started. @@ -3402,7 +3416,14 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) // update thumbnail data // for ptSLA generate the thumbnail after supports and pad have been calculated to have them rendered if ((this->printer_technology == ptSLA) && (evt.status.percent == -3)) - generate_thumbnail(this->thumbnail_data, THUMBNAIL_SIZE_SLA.first, THUMBNAIL_SIZE_SLA.second, true, false); + { + this->thumbnail_data.clear(); + for (const std::pair& size : THUMBNAIL_SIZE_SLA) + { + this->thumbnail_data.push_back(ThumbnailData()); + generate_thumbnail(this->thumbnail_data.back(), size.first, size.second, true, false); + } + } #endif // ENABLE_THUMBNAIL_GENERATOR */ } From 24aed8eb71ab3d983589d42fba347664466b223d Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 25 Oct 2019 14:32:31 +0200 Subject: [PATCH 38/80] ENABLE_THUMBNAIL_GENERATOR -> Added missing include --- src/slic3r/GUI/GUI_App.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 0b2244d65..c35985f11 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -53,6 +53,7 @@ #if ENABLE_THUMBNAIL_GENERATOR #include +#include #endif // ENABLE_THUMBNAIL_GENERATOR namespace Slic3r { From f36dd833d2fecebe86d351fe0f2933e1c920673c Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 29 Oct 2019 07:32:15 +0100 Subject: [PATCH 39/80] ENABLE_THUMBNAIL_GENERATOR -> Reduce thumbnail size if exceeding 3D scene canvas size --- src/slic3r/GUI/GLCanvas3D.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 703321c3c..139ee5fa4 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1658,6 +1658,16 @@ void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, static const float orange[] = { 0.99f, 0.49f, 0.26f }; static const float gray[] = { 0.64f, 0.64f, 0.64f }; + const Size& cnv_size = get_canvas_size(); + unsigned int cnv_w = (unsigned int)cnv_size.get_width(); + unsigned int cnv_h = (unsigned int)cnv_size.get_height(); + if ((w > cnv_w) || (h > cnv_h)) + { + float ratio = std::min((float)cnv_w / (float)w, (float)cnv_h / (float)h); + w = (unsigned int)(ratio * (float)w); + h = (unsigned int)(ratio * (float)h); + } + thumbnail_data.set(w, h); GLVolumePtrs visible_volumes; @@ -1720,7 +1730,6 @@ void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, #endif // restore the framebuffer size to avoid flickering on the 3D scene - const Size& cnv_size = get_canvas_size(); m_camera.apply_viewport(0, 0, cnv_size.get_width(), cnv_size.get_height()); } #endif // ENABLE_THUMBNAIL_GENERATOR From 3ff3eed2b1e0751e823559542975e63d51f62010 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 29 Oct 2019 10:27:51 +0100 Subject: [PATCH 40/80] ENABLE_THUMBNAIL_GENERATOR -> Use off-screen framebuffer to render the thumbnail on graphic cards supporting it --- src/slic3r/GUI/GLCanvas3D.cpp | 219 +++++++++++++++++---------- src/slic3r/GUI/GLCanvas3D.hpp | 6 + src/slic3r/GUI/GLCanvas3DManager.cpp | 6 + src/slic3r/GUI/GLCanvas3DManager.hpp | 2 + 4 files changed, 151 insertions(+), 82 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 139ee5fa4..b40a83682 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1649,88 +1649,10 @@ void GLCanvas3D::render() #if ENABLE_THUMBNAIL_GENERATOR void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only) { - auto is_visible = [](const GLVolume& v) -> bool { - bool ret = v.printable; - ret &= (!v.shader_outside_printer_detection_enabled || !v.is_outside); - return ret; - }; - - static const float orange[] = { 0.99f, 0.49f, 0.26f }; - static const float gray[] = { 0.64f, 0.64f, 0.64f }; - - const Size& cnv_size = get_canvas_size(); - unsigned int cnv_w = (unsigned int)cnv_size.get_width(); - unsigned int cnv_h = (unsigned int)cnv_size.get_height(); - if ((w > cnv_w) || (h > cnv_h)) - { - float ratio = std::min((float)cnv_w / (float)w, (float)cnv_h / (float)h); - w = (unsigned int)(ratio * (float)w); - h = (unsigned int)(ratio * (float)h); - } - - thumbnail_data.set(w, h); - - GLVolumePtrs visible_volumes; - - for (GLVolume* vol : m_volumes.volumes) - { - if (!vol->is_modifier && !vol->is_wipe_tower && (!parts_only || (vol->composite_id.volume_id >= 0))) - { - if (!printable_only || is_visible(*vol)) - visible_volumes.push_back(vol); - } - } - - if (visible_volumes.empty()) - return; - - BoundingBoxf3 box; - for (const GLVolume* vol : visible_volumes) - { - box.merge(vol->transformed_bounding_box()); - } - - Camera camera; - camera.zoom_to_box(box, thumbnail_data.width, thumbnail_data.height); - camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height); - camera.apply_view_matrix(); - camera.apply_projection(box); - - glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); - glsafe(::glEnable(GL_LIGHTING)); - glsafe(::glEnable(GL_DEPTH_TEST)); - - for (const GLVolume* vol : visible_volumes) - { - glsafe(::glColor3fv((vol->printable && !vol->is_outside) ? orange : gray)); - vol->render(); - } - - glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glDisable(GL_LIGHTING)); - glsafe(::glReadPixels(0, 0, thumbnail_data.width, thumbnail_data.height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data())); - -#if 0 - // debug export of generated image - wxImage image(thumbnail_data.width, thumbnail_data.height); - image.InitAlpha(); - - for (unsigned int r = 0; r < thumbnail_data.height; ++r) - { - unsigned int rr = (thumbnail_data.height - 1 - r) * thumbnail_data.width; - for (unsigned int c = 0; c < thumbnail_data.width; ++c) - { - unsigned char* px = thumbnail_data.pixels.data() + 4 * (rr + c); - image.SetRGB((int)c, (int)r, px[0], px[1], px[2]); - image.SetAlpha((int)c, (int)r, px[3]); - } - } - - image.SaveFile("C:/test.png", wxBITMAP_TYPE_PNG); -#endif - - // restore the framebuffer size to avoid flickering on the 3D scene - m_camera.apply_viewport(0, 0, cnv_size.get_width(), cnv_size.get_height()); + if (GLCanvas3DManager::are_framebuffers_supported()) + _render_thumbnail_framebuffer(thumbnail_data, w, h, printable_only, parts_only); + else + _render_thumbnail_legacy(thumbnail_data, w, h, printable_only, parts_only); } #endif // ENABLE_THUMBNAIL_GENERATOR @@ -3644,6 +3566,139 @@ void GLCanvas3D::_render_undo_redo_stack(const bool is_undo, float pos_x) imgui->end(); } +#if ENABLE_THUMBNAIL_GENERATOR +static void render_volumes_in_thumbnail(const GLVolumePtrs& volumes, ThumbnailData& thumbnail_data, bool printable_only, bool parts_only) +{ + auto is_visible = [](const GLVolume& v) -> bool + { + bool ret = v.printable; + ret &= (!v.shader_outside_printer_detection_enabled || !v.is_outside); + return ret; + }; + + static const float orange[] = { 0.99f, 0.49f, 0.26f }; + static const float gray[] = { 0.64f, 0.64f, 0.64f }; + + GLVolumePtrs visible_volumes; + + for (GLVolume* vol : volumes) + { + if (!vol->is_modifier && !vol->is_wipe_tower && (!parts_only || (vol->composite_id.volume_id >= 0))) + { + if (!printable_only || is_visible(*vol)) + visible_volumes.push_back(vol); + } + } + + if (visible_volumes.empty()) + return; + + BoundingBoxf3 box; + for (const GLVolume* vol : visible_volumes) + { + box.merge(vol->transformed_bounding_box()); + } + + Camera camera; + camera.zoom_to_box(box, thumbnail_data.width, thumbnail_data.height); + camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height); + camera.apply_view_matrix(); + camera.apply_projection(box); + + glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); + glsafe(::glEnable(GL_LIGHTING)); + glsafe(::glEnable(GL_DEPTH_TEST)); + + for (const GLVolume* vol : visible_volumes) + { + glsafe(::glColor3fv((vol->printable && !vol->is_outside) ? orange : gray)); + vol->render(); + } + + glsafe(::glDisable(GL_DEPTH_TEST)); + glsafe(::glDisable(GL_LIGHTING)); + glsafe(::glReadPixels(0, 0, thumbnail_data.width, thumbnail_data.height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data())); + +#if 0 + // debug export of generated image + wxImage image(thumbnail_data.width, thumbnail_data.height); + image.InitAlpha(); + + for (unsigned int r = 0; r < thumbnail_data.height; ++r) + { + unsigned int rr = (thumbnail_data.height - 1 - r) * thumbnail_data.width; + for (unsigned int c = 0; c < thumbnail_data.width; ++c) + { + unsigned char* px = thumbnail_data.pixels.data() + 4 * (rr + c); + image.SetRGB((int)c, (int)r, px[0], px[1], px[2]); + image.SetAlpha((int)c, (int)r, px[3]); + } + } + + image.SaveFile("C:/prusa/test/test.png", wxBITMAP_TYPE_PNG); +#endif +} + +void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only) +{ + thumbnail_data.set(w, h); + if (!thumbnail_data.is_valid()) + return; + + GLuint fbo; + glsafe(::glGenFramebuffers(1, &fbo)); + glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, fbo)); + + GLuint tex; + glsafe(::glGenTextures(1, &tex)); + glsafe(::glBindTexture(GL_TEXTURE_2D, tex)); + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0)); + + GLuint depth; + glsafe(::glGenRenderbuffers(1, &depth)); + glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, depth)); + glsafe(::glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h)); + glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth)); + + GLenum drawBufs[] = { GL_COLOR_ATTACHMENT0 }; + glsafe(::glDrawBuffers(1, drawBufs)); + + if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) + render_volumes_in_thumbnail(m_volumes.volumes, thumbnail_data, printable_only, parts_only); + + glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0)); + glsafe(::glDeleteRenderbuffers(1, &depth)); + glsafe(::glDeleteTextures(1, &tex)); + glsafe(::glDeleteFramebuffers(1, &fbo)); +} + +void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only) +{ + // check that thumbnail size does not exceed the default framebuffer size + const Size& cnv_size = get_canvas_size(); + unsigned int cnv_w = (unsigned int)cnv_size.get_width(); + unsigned int cnv_h = (unsigned int)cnv_size.get_height(); + if ((w > cnv_w) || (h > cnv_h)) + { + float ratio = std::min((float)cnv_w / (float)w, (float)cnv_h / (float)h); + w = (unsigned int)(ratio * (float)w); + h = (unsigned int)(ratio * (float)h); + } + + thumbnail_data.set(w, h); + if (!thumbnail_data.is_valid()) + return; + + render_volumes_in_thumbnail(m_volumes.volumes, thumbnail_data, printable_only, parts_only); + + // restore the default framebuffer size to avoid flickering on the 3D scene + m_camera.apply_viewport(0, 0, cnv_size.get_width(), cnv_size.get_height()); +} +#endif // ENABLE_THUMBNAIL_GENERATOR + bool GLCanvas3D::_init_toolbars() { if (!_init_main_toolbar()) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 5b06b6311..fce4661a4 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -674,6 +674,12 @@ private: void _render_sla_slices() const; void _render_selection_sidebar_hints() const; void _render_undo_redo_stack(const bool is_undo, float pos_x); +#if ENABLE_THUMBNAIL_GENERATOR + // render thumbnail using an off-screen framebuffer + void _render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only); + // render thumbnail using the default framebuffer + void _render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only); +#endif // ENABLE_THUMBNAIL_GENERATOR void _update_volumes_hover_state() const; diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index 9690e8a8d..03daa0b00 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -189,6 +189,7 @@ std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool exten GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::MS_Unknown; bool GLCanvas3DManager::s_compressed_textures_supported = false; +bool GLCanvas3DManager::s_framebuffers_supported = false; GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info; GLCanvas3DManager::GLCanvas3DManager() @@ -269,6 +270,11 @@ void GLCanvas3DManager::init_gl() else s_compressed_textures_supported = false; + if (s_gl_info.is_version_greater_or_equal_to(3, 0) && GLEW_ARB_framebuffer_object) + s_framebuffers_supported = true; + else + s_framebuffers_supported = false; + if (! s_gl_info.is_version_greater_or_equal_to(2, 0)) { // Complain about the OpenGL version. wxString message = wxString::Format( diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp index 760266a27..a2e35f811 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -77,6 +77,7 @@ private: bool m_gl_initialized; static EMultisampleState s_multisample; static bool s_compressed_textures_supported; + static bool s_framebuffers_supported; public: GLCanvas3DManager(); @@ -97,6 +98,7 @@ public: static bool can_multisample() { return s_multisample == MS_Enabled; } static bool are_compressed_textures_supported() { return s_compressed_textures_supported; } + static bool are_framebuffers_supported() { return s_framebuffers_supported; } static wxGLCanvas* create_wxglcanvas(wxWindow *parent); From a7b4b232e95bbe2751631dcf2ef1bd192c4a18cf Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 29 Oct 2019 14:45:15 +0100 Subject: [PATCH 41/80] ENABLE_THUMBNAIL_GENERATOR -> Use multisampling when generating thumbnail using off-screen framebuffer --- src/slic3r/GUI/GLCanvas3D.cpp | 152 +++++++++++++++++++++++++--------- 1 file changed, 114 insertions(+), 38 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index b40a83682..ae2f4989f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3567,6 +3567,29 @@ void GLCanvas3D::_render_undo_redo_stack(const bool is_undo, float pos_x) } #if ENABLE_THUMBNAIL_GENERATOR +#define ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT 0 +#if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT +static void debug_output_thumbnail(const ThumbnailData& thumbnail_data) +{ + // debug export of generated image + wxImage image(thumbnail_data.width, thumbnail_data.height); + image.InitAlpha(); + + for (unsigned int r = 0; r < thumbnail_data.height; ++r) + { + unsigned int rr = (thumbnail_data.height - 1 - r) * thumbnail_data.width; + for (unsigned int c = 0; c < thumbnail_data.width; ++c) + { + unsigned char* px = (unsigned char*)thumbnail_data.pixels.data() + 4 * (rr + c); + image.SetRGB((int)c, (int)r, px[0], px[1], px[2]); + image.SetAlpha((int)c, (int)r, px[3]); + } + } + + image.SaveFile("C:/prusa/test/test.png", wxBITMAP_TYPE_PNG); +} +#endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT + static void render_volumes_in_thumbnail(const GLVolumePtrs& volumes, ThumbnailData& thumbnail_data, bool printable_only, bool parts_only) { auto is_visible = [](const GLVolume& v) -> bool @@ -3617,26 +3640,6 @@ static void render_volumes_in_thumbnail(const GLVolumePtrs& volumes, ThumbnailDa glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_LIGHTING)); - glsafe(::glReadPixels(0, 0, thumbnail_data.width, thumbnail_data.height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data())); - -#if 0 - // debug export of generated image - wxImage image(thumbnail_data.width, thumbnail_data.height); - image.InitAlpha(); - - for (unsigned int r = 0; r < thumbnail_data.height; ++r) - { - unsigned int rr = (thumbnail_data.height - 1 - r) * thumbnail_data.width; - for (unsigned int c = 0; c < thumbnail_data.width; ++c) - { - unsigned char* px = thumbnail_data.pixels.data() + 4 * (rr + c); - image.SetRGB((int)c, (int)r, px[0], px[1], px[2]); - image.SetAlpha((int)c, (int)r, px[3]); - } - } - - image.SaveFile("C:/prusa/test/test.png", wxBITMAP_TYPE_PNG); -#endif } void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only) @@ -3645,34 +3648,102 @@ void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, un if (!thumbnail_data.is_valid()) return; - GLuint fbo; - glsafe(::glGenFramebuffers(1, &fbo)); - glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, fbo)); + bool multisample = m_multisample_allowed; + if (multisample) + glsafe(::glEnable(GL_MULTISAMPLE)); - GLuint tex; - glsafe(::glGenTextures(1, &tex)); - glsafe(::glBindTexture(GL_TEXTURE_2D, tex)); - glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr)); - glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0)); + GLint max_samples; + glsafe(::glGetIntegerv(GL_MAX_SAMPLES, &max_samples)); + GLsizei num_samples = max_samples / 2; - GLuint depth; - glsafe(::glGenRenderbuffers(1, &depth)); - glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, depth)); - glsafe(::glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h)); - glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth)); + GLuint render_fbo; + glsafe(::glGenFramebuffers(1, &render_fbo)); + glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, render_fbo)); + + GLuint render_tex = 0; + GLuint render_tex_buffer = 0; + if (multisample) + { + // use renderbuffer instead of texture to avoid the need to use glTexImage2DMultisample which is available only since OpenGL 3.2 + glsafe(::glGenRenderbuffers(1, &render_tex_buffer)); + glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, render_tex_buffer)); + glsafe(::glRenderbufferStorageMultisample(GL_RENDERBUFFER, num_samples, GL_RGBA8, w, h)); + glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, render_tex_buffer)); + } + else + { + glsafe(::glGenTextures(1, &render_tex)); + glsafe(::glBindTexture(GL_TEXTURE_2D, render_tex)); + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, render_tex, 0)); + } + + GLuint render_depth; + glsafe(::glGenRenderbuffers(1, &render_depth)); + glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, render_depth)); + if (multisample) + glsafe(::glRenderbufferStorageMultisample(GL_RENDERBUFFER, num_samples, GL_DEPTH_COMPONENT24, w, h)); + else + glsafe(::glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h)); + + glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, render_depth)); GLenum drawBufs[] = { GL_COLOR_ATTACHMENT0 }; glsafe(::glDrawBuffers(1, drawBufs)); if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) + { render_volumes_in_thumbnail(m_volumes.volumes, thumbnail_data, printable_only, parts_only); + if (multisample) + { + GLuint resolve_fbo; + glsafe(::glGenFramebuffers(1, &resolve_fbo)); + glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, resolve_fbo)); + + GLuint resolve_tex; + glsafe(::glGenTextures(1, &resolve_tex)); + glsafe(::glBindTexture(GL_TEXTURE_2D, resolve_tex)); + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolve_tex, 0)); + + glsafe(::glDrawBuffers(1, drawBufs)); + + if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) + { + glsafe(::glBindFramebuffer(GL_READ_FRAMEBUFFER, render_fbo)); + glsafe(::glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo)); + glsafe(::glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR)); + + glsafe(::glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo)); + glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data())); + } + + glsafe(::glDeleteTextures(1, &resolve_tex)); + glsafe(::glDeleteFramebuffers(1, &resolve_fbo)); + } + else + glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data())); + +#if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT + debug_output_thumbnail(thumbnail_data); +#endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT + } + glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0)); - glsafe(::glDeleteRenderbuffers(1, &depth)); - glsafe(::glDeleteTextures(1, &tex)); - glsafe(::glDeleteFramebuffers(1, &fbo)); + glsafe(::glDeleteRenderbuffers(1, &render_depth)); + if (render_tex_buffer != 0) + glsafe(::glDeleteRenderbuffers(1, &render_tex_buffer)); + if (render_tex != 0) + glsafe(::glDeleteTextures(1, &render_tex)); + glsafe(::glDeleteFramebuffers(1, &render_fbo)); + + if (multisample) + glsafe(::glDisable(GL_MULTISAMPLE)); } void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only) @@ -3694,6 +3765,11 @@ void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigne render_volumes_in_thumbnail(m_volumes.volumes, thumbnail_data, printable_only, parts_only); + glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data())); +#if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT + debug_output_thumbnail(thumbnail_data); +#endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT + // restore the default framebuffer size to avoid flickering on the 3D scene m_camera.apply_viewport(0, 0, cnv_size.get_width(), cnv_size.get_height()); } From f6453aab1b1569fd5ac7df02232ff4dff37159a7 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 30 Oct 2019 10:09:58 +0100 Subject: [PATCH 42/80] ENABLE_THUMBNAIL_GENERATOR -> Fixed potential race condition when generating thumbnails --- src/libslic3r/GCode.cpp | 1 + src/slic3r/GUI/Plater.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 92f733787..ebb82cfb2 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -971,6 +971,7 @@ void GCode::_do_export(Print &print, FILE *file) _write(file, "; thumbnail end\n;\n\n"); } + print.throw_if_canceled(); } } #endif // ENABLE_THUMBNAIL_GENERATOR diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index f56d6fc27..464093712 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3046,7 +3046,8 @@ bool Plater::priv::restart_background_process(unsigned int state) (state & UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT) != 0 || (state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 ) ) { #if ENABLE_THUMBNAIL_GENERATOR - if ((state & UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT) == 0) + if (((state & UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT) == 0) && + (this->background_process.state() != BackgroundSlicingProcess::STATE_RUNNING)) { // update thumbnail data if (this->printer_technology == ptFFF) From 636e446da169940956a27e1d2fa0f240c8929adb Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 31 Oct 2019 16:40:38 +0100 Subject: [PATCH 43/80] ENABLE_THUMBNAIL_GENERATOR -> Changes to zoom factor and centering algorithm when rendering thumbnails --- src/slic3r/GUI/Camera.cpp | 102 +++++++++++++++++++++++++++++++++- src/slic3r/GUI/Camera.hpp | 17 ++++++ src/slic3r/GUI/GLCanvas3D.cpp | 15 ++++- src/slic3r/GUI/GLCanvas3D.hpp | 8 +++ 4 files changed, 140 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 8e3a6d1f1..b5aac32ed 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -1,7 +1,9 @@ #include "libslic3r/libslic3r.h" #include "Camera.hpp" +#if !ENABLE_THUMBNAIL_GENERATOR #include "3DScene.hpp" +#endif // !ENABLE_THUMBNAIL_GENERATOR #include "GUI_App.hpp" #include "AppConfig.hpp" @@ -22,6 +24,10 @@ namespace Slic3r { namespace GUI { const double Camera::DefaultDistance = 1000.0; +#if ENABLE_THUMBNAIL_GENERATOR +const double Camera::DefaultZoomToBoxMarginFactor = 1.0; +const double Camera::DefaultZoomToVolumesMarginFactor = 1.1; +#endif // ENABLE_THUMBNAIL_GENERATOR double Camera::FrustrumMinZRange = 50.0; double Camera::FrustrumMinNearZ = 100.0; double Camera::FrustrumZMargin = 10.0; @@ -266,10 +272,18 @@ void Camera::apply_projection(const BoundingBoxf3& box) const glsafe(::glMatrixMode(GL_MODELVIEW)); } +#if ENABLE_THUMBNAIL_GENERATOR +void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h, double margin_factor) +#else void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h) +#endif // ENABLE_THUMBNAIL_GENERATOR { // Calculate the zoom factor needed to adjust the view around the given box. +#if ENABLE_THUMBNAIL_GENERATOR + double zoom = calc_zoom_to_bounding_box_factor(box, canvas_w, canvas_h, margin_factor); +#else double zoom = calc_zoom_to_bounding_box_factor(box, canvas_w, canvas_h); +#endif // ENABLE_THUMBNAIL_GENERATOR if (zoom > 0.0) { m_zoom = zoom; @@ -278,6 +292,20 @@ void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h) } } +#if ENABLE_THUMBNAIL_GENERATOR +void Camera::zoom_to_volumes(const GLVolumePtrs& volumes, int canvas_w, int canvas_h, double margin_factor) +{ + Vec3d center; + double zoom = calc_zoom_to_volumes_factor(volumes, canvas_w, canvas_h, center, margin_factor); + if (zoom > 0.0) + { + m_zoom = zoom; + // center view around the calculated center + m_target = center; + } +} +#endif // ENABLE_THUMBNAIL_GENERATOR + #if ENABLE_CAMERA_STATISTICS void Camera::debug_render() const { @@ -372,7 +400,11 @@ std::pair Camera::calc_tight_frustrum_zs_around(const BoundingBo return ret; } +#if ENABLE_THUMBNAIL_GENERATOR +double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h, double margin_factor) const +#else double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const +#endif // ENABLE_THUMBNAIL_GENERATOR { double max_bb_size = box.max_size(); if (max_bb_size == 0.0) @@ -405,13 +437,15 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int ca double max_x = 0.0; double max_y = 0.0; +#if !ENABLE_THUMBNAIL_GENERATOR // margin factor to give some empty space around the box double margin_factor = 1.25; +#endif // !ENABLE_THUMBNAIL_GENERATOR for (const Vec3d& v : vertices) { // project vertex on the plane perpendicular to camera forward axis - Vec3d pos(v(0) - bb_center(0), v(1) - bb_center(1), v(2) - bb_center(2)); + Vec3d pos = v - bb_center; Vec3d proj_on_plane = pos - pos.dot(forward) * forward; // calculates vertex coordinate along camera xy axes @@ -431,6 +465,72 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int ca return std::min((double)canvas_w / (2.0 * max_x), (double)canvas_h / (2.0 * max_y)); } +#if ENABLE_THUMBNAIL_GENERATOR +double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, int canvas_w, int canvas_h, Vec3d& center, double margin_factor) const +{ + if (volumes.empty()) + return -1.0; + + // project the volumes vertices on a plane perpendicular to the camera forward axis + // then calculates the vertices coordinate on this plane along the camera xy axes + + // ensure that the view matrix is updated + apply_view_matrix(); + + Vec3d right = get_dir_right(); + Vec3d up = get_dir_up(); + Vec3d forward = get_dir_forward(); + + BoundingBoxf3 box; + for (const GLVolume* volume : volumes) + { + box.merge(volume->transformed_bounding_box()); + } + center = box.center(); + + double min_x = DBL_MAX; + double min_y = DBL_MAX; + double max_x = -DBL_MAX; + double max_y = -DBL_MAX; + + for (const GLVolume* volume : volumes) + { + const Transform3d& transform = volume->world_matrix(); + const TriangleMesh* hull = volume->convex_hull(); + if (hull == nullptr) + continue; + + for (const Vec3f& vertex : hull->its.vertices) + { + Vec3d v = transform * vertex.cast(); + + // project vertex on the plane perpendicular to camera forward axis + Vec3d pos = v - center; + Vec3d proj_on_plane = pos - pos.dot(forward) * forward; + + // calculates vertex coordinate along camera xy axes + double x_on_plane = proj_on_plane.dot(right); + double y_on_plane = proj_on_plane.dot(up); + + min_x = std::min(min_x, x_on_plane); + min_y = std::min(min_y, y_on_plane); + max_x = std::max(max_x, x_on_plane); + max_y = std::max(max_y, y_on_plane); + } + } + + center += 0.5 * (max_x + min_x) * right + 0.5 * (max_y + min_y) * up; + + double dx = margin_factor * (max_x - min_x); + double dy = margin_factor * (max_y - min_y); + + if ((dx == 0.0) || (dy == 0.0)) + return -1.0f; + + return std::min((double)canvas_w / dx, (double)canvas_h / dy); +} +#endif // ENABLE_THUMBNAIL_GENERATOR + void Camera::set_distance(double distance) const { m_distance = distance; diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 839d0d6cf..cb634138f 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -2,6 +2,9 @@ #define slic3r_Camera_hpp_ #include "libslic3r/BoundingBox.hpp" +#if ENABLE_THUMBNAIL_GENERATOR +#include "3DScene.hpp" +#endif // ENABLE_THUMBNAIL_GENERATOR #include namespace Slic3r { @@ -10,6 +13,10 @@ namespace GUI { struct Camera { static const double DefaultDistance; +#if ENABLE_THUMBNAIL_GENERATOR + static const double DefaultZoomToBoxMarginFactor; + static const double DefaultZoomToVolumesMarginFactor; +#endif // ENABLE_THUMBNAIL_GENERATOR static double FrustrumMinZRange; static double FrustrumMinNearZ; static double FrustrumZMargin; @@ -90,7 +97,12 @@ public: void apply_view_matrix() const; void apply_projection(const BoundingBoxf3& box) const; +#if ENABLE_THUMBNAIL_GENERATOR + void zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h, double margin_factor = DefaultZoomToBoxMarginFactor); + void zoom_to_volumes(const GLVolumePtrs& volumes, int canvas_w, int canvas_h, double margin_factor = DefaultZoomToVolumesMarginFactor); +#else void zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h); +#endif // ENABLE_THUMBNAIL_GENERATOR #if ENABLE_CAMERA_STATISTICS void debug_render() const; @@ -100,7 +112,12 @@ private: // returns tight values for nearZ and farZ plane around the given bounding box // the camera MUST be outside of the bounding box in eye coordinate of the given box std::pair calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const; +#if ENABLE_THUMBNAIL_GENERATOR + double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h, double margin_factor = DefaultZoomToBoxMarginFactor) const; + double calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, int canvas_w, int canvas_h, Vec3d& center, double margin_factor = DefaultZoomToVolumesMarginFactor) const; +#else double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const; +#endif // ENABLE_THUMBNAIL_GENERATOR void set_distance(double distance) const; }; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index cddae1f86..a49c772d3 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1119,6 +1119,10 @@ wxDEFINE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent); wxDEFINE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent); +#if ENABLE_THUMBNAIL_GENERATOR +const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25; +#endif // ENABLE_THUMBNAIL_GENERATOR + GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar) : m_canvas(canvas) , m_context(nullptr) @@ -3623,7 +3627,7 @@ static void render_volumes_in_thumbnail(const GLVolumePtrs& volumes, ThumbnailDa } Camera camera; - camera.zoom_to_box(box, thumbnail_data.width, thumbnail_data.height); + camera.zoom_to_volumes(visible_volumes, thumbnail_data.width, thumbnail_data.height); camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height); camera.apply_view_matrix(); camera.apply_projection(box); @@ -4086,12 +4090,21 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_be return bb; } +#if ENABLE_THUMBNAIL_GENERATOR +void GLCanvas3D::_zoom_to_box(const BoundingBoxf3& box, double margin_factor) +{ + const Size& cnv_size = get_canvas_size(); + m_camera.zoom_to_box(box, cnv_size.get_width(), cnv_size.get_height(), margin_factor); + m_dirty = true; +} +#else void GLCanvas3D::_zoom_to_box(const BoundingBoxf3& box) { const Size& cnv_size = get_canvas_size(); m_camera.zoom_to_box(box, cnv_size.get_width(), cnv_size.get_height()); m_dirty = true; } +#endif // ENABLE_THUMBNAIL_GENERATOR void GLCanvas3D::_refresh_if_shown_on_screen() { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index fce4661a4..850e851fa 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -107,6 +107,10 @@ wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent); class GLCanvas3D { +#if ENABLE_THUMBNAIL_GENERATOR + static const double DefaultCameraZoomToBoxMarginFactor; +#endif // ENABLE_THUMBNAIL_GENERATOR + public: struct GCodePreviewVolumeIndex { @@ -646,7 +650,11 @@ private: BoundingBoxf3 _max_bounding_box(bool include_gizmos, bool include_bed_model) const; +#if ENABLE_THUMBNAIL_GENERATOR + void _zoom_to_box(const BoundingBoxf3& box, double margin_factor = DefaultCameraZoomToBoxMarginFactor); +#else void _zoom_to_box(const BoundingBoxf3& box); +#endif // ENABLE_THUMBNAIL_GENERATOR void _refresh_if_shown_on_screen(); From bf8fcabb29836321dc5252439cd1b4ead0e2537f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 31 Oct 2019 17:03:33 +0100 Subject: [PATCH 44/80] ENABLE_THUMBNAIL_GENERATOR -> Use orthographic camera when rendering thumbnails --- src/slic3r/GUI/Camera.cpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index b5aac32ed..94d673e82 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -26,7 +26,7 @@ namespace GUI { const double Camera::DefaultDistance = 1000.0; #if ENABLE_THUMBNAIL_GENERATOR const double Camera::DefaultZoomToBoxMarginFactor = 1.0; -const double Camera::DefaultZoomToVolumesMarginFactor = 1.1; +const double Camera::DefaultZoomToVolumesMarginFactor = 1.0; #endif // ENABLE_THUMBNAIL_GENERATOR double Camera::FrustrumMinZRange = 50.0; double Camera::FrustrumMinNearZ = 100.0; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a49c772d3..4e36739ac 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3627,6 +3627,7 @@ static void render_volumes_in_thumbnail(const GLVolumePtrs& volumes, ThumbnailDa } Camera camera; + camera.set_type(Camera::Ortho); camera.zoom_to_volumes(visible_volumes, thumbnail_data.width, thumbnail_data.height); camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height); camera.apply_view_matrix(); From f94f75d481c5739ceae297aa76aa5602920c642d Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 1 Nov 2019 12:19:27 +0100 Subject: [PATCH 45/80] ENABLE_THUMBNAIL_GENERATOR -> Render thumbnails using shader --- src/slic3r/GUI/Camera.cpp | 4 ++-- src/slic3r/GUI/GLCanvas3D.cpp | 35 +++++++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 94d673e82..9fbabe930 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -25,8 +25,8 @@ namespace GUI { const double Camera::DefaultDistance = 1000.0; #if ENABLE_THUMBNAIL_GENERATOR -const double Camera::DefaultZoomToBoxMarginFactor = 1.0; -const double Camera::DefaultZoomToVolumesMarginFactor = 1.0; +const double Camera::DefaultZoomToBoxMarginFactor = 1.025; +const double Camera::DefaultZoomToVolumesMarginFactor = 1.025; #endif // ENABLE_THUMBNAIL_GENERATOR double Camera::FrustrumMinZRange = 50.0; double Camera::FrustrumMinNearZ = 100.0; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4e36739ac..f8e7b1f94 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3594,7 +3594,8 @@ static void debug_output_thumbnail(const ThumbnailData& thumbnail_data) } #endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT -static void render_volumes_in_thumbnail(const GLVolumePtrs& volumes, ThumbnailData& thumbnail_data, bool printable_only, bool parts_only) + +static void render_volumes_in_thumbnail(Shader& shader, const GLVolumePtrs& volumes, ThumbnailData& thumbnail_data, bool printable_only, bool parts_only) { auto is_visible = [](const GLVolume& v) -> bool { @@ -3603,8 +3604,8 @@ static void render_volumes_in_thumbnail(const GLVolumePtrs& volumes, ThumbnailDa return ret; }; - static const float orange[] = { 0.99f, 0.49f, 0.26f }; - static const float gray[] = { 0.64f, 0.64f, 0.64f }; + static const GLfloat orange[] = { 0.923f, 0.504f, 0.264f, 1.0f }; + static const GLfloat gray[] = { 0.64f, 0.64f, 0.64f, 1.0f }; GLVolumePtrs visible_volumes; @@ -3634,17 +3635,31 @@ static void render_volumes_in_thumbnail(const GLVolumePtrs& volumes, ThumbnailDa camera.apply_projection(box); glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); - glsafe(::glEnable(GL_LIGHTING)); glsafe(::glEnable(GL_DEPTH_TEST)); + shader.start_using(); + + GLint shader_id = shader.get_shader_program_id(); + GLint color_id = ::glGetUniformLocation(shader_id, "uniform_color"); + GLint print_box_detection_id = ::glGetUniformLocation(shader_id, "print_box.volume_detection"); + glcheck(); + + if (print_box_detection_id != -1) + glsafe(::glUniform1i(print_box_detection_id, 0)); + for (const GLVolume* vol : visible_volumes) { - glsafe(::glColor3fv((vol->printable && !vol->is_outside) ? orange : gray)); + if (color_id >= 0) + glsafe(::glUniform4fv(color_id, 1, (vol->printable && !vol->is_outside) ? orange : gray)); + else + glsafe(::glColor4fv((vol->printable && !vol->is_outside) ? orange : gray)); + vol->render(); } + shader.stop_using(); + glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glDisable(GL_LIGHTING)); } void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only) @@ -3700,7 +3715,7 @@ void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, un if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) { - render_volumes_in_thumbnail(m_volumes.volumes, thumbnail_data, printable_only, parts_only); + render_volumes_in_thumbnail(m_shader, m_volumes.volumes, thumbnail_data, printable_only, parts_only); if (multisample) { @@ -3768,7 +3783,7 @@ void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigne if (!thumbnail_data.is_valid()) return; - render_volumes_in_thumbnail(m_volumes.volumes, thumbnail_data, printable_only, parts_only); + render_volumes_in_thumbnail(m_shader, m_volumes.volumes, thumbnail_data, printable_only, parts_only); glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data())); #if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT @@ -4302,7 +4317,9 @@ void GLCanvas3D::_render_objects() const if (m_volumes.empty()) return; +#if !ENABLE_THUMBNAIL_GENERATOR glsafe(::glEnable(GL_LIGHTING)); +#endif // !ENABLE_THUMBNAIL_GENERATOR glsafe(::glEnable(GL_DEPTH_TEST)); m_camera_clipping_plane = m_gizmos.get_sla_clipping_plane(); @@ -4346,7 +4363,9 @@ void GLCanvas3D::_render_objects() const m_shader.stop_using(); m_camera_clipping_plane = ClippingPlane::ClipsNothing(); +#if !ENABLE_THUMBNAIL_GENERATOR glsafe(::glDisable(GL_LIGHTING)); +#endif // !ENABLE_THUMBNAIL_GENERATOR } void GLCanvas3D::_render_selection() const From 3d450df680eee9a9e5fd786fc3ea436be03f2eff Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 4 Nov 2019 11:59:23 +0100 Subject: [PATCH 46/80] ENABLE_THUMBNAIL_GENERATOR -> Transparent background for thumbnails saved into .3mf --- src/slic3r/GUI/GLCanvas3D.cpp | 22 ++++++++++++++-------- src/slic3r/GUI/GLCanvas3D.hpp | 8 ++++---- src/slic3r/GUI/Plater.cpp | 14 +++++++------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f8e7b1f94..7d58f3c09 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1651,12 +1651,12 @@ void GLCanvas3D::render() } #if ENABLE_THUMBNAIL_GENERATOR -void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only) +void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background) { if (GLCanvas3DManager::are_framebuffers_supported()) - _render_thumbnail_framebuffer(thumbnail_data, w, h, printable_only, parts_only); + _render_thumbnail_framebuffer(thumbnail_data, w, h, printable_only, parts_only, transparent_background); else - _render_thumbnail_legacy(thumbnail_data, w, h, printable_only, parts_only); + _render_thumbnail_legacy(thumbnail_data, w, h, printable_only, parts_only, transparent_background); } #endif // ENABLE_THUMBNAIL_GENERATOR @@ -3595,7 +3595,7 @@ static void debug_output_thumbnail(const ThumbnailData& thumbnail_data) #endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT -static void render_volumes_in_thumbnail(Shader& shader, const GLVolumePtrs& volumes, ThumbnailData& thumbnail_data, bool printable_only, bool parts_only) +static void render_volumes_in_thumbnail(Shader& shader, const GLVolumePtrs& volumes, ThumbnailData& thumbnail_data, bool printable_only, bool parts_only, bool transparent_background) { auto is_visible = [](const GLVolume& v) -> bool { @@ -3634,6 +3634,9 @@ static void render_volumes_in_thumbnail(Shader& shader, const GLVolumePtrs& volu camera.apply_view_matrix(); camera.apply_projection(box); + if (transparent_background) + glsafe(::glClearColor(1.0f, 1.0f, 1.0f, 0.0f)); + glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); glsafe(::glEnable(GL_DEPTH_TEST)); @@ -3660,9 +3663,12 @@ static void render_volumes_in_thumbnail(Shader& shader, const GLVolumePtrs& volu shader.stop_using(); glsafe(::glDisable(GL_DEPTH_TEST)); + + if (transparent_background) + glsafe(::glClearColor(1.0f, 1.0f, 1.0f, 1.0f)); } -void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only) +void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background) { thumbnail_data.set(w, h); if (!thumbnail_data.is_valid()) @@ -3715,7 +3721,7 @@ void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, un if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) { - render_volumes_in_thumbnail(m_shader, m_volumes.volumes, thumbnail_data, printable_only, parts_only); + render_volumes_in_thumbnail(m_shader, m_volumes.volumes, thumbnail_data, printable_only, parts_only, transparent_background); if (multisample) { @@ -3766,7 +3772,7 @@ void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, un glsafe(::glDisable(GL_MULTISAMPLE)); } -void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only) +void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background) { // check that thumbnail size does not exceed the default framebuffer size const Size& cnv_size = get_canvas_size(); @@ -3783,7 +3789,7 @@ void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigne if (!thumbnail_data.is_valid()) return; - render_volumes_in_thumbnail(m_shader, m_volumes.volumes, thumbnail_data, printable_only, parts_only); + render_volumes_in_thumbnail(m_shader, m_volumes.volumes, thumbnail_data, printable_only, parts_only, transparent_background); glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data())); #if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 850e851fa..9f8d9d228 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -529,7 +529,7 @@ public: #if ENABLE_THUMBNAIL_GENERATOR // printable_only == false -> render also non printable volumes as grayed // parts_only == false -> render also sla support and pad - void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only); + void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background); #endif // ENABLE_THUMBNAIL_GENERATOR void select_all(); @@ -684,9 +684,9 @@ private: void _render_undo_redo_stack(const bool is_undo, float pos_x); #if ENABLE_THUMBNAIL_GENERATOR // render thumbnail using an off-screen framebuffer - void _render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only); - // render thumbnail using the default framebuffer - void _render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only); + void _render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background); + // render thumbnail using the default framebuffer + void _render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background); #endif // ENABLE_THUMBNAIL_GENERATOR void _update_volumes_hover_state() const; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 464093712..939af1652 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1928,7 +1928,7 @@ struct Plater::priv bool can_reload_from_disk() const; #if ENABLE_THUMBNAIL_GENERATOR - void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only); + void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background); #endif // ENABLE_THUMBNAIL_GENERATOR void msw_rescale_object_menu(); @@ -3057,7 +3057,7 @@ bool Plater::priv::restart_background_process(unsigned int state) for (const std::pair& size : THUMBNAIL_SIZE_FFF) { this->thumbnail_data.push_back(ThumbnailData()); - generate_thumbnail(this->thumbnail_data.back(), size.first, size.second, true, true); + generate_thumbnail(this->thumbnail_data.back(), size.first, size.second, true, true, false); } } else if (this->printer_technology == ptSLA) @@ -3068,7 +3068,7 @@ bool Plater::priv::restart_background_process(unsigned int state) for (const std::pair& size : THUMBNAIL_SIZE_SLA) { this->thumbnail_data.push_back(ThumbnailData()); - generate_thumbnail(this->thumbnail_data.back(), size.first, size.second, true, true); + generate_thumbnail(this->thumbnail_data.back(), size.first, size.second, true, true, false); } } } @@ -3422,7 +3422,7 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) for (const std::pair& size : THUMBNAIL_SIZE_SLA) { this->thumbnail_data.push_back(ThumbnailData()); - generate_thumbnail(this->thumbnail_data.back(), size.first, size.second, true, false); + generate_thumbnail(this->thumbnail_data.back(), size.first, size.second, true, false, false); } } #endif // ENABLE_THUMBNAIL_GENERATOR @@ -3653,9 +3653,9 @@ bool Plater::priv::init_object_menu() } #if ENABLE_THUMBNAIL_GENERATOR -void Plater::priv::generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only) +void Plater::priv::generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background) { - view3D->get_canvas3d()->render_thumbnail(data, w, h, printable_only, parts_only); + view3D->get_canvas3d()->render_thumbnail(data, w, h, printable_only, parts_only, transparent_background); } #endif // ENABLE_THUMBNAIL_GENERATOR @@ -4699,7 +4699,7 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) wxBusyCursor wait; #if ENABLE_THUMBNAIL_GENERATOR ThumbnailData thumbnail_data; - p->generate_thumbnail(thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, false, true); + p->generate_thumbnail(thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, false, true, true); if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, &thumbnail_data)) { #else if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) { From 64d5ac0d20b4dc7bb2213bfc33e1631bbd3d3e4d Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 4 Nov 2019 14:00:26 +0100 Subject: [PATCH 47/80] ENABLE_THUMBNAIL_GENERATOR -> Export thumbnails to gcode: max length of gcode lines set to 80 characters --- src/libslic3r/GCode.cpp | 22 ++++++++++++++++++++-- src/slic3r/GUI/GUI_App.cpp | 18 +++++++++++++++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 481e82da1..df3225f81 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -957,6 +957,8 @@ void GCode::_do_export(Print &print, FILE *file) // Write thumbnails using base64 encoding if (thumbnail_data != nullptr) { + const unsigned int max_row_length = 78; + for (const ThumbnailData& data : *thumbnail_data) { if (data.is_valid()) @@ -966,10 +968,26 @@ 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) { - _write_format(file, "; %s\n", boost::beast::detail::base64_encode((const std::uint8_t*)(data.pixels.data() + r * row_size), row_size).c_str()); + std::string encoded = boost::beast::detail::base64_encode((const std::uint8_t*)(data.pixels.data() + r * row_size), row_size); + unsigned int row_count = 0; + while (encoded.length() > max_row_length) + { + if (row_count == 0) + _write_format(file, "; %s\n", encoded.substr(0, max_row_length).c_str()); + else + _write_format(file, ";>%s\n", encoded.substr(0, max_row_length).c_str()); + + encoded = encoded.substr(max_row_length); + ++row_count; + } + + if (row_count == 0) + _write_format(file, "; %s\n", encoded.c_str()); + else + _write_format(file, ";>%s\n", encoded.c_str()); } - _write(file, "; thumbnail end\n;\n\n"); + _write(file, "; thumbnail end\n;\n"); } print.throw_if_canceled(); } diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index c35985f11..8f0014a05 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1106,6 +1106,7 @@ void GUI_App::gcode_thumbnails_debug() boost::nowide::ifstream file(in_filename.c_str()); std::vector rows; + std::string row; if (file.good()) { while (std::getline(file, gcode_line)) @@ -1121,9 +1122,16 @@ void GUI_App::gcode_thumbnails_debug() width = (unsigned int)::atoi(width_str.c_str()); std::string height_str = gcode_line.substr(x_pos + 1); height = (unsigned int)::atoi(height_str.c_str()); + row.clear(); } else if (reading_image && boost::starts_with(gcode_line, END_MASK)) { + if (!row.empty()) + { + rows.push_back(row); + row.clear(); + } + if ((unsigned int)rows.size() == height) { std::vector thumbnail(4 * width * height, 0); @@ -1160,7 +1168,15 @@ void GUI_App::gcode_thumbnails_debug() rows.clear(); } else if (reading_image) - rows.push_back(gcode_line.substr(2)); + { + if (!row.empty() && (gcode_line[1] == ' ')) + { + rows.push_back(row); + row.clear(); + } + + row += gcode_line.substr(2); + } } } From 76377ee0fe334ad3957556ede6d1a8b84d4ed6e1 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 4 Nov 2019 15:38:15 +0100 Subject: [PATCH 48/80] ENABLE_THUMBNAIL_GENERATOR -> Export thumbnails to gcode as png data in lines with max 80 characters length --- src/libslic3r/GCode.cpp | 41 ++++++++++++++++++++++++++++++---- src/libslic3r/Technologies.hpp | 1 + src/slic3r/GUI/GUI_App.cpp | 23 ++++++++++++++----- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index df3225f81..6b773f4d3 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -35,6 +35,10 @@ #include +#if ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE +#include "miniz_extension.hpp" +#endif // ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE + #if 0 // Enable debugging and asserts, even in the release build. #define DEBUG @@ -963,6 +967,31 @@ void GCode::_do_export(Print &print, FILE *file) { if (data.is_valid()) { +#if ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE + size_t png_size = 0; + 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 = boost::beast::detail::base64_encode((const std::uint8_t*)png_data, png_size); + + unsigned int row_count = 0; + while (encoded.length() > 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) + _write_format(file, "; %s\n", encoded.c_str()); + + _write(file, "; thumbnail end\n;\n"); + + mz_free(png_data); + } +#else _write_format(file, "\n;\n; thumbnail begin %dx%d\n", data.width, data.height); size_t row_size = 4 * data.width; @@ -981,13 +1010,17 @@ void GCode::_do_export(Print &print, FILE *file) ++row_count; } - if (row_count == 0) - _write_format(file, "; %s\n", encoded.c_str()); - else - _write_format(file, ";>%s\n", encoded.c_str()); + if (encoded.length() > 0) + { + if (row_count == 0) + _write_format(file, "; %s\n", encoded.c_str()); + else + _write_format(file, ";>%s\n", encoded.c_str()); + } } _write(file, "; thumbnail end\n;\n"); +#endif // ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE } print.throw_if_canceled(); } diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 4b351adb2..15cbd3827 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -39,5 +39,6 @@ // Enable thumbnail generator #define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_2_0_ALPHA1) +#define ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE (1 && ENABLE_THUMBNAIL_GENERATOR) #endif // _technologies_h_ diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 8f0014a05..07deff54e 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1104,14 +1104,14 @@ void GUI_App::gcode_thumbnails_debug() std::string in_filename = into_u8(dialog.GetPath()); std::string out_path = boost::filesystem::path(in_filename).remove_filename().append(L"thumbnail").string(); - boost::nowide::ifstream file(in_filename.c_str()); + boost::nowide::ifstream in_file(in_filename.c_str()); std::vector rows; std::string row; - if (file.good()) + if (in_file.good()) { - while (std::getline(file, gcode_line)) + while (std::getline(in_file, gcode_line)) { - if (file.good()) + if (in_file.good()) { if (boost::starts_with(gcode_line, BEGIN_MASK)) { @@ -1126,6 +1126,16 @@ void GUI_App::gcode_thumbnails_debug() } else if (reading_image && boost::starts_with(gcode_line, END_MASK)) { +#if ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE + std::string out_filename = out_path + std::to_string(width) + "x" + std::to_string(height) + ".png"; + 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()); + out_file.close(); + } +#else if (!row.empty()) { rows.push_back(row); @@ -1161,6 +1171,7 @@ void GUI_App::gcode_thumbnails_debug() image.SaveFile(out_path + std::to_string(width) + "x" + std::to_string(height) + ".png", wxBITMAP_TYPE_PNG); } +#endif // ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE reading_image = false; width = 0; @@ -1169,18 +1180,20 @@ void GUI_App::gcode_thumbnails_debug() } else if (reading_image) { +#if !ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE if (!row.empty() && (gcode_line[1] == ' ')) { rows.push_back(row); row.clear(); } +#endif // !ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE row += gcode_line.substr(2); } } } - file.close(); + in_file.close(); } } #endif // ENABLE_THUMBNAIL_GENERATOR From 41dadfdfcfc1c74ca23169ffc0819a2b12d43321 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 5 Nov 2019 14:50:58 +0100 Subject: [PATCH 49/80] ENABLE_THUMBNAIL_GENERATOR -> Generate thumbnails using GLEW_EXT_framebuffer_object on graphic cards supporting it --- src/slic3r/GUI/GLCanvas3D.cpp | 114 ++++++++++++++++++++++++++- src/slic3r/GUI/GLCanvas3D.hpp | 4 +- src/slic3r/GUI/GLCanvas3DManager.cpp | 10 ++- src/slic3r/GUI/GLCanvas3DManager.hpp | 12 ++- 4 files changed, 129 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 7d58f3c09..99f61e51e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1653,10 +1653,12 @@ void GLCanvas3D::render() #if ENABLE_THUMBNAIL_GENERATOR void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background) { - if (GLCanvas3DManager::are_framebuffers_supported()) - _render_thumbnail_framebuffer(thumbnail_data, w, h, printable_only, parts_only, transparent_background); - else - _render_thumbnail_legacy(thumbnail_data, w, h, printable_only, parts_only, transparent_background); + switch (GLCanvas3DManager::get_framebuffers_type()) + { + case GLCanvas3DManager::FB_Arb: { _render_thumbnail_framebuffer(thumbnail_data, w, h, printable_only, parts_only, transparent_background); break; } + case GLCanvas3DManager::FB_Ext: { _render_thumbnail_framebuffer_ext(thumbnail_data, w, h, printable_only, parts_only, transparent_background); break; } + default: { _render_thumbnail_legacy(thumbnail_data, w, h, printable_only, parts_only, transparent_background); break; } + } } #endif // ENABLE_THUMBNAIL_GENERATOR @@ -3772,6 +3774,110 @@ void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, un glsafe(::glDisable(GL_MULTISAMPLE)); } +void GLCanvas3D::_render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background) +{ + thumbnail_data.set(w, h); + if (!thumbnail_data.is_valid()) + return; + + bool multisample = m_multisample_allowed; + if (multisample) + glsafe(::glEnable(GL_MULTISAMPLE)); + + GLint max_samples; + glsafe(::glGetIntegerv(GL_MAX_SAMPLES_EXT, &max_samples)); + GLsizei num_samples = max_samples / 2; + + GLuint render_fbo; + glsafe(::glGenFramebuffersEXT(1, &render_fbo)); + glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, render_fbo)); + + GLuint render_tex = 0; + GLuint render_tex_buffer = 0; + if (multisample) + { + // use renderbuffer instead of texture to avoid the need to use glTexImage2DMultisample which is available only since OpenGL 3.2 + glsafe(::glGenRenderbuffersEXT(1, &render_tex_buffer)); + glsafe(::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_tex_buffer)); + glsafe(::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, num_samples, GL_RGBA8, w, h)); + glsafe(::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, render_tex_buffer)); + } + else + { + glsafe(::glGenTextures(1, &render_tex)); + glsafe(::glBindTexture(GL_TEXTURE_2D, render_tex)); + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, render_tex, 0)); + } + + GLuint render_depth; + glsafe(::glGenRenderbuffersEXT(1, &render_depth)); + glsafe(::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_depth)); + if (multisample) + glsafe(::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, num_samples, GL_DEPTH_COMPONENT24, w, h)); + else + glsafe(::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, w, h)); + + glsafe(::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, render_depth)); + + GLenum drawBufs[] = { GL_COLOR_ATTACHMENT0 }; + glsafe(::glDrawBuffers(1, drawBufs)); + + if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT) + { + render_volumes_in_thumbnail(m_shader, m_volumes.volumes, thumbnail_data, printable_only, parts_only, transparent_background); + + if (multisample) + { + GLuint resolve_fbo; + glsafe(::glGenFramebuffersEXT(1, &resolve_fbo)); + glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, resolve_fbo)); + + GLuint resolve_tex; + glsafe(::glGenTextures(1, &resolve_tex)); + glsafe(::glBindTexture(GL_TEXTURE_2D, resolve_tex)); + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + glsafe(::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, resolve_tex, 0)); + + glsafe(::glDrawBuffers(1, drawBufs)); + + if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT) + { + glsafe(::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, render_fbo)); + glsafe(::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, resolve_fbo)); + glsafe(::glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR)); + + glsafe(::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, resolve_fbo)); + glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data())); + } + + glsafe(::glDeleteTextures(1, &resolve_tex)); + glsafe(::glDeleteFramebuffersEXT(1, &resolve_fbo)); + } + else + glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data())); + +#if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT + debug_output_thumbnail(thumbnail_data); +#endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT + } + + glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); + glsafe(::glDeleteRenderbuffersEXT(1, &render_depth)); + if (render_tex_buffer != 0) + glsafe(::glDeleteRenderbuffersEXT(1, &render_tex_buffer)); + if (render_tex != 0) + glsafe(::glDeleteTextures(1, &render_tex)); + glsafe(::glDeleteFramebuffersEXT(1, &render_fbo)); + + if (multisample) + glsafe(::glDisable(GL_MULTISAMPLE)); +} + void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background) { // check that thumbnail size does not exceed the default framebuffer size diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 9f8d9d228..8c2e6e9a5 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -685,7 +685,9 @@ private: #if ENABLE_THUMBNAIL_GENERATOR // render thumbnail using an off-screen framebuffer void _render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background); - // render thumbnail using the default framebuffer + // render thumbnail using an off-screen framebuffer when GLEW_EXT_framebuffer_object is supported + void _render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background); + // render thumbnail using the default framebuffer void _render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background); #endif // ENABLE_THUMBNAIL_GENERATOR diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index 03daa0b00..3594e85a4 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -189,7 +189,7 @@ std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool exten GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::MS_Unknown; bool GLCanvas3DManager::s_compressed_textures_supported = false; -bool GLCanvas3DManager::s_framebuffers_supported = false; +GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::FB_None; GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info; GLCanvas3DManager::GLCanvas3DManager() @@ -270,10 +270,12 @@ void GLCanvas3DManager::init_gl() else s_compressed_textures_supported = false; - if (s_gl_info.is_version_greater_or_equal_to(3, 0) && GLEW_ARB_framebuffer_object) - s_framebuffers_supported = true; + if (GLEW_ARB_framebuffer_object) + s_framebuffers_type = FB_Arb; + else if (GLEW_EXT_framebuffer_object) + s_framebuffers_type = FB_Ext; else - s_framebuffers_supported = false; + s_framebuffers_type = FB_None; if (! s_gl_info.is_version_greater_or_equal_to(2, 0)) { // Complain about the OpenGL version. diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp index a2e35f811..940e0230a 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -30,6 +30,13 @@ struct Camera; class GLCanvas3DManager { public: + enum EFramebufferType : unsigned char + { + FB_None, + FB_Arb, + FB_Ext + }; + class GLInfo { mutable bool m_detected; @@ -77,7 +84,7 @@ private: bool m_gl_initialized; static EMultisampleState s_multisample; static bool s_compressed_textures_supported; - static bool s_framebuffers_supported; + static EFramebufferType s_framebuffers_type; public: GLCanvas3DManager(); @@ -98,7 +105,8 @@ public: static bool can_multisample() { return s_multisample == MS_Enabled; } static bool are_compressed_textures_supported() { return s_compressed_textures_supported; } - static bool are_framebuffers_supported() { return s_framebuffers_supported; } + static bool are_framebuffers_supported() { return (s_framebuffers_type != FB_None); } + static EFramebufferType get_framebuffers_type() { return s_framebuffers_type; } static wxGLCanvas* create_wxglcanvas(wxWindow *parent); From f8785250d67df5eeea5a26f3db52296e19c0c83d Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Tue, 5 Nov 2019 18:18:27 +0100 Subject: [PATCH 50/80] Disable test_fill.cpp`"Solid surface fill" test for now due to precission issues --- tests/fff_print/test_fill.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/fff_print/test_fill.cpp b/tests/fff_print/test_fill.cpp index ec8b44a0d..c98cdcf43 100644 --- a/tests/fff_print/test_fill.cpp +++ b/tests/fff_print/test_fill.cpp @@ -138,6 +138,8 @@ TEST_CASE("Fill: Pattern Path Length", "[Fill]") { REQUIRE(paths.size() == 1); } } + + #if 0 // Disabled temporarily due to precission issues on the Mac VM SECTION("Solid surface fill") { Slic3r::Points points { Point::new_scale(6883102, 9598327.01296997), @@ -154,6 +156,8 @@ TEST_CASE("Fill: Pattern Path Length", "[Fill]") { REQUIRE(test_if_solid_surface_filled(expolygon, 0.55) == true); } } + #endif + SECTION("Solid surface fill") { Slic3r::Points points { Slic3r::Point(59515297,5422499),Slic3r::Point(59531249,5578697),Slic3r::Point(59695801,6123186), From 1e8aa54559afddf526d86d0c0f58f892209fcf9a Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 7 Nov 2019 09:01:28 +0100 Subject: [PATCH 51/80] ENABLE_THUMBNAIL_GENERATOR -> Added ENABLE_THUMBNAIL_GENERATOR_DEBUG (disabled) --- src/libslic3r/Technologies.hpp | 1 + src/slic3r/GUI/GUI_App.cpp | 4 ++-- src/slic3r/GUI/MainFrame.cpp | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 15cbd3827..5d0a7592c 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -39,6 +39,7 @@ // Enable thumbnail generator #define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_2_0_ALPHA1) +#define ENABLE_THUMBNAIL_GENERATOR_DEBUG (0 && ENABLE_THUMBNAIL_GENERATOR) #define ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE (1 && ENABLE_THUMBNAIL_GENERATOR) #endif // _technologies_h_ diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 07deff54e..0b24e2215 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1087,7 +1087,7 @@ bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage return res; } -#if ENABLE_THUMBNAIL_GENERATOR +#if ENABLE_THUMBNAIL_GENERATOR_DEBUG void GUI_App::gcode_thumbnails_debug() { const std::string BEGIN_MASK = "; thumbnail begin"; @@ -1196,7 +1196,7 @@ void GUI_App::gcode_thumbnails_debug() in_file.close(); } } -#endif // ENABLE_THUMBNAIL_GENERATOR +#endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG void GUI_App::window_pos_save(wxTopLevelWindow* window, const std::string &name) { diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 56eda2c0d..b76110a87 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -682,11 +682,11 @@ void MainFrame::init_menubar() helpMenu->AppendSeparator(); append_menu_item(helpMenu, wxID_ANY, _(L("Keyboard Shortcuts")) + sep + "&?", _(L("Show the list of the keyboard shortcuts")), [this](wxCommandEvent&) { wxGetApp().keyboard_shortcuts(); }); -#if ENABLE_THUMBNAIL_GENERATOR +#if ENABLE_THUMBNAIL_GENERATOR_DEBUG helpMenu->AppendSeparator(); append_menu_item(helpMenu, wxID_ANY, _(L("DEBUG gcode thumbnails")), _(L("DEBUG ONLY - read the selected gcode file and generates png for the contained thumbnails")), [this](wxCommandEvent&) { wxGetApp().gcode_thumbnails_debug(); }); -#endif // ENABLE_THUMBNAIL_GENERATOR +#endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG } // menubar From 67f55d3b23c36021f543e74d90d53902a6effed6 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 7 Nov 2019 12:09:04 +0100 Subject: [PATCH 52/80] 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 cdd35b720..e2ea9bc1a 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 53/80] 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 84a60da6e..9ed7424c0 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 3f0d87c35..5ab65f340 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 bf8cbc235..a603d52ac 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 e2ea9bc1a..da3a07a59 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 000000000..e9c76d2ab --- /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 54/80] #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 63658e817..61849e30d 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 0b24e2215..bcfb9ad39 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 55/80] 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 f4e298180..d09f015b9 100644 --- a/src/platform/osx/Info.plist.in +++ b/src/platform/osx/Info.plist.in @@ -116,5 +116,7 @@ NSApplication NSHighResolutionCapable + NSRequiresAquaSystemAppearance + From f5971316045bb0777ba2ee5482130c9209d165dd Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 11 Nov 2019 15:16:20 +0100 Subject: [PATCH 56/80] Trying to disable dark mode when compiled against the latest OSX SDK as we are not yet ready for that. --- 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 f4e298180..d09f015b9 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 57/80] 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 fc08c6290..9e51735fd 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 eae319efc..74582f601 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 514a90a9e..4aae07d4a 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 58/80] 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 bcfb9ad39..7d37baa66 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 d5753f2cc..5090382ce 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 c47714e46..f7bebd577 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 59/80] 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 086ba7a74..bbfcabd36 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 99f61e51e..e4a5f590d 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 60/80] 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 4185b6664..82b512270 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 5624ada9d..e83904a91 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 61/80] 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 b6d40a034..633ab3f19 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 62/80] 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 e83904a91..96a0a59cd 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 From 0c4507141a6b15968ec3a40af035d28eb0110db4 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 12 Nov 2019 13:19:17 +0100 Subject: [PATCH 63/80] Attempt to fix Mac build on buildserver --- 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 e7b4706ac..426734a67 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -145,6 +145,9 @@ static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double return result; } +// FIXME: needed to fix build on Mac on buildserver +constexpr double FillGyroid::PatternTolerance; + void FillGyroid::_fill_surface_single( const FillParams ¶ms, unsigned int thickness_layers, From 050a9adf36bb85220f3e3bdee59c399bf495c85a Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 12 Nov 2019 13:54:36 +0100 Subject: [PATCH 64/80] OSX issue: Fix Background drawing for some of controls in Dark mode --- src/slic3r/GUI/Field.cpp | 16 +++++++++++----- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 2 +- src/slic3r/GUI/OptionsGroup.hpp | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 42e3448fc..a8953f166 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -11,6 +11,12 @@ #include #include +#ifdef __WXOSX__ +#define wxOSX true +#else +#define wxOSX false +#endif + namespace Slic3r { namespace GUI { wxString double_to_string(double const value, const int max_precision /*= 4*/) @@ -304,7 +310,7 @@ void TextCtrl::BUILD() { auto temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, style); temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - if (! m_opt.multiline) + if (! m_opt.multiline && !wxOSX) // Only disable background refresh for single line input fields, as they are completely painted over by the edit control. // This does not apply to the multi-line edit field, where the last line and a narrow frame around the text is not cleared. temp->SetBackgroundStyle(wxBG_STYLE_PAINT); @@ -491,7 +497,7 @@ void CheckBox::BUILD() { // Set Label as a string of at least one space simbol to correct system scaling of a CheckBox auto temp = new wxCheckBox(m_parent, wxID_ANY, wxString(" "), wxDefaultPosition, size); temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - temp->SetBackgroundStyle(wxBG_STYLE_PAINT); + if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT); temp->SetValue(check_value); if (m_opt.readonly) temp->Disable(); @@ -601,7 +607,7 @@ void SpinCtrl::BUILD() { auto temp = new wxSpinCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, 0|wxTE_PROCESS_ENTER, min_val, max_val, default_value); temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - temp->SetBackgroundStyle(wxBG_STYLE_PAINT); + if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT); // XXX: On OS X the wxSpinCtrl widget is made up of two subwidgets, unfortunatelly // the kill focus event is not propagated to the encompassing widget, @@ -717,7 +723,7 @@ void Choice::BUILD() { } temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - temp->SetBackgroundStyle(wxBG_STYLE_PAINT); + if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT); // recast as a wxWindow to fit the calling convention window = dynamic_cast(temp); @@ -1072,7 +1078,7 @@ void ColourPicker::BUILD() auto temp = new wxColourPickerCtrl(m_parent, wxID_ANY, clr, wxDefaultPosition, size); temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - temp->SetBackgroundStyle(wxBG_STYLE_PAINT); + if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT); // // recast as a wxWindow to fit the calling convention window = dynamic_cast(temp); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 4ecab8a0f..937e3dbdc 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -57,7 +57,7 @@ static wxBitmapComboBox* create_word_local_combo(wxWindow *parent) #endif //__WXOSX__ temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - temp->SetBackgroundStyle(wxBG_STYLE_PAINT); + if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT); temp->Append(_(L("World coordinates"))); temp->Append(_(L("Local coordinates"))); diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp index cc3d89b1f..6089e18f5 100644 --- a/src/slic3r/GUI/OptionsGroup.hpp +++ b/src/slic3r/GUI/OptionsGroup.hpp @@ -175,7 +175,7 @@ public: staticbox(title!=""), extra_column(extra_clmn) { if (staticbox) { stb = new wxStaticBox(_parent, wxID_ANY, title); - stb->SetBackgroundStyle(wxBG_STYLE_PAINT); + if (!wxOSX) stb->SetBackgroundStyle(wxBG_STYLE_PAINT); stb->SetFont(wxGetApp().bold_font()); } else stb = nullptr; From 53cdb8ef539bedef38367c5f0136c38ce93a3458 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 14 Nov 2019 10:05:02 +0100 Subject: [PATCH 65/80] No sparse layers option marked as EXPERIMENTAL --- src/libslic3r/PrintConfig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index f082e13b3..6fa6ae3a2 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1826,7 +1826,7 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionBool(true)); def = this->add("wipe_tower_no_sparse_layers", coBool); - def->label = L("No sparse layers"); + def->label = L("No sparse layers (EXPERIMENTAL)"); def->tooltip = L("If enabled, the wipe tower will not be printed on layers with no toolchanges. " "On layers with a toolchange, extruder will travel downward to print the wipe tower. " "User is responsible for ensuring there is no collision with the print."); From 8c22b0cd4f85bf75150d30841473b69fd2c17525 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 14 Nov 2019 14:02:20 +0100 Subject: [PATCH 66/80] Added MINI and Creality Ender to ConfigWizard --- resources/icons/printers/Creality_Ender3.png | Bin 0 -> 62795 bytes .../icons/printers/PrusaResearch_MINI.png | Bin 0 -> 59414 bytes resources/profiles/Creality.ini | 415 ++++++++++++++++++ src/slic3r/GUI/ConfigWizard.cpp | 7 +- 4 files changed, 420 insertions(+), 2 deletions(-) create mode 100644 resources/icons/printers/Creality_Ender3.png create mode 100644 resources/icons/printers/PrusaResearch_MINI.png create mode 100644 resources/profiles/Creality.ini diff --git a/resources/icons/printers/Creality_Ender3.png b/resources/icons/printers/Creality_Ender3.png new file mode 100644 index 0000000000000000000000000000000000000000..52861197c7f17d27df53b6872e1e0e2a82aac410 GIT binary patch literal 62795 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 z z?B+7Ew+{;yJv5c?csQWG5tdPun>?0k?FV4KcwTX5?W%wMUDF0gWN};hbB`eb%~Wc4 zk4jrzYSx<>6cIEG1srZzok8EP*H4E8u)CX`vI`7g>W|EU+R?4O-|j^`iyQmobh~sb z{KDz9ePa61%Q3qKM*ifaq~;*tha^nY6lK~G3BH%EoWfuW!4SQ;29MNqZHr~93?lAv z`>8fKqcry}isMi;I((B8@8+eYim;yaRp#7C;JZTbl%UoExGy3)0tAIhe=*1XQU(OP ze$SV=uwdNf3p`nL8MHesRFcvAR4F8xU_C&48Q)l>qihPm;LeaB0HJpxuobPk5|F7| zX3r9d8Dt!`pc^NBpH~E63kAkC9Oo_f&jSQ1y zZpmInbrFG0HW^+fMKRyZLvS=+mQwQ5;Oa@Tb{=<~+CFZ`WPPRW0#Wce=yTf$>@x28 zpx2CUnO|AF;q0`0=Nu&I0i6oRv8cnAyo2^edFg(cldy6hUxU zZA6)5%6Qh1a>Zw@nuEE*>~QMI!=U0CB91C715(D|4!5EsobR$obp03|y1on;qRz9h zVCbvEx`~YD9S2X0^G3P1n|3V|!oSX@QORes8pQK&A}%GrP&V_oE-ILbFMf#u*%dk$AKyMaYXLg*zO5_k=Lk&>xK&7 znkA(nk>BWh^mLiJ5(D|+9E?jAyBGj&2ZD;Asn<)Pw08bgq*g81^Qj6;~{ z`_$2qp%N$R!?&ZITPIcTyxcjd-VW%J67r4JHRx1t2Kk&;sj+*X4op+mZs>nlFcVjQ z8Q?5Rw@s_nfvy~CWk{%1xiyh-kV$&kg}UvdyTPPLpg((QvlVESyC=hG6nfpMU!Vp4 zGOl)Hd^;#Uy>6ZKmASRVB4TU+EEm1^x^d#jHb{84>;?Y{n(cv^Q&3Q`N|Vj(wNwb~}7DVi5i%iyI^3di4vwoIy+nyn{NW!9|{nD3J-?)$iKl2gLgOLo}W7 z-n;MOtL?r^S={rPXkhhdX1~r$Te&+)UA?9zQ-%9|Wi$0F=ZC0%Sj_{?;sFZ-s9(55lK<$++=p38ds zFYPNJ=gIb*>A$MCDP%t&`ouuFY|E}OliCsQoAC44 zLV<<47c$F`A0EE9xj9_F*-F-NEr(D|gr4T|lP?a&Pj*^7V^cyx*_~A_r(OIQb~2np zJrr}AnO_pzBQDA0&6S{fjz}cCHH?gGVk@psMKNA?LKn>@6ksSC|lu`gl;+$emF1S~>HOaf6Q z-2(YTTx!)bB%RSG3u!MJ)}G`#oD{+Aw}`!}j|+;Xw8u|zKP|g4%EmJ_HPF9xION?` zK23*jcv1A?cfJWZ#^VnN-+o4R z{yp@u5p-EEN0Ef(67Th>&x`WL#!FWfWG?GfFv!13Ac;181lV}?oydx4JC)T&h9sFH zDAh`>6>&Qb7%~{SqobM+%xZWV{w)l2<+eFFOZek%=7Mv)YO#wJU02G9O(M8PSEeSn zobb0+4%XPm_uu<^ZM_ns`+SR3>~)}eY3GU;hUbNPVroEl8lg|X;~weQ0UAmWP}d{} z+L5onOGg;|bgjVVI3!KC67!M%bYJ`G+BNr}vG)Zq-Q9JSd*VB8i&4Te8-T4CV&4SN zdJYFMZRzs8bjxOnHX643(|u1_q_aT&?<;#LiYL?XJU23x&{-9Gr0u81qj7qMHL@A8{ zm4r94UU7>9TwWXxd)3D?pJn zXBa_=9wQ}}<1oFJnVA_88TBD-`m?!i&og)O=;oxCUXQ-l%6i_GU5lL<-KT*#@I~5L zyqnl7X{|Xu@+x0#E=_Oo?Z(r(n;$mir%fmWs3wo{xxS@K;!S)#buT9Gq_&GhfX-{& zW2CBfZNJo>y;xz%2Z zijr){!|ghdTyZy6d>(*vQ=CP3O>WBG^CY6b&dUOzoHNgJ?y4a@DXhxhQKvj`3XJU@ zR*{J-Q|6N~%Z?RbDMV-)bSqz4mf%i{3vuPhL-$zUl;Kr1bccdiS@2oX%f`6LLhf=J zHr|O{fHphQVjwK3*)?|M>S}>n=^6Bq16okgE<1*TDxKxn9>cO;Y&I308HeOs?#@fY7SW6*818Jfwg797nRv+34V z{)9(^GOo!*-Win(r3x~HVR)V|Y0?edX!GiQX+MZZ_0T05jSNv2n@!eIi`fZzPDJV- z5f+_JxR~Oxr{P|Mc_k8NQB>iJdkahWWm(sQwBVcHD#gc|98Na+j%Hp8@2?l}HK^TO zbw8GLRLieE9T)pRKeoozDR!!wl!0)(VAfAN;vp_tPLW~r8LDwKBRimdO}mFME>z`u z09i~U--9J2{Z*dntYhhtW>^iy@KJAW^*jTb$zZXlH>+wg+R=zCgA0#L zX=AVR_zRxTz*|(}Aoc_D#J^LBxG7O;J#^lCqv1LXN@e5uL7GSNHCdN0ci{o6H`%v1 zhSoR=)=VPPH(HjOKIa=EubUfF=tKisW^-fs4koln6xM=+6XVY z1b8>t@p;$ujMT+e+m%3CC6l9+;i^ZF;3u`M zv64Wa+8H6O_a#_a*H*X*uy%A9ZCVU9ok92n_we6u$XDlbcL!;5} zW?s_M(x%KjF3_%6aH;zqlR71J!tqx>{c#UM36{ddkyUu0+{d zNqQlrk(=3>>kII~bCexdsucL*IzIh3);kYB5a1cI1aJ@re({>}JI8wyO+pw6;xi=4 zAb`)|v$13Za?oK$qbVo|cHEG7`1As=X2htDC!~zHlvvCIT%c!+pKHfIBs|RfWEVj!@pFwk>iNCX??M7BnXbAG2NpeWM6XA|s>7>R#*sD}q{E!+;fpZv z=fQ?2+2QYIqLu{#naF*Wc8Sqc+Q_!FVN|X(mhPb8-%Za*?xAi z#cubh%eyVAMp#pK(NO+!QnLwDlG)(wlgAWs!GvzdKq5s@t7d65c~N6x{l!(sR!_*< znxrkOPI|W~ax$>?LAg}>ljql>7JDtFsV%P3zxVybJ9?C5N6yY)?cdk=RZ8Rd)7PyvlqGkC9O-tc zb9(e(?Ey4mi3u~+ppR*JTBTV&$#I?ke*5R|xMqct!DWe4$EnTvhUc7j>S6orM!QK( zLcz$J;?wtHggVh)L|50oQdb9D=JN)+jC+dqCrNQ%YYry0-GR@70e}#tt5q&5hC@%r zxV~7rnXHfh$aUMh`m<|KZMWkVJZ#|l3i*1 zSC&njXrAY?(~_cco)L=EajFbM8rudUl>0G|NKp~TVtgv{1wx6Ib|VUWUi3S=uuQrJ zfL1dVL4b2|F-aFT?e!DEMg2~NRE9>)h}Jp5Vo*_Hk*U4JIi;~2f(iQc)VxgJ2`l+R z9WMsiDE*5E6g&EL(O#X9{9wWtW#95e2=oQ6pzVhsmejj*!-vl!i2FC7i*I$^hO+s6 zw%hcM%HwO6vK=)<*_s!57#2|6@sEp%t?LfORz~;kIttz`UinfsCAu$t#{MD|vEDdN(jv^=-uU?rv z6ibF#-6FZtf%bn-?Y#5_rBU#qGiAi}TfN8rR0mAS=8NVS^F_^abE^20g?P{D(zNHp zy4e1g<#O`T#TIQ|atiIQeT)K5F8Bvzhh><*th|Ds9 zH#|yO7XBg1tsLEizV#UyJxpG^;^J$Su$uX4ey@qryx9D&j%@`Z6JJZ$z0%aXzYj0k zOpZlro0cJUTIy*Utlo~+2VJ3mp=u%5kIMonA0P3mou%n8eA11Gse49|RUs40(XTUU z74;Qo#B*g{5FNS>6;H{LzZU)+Lf@<+-_*NUb6tUN<2@W6f^xnw zy?gTs(XmFf@8+J%dTj{Yh|%*^O4w zqJOQYd;Tq+F;Mn8pV2{(L5@EmKE4-^sQHC94F-8DBbvvLI!LWbk{vDN^HiUYfgT?@gyuK--%IgIp2QO1k#HNCM1!d?1Y03nm1~Seo$pp9d_$m)`1ez8sL9=<{&8(dnsRtteA!NA4j*Q_6-LJYNwiTxM)7Ez~tf zYDN3Qs^D)kBP-w6O~j*O6ol{szi|Wy-*5|9t_n62@Vd^gch|;+nl*DOB0|Bg9|}{> zdph@WfQDht#LzzJfxkRwsTY6OymrTI-O1`#=N6}rCDYY*+9{bHxNl}DPzTS{HfB-6@)PZlQ+c^e&o8JskM_oo0{(uPq{iEk;R_*Ncb$MqkW zhLbPJ85>J|e1mE2P0}R)K9qev3V&AQhO>3>=m;SCT|&*bLh=`QQoQV*YdmZ>hWx5b zANd{-gkR^a@42Cc$oo#dd^^OMA$EX-SMyHZaNC~hsB>Yy;C`dZ7hw^Em+_^7<)@`F zF)FxM+NfV!F9XR;ao6(OJr?lwfU_z!J>T_?jFM|-Mf48FxMz(xH`P{6!-dJ^MeW7D>iD9D3NAFhcZ?%sqw8w|!49(u=7rP}F!u6b-O8#4pMRO2U`E z<3g93L>up^y1mh9jm^%tHBZ;qIZs^s3M@y;quooJTB+K;yx!p;Jgj`TA4QayVBXuW z@<9pdW5d7g9-~|3y#731EQMWs|9tJv^r_L*7?4kBO7l9eRv1KkXYHoO`UCs{E=gIF z_;AigcVE8rOfD5Oh`qv}l9)jbgU{VMZ5Oy{{i+u z3BS2!IQQHq@QPQzolk!JqbO|+tXg-OQpv?}N{E53u5KDZNazPt25LB3xap7A;#H~` z<5R12BS5R!WX1C3oN)XJ+;``_OiYYZ>#ef<=;f&G!qG=BXV2~tyA;TCTb^eHh2y03 z{r`H}xntL0|3EhvJ^jh--#gBCzyAZi^6eke*W1IkoqL#=m|*GBCG_`o6Ey2I>x!P9 z8fND(j&fMBdIj~F8TJhiQ}R6a>>B2d+wVnmi7PI@oUy&5JiPH9%3WPdH+;HKtgZ;A z4huz?ln@hdMx28M`4sb)AoyVjO5=GYnynT=5VS2Sv0RlM85Txl4MfR=n`Ymc4=`(E z=x8LE97>A#*^r*@lo?L~qP;0R7s4jy;ce_W_7(I#aR~qBUoqW+k_dVic)MWSX)-1- z)Zfq9kH3JuyLK==F~;D6#WWiYX6jQQ6++Xpo`mr-jfTOiR1krE`-drY)$qJ3Jw5#x z6Jo*;$JLCDjdJ_#H{myYOyHyZ2HQ5>&!z`AGc|gE9Xt0jGCqw7rx%x;`YS4>vhoAp zakRD*C~>PrDWya!Lwx**L@m=R`$euB}!`vjR;07tu3My(P0=kf_6j<8WAH# zSs1B9txzK3SbNc+5K&qi5kZV-nG)9zsExGq9S5QaKo;^?T5c=|jaB9ny~@m2X1(58)ab$3%L zm#EchOihmyL`H`1H!;R=)XJl&b@#Gs$0Hac+djum2Pgo?QZ(|`&obdI;O^Fxa*$#amy7JFBuq7j$5v`0%eRiT8oGgjgm;q zThm3M>@XIzQc6(DI9eH{Vsj5sN`oU&Sg5kYHB;D@vtEfm<};*@d{ zb}dSH$&8GcX;W1|3e7t2Jt#5@LtEFKjz)}X*D8fmLPa?WrJ)Y0-o$JD4z2;W&tYiL zt_$q$0`}aAw{01^(uIgHF*#0mtp}y*gc9PqCH$7pG}CycGNYqoELpUSr#1oC%8~Cjjy}jMIj%y{f)|__osSFG(rs@0i_xCZhXgQ}o?ktupTg3hMKE%b( z?q}DIU7T>@y6>HS#!27k)b{_+q(t~w&1j54I}RWC=MO)Brat+bkA3oU7q?mgCmz3! zvrj*cJv(=D!upl?t@HTpAFgL)bdqYd%)&)O_1LtK4UWtezdm&o|g(o$x6;>s$ZqdX2ixi zE7xM(naL?yjd}t((vV}7aTiOD2=RWa$!e7xLdZ&So7_%*=XjpnZZeYH3?_bD6Q8kd z8=*C#?G*QTl<7FAc7-qj{+=H09PekL>7q2g1K;V!F?M6}a;?h5%oIV>ZW5nzlEOeUYcP@xm03s!6HsL`83A% z?_tlLJ&cTx^Q&L|fklG@;5hX5_aF$3nW<@jiSg0HTF@|OzJ%!WNwFE!jt$#w7L756 z?%p2$^%I|c#`JXam*4%ym!I{lr=3f)(PC_L5)%ZRfA*==n?Bdxa4X&2H5M;k%%+VG zaoq98&}{i^d}s^(14E2YPO)miQlvg(nOVDNUvojt@alB|dnX+p-l5pA%t3qLcw*ga z%Ajx(V@@PpYoBYiN~LtETtO*?>o}-LLaR)^Y&jhexiyS4D_A62G@Q~YrlrD_j3u99 zp)6iDxd+odf3bNCptM0nQCJSC+*iON@HYm0EIf->pYTLZ_`|2DRyF&E4^ZE=hovi4 zp&UDj8U#L$W4ESK3bfW}M^kS#X!;?wYKifQQSQ0>PW-?|JoqgiBd}xlPL`}Zif29h zS^W41-)CUa5{^6mSdKmZWcKXbO>b`(wQ3iOmn~y_qW<1iedde3eFO9HO+L!09rqnl zJ|mzNpZ||9J$u1m@27wFi~sqn(;s&_fid(C3^Fn@O5pn}TrkAY&>*{Z?&7%PkD<|M zuy^l%7B5-KLl1AIyQ`a0$z|KF-Dm~MI6S#5yk&iZk%s2ZZJHhjoRYy0p=1QlaWKTY zltwm3R7J}zQZUj~a!#Vw8pm--JZr@`aglV7>^31=^v_u%vN)*%MaZFr6g!i_F4?l; zJW-(n3QwUURpekjEb-L0fU6sv-Wp};qLA_+bkCG&`b|c5?4-MYfJ(VSv*{DsZ7^|N z4-?uqIgUfMTEzrDqvIn~sx_MR22XkNlNcKv=KlNdqf)Bixn-1TapmQI;Ep@*q_2OF z2kyOx#^g8?)7FRG*FOZn@V>p3#^k=w9CO@;8~tWe5Ebv{qLdv;)}Jb9L6nJhJrN`J zz$JxJXrq-o&&5Cpl`xQ4B0yjMu+_{TsJ%N^_ETtrJ26w?AUrq0(H{*}oz_^6ef+c7tq&`z;WcUCp zSFOVLeT=aUkM~}1wae7>6wb&2rlzOp?dfIf=7-q7r_A!Diqc(9RTv!TV(EfGYPAa0N|{o*M73J&+P8yu+;-C+@JbcC<&_hK zfTA&4|l(d=2^qHRQDNQdlXks^)h+j5o)DqN9icOg*XN}wx=L>AXpHDpzIvO^h7{t zOycFp`Jg-cqq7n?)mZuI_KX1uQGkDJts2KpC&sspMxwwSiI_cRK$T|TQ=guq?0JMiK&j**VrVoQ5o5sk*f_nt3kdyyk4=8x{8%6R&eYw$KpC3dvV8Ky5?v#_6nwsRHNA|IP!znBr8sPC~K8_8?tikg%Vdwr9!mQh*3cphV^=@Y>bpb5ltvcAz~zyXd5lDZb73WgUFKElGll>q$Z-m$W5xO zE)cP^he)WDNVQMc{x28)`#H_tovh;L4?M);!H_q<`Q?m{P4ly#UCQ3!101t%4IlaE ze`R`V8e`y;6Hnv5P4^@9aX$UP7W`wM$SK~nOzKIl?_Wf36V^_Q(NHe^`}Xi=zlZO7 znukN7E1m|IH2gj0oj9f(z=mx^qfcpjOor#VDGNykddy{46ktvQInsd;=SxP5J^w>x ze0&j8$BZp03`s|)fIp2X*M|LbzwplArR?|;Ol~I)$nng!8q|>VLiWIw$GbUd~LPTTSdVL~MV5eacf)_O##H*H7)VYVZ zGn-uUxSy--zkbfo9>19L8mqZ(bT57VJ=A&@5Qc_jix%;rk9>;pnI=E`?QdAJVm;>_ zU1IaYn`nt**VrgunwjCNk2{l{H~pUXx_z7(hJ2tgPPOE+WO)y-Gd`D(I6P>q6xAwT zxsui+VXIh(M)1*y9h0u>QtRr<+if|f?(jRNv=s-Wus0)A(}z3F6sEvF9z>CFPo=Yx z6epPwX-)|oH+fEZjQ1O#~4g+#VkkHD=ENWi+|H~!m$zpJ=)~;F0Raae(gD^cE(((%k2fbVPJ&!VlkBM%c*ffyBNWS z7rDv@{N$y^5Hu8CrTWl{wWnP7(c|ws|BqK+$-eFi6|b8=YD2xZ#?auPjiDai%k=a# zU0q$=a?=gmdeebbI#|Nzq_9A|L}WB+j@G3aAq9B&~W8d*H9~WQL9#|Rl8WY zpzq2J$E_FqYV?MYm6)E;B1IisUU4F?%mNeVbU~MZ72}-i(95B#ADI zE&42mjMcU+RFSU5qdtS*KXf1O{Po%H!oT~%qS4`=Yr8fy|9i}H9=`edGd7gN%KAHh z&g7jp@REi7EL*n*^ShrjtOC}QG%qVDeo*b3sho7N>>eUJqdmZ-7gKiQ{4WeZJTq5_|}k|-!wYHX^HKm5qPo#+2m?-IWK zz>RDKR=B+!Sk}jM&Ex(%?q$!&0RR>+T#N~~Fg-m@*s9ZCou+qS8BcxcMQm8NfxGU$ zpIdLg9)PK-DF_syCyb0w(%aXw`P9=-xF8G~Oij%s*y~`EBU!{Y>&{Ee!r}*;cu8JR z5Zg&gnRR;;7n z@8h1EZbnMWas80(6O%}57i*=TqgSmYXf^omBU`!sgeUnu$2A^!>MLGw?e8wT`dPoZ zd(+CG@d)KG#4ovMmHM0GFxPAgBodNZDNGm=1_9+t6(t5tpmWSCSsIWsc8H(pr8K!L0Ul*FZ2jnO~kZ9fJUQbF&}Bw^B^J983&OR2P1KEbJij{&^WQ8vr;+2 z)@0RjJmIC2HW2-!F%8NAE!0I*t(Ms~IzF?p=@G6wkyD@aMDD$3JNMrA084u-eCpT% zZYwWl|B5w~0+)LpdW5CRmvPVCceAKk34d_SHBSfj95pg?^^)7~Sh+(C+R=6!gJ^|% z42UGDOIj%vK{X>n%Wo0*O-vACg1{lWRZ@~Ns*QGe*?A>Zk;r00>r%CaiX6>SlaCr->lX-m_4`5Je=UMw&7y%XHd(kl0@IJB}479dTGS5$PIu!4A} zdxfARfY8|8sfcD;Q7r1~ulC}zfnsY;WoBOJZz zXzsY}=E^_3^KCx_SUNcHu(%$9STB+1x=Cz!0)wm(kemFlz(^$%E5?N2x)_7TggV#O zP8z?EIisaU**Ex>aD6H?w^@wERJF>)<&J`*w3NS`!G@6`w{^MTy-#_~9Z{G6E zr*QS1H=zFIZ-4UopZ(@vUe>pg3$||Np7;MFTejXqrB-8bpo^|rH;txCr8dCuBU`xi zzrW1JyRQRaYHXZ|nMwBT+ru3<-pKHt-MsA`Z++TdzU%F0o^|dyUu{fJ5w8o(GH`xE ze|EwZH*xHg4!U9GK~q6G=M2L5dUn5L8&i=zfmISEnhF;OW!!27aW(bnan3&XjQdYG z>BKQd87|*8%h@r$ljNc^ys<2`u ztMX^c<`#L2>sUnuIE1Oz31I_ z?NyuK{+>^-aT+W3oqSUF_<;j#zU2ni9d`=l1uJMZW~lWJas3rnvTyeuHk@=G&-$}h z-na9>%r;Eu24N69?#xp+tys0<_kMGRR?|Wa6A`V`KG}tqM%N|M^eWm6Wp>QmDb07Y z$61j{0{z-mDzO)#_(<00kPfhBrCLUshRLaEPCw=7ADnvHDW_d}*`?2`l|1|~M3+2D zE-Y9u#8aR1;=i3X-qQE|-QWH7n)S!<-uHjtZ~pRaZ{?_?*I;hG2kkitR*mPoRcvEL z+CxRy83e5r7{Lz%>v9VNqG{C5q|92>S&W?>G;L@gN6vWaJIa{g=;VHez?~3tCk$A4 zwyn;JrZ0HG)V5{4!<>BF0Nv730+iOQxOCmGzkB@gz8RdD7=HQQM>f6Ulntl$+;r=m zCxj#WIrog?s8ky~|0U0%+`aVwHfClvu0DG4FF*e259i)7IWdM9lOFk|?2bfnd|)ve zu8lb|`!dhQ^qtat_XA8d#hhT9JbmM@nO@M*G-7=EE&?_j1OTm_mRBwj_zisDr|ebs z9COUEw*$}9j>2^nj-&Ckrd+N73_tgI&-=u$fANcVU31;_s;jS`U;Oq`jz8gKylRaw z@bO9>Ex$o}sPZgSi5T99A`Ai?Mjzq3Y{&fhad&aMsP@PsUhXBjwIn&)%G zqsg@0nWG4duHdPeEl2y8uxQ^SFt*t!pgul|Y0c1(=18r(_Y23K{)BVSea=fyeB4uC z@aFzS>woaU4}6?|e#gsDqc`kYbKG&CQl9h6dVPlJ$#G^T$C;iSV|rrD4lk_}6|AsR zw&|~w={ho>YX524b9HX#yh2c8Hk~VPtX8vU>{v-?g`tkV#LTSP;G)(##Bpi1?D>Jq zRV4c4wunsT{{c3iu=Q+?uGfcL!beJ@;&x^+dd_tx30>WkXmc>6%w}aC zVx8jeL4zjxu0?0Q``Z`xYzr5xJ?qEKR?{+J!%lm*fL5~sBAj>r8DBl`{4>6~Xz7ys zXZGFol4G9omoJ!_m>}MQ)o$fQ;yaINnOXoU^EXeBd2LpiRfTh;ER7BpGd&03pk3Rg zc22%3mZRe1mg7N^NNA-(&vo!k$l!uOmMmSgWO#J!mZAOuCa0#Esn^l2#w*!#2~o~2 zF~X|VtAF~>AN}Y@-}zU6_1>O=0q(o^4o*Mq32az@99yAB7=vCM2RxUQz` zxiplpuo`wDewV1qWO@{ZljKhd%#p*s;UH!s5QUH0nW;H*&*CyUbOu*SA;Am{yhjGl z{fpNwITxBiNMmvg?WDFsqHMKhVr&HMI9&XkXMIS5r+uj2G>G_#!iy0?;^3D;DPqGJ zGiFyC?ef11U33ToIXlU4u$(FU$y7S|T09e+R1z2Rr;K4&i>J3#=r}GYhnDX%F*a5^ z`skzYTe5TsV-Iem)oS57no7k*>~i~(2n5Y0=RE%W_r3ES?>yz>|MsuX>hB-o{s->h zl#|Y;J~PGk9goo6(`S!(OZZUowwzKJ111O=s8#8yl$mxljYiGy`R(1IEzxbMx$=GQIkXj*ms-A>!9MQqUkF`cS#rzH23Wu*M7@)lKOWt zd~=`0@0s>>=o1ZXeK%|7;*00E8BM1rqjw-}ibQ29q_Wo{Xb}c2(%#Hs;cVe5?R+9N z+{p$h{?7W74{@;0*H4{$yL9Tj_)-S77rY*^Hd67u_~4~%#3Z1#ZYF_d#?Wju2LM*D zS@U4rca261rCdDM10fVZDNVD{00^Ic;nQ#FuGQ%88)Db)?d;mIne)$kB3f%2jYc8> zRHjy9;*HNii=pb-g&IviWO`;&r(l1+TD~*nE3QFQN)@ACikbg+Q@%PR{!8Krw8ULQ z?$a*sh%FAtSXs#^D30%VnZlfPD5@?=QTRdk$)2aHE>5!#m>3DC`&Vc2kcwsr?OB1g zq_ogTK&S-Ahw;Q>Xbip|bOWqhb@XNdjIu(>E0s}7VT{SG90eF09H^Xp;<0p9ODtKu zj7<+cz|_Qk9)Iq+hzapqt*9F${Y*MR5JI+3_>B2w{F!O$lT+Gp-1vC14ur{cptNyF zRI_LUO|o5PebUiYH3xw^r9+1r^D8!%wkbifQo2a&^jD0XB??MY&Uda5DI`3Q-y{8WSo+i3_lL z_0bQy$}W!rO%Ot}RmUE19JeX1hqS~5V1%B&A$t1=^$Vttz^F+DtvhKrFXV-v$IW|kyPRR z3FAc#&OzC9P)O!)_R%Z?)dj84iRtEhZC0sX$T}-ECH@nwe3oc?36e2NenE5I%dVC7 z722+Xu?(gG)~(xc%c2DfXf|4y(BL{6?YbzfTOI0B$I%RrjS>VQ0|P_!_V;tm)mNak z;q0@|p=X@Csv99OgV_w*^&CFob^4QbkOLw zSQ^j51TixvhF8|A%hH83Xx^@OR7n6$+nAR0saR^xCv`etDLp`EJ}HljIt&H!4a_oY z+NtULbdC?=XEikK!KQ+k05Nu7xz%gd+_G}zDw?e(XmDNo4r5FuZBtSizf!5tYz5qT z*BzKJWWmA(IIhFB*Iv%rb*ovo?nI`hN9}<^5u3*JFwsn(ghI7i#dAI7w_4Fw2E`>; zg+A&y`BI=^AsrG!AF^tlXUbMP4jjrhMkPjKYJ4P}-ie1|)t6DfCeK5*1eKjVByk=b zZYzthZFYKf(iNTaWEoUNjj{kk$09moG!|lhl+$vwgP;hFK_v75x_f)}tzEZnOUrNK zXcu&eX0u5c_k`H$c5d=UYt?W(yMuPQRHD&rv47uQdVBj=yyz(Q z?AgcOJ&*9@CtW}gEt?}-XHocJi0`-XTP>Qc1|)nZS<#fHjzTH}M>6pp#WZh*KAb4D zx$2iGC|71qTGQ6pRL&+CtEm3-Z;ibbige46PW4h)DIWW)A9Y=n8%?RknSBsMElWMPLkJ7~~ZE2`8Lz)3SvND3x7Weha_l6NF(SjhBe%r*(+d zNnA|1Tw?$JeeB({n*~DyEM2;U+wZuQ?(Q;AIOj=>O&rKH)55>N4`?>(=?Z$W#%Xr0 zv5nrd@l_k1PQPc}c88qiV&p@DCW)_@wnj)H4+(4L4YwG#8B`&n&USgxH<^VMMUTp% z4Ak87bZB>R#AKQfv&=!`If^Pa`A``{F^)x!+Y;IOTDP>;)+ek$Yn?<_o^;A7zhAUq zAVW*QUPV6iapvt5!9Cs7TvrL2*dA&;etZM#TDU_F}nc;3vA`=N4@F&})A zmDFj+D#@~_{YY6ov+qT8B^zCw9W03^I7~>DeJ)qVTo77jzulfW^O!{6ByMR2YpXmx zv{Eg*I@=J2Ax6ZD3tG2!{jH0ZEpHwe9YMP;j_WZoHum^Nz1bJS&E%to9w( z!w(JHwr{6atFUD8LZ)Ww{PD(XIQOh`>Fw>O*{s{0lMp5*CU9NPY9zZmR;)N@rDJDO zWPx_3gbZ|R-wCo~Ie)q|&Pu;d_u|S*jFk!jK?TK1F=Ri%m6B&#m3cn8ol6OGM+QeH z55`>WEKaDjOWY2$D|X1Nxo4rR6us&3gGHlM2U^=LJ_6q-X!#z1-)!NQ+{Q^KpLAQJ zK7r#pl)Mtd`}aA+`}d#jcy8Km?aZJRMn}LP>Xu5S!k*oG*tu&LU0pR6EnLLLhaTqP zhaTkIbIxaadK#r541D}B#4A@YVQ3FtGLqYEKxO{VE47g=1*fw^j=5B6w(NOI<4zJV z&yt!}xcOkU)Yu(?W`h9pcFE-)m%?WzgNn_$*;qIm0U5V3 zMqF0vwjX;I{f-4!WE2uW=o^gKl_FuZMC+uJPX2=l?M_f$*<*5Iob6jSKOt8i?KDvu zN9)AN5O;@H^4PI$CqWR<-PJ`;PcJv!b|d}$-8}L93pg;k9}%HkDpM+z2m?dQZfTI; zf%KqsEYh%eD>WDkXTW4E<^Km$-#|OFrCD+zU3yex7}fSjviDvt2ayjUQq4rM z@*S+f`9h9E4iz|P{tmh%r9dV}yvLy3t}P3wlv2iVVjs0a7gma_JLcFM2Nx`~0YxG- zn?C#Z?cESP3s|Gj(GFVcWU@;~&XQ88M9Xin?UC(t_jXe$S1`tK>&@45)|uyX)KP1x zPuJ$2ct9$yYdr2C=k5%_4iUgEW&PXWiS)#Ns&Vc#n@5 zQ)=xrly(w-I}sx(r7)r4nB$JSe)YNy!Q|v5CNvm?;o;%s>3i*wbdKvJ?@re6iKR`Y zQeoe|{Y*|wGPGcbN~Ov}o40WL?bmbBh0nkbLL^#ysI>+W!Z6IODJ+Pg*;9wUD9WJ2 z@^Z|F@ejrb?Z#gU8M61IOv$ALcqFhR(XV-iRIwXQlJeRN!YFr~&!|JdaoM)a$;^eH znF{8YAIw@hprT+LMQl9VTk+vKD(TrQ4ADxpw01BUg1`sD8c+p$$Wm`__ks1t9Q*sm zOdSLq?XhR)t`m*lQn6uZ!axPBrrlgJo`EH0YK5Y|zn|T^c2lcX85|s>*4@q3*Z!XV zK8L4W_#_St@26U=q0oeZ0g=NYb3REs?Su{tokYCNS=M2w*uskw`J>b<%$A)fP}T~J z>n38?{pBQADxH&k*h%qpC#;@y45=~qzXP;7mzwCGIlDKW%j~?&Ena=yX`q0LCQS^j zRtsZ-5>NsaufV3axBup5E5HwYoU+T7t(zC^-M#B19ZO|Y5F5?eJ_Eb6Xj024Bw@*t zMYyhm5r^Au{3GX`^EfKCvR$wY1QKAxBoaFAfx`+#?f^SFO6WrwK8GAPocW(inGt7K zS{JlHYz%cMF_zz*NMiR>?p%+e$yFF42W>}M_qjTxs1I!Sb+jGlN>L-TW^2~)6^VsW zZn{F0ip)z9f-p#AMtq)Yt*d)irB=lcT9jRvefvk*wr%_ANu8CdYvrJ|lQBDW;*Am! zX6iE-gohvAOsnOybjf16ySupVkGHUO+aAt2_lb-Q?*pwcVG9ZE6ns`g&6|sIBDvk5 z?#R%GB7F~aWECZG3M=yroReKbB7T#7^{|~6h2A6*CywEWONx$rZDZ??(_QE?;*wJ|aW=&sE(9+7mD52%sqse2rk)S#4I9huc?9!`x zV~YD9xa;Dy>e^^WTjSG6GC1RL8trwBR+@6T#Q69)V`JkiSU5;`PdE48cQ3c!aVu-r zAH#HWk}ycmDlBTYcGx-3lo7!5nkhUSyxeKrNA(0pwna5Hi&@L*HVpC&PB}x3U zCYr~O1)@q&3eY)v*20_2@57n0Kj<^@V9i+vhx88nqEt5L&Kn_Zrw#B=sqB?1VYRCl zV?x3(zyx7QgmU&33K~vylt#7EMZ*ud>&^$3PmPWr7d6lbg6l;7pm>H-OsbhO0;y7| zFg!d$v(coxt45{T%{A9tNmo~eqgSnGa%ut-hUuo~#Qc@oGIPo7gHcXrJr;ku94@@L zO~Rzp+e+o9x?>QS`7O~9&ZN#Y%&Omn<>Nsj`FuL}jNPj*IzM#QfjcWYJ|tgq5w#y; z63a{~b2ebsm`*mENsi%za;+Bh3=9$ahR_H>7?#CQf{bAo296No`%Sc~K)XEn;KOX& zy7>b87TwfJqm_NH5tAE`MZ^^=qXP#<(OOaK>SFuO9gH5>!ILkzfT_tzkT4&dq{#C^ zmSoxM3AE_!>J+k5-^nwNB3m1iN@bDcclLcm_X_4;nn|UIxB!GGT7ua#LRANYAvJ0; z+CuEwx<_*`=ieGjo`o$)Illw`+F#rs@!q=tqctguy*Y+ z)a!LGeM;p%^Fpv75DW1=ohYWsVCOlbo#KaP%hO2(tF)0>qc5jI;)#^>86nwpI5TwH zJRFk1ilQ8h-;rb7%=K*EEVBLIS-^0ZWw!OJDoO!+Oo+r_%UZ)0Aln>T5jc^X$L;`X z?BuCRnWNU#Gv41nKo|-t3dZxpko)hy|3ZLDwKk$14=pN^($NG78M~{{uL5|U%h>1` zh)}Im*uH%it;Qs)R;^}oa@tK>A-PYo{Ln!tu>n6=^ zp-JFqOJgH~gn?ZxlE4k2*3(xX99)d=w+O|cwae7Z6c65e?~wR@sk^Ulk5{Upl-+zW zjJGI=v_(5h*{@n_8qFrt(=!Y%SU}S^+A5!_iGM*_TXwf&uiif7_HvTQwj`rq*WbOw&I zXpFYJRw}24rueWg6q0WO-<3=)y;yT1>AT4{fthHvSjI! zDnO}Hp;WGLNU6wg1sWxD`<|*g`j3bK-o2fuXMW{&H<)iTqO)`UJ=0lOv?VFt)FEiy zRybOd?&OrOUD7X-bSE(s@>@R5hS=FcKj7NyuHbcVc`L`9bS7W?)^`@a{1vbH$g5xU zye;4O_s{?5{de5_67Uyz#Z~w6~oVBXh0Fm@Rc&wggGXWMM~Q2E-~~vYZ?T z>#7tQW~&n;kPJgg=2J4+lD;KlBq)kJp8ITTLl&0IcSf*NImrA3O_m9gO3pIL5F3dq zUhI%9BVu-Iur=)w32Wd*N%tK}7_BzcT@odXXnN(t% zAi3Gzx*`*K1ZBz_wD1_s#j$Y#PYV8PHLF2C$D0zc#%U;pM+n;yFV z_N%YF;#C_rZW?;-S{ynp!EC!SEMR`ww_1 zz08$1yqnLLBMfsT$!wm7tKF?WAf!e`PUDd=q9ClyvHgUi8Fd5VTq}nhjj-@}@Vve$T3-m*IFN z{{1W8IOdIi{=zNNoH={>ij~*D?v1a1>qkHK(H}JY8O9q^{KtQOf5|g1dd`2o{-rP2 z@}uv3{bNCWdQGWX$uLQtrn9bCNjfR(KI`O%rZa}kzGU7^o$Y%?Zq_R{027Rye*}fy zoYRq*og>tqeR*!cbin?H3AJoz=O<58mMU#TNpr>0KPT66XQdP#PB2$oc6R%(^bjFC z0CY>?v_N6v>q?7|#(OAqz2tadbGptz{~*VocmgIcluK4hH=9jR4mfrRaV%7n7L<-# zS-^!+ChO@iD2K8rq{gskBy1Z=K;L_ zjc@q#pZ@sA|N4ekzvk|BE7!8^z%bwZpP#P$vsb_I?_Tke7d<#VKKg90QpRpGl2~3S zlno!XbSiXaOuWRErqTzq9Z;~!+fqR-%-Xk^;?nL?8P5jE;E2!bj*}BNM}g5Koo;d5 z953tm{*=iM<(amT7S$ifkM=l8r}&Xrh-4_0UF91yvoa|Zi|?z<{iqzJ70Pw(c3^?A z``e-1-1Z%cDUoWU85lw_8&5ms)Jscl3GLWHWsE^#C~I4et(jdTpY&9u?-SloI)OnV zf(b*E(l|=vw;F8S{7~(Jr#}5dfARLWZ9A}UCkqxY=d!DA|_SsMT$oQ?5rD`Q{Ht4pktRifzW|7=6 zTls+)s_5)c>q+GMKz-|zuM9>J1ig0igk8Rg18@s?lrGiH( zD3{CW6nW(83v6H%fe8tta|(k-lS;LE+qb{}gU4TR{&~%vk8EM#qGjB1{}%q@t#AMA zeYf5CUdM9@Lxb@HUiOMVf9)TxxnkYtzVO*^oOySqEY6nMi8nLRk+@Fel}- zrCA3?H2h-0J)almpq?bsL$ZchEFMJ>dp5GiEh$Y4?XadTeD+x)sW zz3~nI_wWDiE9H{Q;-glwZ*1mi0FLXTCDXXs;6+N~&eAzy-t419uqA;gojWm(@`#~E zF?RxRBwl8v5~vZ&tk~LSmI0WpfBgCA;pMglb$&Lf?HrjhSU?poD>4u!g?(8<*)br* zutTAY(%L8uM#6Sit9>>M9mh&>@fA>6y>882XPox9@kXXf+zRo_EiezWJ@w-t^|z-#vCL-k^`*%}=)78;U1aIiO|pIJB} zDGV#-Q;F)21a#J&rxL~uJy-dTqrr#`{WKDxo}}Ee>!`AJ1cmP-^Z-2JiRb?cz;P75 z2|+ZD%58X*O6s_-MD~s`Njr=&xUNgtD_QuW6o@Kp)~I4e-TuLk{_AO<{PZWj-Cc9p zy5%A6zHbws_}C}@Y0Crm|F!m9N>v+f+SAkhun7$s!|2Ee`}XdCB197_QGN2M1M^zq z6=&S$Dd}V`RU6kKmdx??1lG5lUL{&(WF>XHjND5I3<7#&%)?$hf34>ffnu5U5K~oXnH^Y)3HGt$!m0y&e`Rg4dJG8?UvcRIiT!2YDEcW^AVpg5WoSuV{VfuLtsv-j)44P#9 z^Tj=%4~l^kU0hi4ov~B$gDa+HoG+cKC~BXC{dEfG^3&bXQ}OC-?Fwj1BMUhaH;LFP z&A4v0sc;d&1*&3%#Y>mmcF~1TyKl?p&BvoWJJT3zLzM!k_)PU!>L*?eW&7K4?E1qn z@Ci*w*()QEI|Dn8#ITsUiFP!{9(Tew|Lcc8zWPi5{>3kR{i|QU_;-K!0~3=|FTQBw z=4THr9C`$Ck9pSfp3mOlUAV%`!lgq$7h^I;VIjpBS!KQh2@adHOXp&iS>8oVAjrWJ zs}*cxbDPvhQD)f_vD@BtxRWHAXS3Jld@lQ}q|U|Se=?t_yn8Y&sQ@yHkv~}-uK|e< zXDxz3g*aLqN81@xr2*}wwGco#nr`hlUd)BsM8_3A|3%OL*RHNAK^TJPqLqV$(LmDq zXv8>)v74)B*wjv__&$Q*xf*;w5u`<{LMeqYf?sc-w0`)lZ~x0@eCNNu_r_;D9WWV6l(=gyJ-1H) zhi0gNRt86dh$b+CN!)gc7V$+%U1^6P3=zaAr4VDd;KHYU=ZQ}`Z+!p$VYK5VbvMyi z$n|tG$RY@+(g7BR0YMnzY6mePL1>ScOWT<8LsEaO@f$6SA8_39Cw%==pa1NJfBE>o zzW<_&pSsaiA)7beiTD!}uX@ePUc3D0RhI|N7NR;pjv}PUN#jUm7MXNDC^}~19KkbR zl4GhP*pZMU!rt-hyJXe2YJazi>j@o0VcXhUaN}jK%_n68|8rfOwKbB<(y_u>8mFKu z3vH}aOs3f5^NtbHiI$9%ge0!ZbDWmec0h!o!I&W1P*4i(`QkVVZIOW8<-gUWTCMWD z7ryW_zy19+|L6!fG2V;plGN)Z34S4p$P0~asG~K_phXz^Xzf^UOAI+AZgD$|O9qcI zgpDR%r95%&6Q1zlbD!{p4-fC%`?$u;bZzOfW%oJd%7LKiC;ZXA`)J{NmSJ;yUCd@o z=4qQ$wT+phhfNCilCqLRej*Vchb!2VfoG9v9qKb5X6}^lPjTtxpo%Rl*Jvr!HPvDT zJsA0x)2Z(m&P4aJs5(9*C|3vjUf1!OuF{qng(%vNNT>=3p~h($V~>we5krHO(rb@7 z_VY^?Eu6t`p`#OrQ+mZxCanrlKvMQRG3)gJyC6Xm1kv7hIl2^RE^*s!dxB<*pxHt~ z!-B<&Z#`=DnrobL<$&L85yLM5YYDXZkh9m6iZEf38Rx*sxgGZN`SSZUtE5mRlAQdi zvjob#cRp-3@5KlzT2UbLf2LE)c|fw|6ep}yc34NZ@->2tbdL0HTv(DhT_7KA7#uJ9 zNtikRdR!+!D;$K-2w`aQ$3ZBJR!*Q%H0X`Z0N-yp@yiRcuU(=Ru7^PYLH>3&6KZYuZLUfLP2$#yE%SmzlkD@I-g%flWySnv7K_iu0sO^lg$GGTWcxeXhkU#ikmO2x zV`Hfum8qgunvaO4+;$1jlO{B^U`%O6Ru$6cf#QyLL^Xh}DuNQ%9A? z)x{bW5!1<@ z(j@|}>rtwdZD_9%j4y>L$GAKh=sY2OpZEW{q98Q|o^TjNg!8yAYm4qph0*cFQGM)@Yv?_d_9dERU zRthf)vKN(}5ol$Xh@eAJ(W;irNm=%%#?{JbW9&*A6~%F2*_f<%Cuu@P+D2Q5d9H`n z8rRWi9c^%=b)IJP6{ML#pZt!VPfql-%q4RcItP@A5u=V!8O4c(w6h|IQ${Fh$%Kf` z_L2x&B|{;0IZ1vdvG~lRv0vR``LxNCGNEzie%zY2I%fRJ$yP4PfDYT4f375gb)cj| zLeYqE^G2akXbH3u&?Z2MspO>}gi1@78&YwE=o|o2!75kwKXpm(e!n^+5<1S-Y{B5|xmkj`%GK67NKuBm15?S8x~o z#EB~`!x*ab?)=$UjDsQY#sHh z1{~$s!#P!S3KtSBjZ>7$6?ArS_FSaRs_giC3MXL{quzi^&Vx-d1uGXCfK>RUBSxLNa=J~k1xi+^{ab$eQLL-7j zl3J0tZ4a7a!Ij8p?X+A+QF82h%OGrKBy`Lr6(czKVSq7GiZz2oQqPF;`<15GaU$=x zu`5`V!X@@P+rJLrqVUjoI8ndbMY=)YW6wWSvj)Xwh@MulD2-=%N)n?mdnehRtGxg_ zFe23wU5V9C;$V*%DjKmyMLxYV^X4~Xaom?gG5155E89c0Yp^fht5MAs}VD=FY-Z_R9PmE;jc*Iwo64)Y~^;6 zE_o_M9B!qo{hEJ90a{c73u1+=kQBEcV#?Um`F9#3a8vKNBx* z%?@s>v^&vqKB?1@4GyT5a+pG+Buw9=QsJjd&XjT#q4Be0Au;A1jhP5s>f)fHy`gn% z6zXJ}Ea92>s8ESrcSdNon%J$n1nuaysqb99vzj*PoSC5 z9j7fxjzTPU8lkIkT=QgLB$W9)) z?Iw2Gn2eyw{j$)5!X0}r-e@W{{<8ZqrlllmDw_Y+s9C4B=Su&t!$cFmHu<_H>Qj+p zYWoaHJKIy_5lHgHwC!w^XJJih6V2Wp&vh}bM;L8{E@DGBvsyqqj&YPif)FvrEf(jw zP7pdSqV3*!A>bocctyWscdb!Ya3!bL0%a5>$BTAB4QRERsqL2W3`L<&SuP{Vmr^Ua zo7~GVn9Hm@6ibj;H>D~iXDCZ*vbN9orE$*1_zay?+%_VK>nN5}tX0;VkeM)fw0zD7 zOP%6cW|x@phAz-fW|c5iBA=B+Mj#z|G=(+s?^!ZtpK)Dq9gNZ#qYz_f0<%IWR0xiX zNPrNpl}eKl35|BaaqVod(uB&c7|QKpr7YYs2w^glX;0t^S}jBj%I?>Z8LesfXbw|L zJ2S_v&4mybrq11T9Aujqy(Y_KnXQ}+@oq_xic~7He%t*qW)6B=_@Pjlv4gaCeKB=n zp!ux!KAe;_{$g6i--?D|`+H)2RDg2P;7i-CGkM8;=5=JgPIAzE0It%$12hQjfj^NW zJL^k!1*Jq0h>u9vYI`3v10^W!pwa1OjWK}C7!8RKQ!3%17*E?(<6sZTh|BJP0V0OY zQch(haZ#{l+nce`GoS5ZHCsd~O;usWPm%=`v80VLb9~~fL={pLHjs(G&%%2-#`+U* z_Mto{@%u8>imzv>IrlpxmoHfepdw)qhc$FmOS27-;=S45?8!H9587G^ z;2el!DAH;RCRuBpqK{bHWji~J88|b5wZwQiHJTJEk=%#EZinKDI8?7i+ayQ_KYWhC zJDVPJydci45u*z+3axQ0$pBO~n(!e_Gu6dmfasQIQ&`Ezih1AU@gvzC{7IHKia0;qV| zRQ#x#wTyguDdd|^UdZfOsBo217%Y}G5_T2etd$DTCBhIeX)H&aBs4w(p5tZkeH>q> z5(XE^Y`C7*2(kWQT`>V(&2jgJwx)@~$C1^7WwN^o>iNYc55-aP~ zkR)y+t%D6M6%!k6HYf^ZcUHGMG-U#$5?owtS^9BMn<^1T_8n98=$gHfAp65JYlQAqgjn z^>Ub~fhx(Bc~qr)lo>KhZB)8GFrQTZGr>=VTp1&=(*#M8soUQ2C&G$Do|K92XRX-W z1y!JU3@;+aP9%jQam~d)B@!gHD%#NR?7HHml)3_O$}O~3I3)*Fnn9OG#4U}X+;OG7 zvN)v{cq7;@YzbO>a+M%davuqp0a#>VA;f6T>F$cr%XU01lz3{E8Ku!oV1m z3mD|3Lqg_H1((?Vb5j|JAG8FDRe(mbDMiaJR8(IAC<*bW^N@iO!9P7QMEeRqSX- zOeE125QJgQW0M+*iH=A$xv@NC5_?SHXgAsZ-|@U6V-U3byvB~{RK#96u8vm6#QG{; z5*44~9Ir{pGAl?@v3!R_$3$dRO(Bmi^x~{rZP9s@#(C$H@6k?DV8;AwV|Ws^Jd4?q z6fNUNbu{k8E1@-m?j>)$LtTGqjo#(Z@T0pP7$2B|Fo?un5S?hHK~qM;GD?B=2UTD| zyWrZT(XInWFIWUU6C8W*&FnDG9BA>>XyZi_x5*g&l-o0bjOLVBKr=ES<8%veaE)yDJ_bxHd zWt6`4rep-YvbxFDnUZrI6!%YbKY#Xirm>{6e42wyq|9P?74sx@oW_drjBqpp1asja6z^CB5seyQ>;gSlSWca%fW^pU`% zkRve~wNct`nvN7`qcqut;)!re>@kDV3fFV(hKzm-v`ixm+gEM9)1MzTEJ2R&^*+!0K%g-`r9!aJQOe9X`UM!&i#vVC_=?SP*5I01% zd@#+3L9MjH>9!0`X#eXn=n9x=?0#Q9qRTcS&dgY^geqG}E@Jm98r`d$@4o1#=5@b3 zRdo+N2w+5XC?S5(A}~QRQ<%;jh;b0Rje)iU(?oQNu|xcX4IYh{NeNmx_{q>m!C9eySkiC0$F;kz6*)bKgiI*%pkg{kx=1hf_*u5my z>20x68knCPWGU@D8e{K-x#MPKVNM5^T1Tjmt?N7|Mdn@he3D9Wd;7Z!%cSBZQrWGY z=(H4;4kEmB(g(I4$J7k8Ks6>2Ul84c=&BtMUJ0-#Ob8C5%ZOCLG{6n4n@kLZEi2HR zs@)UXb3k_i2D*S#J)DPbtT>nc^H<`!i6XS)PC!ii_HdfOqNx~OMXFoH*fnJ+N%y9< z6j3UQ&I{05;cCsq#B}$r@yUKXmwkJN+4Arfn$uGpzi!RQ`VAYt8pD-N9G4XwI=4ry zt&^Khl(d8J?C-?I6I~FcNRMz#vGZJRu=%7v6QL{F~)WELqz_C$8qfGB7FQ(1|W z5;W@sox2)dpN_L-n(zASEEW(No9?eWm%R78RH2sHpUKP zhy#HTpwl#bI$;Vl5Sny4bV49$rZ5=;#z2e*j2+7c$u_oSYqYGfN-EXx>dnKQ&$RdM zKlVBI-dC0f=)b~8=OcaIt9$Re_uO-Sd+oJ;>$lb_d1@wse529mI_J>N1J)RWF7pfC zT9><3`E9KORf&tlB$HT=>qK#lG)dW8J;(RF{kwkat^fEtegqg*=VJ3>pON%etcvt3 z(~R5%eG`!DaZf;=8^`yC?xgajV!qRYSq=ecJKg;}>##NkfqkI!o30 zQ@Ih5u!KlLVThz5k`N0+tPGKK1WFOR9PPllA+NexvUnhXG=~_7HK>EQ*0HgL)Q??6YTIcKY1;udl@oiX3ud5YpmAQ0-^Wu_yU*En&U3Lkj$imM|pE zQkECzil6+6ANjT`uD$j>;6Xf%spkf4_3!CVdXAuQT#@}%P-R~V@6(yJujIr2y<7?@ z34)*;6*l2z_FLR)hnYMFevplCEU4ICU%hQO=wEg0$`gMAjyy}LntPAGqjN~52*ZG} zWpI#ZIrh00lzVQSjSxbV=itOd|9k0u^BdmoGbh=50=gj^twnBrnRrXIT#cW0a`+I5K%k)?AQ{TT;UwX z7Bri+4S?127jFNXd;az(?*7=v-*WwnZ)UFD#046J#F(5Q2q!Vb7<3NYq{h@%c??$; z8svs7NjP|5KB>U$-HQo~r<)1yzf@EAc*=&48%CB)$T$G--k|?upE>;ME$8?>z6_ZE zu9-O@1W_C#gr_X~-R`m}@+*yTgCAn?2p5$J<>6?6HX};r^_qEcvQ2X8snj-&2IJNSA*rh58%Jt;hdjoHx1&w zot+cg>+7$-c>e5Lw>CFkt^|<^0)$j#Sw<8_D5c5LgftzZlr~DLOh{QMtx_RmQRG=8 z&-0cL@XVRB2%-4+T_5_CEevx@i=UgFo4-#fHBee5Q50<(hkWXZQ*XF%=FA<|n3@iP z5%ElM$17g?tH+KW{1azPE|p58RD&Q0M^egEDa~Y_*uJBRZoWwHGyRy`T{%ITb8!&S z3+v1V3YSxD4r5<-pNj{m@#7^3s@=v4l0q?8>mWr3TmUYED2Cj@()Eu_FXJ>VjtMDP zTwLVYr_aCQ&))aRSFEgGpucmGcC*dQ?A-3&=9#%b`60B%7;k-9p69nosTp_Y3<87{%+A!& zfhN!MmQV$c-uKC$edY_bpN*mrAuvkmL6#SzIF6Griuyu|A&5bs!;TJuo>D5&K`>BC z_obAHRBEJ^?h7GCQmZTo!>+MtgIqdz{{GhpX}Qo5q;V51ESYoT%4*o3X{~k$FGVPK zit0X=uPKaRAu7NnU`GD7#v#nl(S7RF9rr)=$#-Nri+6UmU(ngPcw;?|5mK?$-Q(%U zALgnPm#44!)*pDso8R)y|L($0=WW0G3-|oTdM)($aFfs6N845BD9Rw)d8Wg6?RRLU zQBu(9^~GPk@53KIcKKyb9z3{w_tK%|UsHkf!#V|Aia`&{sa=2y@Kx|9#xK-=SGC$# z``R!08s`vF?gMdeZ}-Zr_4PMC{p1sG+S%NAov{`jgftpW=9Ug%9b`#Hz0oE~hFEI| zv~SNEh9OEzhW$RHVZXc<y1DM^_8XkHM&b7ijNxBt_1-3u`x>KfijDQhduR?tIyIp1k3@S4bssrkW}4roPa= z4=nvIH`N=%zrS}m;JKxpQ^1^7zI~|x@XN9gC5VG4M9Bbfbar=+udlAYW$nVsH*T!1 zzIJP4m20lQk!x?djg7Tcgmk!~U}^afmtXS&2K@n22=Y83{&JpaZC_KB{vHyidc*i zM6w2b#YU>B&DL?o_+HEn_I>{Jp=Fx}F{Ie+bt7GX=bLx8b{#ia!{x7K;~>1UW*SftnMzWms+W3Owp zXYO*9{&WhD)9U;&-u4^p@pBrUTYvFf$%-!(0Deg;FCdEIi6!prEv&CxeB-$@Pyge+ z?VZ>4dOZ<@fgj4Kl+X7IgAk5kzlSvi>le-=rJ&YmF&GSK&CKA8VPkg_XA1iL4(Vvb z>dHBkl*k|=2t(ppyS&L7twRtFYYbW|f*@jU@c@lhi*rvuMPB6G{;JpT*B|WC*;%LF zXq6V%FGQ(*qro&uh@zM{8@J~no>r2{SSeQ}gu6@CY2b;6?%O88-Z@ynzLz<4p;-vTd*`NOLr|V-PqCY<;d?}Z5f}Ncmwsv=@HCsGz-~C)% z`MR$^(Z2pJsrCoy)=%ad8|6#q@l@-&I=-aP`m5!9p9{oc6qS}3dY!!kYZoqj?U_@j zzO}p8d0m!{nsGg*)o#;jw@H%}r8P6{jE&U|y1QL!%?9ncd4v#btgW!}sZUU=)v>M` zTC(w#^dx82)o5vo0fQ{9Q)SE4DO$$Rqtbi<7-?i+C26N3AH_W}OBE%Q% znpFa*x~a}NoUD2_dq$yfg2mV{Cmkfh13J=Bi(we^*Ppzv@!r#GFCppNzP`2nEpK_t z8@c+>L3Y+JkYwp)0H1&O!SBE4p3i)T)=gHPd6r|X8Uw9C2?~>At?$A#COFtH))EM? zwxom0>L4kRLb0>AN0wV!vvcS;WPbTDk3V+m&GQEi{8gZXfw3mlQYB#&_jRbx30b*T zQzp5>DZms2zc_FI_hBytgkgkI-ks>~?#^$luD)q)_2M_IoIUf6AnWzU3@X&jH0DuK zQW(qetFJ=JfVsJObP!;TWp8JT(@#Fe&c-^;)(khl_;${pJ;T#aKI(%Ct{rY2b4~~{Cs~YA zB!fvhH;$nuV7Jaa_ukK`?Q^2lsM8w`+1}jd+U4U!^^h}9pMK?;b9?W3;GxfbGa}&B zsWTi%dR%tHNkScvkxL0v(1dFCV7aoMF)KQJ-nytYgsc5r!eV+gtQ|9h6c8QA{h2 z5kg`sQ2MZ&G|#EW4T4BBN(K~JL7JrGSxy)R1VM;(25T%@dtcZVhA@igce`wFtRbaB z2Z85Ul~3A?UAodu5kjC;HIC1rr1CX&B?ydDG<88ey8uPO+CY%io0V40<5f(P3B}-GRl?;YS>u*1I z_cupD!0y%_PoH^;`f`ojS|TaYQi1j7D9eRr$7b4tS_+4drS-M~Yb;7CqBz1?OB6<2 zamBSLtvPq*S=LrBa?8y(5Y?OXM=5ENvb)9iF&fLb@+SjeGTzu=+`r7OE_I78r($wm8X6NVq2rl7x`pL)GSiL|T*UO3`jgp$R z3+Fj^<}`&ZsKqs$gFMeXn1x_88gT!;e~VI**||9n@Lq>3NifdPXtoH$2;rd7XcE_I zjD~%j^E-x+5-l}Z*(h*krp=(=r`c?hrX%vSAWIX%DCXGZS7Gu3>k5oDUUHmgdiRaLniyC4(VPBR~7p00Do%SLOy>gAc0T~<1K zEH5l_`)#*z*_BswczJ=f$3KG-7ArId4=r>4+4J20`Oi>q^=`*I{>5_;^ckAK%+ja3f9kRb57?|yf$y|uCV+ST(HzIAhL?G2s1of%^cQ5+M+ zG1hr%%ll0JOsq9*tgj-4FSNAAVX=PRoe($+gH8vjd}5`$H^MoA#nNoG07#RRVXu$1 z)?e6UNOy0SA}c709Hm2))>u<88ul6XdxSyceLX2Kg&~e>=s>fZB{*wnH0t0SQ52!H z!We@>Bc;Y#gOZYZqfT6Jk|h~B)C_t9Z^3bdQACm?IOFT>!pQsGMV@0#)q@k9b!e?i zpVJ|w#iEIeO~^X1Cs;3mgj^z;JO#QfTPEb5l1n5y}loAA4UXGNR}r1 zFu32vy)q- zUkjrMXA6?#yw@%uF}5gOMoGWhB?v;oFf4amfib!7u<6*xJS0Wo?Uj@m=X^I%bq4G@ z>8@kl)I7sc49g%_PHnGlyf{3aWf4w{t=8nmg0V0gz>-Q}koka6191f1l=GX8g`cu-(E}Vb!-qz+@^CUYuN>hR`WbxoKCNIXmVxHx=GLswVh(J$Be_y(8an=uy z5kjDJxpj()asq2Cd682Tg%7$)ZGyuR1{HT}356ufGE!s7(hLy&PnJs#dXQe(bY2wh^pmTr;5 zmF!dHT^nah>d~jbcXzf3qB`x_HpUbvp>WP)MG991!Czg6rRM_lbPQdqHF)r|pZgE* zdH1`11mRdXu*j9yoFr^CIQz_Lk~{?j%~}(IW0WQYS`&mJQ5X@ITev_Vr2hhOy^eE^ zWH|CSNqR7wtRO3Lkf4-A$q1>ub+X1=XDxmAc|#=zazvq~Rj-leIqR#d$6GU0Oy;AKGsNQxvObINB;f6~jq_p&o;Dq-l-l;Bl@zdX!#gkKtfI z7=$Qkc8E=XLpA*&j@A8nI|4+ZOvb6tSy6HM-<28 zg&|2s2(8Ci*vdHic-;BxuM|l-LMe?@5k;00hKiyn`DP(~G>r0L$lvL3Q);^^g@_4zW?f*u{kz`&^KmWC^1?*QxlrP2nYFXlxK@!S z3*A9~aktyOJQ)pVRVhe8`Sh=E1?88Wvkswkc|nE$DeB;?Z)PH7Szl^PF^oWnh%`%C zXwS2}e1LkbMphVhwzny=9BXrMmckga%m-qCXCo@=p#0*6$+6C7{E}pZ!!aCqcVTOD z(=Ws*BGeis6*`E#Uo0I#5Yl;O7X-w$I)RD^q(p`hVa*4$X_6w9LN^)+TX3M(BoHwl z|JX;k`@x4;(1ss+%LrVJjVwXV%wY4pOtY1h)ylINs$vkPy^Ap~yYGHtjABvkfifk- zfe#4d8atf?8#Ks`;llZgNE|m_e?4of&vJfkmwJ1f%l7)@xxp5O@A~%dU~jLBtk+pQ zyv)WE>uBMdmwU_X4Mmn^6s2s{mOxik_D~62S$<`$U}tv|sRZXQT;$P59^sCczJ!}@ zej%N1ABR9Ig)`om@tpn7#>6+zmD~1!u2lZzk>@E3OY;vcA3pRDz)jrx(EI=BH{bTr zPd(&*;XnNHe?D~hP_nzRad2;E_u$^{&XM8f=JA!4i$~YjSH#xV*38=aIy>9j43iOQ zo-;@ivLyB0Nu?wRHMJ-v&;e2GExO;r8|7AJQCbm25%nlW1)x+&9L2O3<|)?Jc;d;& zX*8SE2xkXuWD)V=97UFocOa=GQtGiET?Kz*ceMgGmCNDV00}}Cbqc0e zmW}|mS!lGlaAt#hAAE>SF<@z?g;bJf&Ya=g*>ltvk5R~3w%2yK{-#@KwVE70beJ?v z8H^HwdW#pGIEZLQ{Fgs?4^b5R%&ZU;){-PUh*eQB>jx>L4U|>dx5XL z^J}>2rWf+NWj__4{xASo$NukDq9o%9NPZXoXm^u7jroMnn3ep|55rx5&JB?s02h z=@38=NR(2T!jKgfB`Kw%lB=%1l2^a{r8H|HfAYuwgWFzm$HO<=cuV@^sZ+0R&CW0w zp5@tRo?$Q;P^(2q1VI#1uhogekRT3;qlhT_3td(J{W2h5Mzl+x1Z3>EvTGD0ZsVDjDXYS{ba~Cl)v()RFm)(9V_dIZp z6H5|;6gCnzvN>iKn`6G*4_I~Mq6@E?m?S1jBfd|8S8?H53KsPU(jmB_3<&EWVosmh z<&%$nfrn4skJb_$geawbC6APxdG;JDD=W;-&iY~Vk;XbhtyU*b4ca8^jRqWCUMe%T zKKmC30Sj~UjM9XnC_F2sbvepSQj9Y4Ea%1>ZscoU{aWIBlXm+NTJN+PwuIU#XQB7E1LOQb9Nj_Nr*fzflAZyoTNPki!+e)va!8!5v$m$k-BzN9%3&#!}A_gu$aW#MXp}(b>ONb;p zTZT>Q%+J)YN#DC%uAJ-V98_!&gx7}$K^SrEcJA%bJ(Kb!o?M;X5~uCQq$tO^Ei%a)M}(@GQO%|plLQ5G@1>H z!jwHhm=w`UMYA=F$sMaJD?EPc37$Un1aor>tgf!o>kpWpU&0m!Q4Le_QaW)dil=J{ zCX0EJTk$GucWKXw$#LYeBOkl+@?&r4XBmURfRk5UMSG^b)2KK0=H};i78e)Smk%F# z=DHhhc;M*KW2YO9=616+(^)vMw2didpL*h{TkpE-qu=oPzxt~ycRPDhYei5Bd5Sz| zG)ic-W=N9+V{=BMlvmzy$JX24{7vus@P|MAw$08?`?8})SYKVkI=_s%y*~Fn@;HsS zPA!(=!i95KAk8wOC}MeOo}%J`ofo8oXLpS$FvgG@OWGS^?BGi*&9DA=@r_sU^FQ%J zEY{)P&wh?4&Tdh!H`vJx*Bn30?Kj`br|)}!&5bqgdH4ysolTC+UJs(+eAluYG&me6 zhTRNG{u?33;-+e-kW=7=O{H*2INt=(dS+=2ugNJDGFm~&$Q|6?s0K_ z9VIeuy!i(H>#zShfBNTt$d#90!3{UvNPDJDuiy77NF}hQs)Ls}XO(kKiE*KXoBA<9 zwVV34o|YMk|dQE@iL8Agqo)?5V;L5A7fazx<28_|D(|<3Ic^iyaH~wN~uybco}a zdZSKZ3M`H+P02H#=`*IRRdeO{LXIVkLMwzYpuJ{UNq+-yjz*(_Qj*aqVK^KhrKH(x zd6vak0`1597KNcGaz;r)GD?_hNWvqFEH5ol&}NhlSzW!r>h?At{OeD0VdVnO8upAp zBe=ZtFbr#~j5KNN14mn!arY^uD%#WUURdM(Yh200R|NpxnpWpE~a`mP|C7=^!R&!=I8(Y z>wEovdgZkzKMr6DgOc#r=O2FA&;8U-{>tYbxbMZgogPXEhRKMe^hv^C(pl=@+yYhi*N4_5xD-i<;&ci*s}Q;6MLv?!M=4o_P8ksmjAzvOV1-%J=jlB&`Ah?R!oPh64f}u&}T+jtMAx9A`;NUS!}LwR%KctC3`u|Mz$P zggCCVv#~{Yv&U1b7m?EY;}_Oeal$bijW90c&SOV8+`R}-4LIAAaHx$*vyxvHD4z!a zO0WqD+Vk?2u6WAlz>9zkg^gGay5M%JT#Oeb)nhg{GoD`W5G@}VF9>6Of=2qHM6Z3p z(d!L);jzO+jetjQ25-4fMHp~}76lg6`N@AVQqA2Al(RO==yYIe>TW@_KKl*(? z#23EsI3NA!-Q0HTi+JTLUWO?O4jnwq>gG9y{eIb*)L&PuLwKgkl@nXavCz{PomBHw znN{3Z5GM&C$+Cnz%~(2e?5?HKY8zvy)tjVA692&WeeXS={@nfgnv+*EzkG;|%}u&% zDPgG5N^@X&nb*AfYrgQdx4h+DU;pMezZ-ZO;EtEw{*olguAHBnxg{NR4$jWZtY2K) zJ@>x%z5n)){*Mp7`|-yfz2eC;=P*DR#gJt_iBS{;s?XN;7QKF-Zl{lRP_NaQotY<& zW1o?7Af%vHuVInw?d^>#QM~5DvmixQcrqZ6G-j4?Kos?fq6mlZUGHr{mKJn6U9vpm z;DH4e7nV4`vPu|$)Da)}=p!_mG3{oJrNu=y2Ln)!FbL`Py2Me;O*h>{{pdBkKHNia z0iH2j7&NFa%ur+*2oDG;y{O7(%BpToWunO$oEhht#}(~TK`pAYtk=A078+y@Q3!!# zYa2eXzDnBJWu_jEu_0vTgS&A+*Jw4k>ofPVFf-$e70UE`TI2-EH+igfb5(Np5?|aP zmBtuDzq`vDzTumZ;R1j3&Oc>$ZwH5AacPm6)(i`a3qB2==G1Bpj45}Zk`63|Pd;yM zy+6Lcg>BW;XPkmU@KuPD1m!l=?}MnCE&3qpUGMyzpS2lWeIcoVktQ(H4L^!t6% zG$YGX1eWVxaLtpodUXD-zxt~agKp>c=4`Wn^))Ye__CSS=_E})_Qc~)z3#ui_cvet zzW2ZPpYC?M2LM{FIzmg76Ju@~A*e+$gW-T*`|UpjpxJ0rtJPSTUm^^HvUhRS)KAiA z%o6u{=R+bx8cB1Z+9NNN`JV9bVi%B~K%;oNGU zoEr5wDB~hRw7f(`_2Hlv z$1E=|d&#HrNsFKUKYsRYNs_%y3rdzCKx<7HDs&LCva(JA)ax}499W>p{f%qX>mZe< zsjQ(emZI>Y{wS2=tYDsJY;CQ3_Ck9aN-K?0nw1OZ*w|Pfw+F7;4ph10JkJRN&HUUP zquv(VyW50O%);UvqhZ9}-X6XFkjsxB=S45NgMP2isi&V|Yx5$3_GMOcvu$2{%MHxg zA-BHhHafLBr_P)rO*52`L{W^%Gamf>L+tEieDAe6+$wqEDa%vLa&v2jVbVitU6#sO zq%9j4ms;oC53EE?-5IUD7)oh{K@ww_b9+!2|NUa1(S&Zo<4^Y)0Zm!8&2=~{JQGsh za3RY69>&m&BU~JnuPwk?=4%a1n$t7I*l({&uvF=f4~BgXA3VezFT0bKix)V5@jS2k z+OHuDBcdqATKN1!4|46bFTfbf0}njNg^TB?H5znw_psJ58YXo1_PG4`k&o*z7!`&8 zJTXS_q&r6y5LUp}({tIXo(JQC%xN%>&AaCb|K_6~{kG3P{7`)5i4){`j?xMxe9c(1 z)$l1=>!{UhwCCo=0gb>{n^aqjwQ%CPYYCJd2Xg*7Qx;hI&l5t@-R)paPE>E8w8Rtz zS(agp#TehP(AbPL8;-?2Ns=IiVs>_h+!X$GRAA10x?P1xCFyiKW9>$sWu*&R0|cFJ zhesd%Jl)afA?#WR%by z43IQ=;gSY7AhU48V$5+lWMnfk6uHpkQZsS_i^f<_-3^BWicHgJwJ>>#Qj(eokrtE) z89BirWtek4UleN`)Fd?Ous!1Ob3=SnkzfqovHG$yTW+#_`}^e|50z$=x*)Lsx({(?crkQhPYh5pmnJm7lspxc*BwYcuVgkmU z=cj;889`3_EJ7fnI39N%GKIkj-wW6l7H0*{T5Ordc9oRSIs)k%mSkB$7$^cAl+>Cl z6`{7k$ zAW0H*5P0hz1Sp}f&SI<~&t zg-(GA>)uER@E!ZhVuTXBRgvxZu3KC7#1Lp5fDEv<)ONe+|0{;fOAL&GJQdVpcPt#aLsx{PN3)YXPHv#+|RclTN3{Gf$o-iUO{?@#G)f^un8dX8F*8GsEG~ zXPC9}t@%n2BSbk#i)coBGSBR!fvt`=~x+?Raa)Q3f)8 z(7BWX;mYkvDR#Cu(K^5dF;ZBebx2MYgs@x{3#@m#dj#BBTCQOG?((8LmQ>4oC_F86%k`M$6r8Rk4@Qts3JwN_a zzrdN(Phg$n+_|&d_qqFc@`=Ydcm4ua3Tll8LIw;5eL7uVFM06bK@J}}jF>;livq)< zeh^ncAp|N*iOrCj07Cear)Qwk<=d}Fy+c?BW+l{W{tj9TK@8>WZr`$Ak}8Q7IrLIW zVUK4x;*h<~jE#{Zno&6NeSIz_+xWyXPb~O^NpTpI@cp6vX?Picms_Y(0Ok#nDKbnk z!r2<#UKfia2t%?wqdhyz8@}#MNFfMxz^Nyn#N;_wUwy@0H{Ej6FI;xT@lWJM!QO7i zQ;AZPio)tPRU-fKhB7v|rG+lPL`6?gy>OC}@mUzTFGC&#!6*m- zPh%}ui$$Vk0M2sp;tD_bgFnpM|H-%Uhrj>p{MI}E46Pz&W*b;jc==^{wn_>D9g+@Ng-)_J;J1HuyI9iA2aHY34$HL8I8W5IiW%#*MSsp5j0c(x<(BG#rd@XD;VUMotVgX$Ka)863T$F;<;V< zJk_pO;zg7OY7D88RdQn=x4>B+==q@n{yoCT7h-ff9bDdJdHKNSZ@T5CpT6?MRUeQ_ z)9rMDvb@VxBm^-1d3MSqS3gQ0dn)xkeUxB!-UX>dCI~TJ6@CGiw;utk$xbfPfO)U;EdBUJq&^H-* zl5??RnLV%phaA=@q|GTjVz5Z&%#fEXIzGP>@`>{UzO`W~YLGd_Xm3Qz1T>OH>J^7z_p^{XPemm(SgB^Yy=Y;^eizRjb$O^?Ici zx@@i~tIXwO$1gKYW1?f)r>;<2W(pI&>-+Ot}%KpaH_UG_SwR)~@chyNm2 zTl#0^iIp5M&atq##AojQ5Fh#T-(Ys}5a0jZ-_39Q{-5y71CMfWd5O_*NWVWQvrYkN zlA*MwR*wku9OMO7z+gB;Dn%3p1Uh6e8hI^-*5pO*wIbHLJk}Ir088O5J5%4sIZuOG zW6AT}TWK6wmN7ds%huKwXP-U8(xHO@ENM+uZJmuqoIJe9(aW#k-0C`=ZjUtWQWSmi zAfOi2P&ksUElyrz;ZTkIjJGa~Gsz^MTMda_F%RmQZh7g}6>=it_QJ}*nT8@x$>;V-R>gT1NqS7jh@i6+z z{ZLvl8l~iUL9ov#uTMmF=x>4GT)vZ-uj9={{3|~ zUjOf#vorayKP+^l}_y4E{ zx+x``)_&Bjvu><|o$^$?^s>AHLf|#gE?{e8gM06LfN%Mx*Ky}7@8n&7_I@6D>@-oJ zDGCp!EGvAAI^|R5gMOce^;~X$FeERT63=oJM4=^16XLi=o@FGXgnGS!wT8hUq1)L* zNX5d!JYgJ>=Z3*xNSMqTAU+tB|M`F&Ol*rXa30KnUu!8bO&VpKNoM;V9wY zOq2Kg>ASe{>cjl5zqY2wK~;m<8SJb^DnnRLk-35* zhe&dh5L~vm%ro&UzbFOWtuD2Gk2lVReD~3WmQERpocfGJ2;;YPX%V7KJZMu=6WYs0 zhdGZvy~9q@=LH9ka^023xc~8|+3s|y)ymy<%p3qxG8&~U%(j_r)mhotz!>LapedK5 z3LvNZY`d~Ah;%-qsI_J|8qwX^r4fbPddtnfed7yn{<#B(4z3Ib13EiC*`>-3uwufq zmH(AMl48oNP7X1)+|?7lDZ2-730F#efN`G76jdl$0lNHMhfyJwrYL;YO=&eAhbzl{ zrt-zdEQj?zTwJel-$Rd36owCewu%%?b2+tXf&G`Q(#R&nq<`KHS(fh zZDWlvs`=g=!duuZ%gPJw#pYE_q_xF3+a`p>7~is>R;!WcBL;&$AShx>EF}GIpGLDu zbEe5|lF;wix3|ExCb>e{?)u0~2xh`i`Mu5QNIm7G<6SH2K zpUT`j)f%!mYaNl&W8bt28pf-sTzR$xGI%Skv_dPzeGh+u!Eiupc7|FUm%goU zyA=eUFO>+AG$|X=7=kdQR`c{zmL|-!nhcYaqR6S&Yo(^cN8rQZpcEVVax1L^(mY29 zg>z!c%J`8IK^S^J(ORM~CJ9o8!=YcWQk6CG^KgQ-+bi#Jo(6Hx&39Y z=E!9$JoJU%B1?0EP=SyP4V-8w79!2w=8(eep@RlALXZ~f^Zf3`V?4Co6ThSFqc(fNY z?^Z!5io&9mLtvSiYtw8s=~=;D6wL4Jacf;LAEzXH9nv%;YPWntMpq68s>M(gtoQY! zM=!hL&u3fVqOx{AEAlyOXR2AMWZN+hO@R_6a{&jpb+#%2@jlp7J-kgjho;> zuuXeo4JjdxBW7B&EVkRU+wFdProDRdnv+kx<=ejVH&5Ph{RawT==XY1(y^6;^67v5V?X}u zKlPJ8{)1H+l`{rca?x(es!zZy$7DR!YAajfE8(d>Sq5vpUT?C+Nx`7k$2yBrnp&+! zmijuj-oSSyt;aE~<_xPF8)z+2$h8QOs-@@sL$~_*uvGLhzl-HQu-k z2f`F~I?$5P5D+=faO~|-ES&iBulv^Pe{N>Zc#4w=n^Tya!q~_Zu4YU=n-|4go||@F z^(q{g!ovaGg1 z2nu76rL=J{7yyo_QO6`Her|}F^83BCR2o66)nYUnvDeun2>jOUw_4*}DIB$WgFM%K z_^&^X)|%E#(`y?_D$thS_gGVc_E<9(vQ#3a!z6-aeUF*w7%pfL8{Y)Sn4Gn>9d@^O z2$Z7G0WBvuj^yDq;^U7g{>_%)|9s)l>o#QRGAbabL1M`3hd1Vq9Htp{%Pm}v7`W>2dN02XPpom12~nKE13YaU4+?L!M_dKy_Ku4yM@-=62|y;5WQhSr#Hm8ihnL~BKL!GqU00%jiQ*+V^j%~ePEs()2$oE zI2V3Fj-Q`Chw?pj<>ZZh-%H+DIL1PieTS5EJA2G89pG1g>%YC~{Dlk8-h1C?mku2{ z%D?p5-(fb+Rla%X07TI9K)(_AKOJFrZeiqf2R{DGG|BpkA*N1Zu*;D*v3P$`yH@ zPfE6&@6O+zYm=oZNs>~p)qS;d=?{*RIf8L2xDs7SDL_J2z(J)sx#Zg*gjMEJY81YK z%wNdkJh9s+-Ps}w0w{ddO&n)u+FXP~4Cm4-}^g7#I|tnf5oC%;#atjY$(RID~;;l}Sdw#w7kDN*StGn5YW)ZFp0Nac%G%f2^Z z?5qo+*jig>@z9~+Z~p!}UjF)5z2b>%-+TA7qo^l;L_dE7@r(K5q z;GFiOD`ZQU`m9TkIRRruCw8{C_5rs7*S?t^m#hlsL^)60KW>fTz>!0I@}7^s;8ROXn*iX)n^|fWzt}q48IlA3GC$74J zH+{pa`Orr`#^X;t%k0d|*a!D&zw&#P86@MJujp1@ZvvEh4Sx>S6comwly^tcG(~H# zUmgudSYznz?T}^#vx`dz9C@D8YPHCVoZeoC*_j!FASi|IYC>I>R3=jTW-Xf?-uJ42 z+g_f*Mp^S|0T=K+kKVvvoZF*`;-AfD9IyBIw?pmzMeTXYONteT`Zi69m4o%rtO) z+I8}twzPO&{#p59(CPL#cwmmVf6LcXq(eUYz@xO9EsDYe-a1)r3>-UlCL;lMJs$OxojabaP6 z&J}>Cub)y13$y~sX#~G{pW(J67HX6(0$>cH=+em}-ZEqOw>PXpob$ci67UND`T)qG zUfnQ(=dTqIJD7E_SH5Q?z;sbpzVfq|U3CLG8F;_hTAVc)XEDxT(t@#VthU|~#A4si z@+n!;Y*W^E%pFgIaUaSmyIi&XoqE1>DJHk8N}^0HkP2&V%Ej2XFqnEC)KC8Sk3GkU zOkP#B)3SDa2Ic2?r`rSF`#-~8pT(u6GnZd^&EFn6e8t-N)vZsdpz#;Sj$HOP#^tRn z&yQ~J?$Yb_NYe~s48_>*E$5k(EP^b#U|TjTtkr9*te&US>2UhYDr+0tL}4&qWEFQ_ zNk*$GigAC7G0^eMqBBtaOA zC5_V-d3@E%ov!M(>5La;Z4E4M5ion$V$b_xP(gKLoYvvYGyFRi;JrNr>vvD z8RgHi1spZ!7l;K8w7pWW*d@Q>`~QzYaQQhi+Qk$())eJL0^j{fI9GNtt^8eA{w)9Z zv2;vxp=O&iFd``f=q>bEXw#P2cz6Zuk^YlN;Bu(7$x+u#0nUVrDUeB>|xjGJHla-KcA!ted@Ul5lK*{f83 zWubw|?gFKoMReZUzvGV-p@ z)M^vs#M`Ak7Nu(|?D$iI%bH3Zh?dhCLm+{5^o5| z9ZrL&1F^@g2=Jg*KubfdfE4+rB7!C#u`aK4N0mETW4hF-6gTbIa8VtixlFW`q$zql!%l%P*F&U+ebTn-DhlBai zC~1yHqt+-%Tf@$KIpoqp;x|NZ@c zNvA&`uGKvEEHz;ml#LaYA1qmZ-|FUDA;|lE(w#1s9Xrh1{>8uet(U#&TYu&FWtTlB zGDm1kQy0k`NjmS6WPb3-XBUT`{rF-a#ey1a&WgQ@vpOthTUQ>OSFv6eSuYZdG9ir> zT3WO+BGMLBcQW5}*;TK(tMk&I`57}xP@@fydJGOZ25AYl@`o3bl>#6!iCrorj)O5V zxj)mc#Xc8e48CcURaN*fU6GHF-sP)c`yA}Y7!NS9^6pDp>oK6G0XxlXOfw&s0{Bv3 zPkvq+K$=Tl^Bm{A@2oD_Xi9(7gG82vtqP^Qm6c@*yK13TT?Eff+j7S+ZNr&}bw-a_c zT`?F98bw|#o7^tvMLt&;J8O+?J7?MsTNh3Q!a5P;xH<$cKXTwV-}*JL{ed|tS=7*O z21KnEdg%~$W)3?Xk#BA?%5w5rNYR)<9K3@1vBR{kxe-xo;)>i$O-m)AD7j=I6hcN6 zK@*ZKlo@$2k8gYlrYY`tKfu}Vs#Y=C*w2A-jKcWuODAi5y@i4cDuL2WehgH zx6|)Yxo(wKy=uf!1%_qKt8d*#^)ma^fOInG|Uf zKdoz&Bc$-LLDD5|)~R1{5;@bRusI@%am_ZaIghK)VB#NKBMf?79+u8jA9hd&{MMkXjdB^u|-y4jhdpG5i zmlpb~0nnFoL8kr2OD#5&b1Dxz^{w_Vgz1z1Qs?rOT%oV_{Hyy=Qk>(@FZY%4IbXUM zDiM<`$4&_8+ux2|D(QJ$Dlj2R56X|+$W883^F@Ia$_u(o28F@p7GFJ^`{*zkL9YW@ zj!XxLq=PClq%g=JM9wTA<_{s}kK(jX5?Lv|U{XjBYF~lH)N-HlQ7<_vtIarXSN`pD zz4nWNJ2o!UZ#VV&>apqPpZm3V2IkVuLx{=WI4DPgjo(RpwSaj3c>egG;kcAvdH#6* z_@DZC9?;Jp|DcZN0sZ{(59)Xx(9a+LppNGO{rvF{>UbW|&maGwj^_dW{P7R!`2PS5 WD$uv(QG=ZT0000SetFont(font_alt_nozzle); variants_sizer->Add(alt_label, 0, wxBOTTOM, 3); + is_variants = true; } auto *cbox = new Checkbox(variants_panel, label, model_id, variant.name); @@ -280,10 +283,10 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt } title_sizer->AddStretchSpacer(); - if (titles.size() > 1) { + if (/*titles.size() > 1*/is_variants) { // It only makes sense to add the All / None buttons if there's multiple printers - auto *sel_all_std = new wxButton(this, wxID_ANY, _(L("All standard"))); + auto *sel_all_std = new wxButton(this, wxID_ANY, titles.size() > 1 ? _(L("All standard")) : _(L("Standard"))); auto *sel_all = new wxButton(this, wxID_ANY, _(L("All"))); auto *sel_none = new wxButton(this, wxID_ANY, _(L("None"))); sel_all_std->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->select_all(true, false); }); From dd59945098fbf55eb45e30d67471f8f265895a65 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 14 Nov 2019 17:02:32 +0100 Subject: [PATCH 67/80] Fix of a typo in KDTreeIndirect. Improvement of the infill path planning. Regression fix of Gyroid infill crashes. Some unit tests for elephant foot and path planning. --- src/libslic3r/ClipperUtils.cpp | 2 +- src/libslic3r/ElephantFootCompensation.cpp | 87 ++++--- src/libslic3r/ExtrusionEntity.hpp | 9 + src/libslic3r/Fill/FillBase.cpp | 102 ++++---- src/libslic3r/Fill/FillGyroid.cpp | 27 ++- src/libslic3r/KDTreeIndirect.hpp | 86 +++---- src/libslic3r/ShortestPath.cpp | 218 +++++++++++++++++- .../test_elephant_foot_compensation.cpp | 15 ++ tests/libslic3r/test_geometry.cpp | 42 +++- 9 files changed, 443 insertions(+), 145 deletions(-) diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 25100b22f..f053aea29 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -1205,7 +1205,7 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector& ds : deltas) + for (const std::vector& ds : deltas) for (float delta : ds) assert(delta <= 0.); assert(expoly.holes.size() + 1 == deltas.size()); diff --git a/src/libslic3r/ElephantFootCompensation.cpp b/src/libslic3r/ElephantFootCompensation.cpp index 0f4eb0135..828064c32 100644 --- a/src/libslic3r/ElephantFootCompensation.cpp +++ b/src/libslic3r/ElephantFootCompensation.cpp @@ -60,9 +60,9 @@ std::vector contour_distance(const EdgeGrid::Grid &grid, const size_t idx for (size_t axis = 0; axis < 2; ++ axis) { double dx = std::abs(dir(axis)); if (dx >= EPSILON) { - double tedge = (dir(axis) > 0) ? (double(bbox.max(axis)) - EPSILON - this->pt(axis)) : (this->pt(axis) - double(bbox.min(axis)) - EPSILON); + double tedge = (dir(axis) > 0) ? (double(bbox.max(axis)) - SCALED_EPSILON - this->pt(axis)) : (this->pt(axis) - double(bbox.min(axis)) - SCALED_EPSILON); if (tedge < dx) - t = tedge / dx; + t = std::min(t, tedge / dx); } } this->dir = dir; @@ -70,6 +70,7 @@ std::vector contour_distance(const EdgeGrid::Grid &grid, const size_t idx dir *= t; this->pt_end = (this->pt + dir).cast(); this->t_min = 1.; + assert(this->grid.bbox().contains(this->pt_start) && this->grid.bbox().contains(this->pt_end)); } bool operator()(coord_t iy, coord_t ix) { @@ -361,7 +362,7 @@ static inline void smooth_compensation_banded(const Points &contour, float band, } ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow &external_perimeter_flow, const double compensation) -{ +{ // The contour shall be wide enough to apply the external perimeter plus compensation on both sides. double min_contour_width = double(external_perimeter_flow.scaled_width() + external_perimeter_flow.scaled_spacing()); double scaled_compensation = scale_(compensation); @@ -369,39 +370,59 @@ ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow & // Make the search radius a bit larger for the averaging in contour_distance over a fan of rays to work. double search_radius = min_contour_width_compensated + min_contour_width * 0.5; - EdgeGrid::Grid grid; - ExPolygon simplified = input_expoly.simplify(SCALED_EPSILON).front(); - BoundingBox bbox = get_extents(simplified.contour); - bbox.offset(SCALED_EPSILON); - grid.set_bbox(bbox); - grid.create(simplified, coord_t(0.7 * search_radius)); - std::vector> deltas; - deltas.reserve(simplified.holes.size() + 1); - ExPolygon resampled(simplified); - double resample_interval = scale_(0.5); - for (size_t idx_contour = 0; idx_contour <= simplified.holes.size(); ++ idx_contour) { - Polygon &poly = (idx_contour == 0) ? resampled.contour : resampled.holes[idx_contour - 1]; - std::vector resampled_point_parameters; - poly.points = resample_polygon(poly.points, resample_interval, resampled_point_parameters); - std::vector dists = contour_distance(grid, idx_contour, poly.points, resampled_point_parameters, search_radius); - for (float &d : dists) { -// printf("Point %d, Distance: %lf\n", int(&d - dists.data()), unscale(d)); - // Convert contour width to available compensation distance. - if (d < min_contour_width) - d = 0.f; - else if (d > min_contour_width_compensated) - d = - float(scaled_compensation); - else - d = - (d - float(min_contour_width)) / 2.f; - assert(d >= - float(scaled_compensation) && d <= 0.f); + BoundingBox bbox = get_extents(input_expoly.contour); + Point bbox_size = bbox.size(); + ExPolygon out; + if (bbox_size.x() < min_contour_width_compensated + SCALED_EPSILON || + bbox_size.y() < min_contour_width_compensated + SCALED_EPSILON || + input_expoly.area() < min_contour_width_compensated * min_contour_width_compensated * 5.) + { + // The contour is tiny. Don't correct it. + out = input_expoly; + } + else + { + EdgeGrid::Grid grid; + ExPolygon simplified = input_expoly.simplify(SCALED_EPSILON).front(); + BoundingBox bbox = get_extents(simplified.contour); + bbox.offset(SCALED_EPSILON); + grid.set_bbox(bbox); + grid.create(simplified, coord_t(0.7 * search_radius)); + std::vector> deltas; + deltas.reserve(simplified.holes.size() + 1); + ExPolygon resampled(simplified); + double resample_interval = scale_(0.5); + for (size_t idx_contour = 0; idx_contour <= simplified.holes.size(); ++ idx_contour) { + Polygon &poly = (idx_contour == 0) ? resampled.contour : resampled.holes[idx_contour - 1]; + std::vector resampled_point_parameters; + poly.points = resample_polygon(poly.points, resample_interval, resampled_point_parameters); + std::vector dists = contour_distance(grid, idx_contour, poly.points, resampled_point_parameters, search_radius); + for (float &d : dists) { + // printf("Point %d, Distance: %lf\n", int(&d - dists.data()), unscale(d)); + // Convert contour width to available compensation distance. + if (d < min_contour_width) + d = 0.f; + else if (d > min_contour_width_compensated) + d = - float(scaled_compensation); + else + d = - (d - float(min_contour_width)) / 2.f; + assert(d >= - float(scaled_compensation) && d <= 0.f); + } + // smooth_compensation(dists, 0.4f, 10); + smooth_compensation_banded(poly.points, float(0.8 * resample_interval), dists, 0.3f, 3); + deltas.emplace_back(dists); } -// smooth_compensation(dists, 0.4f, 10); - smooth_compensation_banded(poly.points, float(0.8 * resample_interval), dists, 0.3f, 3); - deltas.emplace_back(dists); + + ExPolygons out_vec = variable_offset_inner_ex(resampled, deltas, 2.); + assert(out_vec.size() == 1); + if (out_vec.size() == 1) + out = std::move(out_vec.front()); + else + // Something went wrong, don't compensate. + out = input_expoly; } - ExPolygons out = variable_offset_inner_ex(resampled, deltas, 2.); - return out.front(); + return out; } ExPolygons elephant_foot_compensation(const ExPolygons &input, const Flow &external_perimeter_flow, const double compensation) diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index b22d85b65..b76991f1c 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -267,6 +267,15 @@ public: //static inline std::string role_to_string(ExtrusionLoopRole role); +#ifndef NDEBUG + bool validate() const { + assert(this->first_point() == this->paths.back().polyline.points.back()); + for (size_t i = 1; i < paths.size(); ++ i) + assert(this->paths[i - 1].polyline.points.back() == this->paths[i].polyline.points.front()); + return true; + } +#endif /* NDEBUG */ + private: ExtrusionLoopRole m_loop_role; }; diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 0ba75465f..88eba9a51 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -534,7 +534,8 @@ struct ContourPointData { // Verify whether the contour from point idx_start to point idx_end could be taken (whether all segments along the contour were not yet extruded). static bool could_take(const std::vector &contour_data, size_t idx_start, size_t idx_end) { - for (size_t i = idx_start; i < idx_end; ) { + assert(idx_start != idx_end); + for (size_t i = idx_start; i != idx_end; ) { if (contour_data[i].segment_consumed || contour_data[i].point_consumed) return false; if (++ i == contour_data.size()) @@ -899,63 +900,86 @@ void Fill::connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary_ // Mark the points and segments of split boundary as consumed if they are very close to some of the infill line. { - const double clip_distance = scale_(this->spacing); + //const double clip_distance = scale_(this->spacing); + const double clip_distance = 3. * scale_(this->spacing); const double distance_colliding = scale_(this->spacing); mark_boundary_segments_touching_infill(boundary, boundary_data, bbox, infill_ordered, clip_distance, distance_colliding); } - // Chain infill_ordered. - //FIXME run the following loop through a heap sorted by the shortest perimeter edge that could be taken. - //length between two lines + // Connection from end of one infill line to the start of another infill line. //const float length_max = scale_(this->spacing); - const float length_max = scale_((2. / params.density) * this->spacing); - size_t idx_chain_last = 0; +// const float length_max = scale_((2. / params.density) * this->spacing); + const float length_max = scale_((1000. / params.density) * this->spacing); + std::vector merged_with(infill_ordered.size()); + for (size_t i = 0; i < merged_with.size(); ++ i) + merged_with[i] = i; + struct ConnectionCost { + ConnectionCost(size_t idx_first, double cost, bool reversed) : idx_first(idx_first), cost(cost), reversed(reversed) {} + size_t idx_first; + double cost; + bool reversed; + }; + std::vector connections_sorted; + connections_sorted.reserve(infill_ordered.size() * 2 - 2); for (size_t idx_chain = 1; idx_chain < infill_ordered.size(); ++ idx_chain) { - Polyline &pl1 = infill_ordered[idx_chain_last]; - Polyline &pl2 = infill_ordered[idx_chain]; + const Polyline &pl1 = infill_ordered[idx_chain - 1]; + const Polyline &pl2 = infill_ordered[idx_chain]; const std::pair *cp1 = &map_infill_end_point_to_boundary[(idx_chain - 1) * 2 + 1]; const std::pair *cp2 = &map_infill_end_point_to_boundary[idx_chain * 2]; - const Points &contour = boundary[cp1->first]; - std::vector &contour_data = boundary_data[cp1->first]; - bool valid = false; - bool reversed = false; + const std::vector &contour_data = boundary_data[cp1->first]; if (cp1->first == cp2->first) { // End points on the same contour. Try to connect them. - float param_lo = (cp1->second == 0) ? 0.f : contour_data[cp1->second].param; - float param_hi = (cp2->second == 0) ? 0.f : contour_data[cp2->second].param; + float param_lo = (cp1->second == 0) ? 0.f : contour_data[cp1->second].param; + float param_hi = (cp2->second == 0) ? 0.f : contour_data[cp2->second].param; float param_end = contour_data.front().param; + bool reversed = false; if (param_lo > param_hi) { std::swap(param_lo, param_hi); - std::swap(cp1, cp2); reversed = true; } assert(param_lo >= 0.f && param_lo <= param_end); assert(param_hi >= 0.f && param_hi <= param_end); - float dist1 = param_hi - param_lo; - float dist2 = param_lo + param_end - param_hi; - if (dist1 > dist2) { - std::swap(dist1, dist2); - std::swap(cp1, cp2); - reversed = ! reversed; - } - if (dist1 < length_max) { - // Try to connect the shorter path. - valid = could_take(contour_data, cp1->second, cp2->second); - // Try to connect the longer path. - if (! valid && dist2 < length_max) { - std::swap(cp1, cp2); - reversed = ! reversed; - valid = could_take(contour_data, cp1->second, cp2->second); - } - } + double len = param_hi - param_lo; + if (len < length_max) + connections_sorted.emplace_back(idx_chain - 1, len, reversed); + len = param_lo + param_end - param_hi; + if (len < length_max) + connections_sorted.emplace_back(idx_chain - 1, len, ! reversed); } - if (valid) - take(pl1, std::move(pl2), contour, contour_data, cp1->second, cp2->second, reversed); - else if (++ idx_chain_last < idx_chain) - infill_ordered[idx_chain_last] = std::move(pl2); } - infill_ordered.erase(infill_ordered.begin() + idx_chain_last + 1, infill_ordered.end()); - append(polylines_out, std::move(infill_ordered)); + std::sort(connections_sorted.begin(), connections_sorted.end(), [](const ConnectionCost& l, const ConnectionCost& r) { return l.cost < r.cost; }); + + size_t idx_chain_last = 0; + for (ConnectionCost &connection_cost : connections_sorted) { + const std::pair *cp1 = &map_infill_end_point_to_boundary[connection_cost.idx_first * 2 + 1]; + const std::pair *cp2 = &map_infill_end_point_to_boundary[(connection_cost.idx_first + 1) * 2]; + assert(cp1->first == cp2->first); + std::vector &contour_data = boundary_data[cp1->first]; + if (connection_cost.reversed) + std::swap(cp1, cp2); + if (could_take(contour_data, cp1->second, cp2->second)) { + // Indices of the polygons to be connected. + size_t idx_first = connection_cost.idx_first; + size_t idx_second = idx_first + 1; + for (size_t last = idx_first;;) { + size_t lower = merged_with[last]; + if (lower == last) { + merged_with[idx_first] = lower; + idx_first = lower; + break; + } + last = lower; + } + // Connect the two polygons using the boundary contour. + take(infill_ordered[idx_first], std::move(infill_ordered[idx_second]), boundary[cp1->first], contour_data, cp1->second, cp2->second, connection_cost.reversed); + // Mark the second polygon as merged with the first one. + merged_with[idx_second] = merged_with[idx_first]; + } + } + polylines_out.reserve(polylines_out.size() + std::count_if(infill_ordered.begin(), infill_ordered.end(), [](const Polyline &pl) { return ! pl.empty(); })); + for (Polyline &pl : infill_ordered) + if (! pl.empty()) + polylines_out.emplace_back(std::move(pl)); } #endif diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index e7b4706ac..b12dfb2e7 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -166,7 +166,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_square = make_gyroid_waves( + Polylines polylines = make_gyroid_waves( scale_(this->z), density_adjusted, this->spacing, @@ -174,22 +174,25 @@ void FillGyroid::_fill_surface_single( ceil(bb.size()(1) / distance) + 1.); // shift the polyline to the grid origin - for (Polyline &pl : polylines_square) + for (Polyline &pl : polylines) pl.translate(bb.min); - Polylines polylines_chained = chain_polylines(intersection_pl(polylines_square, to_polygons(expolygon))); + polylines = intersection_pl(polylines, to_polygons(expolygon)); - size_t polylines_out_first_idx = polylines_out.size(); - if (! polylines_chained.empty()) { - // connect lines + if (! polylines.empty()) + // remove too small bits (larger than longer) + polylines.erase( + std::remove_if(polylines.begin(), polylines.end(), [this](const Polyline &pl) { return pl.length() < scale_(this->spacing * 3); }), + polylines.end()); + + if (! polylines.empty()) { + polylines = chain_polylines(polylines); + // connect lines + size_t polylines_out_first_idx = polylines_out.size(); if (params.dont_connect) - append(polylines_out, std::move(polylines_chained)); + append(polylines_out, std::move(polylines)); else - this->connect_infill(std::move(polylines_chained), expolygon, polylines_out, params); - // remove too small bits (larger than longer) - polylines_out.erase( - std::remove_if(polylines_out.begin() + polylines_out_first_idx, polylines_out.end(), [this](const Polyline &pl){ return pl.length() < scale_(this->spacing * 3); }), - polylines_out.end()); + this->connect_infill(std::move(polylines), expolygon, polylines_out, params); // new paths must be rotated back if (abs(infill_angle) >= EPSILON) { for (auto it = polylines_out.begin() + polylines_out_first_idx; it != polylines_out.end(); ++ it) diff --git a/src/libslic3r/KDTreeIndirect.hpp b/src/libslic3r/KDTreeIndirect.hpp index 3cccfdafa..239008559 100644 --- a/src/libslic3r/KDTreeIndirect.hpp +++ b/src/libslic3r/KDTreeIndirect.hpp @@ -46,9 +46,9 @@ public: if (indices.empty()) clear(); else { - // Allocate a next highest power of 2 nodes, because the incomplete binary tree will not have the leaves filled strictly from the left. + // Allocate enough memory for a full binary tree. m_nodes.assign(next_highest_power_of_2(indices.size() + 1), npos); - build_recursive(indices, 0, 0, 0, (int)(indices.size() - 1)); + build_recursive(indices, 0, 0, 0, indices.size() - 1); } indices.clear(); } @@ -81,7 +81,7 @@ public: private: // Build a balanced tree by splitting the input sequence by an axis aligned plane at a dimension. - void build_recursive(std::vector &input, size_t node, int dimension, int left, int right) + void build_recursive(std::vector &input, size_t node, const size_t dimension, const size_t left, const size_t right) { if (left > right) return; @@ -94,54 +94,56 @@ private: return; } - // Partition the input sequence to two equal halves. - int center = (left + right) >> 1; + // Partition the input to left / right pieces of the same length to produce a balanced tree. + size_t center = (left + right) / 2; partition_input(input, dimension, left, right, center); // Insert a node into the tree. m_nodes[node] = input[center]; - // Partition the left and right subtrees. - size_t next_dimension = (++ dimension == NumDimensions) ? 0 : dimension; - build_recursive(input, (node << 1) + 1, next_dimension, left, center - 1); - build_recursive(input, (node << 1) + 2, next_dimension, center + 1, right); + // Build up the left / right subtrees. + size_t next_dimension = dimension; + if (++ next_dimension == NumDimensions) + next_dimension = 0; + if (center > left) + build_recursive(input, node * 2 + 1, next_dimension, left, center - 1); + build_recursive(input, node * 2 + 2, next_dimension, center + 1, right); } - // Partition the input m_nodes at k using QuickSelect method. + // Partition the input m_nodes at "k" and "dimension" using the QuickSelect method: // https://en.wikipedia.org/wiki/Quickselect - void partition_input(std::vector &input, int dimension, int left, int right, int k) const + // Items left of the k'th item are lower than the k'th item in the "dimension", + // items right of the k'th item are higher than the k'th item in the "dimension", + void partition_input(std::vector &input, const size_t dimension, size_t left, size_t right, const size_t k) const { while (left < right) { - // Guess the k'th element. - // Pick the pivot as a median of first, center and last value. - // Sort first, center and last values. - int center = (left + right) >> 1; - auto left_value = this->coordinate(input[left], dimension); - auto center_value = this->coordinate(input[center], dimension); - auto right_value = this->coordinate(input[right], dimension); - if (center_value < left_value) { - std::swap(input[left], input[center]); - std::swap(left_value, center_value); + size_t center = (left + right) / 2; + CoordType pivot; + { + // Bubble sort the input[left], input[center], input[right], so that a median of the three values + // will end up in input[center]. + CoordType left_value = this->coordinate(input[left], dimension); + CoordType center_value = this->coordinate(input[center], dimension); + CoordType right_value = this->coordinate(input[right], dimension); + if (left_value > center_value) { + std::swap(input[left], input[center]); + std::swap(left_value, center_value); + } + if (left_value > right_value) { + std::swap(input[left], input[right]); + right_value = left_value; + } + if (center_value > right_value) { + std::swap(input[center], input[right]); + center_value = right_value; + } + pivot = center_value; } - if (right_value < left_value) { - std::swap(input[left], input[right]); - std::swap(left_value, right_value); - } - if (right_value < center_value) { - std::swap(input[center], input[right]); - // No need to do that, result is not used. - // std::swap(center_value, right_value); - } - // Only two or three values are left and those are sorted already. - if (left + 3 > right) + if (right <= left + 2) + // The interval is already sorted. break; - // left and right items are already at their correct positions. - // input[left].point[dimension] <= input[center].point[dimension] <= input[right].point[dimension] - // Move the pivot to the (right - 1) position. - std::swap(input[center], input[right - 1]); - // Pivot value. - double pivot = this->coordinate(input[right - 1], dimension); + size_t i = left; + size_t j = right - 1; + std::swap(input[center], input[j]); // Partition the set based on the pivot. - int i = left; - int j = right - 1; for (;;) { // Skip left points that are already at correct positions. // Search will certainly stop at position (right - 1), which stores the pivot. @@ -153,7 +155,7 @@ private: std::swap(input[i], input[j]); } // Restore pivot to the center of the sequence. - std::swap(input[i], input[right]); + std::swap(input[i], input[right - 1]); // Which side the kth element is in? if (k < i) right = i - 1; @@ -173,7 +175,7 @@ private: return; // Left / right child node index. - size_t left = (node << 1) + 1; + size_t left = node * 2 + 1; size_t right = left + 1; unsigned int mask = visitor(m_nodes[node], dimension); if ((mask & (unsigned int)VisitorReturnMask::STOP) == 0) { diff --git a/src/libslic3r/ShortestPath.cpp b/src/libslic3r/ShortestPath.cpp index a0fb05005..b38655e68 100644 --- a/src/libslic3r/ShortestPath.cpp +++ b/src/libslic3r/ShortestPath.cpp @@ -237,11 +237,19 @@ std::vector> chain_segments_greedy_constrained_reversals // Chain the end points: find (num_segments - 1) shortest links not forming bifurcations or loops. assert(num_segments >= 2); +#ifndef NDEBUG + double distance_taken_last = 0.; +#endif /* NDEBUG */ for (int iter = int(num_segments) - 2;; -- iter) { assert(validate_graph_and_queue()); // Take the first end point, for which the link points to the currently closest valid neighbor. EndPoint &end_point1 = *queue.top(); - assert(end_point1.edge_out != nullptr); +#ifndef NDEBUG + // Each edge added shall be longer than the previous one taken. + assert(end_point1.distance_out > distance_taken_last - SCALED_EPSILON); + distance_taken_last = end_point1.distance_out; +#endif /* NDEBUG */ + assert(end_point1.edge_out != nullptr); // No point on the queue may be connected yet. assert(end_point1.chain_id == 0); // Take the closest end point to the first end point, @@ -313,6 +321,10 @@ std::vector> chain_segments_greedy_constrained_reversals assert(next_idx < end_points.size()); end_point1.edge_out = &end_points[next_idx]; end_point1.distance_out = (end_points[next_idx].pos - end_point1.pos).squaredNorm(); +#ifndef NDEBUG + // Each edge shall be longer than the last one removed from the queue. + assert(end_point1.distance_out > distance_taken_last - SCALED_EPSILON); +#endif /* NDEBUG */ // Update position of this end point in the queue based on the distance calculated at the line above. queue.update(end_point1.heap_idx); //FIXME Remove the other end point from the KD tree. @@ -460,18 +472,206 @@ std::vector chain_points(const Points &points, Point *start_near) return out; } +// Flip the sequences of polylines to lower the total length of connecting lines. +// #define DEBUG_SVG_OUTPUT +static inline void improve_ordering_by_segment_flipping(Polylines &polylines, bool fixed_start) +{ +#ifndef NDEBUG + auto cost = [&polylines]() { + double sum = 0.; + for (size_t i = 1; i < polylines.size(); ++i) + sum += (polylines[i].first_point() - polylines[i - 1].last_point()).cast().norm(); + return sum; + }; + double cost_initial = cost(); + + static int iRun = 0; + ++ iRun; + BoundingBox bbox = get_extents(polylines); +#ifdef DEBUG_SVG_OUTPUT + { + SVG svg(debug_out_path("improve_ordering_by_segment_flipping-initial-%d.svg", iRun).c_str(), bbox); + svg.draw(polylines); + for (size_t i = 1; i < polylines.size(); ++ i) + svg.draw(Line(polylines[i - 1].last_point(), polylines[i].first_point()), "red"); + } +#endif /* DEBUG_SVG_OUTPUT */ +#endif /* NDEBUG */ + + struct Connection { + Connection(size_t heap_idx = std::numeric_limits::max(), bool flipped = false) : heap_idx(heap_idx), flipped(flipped) {} + // Position of this object on MutablePriorityHeap. + size_t heap_idx; + // Is segment_idx flipped? + bool flipped; + + double squaredNorm(const Polylines &polylines, const std::vector &connections) const + { return ((this + 1)->start_point(polylines, connections) - this->end_point(polylines, connections)).squaredNorm(); } + double norm(const Polylines &polylines, const std::vector &connections) const + { return sqrt(this->squaredNorm(polylines, connections)); } + double squaredNorm(const Polylines &polylines, const std::vector &connections, bool try_flip1, bool try_flip2) const + { return ((this + 1)->start_point(polylines, connections, try_flip2) - this->end_point(polylines, connections, try_flip1)).squaredNorm(); } + double norm(const Polylines &polylines, const std::vector &connections, bool try_flip1, bool try_flip2) const + { return sqrt(this->squaredNorm(polylines, connections, try_flip1, try_flip2)); } + Vec2d start_point(const Polylines &polylines, const std::vector &connections, bool flip = false) const + { const Polyline &pl = polylines[this - connections.data()]; return ((this->flipped == flip) ? pl.points.front() : pl.points.back()).cast(); } + Vec2d end_point(const Polylines &polylines, const std::vector &connections, bool flip = false) const + { const Polyline &pl = polylines[this - connections.data()]; return ((this->flipped == flip) ? pl.points.back() : pl.points.front()).cast(); } + + bool in_queue() const { return this->heap_idx != std::numeric_limits::max(); } + void flip() { this->flipped = ! this->flipped; } + }; + std::vector connections(polylines.size()); + +#ifndef NDEBUG + auto cost_flipped = [fixed_start, &polylines, &connections]() { + assert(! fixed_start || ! connections.front().flipped); + double sum = 0.; + for (size_t i = 1; i < polylines.size(); ++ i) + sum += connections[i - 1].norm(polylines, connections); + return sum; + }; + double cost_prev = cost_flipped(); + assert(std::abs(cost_initial - cost_prev) < SCALED_EPSILON); + + auto print_statistics = [&polylines, &connections]() { +#if 0 + for (size_t i = 1; i < polylines.size(); ++ i) + printf("Connecting %d with %d: Current length %lf flip(%d, %d), left flipped: %lf, right flipped: %lf, both flipped: %lf, \n", + int(i - 1), int(i), + unscale(connections[i - 1].norm(polylines, connections)), + int(connections[i - 1].flipped), int(connections[i].flipped), + unscale(connections[i - 1].norm(polylines, connections, true, false)), + unscale(connections[i - 1].norm(polylines, connections, false, true)), + unscale(connections[i - 1].norm(polylines, connections, true, true))); +#endif + }; + print_statistics(); +#endif /* NDEBUG */ + + // Initialize a MutablePriorityHeap of connections between polylines. + auto queue = make_mutable_priority_queue( + [](Connection *connection, size_t idx){ connection->heap_idx = idx; }, + // Sort by decreasing connection distance. + [&polylines, &connections](Connection *l, Connection *r){ return l->squaredNorm(polylines, connections) > r->squaredNorm(polylines, connections); }); + queue.reserve(polylines.size() - 1); + for (size_t i = 0; i + 1 < polylines.size(); ++ i) + queue.push(&connections[i]); + + static constexpr size_t itercnt = 100; + size_t iter = 0; + for (; ! queue.empty() && iter < itercnt; ++ iter) { + Connection &connection = *queue.top(); + queue.pop(); + connection.heap_idx = std::numeric_limits::max(); + size_t idx_first = &connection - connections.data(); + // Try to flip segments starting with idx_first + 1 to the end. + // Calculate the last segment to be flipped to improve the total path length. + double length_current = connection.norm(polylines, connections); + double length_flipped = connection.norm(polylines, connections, false, true); + int best_idx_forward = int(idx_first); + double best_improvement_forward = 0.; + for (size_t i = idx_first + 1; i + 1 < connections.size(); ++ i) { + length_current += connections[i].norm(polylines, connections); + double this_improvement = length_current - length_flipped - connections[i].norm(polylines, connections, true, false); + length_flipped += connections[i].norm(polylines, connections, true, true); + if (this_improvement > best_improvement_forward) { + best_improvement_forward = this_improvement; + best_idx_forward = int(i); + } +// if (length_flipped > 1.5 * length_current) +// break; + } + if (length_current - length_flipped > best_improvement_forward) + // Best improvement by flipping up to the end. + best_idx_forward = int(connections.size()) - 1; + // Try to flip segments starting with idx_first - 1 to the start. + // Calculate the last segment to be flipped to improve the total path length. + length_current = connection.norm(polylines, connections); + length_flipped = connection.norm(polylines, connections, true, false); + int best_idx_backwards = int(idx_first); + double best_improvement_backwards = 0.; + for (int i = int(idx_first) - 1; i >= 0; -- i) { + length_current += connections[i].norm(polylines, connections); + double this_improvement = length_current - length_flipped - connections[i].norm(polylines, connections, false, true); + length_flipped += connections[i].norm(polylines, connections, true, true); + if (this_improvement > best_improvement_backwards) { + best_improvement_backwards = this_improvement; + best_idx_backwards = int(i); + } +// if (length_flipped > 1.5 * length_current) +// break; + } + if (! fixed_start && length_current - length_flipped > best_improvement_backwards) + // Best improvement by flipping up to the start including the first polyline. + best_idx_backwards = -1; + int update_begin = int(idx_first); + int update_end = best_idx_forward; + if (best_improvement_backwards > 0. && best_improvement_backwards > best_improvement_forward) { + // Flip the sequence of polylines from idx_first to best_improvement_forward + 1. + update_begin = best_idx_backwards; + update_end = int(idx_first); + } + assert(update_begin <= update_end); + if (update_begin == update_end) + continue; + for (int i = update_begin + 1; i <= update_end; ++ i) + connections[i].flip(); + +#ifndef NDEBUG + double cost = cost_flipped(); + assert(cost < cost_prev); + cost_prev = cost; + print_statistics(); +#endif /* NDEBUG */ + + update_end = std::min(update_end + 1, int(connections.size()) - 1); + for (int i = std::max(0, update_begin); i < update_end; ++ i) { + Connection &c = connections[i]; + if (c.in_queue()) + queue.update(c.heap_idx); + else + queue.push(&c); + } + } + + // Flip the segments based on the flip flag. + for (Polyline &pl : polylines) + if (connections[&pl - polylines.data()].flipped) + pl.reverse(); + +#ifndef NDEBUG + double cost_final = cost(); +#ifdef DEBUG_SVG_OUTPUT + { + SVG svg(debug_out_path("improve_ordering_by_segment_flipping-final-%d.svg", iRun).c_str(), bbox); + svg.draw(polylines); + for (size_t i = 1; i < polylines.size(); ++ i) + svg.draw(Line(polylines[i - 1].last_point(), polylines[i].first_point()), "red"); + } +#endif /* DEBUG_SVG_OUTPUT */ +#endif /* NDEBUG */ + + assert(cost_final <= cost_prev); + assert(cost_final <= cost_initial); +} + Polylines chain_polylines(Polylines &&polylines, const Point *start_near) { - auto segment_end_point = [&polylines](size_t idx, bool first_point) -> const Point& { return first_point ? polylines[idx].first_point() : polylines[idx].last_point(); }; - std::vector> ordered = chain_segments_greedy(segment_end_point, polylines.size(), start_near); Polylines out; - out.reserve(polylines.size()); - for (auto &segment_and_reversal : ordered) { - out.emplace_back(std::move(polylines[segment_and_reversal.first])); - if (segment_and_reversal.second) - out.back().reverse(); + if (! polylines.empty()) { + auto segment_end_point = [&polylines](size_t idx, bool first_point) -> const Point& { return first_point ? polylines[idx].first_point() : polylines[idx].last_point(); }; + std::vector> ordered = chain_segments_greedy(segment_end_point, polylines.size(), start_near); + out.reserve(polylines.size()); + for (auto &segment_and_reversal : ordered) { + out.emplace_back(std::move(polylines[segment_and_reversal.first])); + if (segment_and_reversal.second) + out.back().reverse(); + } + if (out.size() > 1) + improve_ordering_by_segment_flipping(out, start_near != nullptr); } - return out; + return out; } template static inline T chain_path_items(const Points &points, const T &items) diff --git a/tests/libslic3r/test_elephant_foot_compensation.cpp b/tests/libslic3r/test_elephant_foot_compensation.cpp index 9a7e65264..e5ea97e68 100644 --- a/tests/libslic3r/test_elephant_foot_compensation.cpp +++ b/tests/libslic3r/test_elephant_foot_compensation.cpp @@ -222,6 +222,21 @@ static ExPolygon vase_with_fins() SCENARIO("Elephant foot compensation", "[ElephantFoot]") { + GIVEN("Tiny contour") { + ExPolygon expoly({ { 133382606, 94912473 }, { 134232493, 95001115 }, { 133783926, 95159440 }, { 133441897, 95180666 }, { 133408242, 95191984 }, { 133339012, 95166830 }, { 132991642, 95011087 }, { 133206549, 94908304 } }); + WHEN("Compensated") { + ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.419999987f, 0.2f, 0.4f, false), 0.2f); +#ifdef TESTS_EXPORT_SVGS + SVG::export_expolygons(debug_out_path("elephant_foot_compensation_tiny.svg").c_str(), + { { { expoly }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } }, + { { expoly_compensated }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } } }); +#endif /* TESTS_EXPORT_SVGS */ + THEN("Tiny contour is not compensated") { + REQUIRE(expoly_compensated == expoly); + } + } + } + GIVEN("Large box") { ExPolygon expoly( { {50000000, 50000000 }, { 0, 50000000 }, { 0, 0 }, { 50000000, 0 } } ); WHEN("Compensated") { diff --git a/tests/libslic3r/test_geometry.cpp b/tests/libslic3r/test_geometry.cpp index 22755c262..4a800b3d3 100644 --- a/tests/libslic3r/test_geometry.cpp +++ b/tests/libslic3r/test_geometry.cpp @@ -252,15 +252,39 @@ SCENARIO("Circle Fit, TaubinFit with Newton's method", "[Geometry]") { } } -TEST_CASE("Chained path working correctly", "[Geometry]"){ - // if chained_path() works correctly, these points should be joined with no diagonal paths - // (thus 26 units long) - std::vector points = {Point(26,26),Point(52,26),Point(0,26),Point(26,52),Point(26,0),Point(0,52),Point(52,52),Point(52,0)}; - std::vector indices = chain_points(points); - for (Points::size_type i = 0; i + 1 < indices.size(); ++ i) { - double dist = (points.at(indices.at(i)).cast() - points.at(indices.at(i+1)).cast()).norm(); - REQUIRE(std::abs(dist-26) <= EPSILON); - } +SCENARIO("Path chaining", "[Geometry]") { + GIVEN("A path") { + std::vector points = { Point(26,26),Point(52,26),Point(0,26),Point(26,52),Point(26,0),Point(0,52),Point(52,52),Point(52,0) }; + THEN("Chained with no diagonals (thus 26 units long)") { + std::vector indices = chain_points(points); + for (Points::size_type i = 0; i + 1 < indices.size(); ++ i) { + double dist = (points.at(indices.at(i)).cast() - points.at(indices.at(i+1)).cast()).norm(); + REQUIRE(std::abs(dist-26) <= EPSILON); + } + } + } + GIVEN("Loop pieces") { + Point a { 2185796, 19058485 }; + Point b { 3957902, 18149382 }; + Point c { 2912841, 18790564 }; + Point d { 2831848, 18832390 }; + Point e { 3179601, 18627769 }; + Point f { 3137952, 18653370 }; + Polylines polylines = { { a, b }, + { c, d }, + { e, f }, + { d, a }, + { f, c }, + { b, e } }; + Polylines chained = chain_polylines(polylines, &a); + THEN("Connected without a gap") { + for (size_t i = 0; i < chained.size(); ++i) { + const Polyline &pl1 = (i == 0) ? chained.back() : chained[i - 1]; + const Polyline &pl2 = chained[i]; + REQUIRE(pl1.points.back() == pl2.points.front()); + } + } + } } SCENARIO("Line distances", "[Geometry]"){ From 840c59cd3d64ddbe616f5d599dca4db1794c32e9 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 15 Nov 2019 08:32:19 +0100 Subject: [PATCH 68/80] Added new PrusaResearch.ini (with MINI and aliases) --- resources/profiles/PrusaResearch.ini | 1269 ++++++++++++++++++++++---- 1 file changed, 1105 insertions(+), 164 deletions(-) diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index 9add73b4d..bc41fab6b 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -5,7 +5,7 @@ name = Prusa Research # Configuration version of this file. Config file will only be installed, if the config_version differs. # This means, the server may force the PrusaSlicer configuration to be downgraded. -config_version = 1.0.1 +config_version = 1.0.4 # Where to get the updates from? config_update_url = http://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/ changelog_url = http://files.prusa3d.com/?latest=slicer-profiles&lng=%1% @@ -16,6 +16,13 @@ changelog_url = http://files.prusa3d.com/?latest=slicer-profiles&lng=%1% #for example by the melt zone size, or whether the nozzle is hardened. # Printer model name will be shown by the installation wizard. + +[printer_model:MINI] +name = Original Prusa MINI +variants = 0.4; 0.25 +technology = FFF +family = MINI + [printer_model:MK3S] name = Original Prusa i3 MK3S variants = 0.4; 0.25; 0.6 @@ -82,29 +89,6 @@ variants = default technology = SLA family = SL1 -[default_filaments] -Generic PLA = 1 -Generic PLA MMU2 = 1 -Prusa PLA = 1 -Prusa PLA MMU2 = 1 -Prusament PLA = 1 -Prusament PLA MMU2 = 1 - -[default_sla_materials] -Prusa Azure Blue Tough 0.05 = 1 -Prusa Black Tough 0.05 = 1 -Prusa Green Casting 0.05 = 1 -Prusa Grey Tough 0.05 = 1 -Prusa Maroon Tough 0.05 = 1 -Prusa Orange Tough 0.025 = 1 -Prusa Orange Tough 0.035 = 1 -Prusa Orange Tough 0.05 = 1 -Prusa Orange Tough 0.1 = 1 -Prusa Pink Tough 0.05 = 1 -Prusa Skin Tough 0.05 = 1 -Prusa Transparent Red Tough 0.05 = 1 -Prusa White Tough 0.05 = 1 - # All presets starting with asterisk, for example *common*, are intermediate and they will # not make it into the user interface. @@ -222,11 +206,24 @@ travel_speed = 180 wipe_tower_x = 170 wipe_tower_y = 125 +## MINI + +[print:*MINI*] +fill_pattern = grid +travel_speed = 150 +wipe_tower = 0 +default_acceleration = 1250 +first_layer_acceleration = 800 +infill_acceleration = 1000 +bridge_acceleration = 1000 +support_material_speed = 40 +max_print_speed = 150 + # Print parameters common to a 0.25mm diameter nozzle. [print:*0.25nozzle*] external_perimeter_extrusion_width = 0.25 extrusion_width = 0.25 -first_layer_extrusion_width = 0.25 +first_layer_extrusion_width = 0.3 infill_extrusion_width = 0.25 perimeter_extrusion_width = 0.25 solid_infill_extrusion_width = 0.25 @@ -241,7 +238,7 @@ output_filename_format = {input_filename_base}_{nozzle_diameter[0]}n_{layer_heig [print:*0.25nozzleMK3*] external_perimeter_extrusion_width = 0.25 extrusion_width = 0.25 -first_layer_extrusion_width = 0.35 +first_layer_extrusion_width = 0.3 infill_extrusion_width = 0.25 perimeter_extrusion_width = 0.25 solid_infill_extrusion_width = 0.25 @@ -271,6 +268,38 @@ fill_pattern = grid fill_density = 20% output_filename_format = {input_filename_base}_{nozzle_diameter[0]}n_{layer_height}mm_{filament_type[0]}_{printer_model}_{print_time}.gcode +[print:*0.25nozzleMINI*] +external_perimeter_extrusion_width = 0.25 +extrusion_width = 0.25 +first_layer_extrusion_width = 0.3 +infill_extrusion_width = 0.25 +perimeter_extrusion_width = 0.25 +solid_infill_extrusion_width = 0.25 +top_infill_extrusion_width = 0.25 +support_material_extrusion_width = 0.2 +support_material_interface_layers = 0 +support_material_interface_spacing = 0.15 +support_material_spacing = 1 +support_material_xy_spacing = 150% +perimeter_speed = 30 +external_perimeter_speed = 20 +small_perimeter_speed = 20 +infill_speed = 40 +solid_infill_speed = 40 +top_solid_infill_speed = 30 +support_material_speed = 40 +bridge_speed = 20 +gap_fill_speed = 30 +perimeter_acceleration = 500 +infill_acceleration = 800 +bridge_acceleration = 500 +first_layer_acceleration = 500 +max_print_speed = 80 +perimeters = 3 +fill_pattern = grid +fill_density = 20% +output_filename_format = {input_filename_base}_{nozzle_diameter[0]}n_{layer_height}mm_{filament_type[0]}_{printer_model}_{print_time}.gcode + # Print parameters common to a 0.6mm diameter nozzle. [print:*0.6nozzle*] external_perimeter_extrusion_width = 0.61 @@ -324,7 +353,7 @@ inherits = *common* bottom_solid_layers = 10 bridge_acceleration = 300 bridge_flow_ratio = 0.7 -default_acceleration = 500 +default_acceleration = 1000 external_perimeter_speed = 20 fill_density = 20% first_layer_acceleration = 500 @@ -346,12 +375,14 @@ top_solid_layers = 15 [print:0.05mm ULTRADETAIL] inherits = *0.05mm* +alias = 0.05mm ULTRADETAIL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders==1 infill_extrusion_width = 0.5 # MK3 # [print:0.05mm ULTRADETAIL MK3] inherits = *0.05mm*; *MK3* +alias = 0.05mm ULTRADETAIL fill_pattern = gyroid fill_density = 15% compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material @@ -360,6 +391,7 @@ top_infill_extrusion_width = 0.4 # MK2 # [print:0.05mm ULTRADETAIL 0.25 nozzle] inherits = *0.05mm*; *0.25nozzle* +alias = 0.05mm ULTRADETAIL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25 and num_extruders==1 fill_density = 20% infill_speed = 20 @@ -372,10 +404,10 @@ support_material_speed = 20 # MK3 # [print:0.05mm ULTRADETAIL 0.25 nozzle MK3] inherits = *0.05mm*; *0.25nozzle*; *MK3* +alias = 0.05mm ULTRADETAIL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.25 and num_extruders==1 fill_pattern = grid fill_density = 20% -first_layer_extrusion_width = 0.35 # XXXXXXXXXXXXXXXXXXXX # XXX--- 0.07mm ---XXX @@ -387,7 +419,7 @@ bottom_solid_layers = 8 bridge_acceleration = 300 bridge_flow_ratio = 0.7 bridge_speed = 20 -default_acceleration = 500 +default_acceleration = 1000 external_perimeter_speed = 20 fill_density = 15% first_layer_acceleration = 500 @@ -410,12 +442,14 @@ top_solid_layers = 11 # MK3 # [print:0.07mm ULTRADETAIL MK3] inherits = *0.07mm*; *MK3* +alias = 0.07mm ULTRADETAIL fill_pattern = gyroid compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material top_infill_extrusion_width = 0.4 [print:0.07mm ULTRADETAIL 0.25 nozzle MK3] inherits = *0.07mm*; *0.25nozzle*; *MK3* +alias = 0.07mm ULTRADETAIL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.25 and num_extruders==1 infill_speed = 30 solid_infill_speed = 30 @@ -423,7 +457,6 @@ support_material_speed = 30 top_solid_infill_speed = 20 fill_pattern = grid fill_density = 20% -first_layer_extrusion_width = 0.35 # XXXXXXXXXXXXXXXXXXXX # XXX--- 0.10mm ---XXX @@ -442,6 +475,7 @@ top_solid_layers = 9 # MK2 # [print:0.10mm DETAIL] inherits = *0.10mm* +alias = 0.10mm DETAIL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders==1 external_perimeter_speed = 40 infill_acceleration = 2000 @@ -452,6 +486,7 @@ solid_infill_speed = 50 # MK3 # [print:0.10mm DETAIL MK3] inherits = *0.10mm*; *MK3* +alias = 0.10mm DETAIL bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material external_perimeter_speed = 25 @@ -468,10 +503,11 @@ fill_density = 15% # MK2 # [print:0.10mm DETAIL 0.25 nozzle] inherits = *0.10mm*; *0.25nozzle* +alias = 0.10mm DETAIL bridge_acceleration = 600 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25 external_perimeter_speed = 20 -infill_acceleration = 1600 +infill_acceleration = 1000 infill_speed = 40 perimeter_acceleration = 600 perimeter_speed = 25 @@ -482,6 +518,7 @@ top_solid_infill_speed = 30 # MK3 # [print:0.10mm DETAIL 0.25 nozzle MK3] inherits = *0.10mm*; *0.25nozzleMK3*; *MK3* +alias = 0.10mm DETAIL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.25 fill_pattern = grid fill_density = 20% @@ -520,17 +557,19 @@ top_solid_infill_speed = 70 # MK2 # [print:0.15mm OPTIMAL] inherits = *0.15mm* +alias = 0.15mm OPTIMAL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 top_infill_extrusion_width = 0.45 # MK2 # [print:0.15mm OPTIMAL 0.25 nozzle] inherits = *0.15mm*; *0.25nozzle* +alias = 0.15mm OPTIMAL bridge_acceleration = 600 bridge_flow_ratio = 0.7 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25 external_perimeter_speed = 20 -infill_acceleration = 1600 +infill_acceleration = 1000 infill_speed = 40 perimeter_acceleration = 600 perimeter_speed = 25 @@ -541,11 +580,13 @@ top_solid_infill_speed = 30 # MK2 # [print:0.15mm OPTIMAL 0.6 nozzle] inherits = *0.15mm*; *0.6nozzle* +alias = 0.15mm OPTIMAL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 # MK3 # [print:0.15mm QUALITY MK3] inherits = *0.15mm*; *MK3* +alias = 0.15mm QUALITY bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 external_perimeter_speed = 25 @@ -560,6 +601,7 @@ fill_density = 15% [print:0.15mm SPEED MK3] inherits = *0.15mm*; *MK3* +alias = 0.15mm SPEED bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 external_perimeter_speed = 35 @@ -573,6 +615,7 @@ top_solid_infill_speed = 50 # MK3 MMU # [print:0.15mm SOLUBLE FULL MK3] inherits = 0.15mm SPEED MK3; *soluble_support* +alias = 0.15mm SOLUBLE FULL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 notes = Set your soluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder support_material_extruder = 5 @@ -585,6 +628,7 @@ top_solid_infill_speed = 30 # MK3 MMU # [print:0.15mm SOLUBLE INTERFACE MK3] inherits = 0.15mm SOLUBLE FULL MK3 +alias = 0.15mm SOLUBLE INTERFACE notes = Set your soluble extruder in Multiple Extruders > Support material/raft interface extruder support_material_extruder = 0 support_material_interface_layers = 3 @@ -593,6 +637,7 @@ support_material_with_sheath = 0 # MK2 MMU # [print:0.15mm OPTIMAL SOLUBLE FULL] inherits = *0.15mm*; *soluble_support* +alias = 0.15mm OPTIMAL SOLUBLE FULL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 and num_extruders>1 external_perimeter_speed = 25 notes = Set your soluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder @@ -604,6 +649,7 @@ top_solid_infill_speed = 30 # MK2 MMU # [print:0.15mm OPTIMAL SOLUBLE INTERFACE] inherits = 0.15mm OPTIMAL SOLUBLE FULL +alias = 0.15mm OPTIMAL SOLUBLE INTERFACE notes = Set your soluble extruder in Multiple Extruders > Support material/raft interface extruder support_material_extruder = 0 support_material_interface_layers = 3 @@ -613,6 +659,7 @@ support_material_xy_spacing = 80% # MK3 # [print:0.15mm QUALITY 0.25 nozzle MK3] inherits = *0.15mm*; *0.25nozzleMK3*; *MK3* +alias = 0.15mm QUALITY compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.25 fill_pattern = grid fill_density = 20% @@ -620,6 +667,7 @@ fill_density = 20% # MK3 # [print:0.15mm DETAIL 0.6 nozzle MK3] inherits = *0.15mm*; *0.6nozzleMK3*; *MK306* +alias = 0.15mm DETAIL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.6 external_perimeter_speed = 35 infill_acceleration = 1250 @@ -663,6 +711,7 @@ top_solid_infill_speed = 70 # MK3 # [print:0.20mm QUALITY MK3] inherits = *0.20mm*; *MK3* +alias = 0.20mm QUALITY bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 external_perimeter_speed = 25 @@ -677,6 +726,7 @@ fill_density = 15% [print:0.20mm SPEED MK3] inherits = *0.20mm*; *MK3* +alias = 0.20mm SPEED bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 external_perimeter_speed = 35 @@ -690,6 +740,7 @@ top_solid_infill_speed = 50 # MK3 MMU # [print:0.20mm SOLUBLE FULL MK3] inherits = 0.20mm SPEED MK3; *soluble_support* +alias = 0.20mm SOLUBLE FULL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 notes = Set your soluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder support_material_extruder = 5 @@ -702,6 +753,7 @@ top_solid_infill_speed = 30 # MK3 MMU # [print:0.20mm SOLUBLE INTERFACE MK3] inherits = 0.20mm SOLUBLE FULL MK3 +alias = 0.20mm SOLUBLE INTERFACE notes = Set your soluble extruder in Multiple Extruders > Support material/raft interface extruder support_material_extruder = 0 support_material_interface_layers = 3 @@ -715,6 +767,7 @@ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and # MK2 # [print:0.20mm NORMAL 0.6 nozzle] inherits = *0.20mm*; *0.6nozzle* +alias = 0.20mm NORMAL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 # MK2 MMU # @@ -739,6 +792,7 @@ support_material_xy_spacing = 80% # MK3 # [print:0.20mm DETAIL 0.6 nozzle MK3] inherits = *0.20mm*; *0.6nozzleMK3*; *MK306* +alias = 0.20mm DETAIL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.6 external_perimeter_speed = 35 infill_acceleration = 1250 @@ -748,6 +802,21 @@ perimeter_speed = 45 solid_infill_speed = 70 top_solid_infill_speed = 45 + +# XXXXXXXXXXXXXXXXXXXX +# XXX--- 0.25mm ---XXX +# XXXXXXXXXXXXXXXXXXXX + +[print:*0.25mm*] +inherits = *common* +bottom_solid_layers = 4 +bridge_flow_ratio = 0.95 +external_perimeter_speed = 40 +perimeter_acceleration = 800 +layer_height = 0.25 +perimeter_speed = 50 +top_solid_layers = 4 + # XXXXXXXXXXXXXXXXXXXX # XXX--- 0.30mm ---XXX # XXXXXXXXXXXXXXXXXXXX @@ -768,6 +837,7 @@ top_solid_layers = 4 [print:0.30mm QUALITY 0.6 nozzle MK3] inherits = *0.30mm*; *0.6nozzleMK3*; *MK306* +alias = 0.30mm QUALITY compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.6 external_perimeter_speed = 35 infill_acceleration = 1250 @@ -779,6 +849,7 @@ top_solid_infill_speed = 45 [print:0.30mm SOLUBLE FULL 0.6 nozzle MK3] inherits = 0.30mm QUALITY 0.6 nozzle MK3; *soluble_support* +alias = 0.30mm SOLUBLE FULL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.6 and num_extruders>1 notes = Set your soluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder support_material_extruder = 5 @@ -793,6 +864,7 @@ support_material_xy_spacing = 80% [print:0.30mm SOLUBLE INTERFACE 0.6 nozzle MK3] inherits = 0.30mm SOLUBLE FULL 0.6 nozzle MK3 +alias = 0.30mm SOLUBLE INTERFACE notes = Set your soluble extruder in Multiple Extruders > Support material/raft interface extruder support_material_extruder = 0 support_material_interface_layers = 3 @@ -800,6 +872,7 @@ support_material_with_sheath = 0 [print:0.30mm DRAFT MK3] inherits = *0.30mm*; *MK3* +alias = 0.30mm DRAFT bottom_solid_layers = 3 bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 @@ -851,15 +924,18 @@ first_layer_extrusion_width = 0.42 perimeter_extrusion_width = 0.43 solid_infill_extrusion_width = 0.7 top_infill_extrusion_width = 0.43 +support_material_extrusion_width = 0.37 # MK2 # [print:0.35mm FAST 0.6 nozzle] inherits = *0.35mm*; *0.6nozzle* +alias = 0.35mm FAST compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 # MK2 MMU # [print:0.35mm FAST sol full 0.6 nozzle] inherits = *0.35mm*; *0.6nozzle*; *soluble_support* +alias = 0.35mm FAST SOLUBLE FULL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_model=="MK2SMM" and nozzle_diameter[0]==0.6 and num_extruders>1 external_perimeter_extrusion_width = 0.6 external_perimeter_speed = 30 @@ -874,6 +950,7 @@ support_material_extrusion_width = 0.6 # MK2 MMU # [print:0.35mm FAST sol int 0.6 nozzle] inherits = 0.35mm FAST sol full 0.6 nozzle +alias = 0.35mm FAST SOLUBLE INTERFACE support_material_extruder = 0 support_material_interface_layers = 3 support_material_with_sheath = 0 @@ -882,6 +959,7 @@ support_material_xy_spacing = 150% # MK3 # [print:0.35mm SPEED 0.6 nozzle MK3] inherits = *0.35mm*; *0.6nozzleMK3*; *MK306* +alias = 0.35mm SPEED compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.6 external_perimeter_speed = 35 infill_acceleration = 1250 @@ -917,6 +995,7 @@ top_solid_layers = 4 # MK3 # [print:0.40mm DRAFT 0.6 nozzle MK3] inherits = *0.40mm*; *0.6nozzleMK3*; *MK306* +alias = 0.40mm DRAFT compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.6 external_perimeter_speed = 35 infill_acceleration = 1250 @@ -943,12 +1022,14 @@ single_extruder_multi_material_priming = 0 # MK2.5 # [print:0.15mm OPTIMAL MK2.5] inherits = 0.15mm OPTIMAL +alias = 0.15mm OPTIMAL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 single_extruder_multi_material_priming = 0 # MK2.5 MMU2 # [print:0.15mm OPTIMAL SOLUBLE FULL MK2.5] inherits = 0.15mm OPTIMAL SOLUBLE FULL +alias = 0.15mm OPTIMAL SOLUBLE FULL support_material_extruder = 5 support_material_interface_extruder = 5 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 @@ -956,6 +1037,7 @@ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and # MK2.5 MMU2 # [print:0.15mm OPTIMAL SOLUBLE INTERFACE MK2.5] inherits = 0.15mm OPTIMAL SOLUBLE INTERFACE +alias = 0.15mm OPTIMAL SOLUBLE INTERFACE support_material_extruder = 0 support_material_interface_extruder = 5 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 @@ -963,18 +1045,21 @@ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and # MK2.5 # [print:0.20mm 100mms Linear Advance MK2.5] inherits = 0.20mm 100mms Linear Advance +alias = 0.20mm 100mms Linear Advance compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 single_extruder_multi_material_priming = 0 # MK2.5 # [print:0.20mm NORMAL MK2.5] inherits = 0.20mm NORMAL +alias = 0.20mm NORMAL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 single_extruder_multi_material_priming = 0 # MK2.5 MMU2 # [print:0.20mm NORMAL SOLUBLE FULL MK2.5] inherits = 0.20mm NORMAL SOLUBLE FULL +alias = 0.20mm NORMAL SOLUBLE FULL support_material_extruder = 5 support_material_interface_extruder = 5 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 @@ -983,6 +1068,7 @@ single_extruder_multi_material_priming = 0 # MK2.5 MMU2 # [print:0.20mm NORMAL SOLUBLE INTERFACE MK2.5] inherits = 0.20mm NORMAL SOLUBLE INTERFACE +alias = 0.20mm NORMAL SOLUBLE INTERFACE support_material_extruder = 0 support_material_interface_extruder = 5 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 @@ -991,12 +1077,14 @@ single_extruder_multi_material_priming = 0 # MK2.5 # [print:0.35mm FAST MK2.5] inherits = 0.35mm FAST +alias = 0.35mm FAST compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 single_extruder_multi_material_priming = 0 # MK2.5 MMU2 0.6 nozzle# [print:0.35mm SOLUBLE FULL 0.6 nozzle MK2.5] inherits = *0.35mm*; *0.6nozzle*; *soluble_support* +alias = 0.35mm SOLUBLE FULL compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and printer_model!="MK2SMM" and nozzle_diameter[0]==0.6 and num_extruders>1 external_perimeter_extrusion_width = 0.6 external_perimeter_speed = 30 @@ -1012,11 +1100,154 @@ support_material_extrusion_width = 0.6 [print:0.35mm SOLUBLE INTERFACE 0.6 nozzle MK2.5] inherits = 0.35mm SOLUBLE FULL 0.6 nozzle MK2.5 +alias = 0.35mm SOLUBLE INTERFACE support_material_extruder = 0 support_material_interface_layers = 3 support_material_with_sheath = 0 support_material_xy_spacing = 80% +## MINI print profiles + +# 0.4mm nozzle + +[print:0.05mm ULTRADETAIL MINI] +inherits = *0.05mm*; *MINI* +alias = 0.05mm ULTRADETAIL +fill_pattern = gyroid +fill_density = 15% +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.4 +top_infill_extrusion_width = 0.4 +small_perimeter_speed = 15 +perimeter_extrusion_width = 0.4 +external_perimeter_extrusion_width = 0.4 + +[print:0.07mm ULTRADETAIL MINI] +inherits = *0.07mm*; *MINI* +alias = 0.07mm ULTRADETAIL +fill_pattern = gyroid +fill_density = 15% +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.4 +top_infill_extrusion_width = 0.4 +small_perimeter_speed = 15 +perimeter_extrusion_width = 0.4 +external_perimeter_extrusion_width = 0.4 + +[print:0.10mm DETAIL MINI] +inherits = *0.10mm*; *MINI* +alias = 0.10mm DETAIL +bridge_speed = 30 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.4 +perimeter_speed = 40 +external_perimeter_speed = 30 +infill_speed = 80 +solid_infill_speed = 80 +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 40 +fill_pattern = gyroid +fill_density = 15% +perimeters = 3 +bridge_acceleration = 800 + +[print:0.15mm QUALITY MINI] +inherits = *0.15mm*; *MINI* +alias = 0.15mm QUALITY +bridge_speed = 30 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.4 +perimeter_speed = 40 +external_perimeter_speed = 30 +infill_speed = 80 +solid_infill_speed = 80 +top_solid_infill_speed = 40 +fill_pattern = gyroid +fill_density = 15% +bridge_flow_ratio = 0.85 + +[print:0.15mm SPEED MINI] +inherits = *0.15mm*; *MINI* +alias = 0.15mm SPEED +bridge_speed = 30 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.4 +perimeter_speed = 50 +external_perimeter_speed = 40 +infill_speed = 140 +solid_infill_speed = 140 +top_solid_infill_speed = 40 +bridge_flow_ratio = 0.85 + +[print:0.20mm QUALITY MINI] +inherits = *0.20mm*; *MINI* +alias = 0.20mm QUALITY +bridge_speed = 30 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.4 +perimeter_speed = 40 +external_perimeter_speed = 30 +infill_speed = 80 +solid_infill_speed = 80 +top_solid_infill_speed = 40 +fill_pattern = gyroid +fill_density = 15% + +[print:0.20mm SPEED MINI] +inherits = *0.20mm*; *MINI* +alias = 0.20mm SPEED +bridge_speed = 30 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.4 +perimeter_speed = 50 +external_perimeter_speed = 40 +infill_speed = 140 +max_print_speed = 150 +solid_infill_speed = 140 +top_solid_infill_speed = 40 + +[print:0.25mm DRAFT MINI] +inherits = *0.25mm*; *MINI* +alias = 0.25mm DRAFT +bridge_speed = 30 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.4 +external_perimeter_speed = 40 +infill_speed = 90 +perimeter_speed = 50 +small_perimeter_speed = 25 +solid_infill_speed = 85 +top_solid_infill_speed = 45 +first_layer_extrusion_width = 0.42 +infill_extrusion_width = 0.48 +solid_infill_extrusion_width = 0.48 +top_infill_extrusion_width = 0.4 + +# 0.25mm nozzle +[print:0.05mm ULTRADETAIL 0.25 nozzle MINI] +inherits = *0.05mm*; *0.25nozzle*; *MINI* +alias = 0.05mm ULTRADETAIL +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.25 +fill_pattern = grid +fill_density = 20% + +[print:0.07mm ULTRADETAIL 0.25 nozzle MINI] +inherits = *0.07mm*; *0.25nozzle*; *MINI* +alias = 0.07mm ULTRADETAIL +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.25 +infill_speed = 30 +solid_infill_speed = 30 +support_material_speed = 30 +top_solid_infill_speed = 20 +fill_pattern = grid +fill_density = 20% + +[print:0.10mm DETAIL 0.25 nozzle MINI] +inherits = *0.10mm*; *0.25nozzleMINI*; *MINI* +alias = 0.10mm DETAIL +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.25 +fill_pattern = grid +fill_density = 20% + +[print:0.15mm QUALITY 0.25 nozzle MINI] +inherits = *0.15mm*; *0.25nozzleMINI*; *MINI* +alias = 0.15mm QUALITY +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.25 +fill_pattern = grid +fill_density = 20% + # XXXXXXxxXXXXXXXXXXXXXX # XXX--- filament ---XXX # XXXXXXXXxxXXXXXXXXXXXX @@ -1048,7 +1279,7 @@ filament_settings_id = "" filament_soluble = 0 min_print_speed = 15 slowdown_below_layer_time = 20 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif} ; Filament gcode" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif} ; Filament gcode" [filament:*PLA*] inherits = *common* @@ -1057,7 +1288,7 @@ bridge_fan_speed = 100 disable_fan_first_layers = 1 fan_always_on = 1 fan_below_layer_time = 100 -filament_colour = #FF3232 +filament_colour = #FF8000 filament_max_volumetric_speed = 15 filament_type = PLA first_layer_bed_temperature = 60 @@ -1065,7 +1296,7 @@ first_layer_temperature = 215 max_fan_speed = 100 min_fan_speed = 100 temperature = 210 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{elsif nozzle_diameter[0]==0.6}18{else}30{endif} ; Filament gcode" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{elsif nozzle_diameter[0]==0.6}18{else}30{endif} ; Filament gcode" [filament:*PET*] inherits = *common* @@ -1076,7 +1307,7 @@ fan_always_on = 1 fan_below_layer_time = 20 filament_colour = #FF8000 filament_max_volumetric_speed = 8 -filament_type = PET +filament_type = PETG first_layer_bed_temperature = 85 first_layer_temperature = 230 max_fan_speed = 50 @@ -1085,7 +1316,7 @@ start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{el temperature = 240 filament_retract_length = 1.4 filament_retract_lift = 0.2 -compatible_printers_condition = printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) +compatible_printers_condition = printer_model!="MK2SMM" and printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) [filament:*PET06*] inherits = *PET* @@ -1099,6 +1330,49 @@ filament_retract_speed = nil filament_retract_lift = 0.2 compatible_printers_condition = printer_model=="MK2SMM" +[filament:*PETMINI*] +inherits = *PET* +filament_retract_length = nil +filament_retract_speed = 40 +filament_deretract_speed = 25 +filament_retract_lift = nil +filament_retract_before_travel = 1 +filament_max_volumetric_speed = 7 +compatible_printers_condition = printer_model=="MINI" +start_filament_gcode = "M900 K0.2 ; Filament gcode" + +[filament:*ABSMINI*] +inherits = *ABS* +bed_temperature = 100 +filament_retract_length = 2.7 +filament_retract_speed = nil +filament_deretract_speed = nil +filament_retract_lift = nil +filament_retract_before_travel = 3 +filament_wipe = 0 +filament_max_volumetric_speed = 10 +compatible_printers_condition = printer_model=="MINI" +start_filament_gcode = "M900 K0.2 ; Filament gcode" + +[filament:*FLEXMINI*] +inherits = *FLEX* +filament_retract_length = 6 +filament_retract_speed = 40 +filament_deretract_speed = 15 +filament_retract_lift = 0 +filament_retract_before_travel = 7 +filament_wipe = 0 +bridge_fan_speed = 70 +fan_always_on = 1 +cooling = 0 +max_fan_speed = 40 +min_fan_speed = 40 +filament_max_volumetric_speed = 1.6 +compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_model=="MINI" +disable_fan_first_layers = 3 +extrusion_multiplier = 1.2 +start_filament_gcode = "M900 K0 ; Filament gcode" + [filament:*ABS*] inherits = *common* bed_temperature = 110 @@ -1117,13 +1391,14 @@ max_fan_speed = 30 min_fan_speed = 20 temperature = 255 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{elsif nozzle_diameter[0]==0.6}18{else}30{endif} ; Filament gcode" +compatible_printers_condition = printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) [filament:*FLEX*] inherits = *common* bed_temperature = 50 -bridge_fan_speed = 100 +bridge_fan_speed = 80 # For now, all but selected filaments are disabled for the MMU 2.0 -compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_model!="MK2SMM" and num_extruders==1 && ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material) +compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_model!="MK2SMM" and printer_model!="MINI" and num_extruders==1 && ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material) cooling = 0 disable_fan_first_layers = 1 extrusion_multiplier = 1.2 @@ -1141,27 +1416,46 @@ temperature = 240 filament_retract_length = 0.4 filament_retract_lift = 0 -[filament:ColorFabb Brass Bronze] +[filament:ColorFabb bronzeFill] inherits = *PLA* -# For now, all but selected filaments are disabled for the MMU 2.0 +filament_vendor = ColorFabb compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) extrusion_multiplier = 1.2 -filament_cost = 56.64 +filament_cost = 72.89 filament_density = 3.9 filament_colour = #804040 filament_max_volumetric_speed = 9 -filament_notes = "List of materials tested with standard print settings:\n\nColorFabb bronzeFill\nColorFabb brassFill\nColorFabb steelFill\nColorFabb copperFill" + +[filament:ColorFabb steelFill] +inherits = *PLA* filament_vendor = ColorFabb +compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) +extrusion_multiplier = 1.2 +filament_cost = 72.89 +filament_density = 3.13 +filament_colour = #808080 +filament_max_volumetric_speed = 8 + +[filament:ColorFabb copperFill] +inherits = *PLA* +filament_vendor = ColorFabb +compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) +extrusion_multiplier = 1.2 +filament_cost = 72.89 +filament_density = 3.9 +filament_colour = #82603E +filament_max_volumetric_speed = 9 [filament:ColorFabb HT] inherits = *PET* +filament_vendor = ColorFabb bed_temperature = 110 bridge_fan_speed = 30 cooling = 1 disable_fan_first_layers = 3 fan_always_on = 0 fan_below_layer_time = 10 -filament_cost = 58.66 +filament_cost = 65.66 filament_density = 1.18 first_layer_bed_temperature = 105 first_layer_temperature = 270 @@ -1169,56 +1463,53 @@ max_fan_speed = 20 min_fan_speed = 10 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode" temperature = 270 -filament_vendor = ColorFabb [filament:ColorFabb PLA-PHA] inherits = *PLA* -filament_cost = 55.5 -filament_density = 1.24 filament_vendor = ColorFabb +filament_cost = 52.46 +filament_density = 1.24 [filament:ColorFabb woodFill] inherits = *PLA* -# For now, all but selected filaments are disabled for the MMU 2.0 +filament_vendor = ColorFabb compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) extrusion_multiplier = 1.2 -filament_cost = 62.9 +filament_cost = 58.30 filament_density = 1.15 filament_colour = #dfc287 -filament_max_volumetric_speed = 10 +filament_max_volumetric_speed = 9 first_layer_temperature = 200 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/}0{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}0{else}10{endif}; Filament gcode" temperature = 200 -filament_vendor = ColorFabb [filament:ColorFabb corkFill] inherits = *PLA* +filament_vendor = ColorFabb compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) extrusion_multiplier = 1.2 -filament_cost = 45.45 +filament_cost = 58.30 filament_density = 1.18 filament_colour = #634d33 filament_max_volumetric_speed = 6 first_layer_temperature = 220 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/}0{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}0{else}10{endif}; Filament gcode" temperature = 220 -filament_vendor = ColorFabb [filament:ColorFabb XT] inherits = *PET* -filament_type = PET -filament_cost = 62.9 +filament_vendor = ColorFabb +filament_cost = 58.30 filament_density = 1.27 first_layer_bed_temperature = 90 first_layer_temperature = 260 temperature = 270 -filament_vendor = ColorFabb [filament:ColorFabb XT-CF20] inherits = *PET* -compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) +filament_vendor = ColorFabb extrusion_multiplier = 1.2 -filament_cost = 80.65 +filament_cost = 72.89 filament_density = 1.35 filament_colour = #804040 filament_max_volumetric_speed = 1 @@ -1228,11 +1519,11 @@ start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{el temperature = 260 filament_retract_length = nil filament_retract_lift = 0.2 -filament_vendor = ColorFabb [filament:ColorFabb nGen] inherits = *PET* -filament_cost = 21.2 +filament_vendor = ColorFabb +filament_cost = 52.46 filament_density = 1.2 bridge_fan_speed = 40 fan_always_on = 0 @@ -1241,11 +1532,11 @@ filament_type = NGEN first_layer_temperature = 240 max_fan_speed = 35 min_fan_speed = 20 -filament_vendor = ColorFabb [filament:ColorFabb nGen flex] inherits = *FLEX* -filament_cost = 0 +filament_vendor = ColorFabb +filament_cost = 58.30 filament_density = 1 bed_temperature = 85 bridge_fan_speed = 40 @@ -1261,35 +1552,42 @@ min_fan_speed = 20 temperature = 260 filament_retract_length = nil filament_retract_lift = 0 -compatible_printers_condition = nozzle_diameter[0]>0.35 and num_extruders==1 && ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material) -filament_vendor = ColorFabb +compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_model!="MINI" and num_extruders==1 && ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material) [filament:E3D Edge] inherits = *PET* +filament_vendor = E3D filament_cost = 56.9 filament_density = 1.26 filament_type = EDGE -filament_vendor = E3D +compatible_printers_condition = printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) [filament:E3D PC-ABS] inherits = *ABS* +filament_vendor = E3D filament_cost = 0 filament_type = PC filament_density = 1.05 first_layer_temperature = 270 temperature = 270 -filament_vendor = E3D + +[filament:Fillamentum PLA] +inherits = *PLA* +filament_vendor = Fillamentum +filament_cost = 25.4 +filament_density = 1.24 [filament:Fillamentum ABS] inherits = *ABS* +filament_vendor = Fillamentum filament_cost = 32.4 filament_density = 1.04 first_layer_temperature = 240 temperature = 240 -filament_vendor = Fillamentum [filament:Fillamentum ASA] inherits = *ABS* +filament_vendor = Fillamentum filament_cost = 38.7 filament_density = 1.07 fan_always_on = 1 @@ -1301,10 +1599,10 @@ slowdown_below_layer_time = 15 first_layer_temperature = 265 temperature = 265 filament_type = ASA -filament_vendor = Fillamentum [filament:Prusament ASA] inherits = *ABS* +filament_vendor = Prusa Polymers filament_cost = 35.28 filament_density = 1.07 fan_always_on = 1 @@ -1324,6 +1622,7 @@ start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{el [filament:Fillamentum CPE] inherits = *PET* +filament_vendor = Fillamentum filament_cost = 54.1 filament_density = 1.25 filament_type = CPE @@ -1332,11 +1631,10 @@ first_layer_temperature = 275 max_fan_speed = 50 min_fan_speed = 50 temperature = 275 -filament_vendor = Fillamentum [filament:Fillamentum Timberfill] inherits = *PLA* -# For now, all but selected filaments are disabled for the MMU 2.0 +filament_vendor = Fillamentum compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) extrusion_multiplier = 1.2 filament_cost = 68 @@ -1344,33 +1642,33 @@ filament_density = 1.15 filament_colour = #804040 filament_max_volumetric_speed = 10 first_layer_temperature = 190 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/}0{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}0{else}10{endif}; Filament gcode" temperature = 190 -filament_vendor = Fillamentum [filament:Generic ABS] inherits = *ABS* +filament_vendor = Generic filament_cost = 27.82 filament_density = 1.04 filament_notes = "List of materials tested with standard ABS print settings:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladec ABS" -filament_vendor = Generic [filament:Generic PET] inherits = *PET* +filament_vendor = Generic filament_cost = 27.82 filament_density = 1.27 filament_notes = "List of manufacturers tested with standard PET print settings:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladec PETG" -filament_vendor = Generic [filament:Generic PLA] inherits = *PLA* +filament_vendor = Generic filament_cost = 25.4 filament_density = 1.24 filament_notes = "List of materials tested with standard PLA print settings:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH" -filament_vendor = Generic [filament:Generic FLEX] inherits = *FLEX* +filament_vendor = Generic filament_cost = 82 filament_density = 1.22 filament_max_volumetric_speed = 1.2 @@ -1380,6 +1678,7 @@ filament_retract_lift = nil [filament:Polymaker PC-Max] inherits = *ABS* +filament_vendor = Polymaker filament_cost = 77.3 filament_density = 1.20 filament_type = PC @@ -1388,10 +1687,11 @@ filament_colour = #3A80CA first_layer_bed_temperature = 100 first_layer_temperature = 270 temperature = 270 -filament_vendor = Polymaker +bridge_fan_speed = 0 [filament:PrimaSelect PVA+] inherits = *PLA* +filament_vendor = PrimaSelect filament_cost = 108 filament_density = 1.23 cooling = 0 @@ -1403,16 +1703,15 @@ filament_ramming_parameters = "120 100 8.3871 8.6129 8.93548 9.22581 9.48387 9.7 filament_soluble = 1 filament_type = PVA first_layer_temperature = 195 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/}0{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}0{else}10{endif}; Filament gcode" temperature = 195 -filament_vendor = PrimaSelect [filament:Prusa ABS] inherits = *ABS* +filament_vendor = Prusa filament_cost = 27.82 filament_density = 1.08 filament_notes = "List of materials tested with standard ABS print settings:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladec ABS" -filament_vendor = Prusa [filament:*ABS MMU2*] inherits = Prusa ABS @@ -1429,10 +1728,13 @@ filament_unloading_speed = 20 [filament:Generic ABS MMU2] inherits = *ABS MMU2* +alias = Generic ABS filament_vendor = Generic [filament:Prusament ASA MMU2] inherits = *ABS MMU2* +alias = Prusament ASA +filament_vendor = Prusa Polymers filament_cost = 35.28 filament_density = 1.07 fan_always_on = 1 @@ -1455,10 +1757,12 @@ start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{el [filament:Prusa ABS MMU2] inherits = *ABS MMU2* +alias = Prusa ABS filament_vendor = Prusa [filament:Prusa HIPS] inherits = *ABS* +filament_vendor = Prusa filament_cost = 27.3 filament_density = 1.04 bridge_fan_speed = 50 @@ -1472,43 +1776,44 @@ filament_type = HIPS first_layer_temperature = 220 max_fan_speed = 20 min_fan_speed = 20 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/}0{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}0{else}10{endif}; Filament gcode" temperature = 220 -filament_vendor = Prusa [filament:Prusa PET] inherits = *PET* +filament_vendor = Prusa filament_cost = 27.82 filament_density = 1.27 filament_notes = "List of manufacturers tested with standard PET print settings:\n\nE3D Edge\nPlasty Mladec PETG" -compatible_printers_condition = nozzle_diameter[0]!=0.6 and printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) -filament_vendor = Prusa +compatible_printers_condition = nozzle_diameter[0]!=0.6 and printer_model!="MK2SMM" and printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) [filament:Prusament PETG] inherits = *PET* +filament_vendor = Prusa Polymers first_layer_temperature = 240 temperature = 250 filament_cost = 24.99 filament_density = 1.27 filament_type = PETG -compatible_printers_condition = nozzle_diameter[0]!=0.6 and printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) -filament_vendor = Prusa +compatible_printers_condition = nozzle_diameter[0]!=0.6 and printer_model!="MK2SMM" and printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) [filament:Prusa PET 0.6 nozzle] inherits = *PET06* +alias = Prusa PET +filament_vendor = Prusa filament_cost = 27.82 filament_density = 1.27 filament_notes = "List of manufacturers tested with standard PET print settings:\n\nE3D Edge\nPlasty Mladec PETG" -filament_vendor = Prusa [filament:Prusament PETG 0.6 nozzle] inherits = *PET06* +alias = Prusament PETG +filament_vendor = Prusa Polymers first_layer_temperature = 240 temperature = 250 filament_cost = 24.99 filament_density = 1.27 filament_type = PETG -filament_vendor = Prusa [filament:*PET MMU2*] inherits = Prusa PET @@ -1536,42 +1841,50 @@ filament_max_volumetric_speed = 13 [filament:Generic PET MMU2] inherits = *PET MMU2* +alias = Generic PET filament_vendor = Generic [filament:Prusa PET MMU2] inherits = *PET MMU2* +alias = Prusa PET filament_vendor = Prusa [filament:Prusament PETG MMU2] inherits = *PET MMU2* filament_type = PETG +alias = Prusament PETG +filament_vendor = Prusa Polymers [filament:Generic PET MMU2 0.6 nozzle] inherits = *PET MMU2 06* +alias = Generic PET +filament_vendor = Generic [filament:Prusa PET MMU2 0.6 nozzle] inherits = *PET MMU2 06* +alias = Prusa PET filament_vendor = Prusa [filament:Prusament PETG MMU2 0.6 nozzle] inherits = *PET MMU2 06* filament_type = PETG -filament_vendor = Prusa +alias = Prusament PETG +filament_vendor = Prusa Polymers [filament:Prusa PLA] inherits = *PLA* +filament_vendor = Prusa filament_cost = 25.4 filament_density = 1.24 -filament_notes = "List of materials tested with standard PLA print settings:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFiberlogy PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nAmazonBasics PLA" -filament_vendor = Prusa +filament_notes = "List of materials tested with standard PLA print settings:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFiberlogy PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nAmazonBasics PLA" [filament:Prusament PLA] inherits = *PLA* +filament_vendor = Prusa Polymers temperature = 215 filament_cost = 24.99 filament_density = 1.24 filament_notes = "Affordable filament for everyday printing in premium quality manufactured in-house by Josef Prusa" -filament_vendor = Prusa [filament:*PLA MMU2*] inherits = Prusa PLA @@ -1591,25 +1904,29 @@ filament_unloading_speed_start = 100 [filament:Generic PLA MMU2] inherits = *PLA MMU2* +alias = Generic PLA filament_vendor = Generic [filament:Prusa PLA MMU2] inherits = *PLA MMU2* +alias = Prusa PLA filament_vendor = Prusa [filament:Prusament PLA MMU2] inherits = *PLA MMU2* -filament_vendor = Prusa +alias = Prusament PLA +filament_vendor = Prusa Polymers [filament:SemiFlex or Flexfill 98A] inherits = *FLEX* +filament_vendor = Generic filament_cost = 82 filament_density = 1.22 filament_max_volumetric_speed = 1.35 -filament_vendor = Flexfill [filament:Taulman Bridge] inherits = *common* +filament_vendor = Taulman filament_cost = 40 filament_density = 1.13 bed_temperature = 90 @@ -1626,12 +1943,12 @@ first_layer_bed_temperature = 60 first_layer_temperature = 240 max_fan_speed = 5 min_fan_speed = 0 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/}0{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}0{else}10{endif}; Filament gcode" temperature = 250 -filament_vendor = Taulman [filament:Taulman T-Glase] inherits = *PET* +filament_vendor = Taulman filament_cost = 40 filament_density = 1.27 bridge_fan_speed = 40 @@ -1642,10 +1959,16 @@ first_layer_temperature = 240 max_fan_speed = 5 min_fan_speed = 0 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" -filament_vendor = Taulman + +[filament:Verbatim PLA] +inherits = *PLA* +filament_vendor = Verbatim +filament_cost = 42.99 +filament_density = 1.24 [filament:Verbatim BVOH] inherits = *common* +filament_vendor = Verbatim filament_cost = 218 filament_density = 1.23 bed_temperature = 60 @@ -1664,12 +1987,13 @@ first_layer_bed_temperature = 60 first_layer_temperature = 215 max_fan_speed = 100 min_fan_speed = 100 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/}0{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}0{else}10{endif}; Filament gcode" temperature = 210 -filament_vendor = Verbatim [filament:Verbatim BVOH MMU2] inherits = Verbatim BVOH +alias = Verbatim BVOH +filament_vendor = Verbatim compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material temperature = 195 fan_always_on = 1 @@ -1686,10 +2010,11 @@ filament_unload_time = 12 filament_unloading_speed = 20 filament_unloading_speed_start = 100 filament_loading_speed_start = 19 -filament_vendor = Verbatim [filament:PrimaSelect PVA+ MMU2] inherits = *common* +alias = PrimaSelect PVA+ +filament_vendor = PrimaSelect compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material bed_temperature = 60 bridge_fan_speed = 100 @@ -1725,10 +2050,10 @@ min_print_speed = 15 slowdown_below_layer_time = 20 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" temperature = 195 -filament_vendor = PrimaSelect [filament:Verbatim PP] inherits = *common* +filament_vendor = Verbatim filament_cost = 72 filament_density = 0.89 bed_temperature = 100 @@ -1746,14 +2071,15 @@ first_layer_bed_temperature = 100 first_layer_temperature = 220 max_fan_speed = 100 min_fan_speed = 100 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/}0{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}0{else}10{endif}; Filament gcode" temperature = 220 -filament_vendor = Verbatim ## Filaments MMU1 [filament:ColorFabb HT MMU1] inherits = *PETMMU1* +alias = ColorFabb HT +filament_vendor = ColorFabb bed_temperature = 110 bridge_fan_speed = 30 cooling = 1 @@ -1771,7 +2097,9 @@ temperature = 270 [filament:ColorFabb XT MMU1] inherits = *PETMMU1* -filament_type = PET +alias = ColorFabb XT +filament_vendor = ColorFabb +filament_type = PETG filament_cost = 62.9 filament_density = 1.27 first_layer_bed_temperature = 90 @@ -1780,6 +2108,8 @@ temperature = 270 [filament:ColorFabb XT-CF20 MMU1] inherits = *PETMMU1* +alias = ColorFabb XT-CF20 +filament_vendor = ColorFabb compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_model=="MK2SMM" extrusion_multiplier = 1.2 filament_cost = 80.65 @@ -1793,6 +2123,8 @@ temperature = 260 [filament:ColorFabb nGen MMU1] inherits = *PETMMU1* +alias = ColorFabb nGen +filament_vendor = ColorFabb filament_cost = 21.2 filament_density = 1.2 bridge_fan_speed = 40 @@ -1805,6 +2137,8 @@ min_fan_speed = 20 [filament:E3D Edge MMU1] inherits = *PETMMU1* +alias = E3D Edge +filament_vendor = E3D filament_cost = 56.9 filament_density = 1.26 filament_type = EDGE @@ -1812,6 +2146,8 @@ filament_notes = "List of manufacturers tested with standard PET print settings: [filament:Fillamentum CPE MMU1] inherits = *PETMMU1* +alias = Fillamentum CPE +filament_vendor = Fillamentum filament_cost = 54.1 filament_density = 1.25 filament_type = CPE @@ -1823,18 +2159,24 @@ temperature = 275 [filament:Generic PET MMU1] inherits = *PETMMU1* +alias = Generic PET +filament_vendor = Generic filament_cost = 27.82 filament_density = 1.27 filament_notes = "List of manufacturers tested with standard PET print settings:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladec PETG" [filament:Prusa PET MMU1] inherits = *PETMMU1* +alias = Prusa PET +filament_vendor = Prusa filament_cost = 27.82 filament_density = 1.27 filament_notes = "List of manufacturers tested with standard PET print settings:\n\nE3D Edge\nPlasty Mladec PETG" [filament:Prusament PETG MMU1] inherits = *PETMMU1* +alias = Prusament PETG +filament_vendor = Prusa Polymers first_layer_temperature = 240 temperature = 250 filament_cost = 24.99 @@ -1843,6 +2185,8 @@ filament_type = PETG [filament:Taulman T-Glase MMU1] inherits = *PETMMU1* +alias = Taulman T-Glase +filament_vendor = Taulman filament_cost = 40 filament_density = 1.27 bridge_fan_speed = 40 @@ -1856,6 +2200,8 @@ start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{el [filament:SemiFlex or Flexfill 98A MMU1] inherits = *FLEX* +alias = SemiFlex or Flexfill 98A +filament_vendor = Generic filament_cost = 82 filament_density = 1.22 filament_max_volumetric_speed = 1.35 @@ -1866,6 +2212,8 @@ compatible_printers_condition = printer_model=="MK2SMM" [filament:Generic FLEX MMU1] inherits = *FLEX* +alias = Generic FLEX +filament_vendor = Generic filament_cost = 82 filament_density = 1.22 filament_max_volumetric_speed = 1.2 @@ -1874,6 +2222,195 @@ filament_retract_speed = nil filament_retract_lift = nil compatible_printers_condition = printer_model=="MK2SMM" +## Filaments MINI + +[filament:Generic PET MINI] +inherits = Generic PET; *PETMINI* +alias = Generic PET + +[filament:Generic ABS MINI] +inherits = Generic ABS; *ABSMINI* +alias = Generic ABS + +[filament:Prusament PETG MINI] +inherits = Prusament PETG; *PETMINI* +alias = Prusament PETG + +[filament:Prusament ASA MINI] +inherits = Prusament ASA; *ABSMINI* +alias = Prusament ASA +first_layer_temperature = 260 +first_layer_bed_temperature = 100 +temperature = 260 +bed_temperature = 100 +fan_always_on = 1 +cooling = 1 +min_fan_speed = 20 +max_fan_speed = 20 +min_print_speed = 15 +slowdown_below_layer_time = 15 +disable_fan_first_layers = 4 +filament_type = ASA +filament_colour = #FFF2EC + +[filament:Fillamentum Flexfill 98A MINI] +inherits = SemiFlex or Flexfill 98A; *FLEXMINI* +alias = Fillamentum Flexfill 98A +filament_vendor = Fillamentum +filament_max_volumetric_speed = 1.6 + +[filament:Fillamentum CPE MINI] +inherits = Fillamentum CPE; *PETMINI* +alias = Fillamentum CPE +first_layer_temperature = 265 +first_layer_bed_temperature = 90 +temperature = 265 + +[filament:ColorFabb nGen MINI] +inherits = ColorFabb nGen; *PETMINI* +alias = ColorFabb nGen + +[filament:ColorFabb nGen flex MINI] +inherits = ColorFabb nGen flex; *FLEXMINI* +alias = ColorFabb nGen flex +filament_max_volumetric_speed = 4 + +[filament:E3D PC-ABS MINI] +inherits = E3D PC-ABS; *ABSMINI* +alias = E3D PC-ABS + +[filament:Fillamentum ABS MINI] +inherits = Fillamentum ABS; *ABSMINI* +alias = Fillamentum ABS + +[filament:Fillamentum ASA MINI] +inherits = Fillamentum ASA; *ABSMINI* +alias = Fillamentum ASA +first_layer_temperature = 255 +first_layer_bed_temperature = 100 +temperature = 255 +bed_temperature = 100 +fan_always_on = 1 +cooling = 1 +min_fan_speed = 20 +max_fan_speed = 20 +min_print_speed = 15 +slowdown_below_layer_time = 15 +disable_fan_first_layers = 4 +filament_type = ASA +filament_colour = #FFF2EC + +[filament:Polymaker PC-Max MINI] +inherits = Polymaker PC-Max; *ABSMINI* +alias = Polymaker PC-Max +filament_type = PC +bed_temperature = 100 +filament_colour = #3A80CA +first_layer_bed_temperature = 100 +first_layer_temperature = 270 +temperature = 270 +bridge_fan_speed = 0 + +[filament:Prusa ABS MINI] +inherits = *ABSMINI* +alias = Prusa ABS +filament_vendor = Prusa + +[filament:Generic HIPS MINI] +inherits = *ABSMINI* +alias = Generic HIPS +filament_vendor = Generic +filament_cost = 27.3 +filament_density = 1.04 +bridge_fan_speed = 50 +cooling = 1 +extrusion_multiplier = 0.9 +fan_always_on = 1 +fan_below_layer_time = 10 +filament_colour = #FFFFD7 +filament_soluble = 1 +filament_type = HIPS +first_layer_temperature = 230 +max_fan_speed = 20 +min_fan_speed = 20 +start_filament_gcode = "M900 K0.2 ; Filament gcode" +temperature = 230 + +[filament:ColorFabb HT MINI] +inherits = *PETMINI* +alias = ColorFabb HT +filament_vendor = ColorFabb +bed_temperature = 100 +bridge_fan_speed = 30 +cooling = 1 +disable_fan_first_layers = 3 +fan_always_on = 0 +fan_below_layer_time = 10 +filament_cost = 58.66 +filament_density = 1.18 +first_layer_bed_temperature = 100 +first_layer_temperature = 270 +max_fan_speed = 20 +min_fan_speed = 10 +start_filament_gcode = "M900 K0.2 ; Filament gcode" +temperature = 270 + +[filament:ColorFabb XT MINI] +inherits = *PETMINI* +alias = ColorFabb XT +filament_vendor = ColorFabb +filament_type = PETG +filament_cost = 62.9 +filament_density = 1.27 +first_layer_bed_temperature = 90 +first_layer_temperature = 260 +temperature = 270 + +[filament:ColorFabb XT-CF20 MINI] +inherits = *PETMINI* +alias = ColorFabb XT-CF20 +filament_vendor = ColorFabb +compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_model=="MINI" +extrusion_multiplier = 1.2 +filament_cost = 80.65 +filament_density = 1.35 +filament_colour = #804040 +filament_max_volumetric_speed = 1 +first_layer_bed_temperature = 90 +first_layer_temperature = 260 +start_filament_gcode = "M900 K0.2 ; Filament gcode" +temperature = 260 + +[filament:Taulman T-Glase MINI] +inherits = *PETMINI* +alias = Taulman T-Glase +filament_vendor = Taulman +filament_cost = 40 +filament_density = 1.27 +bridge_fan_speed = 40 +cooling = 0 +fan_always_on = 0 +first_layer_bed_temperature = 90 +first_layer_temperature = 240 +max_fan_speed = 5 +min_fan_speed = 0 +start_filament_gcode = "M900 K0.2 ; Filament gcode" + +[filament:E3D Edge MINI] +inherits = *PETMINI* +alias = E3D Edge +filament_vendor = E3D +filament_cost = 56.9 +filament_density = 1.26 +filament_type = EDGE + +[filament:Prusa PET MINI] +inherits = *PETMINI* +alias = Prusa PET +filament_vendor = Prusa +filament_cost = 27.82 +filament_density = 1.27 + [sla_print:*common*] compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_SL1.*/ layer_height = 0.05 @@ -1921,7 +2458,7 @@ support_head_front_diameter = 0.5 support_head_penetration = 0.5 support_pillar_diameter = 1.3 -########### Materials 0.025 +########### Materials [sla_material:*common 0.05*] compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_SL1.*/ @@ -1955,209 +2492,421 @@ initial_layer_height = 0.1 ########### Materials 0.025 +[sla_material:3DM-ABS 0.025] +inherits = *common 0.025* +exposure_time = 12 +initial_exposure_time = 35 +material_type = Tough +material_vendor = 3DM + +[sla_material:3DM-Vulcan Gold 0.025] +inherits = *common 0.025* +exposure_time = 12 +initial_exposure_time = 30 +material_type = Tough +material_vendor = 3DM + [sla_material:BlueCast Phrozen Wax 0.025] inherits = *common 0.025* exposure_time = 15 initial_exposure_time = 50 +material_type = Tough +material_vendor = BlueCast [sla_material:BlueCast EcoGray 0.025] inherits = *common 0.025* exposure_time = 6 initial_exposure_time = 40 +material_type = Tough +material_vendor = BlueCast -[sla_material:BlueCast Keramaster Dental 0.025] -material_type = Dental +[sla_material:BlueCast Kera Master Dental 0.025] inherits = *common 0.025* exposure_time = 6 initial_exposure_time = 45 -material_vendor = Bluecast +material_type = Dental +material_vendor = BlueCast [sla_material:BlueCast X10 0.025] inherits = *common 0.025* exposure_time = 4 initial_exposure_time = 100 +material_type = Tough +material_vendor = BlueCast +[sla_material:Esun Bio-Photopolymer Resin White 0.025] +inherits = *common 0.025* +exposure_time = 5 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Esun + +[sla_material:Esun Standard Resin Black 0.025] +inherits = *common 0.025* +exposure_time = 6 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Esun + +[sla_material:Photocentric Ash Grey 0.025] +inherits = *common 0.025* +exposure_time = 9 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Photocentric + +[sla_material:Resinworks 3D Violet 0.025] +inherits = *common 0.025* +exposure_time = 15 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Resinworks 3D + +[sla_material:Resinworks 3D Green 0.025] +inherits = *common 0.025* +exposure_time = 17 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Resinworks 3D + +## Prusa [sla_material:Prusa Orange Tough 0.025] inherits = *common 0.025* exposure_time = 6 initial_exposure_time = 35 +material_type = Tough material_vendor = Prusa [sla_material:Prusa Grey Tough 0.025] inherits = *common 0.025* exposure_time = 7 initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa Azure Blue Tough 0.025] inherits = *common 0.025* exposure_time = 7 initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa + [sla_material:Prusa Maroon Tough 0.025] inherits = *common 0.025* exposure_time = 6 initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa Beige Tough 0.025] inherits = *common 0.025* exposure_time = 6 initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa Pink Tough 0.025] inherits = *common 0.025* exposure_time = 7 initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa White Tough 0.025] inherits = *common 0.025* exposure_time = 6.5 initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa Transparent Tough 0.025] inherits = *common 0.025* exposure_time = 6 initial_exposure_time = 15 +material_type = Tough +material_vendor = Prusa -[sla_material:Prusa Green Casting 0.025] +[sla_material:Prusa Green Dental Casting 0.025] inherits = *common 0.025* exposure_time = 12 -initial_exposure_time = 35 +initial_exposure_time = 40 +material_type = Casting +material_vendor = Prusa -## [sla_material:Prusa Transparent Green Tough 0.025] +[sla_material:Prusa Transparent Green Tough 0.025] +inherits = *common 0.025* +exposure_time = 5 +initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa + +[sla_material:Prusa Clear ABS like 0.025] +inherits = *common 0.025* +exposure_time = 6 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Prusa + +## [sla_material:Prusa ABS like White 0.025] ## inherits = *common 0.025* -## exposure_time = 5 -## initial_exposure_time = 35 +## exposure_time = 6 +## initial_exposure_time = 30 + +[sla_material:Prusa Grey High Tenacity 0.025] +inherits = *common 0.025* +exposure_time = 5 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Prusa + +[sla_material:Prusa Cyan Super Low Odor 0.025] +inherits = *common 0.025* +exposure_time = 5 +initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa + +[sla_material:Prusa Magenta Super Low Odor 0.025] +inherits = *common 0.025* +exposure_time = 5 +initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa + +[sla_material:Prusa Yellow Super Low Odor 0.025] +inherits = *common 0.025* +exposure_time = 5 +initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa + +[sla_material:Prusa Orange-Yellow Teeth Model 0.025] +inherits = *common 0.025* +exposure_time = 5 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Prusa + ########### Materials 0.05 +[sla_material:Asiga Denta Model 0.05] +inherits = *common 0.05* +exposure_time = 15 +initial_exposure_time = 30 +material_type = Dental +material_vendor = Asiga + +[sla_material:Ameralabs AMD 3 LED 0.05] +inherits = *common 0.05* +exposure_time = 5 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Ameralabs + [sla_material:BlueCast EcoGray 0.05] inherits = *common 0.05* exposure_time = 7 initial_exposure_time = 35 -material_vendor = Bluecast +material_type = Tough +material_vendor = BlueCast -[sla_material:BlueCast Keramaster 0.05] -inherits = *common 0.05* -exposure_time = 8 -initial_exposure_time = 45 -material_vendor = Bluecast - -[sla_material:BlueCast Keramaster Dental 0.05] -material_type = Dental +[sla_material:BlueCast Kera Master Dental 0.05] inherits = *common 0.05* exposure_time = 7 initial_exposure_time = 50 -material_vendor = Bluecast +material_type = Dental +material_vendor = BlueCast [sla_material:BlueCast LCD-DLP Original 0.05] inherits = *common 0.05* exposure_time = 10 initial_exposure_time = 60 -material_vendor = Bluecast +material_type = Tough +material_vendor = BlueCast [sla_material:BlueCast Phrozen Wax 0.05] inherits = *common 0.05* exposure_time = 16 initial_exposure_time = 50 -material_vendor = Bluecast +material_type = Tough +material_vendor = BlueCast [sla_material:BlueCast S+ 0.05] inherits = *common 0.05* exposure_time = 9 initial_exposure_time = 45 -material_vendor = Bluecast +material_type = Tough +material_vendor = BlueCast + +[sla_material:BlueCast X5 0.05] +inherits = *common 0.05* +exposure_time = 9 +initial_exposure_time = 100 +material_type = Tough +material_vendor = BlueCast [sla_material:BlueCast X10 0.05] inherits = *common 0.05* exposure_time = 6 initial_exposure_time = 100 +material_type = Tough +material_vendor = BlueCast + +[sla_material:BlueCast 23LS 0.05] +inherits = *common 0.05* +exposure_time = 8 +initial_exposure_time = 50 +material_type = Tough +material_vendor = BlueCast [sla_material:Monocure 3D Black Rapid Resin 0.05] inherits = *common 0.05* exposure_time = 6 initial_exposure_time = 40 +material_type = Tough material_vendor = Monocure [sla_material:Monocure 3D Blue Rapid Resin 0.05] inherits = *common 0.05* exposure_time = 7 initial_exposure_time = 40 +material_type = Tough material_vendor = Monocure [sla_material:Monocure 3D Clear Rapid Resin 0.05] inherits = *common 0.05* exposure_time = 8 initial_exposure_time = 40 +material_type = Tough material_vendor = Monocure [sla_material:Monocure 3D Grey Rapid Resin 0.05] inherits = *common 0.05* exposure_time = 10 initial_exposure_time = 30 +material_type = Tough material_vendor = Monocure [sla_material:Monocure 3D White Rapid Resin 0.05] inherits = *common 0.05* exposure_time = 7 initial_exposure_time = 40 +material_type = Tough material_vendor = Monocure [sla_material:3DM-HTR140 (high temperature) 0.05] inherits = *common 0.05* exposure_time = 12 initial_exposure_time = 45 +material_type = Tough +material_vendor = Monocure + +[sla_material:Esun Bio-Photopolymer Resin White 0.05] +inherits = *common 0.05* +exposure_time = 8 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Esun + +[sla_material:Esun Standard Resin Black 0.05] +inherits = *common 0.05* +exposure_time = 7 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Esun [sla_material:3DM-ABS 0.05] inherits = *common 0.05* exposure_time = 13 initial_exposure_time = 25 +material_type = Tough +material_vendor = 3DM [sla_material:3DM-BLACK 0.05] inherits = *common 0.05* exposure_time = 20 initial_exposure_time = 40 +material_type = Tough material_vendor = 3DM [sla_material:3DM-DENT 0.05] inherits = *common 0.05* exposure_time = 7 initial_exposure_time = 45 +material_type = Dental material_vendor = 3DM [sla_material:3DM-HR Green 0.05] inherits = *common 0.05* exposure_time = 15 initial_exposure_time = 40 +material_type = Tough material_vendor = 3DM [sla_material:3DM-HR Red Wine 0.05] inherits = *common 0.05* exposure_time = 9 initial_exposure_time = 35 +material_type = Tough material_vendor = 3DM [sla_material:3DM-XPRO White 0.05] inherits = *common 0.05* exposure_time = 9 initial_exposure_time = 35 +material_type = Tough +material_vendor = 3DM + +[sla_material:3DM-Vulcan Gold 0.05] +inherits = *common 0.05* +exposure_time = 15 +initial_exposure_time = 30 +material_type = Tough material_vendor = 3DM [sla_material:FTD Ash Grey 0.05] inherits = *common 0.05* exposure_time = 9 initial_exposure_time = 40 +material_type = Tough material_vendor = FTD [sla_material:Harz Labs Model Resin Cherry 0.05] inherits = *common 0.05* exposure_time = 8 initial_exposure_time = 45 +material_type = Tough material_vendor = Harz Labs +[sla_material:Resinworks 3D Violet 0.05] +inherits = *common 0.05* +exposure_time = 17 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Resinworks 3D + +[sla_material:Resinworks 3D Green 0.05] +inherits = *common 0.05* +exposure_time = 21 +initial_exposure_time = 35 +material_type = Tough +material_vendor = Resinworks 3D + [sla_material:Photocentric Hard Grey 0.05] inherits = *common 0.05* exposure_time = 15 initial_exposure_time = 30 +material_type = Tough +material_vendor = Photocentric + +[sla_material:Photocentric Ash Grey 0.05] +inherits = *common 0.05* +exposure_time = 10 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Photocentric ## Prusa @@ -2165,46 +2914,91 @@ initial_exposure_time = 30 inherits = *common 0.05* exposure_time = 7 initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa Orange Tough 0.05] inherits = *common 0.05* exposure_time = 7.5 initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa Grey Tough 0.05] inherits = *common 0.05* exposure_time = 8.5 initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa Black Tough 0.05] inherits = *common 0.05* exposure_time = 6 initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa ## [sla_material:Prusa Beige Super Low Odor 0.05] ## inherits = *common 0.05* ## exposure_time = 7.5 ## initial_exposure_time = 35 +## material_type = Tough +## material_vendor = Prusa ## [sla_material:Prusa White Super Low Odor 0.05] ## inherits = *common 0.05* ## exposure_time = 6.5 ## initial_exposure_time = 35 +## material_type = Tough +## material_vendor = Prusa ## [sla_material:Prusa Grey Super Low Odor 0.05] ## inherits = *common 0.05* ## exposure_time = 6.5 ## initial_exposure_time = 35 +## material_type = Tough +## material_vendor = Prusa + +[sla_material:Prusa Cyan Super Low Odor 0.05] +inherits = *common 0.05* +exposure_time = 6 +initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa + +[sla_material:Prusa Magenta Super Low Odor 0.05] +inherits = *common 0.05* +exposure_time = 6 +initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa + +[sla_material:Prusa Yellow Super Low Odor 0.05] +inherits = *common 0.05* +exposure_time = 6 +initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa ## [sla_material:Prusa Black High Tenacity 0.05] ## inherits = *common 0.05* ## exposure_time = 7 ## initial_exposure_time = 35 +## material_type = Tough +## material_vendor = Prusa -[sla_material:Prusa Green Casting 0.05] +[sla_material:Prusa Orange-Yellow Teeth Model 0.05] +inherits = *common 0.05* +exposure_time = 7 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Prusa + +[sla_material:Prusa Green Dental Casting 0.05] inherits = *common 0.05* exposure_time = 13 -initial_exposure_time = 40 +initial_exposure_time = 50 +material_type = Casting material_vendor = Prusa ## [sla_material:Prusa Yellow Solid 0.05] @@ -2216,61 +3010,74 @@ material_vendor = Prusa inherits = *common 0.05* exposure_time = 7.5 initial_exposure_time = 35 +material_type = Tough material_vendor = Prusa -## [sla_material:Prusa Transparent Green Tough 0.05] -## inherits = *common 0.05* -## exposure_time = 6 -## initial_exposure_time = 35 +[sla_material:Prusa Transparent Green Tough 0.05] +inherits = *common 0.05* +exposure_time = 6 +initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa Transparent Red Tough 0.05] inherits = *common 0.05* exposure_time = 6 initial_exposure_time = 35 +material_type = Tough material_vendor = Prusa [sla_material:Prusa Maroon Tough 0.05] inherits = *common 0.05* exposure_time = 7.5 initial_exposure_time = 35 +material_type = Tough material_vendor = Prusa [sla_material:Prusa Pink Tough 0.05] inherits = *common 0.05* exposure_time = 8 initial_exposure_time = 35 +material_type = Tough material_vendor = Prusa [sla_material:Prusa Azure Blue Tough 0.05] inherits = *common 0.05* exposure_time = 8 initial_exposure_time = 35 +material_type = Tough material_vendor = Prusa [sla_material:Prusa Transparent Tough 0.05] inherits = *common 0.05* exposure_time = 7 initial_exposure_time = 15 +material_type = Tough +material_vendor = Prusa ## [sla_material:Prusa Yellow Flexible 0.05] ## inherits = *common 0.05* ## exposure_time = 9 ## initial_exposure_time = 35 -## [sla_material:Prusa Clear Flexible 0.05] -## inherits = *common 0.05* -## exposure_time = 5 -## initial_exposure_time = 15 +[sla_material:Prusa Clear Flexible 0.05] +inherits = *common 0.05* +exposure_time = 5 +initial_exposure_time = 15 +material_type = Flexible +material_vendor = Prusa ## [sla_material:Prusa White Flexible 0.05] ## inherits = *common 0.05* ## exposure_time = 9 ## initial_exposure_time = 35 -## [sla_material:Prusa Blue Flexible 0.05] -## inherits = *common 0.05* -## exposure_time = 9 -## initial_exposure_time = 35 +[sla_material:Prusa Blue Flexible 0.05] +inherits = *common 0.05* +exposure_time = 5 +initial_exposure_time = 15 +material_type = Flexible +material_vendor = Prusa ## [sla_material:Prusa Black Flexible 0.05] ## inherits = *common 0.05* @@ -2282,61 +3089,128 @@ initial_exposure_time = 15 ## exposure_time = 9 ## initial_exposure_time = 35 +[sla_material:Prusa Clear ABS like 0.05] +inherits = *common 0.05* +exposure_time = 8 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Prusa + +## [sla_material:Prusa ABS like White 0.05] +## inherits = *common 0.05* +## exposure_time = 8 +## initial_exposure_time = 30 + +[sla_material:Prusa Yellow Jewelry Casting 0.05] +inherits = *common 0.05* +exposure_time = 13 +initial_exposure_time = 45 +material_type = Casting +material_vendor = Prusa + +[sla_material:Prusa Grey High Tenacity 0.05] +inherits = *common 0.05* +exposure_time = 7 +initial_exposure_time = 30 +material_type = Tough +material_vendor = Prusa + ########### Materials 0.035 [sla_material:Prusa Orange Tough 0.035] inherits = *common 0.035* exposure_time = 6 initial_exposure_time = 35 +material_type = Tough material_vendor = Prusa ########### Materials 0.1 +[sla_material:BlueCast EcoGray 0.1] +inherits = *common 0.1* +exposure_time = 10 +initial_exposure_time = 35 +material_type = Tough +material_vendor = BlueCast + +[sla_material:BlueCast Kera Master Dental 0.1] +inherits = *common 0.1* +exposure_time = 13 +initial_exposure_time = 50 +material_type = Tough +material_vendor = BlueCast + +## Prusa + [sla_material:Prusa Orange Tough 0.1] inherits = *common 0.1* exposure_time = 13 initial_exposure_time = 45 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa Beige Tough 0.1] inherits = *common 0.1* exposure_time = 13 initial_exposure_time = 45 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa Pink Tough 0.1] inherits = *common 0.1* exposure_time = 13 initial_exposure_time = 45 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa Azure Blue Tough 0.1] inherits = *common 0.1* exposure_time = 13 initial_exposure_time = 45 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa Maroon Tough 0.1] inherits = *common 0.1* exposure_time = 13 initial_exposure_time = 45 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa White Tough 0.1] inherits = *common 0.1* exposure_time = 13 initial_exposure_time = 45 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa Black Tough 0.1] inherits = *common 0.1* exposure_time = 13 initial_exposure_time = 55 +material_type = Tough +material_vendor = Prusa [sla_material:Prusa Transparent Tough 0.1] inherits = *common 0.1* exposure_time = 8 initial_exposure_time = 35 +material_type = Tough material_vendor = Prusa -[sla_material:Prusa Green Casting 0.1] +[sla_material:Prusa Green Dental Casting 0.1] inherits = *common 0.1* exposure_time = 15 initial_exposure_time = 50 +material_type = Casting +material_vendor = Prusa + +[sla_material:Prusa Transparent Green Tough 0.1] +inherits = *common 0.1* +exposure_time = 7 +initial_exposure_time = 35 +material_type = Tough +material_vendor = Prusa [printer:*common*] printer_technology = FFF @@ -2454,6 +3328,7 @@ retract_length = 1 retract_speed = 50 variable_layer_height = 1 printer_variant = 0.25 +retract_lift = 0.15 default_print_profile = 0.10mm DETAIL 0.25 nozzle [printer:Original Prusa i3 MK2S 0.6 nozzle] @@ -2503,19 +3378,19 @@ min_layer_height = 0.1 inherits = Original Prusa i3 MK2S printer_model = MK2.5 remaining_times = 1 -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5 0.25 nozzle] inherits = Original Prusa i3 MK2S 0.25 nozzle printer_model = MK2.5 remaining_times = 1 -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5 0.6 nozzle] inherits = Original Prusa i3 MK2S 0.6 nozzle printer_model = MK2.5 remaining_times = 1 -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5 MMU2 Single] inherits = Original Prusa i3 MK2.5; *mm2* @@ -2544,7 +3419,7 @@ machine_min_travel_rate = 0 default_print_profile = 0.15mm OPTIMAL MK2.5 default_filament_profile = Prusament PLA printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2.5\n -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\n; select extruder\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; load to nozzle\nTc\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\n; select extruder\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; load to nozzle\nTc\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors [printer:Original Prusa i3 MK2.5 MMU2 Single 0.6 nozzle] @@ -2586,23 +3461,23 @@ single_extruder_multi_material = 1 # to be defined explicitely. nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors\n [printer:Original Prusa i3 MK2.5S] inherits = Original Prusa i3 MK2.5 printer_model = MK2.5S -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5S 0.25 nozzle] inherits = Original Prusa i3 MK2.5 0.25 nozzle printer_model = MK2.5S -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5S 0.6 nozzle] inherits = Original Prusa i3 MK2.5 0.6 nozzle printer_model = MK2.5S -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5S MMU2S Single] inherits = Original Prusa i3 MK2.5; *mm2s* @@ -2631,7 +3506,7 @@ machine_min_travel_rate = 0 default_print_profile = 0.15mm OPTIMAL MK2.5 default_filament_profile = Prusament PLA printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2.5\n -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors [printer:Original Prusa i3 MK2.5S MMU2S Single 0.6 nozzle] @@ -2650,8 +3525,9 @@ max_layer_height = 0.15 min_layer_height = 0.05 nozzle_diameter = 0.25 printer_variant = 0.25 +retract_lift = 0.15 default_print_profile = 0.10mm DETAIL 0.25 nozzle -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F1400.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F1400.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n [printer:Original Prusa i3 MK2.5S MMU2S] inherits = Original Prusa i3 MK2.5; *mm2s* @@ -2684,7 +3560,7 @@ single_extruder_multi_material = 1 # to be defined explicitely. nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors\n [printer:Original Prusa i3 MK2.5S MMU2S 0.6 nozzle] @@ -2731,7 +3607,7 @@ remaining_times = 1 printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n retract_lift_below = 209 max_print_height = 210 -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} printer_model = MK3 default_print_profile = 0.15mm QUALITY MK3 @@ -2741,7 +3617,8 @@ nozzle_diameter = 0.25 max_layer_height = 0.15 min_layer_height = 0.05 printer_variant = 0.25 -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E8.0 F700.0 ; intro line\nG1 X100.0 E12.5 F700.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} +retract_lift = 0.15 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E8.0 F700.0 ; intro line\nG1 X100.0 E12.5 F700.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} default_print_profile = 0.10mm DETAIL 0.25 nozzle MK3 [printer:Original Prusa i3 MK3 0.6 nozzle] @@ -2755,17 +3632,17 @@ default_print_profile = 0.30mm QUALITY 0.6 nozzle MK3 [printer:Original Prusa i3 MK3S] inherits = Original Prusa i3 MK3 printer_model = MK3S -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} [printer:Original Prusa i3 MK3S 0.25 nozzle] inherits = Original Prusa i3 MK3 0.25 nozzle printer_model = MK3S -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E8.0 F700.0 ; intro line\nG1 X100.0 E12.5 F700.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E8.0 F700.0 ; intro line\nG1 X100.0 E12.5 F700.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} [printer:Original Prusa i3 MK3S 0.6 nozzle] inherits = Original Prusa i3 MK3 0.6 nozzle printer_model = MK3S -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} [printer:*mm2*] inherits = Original Prusa i3 MK3 @@ -2795,7 +3672,7 @@ default_filament_profile = Prusament PLA MMU2 inherits = *mm2* single_extruder_multi_material = 0 default_filament_profile = Prusament PLA -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors [printer:Original Prusa i3 MK3 MMU2 Single 0.6 nozzle] @@ -2814,7 +3691,8 @@ nozzle_diameter = 0.25 max_layer_height = 0.15 min_layer_height = 0.05 printer_variant = 0.25 -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 E8.0 F1000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F1400.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n +retract_lift = 0.15 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 E8.0 F1000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F1400.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n default_print_profile = 0.10mm DETAIL 0.25 nozzle MK3 [printer:Original Prusa i3 MK3 MMU2] @@ -2825,14 +3703,14 @@ inherits = *mm2* machine_max_acceleration_e = 8000,8000 nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors\n [printer:Original Prusa i3 MK3S MMU2S Single] inherits = *mm2s* single_extruder_multi_material = 0 default_filament_profile = Prusament PLA -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors [printer:Original Prusa i3 MK3S MMU2S Single 0.6 nozzle] @@ -2851,7 +3729,8 @@ nozzle_diameter = 0.25 max_layer_height = 0.15 min_layer_height = 0.05 printer_variant = 0.25 -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F1400.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n +retract_lift = 0.15 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F1400.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n default_print_profile = 0.10mm DETAIL 0.25 nozzle MK3 [printer:Original Prusa i3 MK3S MMU2S] @@ -2859,7 +3738,7 @@ inherits = *mm2s* machine_max_acceleration_e = 8000,8000 nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F -start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.8.1 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors\n ## 0.6mm nozzle MMU2/S printer profiles @@ -2880,6 +3759,68 @@ min_layer_height = 0.15 printer_variant = 0.6 default_print_profile = 0.30mm QUALITY 0.6 nozzle MK3 +## MINI + +[printer:Original Prusa MINI] +inherits = *common* +printer_model = MINI +printer_technology = FFF +printer_variant = 0.4 +printer_vendor = +bed_shape = 0x0,180x0,180x180,0x180 +default_filament_profile = "Prusament PLA MINI" +default_print_profile = 0.15mm QUALITY MINI +gcode_flavor = marlin +machine_max_acceleration_e = 5000 +machine_max_acceleration_extruding = 1250 +machine_max_acceleration_retracting = 1250 +machine_max_acceleration_x = 1250 +machine_max_acceleration_y = 1250 +machine_max_acceleration_z = 400 +machine_max_feedrate_e = 80 +machine_max_feedrate_x = 180 +machine_max_feedrate_y = 180 +machine_max_feedrate_z = 12 +machine_max_jerk_e = 10 +machine_max_jerk_x = 8 +machine_max_jerk_y = 8 +machine_max_jerk_z = 2 +machine_min_extruding_rate = 0 +machine_min_travel_rate = 0 +max_layer_height = 0.25 +max_print_height = 180 +min_layer_height = 0.07 +nozzle_diameter = 0.4 +retract_length = 3.2 +retract_lift = 0.2 +retract_speed = 70 +deretract_speed = 40 +wipe = 1 +retract_before_wipe = 70% +retract_before_travel = 1.5 +retract_lift_above = 0 +retract_lift_below = 179 +retract_layer_change = 0 +silent_mode = 0 +remaining_times = 1 +start_gcode = M569 S0 E \nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM92 E317 ; set steps/unit for extruder\nM104 S170 ; set extruder temp for bed leveling\nM140 S[first_layer_bed_temperature] ; set bed temp\nM109 R170 ; wait for bed leveling temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG28 ; home all without mesh bed level\nG29 ; mesh bed leveling \nM104 S[first_layer_temperature] ; set extruder temp\nG92 E0.0\nG1 Y-2.0 X179 F2400\nG1 Z3 F720\nM109 S[first_layer_temperature] ; wait for extruder temp\n\n; intro line\nG1 X170 F1000\nG1 Z0.2 F720\nG1 X110.0 E8.0 F900\nG1 X40.0 E10.0 F700\nG92 E0.0\n\nM221 S95 ; set flow +end_gcode = G1 E-1 F2100 ; retract\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+5, max_print_height)}{endif} F720 ; Move print head up\nG1 X0 Y180 F4200 ; park print head\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM221 S100 ; reset flow\nM84 ; disable motors +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MINI\n +extruder_colour = + +[printer:Original Prusa MINI 0.25 nozzle] +inherits = Original Prusa MINI +printer_variant = 0.25 +nozzle_diameter = 0.25 +retract_length = 3 +retract_lift = 0.15 +retract_speed = 70 +deretract_speed = 40 +wipe = 1 +retract_before_wipe = 70% +retract_before_travel = 1 +start_gcode = M569 S0 E \nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM92 E317 ; set steps/unit for extruder\nM104 S170 ; set extruder temp for bed leveling\nM140 S[first_layer_bed_temperature] ; set bed temp\nM109 R170 ; wait for bed leveling temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG28 ; home all without mesh bed level\nG29 ; mesh bed leveling \nM104 S[first_layer_temperature] ; set extruder temp\nG92 E0.0\nG1 Y-2.0 X179 F2400\nG1 Z3 F720\nM109 S[first_layer_temperature] ; wait for extruder temp\n\n; intro line\nG1 X170 F1000\nG1 Z0.2 F720\nG1 X110.0 E8.0 F600\nG1 X40.0 E10.0 F400\nG92 E0.0\n\nM221 S95 ; set flow + [printer:Original Prusa SL1] printer_technology = SLA printer_model = SL1 From 2dec84a429326b9a95f3c572bae263c6dbe7b72f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 15 Nov 2019 09:28:51 +0100 Subject: [PATCH 69/80] Added model and texture for Mini and Ender3 printer printbeds --- resources/icons/bed/ender3.svg | 47 +++++++++++++++++++++ resources/icons/bed/mini.svg | 70 ++++++++++++++++++++++++++++++++ resources/models/ender3_bed.stl | Bin 0 -> 50484 bytes resources/models/mini_bed.stl | Bin 0 -> 648084 bytes src/slic3r/GUI/3DBed.cpp | 66 +++++++++++++++--------------- src/slic3r/GUI/3DBed.hpp | 2 + 6 files changed, 153 insertions(+), 32 deletions(-) create mode 100644 resources/icons/bed/ender3.svg create mode 100644 resources/icons/bed/mini.svg create mode 100644 resources/models/ender3_bed.stl create mode 100644 resources/models/mini_bed.stl diff --git a/resources/icons/bed/ender3.svg b/resources/icons/bed/ender3.svg new file mode 100644 index 000000000..06910afdf --- /dev/null +++ b/resources/icons/bed/ender3.svg @@ -0,0 +1,47 @@ + + ender3_bed_texture + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/bed/mini.svg b/resources/icons/bed/mini.svg new file mode 100644 index 000000000..93c3437bd --- /dev/null +++ b/resources/icons/bed/mini.svg @@ -0,0 +1,70 @@ + + MINI_bed_texture + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/models/ender3_bed.stl b/resources/models/ender3_bed.stl new file mode 100644 index 0000000000000000000000000000000000000000..fb8f86d094e6cc1adf87808aefa292fb217000ea GIT binary patch literal 50484 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ⅆ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 literal 0 HcmV?d00001 diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 82b512270..d0bab50c6 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -272,27 +272,13 @@ void Bed3D::render(GLCanvas3D& canvas, float theta, float scale_factor) const switch (m_type) { - case MK2: - { - render_prusa(canvas, "mk2", theta > 90.0f); - break; - } - case MK3: - { - render_prusa(canvas, "mk3", theta > 90.0f); - break; - } - case SL1: - { - render_prusa(canvas, "sl1", theta > 90.0f); - break; - } + case MK2: { render_prusa(canvas, "mk2", theta > 90.0f); break; } + case MK3: { render_prusa(canvas, "mk3", theta > 90.0f); break; } + case SL1: { render_prusa(canvas, "sl1", theta > 90.0f); break; } + case MINI: { render_prusa(canvas, "mini", theta > 90.0f); break; } + case ENDER3: { render_prusa(canvas, "ender3", theta > 90.0f); break; } default: - case Custom: - { - render_custom(canvas, theta > 90.0f); - break; - } + case Custom: { render_custom(canvas, theta > 90.0f); break; } } } @@ -364,22 +350,38 @@ Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const { if (curr->config.has("bed_shape")) { - if ((curr->vendor != nullptr) && (curr->vendor->name == "Prusa Research") && (shape == dynamic_cast(curr->config.option("bed_shape"))->values)) + if (curr->vendor != nullptr) { - if (boost::contains(curr->name, "SL1")) + if ((curr->vendor->name == "Prusa Research") && (shape == dynamic_cast(curr->config.option("bed_shape"))->values)) { - type = SL1; - break; + if (boost::contains(curr->name, "SL1")) + { + type = SL1; + break; + } + else if (boost::contains(curr->name, "MK3") || boost::contains(curr->name, "MK2.5")) + { + type = MK3; + break; + } + else if (boost::contains(curr->name, "MK2")) + { + type = MK2; + break; + } + else if (boost::contains(curr->name, "MINI")) + { + type = MINI; + break; + } } - else if (boost::contains(curr->name, "MK3") || boost::contains(curr->name, "MK2.5")) + else if ((curr->vendor->name == "Creality") && (shape == dynamic_cast(curr->config.option("bed_shape"))->values)) { - type = MK3; - break; - } - else if (boost::contains(curr->name, "MK2")) - { - type = MK2; - break; + if (boost::contains(curr->name, "ENDER-3")) + { + type = ENDER3; + break; + } } } } diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index c9a30e6ec..132836711 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -67,6 +67,8 @@ public: MK2, MK3, SL1, + MINI, + ENDER3, Custom, Num_Types }; From 32d794756ee2e7d43bafd07180e3e6f05e000265 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 15 Nov 2019 10:05:56 +0100 Subject: [PATCH 70/80] Lighter model for mini printer printbed --- resources/models/mini_bed.stl | Bin 648084 -> 57884 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resources/models/mini_bed.stl b/resources/models/mini_bed.stl index a189f851fb8189fc313fc71470ae4108009d113d..2f4c45b7b150b7883c038f2104c53e8aa35fe812 100644 GIT binary patch literal 57884 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ⅆ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 From ac628c8069779ce029529ef037eb1c4a7e5f0770 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 15 Nov 2019 11:53:16 +0100 Subject: [PATCH 71/80] New texture for mini printer printbed --- resources/icons/bed/mini.svg | 145 ++++++++++++++++++++++------------- 1 file changed, 92 insertions(+), 53 deletions(-) diff --git a/resources/icons/bed/mini.svg b/resources/icons/bed/mini.svg index 93c3437bd..1b9476ef8 100644 --- a/resources/icons/bed/mini.svg +++ b/resources/icons/bed/mini.svg @@ -1,70 +1,109 @@ - - MINI_bed_texture - - - - - - - - - - + + bed_texture_denser + + + + + + + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From fe4b65e3056f078eaffb524cf5632f299242508d Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 15 Nov 2019 16:20:01 +0100 Subject: [PATCH 72/80] Improvement of the Elephant foot compensation: Using a positive curvature estimate to control the strength of the Elephant foot compensation shall work similarly to the previous implementation while avoiding pinching off tiny pieces from the contour. --- src/libslic3r/EdgeGrid.hpp | 19 ++ src/libslic3r/ElephantFootCompensation.cpp | 248 +++++++++++++++--- src/libslic3r/Utils.hpp | 59 +++++ .../test_elephant_foot_compensation.cpp | 209 +++++++++++++++ 4 files changed, 497 insertions(+), 38 deletions(-) diff --git a/src/libslic3r/EdgeGrid.hpp b/src/libslic3r/EdgeGrid.hpp index 1a51f3439..81517a5c4 100644 --- a/src/libslic3r/EdgeGrid.hpp +++ b/src/libslic3r/EdgeGrid.hpp @@ -209,6 +209,25 @@ public: } } + template void visit_cells_intersecting_box(BoundingBox bbox, VISITOR &visitor) const + { + // End points of the line segment. + bbox.min -= m_bbox.min; + bbox.max -= m_bbox.min + Point(1, 1); + // Get the cells of the end points. + bbox.min /= m_resolution; + bbox.max /= m_resolution; + // Trim with the cells. + bbox.min.x() = std::max(bbox.min.x(), 0); + bbox.min.y() = std::max(bbox.min.y(), 0); + bbox.max.x() = std::min(bbox.max.x(), (coord_t)m_cols - 1); + bbox.max.y() = std::min(bbox.max.y(), (coord_t)m_rows - 1); + for (coord_t iy = bbox.min.y(); iy <= bbox.max.y(); ++ iy) + for (coord_t ix = bbox.min.x(); ix <= bbox.max.x(); ++ ix) + if (! visitor(iy, ix)) + return; + } + std::pair>::const_iterator, std::vector>::const_iterator> cell_data_range(coord_t row, coord_t col) const { const EdgeGrid::Grid::Cell &cell = m_cells[row * m_cols + col]; diff --git a/src/libslic3r/ElephantFootCompensation.cpp b/src/libslic3r/ElephantFootCompensation.cpp index 828064c32..69a20b5ec 100644 --- a/src/libslic3r/ElephantFootCompensation.cpp +++ b/src/libslic3r/ElephantFootCompensation.cpp @@ -8,6 +8,7 @@ #include "Flow.hpp" #include "Geometry.hpp" #include "SVG.hpp" +#include "Utils.hpp" #include #include @@ -26,6 +27,10 @@ struct ResampledPoint { double curve_parameter; }; +// Distance calculated using SDF (Shape Diameter Function). +// The distance is calculated by casting a fan of rays and measuring the intersection distance. +// Thus the calculation is relatively slow. For the Elephant foot compensation purpose, this distance metric does not avoid +// pinching off small pieces of a contour, thus this function has been superseded by contour_distance2(). std::vector contour_distance(const EdgeGrid::Grid &grid, const size_t idx_contour, const Slic3r::Points &contour, const std::vector &resampled_point_parameters, double search_radius) { assert(! contour.empty()); @@ -167,7 +172,7 @@ std::vector contour_distance(const EdgeGrid::Grid &grid, const size_t idx SVG svg(debug_out_path("contour_distance_raycasted-%d-%d.svg", iRun, &pt_next - contour.data()).c_str(), bbox); svg.draw(expoly_grid); svg.draw_outline(Polygon(contour), "blue", scale_(0.01)); - svg.draw(*pt_this, "red", scale_(0.1)); + svg.draw(*pt_this, "red", coord_t(scale_(0.1))); #endif /* CONTOUR_DISTANCE_DEBUG_SVG */ for (int i = - num_rays + 1; i < num_rays; ++ i) { @@ -182,7 +187,7 @@ std::vector contour_distance(const EdgeGrid::Grid &grid, const size_t idx svg.draw(Line(visitor.pt_start, visitor.pt_end), "yellow", scale_(0.01)); if (visitor.t_min < 1.) { Vec2d pt = visitor.pt + visitor.dir * visitor.t_min; - svg.draw(Point(pt), "red", scale_(0.1)); + svg.draw(Point(pt), "red", coord_t(scale_(0.1))); } #endif /* CONTOUR_DISTANCE_DEBUG_SVG */ } @@ -209,7 +214,7 @@ std::vector contour_distance(const EdgeGrid::Grid &grid, const size_t idx out.emplace_back(float(distances.front() * search_radius)); #endif #ifdef CONTOUR_DISTANCE_DEBUG_SVG - printf("contour_distance_raycasted-%d-%d.svg - distance %lf\n", iRun, &pt_next - contour.data(), unscale(out.back())); + printf("contour_distance_raycasted-%d-%d.svg - distance %lf\n", iRun, int(&pt_next - contour.data()), unscale(out.back())); #endif /* CONTOUR_DISTANCE_DEBUG_SVG */ pt_this = &pt_next; idx_pt_this = &pt_next - contour.data(); @@ -223,6 +228,188 @@ std::vector contour_distance(const EdgeGrid::Grid &grid, const size_t idx return out; } +// Contour distance by measuring the closest point of an ExPolygon stored inside the EdgeGrid, while filtering out points of the same contour +// at concave regions, or convex regions with low curvature (curvature is estimated as a ratio between contour length and chordal distance crossing the contour ends). +std::vector contour_distance2(const EdgeGrid::Grid &grid, const size_t idx_contour, const Slic3r::Points &contour, const std::vector &resampled_point_parameters, double compensation, double search_radius) +{ + assert(! contour.empty()); + assert(contour.size() >= 2); + + std::vector out; + + if (contour.size() > 2) + { +#ifdef CONTOUR_DISTANCE_DEBUG_SVG + static int iRun = 0; + ++ iRun; + BoundingBox bbox = get_extents(contour); + bbox.merge(grid.bbox()); + ExPolygon expoly_grid; + expoly_grid.contour = Polygon(*grid.contours().front()); + for (size_t i = 1; i < grid.contours().size(); ++ i) + expoly_grid.holes.emplace_back(Polygon(*grid.contours()[i])); +#endif + struct Visitor { + Visitor(const EdgeGrid::Grid &grid, const size_t idx_contour, const std::vector &resampled_point_parameters, double dist_same_contour_accept, double dist_same_contour_reject) : + grid(grid), idx_contour(idx_contour), contour(*grid.contours()[idx_contour]), resampled_point_parameters(resampled_point_parameters), dist_same_contour_accept(dist_same_contour_accept), dist_same_contour_reject(dist_same_contour_reject) {} + + void init(const Points &contour, const Point &apoint) { + this->idx_point = &apoint - contour.data(); + this->point = apoint; + this->found = false; + this->dir_inside = this->dir_inside_at_point(contour, this->idx_point); + } + + bool operator()(coord_t iy, coord_t ix) { + // Called with a row and colum of the grid cell, which is intersected by a line. + auto cell_data_range = this->grid.cell_data_range(iy, ix); + for (auto it_contour_and_segment = cell_data_range.first; it_contour_and_segment != cell_data_range.second; ++ it_contour_and_segment) { + // End points of the line segment and their vector. + std::pair segment = this->grid.segment(*it_contour_and_segment); + const Vec2d v = (segment.second - segment.first).cast(); + const Vec2d va = (this->point - segment.first).cast(); + const double l2 = v.squaredNorm(); // avoid a sqrt + const double t = (l2 == 0.0) ? 0. : clamp(0., 1., va.dot(v) / l2); + // Closest point from this->point to the segment. + const Vec2d foot = segment.first.cast() + t * v; + const Vec2d bisector = foot - this->point.cast(); + const double dist = bisector.norm(); + if ((! this->found || dist < this->distance) && this->dir_inside.dot(bisector) > 0) { + bool accept = true; + if (it_contour_and_segment->first == idx_contour) { + // Complex case: The closest segment originates from the same contour as the starting point. + // Reject the closest point if its distance along the contour is reasonable compared to the current contour bisector (this->pt, foot). + double param_lo = resampled_point_parameters[this->idx_point].curve_parameter; + double param_hi; + double param_end = resampled_point_parameters.back().curve_parameter; + const Slic3r::Points &ipts = *grid.contours()[it_contour_and_segment->first]; + const size_t ipt = it_contour_and_segment->second; + { + ResampledPoint key(ipt, false, 0.); + auto lower = [](const ResampledPoint& l, const ResampledPoint r) { return l.idx_src < r.idx_src || (l.idx_src == r.idx_src && int(l.interpolated) > int(r.interpolated)); }; + auto it = std::lower_bound(resampled_point_parameters.begin(), resampled_point_parameters.end(), key, lower); + assert(it != resampled_point_parameters.end() && it->idx_src == ipt && ! it->interpolated); + param_hi = t * sqrt(l2); + if (ipt + 1 < ipts.size()) + param_hi += it->curve_parameter; + } + if (param_lo > param_hi) + std::swap(param_lo, param_hi); + assert(param_lo > - SCALED_EPSILON && param_lo <= param_end + SCALED_EPSILON); + assert(param_hi > - SCALED_EPSILON && param_hi <= param_end + SCALED_EPSILON); + double dist_along_contour = std::min(param_hi - param_lo, param_lo + param_end - param_hi); + if (dist_along_contour < dist_same_contour_accept) + accept = false; + else if (dist < dist_same_contour_reject + SCALED_EPSILON) { + // this->point is close to foot. This point will only be accepted if the path along the contour is significantly + // longer than the bisector. That is, the path shall not bulge away from the bisector too much. + // Bulge is estimated by 0.6 of the circle circumference drawn around the bisector. + // Test whether the contour is convex or concave. + bool inside = + (t == 0.) ? this->inside_corner(ipts, ipt, this->point) : + (t == 1.) ? this->inside_corner(ipts, ipt + 1 == ipts.size() ? 0 : ipt + 1, this->point) : + this->left_of_segment(ipts, ipt, this->point); + accept = inside && dist_along_contour > 0.6 * M_PI * dist; + } + } + if (accept && (! this->found || dist < this->distance)) { + // Simple case: Just measure the shortest distance. + this->distance = dist; +#ifdef CONTOUR_DISTANCE_DEBUG_SVG + this->closest_point = foot.cast(); +#endif /* CONTOUR_DISTANCE_DEBUG_SVG */ + this->found = true; + } + } + } + // Continue traversing the grid. + return true; + } + + const EdgeGrid::Grid &grid; + const size_t idx_contour; + const Points &contour; + const std::vector &resampled_point_parameters; + const double dist_same_contour_accept; + const double dist_same_contour_reject; + + size_t idx_point; + Point point; + // Direction inside the contour from idx_point, not normalized. + Vec2d dir_inside; + bool found; + double distance; +#ifdef CONTOUR_DISTANCE_DEBUG_SVG + Point closest_point; +#endif /* CONTOUR_DISTANCE_DEBUG_SVG */ + + private: + static Vec2d dir_inside_at_point(const Points &contour, size_t i) { + size_t iprev = prev_idx_modulo(i, contour); + size_t inext = next_idx_modulo(i, contour); + Vec2d v1 = (contour[i] - contour[iprev]).cast(); + Vec2d v2 = (contour[inext] - contour[i]).cast(); + return Vec2d(- v1.y() - v2.y(), v1.x() + v2.x()); + } + static Vec2d dir_inside_at_segment(const Points& contour, size_t i) { + size_t inext = next_idx_modulo(i, contour); + Vec2d v = (contour[inext] - contour[i]).cast(); + return Vec2d(- v.y(), v.x()); + } + + static bool inside_corner(const Slic3r::Points &contour, size_t i, const Point &pt_oposite) { + const Vec2d pt = pt_oposite.cast(); + size_t iprev = prev_idx_modulo(i, contour); + size_t inext = next_idx_modulo(i, contour); + Vec2d v1 = (contour[i] - contour[iprev]).cast(); + Vec2d v2 = (contour[inext] - contour[i]).cast(); + bool left_of_v1 = cross2(v1, pt - contour[iprev].cast()) > 0.; + bool left_of_v2 = cross2(v2, pt - contour[i ].cast()) > 0.; + return cross2(v1, v2) > 0 ? + left_of_v1 && left_of_v2 : // convex corner + left_of_v1 || left_of_v2; // concave corner + } + static bool left_of_segment(const Slic3r::Points &contour, size_t i, const Point &pt_oposite) { + const Vec2d pt = pt_oposite.cast(); + size_t inext = next_idx_modulo(i, contour); + Vec2d v = (contour[inext] - contour[i]).cast(); + return cross2(v, pt - contour[i].cast()) > 0.; + } + } visitor(grid, idx_contour, resampled_point_parameters, 0.5 * compensation * M_PI, search_radius); + + out.reserve(contour.size()); + Point radius_vector(search_radius, search_radius); + for (const Point &pt : contour) { + visitor.init(contour, pt); + grid.visit_cells_intersecting_box(BoundingBox(pt - radius_vector, pt + radius_vector), visitor); + out.emplace_back(float(visitor.found ? std::min(visitor.distance, search_radius) : search_radius)); + +#if 0 +//#ifdef CONTOUR_DISTANCE_DEBUG_SVG + if (out.back() < search_radius) { + SVG svg(debug_out_path("contour_distance_filtered-%d-%d.svg", iRun, int(&pt - contour.data())).c_str(), bbox); + svg.draw(expoly_grid); + svg.draw_outline(Polygon(contour), "blue", scale_(0.01)); + svg.draw(pt, "green", coord_t(scale_(0.1))); + svg.draw(visitor.closest_point, "red", coord_t(scale_(0.1))); + printf("contour_distance_filtered-%d-%d.svg - distance %lf\n", iRun, int(&pt - contour.data()), unscale(out.back())); + } +#endif /* CONTOUR_DISTANCE_DEBUG_SVG */ + } +#ifdef CONTOUR_DISTANCE_DEBUG_SVG + if (out.back() < search_radius) { + SVG svg(debug_out_path("contour_distance_filtered-final-%d.svg", iRun).c_str(), bbox); + svg.draw(expoly_grid); + svg.draw_outline(Polygon(contour), "blue", scale_(0.01)); + for (size_t i = 0; i < contour.size(); ++ i) + svg.draw(contour[i], out[i] < float(search_radius - SCALED_EPSILON) ? "red" : "green", coord_t(scale_(0.1))); + } +#endif /* CONTOUR_DISTANCE_DEBUG_SVG */ + } + + return out; +} + Points resample_polygon(const Points &contour, double dist, std::vector &resampled_point_parameters) { Points out; @@ -258,8 +445,8 @@ static inline void smooth_compensation(std::vector &compensation, float s std::vector out(compensation); for (size_t iter = 0; iter < num_iterations; ++ iter) { for (size_t i = 0; i < compensation.size(); ++ i) { - float prev = (i == 0) ? compensation.back() : compensation[i - 1]; - float next = (i + 1 == compensation.size()) ? compensation.front() : compensation[i + 1]; + float prev = prev_value_modulo(i, compensation); + float next = next_value_modulo(i, compensation); float laplacian = compensation[i] * (1.f - strength) + 0.5f * strength * (prev + next); // Compensations are negative. Only apply the laplacian if it leads to lower compensation. out[i] = std::max(laplacian, compensation[i]); @@ -268,30 +455,6 @@ static inline void smooth_compensation(std::vector &compensation, float s } } -template -static inline INDEX_TYPE prev_idx_cyclic(INDEX_TYPE idx, const CONTAINER &container) -{ - if (idx == 0) - idx = INDEX_TYPE(container.size()); - return -- idx; -} - -template -static inline INDEX_TYPE next_idx_cyclic(INDEX_TYPE idx, const CONTAINER &container) -{ - if (++ idx == INDEX_TYPE(container.size())) - idx = 0; - return idx; -} - -template -static inline T exchange(T& obj, U&& new_value) -{ - T old_value = std::move(obj); - obj = std::forward(new_value); - return old_value; -} - static inline void smooth_compensation_banded(const Points &contour, float band, std::vector &compensation, float strength, size_t num_iterations) { assert(contour.size() == compensation.size()); @@ -303,13 +466,13 @@ static inline void smooth_compensation_banded(const Points &contour, float band, for (int i = 0; i < int(compensation.size()); ++ i) { const Vec2f pthis = contour[i].cast(); - int j = prev_idx_cyclic(i, contour); + int j = prev_idx_modulo(i, contour); Vec2f pprev = contour[j].cast(); float prev = compensation[j]; float l2 = (pthis - pprev).squaredNorm(); if (l2 < dist_min2) { float l = sqrt(l2); - int jprev = exchange(j, prev_idx_cyclic(j, contour)); + int jprev = exchange(j, prev_idx_modulo(j, contour)); while (j != i) { const Vec2f pp = contour[j].cast(); const float lthis = (pp - pprev).norm(); @@ -324,17 +487,17 @@ static inline void smooth_compensation_banded(const Points &contour, float band, prev = use_min ? std::min(prev, compensation[j]) : compensation[j]; pprev = pp; l = lnext; - jprev = exchange(j, prev_idx_cyclic(j, contour)); + jprev = exchange(j, prev_idx_modulo(j, contour)); } } - j = next_idx_cyclic(i, contour); + j = next_idx_modulo(i, contour); pprev = contour[j].cast(); float next = compensation[j]; l2 = (pprev - pthis).squaredNorm(); if (l2 < dist_min2) { float l = sqrt(l2); - int jprev = exchange(j, next_idx_cyclic(j, contour)); + int jprev = exchange(j, next_idx_modulo(j, contour)); while (j != i) { const Vec2f pp = contour[j].cast(); const float lthis = (pp - pprev).norm(); @@ -349,7 +512,7 @@ static inline void smooth_compensation_banded(const Points &contour, float band, next = use_min ? std::min(next, compensation[j]) : compensation[j]; pprev = pp; l = lnext; - jprev = exchange(j, next_idx_cyclic(j, contour)); + jprev = exchange(j, next_idx_modulo(j, contour)); } } @@ -396,7 +559,7 @@ ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow & Polygon &poly = (idx_contour == 0) ? resampled.contour : resampled.holes[idx_contour - 1]; std::vector resampled_point_parameters; poly.points = resample_polygon(poly.points, resample_interval, resampled_point_parameters); - std::vector dists = contour_distance(grid, idx_contour, poly.points, resampled_point_parameters, search_radius); + std::vector dists = contour_distance2(grid, idx_contour, poly.points, resampled_point_parameters, scaled_compensation, search_radius); for (float &d : dists) { // printf("Point %d, Distance: %lf\n", int(&d - dists.data()), unscale(d)); // Convert contour width to available compensation distance. @@ -414,12 +577,21 @@ ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow & } ExPolygons out_vec = variable_offset_inner_ex(resampled, deltas, 2.); - assert(out_vec.size() == 1); if (out_vec.size() == 1) out = std::move(out_vec.front()); - else + else { // Something went wrong, don't compensate. out = input_expoly; +#ifdef TESTS_EXPORT_SVGS + if (out_vec.size() > 1) { + static int iRun = 0; + SVG::export_expolygons(debug_out_path("elephant_foot_compensation-many_contours-%d.svg", iRun ++).c_str(), + { { { input_expoly }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } }, + { { out_vec }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } } }); + } +#endif /* TESTS_EXPORT_SVGS */ + assert(out_vec.size() == 1); + } } return out; diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 9af2adcc6..71e896745 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -165,6 +165,65 @@ template size_t next_highest_power_of_2(T v, return next_highest_power_of_2(uint32_t(v)); } +template +inline INDEX_TYPE prev_idx_modulo(INDEX_TYPE idx, const INDEX_TYPE count) +{ + if (idx == 0) + idx = count; + return -- idx; +} + +template +inline INDEX_TYPE next_idx_modulo(INDEX_TYPE idx, const INDEX_TYPE count) +{ + if (++ idx == count) + idx = 0; + return idx; +} + +template +inline typename CONTAINER_TYPE::size_type prev_idx_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) +{ + return prev_idx_modulo(idx, container.size()); +} + +template +inline typename CONTAINER_TYPE::size_type next_idx_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) +{ + return next_idx_modulo(idx, container.size()); +} + +template +inline typename const CONTAINER_TYPE::value_type& prev_value_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) +{ + return container[prev_idx_modulo(idx, container.size())]; +} + +template +inline typename CONTAINER_TYPE::value_type& prev_value_modulo(typename CONTAINER_TYPE::size_type idx, CONTAINER_TYPE &container) +{ + return container[prev_idx_modulo(idx, container.size())]; +} + +template +inline typename const CONTAINER_TYPE::value_type& next_value_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) +{ + return container[next_idx_modulo(idx, container.size())]; +} + +template +inline typename CONTAINER_TYPE::value_type& next_value_modulo(typename CONTAINER_TYPE::size_type idx, CONTAINER_TYPE &container) +{ + return container[next_idx_modulo(idx, container.size())]; +} + +template +inline T exchange(T& obj, U&& new_value) +{ + T old_value = std::move(obj); + obj = std::forward(new_value); + return old_value; +} extern std::string xml_escape(std::string text); diff --git a/tests/libslic3r/test_elephant_foot_compensation.cpp b/tests/libslic3r/test_elephant_foot_compensation.cpp index e5ea97e68..98ec5df52 100644 --- a/tests/libslic3r/test_elephant_foot_compensation.cpp +++ b/tests/libslic3r/test_elephant_foot_compensation.cpp @@ -220,8 +220,217 @@ static ExPolygon vase_with_fins() return out; } +static ExPolygon contour_with_hole() +{ + ExPolygon out; + out.contour.points = { + { 23302819, 108248}, { 23410179, 157624}, { 23451825, 176777}, { 24106418, 478750}, { 24704172, 811512}, { 24883849, 911534}, { 25980045, 1530217}, { 26591038, 1897423}, { 26829981, 2041022}, { 27158523, 2249848}, { 27618921, 2584465}, + { 27896903, 2786507}, { 28144524, 2978990}, { 28815685, 3551061}, { 28909975, 3628821}, { 29371498, 4009409}, { 29402087, 4037084}, { 29493584, 4119861}, { 29765627, 4382947}, { 30607836, 5197449}, { 30934687, 5508413}, { 31019374, 5593546}, + { 31075807, 5655861}, { 31235879, 5823254}, { 31667505, 6274618}, { 31976596, 6656087}, { 32328364, 7055603}, { 32440973, 7183484}, { 32491346, 7249288}, { 33179667, 8148478}, { 33575401, 8717521}, { 33835875, 9075811}, { 34010014, 9315332}, + { 34304500, 9781688}, { 34369165, 9898535}, { 34397842, 9950359}, { 34494651, 10316439}, { 34501993, 10344190}, { 34385828, 10617514}, { 34331252, 10651174}, { 34084812, 10803186}, { 33894353, 10899665}, { 33398927, 11326583}, + { 33183121, 11494200}, { 32195826, 12261037}, { 31686925, 12719913}, { 31571718, 12807396}, { 31250995, 13050935}, { 31207108, 13086856}, { 31130381, 13149671}, { 31070741, 13206732}, { 30967095, 13305896}, { 30228082, 14071658}, + { 30116771, 14212337}, { 30044101, 14304176}, { 29567520, 14906137}, { 29043350, 15664879}, { 28911161, 15871189}, { 28855871, 15957479}, { 28714334, 16227582}, { 28650159, 16350050}, { 28364584, 16899765}, { 28240857, 17235607}, + { 28151371, 17509658}, { 28114198, 17623503}, { 28309361, 17730441}, { 28370394, 17763884}, { 28488974, 17847025}, { 28525745, 17872806}, { 29082248, 18281292}, { 29152930, 18376480}, { 29168058, 18396855}, { 29173722, 18656366}, + { 29176206, 18770149}, { 29167406, 18857292}, { 29104337, 19029141}, { 29049428, 19178752}, { 28907061, 19434701}, { 28857790, 19523283}, { 28715480, 19775043}, { 28630622, 20043684}, { 28609342, 20111052}, { 28573760, 20267045}, + { 28403454, 21103762}, { 28370165, 21230085}, { 28332310, 21373746}, { 28315057, 21418891}, { 28294569, 21472487}, { 28334157, 21579715}, { 28561468, 21814880}, { 28854906, 22118451}, { 29225599, 22499341}, { 29285205, 22617454}, + { 29324833, 22695983}, { 29313473, 22800767}, { 29312583, 22808982}, { 29272380, 22876835}, { 28829469, 23460472}, { 28817999, 23488286}, { 28796393, 23540675}, { 28775618, 23627381}, { 28732328, 23808034}, { 28661140, 24177335}, + { 28645731, 24834289}, { 28625222, 25202417}, { 28579034, 26031478}, { 28586310, 26420529}, { 28633240, 26560504}, { 28664456, 26653603}, { 28740916, 26788014}, { 28797005, 26886614}, { 28812464, 26950783}, { 28858428, 27009579}, + { 28975940, 26859631}, { 29022419, 26805440}, { 29115451, 26696972}, { 29135739, 26685915}, { 29155135, 26675346}, { 29408332, 26616458}, { 29592642, 26573591}, { 29614928, 26568091}, { 29711634, 26559197}, { 30723503, 26466299}, + { 31183646, 26470661}, { 31550568, 26550771}, { 31777556, 26600329}, { 32014697, 26671604}, { 32334931, 26854665}, { 32449353, 26920987}, { 32657873, 27041843}, { 32701539, 27084927}, { 32750872, 27133602}, { 33434549, 27790306}, + { 33487600, 27817659}, { 33548673, 27849142}, { 33793150, 28109624}, { 33877574, 28164293}, { 33965395, 28221161}, { 33999067, 28249986}, { 34024398, 28271673}, { 34059690, 28329572}, { 34087359, 28374972}, { 34181544, 28710471}, + { 34170186, 28732578}, { 34134947, 28801161}, { 34092867, 29064916}, { 33950784, 29233310}, { 33878646, 29318804}, { 33721956, 29672399}, { 33660358, 29727949}, { 33620108, 29764243}, { 33393624, 30270577}, { 33094597, 30771032}, + { 33063116, 30812704}, { 32973928, 30930779}, { 32608081, 31341847}, { 32393317, 31544017}, { 32206520, 31719862}, { 31997581, 31894374}, { 31972538, 31942583}, { 32059002, 32025240}, { 32171917, 32133182}, { 32501317, 32311025}, + { 32715593, 32426714}, { 32802065, 32479231}, { 32956210, 32574312}, { 33249042, 32770899}, { 33946833, 33239350}, { 34445301, 33680139}, { 34778020, 33974357}, { 35230994, 34391224}, { 35341113, 34460366}, { 35450459, 34529022}, + { 35625170, 34673345}, { 35764733, 34757179}, { 35775747, 34633947}, { 35846476, 34564107}, { 35965365, 34446723}, { 36038088, 34379954}, { 36151170, 34276133}, { 36426218, 34106680}, { 36531666, 34187969}, { 36695885, 34314565}, + { 37011093, 34586835}, { 37067557, 34150814}, { 37052506, 33989541}, { 37037043, 33823855}, { 37069574, 33661923}, { 37083653, 33591851}, { 37186706, 33497192}, { 37521634, 33288703}, { 37617140, 33275082}, { 37684699, 33219614}, + { 37821418, 33228393}, { 37938489, 33235910}, { 38091617, 33138918}, { 38155158, 33060873}, { 38213556, 32989142}, { 38727086, 32659362}, { 38746459, 32654507}, { 38809135, 32638806}, { 38820634, 32624462}, { 38855007, 32581573}, + { 39134002, 32235481}, { 39392850, 32163442}, { 39569189, 32115608}, { 39686862, 32083692}, { 39744314, 32146839}, { 39840707, 31963655}, { 39973169, 31711932}, { 40025735, 31592644}, { 40157184, 31465080}, { 40313010, 31313863}, + { 40390192, 31223588}, { 40418596, 31230809}, { 40594404, 31186692}, { 40732045, 31068306}, { 40746151, 30846139}, { 40761255, 30608300}, { 40853394, 30223426}, { 40876768, 30095588}, { 40895496, 29993166}, { 40968240, 29949606}, + { 41197066, 29989787}, { 41412367, 30027591}, { 41472384, 29977101}, { 41695297, 29659954}, { 41890516, 29382211}, { 42157410, 28987811}, { 42408947, 28616097}, { 42669462, 28292349}, { 42683144, 28275345}, { 42919982, 27924149}, + { 43162781, 27628506}, { 43527344, 27260325}, { 43847191, 27036250}, { 44057061, 26922424}, { 44231096, 26828037}, { 44301999, 26795490}, { 44327421, 26804561}, { 44319287, 26913761}, { 44143507, 27648484}, { 44107324, 27729499}, + { 44074236, 27803580}, { 44025541, 27932083}, { 43944121, 28146941}, { 43877811, 28710269}, { 43895199, 28764671}, { 43933238, 28883702}, { 43919165, 29004140}, { 43888109, 29269841}, { 43825852, 29576752}, { 43811824, 29609468}, + { 43748820, 29756420}, { 43763658, 29837769}, { 43832567, 30215488}, { 44075125, 29807258}, { 44209233, 29804204}, { 44310228, 29813855}, { 44365586, 29958259}, { 43873534, 30271247}, { 44003187, 30330249}, { 44617279, 30687869}, + { 44694113, 31070182}, { 44941015, 31257544}, { 45130334, 31171398}, { 45147836, 31132029}, { 45242053, 31070592}, { 45345637, 31033061}, { 45565937, 30953238}, { 45609517, 30857448}, { 45651888, 30764320}, { 45660681, 30754094}, + { 45822750, 30772646}, { 45944979, 30753042}, { 45964326, 30749938}, { 46054945, 30795588}, { 46577640, 31130668}, { 46870296, 31313313}, { 46976414, 31379541}, { 46998128, 31406087}, { 47008874, 31439291}, { 47031018, 31569281}, + { 47031214, 31576854}, { 47036334, 31774677}, { 47193705, 31889293}, { 47353245, 32029772}, { 47484683, 32145510}, { 47534251, 32233847}, { 47538509, 32241438}, { 47602626, 32453825}, { 47622648, 32465115}, { 47701707, 32575250}, + { 47776955, 33122018}, { 47677092, 33345574}, { 47630772, 33380015}, { 47572757, 33423150}, { 47328653, 33537512}, { 47343826, 33612940}, { 47462219, 33617810}, { 47578431, 33622591}, { 47808035, 33604884}, { 47842258, 33885890}, + { 47847000, 34154765}, { 47852298, 34455418}, { 47806556, 34798342}, { 47804979, 34803470}, { 47795265, 34835122}, { 47811501, 34879922}, { 47843100, 35247684}, { 47839663, 35481904}, { 47833503, 35902474}, { 47803910, 36044010}, + { 47819598, 36077879}, { 47841934, 36100587}, { 47854870, 36165755}, { 47911856, 36452861}, { 47927332, 36616382}, { 47936929, 36717785}, { 47770423, 36987292}, { 47699764, 37101659}, { 47671115, 37157488}, { 47423375, 37424772}, + { 47616349, 37518717}, { 47680621, 37550006}, { 47836151, 37632587}, { 47811936, 37777743}, { 47716954, 38113916}, { 47654340, 38250491}, { 47533407, 38514290}, { 47431515, 38674036}, { 47367427, 38987733}, { 47348164, 39043625}, + { 47298533, 39187606}, { 47279676, 39231940}, { 47252411, 39296047}, { 47246894, 39304927}, { 47238746, 39318037}, { 47232029, 39335258}, { 47220194, 39365593}, { 47196053, 39429922}, { 47159408, 39527585}, { 47041654, 39691835}, + { 47002148, 39908798}, { 46964248, 39997937}, { 46895728, 40159083}, { 46826610, 40301043}, { 46763479, 40430710}, { 46514929, 40884923}, { 46474179, 40918994}, { 46440818, 40946888}, { 46433233, 40992821}, { 46426528, 41033401}, + { 46108271, 41626808}, { 46056215, 41723876}, { 45997871, 41855066}, { 45755987, 42227269}, { 45653183, 42385466}, { 45444848, 42652871}, { 45380966, 42654262}, { 45336326, 42655238}, { 45326382, 42763461}, { 45318953, 42844333}, + { 45175146, 43086382}, { 45086585, 43235443}, { 45055897, 43281060}, { 44968051, 43418247}, { 44470500, 44195272}, { 44413430, 44364401}, { 44390221, 44433179}, { 44309502, 44528273}, { 44199667, 44604532}, { 43887229, 44833256}, + { 43815081, 44886070}, { 43726552, 44932547}, { 43689058, 44928887}, { 43686137, 44927822}, { 43280111, 44871367}, { 43249704, 44937548}, { 43324977, 45004000}, { 43046101, 45224515}, { 42898716, 45341059}, { 42838343, 45382240}, + { 42721108, 45493632}, { 42470119, 45669357}, { 42359756, 45746630}, { 42073412, 45910212}, { 42022050, 45926905}, { 41907133, 46027394}, { 41144940, 46559849}, { 40902566, 46683907}, { 40884989, 46688481}, { 40811763, 46707548}, + { 40768612, 46786655}, { 40675645, 46871372}, { 40548269, 46985681}, { 40382460, 47085920}, { 40082094, 47267510}, { 39768380, 47413990}, { 39734614, 47420931}, { 39586801, 47437916}, { 39408498, 47458403}, { 39355630, 47574767}, + { 39281498, 47737937}, { 39251009, 47783502}, { 39152882, 47890727}, { 39013408, 48043132}, { 38921577, 48100514}, { 38896008, 48108330}, { 38727116, 48102492}, { 38692428, 48101294}, { 38425261, 48075982}, { 38342344, 48047392}, + { 38336010, 48154957}, { 38151978, 48395628}, { 37811687, 48488990}, { 37804084, 48490379}, { 37674998, 48513979}, { 37674196, 48513196}, { 37658712, 48498074}, { 37592273, 48482371}, { 37336907, 48659173}, { 37140701, 48741338}, + { 37129466, 48764064}, { 37075599, 48873013}, { 36739574, 48838715}, { 36721697, 48864552}, { 36456161, 49171298}, { 36442740, 49184060}, { 36436660, 49212679}, { 36300951, 49585030}, { 36223897, 49727927}, { 36150156, 49864671}, + { 35924446, 50245885}, { 35769083, 50508275}, { 35750118, 50514284}, { 35323137, 50653609}, { 34050908, 50703703}, { 33864494, 50706292}, { 33666152, 50709051}, { 33813201, 50839130}, { 33884905, 50893350}, { 33912037, 50913867}, + { 34282238, 51132740}, { 35016181, 51605972}, { 35027459, 51615787}, { 35030754, 51618656}, { 35108803, 51693454}, { 35137469, 51720927}, { 34948522, 51872654}, { 34658613, 52064227}, { 34464997, 52192175}, { 34289189, 52285353}, + { 34219119, 52312637}, { 33847969, 52428212}, { 33681538, 52480036}, { 33407178, 52510887}, { 33421683, 52685666}, { 33428342, 52765908}, { 33392094, 53146294}, { 33371466, 53362761}, { 33253040, 54291767}, { 33196142, 54612534}, + { 33128154, 54815569}, { 33095559, 54912904}, { 32570427, 55111061}, { 32525706, 55125923}, { 32458612, 55148214}, { 32385063, 55163161}, { 32282016, 55184108}, { 32241393, 55188603}, { 32190544, 55194226}, { 32027959, 55217259}, + { 32011561, 56072729}, { 32003567, 57064095}, { 31997637, 57799631}, { 32015577, 60287161}, { 32014290, 61201940}, { 32012996, 62120667}, { 32007630, 62197246}, { 32002828, 62265761}, { 32003310, 62373952}, { 32003630, 62444825}, + { 31951202, 63100419}, { 31935103, 63301732}, { 31937490, 63354807}, { 31968533, 64124669}, { 32071989, 64767136}, { 32091323, 64947492}, { 32101518, 65042609}, { 32140486, 65216353}, { 32159835, 65302616}, { 32422071, 66001036}, + { 32441049, 66056128}, { 32463003, 66119864}, { 32483582, 66164217}, { 32504016, 66208251}, { 32702117, 66557895}, { 32734168, 66611648}, { 32759723, 66654509}, { 32985249, 66546464}, { 33208649, 66439436}, { 33424955, 66330151}, + { 33554797, 66263457}, { 33891385, 66090564}, { 34622897, 65616004}, { 34819546, 65471063}, { 34988926, 65346218}, { 35739513, 64794843}, { 36421629, 64150515}, { 36944662, 63656452}, { 36959929, 63643292}, { 36964174, 63639854}, + { 36973615, 63630686}, { 37023366, 63597643}, { 37652255, 63172287}, { 37804320, 63100590}, { 37939211, 63174238}, { 37949998, 63178562}, { 38147664, 63257792}, { 38147652, 63269386}, { 38147521, 63403665}, { 38150429, 63418056}, + { 38177182, 63550576}, { 38159827, 64298859}, { 38153585, 64520174}, { 38146482, 64771937}, { 38142126, 64820836}, { 38138239, 64839298}, { 38115242, 65010431}, { 38113231, 65025393}, { 37912271, 66372984}, { 37841830, 66687479}, + { 37674277, 67228175}, { 37551047, 67593509}, { 37497098, 67727333}, { 37392268, 67951311}, { 36986640, 68817980}, { 36604483, 69575518}, { 36479686, 69769345}, { 36265058, 70102690}, { 36332308, 70163400}, { 36398395, 70223058}, + { 36718105, 70645723}, { 36714573, 70708131}, { 36707947, 70825274}, { 36665865, 71083146}, { 36295751, 71910509}, { 36243731, 72020144}, { 36010145, 72512434}, { 35364761, 74115820}, { 35327445, 74206370}, { 35287332, 74303707}, + { 35262905, 74370595}, { 35235816, 74444782}, { 35006275, 75142899}, { 34758612, 75896141}, { 34609479, 76324076}, { 34534936, 76598593}, { 34419529, 77019735}, { 34125782, 78091675}, { 34270135, 78023153}, { 34366481, 77977415}, + { 34669421, 77827427}, { 35532698, 77282412}, { 35875762, 77065829}, { 35924952, 77041288}, { 35981906, 77004141}, { 36227708, 76899428}, { 36700108, 76693284}, { 36835857, 76657801}, { 36942059, 76731654}, { 36959107, 76741135}, + { 37155031, 76850094}, { 37152161, 76868751}, { 37133420, 76990662}, { 37135224, 77014721}, { 37144331, 77136260}, { 37029215, 77783623}, { 36994547, 77984972}, { 36957442, 78200506}, { 36949745, 78231593}, { 36945059, 78243379}, + { 36909925, 78358183}, { 36908693, 78362210}, { 36517584, 79569608}, { 36400200, 79852238}, { 36160758, 80317591}, { 36001388, 80606724}, { 35929263, 80720331}, { 35803937, 80894237}, { 35313741, 81574455}, { 34810829, 82211118}, + { 34636165, 82398130}, { 34424143, 82625140}, { 34177218, 82875584}, { 34001320, 83053991}, { 33330876, 83686990}, { 33313615, 83940131}, { 33257889, 84757318}, { 33154596, 86125618}, { 33050414, 87930914}, { 33037323, 88157771}, + { 32996151, 88791902}, { 33122354, 88720953}, { 34042644, 88195810}, { 34854618, 87571171}, { 35217422, 87292077}, { 35240201, 87279017}, { 35256654, 87268145}, { 35304044, 87230648}, { 35465557, 87154377}, { 35979874, 86886707}, + { 36162994, 86833255}, { 36213131, 86859811}, { 36328089, 86920714}, { 36446386, 87103899}, { 36444792, 87129675}, { 36435583, 87278561}, { 36439166, 87306042}, { 36455346, 87430153}, { 36439626, 87577638}, { 36363937, 88287781}, + { 36334385, 88516418}, { 36324472, 88550288}, { 36266923, 88831775}, { 36258817, 88871412}, { 36009099, 90001153}, { 35925390, 90278389}, { 35742522, 90743063}, { 35584494, 91114154}, { 35511233, 91260521}, { 35378328, 91493626}, + { 34896978, 92337857}, { 34592698, 92829175}, { 34534101, 92906355}, { 34379904, 93109443}, { 34292029, 93224277}, { 34181322, 93368951}, { 33996695, 93594059}, { 33791238, 93844563}, { 33350304, 94350448}, { 32679061, 95059135}, + { 32663276, 95383974}, { 32630835, 96051559}, { 32623715, 96162432}, { 32625261, 96184173}, { 32631760, 96253789}, { 32637940, 96319986}, { 32671334, 96831435}, { 32555999, 97073603}, { 32552956, 97110111}, { 32549772, 97148299}, + { 32339278, 100576678}, { 32333722, 100685777}, { 32330348, 100752035}, { 32315766, 101012907}, { 32604225, 100816839}, { 32833219, 100661190}, { 33690734, 100037568}, { 33947721, 99810841}, { 34263306, 99532414}, { 34709871, 99161136}, + { 35458100, 98470566}, { 35535202, 98409290}, { 35673889, 98299068}, { 35825183, 98230993}, { 36031300, 98138241}, { 36364183, 98058757}, { 36389853, 98099020}, { 36443213, 98182736}, { 36495776, 98421334}, { 36464592, 98534766}, + { 36403262, 98757832}, { 36433188, 98786253}, { 36468201, 98819516}, { 36427877, 99135414}, { 36380139, 99509425}, { 36367327, 99566653}, { 36130997, 100458902}, { 36092849, 100736616}, { 35993189, 101207413}, { 35961980, 101354843}, + { 35901824, 101565944}, { 35599001, 102436249}, { 35598486, 102437494}, { 35525627, 102612717}, { 35498238, 102672427}, { 35179093, 103368204}, { 34902420, 103873765}, { 34074371, 105280790}, { 33796945, 105666257}, { 33430747, 106175067}, + { 32757675, 107021332}, { 32288404, 107611357}, { 32147333, 107782229}, { 32045181, 107903768}, { 32013865, 108446053}, { 32004365, 108597331}, { 31933356, 109727991}, { 31929556, 109801743}, { 31921205, 109963885}, { 31919950, 109998202}, + { 31917378, 110068478}, { 31935487, 110174763}, { 31962352, 110332410}, { 31868759, 110776536}, { 31779274, 112901692}, { 31772558, 113008639}, { 31763520, 113152580}, { 31760914, 113226796}, { 31757613, 113320828}, { 31878079, 113245898}, + { 32056600, 113134847}, { 32205325, 113028281}, { 32417383, 112876331}, { 32791706, 112611586}, { 33374891, 112199137}, { 34043729, 111739447}, { 34299836, 111533282}, { 34686259, 111194925}, { 35041202, 110899316}, { 36153161, 109973245}, + { 36489565, 109732139}, { 36935134, 109547251}, { 36998142, 109523782}, { 37285208, 109416845}, { 37303575, 109443686}, { 37380657, 109556352}, { 37429339, 109768662}, { 37389406, 109896075}, { 37312708, 110140778}, { 37330397, 110173101}, + { 37358669, 110224762}, { 37347970, 110508588}, { 37343682, 110622428}, { 37233824, 111039422}, { 36974286, 111866215}, { 36941457, 112104350}, { 36810462, 112600390}, { 36763361, 112778757}, { 36685333, 113003686}, { 36304140, 113929965}, + { 36303227, 113931942}, { 36219925, 114112998}, { 36185254, 114177524}, { 35766113, 114957538}, { 35699185, 115058398}, { 35271549, 115739102}, { 34529522, 116832154}, { 34230604, 117226448}, { 34152175, 117323267}, { 33753453, 117815498}, + { 33688745, 117896887}, { 33515149, 118115220}, { 33167360, 118505862}, { 32252839, 119533076}, { 31951224, 119865885}, { 31856676, 119967574}, { 31811772, 120013039}, { 31820788, 120150853}, { 31837447, 120637820}, { 31884548, 122014628}, + { 31884879, 122025348}, { 31884889, 122025915}, { 31884859, 122030715}, { 31853727, 124752378}, { 31852710, 125798379}, { 32040109, 125687330}, { 32336721, 125511560}, { 33050838, 125039566}, { 33741293, 124531865}, { 34004877, 124347492}, + { 34706008, 123857040}, { 34900746, 123695124}, { 35248769, 123405773}, { 35958009, 122839178}, { 36752647, 122139217}, { 36794698, 122103853}, { 36926183, 121993279}, { 37041929, 121900209}, { 37364281, 121641009}, { 37506782, 121535931}, + { 37599623, 121475276}, { 37805210, 121390600}, { 38274450, 121197339}, { 38429386, 121137935}, { 38611951, 121409191}, { 38647554, 121490884}, { 38558179, 121763354}, { 38544345, 121816126}, { 38504735, 121967178}, { 38540287, 122025777}, + { 38533522, 122225637}, { 38527834, 122393821}, { 38490015, 122574939}, { 38335371, 123023448}, { 38226910, 123422167}, { 38128017, 123785706}, { 38110062, 123913558}, { 38039445, 124196782}, { 37811751, 125109983}, { 37795287, 125159401}, + { 37789856, 125175267}, { 37747302, 125281671}, { 37678378, 125454008}, { 37326009, 126304036}, { 37280379, 126403545}, { 36723741, 127438116}, { 36607591, 127622339}, { 35307172, 129556108}, { 34960577, 130042788}, { 34625146, 130457962}, + { 34244496, 130929114}, { 33616736, 131638592}, { 33126427, 132192717}, { 32289044, 133098400}, { 32128210, 133254928}, { 32114672, 133265860}, { 32051379, 133303244}, { 31973610, 133349175}, { 32021296, 134019482}, { 32078232, 134927829}, + { 32192915, 136757391}, { 32250210, 137342897}, { 32301584, 137908848}, { 32406571, 139065434}, { 32456488, 139422175}, { 32511513, 139855909}, { 32587723, 140456611}, { 33065481, 140191593}, { 33323332, 140063408}, { 33766028, 139843340}, + { 33978698, 139717429}, { 34224999, 139571601}, { 35090288, 139002456}, { 36098536, 138270161}, { 36204726, 138196467}, { 36870073, 137734734}, { 36937868, 137678015}, { 37269439, 137400662}, { 38224552, 136636721}, { 39248462, 135736109}, + { 39262231, 135724978}, { 39431206, 135588270}, { 39558286, 135491389}, { 40066663, 135103831}, { 40597978, 134876486}, { 40913397, 134752602}, { 41009750, 134730971}, { 41033440, 134769160}, { 41137853, 134937472}, { 41236776, 135135656}, + { 41185372, 135392011}, { 41170368, 135466840}, { 41117848, 135629223}, { 41128977, 135726643}, { 41112112, 135925316}, { 41028443, 136275112}, { 40892177, 136737346}, { 40715316, 137337282}, { 40625973, 137862286}, { 40571054, 138077826}, + { 40413004, 138698127}, { 40307787, 139028628}, { 40280705, 139108396}, { 40108570, 139542037}, { 39781168, 140366808}, { 39776747, 140377453}, { 39771298, 140388940}, { 39694209, 140532631}, { 39126953, 141589960}, { 39112976, 141613526}, + { 38864787, 141998169}, { 38780359, 142124163}, { 37534211, 143983846}, { 36837998, 144898691}, { 36749607, 145008489}, { 36437049, 145396720}, { 36308895, 145540735}, { 35926199, 145970826}, { 35104551, 146848709}, { 34756762, 147234955}, + { 34428436, 147599589}, { 34120556, 147908106}, { 34059694, 147944671}, { 33992021, 147971830}, { 33888925, 148013197}, { 33994002, 148234139}, { 34102871, 148463060}, { 34260406, 148815390}, { 34505558, 149252538}, { 34649150, 149539737}, + { 34875213, 149991894}, { 34913367, 150060689}, { 34939834, 150108425}, { 35009188, 150222655}, { 35057146, 150301638}, { 35531716, 151039155}, { 35961908, 151607166}, { 36198106, 151919026}, { 37112008, 151466356}, { 37122527, 151461129}, + { 37143274, 151448455}, { 37793852, 151104327}, { 38753278, 150462096}, { 39057095, 150265965}, { 39387132, 150052914}, { 39992757, 149578233}, { 40209373, 149410006}, { 40448656, 149224173}, { 41648972, 148150708}, { 41827582, 147994189}, + { 42089284, 147764870}, { 42281920, 147557241}, { 42535672, 147283737}, { 43211137, 146606344}, { 43969650, 145734949}, { 44008274, 145690567}, { 44434382, 145256367}, { 44673165, 145036231}, { 44753304, 144976343}, { 44941707, 144886575}, + { 45449136, 144644796}, { 45533221, 144617860}, { 45594657, 144672684}, { 45686988, 144755077}, { 45821054, 144894151}, { 45845698, 144928928}, { 45802394, 145256827}, { 45801968, 145263145}, { 45793099, 145396327}, { 45826083, 145436911}, + { 45827387, 145448733}, { 45852550, 145676686}, { 45846396, 146183080}, { 45801072, 146729105}, { 45751200, 147329993}, { 45765306, 147565974}, { 45765766, 147690105}, { 45758629, 147823920}, { 45717918, 148587045}, { 45669293, 148998256}, + { 45657164, 149090109}, { 45565455, 149517107}, { 45390903, 150329829}, { 45380310, 150370709}, { 45303883, 150599765}, { 45049477, 151362234}, { 45041081, 151384892}, { 44988127, 151512567}, { 44899898, 151709940}, { 44188361, 153301702}, + { 43960091, 153807492}, { 43687530, 154326968}, { 43680264, 154339888}, { 43428400, 154787836}, { 43418419, 154804941}, { 43222756, 155140257}, { 43211901, 155157187}, { 43019606, 155457042}, { 42439201, 156284412}, { 42742998, 156320854}, + { 42946786, 156345296}, { 43218356, 156408139}, { 43490220, 156548626}, { 43600789, 156605776}, { 43616758, 156616967}, { 43638494, 156675797}, { 43689725, 156874320}, { 43697411, 156939181}, { 43667792, 157194800}, { 43663112, 157219786}, + { 43589483, 157612846}, { 43578259, 157650201}, { 43503908, 157897703}, { 43271842, 158586008}, { 43026656, 159112379}, { 42680049, 159768278}, { 42229097, 160621619}, { 41614538, 161818913}, { 41602009, 161838594}, { 41549009, 161921905}, + { 41366702, 162195210}, { 41089703, 162610457}, { 41051349, 162661598}, { 40028827, 163938879}, { 39981539, 163995316}, { 39859709, 164140726}, { 39557928, 164489623}, { 38840108, 165319487}, { 38817977, 165343409}, { 36508721, 167822791}, + { 35803734, 168527171}, { 35265129, 169065323}, { 35217638, 169111343}, { 35182142, 169143335}, { 34143283, 170051242}, { 34091092, 170092305}, { 33992346, 170169987}, { 32820222, 171015261}, { 32596277, 171172367}, { 32366414, 171333625}, + { 30949741, 172256683}, { 30776429, 172369214}, { 30685231, 172428426}, { 29784929, 172978028}, { 29711510, 173022900}, { 29649347, 173060901}, { 29626880, 173084470}, { 29607989, 173104288}, { 29476620, 173372906}, { 29166644, 173374167}, + { 29105869, 173396269}, { 29066168, 173410694}, { 28480959, 173773359}, { 28318456, 173874074}, { 28236958, 173920336}, { 28053468, 174015451}, { 27663961, 174212865}, { 26444009, 174781179}, { 25128636, 175292014}, { 24833691, 175404475}, + { 24567873, 175499255}, { 23673660, 175815148}, { 23263816, 175959931}, { 22989484, 175996217}, { 22919277, 176005507}, { 22821755, 176011321}, { 22593369, 175931875}, { 22197778, 175796707}, { 20895444, 175329856}, { 20562493, 175210506}, + { 20357518, 175131409}, { 19431901, 174778687}, { 19227774, 174700914}, { 17432818, 173805114}, { 17355249, 173765680}, { 17340552, 173757060}, { 17293649, 173727963}, { 15176003, 172414266}, { 14987901, 172296594}, { 14897452, 172240019}, + { 14730104, 172123866}, { 14649567, 172067971}, { 12604451, 170685425}, { 12582065, 170669040}, { 12501564, 170610143}, { 12483411, 170595498}, { 12418519, 170543227}, { 11146256, 169546467}, { 11131285, 169533173}, { 10973608, 169393198}, + { 10963368, 169383375}, { 10855356, 169279681}, { 9350332, 167783891}, { 9237755, 167663880}, { 9038028, 167450975}, { 7554140, 165846157}, { 6510331, 164717307}, { 6450301, 164645790}, { 4792198, 162599032}, { 4711896, 162499401}, + { 4702892, 162486484}, { 4689884, 162466018}, { 4689721, 162465748}, { 4111625, 161512044}, { 3262811, 159825639}, { 3085907, 159501392}, { 2964224, 159278374}, { 2880198, 159123098}, { 2827825, 159026309}, { 2730830, 158798250}, + { 2662597, 158637824}, { 2461794, 158144454}, { 2258655, 157377436}, { 2232776, 156966420}, { 2227381, 156880727}, { 2229842, 156800001}, { 2404803, 156571898}, { 2502593, 156512353}, { 2571069, 156470646}, { 3012355, 156329121}, + { 3172690, 156317433}, { 3263007, 156310852}, { 3448807, 156270050}, { 2933268, 155537448}, { 2932334, 155536119}, { 2690506, 155171633}, { 2473838, 154800417}, { 2214521, 154335871}, { 1956160, 153843466}, { 1643404, 153150964}, + { 936422, 151585583}, { 886715, 151471650}, { 881872, 151459055}, { 835673, 151315362}, { 420381, 150023686}, { 415543, 150006511}, { 411493, 149986474}, { 371105, 149740432}, { 184472, 148603483}, { 176976, 148544106}, { 143829, 148268525}, + { 141423, 148213179}, { 118798, 147692447}, { 141994, 147109270}, { 96664, 146619882}, { 46940, 146083025}, { 34028, 145778412}, { 32148, 145734124}, { 50580, 145571914}, { 79797, 145477573}, { 59893, 144996644}, { 53607, 144916874}, + { 75632, 144881102}, { 170230, 144783356}, { 367047, 144609349}, { 495089, 144649841}, { 696206, 144748339}, { 861062, 144829070}, { 1202743, 145013350}, { 1665932, 145467720}, { 1738044, 145542186}, { 1871110, 145679584}, { 2233705, 146073631}, + { 2875888, 146771504}, { 2976802, 146887761}, { 3008358, 146918708}, { 3105019, 147016992}, { 3562844, 147482514}, { 3900940, 147829488}, { 3926192, 147851556}, { 5456634, 149216502}, { 5473415, 149229592}, { 5678115, 149389248}, + { 6416516, 149979537}, { 6693887, 150160404}, { 7011978, 150367823}, { 8034093, 151060650}, { 8245822, 151174920}, { 8663509, 151400371}, { 8734568, 151444233}, { 9700825, 151913516}, { 10314440, 151101573}, { 10876143, 150241580}, + { 10937084, 150142918}, { 10989872, 150057455}, { 11012110, 150016058}, { 11029139, 149984364}, { 11202330, 149640866}, { 11331097, 149385460}, { 11601540, 148893595}, { 11801542, 148453984}, { 11867898, 148312015}, { 12006182, 148016156}, + { 11936334, 147987685}, { 11846756, 147951181}, { 11775937, 147908929}, { 11448318, 147578728}, { 10005162, 146006655}, { 9941330, 145934468}, { 9420742, 145345782}, { 9364739, 145276533}, { 9005053, 144831776}, { 8354706, 143947082}, + { 7741954, 143034251}, { 7046776, 141998616}, { 6866979, 141726486}, { 6759755, 141551328}, { 6581042, 141228382}, { 6214827, 140566592}, { 6160332, 140464737}, { 6154984, 140452943}, { 6118667, 140365627}, { 5608006, 139066930}, + { 5576877, 138974353}, { 5449821, 138579522}, { 5423448, 138473840}, { 5269717, 137857830}, { 5183256, 137323221}, { 5051763, 136885377}, { 4900390, 136381329}, { 4788716, 135926420}, { 4778542, 135832434}, { 4751278, 135580592}, + { 4759133, 135551850}, { 4772567, 135502722}, { 4750760, 135428400}, { 4689711, 135220325}, { 4720284, 134950229}, { 4772938, 134876983}, { 4872059, 134739100}, { 4907041, 134734799}, { 4988166, 134747911}, { 5187996, 134827143}, + { 5324282, 134881173}, { 5823633, 135095262}, { 6457261, 135576778}, { 6468046, 135585394}, { 6645027, 135726930}, { 7665807, 136625984}, { 8014871, 136908364}, { 8760642, 137511681}, { 9070115, 137764153}, { 9505207, 138067027}, + { 9692018, 138199840}, { 10866067, 139034528}, { 10974854, 139102654}, { 11199174, 139243162}, { 11980766, 139757269}, { 12820102, 140204762}, { 13013724, 140301821}, { 13307713, 140449197}, { 13339465, 140204984}, { 13387908, 139832384}, + { 13476326, 139229254}, { 13545245, 138464294}, { 13637934, 137435521}, { 13704650, 136750183}, { 13756310, 135946981}, { 13854009, 134427968}, { 13931781, 133352665}, { 13880515, 133326641}, { 13806176, 133288914}, { 13608773, 133095964}, + { 13229938, 132676064}, { 12917088, 132329299}, { 12475540, 131854762}, { 12234438, 131582242}, { 11645945, 130917061}, { 11435343, 130656410}, { 11256705, 130435328}, { 11087956, 130227341}, { 10943531, 130049329}, { 10660547, 129658000}, + { 9884836, 128504691}, { 9363495, 127729593}, { 9183437, 127445707}, { 8613352, 126392173}, { 8569664, 126295529}, { 8233135, 125484892}, { 8100143, 125150567}, { 8091324, 125125230}, { 8068370, 125055541}, { 8047369, 124966573}, + { 7827878, 124036734}, { 7815999, 123941440}, { 7743138, 123689990}, { 7467916, 122740178}, { 7381012, 122383130}, { 7365871, 122250909}, { 7330956, 121946008}, { 7347071, 121910652}, { 7366239, 121868607}, { 7337555, 121775565}, + { 7275180, 121573218}, { 7357784, 121255913}, { 7363162, 121248563}, { 7433561, 121152362}, { 7492882, 121172887}, { 8152120, 121400901}, { 8296078, 121458859}, { 8337642, 121483827}, { 8428744, 121552386}, { 8461373, 121578560}, + { 9113408, 122101612}, { 9968838, 122858025}, { 10418874, 123221408}, { 11203964, 123855334}, { 11236475, 123882487}, { 11264272, 123901717}, { 12869603, 125041315}, { 13619004, 125547677}, { 13833945, 125671552}, { 14049136, 125795572}, + { 14042979, 124631730}, { 14031124, 123791039}, { 14029618, 123425913}, { 14024871, 122275773}, { 14024680, 122240909}, { 14024300, 122172017}, { 14024368, 122132419}, { 14024494, 122058437}, { 14025750, 122003675}, { 14028093, 121901540}, + { 14053706, 121051621}, { 14084937, 120015176}, { 13976495, 119893307}, { 12808105, 118596333}, { 12632795, 118395530}, { 12332420, 118051483}, { 12010936, 117651678}, { 11662489, 117218341}, { 11286185, 116695820}, { 10542401, 115590915}, + { 10484664, 115505145}, { 10085127, 114875400}, { 9677465, 114107097}, { 9676038, 114103997}, { 9587011, 113910478}, { 9572058, 113874387}, { 9221672, 113028545}, { 9132465, 112762183}, { 8929936, 112011523}, { 8896027, 111773355}, + { 8763540, 111338847}, { 8591711, 110775312}, { 8585822, 110750616}, { 8583286, 110726469}, { 8532504, 110242770}, { 8561517, 110201837}, { 8589689, 110162093}, { 8539283, 109999835}, { 8459773, 109743891}, { 8476274, 109635698}, + { 8539247, 109532026}, { 8559299, 109499015}, { 8639538, 109407427}, { 8837219, 109481673}, { 9374636, 109713713}, { 9614985, 109884378}, { 9895885, 110108176}, { 10150796, 110311272}, { 10647433, 110745796}, { 11163900, 111149653}, + { 11435641, 111378216}, { 11952173, 111812662}, { 12063358, 111892355}, { 12195941, 111987389}, { 13754894, 113077948}, { 13965930, 113207021}, { 14143358, 113315534}, { 14095680, 112195851}, { 14075275, 111736247}, { 14031684, 110754424}, + { 13949266, 109698295}, { 13931155, 109374956}, { 13907232, 108947887}, { 13903305, 108820557}, { 13899752, 108705317}, { 13898286, 108692370}, { 13896892, 108680054}, { 13882077, 108455610}, { 13866991, 108227067}, { 13852378, 107897586}, + { 13627196, 107630194}, { 13249326, 107173733}, { 13128837, 107021896}, { 12504668, 106235327}, { 12449045, 106156712}, { 12301165, 105947708}, { 12240927, 105864439}, { 12071292, 105629917}, { 11741182, 105140360}, { 11102902, 104050785}, + { 11009874, 103891983}, { 10724262, 103375048}, { 10370561, 102607103}, { 10302463, 102446702}, { 9995869, 101563023}, { 9933827, 101340326}, { 9788639, 100674614}, { 9761576, 100425516}, { 9620310, 99895785}, { 9572074, 99714909}, + { 9473316, 99261511}, { 9457110, 98860065}, { 9475422, 98813097}, { 9491516, 98771818}, { 9454445, 98628574}, { 9395112, 98399301}, { 9430018, 98201406}, { 9448015, 98172416}, { 9519385, 98057456}, { 9858391, 98155219}, { 10045563, 98209192}, + { 10217386, 98274096}, { 10328458, 98365757}, { 11168922, 99136589}, { 11517095, 99428522}, { 11782963, 99664460}, { 12152171, 99992110}, { 12543518, 100270019}, { 12914813, 100533689}, { 13199749, 100744460}, { 13324020, 100835567}, + { 13585579, 101027330}, { 13575682, 100826649}, { 13569447, 100700201}, { 13562345, 100567361}, { 13559065, 100506021}, { 13429751, 98521010}, { 13371150, 97621467}, { 13343156, 97180710}, { 13333987, 97039073}, { 13207473, 95084673}, + { 13138184, 95005008}, { 13017680, 94866468}, { 12083312, 93848129}, { 12022705, 93771797}, { 11862461, 93569995}, { 11784430, 93470508}, { 11589381, 93221813}, { 11309567, 92840780}, { 10844778, 92098029}, { 10775191, 91976786}, + { 10496881, 91491862}, { 10185086, 90849349}, { 10144137, 90764963}, { 10074833, 90600171}, { 9828579, 89857830}, { 9703614, 89075796}, { 9674971, 88969502}, { 9495272, 88102892}, { 9475468, 87916753}, { 9440640, 87589408}, { 9465676, 87528619}, + { 9487914, 87474617}, { 9465041, 87357340}, { 9428525, 87170118}, { 9490390, 86904119}, { 9512256, 86883153}, { 9574632, 86823334}, { 9727402, 86841642}, { 10166330, 86894255}, { 10190151, 86899193}, { 10198409, 86903284}, { 10249971, 86942095}, + { 10299758, 86980568}, { 11788945, 88131376}, { 11901024, 88196968}, { 12050012, 88284161}, { 12770268, 88697024}, { 12893258, 88767518}, { 12865978, 88340499}, { 12755514, 86383203}, { 12590001, 84209400}, { 12584956, 84143148}, + { 12549052, 83666692}, { 11929877, 83107725}, { 11390770, 82556851}, { 11083660, 82243035}, { 10537284, 81546957}, { 10424674, 81403496}, { 10079867, 80926984}, { 9689286, 80270083}, { 9687616, 80267071}, { 9615613, 80136762}, + { 9601056, 80104215}, { 9309849, 79453353}, { 9259598, 79312241}, { 9118888, 78788995}, { 9088297, 78585733}, { 8994447, 78301695}, { 8881493, 77959840}, { 8828452, 77771748}, { 8812025, 77688113}, { 8733303, 77287329}, { 8744431, 77274990}, + { 8786674, 77228142}, { 8770800, 77179143}, { 8746495, 77100409}, { 8709758, 76981397}, { 8765710, 76725562}, { 8780763, 76703647}, { 8821796, 76643902}, { 9050198, 76667553}, { 9430163, 76706910}, { 9505621, 76721216}, { 9535183, 76740071}, + { 9561982, 76753134}, { 11021709, 77681521}, { 11271938, 77809531}, { 11740477, 78049225}, { 11713323, 77940287}, { 11500961, 77088300}, { 11491445, 77055518}, { 11468672, 76977103}, { 11007894, 75454998}, { 10625858, 74342820}, + { 10581531, 74223613}, { 10547931, 74133250}, { 9872558, 72487409}, { 9785055, 72279833}, { 9735127, 72161397}, { 9661531, 72007947}, { 9614591, 71910070}, { 9234200, 71112437}, { 9147114, 70727104}, { 9142261, 70702843}, { 9138267, 70682891}, + { 9286224, 70443224}, { 9461343, 70247284}, { 9556416, 70162672}, { 9625168, 70101485}, { 9435737, 69811425}, { 9287394, 69584273}, { 8757085, 68530695}, { 8673850, 68365333}, { 8445942, 67877601}, { 8187617, 67187177}, { 8139627, 67039434}, + { 7937861, 66234567}, { 7892565, 65909655}, { 7845288, 65439718}, { 7844011, 65310767}, { 7823103, 65136343}, { 7778117, 64761067}, { 7716333, 64313964}, { 7705694, 64124356}, { 7687717, 63803945}, { 7701643, 63790152}, { 7718011, 63773943}, + { 7758186, 63752036}, { 7729172, 63586572}, { 7697769, 63407488}, { 7779619, 63146399}, { 7790119, 63132497}, { 7857734, 63042993}, { 7899799, 63053366}, { 8115923, 63106666}, { 8464711, 63240292}, { 8677072, 63398904}, { 8767176, 63477143}, + { 8977927, 63660143}, { 9421383, 64100703}, { 9785048, 64413088}, { 9975436, 64589567}, { 10286420, 64877827}, { 11014721, 65410888}, { 11115862, 65482249}, { 11327524, 65631599}, { 11395991, 65675856}, { 11535890, 65766274}, { 12026448, 66109919}, + { 12502690, 66343355}, { 12786634, 66472769}, { 13164960, 66645193}, { 13207596, 66564001}, { 13256756, 66470394}, { 13640736, 65570500}, { 13683003, 65454507}, { 13718537, 65356988}, { 13735231, 65270567}, { 13747424, 65207437}, + { 13863686, 64629409}, { 13875328, 64496043}, { 13887975, 64351165}, { 13957488, 63607260}, { 13950883, 63386188}, { 13943973, 63154947}, { 13895952, 62476120}, { 13876483, 62262044}, { 13859838, 62079009}, { 13859584, 62074662}, + { 13859582, 62065658}, { 13859483, 61971042}, { 13862761, 55222623}, { 13815791, 55212684}, { 13617475, 55174296}, { 13379849, 55128299}, { 13200660, 55067043}, { 13117648, 55038667}, { 12798922, 54907256}, { 12743350, 54730557}, + { 12719703, 54655364}, { 12656225, 54324243}, { 12632418, 53676660}, { 12625539, 53489551}, { 12652785, 53052852}, { 12782795, 52820186}, { 12846930, 52705411}, { 13041220, 52491209}, { 13143647, 52409064}, { 13187810, 52373646}, + { 13354789, 52319639}, { 13381838, 52313108}, { 13407786, 52306845}, { 13609096, 52308186}, { 13798532, 52309451}, { 14794521, 52294618}, { 15549961, 52336594}, { 16050147, 52311338}, { 16209513, 52303295}, { 16312325, 52297439}, + { 16369590, 51869307}, { 16340473, 51576398}, { 16331091, 51482008}, { 16316170, 51377054}, { 16241360, 51186578}, { 16186688, 51047373}, { 16076915, 50725256}, { 16093629, 50461603}, { 16098435, 50385771}, { 16109774, 50333994}, + { 16208639, 50141731}, { 16271132, 50020206}, { 16284775, 49997056}, { 16295310, 49985147}, { 16360397, 49947770}, { 16432796, 49916484}, { 16999910, 49671395}, { 17079341, 49631019}, { 17221011, 49559013}, { 17356128, 49546264}, + { 17369996, 49528116}, { 17426993, 49502498}, { 17530282, 49456075}, { 17342293, 49148088}, { 17284381, 49008875}, { 17254026, 48935905}, { 17357436, 48625105}, { 17422365, 48429965}, { 17423796, 48426977}, { 17601162, 48056939}, + { 17599241, 47980228}, { 17595410, 47827198}, { 17579402, 47751708}, { 17538195, 47557388}, { 17400788, 46598168}, { 17023471, 46464319}, { 16973301, 46446494}, { 16812540, 46389386}, { 16673736, 46329440}, { 16319654, 46176525}, + { 15950663, 46003440}, { 15838028, 45939836}, { 15697899, 45836427}, { 15289766, 45502367}, { 15260072, 45476441}, { 14999104, 45248614}, { 14962927, 45210840}, { 14722491, 44959778}, { 14678301, 44921783}, { 14404868, 44686698}, + { 14020130, 44298671}, { 13905758, 44155324}, { 13566066, 43648328}, { 13163266, 43047144}, { 13102631, 42937239}, { 13070977, 42862998}, { 12945977, 42560557}, { 12902489, 42448510}, { 12696099, 41916758}, { 12684650, 41857975}, + { 12656516, 41713516}, { 12557005, 40938961}, { 12554067, 40837978}, { 12550435, 40713161}, { 12562692, 40535359}, { 12575839, 40344643}, { 12609216, 40034504}, { 12660395, 39915667}, { 12708691, 39803526}, { 12798899, 39599814}, + { 12938906, 39372986}, { 12995589, 39281154}, { 13232289, 39007147}, { 13498241, 38725717}, { 13591444, 38550048}, { 13628611, 38480001}, { 13631794, 38446522}, { 13586786, 38388985}, { 13507530, 38236091}, { 13096257, 38028857}, + { 12821362, 37838492}, { 12551686, 37651741}, { 12445887, 37503612}, { 12369283, 37396362}, { 12264258, 37242462}, { 12195026, 37044172}, { 12148552, 36863589}, { 12101329, 36680088}, { 12142095, 35348959}, { 12144651, 35291418}, + { 12162788, 34883134}, { 12163706, 34850506}, { 12168637, 34675334}, { 12163420, 34644423}, { 12134883, 34475307}, { 12106311, 33932082}, { 12095021, 33476333}, { 12094122, 33057779}, { 12092211, 32168031}, { 12100800, 31962352}, + { 12107580, 31800023}, { 12116077, 31640101}, { 12122543, 31518406}, { 12193613, 31111725}, { 12255946, 30755035}, { 12655685, 28642673}, { 12654000, 28322388}, { 12689137, 28120452}, { 12708722, 28007885}, { 12692342, 27740702}, + { 12770201, 27316837}, { 12810004, 27100162}, { 12822406, 26990057}, { 12840969, 26876333}, { 12930142, 26507364}, { 13006294, 26192274}, { 13140275, 25812749}, { 13171909, 25737294}, { 13213594, 25637871}, { 13513395, 24982223}, + { 13564918, 24904642}, { 13614340, 24830229}, { 13673478, 24765245}, { 13723561, 24710211}, { 13790283, 24595233}, { 13857122, 24480057}, { 14153860, 24116007}, { 14231993, 24020147}, { 14248273, 23981550}, { 14451243, 23786195}, + { 14602942, 23651634}, { 14684407, 23579375}, { 15221344, 23339532}, { 15255414, 23324310}, { 15480802, 23178412}, { 15646843, 23091400}, { 16018697, 22744059}, { 16456749, 22567685}, { 16708674, 22466255}, { 16837697, 22410158}, + { 17154392, 22190832}, { 17069931, 22106918}, { 17007737, 21985244}, { 16978925, 21928875}, { 17036320, 21826992}, { 17212750, 21670157}, { 17298093, 21594293}, { 17451145, 21457485}, { 17530883, 21256458}, { 17541075, 21230767}, + { 17549886, 21207629}, { 17244063, 20372250}, { 17209346, 20248411}, { 17092010, 20089995}, { 17023648, 19955801}, { 16984483, 19912896}, { 16834254, 19784836}, { 16625524, 19606905}, { 16620983, 19603024}, { 16616582, 19597241}, + { 16614255, 19589014}, { 16578856, 19463898}, { 16588025, 19439937}, { 16595650, 19420015}, { 16602627, 19365704}, { 16608518, 19319848}, { 16694764, 19210381}, { 16784442, 19096556}, { 16461235, 17851161}, { 16421291, 17669728}, + { 16359955, 17616552}, { 16304854, 17528237}, { 16266671, 17467038}, { 16001330, 17343372}, { 15927109, 17308781}, { 15828509, 17248124}, { 15766385, 17190011}, { 15678175, 17097940}, { 15629868, 17047518}, { 15678592, 16534350}, + { 15695434, 16356965}, { 15704034, 16303332}, { 15705308, 16269732}, { 15725443, 15743784}, { 15808595, 15332260}, { 15821377, 15312568}, { 15838901, 15285580}, { 15993537, 15201723}, { 16119571, 15175593}, { 16189683, 15163592}, + { 16237347, 15155438}, { 16508759, 15159065}, { 16375757, 14977910}, { 16282021, 14850635}, { 15510709, 13877187}, { 15342882, 13710959}, { 15237532, 13606608}, { 14831965, 13239743}, { 14581428, 13013122}, { 14293147, 12740902}, + { 14190984, 12660109}, { 13669460, 12247703}, { 12564414, 11331695}, { 12487187, 11271158}, { 12046686, 10925925}, { 11871179, 10835479}, { 11582487, 10686699}, { 11523291, 10654160}, { 11396348, 10324251}, { 11575096, 9791088}, + { 11656410, 9657529}, { 11694903, 9594301}, { 12154341, 8957487}, { 12327404, 8717611}, { 12920992, 7861977}, { 13163209, 7541046}, { 13299428, 7360558}, { 13534727, 7094968}, { 13607608, 7012705}, { 14344532, 6120949}, { 15087045, 5393680}, + { 15307430, 5177820}, { 15930737, 4553097}, { 16730116, 3841678}, { 17107544, 3505773}, { 17287251, 3346015}, { 17407773, 3251557}, { 17762201, 2970942}, { 18238970, 2593464}, { 18584923, 2367852}, { 18697829, 2294226}, { 18997703, 2084694}, + { 19253265, 1922140}, { 19413044, 1820512}, { 20082389, 1425058}, { 21018405, 914454}, { 21306702, 757182}, { 21909855, 426548}, { 22232009, 276063}, { 22432844, 180461}, { 22572399, 114027}, { 22900298, 67093} + }; + out.holes.emplace_back(Slic3r::Points( { + { 28812659, 51882256}, { 28813904, 51895244}, { 28807002, 51890550}, { 28850702, 52059657}, { 28856299, 52123368}, { 29045593, 52135332}, { 29004080, 52024610}, { 28932623, 51976002}, { 29332407, 51880142}, { 29334099, 51804647}, + { 29252306, 51781113}, { 29155613, 51753292}, { 28890648, 51728889}, { 28797131, 51720277} + } )); + return out; +} + SCENARIO("Elephant foot compensation", "[ElephantFoot]") { + GIVEN("Contour with hole") { + ExPolygon expoly = contour_with_hole(); + WHEN("Compensated") { + // Elephant foot compensation shall not pinch off bits from this contour. + ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.419999987f, 0.2f, 0.4f, false), 0.2f); +#ifdef TESTS_EXPORT_SVGS + SVG::export_expolygons(debug_out_path("elephant_foot_compensation_with_hole.svg").c_str(), + { { { expoly }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } }, + { { expoly_compensated }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } } }); +#endif /* TESTS_EXPORT_SVGS */ + THEN("area of the compensated polygon is smaller") { + REQUIRE(expoly_compensated.area() < expoly.area()); + } + } + } + GIVEN("Tiny contour") { ExPolygon expoly({ { 133382606, 94912473 }, { 134232493, 95001115 }, { 133783926, 95159440 }, { 133441897, 95180666 }, { 133408242, 95191984 }, { 133339012, 95166830 }, { 132991642, 95011087 }, { 133206549, 94908304 } }); WHEN("Compensated") { From b2a6a07d723e11277f5ce5f78d67dec5dcb2c1f0 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 15 Nov 2019 17:33:31 +0100 Subject: [PATCH 73/80] Make the .gcode and .sl1 thumbnails configurable through printer profile. --- resources/profiles/PrusaResearch.ini | 2 ++ src/libslic3r/PrintConfig.cpp | 5 +++++ src/slic3r/GUI/Plater.cpp | 13 +++++++------ src/slic3r/GUI/Preset.cpp | 3 ++- src/slic3r/GUI/PresetBundle.cpp | 1 + 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index bc41fab6b..a741f4656 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -3767,6 +3767,7 @@ printer_model = MINI printer_technology = FFF printer_variant = 0.4 printer_vendor = +thumbnails = 240x320,220x165,16x16 bed_shape = 0x0,180x0,180x180,0x180 default_filament_profile = "Prusament PLA MINI" default_print_profile = 0.15mm QUALITY MINI @@ -3827,6 +3828,7 @@ printer_model = SL1 printer_variant = default default_sla_material_profile = Prusa Orange Tough 0.05 default_sla_print_profile = 0.05 Normal +thumbnails = 400x400,800x480 bed_shape = 1.48x1.02,119.48x1.02,119.48x67.02,1.48x67.02 display_height = 68.04 display_orientation = portrait diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 8588fa9c2..82815131e 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -62,6 +62,11 @@ void PrintConfigDef::init_common_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionString("")); + def = this->add("thumbnails", coPoints); + def->label = L("Picture sizes to be stored into a .gcode and .sl1 files"); + def->mode = comExpert; + def->set_default_value(new ConfigOptionPoints()); + def = this->add("layer_height", coFloat); def->label = L("Layer height"); def->category = L("Layers and Perimeters"); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8cc47b45a..221eff7c2 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -87,8 +87,6 @@ using Slic3r::Preset; using Slic3r::PrintHostJob; #if ENABLE_THUMBNAIL_GENERATOR -static const std::vector < std::pair> THUMBNAIL_SIZE_FFF = { { 240, 320 }, { 220, 165 }, { 16, 16 } }; -static const std::vector> THUMBNAIL_SIZE_SLA = { { 800, 480 } }; static const std::pair THUMBNAIL_SIZE_3MF = { 256, 256 }; #endif // ENABLE_THUMBNAIL_GENERATOR @@ -3069,14 +3067,16 @@ bool Plater::priv::restart_background_process(unsigned int state) (this->background_process.state() != BackgroundSlicingProcess::STATE_RUNNING)) { // update thumbnail data + const std::vector &thumbnail_sizes = this->background_process.current_print()->full_print_config().option("thumbnails")->values; if (this->printer_technology == ptFFF) { // for ptFFF we need to generate the thumbnails before the export of gcode starts this->thumbnail_data.clear(); - for (const std::pair& size : THUMBNAIL_SIZE_FFF) + for (const Vec2d &sized : thumbnail_sizes) { this->thumbnail_data.push_back(ThumbnailData()); - generate_thumbnail(this->thumbnail_data.back(), size.first, size.second, true, true, false); + Point size(sized); // round to ints + generate_thumbnail(this->thumbnail_data.back(), size.x(), size.y(), true, true, false); } } else if (this->printer_technology == ptSLA) @@ -3084,10 +3084,11 @@ bool Plater::priv::restart_background_process(unsigned int state) // for ptSLA generate thumbnails without supports and pad (not yet calculated) // to render also supports and pad see on_slicing_update() this->thumbnail_data.clear(); - for (const std::pair& size : THUMBNAIL_SIZE_SLA) + for (const Vec2d &sized : thumbnail_sizes) { this->thumbnail_data.push_back(ThumbnailData()); - generate_thumbnail(this->thumbnail_data.back(), size.first, size.second, true, true, false); + Point size(sized); // round to ints + generate_thumbnail(this->thumbnail_data.back(), size.x(), size.y(), true, true, false); } } } diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 6ca6b785e..32a03b6b2 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -444,7 +444,8 @@ const std::vector& Preset::printer_options() "machine_max_acceleration_x", "machine_max_acceleration_y", "machine_max_acceleration_z", "machine_max_acceleration_e", "machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e", "machine_min_extruding_rate", "machine_min_travel_rate", - "machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e" + "machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e", + "thumbnails" }; s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end()); } diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 92db623f0..01c42d3de 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -96,6 +96,7 @@ PresetBundle::PresetBundle() : preset.config.optptr("printer_vendor", true); preset.config.optptr("printer_model", true); preset.config.optptr("printer_variant", true); + preset.config.optptr("thumbnails", true); if (i == 0) { preset.config.optptr("default_print_profile", true); preset.config.option("default_filament_profile", true)->values = { "" }; From bbb519ad0eceba5a2a6812b853fa2192bd8c9594 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Sat, 16 Nov 2019 08:22:39 +0100 Subject: [PATCH 74/80] Fixed a typo in MeshUtils.hpp --- src/libslic3r/Utils.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 71e896745..e5fae485a 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -194,7 +194,7 @@ inline typename CONTAINER_TYPE::size_type next_idx_modulo(typename CONTAINER_TYP } template -inline typename const CONTAINER_TYPE::value_type& prev_value_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) +inline const typename CONTAINER_TYPE::value_type& prev_value_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) { return container[prev_idx_modulo(idx, container.size())]; } @@ -206,7 +206,7 @@ inline typename CONTAINER_TYPE::value_type& prev_value_modulo(typename CONTAINER } template -inline typename const CONTAINER_TYPE::value_type& next_value_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) +inline const typename CONTAINER_TYPE::value_type& next_value_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) { return container[next_idx_modulo(idx, container.size())]; } From a1aa343416d402bb2e7f28d131503c3067e534df Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sat, 16 Nov 2019 09:04:06 +0100 Subject: [PATCH 75/80] Follow-up of b2a6a07d723e11277f5ce5f78d67dec5dcb2c1f0 -> Fixed code to render supports and pad into thumbnails for sla printer (currently commented out) --- src/slic3r/GUI/Plater.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 221eff7c2..f04e1e17f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3438,11 +3438,13 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) // for ptSLA generate the thumbnail after supports and pad have been calculated to have them rendered if ((this->printer_technology == ptSLA) && (evt.status.percent == -3)) { + const std::vector& thumbnail_sizes = this->background_process.current_print()->full_print_config().option("thumbnails")->values; this->thumbnail_data.clear(); - for (const std::pair& size : THUMBNAIL_SIZE_SLA) + for (const Vec2d &sized : thumbnail_sizes) { this->thumbnail_data.push_back(ThumbnailData()); - generate_thumbnail(this->thumbnail_data.back(), size.first, size.second, true, false, false); + Point size(sized); // round to ints + generate_thumbnail(this->thumbnail_data.back(), size.x(), size.y(), true, false, false); } } #endif // ENABLE_THUMBNAIL_GENERATOR From 7baefdf79dea3bb4ab88cb5ea324354bed5eacde Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 18 Nov 2019 10:04:32 +0100 Subject: [PATCH 76/80] Fix for deps patching --- deps/deps-unix-common.cmake | 13 ++++++------- deps/deps-windows.cmake | 11 ++++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/deps/deps-unix-common.cmake b/deps/deps-unix-common.cmake index 74582f601..944d2c06d 100644 --- a/deps/deps-unix-common.cmake +++ b/deps/deps-unix-common.cmake @@ -61,8 +61,8 @@ ExternalProject_Add(dep_qhull -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local ${DEP_CMAKE_OPTS} - UPDATE_COMMAND "" - PATCH_COMMAND patch -p1 < ${CMAKE_CURRENT_SOURCE_DIR}/qhull-mods.patch + PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && + ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/qhull-mods.patch ) ExternalProject_Add(dep_blosc @@ -80,8 +80,8 @@ ExternalProject_Add(dep_blosc -DBUILD_TESTS=OFF -DBUILD_BENCHMARKS=OFF -DPREFER_EXTERNAL_ZLIB=ON - UPDATE_COMMAND "" - PATCH_COMMAND ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/blosc-mods.patch + PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && + ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/blosc-mods.patch ) ExternalProject_Add(dep_openexr @@ -96,7 +96,6 @@ ExternalProject_Add(dep_openexr -DPYILMBASE_ENABLE:BOOL=OFF -DOPENEXR_VIEWERS_ENABLE:BOOL=OFF -DOPENEXR_BUILD_UTILS:BOOL=OFF - UPDATE_COMMAND "" ) ExternalProject_Add(dep_openvdb @@ -116,6 +115,6 @@ ExternalProject_Add(dep_openvdb -DOPENVDB_CORE_STATIC=ON -DTBB_STATIC=ON -DOPENVDB_BUILD_VDB_PRINT=ON - UPDATE_COMMAND "" - PATCH_COMMAND ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/openvdb-mods.patch + PATCH_COMMAND PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && + ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/openvdb-mods.patch ) \ No newline at end of file diff --git a/deps/deps-windows.cmake b/deps/deps-windows.cmake index 4aae07d4a..3affbaefa 100644 --- a/deps/deps-windows.cmake +++ b/deps/deps-windows.cmake @@ -226,7 +226,8 @@ ExternalProject_Add(dep_qhull -DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_DEBUG_POSTFIX=d - UPDATE_COMMAND "" + PATCH_COMMAND PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && + ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/qhull-mods.patch BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj INSTALL_COMMAND "" ) @@ -287,8 +288,8 @@ ExternalProject_Add(dep_blosc -DPREFER_EXTERNAL_ZLIB=ON -DBLOSC_IS_SUBPROJECT:BOOL=ON -DBLOSC_INSTALL:BOOL=ON - UPDATE_COMMAND "" - PATCH_COMMAND ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/blosc-mods.patch + PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && + ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/blosc-mods.patch BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj INSTALL_COMMAND "" ) @@ -339,8 +340,8 @@ ExternalProject_Add(dep_openvdb -DTBB_STATIC=ON -DOPENVDB_BUILD_VDB_PRINT=ON BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj - UPDATE_COMMAND "" - PATCH_COMMAND ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/openvdb-mods.patch + PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && + ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/openvdb-mods.patch INSTALL_COMMAND "" ) From ab735bdc5445a77aa0fb69f22c4cd9565b382124 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 18 Nov 2019 09:35:26 +0100 Subject: [PATCH 77/80] Follow up: fixing patches on windows --- deps/blosc-mods.patch | 3 ++- deps/deps-windows.cmake | 5 +---- deps/openvdb-mods.patch | 3 ++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/deps/blosc-mods.patch b/deps/blosc-mods.patch index 9a91b4974..9b1b9cb27 100644 --- a/deps/blosc-mods.patch +++ b/deps/blosc-mods.patch @@ -1,8 +1,9 @@ -From 5669891dfaaa4c814f3ec667ca6bf4e693aea978 Mon Sep 17 00:00:00 2001 +From 7cf6c014a36f1712efbdbe9bc52d2d4922b54673 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 30 Oct 2019 12:54:52 +0100 Subject: [PATCH] Blosc 1.17 fixes and cmake config script +Signed-off-by: tamasmeszaros --- CMakeLists.txt | 105 +++++++++++++++++----------------- blosc/CMakeLists.txt | 118 +++++++++------------------------------ diff --git a/deps/deps-windows.cmake b/deps/deps-windows.cmake index 3affbaefa..1b978bdde 100644 --- a/deps/deps-windows.cmake +++ b/deps/deps-windows.cmake @@ -226,8 +226,6 @@ ExternalProject_Add(dep_qhull -DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_DEBUG_POSTFIX=d - PATCH_COMMAND PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && - ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/qhull-mods.patch BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj INSTALL_COMMAND "" ) @@ -311,7 +309,6 @@ ExternalProject_Add(dep_openexr -DPYILMBASE_ENABLE:BOOL=OFF -DOPENEXR_VIEWERS_ENABLE:BOOL=OFF -DOPENEXR_BUILD_UTILS:BOOL=OFF - UPDATE_COMMAND "" BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj INSTALL_COMMAND "" ) @@ -324,7 +321,7 @@ ExternalProject_Add(dep_openvdb #URL_HASH SHA256=dc337399dce8e1c9f21f20e97b1ce7e4933cb0a63bb3b8b734d8fcc464aa0c48 GIT_REPOSITORY https://github.com/AcademySoftwareFoundation/openvdb.git GIT_TAG aebaf8d95be5e57fd33949281ec357db4a576c2e #v6.2.1 - DEPENDS dep_blosc dep_openexr #dep_tbb dep_boost + DEPENDS dep_blosc dep_openexr dep_tbb dep_boost CMAKE_GENERATOR "${DEP_MSVC_GEN}" CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}" CMAKE_ARGS diff --git a/deps/openvdb-mods.patch b/deps/openvdb-mods.patch index 60687b8d1..023cb5308 100644 --- a/deps/openvdb-mods.patch +++ b/deps/openvdb-mods.patch @@ -1,8 +1,9 @@ -From e48f4a835fe7cb391f9f90945472bd367fb4c4f1 Mon Sep 17 00:00:00 2001 +From dbe038fce8a15ddc9a5c83ec5156d7bc9e178015 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 16 Oct 2019 17:42:50 +0200 Subject: [PATCH] Build fixes for PrusaSlicer integration +Signed-off-by: tamasmeszaros --- CMakeLists.txt | 3 - cmake/FindBlosc.cmake | 218 --------------- From cfc927b3711701c68ad1e594e10db86e69f489ad Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 18 Nov 2019 10:59:58 +0100 Subject: [PATCH 78/80] Fix qhull download --- deps/deps-unix-common.cmake | 6 ++++-- deps/deps-windows.cmake | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/deps/deps-unix-common.cmake b/deps/deps-unix-common.cmake index 944d2c06d..d0305bd4d 100644 --- a/deps/deps-unix-common.cmake +++ b/deps/deps-unix-common.cmake @@ -55,8 +55,10 @@ find_package(Git REQUIRED) ExternalProject_Add(dep_qhull EXCLUDE_FROM_ALL 1 - URL "https://github.com/qhull/qhull/archive/v7.3.2.tar.gz" - URL_HASH SHA256=619c8a954880d545194bc03359404ef36a1abd2dde03678089459757fd790cb0 + #URL "https://github.com/qhull/qhull/archive/v7.3.2.tar.gz" + #URL_HASH SHA256=619c8a954880d545194bc03359404ef36a1abd2dde03678089459757fd790cb0 + GIT_REPOSITORY https://github.com/qhull/qhull.git + GIT_TAG v7.3.2 CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local diff --git a/deps/deps-windows.cmake b/deps/deps-windows.cmake index 1b978bdde..cca88c308 100644 --- a/deps/deps-windows.cmake +++ b/deps/deps-windows.cmake @@ -218,8 +218,10 @@ find_package(Git REQUIRED) ExternalProject_Add(dep_qhull EXCLUDE_FROM_ALL 1 - URL "https://github.com/qhull/qhull/archive/v7.3.2.tar.gz" - URL_HASH SHA256=619c8a954880d545194bc03359404ef36a1abd2dde03678089459757fd790cb0 + #URL "https://github.com/qhull/qhull/archive/v7.3.2.tar.gz" + #URL_HASH SHA256=619c8a954880d545194bc03359404ef36a1abd2dde03678089459757fd790cb0 + GIT_REPOSITORY https://github.com/qhull/qhull.git + GIT_TAG v7.3.2 CMAKE_GENERATOR "${DEP_MSVC_GEN}" CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local From 3b8ee784008df955c8fc0ea4be7b1e935c0d7ce7 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 18 Nov 2019 11:05:25 +0100 Subject: [PATCH 79/80] Use the upstream qhull with the macos patch instead of patching manually --- deps/deps-unix-common.cmake | 4 +--- deps/deps-windows.cmake | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/deps/deps-unix-common.cmake b/deps/deps-unix-common.cmake index d0305bd4d..b2d82c950 100644 --- a/deps/deps-unix-common.cmake +++ b/deps/deps-unix-common.cmake @@ -58,13 +58,11 @@ ExternalProject_Add(dep_qhull #URL "https://github.com/qhull/qhull/archive/v7.3.2.tar.gz" #URL_HASH SHA256=619c8a954880d545194bc03359404ef36a1abd2dde03678089459757fd790cb0 GIT_REPOSITORY https://github.com/qhull/qhull.git - GIT_TAG v7.3.2 + GIT_TAG 7afedcc73666e46a9f1d74632412ebecf53b1b30 # v7.3.2 plus the mac build patch CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local ${DEP_CMAKE_OPTS} - PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && - ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/qhull-mods.patch ) ExternalProject_Add(dep_blosc diff --git a/deps/deps-windows.cmake b/deps/deps-windows.cmake index cca88c308..603f24931 100644 --- a/deps/deps-windows.cmake +++ b/deps/deps-windows.cmake @@ -221,7 +221,7 @@ ExternalProject_Add(dep_qhull #URL "https://github.com/qhull/qhull/archive/v7.3.2.tar.gz" #URL_HASH SHA256=619c8a954880d545194bc03359404ef36a1abd2dde03678089459757fd790cb0 GIT_REPOSITORY https://github.com/qhull/qhull.git - GIT_TAG v7.3.2 + GIT_TAG 7afedcc73666e46a9f1d74632412ebecf53b1b30 # v7.3.2 plus the mac build patch CMAKE_GENERATOR "${DEP_MSVC_GEN}" CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local From 54357f846f695d9879fb023e8cb8de7804ca0dca Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 18 Nov 2019 12:09:46 +0100 Subject: [PATCH 80/80] Change blosc patching "checkout -f" to "reset --hard" --- deps/deps-unix-common.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/deps-unix-common.cmake b/deps/deps-unix-common.cmake index b2d82c950..7491aafe1 100644 --- a/deps/deps-unix-common.cmake +++ b/deps/deps-unix-common.cmake @@ -80,7 +80,7 @@ ExternalProject_Add(dep_blosc -DBUILD_TESTS=OFF -DBUILD_BENCHMARKS=OFF -DPREFER_EXTERNAL_ZLIB=ON - PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && + PATCH_COMMAND ${GIT_EXECUTABLE} reset --hard && git clean -df && ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/blosc-mods.patch )