From ddd0a9abb69ca7715641efaaa34dbbf030b552ef Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 11 Jun 2019 12:40:07 +0200 Subject: [PATCH 01/28] SPE-742: Builtin pad feature in zero elevation mode. --- .clang-format | 2 +- sandboxes/slabasebed/slabasebed.cpp | 32 +-- src/libslic3r/SLA/SLABasePool.cpp | 321 ++++++++++++++++++---- src/libslic3r/SLA/SLABasePool.hpp | 17 +- src/libslic3r/SLA/SLACommon.hpp | 7 + src/libslic3r/SLA/SLASupportTree.cpp | 391 ++++++++++++++++++++------- src/libslic3r/SLA/SLASupportTree.hpp | 21 +- src/libslic3r/SLAPrint.cpp | 126 ++++++--- 8 files changed, 685 insertions(+), 232 deletions(-) diff --git a/.clang-format b/.clang-format index d5740f6894..9a2c3ce1dd 100644 --- a/.clang-format +++ b/.clang-format @@ -46,7 +46,7 @@ BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeComma BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true -ColumnLimit: 75 +ColumnLimit: 78 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: true diff --git a/sandboxes/slabasebed/slabasebed.cpp b/sandboxes/slabasebed/slabasebed.cpp index 0c34eb9f52..5393f61fd7 100644 --- a/sandboxes/slabasebed/slabasebed.cpp +++ b/sandboxes/slabasebed/slabasebed.cpp @@ -15,7 +15,8 @@ const std::string USAGE_STR = { namespace Slic3r { namespace sla { -Contour3D create_base_pool(const ExPolygons &ground_layer, +Contour3D create_base_pool(const Polygons &ground_layer, + const Polygons &holes = {}, const PoolConfig& cfg = PoolConfig()); Contour3D walls(const Polygon& floor_plate, const Polygon& ceiling, @@ -42,37 +43,28 @@ int main(const int argc, const char *argv[]) { model.ReadSTLFile(argv[1]); model.align_to_origin(); - ExPolygons ground_slice; - sla::Contour3D mesh; -// TriangleMesh basepool; - + Polygons ground_slice; sla::base_plate(model, ground_slice, 0.1f); - if(ground_slice.empty()) return EXIT_FAILURE; -// ExPolygon bottom_plate = ground_slice.front(); -// ExPolygon top_plate = bottom_plate; -// sla::offset(top_plate, coord_t(3.0/SCALING_FACTOR)); -// sla::offset(bottom_plate, coord_t(1.0/SCALING_FACTOR)); + Polygon gndfirst; gndfirst = ground_slice.front(); + sla::offset_with_breakstick_holes(gndfirst, 0.5, 10, 0.3); + + sla::Contour3D mesh; + bench.start(); -// TriangleMesh pool; sla::PoolConfig cfg; cfg.min_wall_height_mm = 0; - cfg.edge_radius_mm = 0.2; - mesh = sla::create_base_pool(ground_slice, cfg); - -// mesh.merge(triangulate_expolygon_3d(top_plate, 3.0, false)); -// mesh.merge(triangulate_expolygon_3d(bottom_plate, 0.0, true)); -// mesh = sla::walls(bottom_plate.contour, top_plate.contour, 0, 3, 2.0, [](){}); - + cfg.edge_radius_mm = 0; + mesh = sla::create_base_pool(ground_slice, {}, cfg); + bench.stop(); cout << "Base pool creation time: " << std::setprecision(10) << bench.getElapsedSec() << " seconds." << endl; - -// auto point = []() + for(auto& trind : mesh.indices) { Vec3d p0 = mesh.points[size_t(trind[0])]; Vec3d p1 = mesh.points[size_t(trind[1])]; diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp index 171d2b8d03..9b3f80f1a1 100644 --- a/src/libslic3r/SLA/SLABasePool.cpp +++ b/src/libslic3r/SLA/SLABasePool.cpp @@ -7,9 +7,9 @@ #include "Tesselate.hpp" // For debugging: -//#include -//#include -//#include "SVG.hpp" +// #include +// #include +#include "SVG.hpp" namespace Slic3r { namespace sla { @@ -180,9 +180,10 @@ Contour3D walls(const Polygon& lower, const Polygon& upper, } /// Offsetting with clipper and smoothing the edges into a curvature. -void offset(ExPolygon& sh, coord_t distance) { +void offset(ExPolygon& sh, coord_t distance, bool edgerounding = true) { using ClipperLib::ClipperOffset; using ClipperLib::jtRound; + using ClipperLib::jtMiter; using ClipperLib::etClosedPolygon; using ClipperLib::Paths; using ClipperLib::Path; @@ -199,11 +200,13 @@ void offset(ExPolygon& sh, coord_t distance) { return; } + auto jointype = edgerounding? jtRound : jtMiter; + ClipperOffset offs; offs.ArcTolerance = 0.01*mm(1); Paths result; - offs.AddPath(ctour, jtRound, etClosedPolygon); - offs.AddPaths(holes, jtRound, etClosedPolygon); + offs.AddPath(ctour, jointype, etClosedPolygon); + offs.AddPaths(holes, jointype, etClosedPolygon); offs.Execute(result, static_cast(distance)); // Offsetting reverts the orientation and also removes the last vertex @@ -233,6 +236,49 @@ void offset(ExPolygon& sh, coord_t distance) { } } +void offset(Polygon& sh, coord_t distance, bool edgerounding = true) { + using ClipperLib::ClipperOffset; + using ClipperLib::jtRound; + using ClipperLib::jtMiter; + using ClipperLib::etClosedPolygon; + using ClipperLib::Paths; + using ClipperLib::Path; + + auto&& ctour = Slic3rMultiPoint_to_ClipperPath(sh); + + // If the input is not at least a triangle, we can not do this algorithm + if(ctour.size() < 3) { + BOOST_LOG_TRIVIAL(error) << "Invalid geometry for offsetting!"; + return; + } + + ClipperOffset offs; + offs.ArcTolerance = 0.01*mm(1); + Paths result; + offs.AddPath(ctour, edgerounding ? jtRound : jtMiter, etClosedPolygon); + offs.Execute(result, static_cast(distance)); + + // Offsetting reverts the orientation and also removes the last vertex + // so boost will not have a closed polygon. + + bool found_the_contour = false; + for(auto& r : result) { + if(ClipperLib::Orientation(r)) { + // We don't like if the offsetting generates more than one contour + // but throwing would be an overkill. Instead, we should warn the + // caller about the inability to create correct geometries + if(!found_the_contour) { + auto rr = ClipperPath_to_Slic3rPolygon(r); + sh.points.swap(rr.points); + found_the_contour = true; + } else { + BOOST_LOG_TRIVIAL(warning) + << "Warning: offsetting result is invalid!"; + } + } + } +} + /// Unification of polygons (with clipper) preserving holes as well. ExPolygons unify(const ExPolygons& shapes) { using ClipperLib::ptSubject; @@ -303,6 +349,118 @@ ExPolygons unify(const ExPolygons& shapes) { return retv; } +Polygons unify(const Polygons& shapes) { + using ClipperLib::ptSubject; + + bool closed = true; + bool valid = true; + + ClipperLib::Clipper clipper; + + for(auto& path : shapes) { + auto clipperpath = Slic3rMultiPoint_to_ClipperPath(path); + + if(!clipperpath.empty()) + valid &= clipper.AddPath(clipperpath, ptSubject, closed); + } + + if(!valid) BOOST_LOG_TRIVIAL(warning) << "Unification of invalid shapes!"; + + ClipperLib::Paths result; + clipper.Execute(ClipperLib::ctUnion, result, ClipperLib::pftNonZero); + + Polygons ret; + for (ClipperLib::Path &p : result) { + Polygon pp = ClipperPath_to_Slic3rPolygon(p); + if (!pp.is_clockwise()) ret.emplace_back(std::move(pp)); + } + + return ret; +} + +// Function to cut tiny connector cavities for a given polygon. The input poly +// will be offsetted by "padding" and small rectangle shaped cavities will be +// inserted along the perimeter in every "stride" distance. The stick rectangles +// will have a with about "stick_width". The input dimensions are in world +// measure, not the scaled clipper units. +void offset_with_breakstick_holes(ExPolygon& poly, + double padding, + double stride, + double stick_width, + double penetration) +{ + // We do the basic offsetting first + const bool dont_round_edges = false; + offset(poly, coord_t(padding / SCALING_FACTOR), dont_round_edges); + + SVG svg("bridgestick_plate.svg"); + svg.draw(poly); + + auto transf = [stick_width, penetration, padding, stride](Points &pts) { + // The connector stick will be a small rectangle with dimensions + // stick_width x (penetration + padding) to have some penetration + // into the input polygon. + + Points out; + out.reserve(2 * pts.size()); // output polygon points + + // stick bottom and right edge dimensions + double sbottom = stick_width / SCALING_FACTOR; + double sright = (penetration + padding) / SCALING_FACTOR; + + // scaled stride distance + double sstride = stride / SCALING_FACTOR; + double t = 0; + + // process pairs of vertices as an edge, start with the last and + // first point + for (size_t i = pts.size() - 1, j = 0; j < pts.size(); i = j, ++j) { + // Get vertices and the direction vectors + const Point &a = pts[i], &b = pts[j]; + Vec2d dir = b.cast() - a.cast(); + double nrm = dir.norm(); + dir /= nrm; + Vec2d dirp(-dir(Y), dir(X)); + + // Insert start point + out.emplace_back(a); + + // dodge the start point, do not make sticks on the joins + while (t < sright) t += sright; + double tend = nrm - sright; + + while (t < tend) { // insert the stick on the polygon perimeter + + // calculate the stick rectangle vertices and insert them + // into the output. + Point p1 = a + (t * dir).cast(); + Point p2 = p1 + (sright * dirp).cast(); + Point p3 = p2 + (sbottom * dir).cast(); + Point p4 = p3 + (sright * -dirp).cast(); + out.insert(out.end(), {p1, p2, p3, p4}); + + // continue along the perimeter + t += sstride; + } + + t = t - nrm; + + // Insert edge endpoint + out.emplace_back(b); + } + + // move the new points + out.shrink_to_fit(); + pts.swap(out); + }; + + transf(poly.contour.points); + for (auto &h : poly.holes) transf(h.points); + + svg.draw(poly); + svg.Close(); +} + /// Only a debug function to generate top and bottom plates from a 2D shape. /// It is not used in the algorithm directly. inline Contour3D roofs(const ExPolygon& poly, coord_t z_distance) { @@ -467,41 +625,38 @@ inline Point centroid(Points& pp) { return c; } -inline Point centroid(const ExPolygon& poly) { - return poly.contour.centroid(); +inline Point centroid(const Polygon& poly) { + return poly.centroid(); } /// A fake concave hull that is constructed by connecting separate shapes /// with explicit bridges. Bridges are generated from each shape's centroid /// to the center of the "scene" which is the centroid calculated from the shape /// centroids (a star is created...) -ExPolygons concave_hull(const ExPolygons& polys, double max_dist_mm = 50, - ThrowOnCancel throw_on_cancel = [](){}) +Polygons concave_hull(const Polygons& polys, double max_dist_mm = 50, + ThrowOnCancel throw_on_cancel = [](){}) { namespace bgi = boost::geometry::index; - using SpatElement = std::pair; + using SpatElement = std::pair; using SpatIndex = bgi::rtree< SpatElement, bgi::rstar<16, 4> >; - if(polys.empty()) return ExPolygons(); + if(polys.empty()) return Polygons(); + + const double max_dist = mm(max_dist_mm); - ExPolygons punion = unify(polys); // could be redundant + Polygons punion = unify(polys); // could be redundant if(punion.size() == 1) return punion; // We get the centroids of all the islands in the 2D slice Points centroids; centroids.reserve(punion.size()); std::transform(punion.begin(), punion.end(), std::back_inserter(centroids), - [](const ExPolygon& poly) { return centroid(poly); }); - - - SpatIndex boxindex; unsigned idx = 0; - std::for_each(punion.begin(), punion.end(), - [&boxindex, &idx](const ExPolygon& expo) { - BoundingBox bb(expo); - boxindex.insert(std::make_pair(bb, idx++)); - }); - + [](const Polygon& poly) { return centroid(poly); }); + SpatIndex ctrindex; + unsigned idx = 0; + for(const Point &ct : centroids) ctrindex.insert(std::make_pair(ct, idx++)); + // Centroid of the centroids of islands. This is where the additional // connector sticks are routed. Point cc = centroid(centroids); @@ -511,25 +666,32 @@ ExPolygons concave_hull(const ExPolygons& polys, double max_dist_mm = 50, idx = 0; std::transform(centroids.begin(), centroids.end(), std::back_inserter(punion), - [&punion, &boxindex, cc, max_dist_mm, &idx, throw_on_cancel] + [¢roids, &ctrindex, cc, max_dist, &idx, throw_on_cancel] (const Point& c) { throw_on_cancel(); double dx = x(c) - x(cc), dy = y(c) - y(cc); double l = std::sqrt(dx * dx + dy * dy); double nx = dx / l, ny = dy / l; - double max_dist = mm(max_dist_mm); - - ExPolygon& expo = punion[idx++]; - BoundingBox querybb(expo); - - querybb.offset(max_dist); + + Point& ct = centroids[idx]; + std::vector result; - boxindex.query(bgi::intersects(querybb), std::back_inserter(result)); - if(result.size() <= 1) return ExPolygon(); + ctrindex.query(bgi::nearest(ct, 2), std::back_inserter(result)); - ExPolygon r; - auto& ctour = r.contour.points; + double dist = max_dist; + for (const SpatElement &el : result) + if (el.second != idx) { + dist = Line(el.first, ct).length(); + break; + } + + idx++; + + if (dist >= max_dist) return Polygon(); + + Polygon r; + auto& ctour = r.points; ctour.reserve(3); ctour.emplace_back(cc); @@ -538,7 +700,7 @@ ExPolygons concave_hull(const ExPolygons& polys, double max_dist_mm = 50, ctour.emplace_back(c + Point( -y(d), x(d) )); ctour.emplace_back(c + Point( y(d), -x(d) )); offset(r, mm(1)); - + return r; }); @@ -576,13 +738,14 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h, ExPolygons utmp = unify(tmp); - for(auto& o : utmp) { - auto&& smp = o.simplify(0.1/SCALING_FACTOR); + for(ExPolygon& o : utmp) { + auto&& smp = o.simplify(0.1/SCALING_FACTOR); // TODO: is this important? output.insert(output.end(), smp.begin(), smp.end()); } } -Contour3D create_base_pool(const ExPolygons &ground_layer, +Contour3D create_base_pool(const Polygons &ground_layer, + const ExPolygons &obj_self_pad = {}, const PoolConfig& cfg = PoolConfig()) { // for debugging: @@ -597,7 +760,7 @@ Contour3D create_base_pool(const ExPolygons &ground_layer, // serve as the bottom plate of the pad. We will offset this concave hull // and then offset back the result with clipper with rounding edges ON. This // trick will create a nice rounded pad shape. - ExPolygons concavehs = concave_hull(ground_layer, mergedist, cfg.throw_on_cancel); + Polygons concavehs = concave_hull(ground_layer, mergedist, cfg.throw_on_cancel); const double thickness = cfg.min_wall_thickness_mm; const double wingheight = cfg.min_wall_height_mm; @@ -617,42 +780,37 @@ Contour3D create_base_pool(const ExPolygons &ground_layer, Contour3D pool; - for(ExPolygon& concaveh : concavehs) { - if(concaveh.contour.points.empty()) return pool; - - // Get rid of any holes in the concave hull output. - concaveh.holes.clear(); + for(Polygon& concaveh : concavehs) { + if(concaveh.points.empty()) return pool; // Here lies the trick that does the smoothing only with clipper offset // calls. The offset is configured to round edges. Inner edges will // be rounded because we offset twice: ones to get the outer (top) plate // and again to get the inner (bottom) plate auto outer_base = concaveh; - outer_base.holes.clear(); offset(outer_base, s_safety_dist + s_wingdist + s_thickness); - ExPolygon bottom_poly = outer_base; - bottom_poly.holes.clear(); + ExPolygon bottom_poly; bottom_poly.contour = outer_base; offset(bottom_poly, -s_bottom_offs); // Punching a hole in the top plate for the cavity ExPolygon top_poly; ExPolygon middle_base; ExPolygon inner_base; - top_poly.contour = outer_base.contour; + top_poly.contour = outer_base; if(wingheight > 0) { - inner_base = outer_base; + inner_base.contour = outer_base; offset(inner_base, -(s_thickness + s_wingdist + s_eradius)); - middle_base = outer_base; + middle_base.contour = outer_base; offset(middle_base, -s_thickness); top_poly.holes.emplace_back(middle_base.contour); auto& tph = top_poly.holes.back().points; std::reverse(tph.begin(), tph.end()); } - ExPolygon ob = outer_base; double wh = 0; + ExPolygon ob; ob.contour = outer_base; double wh = 0; // now we will calculate the angle or portion of the circle from // pi/2 that will connect perfectly with the bottom plate. @@ -713,11 +871,56 @@ Contour3D create_base_pool(const ExPolygons &ground_layer, wh, -wingdist, thrcl)); } - // Now we need to triangulate the top and bottom plates as well as the - // cavity bottom plate which is the same as the bottom plate but it is - // elevated by the thickness. - pool.merge(triangulate_expolygon_3d(top_poly)); - pool.merge(triangulate_expolygon_3d(bottom_poly, -fullheight, true)); + if (cfg.embed_object) { + ExPolygons pp = diff_ex(to_polygons(bottom_poly), + to_polygons(obj_self_pad)); + + // Generate outer walls + auto fp = [](const Point &p, Point::coord_type z) { + return unscale(x(p), y(p), z); + }; + + auto straight_walls = [&pool, s_thickness, fp](const Polygon &cntr) + { + auto lines = cntr.lines(); + bool cclk = cntr.is_counter_clockwise(); + + for (auto &l : lines) { + auto s = coord_t(pool.points.size()); + pool.points.emplace_back(fp(l.a, -s_thickness)); + pool.points.emplace_back(fp(l.b, -s_thickness)); + pool.points.emplace_back(fp(l.a, 0)); + pool.points.emplace_back(fp(l.b, 0)); + + if(cclk) { + pool.indices.emplace_back(s + 3, s + 1, s); + pool.indices.emplace_back(s + 2, s + 3, s); + } else { + pool.indices.emplace_back(s, s + 1, s + 3); + pool.indices.emplace_back(s, s + 3, s + 2); + } + } + }; + + for (ExPolygon &ep : pp) { + pool.merge(triangulate_expolygon_3d(ep)); + pool.merge(triangulate_expolygon_3d(ep, -fullheight, true)); + + for (auto &h : ep.holes) straight_walls(h); + } + + // Skip the outer contour. TODO: make sure the first in the list + // IS the outer contour. + for (auto it = std::next(pp.begin()); it != pp.end(); ++it) + straight_walls(it->contour); + + } else { + // Now we need to triangulate the top and bottom plates as well as + // the cavity bottom plate which is the same as the bottom plate + // but it is elevated by the thickness. + pool.merge(triangulate_expolygon_3d(top_poly)); + pool.merge(triangulate_expolygon_3d(bottom_poly, -fullheight, true)); + } if(wingheight > 0) pool.merge(triangulate_expolygon_3d(inner_base, -wingheight)); @@ -727,8 +930,8 @@ Contour3D create_base_pool(const ExPolygons &ground_layer, return pool; } -void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, - const PoolConfig& cfg) +void create_base_pool(const Polygons &ground_layer, TriangleMesh& out, + const ExPolygons &holes, const PoolConfig& cfg) { @@ -738,7 +941,7 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, // std::fstream fout("pad_debug.obj", std::fstream::out); // if(fout.good()) pool.to_obj(fout); - out.merge(mesh(create_base_pool(ground_layer, cfg))); + out.merge(mesh(create_base_pool(ground_layer, holes, cfg))); } } diff --git a/src/libslic3r/SLA/SLABasePool.hpp b/src/libslic3r/SLA/SLABasePool.hpp index 3c88e58c85..0ed26b6e7d 100644 --- a/src/libslic3r/SLA/SLABasePool.hpp +++ b/src/libslic3r/SLA/SLABasePool.hpp @@ -8,7 +8,9 @@ namespace Slic3r { class ExPolygon; +class Polygon; using ExPolygons = std::vector; +using Polygons = std::vector; class TriangleMesh; @@ -23,12 +25,24 @@ void base_plate(const TriangleMesh& mesh, // input mesh float layerheight = 0.05f, // The sampling height ThrowOnCancel thrfn = [](){}); // Will be called frequently +// Function to cut tiny connector cavities for a given polygon. The input poly +// will be offsetted by "padding" and small rectangle shaped cavities will be +// inserted along the perimeter in every "stride" distance. The stick rectangles +// will have a with about "stick_width". The input dimensions are in world +// measure, not the scaled clipper units. +void offset_with_breakstick_holes(ExPolygon& poly, + double padding, + double stride, + double stick_width, + double penetration = 0.0); + struct PoolConfig { double min_wall_thickness_mm = 2; double min_wall_height_mm = 5; double max_merge_distance_mm = 50; double edge_radius_mm = 1; double wall_slope = std::atan(1.0); // Universal constant for Pi/4 + bool embed_object = false; ThrowOnCancel throw_on_cancel = [](){}; @@ -42,8 +56,9 @@ struct PoolConfig { }; /// Calculate the pool for the mesh for SLA printing -void create_base_pool(const ExPolygons& base_plate, +void create_base_pool(const Polygons& base_plate, TriangleMesh& output_mesh, + const ExPolygons& holes, const PoolConfig& = PoolConfig()); /// TODO: Currently the base plate of the pool will have half the height of the diff --git a/src/libslic3r/SLA/SLACommon.hpp b/src/libslic3r/SLA/SLACommon.hpp index 855802759e..2b72aa92c3 100644 --- a/src/libslic3r/SLA/SLACommon.hpp +++ b/src/libslic3r/SLA/SLACommon.hpp @@ -72,6 +72,7 @@ public: ~EigenMesh3D(); inline double ground_level() const { return m_ground_level; } + inline double& ground_level() { return m_ground_level; } inline const Eigen::MatrixXd& V() const { return m_V; } inline const Eigen::MatrixXi& F() const { return m_F; } @@ -149,6 +150,12 @@ public: #endif /* SLIC3R_SLA_NEEDS_WINDTREE */ double squared_distance(const Vec3d& p, int& i, Vec3d& c) const; + inline double squared_distance(const Vec3d &p) const + { + int i; + Vec3d c; + return squared_distance(p, i, c); + } }; diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index cb2001024d..43ffaed869 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -71,6 +72,8 @@ const double SupportConfig::normal_cutoff_angle = 150.0 * M_PI / 180.0; // The shortest distance of any support structure from the model surface const double SupportConfig::safety_distance_mm = 0.5; +const double SupportConfig::pillar_base_safety_distance_mm = 0.5; + const double SupportConfig::max_solo_pillar_height_mm = 15.0; const double SupportConfig::max_dual_pillar_height_mm = 35.0; const double SupportConfig::optimizer_rel_score_diff = 1e-6; @@ -413,7 +416,7 @@ struct Pillar { assert(steps > 0); height = jp(Z) - endp(Z); - if(height > 0) { // Endpoint is below the starting point + if(height > EPSILON) { // Endpoint is below the starting point // We just create a bridge geometry with the pillar parameters and // move the data. @@ -556,28 +559,47 @@ struct Pad { PoolConfig cfg; double zlevel = 0; - Pad() {} + Pad() = default; Pad(const TriangleMesh& object_support_mesh, - const ExPolygons& baseplate, + const ExPolygons& modelbase, double ground_level, const PoolConfig& pcfg) : cfg(pcfg), - zlevel(ground_level + - (sla::get_pad_fullheight(pcfg) - sla::get_pad_elevation(pcfg)) ) + zlevel(ground_level + + sla::get_pad_fullheight(pcfg) - + sla::get_pad_elevation(pcfg)) { - ExPolygons basep; + Polygons basep; cfg.throw_on_cancel(); - + // The 0.1f is the layer height with which the mesh is sampled and then // the layers are unified into one vector of polygons. - base_plate(object_support_mesh, basep, + ExPolygons platetmp; + base_plate(object_support_mesh, platetmp, float(cfg.min_wall_height_mm + cfg.min_wall_thickness_mm), 0.1f, pcfg.throw_on_cancel); + + // We don't need the holes for the base plate from the supports + for (const ExPolygon &bp : platetmp) basep.emplace_back(bp.contour); + for (const ExPolygon &bp : modelbase) basep.emplace_back(bp.contour); + + if(pcfg.embed_object) { + + auto modelbase_sticks = modelbase; + for(auto& poly : modelbase_sticks) + sla::offset_with_breakstick_holes( + poly, + SupportConfig::pillar_base_safety_distance_mm, // padding + 10, // stride (mm) + 0.3, // stick_width (mm) + 0.1); // penetration (mm) - for(auto& bp : baseplate) basep.emplace_back(bp); + create_base_pool(basep, tmesh, modelbase_sticks, cfg); + } else { + create_base_pool(basep, tmesh, {}, cfg); + } - create_base_pool(basep, tmesh, cfg); tmesh.translate(0, 0, float(zlevel)); } @@ -763,9 +785,9 @@ public: } const Pad& create_pad(const TriangleMesh& object_supports, - const ExPolygons& baseplate, + const ExPolygons& modelbase, const PoolConfig& cfg) { - m_pad = Pad(object_supports, baseplate, ground_level, cfg); + m_pad = Pad(object_supports, modelbase, ground_level, cfg); return m_pad; } @@ -1149,7 +1171,7 @@ class SLASupportTree::Algorithm { auto hr = m.query_ray_hit(p + sd*dir, dir); if(ins_check && hr.is_inside()) { - if(hr.distance() > r + sd) hits[i] = HitResult(0.0); + if(hr.distance() > 2 * r + sd) hits[i] = HitResult(0.0); else { // re-cast the ray from the outside of the object auto hr2 = @@ -1264,9 +1286,12 @@ class SLASupportTree::Algorithm { // For connecting a head to a nearby pillar. bool connect_to_nearpillar(const Head& head, long nearpillar_id) { - - auto nearpillar = [this, nearpillar_id]() { return m_result.pillar(nearpillar_id); }; - if(nearpillar().bridges > m_cfg.max_bridges_on_pillar) return false; + + auto nearpillar = [this, nearpillar_id]() { + return m_result.pillar(nearpillar_id); + }; + + if (nearpillar().bridges > m_cfg.max_bridges_on_pillar) return false; Vec3d headjp = head.junction_point(); Vec3d nearjp_u = nearpillar().startpoint(); @@ -1369,6 +1394,108 @@ class SLASupportTree::Algorithm { return nearest_id >= 0; } + + // This is a proxy function for pillar creation which will mind the gap + // between the pad and the model bottom in zero elevation mode. + void create_ground_pillar(const Vec3d &jp, + const Vec3d &sourcedir, + double radius, + int head_id = -1) + { + // People were killed for this number (seriously) + static const double SQR2 = std::sqrt(2.0); + + double gndlvl = m_result.ground_level; + Vec3d endp = {jp(X), jp(Y), gndlvl}; + double sd = SupportConfig::pillar_base_safety_distance_mm; + int pillar_id = -1; + double min_dist = sd + m_cfg.base_radius_mm + EPSILON; + double dist = 0; + bool can_add_base = true; + bool normal_mode = true; + + if (m_cfg.object_elevation_mm < EPSILON + && (dist = std::sqrt(m_mesh.squared_distance(endp))) < min_dist) { + // Get the distance from the mesh. This can be later optimized + // to get the distance in 2D plane because we are dealing with + // the ground level only. + + normal_mode = false; + double mv = min_dist - dist; + double azimuth = std::atan2(sourcedir(Y), sourcedir(X)); + double sinpolar = std::sin(PI - m_cfg.bridge_slope); + double cospolar = std::cos(PI - m_cfg.bridge_slope); + double cosazm = std::cos(azimuth); + double sinazm = std::sin(azimuth); + + auto dir = Vec3d(cosazm * sinpolar, sinazm * sinpolar, cospolar) + .normalized(); + + using namespace libnest2d::opt; + StopCriteria scr; + scr.stop_score = min_dist; + SubplexOptimizer solver(scr); + + auto result = solver.optimize_max( + [this, dir, jp, gndlvl](double mv) { + Vec3d endp = jp + SQR2 * mv * dir; + endp(Z) = gndlvl; + return std::sqrt(m_mesh.squared_distance(endp)); + }, + initvals(mv), bound(0.0, 2 * min_dist)); + + mv = std::get<0>(result.optimum); + endp = jp + std::sqrt(2) * mv * dir; + Vec3d pgnd = {endp(X), endp(Y), gndlvl}; + can_add_base = result.score > min_dist; + + // We have to check if the bridge is feasible. + if (bridge_mesh_intersect(jp, dir, radius) < (endp - jp).norm()) { + normal_mode = true; + endp = {jp(X), jp(Y), gndlvl}; + } + else { + // If the new endpoint is below ground, do not make a pillar + if (endp(Z) < gndlvl) + endp = endp - SQR2 * (gndlvl - endp(Z)) * dir; // back off + else { + Pillar &plr = m_result.add_pillar(endp, pgnd, radius); + + if (can_add_base) + plr.add_base(m_cfg.base_height_mm, + m_cfg.base_radius_mm); + + pillar_id = plr.id; + } + + m_result.add_bridge(jp, endp, radius); + m_result.add_junction(endp, radius); + + // Add a degenerated pillar and the bridge. + // The degenerate pillar will have zero length and it will + // prevent from queries of head_pillar() to have non-existing + // pillar when the head should have one. + if (head_id >= 0) + m_result.add_pillar(unsigned(head_id), jp, radius); + } + } + + if (normal_mode) { + Pillar &plr = head_id >= 0 + ? m_result.add_pillar(unsigned(head_id), + endp, + radius) + : m_result.add_pillar(jp, endp, radius); + + if (can_add_base) + plr.add_base(m_cfg.base_height_mm, m_cfg.base_radius_mm); + + pillar_id = plr.id; + } + + if(pillar_id >= 0) // Save the pillar endpoint in the spatial index + m_pillar_index.insert(endp, pillar_id); + } public: @@ -1447,9 +1574,9 @@ public: // (Quaternion::FromTwoVectors) and apply the rotation to the // arrow head. - double z = n(2); - double r = 1.0; // for normalized vector - double polar = std::acos(z / r); + double z = n(2); + double r = 1.0; // for normalized vector + double polar = std::acos(z / r); double azimuth = std::atan2(n(1), n(0)); // skip if the tilt is not sane @@ -1473,14 +1600,14 @@ public: std::cos(polar)).normalized(); // check available distance - double t = pinhead_mesh_intersect( - hp, // touching point - nn, // normal - pin_r, - m_cfg.head_back_radius_mm, - w); + EigenMesh3D::hit_result t + = pinhead_mesh_intersect(hp, // touching point + nn, // normal + pin_r, + m_cfg.head_back_radius_mm, + w); - if(t <= w) { + if(t.distance() <= w) { // Let's try to optimize this angle, there might be a // viable normal that doesn't collide with the model @@ -1523,12 +1650,17 @@ public: // save the verified and corrected normal m_support_nmls.row(fidx) = nn; - if(t > w) { - // mark the point for needing a head. - m_iheads.emplace_back(fidx); - } else if( polar >= 3*PI/4 ) { - // Headless supports do not tilt like the headed ones so - // the normal should point almost to the ground. + if (t.distance() > w) { + // Check distance from ground, we might have zero elevation. + if (hp(Z) + w * nn(Z) < m_result.ground_level) { + m_iheadless.emplace_back(fidx); + } else { + // mark the point for needing a head. + m_iheads.emplace_back(fidx); + } + } else if (polar >= 3 * PI / 4) { + // Headless supports do not tilt like the headed ones + // so the normal should point almost to the ground. m_iheadless.emplace_back(fidx); } } @@ -1594,16 +1726,22 @@ public: // from each other in the XY plane to not cross their pillar bases // These clusters of support points will join in one pillar, // possibly in their centroid support point. + auto pointfn = [this](unsigned i) { return m_result.head(i).junction_point(); }; - auto predicate = [this](const SpatElement& e1, const SpatElement& e2) { + + auto predicate = [this](const SpatElement &e1, + const SpatElement &e2) { double d2d = distance(to_2d(e1.first), to_2d(e2.first)); double d3d = distance(e1.first, e2.first); - return d2d < 2 * m_cfg.base_radius_mm && - d3d < m_cfg.max_bridge_length_mm; + return d2d < 2 * m_cfg.base_radius_mm + && d3d < m_cfg.max_bridge_length_mm; }; - m_pillar_clusters = cluster(ground_head_indices, pointfn, predicate, + + m_pillar_clusters = cluster(ground_head_indices, + pointfn, + predicate, m_cfg.max_bridges_on_pillar); } @@ -1615,7 +1753,7 @@ public: void routing_to_ground() { const double pradius = m_cfg.head_back_radius_mm; - const double gndlvl = m_result.ground_level; + // const double gndlvl = m_result.ground_level; ClusterEl cl_centroids; cl_centroids.reserve(m_pillar_clusters.size()); @@ -1648,13 +1786,8 @@ public: Head& h = m_result.head(hid); h.transform(); - Vec3d p = h.junction_point(); p(Z) = gndlvl; - auto& plr = m_result.add_pillar(hid, p, h.r_back_mm) - .add_base(m_cfg.base_height_mm, - m_cfg.base_radius_mm); - // Save the pillar endpoint and the pillar id in the spatial index - m_pillar_index.insert(plr.endpoint(), unsigned(plr.id)); + create_ground_pillar(h.junction_point(), h.dir, h.r_back_mm, h.id); } // now we will go through the clusters ones again and connect the @@ -1681,15 +1814,12 @@ public: !search_pillar_and_connect(sidehead)) { Vec3d pstart = sidehead.junction_point(); - Vec3d pend = Vec3d{pstart(X), pstart(Y), gndlvl}; + //Vec3d pend = Vec3d{pstart(X), pstart(Y), gndlvl}; // Could not find a pillar, create one - auto& pillar = m_result.add_pillar(unsigned(sidehead.id), - pend, pradius) - .add_base(m_cfg.base_height_mm, - m_cfg.base_radius_mm); - - // connects to ground, eligible for bridging - m_pillar_index.insert(pend, unsigned(pillar.id)); + create_ground_pillar(pstart, + sidehead.dir, + pradius, + sidehead.id); } } } @@ -1718,12 +1848,7 @@ public: m_result.add_bridge(hjp, endp, head.r_back_mm); m_result.add_junction(endp, head.r_back_mm); - auto groundp = endp; - groundp(Z) = m_result.ground_level; - auto& newpillar = m_result.add_pillar(endp, groundp, head.r_back_mm) - .add_base(m_cfg.base_height_mm, - m_cfg.base_radius_mm); - m_pillar_index.insert(groundp, unsigned(newpillar.id)); + this->create_ground_pillar(endp, dir, head.r_back_mm); }; std::vector modelpillars; @@ -1883,6 +2008,28 @@ public: m_pillar_index.insert(pillar.endpoint(), pillid); } } + + // Helper function for interconnect_pillars where pairs of already connected + // pillars should be checked for not to be processed again. This can be done + // in O(log) or even constant time with a set or an unordered set of hash + // values uniquely representing a pair of integers. The order of numbers + // within the pair should not matter, it has the same unique hash. + template static I pairhash(I a, I b) + { + using std::ceil; using std::log2; using std::max; using std::min; + + static_assert(std::is_integral::value, + "This function works only for integral types."); + + I g = min(a, b), l = max(a, b); + + auto bits_g = g ? int(ceil(log2(g))) : 0; + + // Assume the hash will fit into the output variable + assert((l ? (ceil(log2(l))) : 0) + bits_g < int(sizeof(I) * CHAR_BIT)); + + return (l << bits_g) + g; + } void interconnect_pillars() { // Now comes the algorithm that connects pillars with each other. @@ -1900,17 +2047,23 @@ public: double min_height_ratio = 0.5; std::set pairs; - + + // A function to connect one pillar with its neighbors. THe number of + // neighbors is given in the configuration. This function if called + // for every pillar in the pillar index. A pair of pillar will not + // be connected multiple times this is ensured by the 'pairs' set which + // remembers the processed pillar pairs auto cascadefn = [this, d, &pairs, min_height_ratio, H1] (const SpatElement& el) { - Vec3d qp = el.first; - - const Pillar& pillar = m_result.pillar(el.second); + Vec3d qp = el.first; // endpoint of the pillar + const Pillar& pillar = m_result.pillar(el.second); // actual pillar + + // Get the max number of neighbors a pillar should connect to unsigned neighbors = m_cfg.pillar_cascade_neighbors; - // connections are enough for one pillar + // connections are already enough for the pillar if(pillar.links >= neighbors) return; // Query all remaining points within reach @@ -1924,21 +2077,21 @@ public: return distance(e1.first, qp) < distance(e2.first, qp); }); - for(auto& re : qres) { + for(auto& re : qres) { // process the queried neighbors - if(re.second == el.second) continue; + if(re.second == el.second) continue; // Skip self auto a = el.second, b = re.second; - // I hope that the area of a square is never equal to its - // circumference - auto hashval = 2 * (a + b) + a * b; - + // Get unique hash for the given pair (order doesn't matter) + auto hashval = pairhash(a, b); + + // Search for the pair amongst the remembered pairs if(pairs.find(hashval) != pairs.end()) continue; const Pillar& neighborpillar = m_result.pillars()[re.second]; - // this neighbor is occupied + // this neighbor is occupied, skip if(neighborpillar.links >= neighbors) continue; if(interconnect(pillar, neighborpillar)) { @@ -1960,47 +2113,75 @@ public: if(pillar.links >= neighbors) break; } }; - + + // Run the cascade for the pillars in the index m_pillar_index.foreach(cascadefn); - + + // We would be done here if we could allow some pillars to not be + // connected with any neighbors. But this might leave the support tree + // unprintable. + // + // The current solution is to insert additional pillars next to these + // lonely pillars. One or even two additional pillar might get inserted + // depending on the length of the lonely pillar. + size_t pillarcount = m_result.pillars().size(); - + + // Again, go through all pillars, this time in the whole support tree + // not just the index. for(size_t pid = 0; pid < pillarcount; pid++) { auto pillar = [this, pid]() { return m_result.pillar(pid); }; - + + // Decide how many additional pillars will be needed: + unsigned needpillars = 0; - if(pillar().bridges > m_cfg.max_bridges_on_pillar) needpillars = 3; - else if(pillar().links < 2 && pillar().height > H2) { + if (pillar().bridges > m_cfg.max_bridges_on_pillar) + needpillars = 3; + else if (pillar().links < 2 && pillar().height > H2) { // Not enough neighbors to support this pillar needpillars = 2 - pillar().links; - } - else if(pillar().links < 1 && pillar().height > H1) { + } else if (pillar().links < 1 && pillar().height > H1) { // No neighbors could be found and the pillar is too long. needpillars = 1; } - // Search for new pillar locations - bool found = false; - double alpha = 0; // goes to 2Pi - double r = 2 * m_cfg.base_radius_mm; - Vec3d pillarsp = pillar().startpoint(); + // Search for new pillar locations: + + bool found = false; + double alpha = 0; // goes to 2Pi + double r = 2 * m_cfg.base_radius_mm; + Vec3d pillarsp = pillar().startpoint(); + + // temp value for starting point detection Vec3d sp(pillarsp(X), pillarsp(Y), pillarsp(Z) - r); - std::vector tv(needpillars, false); - std::vector spts(needpillars); + // A vector of bool for placement feasbility + std::vector canplace(needpillars, false); + std::vector spts(needpillars); // vector of starting points + + double gnd = m_result.ground_level; + double min_dist = SupportConfig::pillar_base_safety_distance_mm + + m_cfg.base_radius_mm + EPSILON; + while(!found && alpha < 2*PI) { - - for(unsigned n = 0; n < needpillars; n++) { - double a = alpha + n * PI/3; - Vec3d s = sp; + for (unsigned n = 0; n < needpillars; n++) { + double a = alpha + n * PI / 3; + Vec3d s = sp; s(X) += std::cos(a) * r; s(Y) += std::sin(a) * r; spts[n] = s; + + // Check the path vertically down auto hr = bridge_mesh_intersect(s, {0, 0, -1}, pillar().r); - tv[n] = std::isinf(hr.distance()); + + // If the path is clear, check for pillar base collisions + canplace[n] = std::isinf(hr.distance()) + && m_mesh.squared_distance({s(X), s(Y), gnd}) + > min_dist; } - found = std::all_of(tv.begin(), tv.end(), [](bool v){return v;}); + found = std::all_of(canplace.begin(), canplace.end(), + [](bool v) { return v; }); // 20 angles will be tried... alpha += 0.1 * PI; @@ -2010,7 +2191,7 @@ public: newpills.reserve(needpillars); if(found) for(unsigned n = 0; n < needpillars; n++) { - Vec3d s = spts[n]; double gnd = m_result.ground_level; + Vec3d s = spts[n]; Pillar p(s, Vec3d(s(X), s(Y), gnd), pillar().r); p.add_base(m_cfg.base_height_mm, m_cfg.base_radius_mm); @@ -2075,9 +2256,12 @@ public: // This is only for checking double idist = bridge_mesh_intersect(sph, dir, R, true); double dist = ray_mesh_intersect(sj, dir); + if (std::isinf(dist)) + dist = sph(Z) - m_result.ground_level - HWIDTH_MM; - if(std::isinf(idist) || std::isnan(idist) || idist < 2*R || - std::isinf(dist) || std::isnan(dist) || dist < 2*R) { + if(std::isnan(idist) || idist < 2*R || + std::isnan(dist) || dist < 2*R) + { BOOST_LOG_TRIVIAL(warning) << "Can not find route for headless" << " support stick at: " << sj.transpose(); @@ -2214,7 +2398,9 @@ bool SLASupportTree::generate(const std::vector &support_points, return pc == ABORT; } -SLASupportTree::SLASupportTree(): m_impl(new Impl()) {} +SLASupportTree::SLASupportTree(double gnd_lvl): m_impl(new Impl()) { + m_impl->ground_level = gnd_lvl; +} const TriangleMesh &SLASupportTree::merged_mesh() const { @@ -2226,7 +2412,7 @@ void SLASupportTree::merged_mesh_with_pad(TriangleMesh &outmesh) const { outmesh.merge(get_pad()); } -SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const +std::vector SLASupportTree::slice(float layerh, float init_layerh) const { if(init_layerh < 0) init_layerh = layerh; auto& stree = get(); @@ -2247,34 +2433,29 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const fullmesh.merge(get_pad()); fullmesh.require_shared_vertices(); // TriangleMeshSlicer needs this TriangleMeshSlicer slicer(&fullmesh); - SlicedSupports ret; + std::vector ret; slicer.slice(heights, 0.f, &ret, get().ctl().cancelfn); return ret; } -SlicedSupports SLASupportTree::slice(const std::vector &heights, +std::vector SLASupportTree::slice(const std::vector &heights, float cr) const { TriangleMesh fullmesh = m_impl->merged_mesh(); fullmesh.merge(get_pad()); fullmesh.require_shared_vertices(); // TriangleMeshSlicer needs this TriangleMeshSlicer slicer(&fullmesh); - SlicedSupports ret; + std::vector ret; slicer.slice(heights, cr, &ret, get().ctl().cancelfn); return ret; } -const TriangleMesh &SLASupportTree::add_pad(const SliceLayer& baseplate, +const TriangleMesh &SLASupportTree::add_pad(const ExPolygons& modelbase, const PoolConfig& pcfg) const { -// PoolConfig pcfg; -// pcfg.min_wall_thickness_mm = min_wall_thickness_mm; -// pcfg.min_wall_height_mm = min_wall_height_mm; -// pcfg.max_merge_distance_mm = max_merge_distance_mm; -// pcfg.edge_radius_mm = edge_radius_mm; - return m_impl->create_pad(merged_mesh(), baseplate, pcfg).tmesh; + return m_impl->create_pad(merged_mesh(), modelbase, pcfg).tmesh; } const TriangleMesh &SLASupportTree::get_pad() const diff --git a/src/libslic3r/SLA/SLASupportTree.hpp b/src/libslic3r/SLA/SLASupportTree.hpp index 66677e4d7a..1602316e8c 100644 --- a/src/libslic3r/SLA/SLASupportTree.hpp +++ b/src/libslic3r/SLA/SLASupportTree.hpp @@ -24,10 +24,11 @@ class TriangleMesh; class Model; class ModelInstance; class ModelObject; +class Polygon; class ExPolygon; -using SliceLayer = std::vector; -using SlicedSupports = std::vector; +using Polygons = std::vector; +using ExPolygons = std::vector; namespace sla { @@ -90,6 +91,10 @@ struct SupportConfig { // The shortest distance of any support structure from the model surface static const double safety_distance_mm; + + // The shortest distance between a pillar base perimeter from the model + // body. This is only useful when elevation is set to zero. + static const double pillar_base_safety_distance_mm; static const double max_solo_pillar_height_mm; static const double max_dual_pillar_height_mm; @@ -160,7 +165,7 @@ class SLASupportTree { public: - SLASupportTree(); + SLASupportTree(double ground_level = 0.0); SLASupportTree(const std::vector& pts, const EigenMesh3D& em, @@ -179,12 +184,16 @@ public: void merged_mesh_with_pad(TriangleMesh&) const; /// Get the sliced 2d layers of the support geometry. - SlicedSupports slice(float layerh, float init_layerh = -1.0) const; + std::vector slice(float layerh, float init_layerh = -1.0) const; - SlicedSupports slice(const std::vector&, float closing_radius) const; + std::vector slice(const std::vector&, float closing_radius) const; /// Adding the "pad" (base pool) under the supports - const TriangleMesh& add_pad(const SliceLayer& baseplate, + /// modelbase will be used according to the embed_object flag in PoolConfig. + /// If set, the plate will interpreted as the model's intrinsic pad. + /// Otherwise, the modelbase will be unified with the base plate calculated + /// from the supports. + const TriangleMesh& add_pad(const ExPolygons& modelbase, const PoolConfig& pcfg) const; /// Get the pad geometry diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index f6a1c429e5..f4599a2661 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -32,8 +32,8 @@ class SLAPrintObject::SupportData { public: sla::EigenMesh3D emesh; // index-triangle representation std::vector support_points; // all the support points (manual/auto) - SupportTreePtr support_tree_ptr; // the supports - SlicedSupports support_slices; // sliced supports + SupportTreePtr support_tree_ptr; // the supports + std::vector support_slices; // sliced supports inline SupportData(const TriangleMesh& trmesh): emesh(trmesh) {} }; @@ -471,7 +471,7 @@ void SLAPrint::set_task(const TaskParams ¶ms) int n_object_steps = int(params.to_object_step) + 1; if (n_object_steps == 0) - n_object_steps = (int)slaposCount; + n_object_steps = int(slaposCount); if (params.single_model_object.valid()) { // Find the print object to be processed with priority. @@ -486,7 +486,7 @@ void SLAPrint::set_task(const TaskParams ¶ms) // Find out whether the priority print object is being currently processed. bool running = false; for (int istep = 0; istep < n_object_steps; ++ istep) { - if (! print_object->m_stepmask[istep]) + if (! print_object->m_stepmask[size_t(istep)]) // Step was skipped, cancel. break; if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) { @@ -502,7 +502,7 @@ void SLAPrint::set_task(const TaskParams ¶ms) if (params.single_model_instance_only) { // Suppress all the steps of other instances. for (SLAPrintObject *po : m_objects) - for (int istep = 0; istep < (int)slaposCount; ++ istep) + for (size_t istep = 0; istep < slaposCount; ++ istep) po->m_stepmask[istep] = false; } else if (! running) { // Swap the print objects, so that the selected print_object is first in the row. @@ -512,15 +512,15 @@ void SLAPrint::set_task(const TaskParams ¶ms) } // and set the steps for the current object. for (int istep = 0; istep < n_object_steps; ++ istep) - print_object->m_stepmask[istep] = true; - for (int istep = n_object_steps; istep < (int)slaposCount; ++ istep) - print_object->m_stepmask[istep] = false; + print_object->m_stepmask[size_t(istep)] = true; + for (int istep = n_object_steps; istep < int(slaposCount); ++ istep) + print_object->m_stepmask[size_t(istep)] = false; } else { // Slicing all objects. bool running = false; for (SLAPrintObject *print_object : m_objects) for (int istep = 0; istep < n_object_steps; ++ istep) { - if (! print_object->m_stepmask[istep]) { + if (! print_object->m_stepmask[size_t(istep)]) { // Step may have been skipped. Restart. goto loop_end; } @@ -536,8 +536,8 @@ void SLAPrint::set_task(const TaskParams ¶ms) this->call_cancel_callback(); for (SLAPrintObject *po : m_objects) { for (int istep = 0; istep < n_object_steps; ++ istep) - po->m_stepmask[istep] = true; - for (int istep = n_object_steps; istep < (int)slaposCount; ++ istep) + po->m_stepmask[size_t(istep)] = true; + for (auto istep = size_t(n_object_steps); istep < slaposCount; ++ istep) po->m_stepmask[istep] = false; } } @@ -555,9 +555,9 @@ void SLAPrint::set_task(const TaskParams ¶ms) void SLAPrint::finalize() { for (SLAPrintObject *po : m_objects) - for (int istep = 0; istep < (int)slaposCount; ++ istep) + for (size_t istep = 0; istep < slaposCount; ++ istep) po->m_stepmask[istep] = true; - for (int istep = 0; istep < (int)slapsCount; ++ istep) + for (size_t istep = 0; istep < slapsCount; ++ istep) m_stepmask[istep] = true; } @@ -599,17 +599,29 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) { return scfg; } +bool use_builtin_pad(const SLAPrintObjectConfig& c) { + return c.support_object_elevation.getFloat() <= EPSILON && + c.pad_enable.getBool(); +} + sla::PoolConfig make_pool_config(const SLAPrintObjectConfig& c) { sla::PoolConfig pcfg; pcfg.min_wall_thickness_mm = c.pad_wall_thickness.getFloat(); - pcfg.wall_slope = c.pad_wall_slope.getFloat(); - pcfg.edge_radius_mm = c.pad_edge_radius.getFloat(); + pcfg.wall_slope = c.pad_wall_slope.getFloat() * PI / 180.0; + + // We do not support radius for now + pcfg.edge_radius_mm = 0.0; //c.pad_edge_radius.getFloat(); + pcfg.max_merge_distance_mm = c.pad_max_merge_distance.getFloat(); pcfg.min_wall_height_mm = c.pad_wall_height.getFloat(); + // set builtin pad implicitly ON + pcfg.embed_object = use_builtin_pad(c); + return pcfg; } + } std::string SLAPrint::validate() const @@ -632,8 +644,10 @@ std::string SLAPrint::validate() const cfg.head_width_mm + 2 * cfg.head_back_radius_mm - cfg.head_penetration_mm; + + double elv = cfg.object_elevation_mm; - if(supports_en && pinhead_width > cfg.object_elevation_mm) + if(supports_en && elv > EPSILON && elv < pinhead_width ) return L("Elevation is too low for object."); } @@ -818,23 +832,55 @@ void SLAPrint::process() BOOST_LOG_TRIVIAL(debug) << "Automatic support points: " << po.m_supportdata->support_points.size(); - // Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass the update status to GLGizmoSlaSupports - m_report_status(*this, -1, L("Generating support points"), SlicingStatus::RELOAD_SLA_SUPPORT_POINTS); + // Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass + // the update status to GLGizmoSlaSupports + m_report_status(*this, + -1, + L("Generating support points"), + SlicingStatus::RELOAD_SLA_SUPPORT_POINTS); } else { - // There are either some points on the front-end, or the user removed them on purpose. No calculation will be done. + // There are either some points on the front-end, or the user + // removed them on purpose. No calculation will be done. po.m_supportdata->support_points = po.transformed_support_points(); } + + // If the builtin pad mode is engaged, we have to filter out all the + // points that are on the bottom of the object + if(use_builtin_pad(po.m_config)) { + double gnd = po.m_supportdata->emesh.ground_level(); + auto & pts = po.m_supportdata->support_points; + + // get iterator to the reorganized vector end + auto endit = std::remove_if( + pts.begin(), + pts.end(), + [&po, gnd](const sla::SupportPoint &sp) { + double diff = std::abs(gnd - double(sp.pos(Z))); + return diff <= po.m_config.pad_wall_thickness.getFloat(); + }); + + // erase all elements after the new end + pts.erase(endit, pts.end()); + } }; // In this step we create the supports auto support_tree = [this, ostepd](SLAPrintObject& po) { if(!po.m_supportdata) return; + + sla::PoolConfig pcfg = make_pool_config(po.m_config); + + if(pcfg.embed_object) + po.m_supportdata->emesh.ground_level() += pcfg.min_wall_thickness_mm; if(!po.m_config.supports_enable.getBool()) { + // Generate empty support tree. It can still host a pad - po.m_supportdata->support_tree_ptr.reset(new SLASupportTree()); + po.m_supportdata->support_tree_ptr.reset( + new SLASupportTree(po.m_supportdata->emesh.ground_level())); + return; } @@ -856,7 +902,7 @@ void SLAPrint::process() ctl.stopcondition = [this](){ return canceled(); }; ctl.cancelfn = [this]() { throw_if_canceled(); }; - + po.m_supportdata->support_tree_ptr.reset( new SLASupportTree(po.m_supportdata->support_points, po.m_supportdata->emesh, scfg, ctl)); @@ -894,27 +940,26 @@ void SLAPrint::process() if(po.m_config.pad_enable.getBool()) { - double wt = po.m_config.pad_wall_thickness.getFloat(); - double h = po.m_config.pad_wall_height.getFloat(); - double md = po.m_config.pad_max_merge_distance.getFloat(); - // Radius is disabled for now... - double er = 0; // po.m_config.pad_edge_radius.getFloat(); - double tilt = po.m_config.pad_wall_slope.getFloat() * PI / 180.0; - double lh = po.m_config.layer_height.getFloat(); - double elevation = po.m_config.support_object_elevation.getFloat(); - if(!po.m_config.supports_enable.getBool()) elevation = 0; - sla::PoolConfig pcfg(wt, h, md, er, tilt); + // Get the distilled pad configuration from the config + sla::PoolConfig pcfg = make_pool_config(po.m_config); - ExPolygons bp; - double pad_h = sla::get_pad_fullheight(pcfg); - auto&& trmesh = po.transformed_mesh(); + ExPolygons bp; // This will store the base plate of the pad. + double pad_h = sla::get_pad_fullheight(pcfg); + const TriangleMesh &trmesh = po.transformed_mesh(); // This call can get pretty time consuming auto thrfn = [this](){ throw_if_canceled(); }; - if(elevation < pad_h) { - // we have to count with the model geometry for the base plate - sla::base_plate(trmesh, bp, float(pad_h), float(lh), thrfn); + if (!po.m_config.supports_enable.getBool() || pcfg.embed_object) { + // No support (thus no elevation) or zero elevation mode + // we sometimes call it "builtin pad" is enabled so we will + // get a sample from the bottom of the mesh and use it for pad + // creation. + sla::base_plate(trmesh, + bp, + float(pad_h), + float(po.m_config.layer_height.getFloat()), + thrfn); } pcfg.throw_on_cancel = thrfn; @@ -1647,7 +1692,7 @@ double SLAPrintObject::get_elevation() const { // will be in the future, we provide the config to the get_pad_elevation // method and we will have the correct value sla::PoolConfig pcfg = make_pool_config(m_config); - ret += sla::get_pad_elevation(pcfg); + if(!pcfg.embed_object) ret += sla::get_pad_elevation(pcfg); } return ret; @@ -1661,8 +1706,9 @@ double SLAPrintObject::get_current_elevation() const if(!has_supports && !has_pad) return 0; - else if(has_supports && !has_pad) + else if(has_supports && !has_pad) { return se ? m_config.support_object_elevation.getFloat() : 0; + } return get_elevation(); } @@ -1786,7 +1832,7 @@ std::vector SLAPrintObject::transformed_support_points() cons ret.reserve(spts.size()); for(sla::SupportPoint& sp : spts) { - Vec3d transformed_pos = trafo() * Vec3d(sp.pos(0), sp.pos(1), sp.pos(2)); + Vec3d transformed_pos = trafo() * Vec3d(double(sp.pos(0)), double(sp.pos(1)), double(sp.pos(2))); ret.emplace_back(transformed_pos(0), transformed_pos(1), transformed_pos(2), sp.head_front_radius, sp.is_new_island); } From b7e3ee0709c9ca3a6da49f4c933d1f079dba27a0 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 11 Jun 2019 15:35:09 +0200 Subject: [PATCH 02/28] Refactor, fix wall normals and gap detection. --- src/libslic3r/SLA/SLABasePool.cpp | 66 +++++++++++++++------------- src/libslic3r/SLA/SLASupportTree.cpp | 12 +++-- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp index 9b3f80f1a1..a882769f6f 100644 --- a/src/libslic3r/SLA/SLABasePool.cpp +++ b/src/libslic3r/SLA/SLABasePool.cpp @@ -857,6 +857,7 @@ Contour3D create_base_pool(const Polygons &ground_layer, if(wingheight > 0) { // Generate the smoothed edge geometry wh = 0; + ob = middle_base; if(s_eradius) pool.merge(round_edges(middle_base, r, phi - 90, // from tangent lines @@ -872,55 +873,58 @@ Contour3D create_base_pool(const Polygons &ground_layer, } if (cfg.embed_object) { - ExPolygons pp = diff_ex(to_polygons(bottom_poly), - to_polygons(obj_self_pad)); + ExPolygons bttms = diff_ex(to_polygons(bottom_poly), + to_polygons(obj_self_pad)); + + assert(!bttms.empty()); + + std::sort(bttms.begin(), bttms.end(), + [](const ExPolygon& e1, const ExPolygon& e2) { + return e1.contour.area() > e2.contour.area(); + }); + + if(wingheight > 0) inner_base.holes = bttms.front().holes; + else top_poly.holes = bttms.front().holes; - // Generate outer walls - auto fp = [](const Point &p, Point::coord_type z) { - return unscale(x(p), y(p), z); - }; - - auto straight_walls = [&pool, s_thickness, fp](const Polygon &cntr) - { + auto straight_walls = + [&pool](const Polygon &cntr, coord_t z_low, coord_t z_high) { + auto lines = cntr.lines(); - bool cclk = cntr.is_counter_clockwise(); for (auto &l : lines) { auto s = coord_t(pool.points.size()); - pool.points.emplace_back(fp(l.a, -s_thickness)); - pool.points.emplace_back(fp(l.b, -s_thickness)); - pool.points.emplace_back(fp(l.a, 0)); - pool.points.emplace_back(fp(l.b, 0)); + auto& pts = pool.points; + pts.emplace_back(unscale(l.a.x(), l.a.y(), z_low)); + pts.emplace_back(unscale(l.b.x(), l.b.y(), z_low)); + pts.emplace_back(unscale(l.a.x(), l.a.y(), z_high)); + pts.emplace_back(unscale(l.b.x(), l.b.y(), z_high)); - if(cclk) { - pool.indices.emplace_back(s + 3, s + 1, s); - pool.indices.emplace_back(s + 2, s + 3, s); - } else { - pool.indices.emplace_back(s, s + 1, s + 3); - pool.indices.emplace_back(s, s + 3, s + 2); - } + pool.indices.emplace_back(s, s + 1, s + 3); + pool.indices.emplace_back(s, s + 3, s + 2); } }; - - for (ExPolygon &ep : pp) { - pool.merge(triangulate_expolygon_3d(ep)); + + coord_t z_lo = -mm(fullheight), z_hi = -mm(wingheight); + for (ExPolygon &ep : bttms) { pool.merge(triangulate_expolygon_3d(ep, -fullheight, true)); - - for (auto &h : ep.holes) straight_walls(h); + for (auto &h : ep.holes) straight_walls(h, z_lo, z_hi); } - // Skip the outer contour. TODO: make sure the first in the list - // IS the outer contour. - for (auto it = std::next(pp.begin()); it != pp.end(); ++it) - straight_walls(it->contour); + // Skip the outer contour, triangulate the holes + for (auto it = std::next(bttms.begin()); it != bttms.end(); ++it) { + pool.merge(triangulate_expolygon_3d(*it, -wingheight)); + straight_walls(it->contour, z_lo, z_hi); + } } else { // Now we need to triangulate the top and bottom plates as well as // the cavity bottom plate which is the same as the bottom plate // but it is elevated by the thickness. - pool.merge(triangulate_expolygon_3d(top_poly)); + pool.merge(triangulate_expolygon_3d(bottom_poly, -fullheight, true)); } + + pool.merge(triangulate_expolygon_3d(top_poly)); if(wingheight > 0) pool.merge(triangulate_expolygon_3d(inner_base, -wingheight)); diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index 43ffaed869..9705e86004 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -2164,7 +2164,10 @@ public: m_cfg.base_radius_mm + EPSILON; while(!found && alpha < 2*PI) { - for (unsigned n = 0; n < needpillars; n++) { + for (unsigned n = 0; + n < needpillars && (!n || canplace[n - 1]); + n++) + { double a = alpha + n * PI / 3; Vec3d s = sp; s(X) += std::cos(a) * r; @@ -2173,11 +2176,12 @@ public: // Check the path vertically down auto hr = bridge_mesh_intersect(s, {0, 0, -1}, pillar().r); + Vec3d gndsp{s(X), s(Y), gnd}; // If the path is clear, check for pillar base collisions - canplace[n] = std::isinf(hr.distance()) - && m_mesh.squared_distance({s(X), s(Y), gnd}) - > min_dist; + canplace[n] = std::isinf(hr.distance()) && + std::sqrt(m_mesh.squared_distance(gndsp)) > + min_dist; } found = std::all_of(canplace.begin(), canplace.end(), From 6877c075dc14c24d8b036ade7cf540ce228dd061 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 11 Jun 2019 17:57:39 +0200 Subject: [PATCH 03/28] SPE-742: Parameter layer for zero elevation feature. --- src/libslic3r/PrintConfig.cpp | 47 ++++++++++++++- src/libslic3r/PrintConfig.hpp | 26 ++++++++- src/libslic3r/SLA/SLABasePool.hpp | 15 +++-- src/libslic3r/SLA/SLACommon.hpp | 6 +- src/libslic3r/SLA/SLASupportTree.cpp | 14 ++--- src/libslic3r/SLA/SLASupportTree.hpp | 11 ++-- src/libslic3r/SLAPrint.cpp | 31 +++++++--- src/slic3r/GUI/Preset.cpp | 4 ++ src/slic3r/GUI/Tab.cpp | 85 ++++++++++++++++++---------- 9 files changed, 179 insertions(+), 60 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 87ea263012..45ff20e789 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2490,6 +2490,19 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(1.0)); + + def = this->add("support_base_safety_distance", coFloat); + def->label = L("Support base safety distance"); + def->category = L("Supports"); + def->tooltip = L( + "The minimum distance of the pillar base from the model in mm. " + "Makes sense in zero elevation mode where a gap according " + "to this parameter is inserted between the model and the pad."); + def->sidetext = L("mm"); + def->min = 0; + def->max = 10; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(0.5)); def = this->add("support_critical_angle", coFloat); def->label = L("Critical angle"); @@ -2523,7 +2536,9 @@ void PrintConfigDef::init_sla_params() def = this->add("support_object_elevation", coFloat); def->label = L("Object elevation"); def->category = L("Supports"); - def->tooltip = L("How much the supports should lift up the supported object."); + def->tooltip = L("How much the supports should lift up the supported object. " + "If this value is zero, the bottom of the model geometry " + "will be considered as part of the pad."); def->sidetext = L("mm"); def->min = 0; def->max = 150; // This is the max height of print on SL1 @@ -2609,6 +2624,36 @@ void PrintConfigDef::init_sla_params() def->max = 90; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(45.0)); + + def = this->add("pad_object_connector_stride", coFloat); + def->label = L("Pad object connector stride"); + def->category = L("Pad"); + def->tooltip = L("Distance between two connector sticks between " + "the object pad and the generated pad."); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(10)); + + def = this->add("pad_object_connector_width", coFloat); + def->label = L("Pad object connector width"); + def->category = L("Pad"); + def->tooltip = L("The width of the connectors sticks which connect the " + "object pad and the generated pad."); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(0.3)); + + def = this->add("pad_object_connector_penetration", coFloat); + def->label = L("Pad object connector penetration"); + def->category = L("Pad"); + def->tooltip = L( + "How much should the tiny connectors penetrate into the model body."); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(0.3)); } void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 1da22b377f..e632e6946c 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -983,6 +983,9 @@ public: // The height of the pillar base cone in mm. ConfigOptionFloat support_base_height /*= 1.0*/; + + // The minimum distance of the pillar base from the model in mm. + ConfigOptionFloat support_base_safety_distance; /*= 1.0*/; // The default angle for connecting support sticks and junctions. ConfigOptionFloat support_critical_angle /*= 45*/; @@ -996,7 +999,7 @@ public: // The elevation in Z direction upwards. This is the space between the pad // and the model object's bounding box bottom. Units in mm. ConfigOptionFloat support_object_elevation /*= 5.0*/; - + /////// Following options influence automatic support points placement: ConfigOptionInt support_points_density_relative; ConfigOptionFloat support_points_minimal_distance; @@ -1021,6 +1024,23 @@ public: // The slope of the pad wall... ConfigOptionFloat pad_wall_slope; + + // ///////////////////////////////////////////////////////////////////////// + // Zero elevation mode parameters: + // - The object pad will be derived from the the model geometry. + // - There will be a gap between the object pad and the generated pad + // according to the support_base_safety_distance parameter. + // - The two pads will be connected with tiny connector sticks + // ///////////////////////////////////////////////////////////////////////// + + // How far to place the connector sticks on the object pad perimeter + ConfigOptionFloat pad_object_connector_stride; + + // The width of the connectors sticks + ConfigOptionFloat pad_object_connector_width; + + // How much should the tiny connectors penetrate into the model body + ConfigOptionFloat pad_object_connector_penetration; protected: void initialize(StaticCacheBase &cache, const char *base_ptr) @@ -1038,6 +1058,7 @@ protected: OPT_PTR(support_pillar_widening_factor); OPT_PTR(support_base_diameter); OPT_PTR(support_base_height); + OPT_PTR(support_base_safety_distance); OPT_PTR(support_critical_angle); OPT_PTR(support_max_bridge_length); OPT_PTR(support_max_pillar_link_distance); @@ -1050,6 +1071,9 @@ protected: OPT_PTR(pad_max_merge_distance); OPT_PTR(pad_edge_radius); OPT_PTR(pad_wall_slope); + OPT_PTR(pad_object_connector_stride); + OPT_PTR(pad_object_connector_width); + OPT_PTR(pad_object_connector_penetration); } }; diff --git a/src/libslic3r/SLA/SLABasePool.hpp b/src/libslic3r/SLA/SLABasePool.hpp index 0ed26b6e7d..129f7ccd46 100644 --- a/src/libslic3r/SLA/SLABasePool.hpp +++ b/src/libslic3r/SLA/SLABasePool.hpp @@ -42,7 +42,14 @@ struct PoolConfig { double max_merge_distance_mm = 50; double edge_radius_mm = 1; double wall_slope = std::atan(1.0); // Universal constant for Pi/4 - bool embed_object = false; + struct EmbedObject { + double object_gap_mm = 0.5; + double stick_stride_mm = 10; + double stick_width_mm = 0.3; + double stick_penetration_mm = 0.1; + bool enabled = false; + operator bool() const { return enabled; } + } embed_object; ThrowOnCancel throw_on_cancel = [](){}; @@ -61,11 +68,7 @@ void create_base_pool(const Polygons& base_plate, const ExPolygons& holes, const PoolConfig& = PoolConfig()); -/// TODO: Currently the base plate of the pool will have half the height of the -/// whole pool. So the carved out space has also half the height. This is not -/// a particularly elegant solution, the thickness should be exactly -/// min_wall_thickness and it should be corrected in the future. This method -/// will return the correct value for further processing. +/// Returns the elevation needed for compensating the pad. inline double get_pad_elevation(const PoolConfig& cfg) { return cfg.min_wall_thickness_mm; } diff --git a/src/libslic3r/SLA/SLACommon.hpp b/src/libslic3r/SLA/SLACommon.hpp index 2b72aa92c3..2666f2a9c3 100644 --- a/src/libslic3r/SLA/SLACommon.hpp +++ b/src/libslic3r/SLA/SLACommon.hpp @@ -60,7 +60,7 @@ class EigenMesh3D { Eigen::MatrixXd m_V; Eigen::MatrixXi m_F; - double m_ground_level = 0; + double m_ground_level = 0, m_gnd_offset = 0; std::unique_ptr m_aabb; public: @@ -71,8 +71,8 @@ public: ~EigenMesh3D(); - inline double ground_level() const { return m_ground_level; } - inline double& ground_level() { return m_ground_level; } + inline double ground_level() const { return m_ground_level + m_gnd_offset; } + inline void ground_level_offset(double o) { m_gnd_offset = o; } inline const Eigen::MatrixXd& V() const { return m_V; } inline const Eigen::MatrixXi& F() const { return m_F; } diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index 9705e86004..b9f2cc14e5 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -72,8 +72,6 @@ const double SupportConfig::normal_cutoff_angle = 150.0 * M_PI / 180.0; // The shortest distance of any support structure from the model surface const double SupportConfig::safety_distance_mm = 0.5; -const double SupportConfig::pillar_base_safety_distance_mm = 0.5; - const double SupportConfig::max_solo_pillar_height_mm = 15.0; const double SupportConfig::max_dual_pillar_height_mm = 35.0; const double SupportConfig::optimizer_rel_score_diff = 1e-6; @@ -590,10 +588,10 @@ struct Pad { for(auto& poly : modelbase_sticks) sla::offset_with_breakstick_holes( poly, - SupportConfig::pillar_base_safety_distance_mm, // padding - 10, // stride (mm) - 0.3, // stick_width (mm) - 0.1); // penetration (mm) + pcfg.embed_object.object_gap_mm, // padding + pcfg.embed_object.stick_stride_mm, + pcfg.embed_object.stick_width_mm, + pcfg.embed_object.stick_penetration_mm); create_base_pool(basep, tmesh, modelbase_sticks, cfg); } else { @@ -1407,7 +1405,7 @@ class SLASupportTree::Algorithm { double gndlvl = m_result.ground_level; Vec3d endp = {jp(X), jp(Y), gndlvl}; - double sd = SupportConfig::pillar_base_safety_distance_mm; + double sd = m_cfg.pillar_base_safety_distance_mm; int pillar_id = -1; double min_dist = sd + m_cfg.base_radius_mm + EPSILON; double dist = 0; @@ -2160,7 +2158,7 @@ public: std::vector spts(needpillars); // vector of starting points double gnd = m_result.ground_level; - double min_dist = SupportConfig::pillar_base_safety_distance_mm + + double min_dist = m_cfg.pillar_base_safety_distance_mm + m_cfg.base_radius_mm + EPSILON; while(!found && alpha < 2*PI) { diff --git a/src/libslic3r/SLA/SLASupportTree.hpp b/src/libslic3r/SLA/SLASupportTree.hpp index 1602316e8c..93627d10c2 100644 --- a/src/libslic3r/SLA/SLASupportTree.hpp +++ b/src/libslic3r/SLA/SLASupportTree.hpp @@ -81,6 +81,10 @@ struct SupportConfig { // The elevation in Z direction upwards. This is the space between the pad // and the model object's bounding box bottom. double object_elevation_mm = 10; + + // The shortest distance between a pillar base perimeter from the model + // body. This is only useful when elevation is set to zero. + const double pillar_base_safety_distance_mm = 0.5; // ///////////////////////////////////////////////////////////////////////// // Compile time configuration values (candidates for runtime) @@ -91,10 +95,6 @@ struct SupportConfig { // The shortest distance of any support structure from the model surface static const double safety_distance_mm; - - // The shortest distance between a pillar base perimeter from the model - // body. This is only useful when elevation is set to zero. - static const double pillar_base_safety_distance_mm; static const double max_solo_pillar_height_mm; static const double max_dual_pillar_height_mm; @@ -186,7 +186,8 @@ public: /// Get the sliced 2d layers of the support geometry. std::vector slice(float layerh, float init_layerh = -1.0) const; - std::vector slice(const std::vector&, float closing_radius) const; + std::vector slice(const std::vector &, + float closing_radius) const; /// Adding the "pad" (base pool) under the supports /// modelbase will be used according to the embed_object flag in PoolConfig. diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index f4599a2661..14cf2b6ff4 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -599,9 +599,20 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) { return scfg; } -bool use_builtin_pad(const SLAPrintObjectConfig& c) { - return c.support_object_elevation.getFloat() <= EPSILON && - c.pad_enable.getBool(); +sla::PoolConfig::EmbedObject use_builtin_pad(const SLAPrintObjectConfig& c) { + sla::PoolConfig::EmbedObject ret; + + ret.enabled = c.support_object_elevation.getFloat() <= EPSILON && + c.pad_enable.getBool(); + + if(ret.enabled) { + ret.object_gap_mm = c.support_base_safety_distance.getFloat(); + ret.stick_width_mm = c.pad_object_connector_width.getFloat(); + ret.stick_stride_mm = c.pad_object_connector_stride.getFloat(); + ret.stick_width_mm = c.pad_object_connector_penetration.getFloat(); + } + + return ret; } sla::PoolConfig make_pool_config(const SLAPrintObjectConfig& c) { @@ -871,9 +882,10 @@ void SLAPrint::process() if(!po.m_supportdata) return; sla::PoolConfig pcfg = make_pool_config(po.m_config); - - if(pcfg.embed_object) - po.m_supportdata->emesh.ground_level() += pcfg.min_wall_thickness_mm; + + if (pcfg.embed_object) + po.m_supportdata->emesh.ground_level_offset( + pcfg.min_wall_thickness_mm); if(!po.m_config.supports_enable.getBool()) { @@ -1635,13 +1647,18 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector& Preset::sla_print_options() "support_pillar_widening_factor", "support_base_diameter", "support_base_height", + "support_base_safety_distance", "support_critical_angle", "support_max_bridge_length", "support_max_pillar_link_distance", @@ -474,6 +475,9 @@ const std::vector& Preset::sla_print_options() "pad_max_merge_distance", "pad_edge_radius", "pad_wall_slope", + "pad_object_connector_stride", + "pad_object_connector_width", + "pad_object_connector_penetration", "output_filename_format", "default_sla_print_profile", "compatible_printers", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 6cd270e5b3..8ca47f1b11 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3481,6 +3481,7 @@ void TabSLAPrint::build() // optgroup->append_single_option_line("support_pillar_widening_factor"); optgroup->append_single_option_line("support_base_diameter"); optgroup->append_single_option_line("support_base_height"); + optgroup->append_single_option_line("support_base_safety_distance"); optgroup->append_single_option_line("support_object_elevation"); optgroup = page->new_optgroup(_(L("Connection of the support sticks and junctions"))); @@ -3501,7 +3502,11 @@ void TabSLAPrint::build() // TODO: Disabling this parameter for the beta release // optgroup->append_single_option_line("pad_edge_radius"); optgroup->append_single_option_line("pad_wall_slope"); - + + optgroup->append_single_option_line("pad_object_connector_stride"); + optgroup->append_single_option_line("pad_object_connector_width"); + optgroup->append_single_option_line("pad_object_connector_penetration"); + page = add_options_page(_(L("Advanced")), "wrench"); optgroup = page->new_optgroup(_(L("Slicing"))); optgroup->append_single_option_line("slice_closing_radius"); @@ -3541,42 +3546,64 @@ void TabSLAPrint::reload_config() void TabSLAPrint::update() { - if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF) + if (m_preset_bundle->printers.get_selected_preset().printer_technology() + == ptFFF) return; // #ys_FIXME -// #ys_FIXME - m_update_cnt++; + // #ys_FIXME + m_update_cnt++; - double head_penetration = m_config->opt_float("support_head_penetration"); - double head_width = m_config->opt_float("support_head_width"); - if(head_penetration > head_width) { - wxString msg_text = _(L("Head penetration should not be greater than the head width.")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Invalid Head penetration")), wxICON_WARNING | wxOK); - DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_OK) { - new_conf.set_key_value("support_head_penetration", new ConfigOptionFloat(head_width)); - } + double head_penetration = m_config->opt_float("support_head_penetration"); + double head_width = m_config->opt_float("support_head_width"); + if (head_penetration > head_width) { + wxString msg_text = _( + L("Head penetration should not be greater than the head width.")); - load_config(new_conf); - } + auto dialog = new wxMessageDialog(parent(), + msg_text, + _(L("Invalid Head penetration")), + wxICON_WARNING | wxOK); - double pinhead_d = m_config->opt_float("support_head_front_diameter"); - double pillar_d = m_config->opt_float("support_pillar_diameter"); - if(pinhead_d > pillar_d) { - wxString msg_text = _(L("Pinhead diameter should be smaller than the pillar diameter.")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Invalid pinhead diameter")), wxICON_WARNING | wxOK); - DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_OK) { - new_conf.set_key_value("support_head_front_diameter", new ConfigOptionFloat(pillar_d / 2.0)); - } + DynamicPrintConfig new_conf = *m_config; + if (dialog->ShowModal() == wxID_OK) { + new_conf.set_key_value("support_head_penetration", + new ConfigOptionFloat(head_width)); + } - load_config(new_conf); - } + load_config(new_conf); + } - m_update_cnt--; + double pinhead_d = m_config->opt_float("support_head_front_diameter"); + double pillar_d = m_config->opt_float("support_pillar_diameter"); + if (pinhead_d > pillar_d) { + wxString msg_text = _(L( + "Pinhead diameter should be smaller than the pillar diameter.")); - if (m_update_cnt == 0) - wxGetApp().mainframe->on_config_changed(m_config); + auto dialog = new wxMessageDialog(parent(), + msg_text, + _(L("Invalid pinhead diameter")), + wxICON_WARNING | wxOK); + + DynamicPrintConfig new_conf = *m_config; + if (dialog->ShowModal() == wxID_OK) { + new_conf.set_key_value("support_head_front_diameter", + new ConfigOptionFloat(pillar_d / 2.0)); + } + + load_config(new_conf); + } + + // if(m_config->opt_float("support_object_elevation") < EPSILON && + // m_config->opt_bool("pad_enable")) { + // // TODO: disable editding of: + // // pad_object_connector_stride + // // pad_object_connector_width + // // pad_object_connector_penetration + // } + + m_update_cnt--; + + if (m_update_cnt == 0) wxGetApp().mainframe->on_config_changed(m_config); } } // GUI From c80aae1bdb3d87a2a27c973232eda33f9444f153 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 11 Jun 2019 18:19:58 +0200 Subject: [PATCH 04/28] Fixes for the parameter layer - Elevation value satisfied with no supports as well - Removed debug svg writing - Gap and sticks made optional in zero elevation pad. --- src/libslic3r/SLA/SLABasePool.cpp | 24 ++++++++++++++---------- src/libslic3r/SLA/SLASupportTree.hpp | 2 +- src/libslic3r/SLAPrint.cpp | 12 ++++++------ 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp index a882769f6f..62a078cb73 100644 --- a/src/libslic3r/SLA/SLABasePool.cpp +++ b/src/libslic3r/SLA/SLABasePool.cpp @@ -9,7 +9,7 @@ // For debugging: // #include // #include -#include "SVG.hpp" +// #include "SVG.hpp" namespace Slic3r { namespace sla { @@ -390,11 +390,13 @@ void offset_with_breakstick_holes(ExPolygon& poly, double penetration) { // We do the basic offsetting first - const bool dont_round_edges = false; - offset(poly, coord_t(padding / SCALING_FACTOR), dont_round_edges); + static const bool dont_round_edges = false; + + if(padding > 0.0) + offset(poly, coord_t(padding / SCALING_FACTOR), dont_round_edges); - SVG svg("bridgestick_plate.svg"); - svg.draw(poly); + // SVG svg("bridgestick_plate.svg"); + // svg.draw(poly); auto transf = [stick_width, penetration, padding, stride](Points &pts) { // The connector stick will be a small rectangle with dimensions @@ -453,12 +455,14 @@ void offset_with_breakstick_holes(ExPolygon& poly, out.shrink_to_fit(); pts.swap(out); }; - - transf(poly.contour.points); - for (auto &h : poly.holes) transf(h.points); - svg.draw(poly); - svg.Close(); + if(stride > 0.0 && stick_width > 0.0 && padding > 0.0) { + transf(poly.contour.points); + for (auto &h : poly.holes) transf(h.points); + } + + // svg.draw(poly); + // svg.Close(); } /// Only a debug function to generate top and bottom plates from a 2D shape. diff --git a/src/libslic3r/SLA/SLASupportTree.hpp b/src/libslic3r/SLA/SLASupportTree.hpp index 93627d10c2..8602d8a46d 100644 --- a/src/libslic3r/SLA/SLASupportTree.hpp +++ b/src/libslic3r/SLA/SLASupportTree.hpp @@ -84,7 +84,7 @@ struct SupportConfig { // The shortest distance between a pillar base perimeter from the model // body. This is only useful when elevation is set to zero. - const double pillar_base_safety_distance_mm = 0.5; + double pillar_base_safety_distance_mm = 0.5; // ///////////////////////////////////////////////////////////////////////// // Compile time configuration values (candidates for runtime) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 14cf2b6ff4..78bd502203 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -595,7 +595,10 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) { scfg.pillar_widening_factor = c.support_pillar_widening_factor.getFloat(); scfg.base_radius_mm = 0.5*c.support_base_diameter.getFloat(); scfg.base_height_mm = c.support_base_height.getFloat(); - + scfg.pillar_base_safety_distance_mm = + c.support_base_safety_distance.getFloat() < EPSILON ? + scfg.safety_distance_mm : c.support_base_safety_distance.getFloat(); + return scfg; } @@ -1699,10 +1702,8 @@ bool SLAPrintObject::invalidate_all_steps() } double SLAPrintObject::get_elevation() const { - bool se = m_config.supports_enable.getBool(); - double ret = se? m_config.support_object_elevation.getFloat() : 0; + double ret = m_config.support_object_elevation.getFloat(); - // if the pad is enabled, then half of the pad height is its base plate if(m_config.pad_enable.getBool()) { // Normally the elevation for the pad itself would be the thickness of // its walls but currently it is half of its thickness. Whatever it @@ -1717,14 +1718,13 @@ double SLAPrintObject::get_elevation() const { double SLAPrintObject::get_current_elevation() const { - bool se = m_config.supports_enable.getBool(); bool has_supports = is_step_done(slaposSupportTree); bool has_pad = is_step_done(slaposBasePool); if(!has_supports && !has_pad) return 0; else if(has_supports && !has_pad) { - return se ? m_config.support_object_elevation.getFloat() : 0; + return m_config.support_object_elevation.getFloat(); } return get_elevation(); From 12396c3051a7abe26d33afe244bcabc938653e3e Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 12 Jun 2019 13:15:42 +0200 Subject: [PATCH 05/28] Fine tuning parameters and fixing pad wings when greater gaps are used. --- src/libslic3r/PrintConfig.cpp | 15 +++++++++++++-- src/libslic3r/PrintConfig.hpp | 4 ++++ src/libslic3r/SLA/SLABasePool.cpp | 22 ++++++++-------------- src/libslic3r/SLA/SLABasePool.hpp | 10 +++++----- src/libslic3r/SLA/SLASupportTree.cpp | 18 +++++++++++++----- src/libslic3r/SLAPrint.cpp | 26 +++++++++++++++++++------- src/slic3r/GUI/Preset.cpp | 1 + src/slic3r/GUI/Tab.cpp | 1 + 8 files changed, 64 insertions(+), 33 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 45ff20e789..377d53bef4 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2502,7 +2502,7 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->max = 10; def->mode = comExpert; - def->set_default_value(new ConfigOptionFloat(0.5)); + def->set_default_value(new ConfigOptionFloat(1)); def = this->add("support_critical_angle", coFloat); def->label = L("Critical angle"); @@ -2625,6 +2625,17 @@ void PrintConfigDef::init_sla_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(45.0)); + def = this->add("pad_object_gap", coFloat); + def->label = L("Pad object gap"); + def->category = L("Pad"); + def->tooltip = L("The gap between the object bottom and the generated " + "pad in zero elevation mode."); + def->sidetext = L("mm"); + def->min = 0; + def->max = 10; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(1)); + def = this->add("pad_object_connector_stride", coFloat); def->label = L("Pad object connector stride"); def->category = L("Pad"); @@ -2643,7 +2654,7 @@ void PrintConfigDef::init_sla_params() def->sidetext = L("mm"); def->min = 0; def->mode = comExpert; - def->set_default_value(new ConfigOptionFloat(0.3)); + def->set_default_value(new ConfigOptionFloat(0.5)); def = this->add("pad_object_connector_penetration", coFloat); def->label = L("Pad object connector penetration"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index e632e6946c..b5ddc4f137 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1033,6 +1033,9 @@ public: // - The two pads will be connected with tiny connector sticks // ///////////////////////////////////////////////////////////////////////// + // This is the gap between the object bottom and the generated pad + ConfigOptionFloat pad_object_gap; + // How far to place the connector sticks on the object pad perimeter ConfigOptionFloat pad_object_connector_stride; @@ -1071,6 +1074,7 @@ protected: OPT_PTR(pad_max_merge_distance); OPT_PTR(pad_edge_radius); OPT_PTR(pad_wall_slope); + OPT_PTR(pad_object_gap); OPT_PTR(pad_object_connector_stride); OPT_PTR(pad_object_connector_width); OPT_PTR(pad_object_connector_penetration); diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp index 62a078cb73..4a1259b5a4 100644 --- a/src/libslic3r/SLA/SLABasePool.cpp +++ b/src/libslic3r/SLA/SLABasePool.cpp @@ -383,18 +383,12 @@ Polygons unify(const Polygons& shapes) { // inserted along the perimeter in every "stride" distance. The stick rectangles // will have a with about "stick_width". The input dimensions are in world // measure, not the scaled clipper units. -void offset_with_breakstick_holes(ExPolygon& poly, - double padding, - double stride, - double stick_width, - double penetration) -{ - // We do the basic offsetting first - static const bool dont_round_edges = false; - - if(padding > 0.0) - offset(poly, coord_t(padding / SCALING_FACTOR), dont_round_edges); - +void breakstick_holes(ExPolygon& poly, + double padding, + double stride, + double stick_width, + double penetration) +{ // SVG svg("bridgestick_plate.svg"); // svg.draw(poly); @@ -428,8 +422,8 @@ void offset_with_breakstick_holes(ExPolygon& poly, out.emplace_back(a); // dodge the start point, do not make sticks on the joins - while (t < sright) t += sright; - double tend = nrm - sright; + while (t < sbottom) t += sbottom; + double tend = nrm - sbottom; while (t < tend) { // insert the stick on the polygon perimeter diff --git a/src/libslic3r/SLA/SLABasePool.hpp b/src/libslic3r/SLA/SLABasePool.hpp index 129f7ccd46..8aa4f5f412 100644 --- a/src/libslic3r/SLA/SLABasePool.hpp +++ b/src/libslic3r/SLA/SLABasePool.hpp @@ -30,11 +30,11 @@ void base_plate(const TriangleMesh& mesh, // input mesh // inserted along the perimeter in every "stride" distance. The stick rectangles // will have a with about "stick_width". The input dimensions are in world // measure, not the scaled clipper units. -void offset_with_breakstick_holes(ExPolygon& poly, - double padding, - double stride, - double stick_width, - double penetration = 0.0); +void breakstick_holes(ExPolygon &poly, + double padding, + double stride, + double stick_width, + double penetration = 0.0); struct PoolConfig { double min_wall_thickness_mm = 2; diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index b9f2cc14e5..ba14b1811f 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -578,23 +578,31 @@ struct Pad { float(cfg.min_wall_height_mm + cfg.min_wall_thickness_mm), 0.1f, pcfg.throw_on_cancel); - // We don't need the holes for the base plate from the supports for (const ExPolygon &bp : platetmp) basep.emplace_back(bp.contour); - for (const ExPolygon &bp : modelbase) basep.emplace_back(bp.contour); + if(pcfg.embed_object) { - auto modelbase_sticks = modelbase; - for(auto& poly : modelbase_sticks) - sla::offset_with_breakstick_holes( + + if (pcfg.embed_object.object_gap_mm > 0.0) + modelbase_sticks + = offset_ex(modelbase_sticks, + coord_t(pcfg.embed_object.object_gap_mm + / SCALING_FACTOR)); + + for(auto& poly : modelbase_sticks) { + basep.emplace_back(poly); + sla::breakstick_holes( poly, pcfg.embed_object.object_gap_mm, // padding pcfg.embed_object.stick_stride_mm, pcfg.embed_object.stick_width_mm, pcfg.embed_object.stick_penetration_mm); + } create_base_pool(basep, tmesh, modelbase_sticks, cfg); } else { + for (const ExPolygon &bp : modelbase) basep.emplace_back(bp.contour); create_base_pool(basep, tmesh, {}, cfg); } diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 78bd502203..bff4c95876 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -602,17 +602,18 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) { return scfg; } -sla::PoolConfig::EmbedObject use_builtin_pad(const SLAPrintObjectConfig& c) { +sla::PoolConfig::EmbedObject builtin_pad_cfg(const SLAPrintObjectConfig& c) { sla::PoolConfig::EmbedObject ret; ret.enabled = c.support_object_elevation.getFloat() <= EPSILON && c.pad_enable.getBool(); if(ret.enabled) { - ret.object_gap_mm = c.support_base_safety_distance.getFloat(); - ret.stick_width_mm = c.pad_object_connector_width.getFloat(); - ret.stick_stride_mm = c.pad_object_connector_stride.getFloat(); - ret.stick_width_mm = c.pad_object_connector_penetration.getFloat(); + ret.object_gap_mm = c.pad_object_gap.getFloat(); + ret.stick_width_mm = c.pad_object_connector_width.getFloat(); + ret.stick_stride_mm = c.pad_object_connector_stride.getFloat(); + ret.stick_penetration_mm = c.pad_object_connector_penetration + .getFloat(); } return ret; @@ -631,7 +632,7 @@ sla::PoolConfig make_pool_config(const SLAPrintObjectConfig& c) { pcfg.min_wall_height_mm = c.pad_wall_height.getFloat(); // set builtin pad implicitly ON - pcfg.embed_object = use_builtin_pad(c); + pcfg.embed_object = builtin_pad_cfg(c); return pcfg; } @@ -663,6 +664,16 @@ std::string SLAPrint::validate() const if(supports_en && elv > EPSILON && elv < pinhead_width ) return L("Elevation is too low for object."); + + sla::PoolConfig::EmbedObject builtinpad = builtin_pad_cfg(po->config()); + if(supports_en && builtinpad.enabled && + cfg.pillar_base_safety_distance_mm < builtinpad.object_gap_mm) { + return L( + "The endings of the support pillars will be deployed on the " + "gap between the object and the pad. 'Support base safety " + "distance' has to be greater than the 'Pad object gap' " + "parameter to avoid this."); + } } return ""; @@ -861,7 +872,7 @@ void SLAPrint::process() // If the builtin pad mode is engaged, we have to filter out all the // points that are on the bottom of the object - if(use_builtin_pad(po.m_config)) { + if(builtin_pad_cfg(po.m_config)) { double gnd = po.m_supportdata->emesh.ground_level(); auto & pts = po.m_supportdata->support_points; @@ -1658,6 +1669,7 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector& Preset::sla_print_options() "pad_max_merge_distance", "pad_edge_radius", "pad_wall_slope", + "pad_object_gap", "pad_object_connector_stride", "pad_object_connector_width", "pad_object_connector_penetration", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 8ca47f1b11..032bf95dfb 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3503,6 +3503,7 @@ void TabSLAPrint::build() // optgroup->append_single_option_line("pad_edge_radius"); optgroup->append_single_option_line("pad_wall_slope"); + optgroup->append_single_option_line("pad_object_gap"); optgroup->append_single_option_line("pad_object_connector_stride"); optgroup->append_single_option_line("pad_object_connector_width"); optgroup->append_single_option_line("pad_object_connector_penetration"); From 10897524df042dae63939cec8251f93940de7916 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 12 Jun 2019 15:29:24 +0200 Subject: [PATCH 06/28] Fixes for gap detection and case with no pad, but zero elevation. --- src/libslic3r/SLA/SLASupportTree.cpp | 21 ++++++++++++++++----- src/libslic3r/SLAPrint.cpp | 21 +++++++++++---------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index ba14b1811f..c2540ba282 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -1410,6 +1410,7 @@ class SLASupportTree::Algorithm { { // People were killed for this number (seriously) static const double SQR2 = std::sqrt(2.0); + static const Vec3d DOWN = {0.0, 0.0, -1.0}; double gndlvl = m_result.ground_level; Vec3d endp = {jp(X), jp(Y), gndlvl}; @@ -1451,20 +1452,30 @@ class SLASupportTree::Algorithm { initvals(mv), bound(0.0, 2 * min_dist)); mv = std::get<0>(result.optimum); - endp = jp + std::sqrt(2) * mv * dir; + endp = jp + SQR2 * mv * dir; Vec3d pgnd = {endp(X), endp(Y), gndlvl}; can_add_base = result.score > min_dist; + + auto abort_in_shame = + [&normal_mode, &can_add_base, &endp, jp, gndlvl]() + { + normal_mode = true; + can_add_base = false; // Nothing left to do, hope for the best + endp = {jp(X), jp(Y), gndlvl}; + }; // We have to check if the bridge is feasible. - if (bridge_mesh_intersect(jp, dir, radius) < (endp - jp).norm()) { - normal_mode = true; - endp = {jp(X), jp(Y), gndlvl}; - } + if (bridge_mesh_intersect(jp, dir, radius) < (endp - jp).norm()) + abort_in_shame(); else { // If the new endpoint is below ground, do not make a pillar if (endp(Z) < gndlvl) endp = endp - SQR2 * (gndlvl - endp(Z)) * dir; // back off else { + + if (!std::isinf(bridge_mesh_intersect(endp, DOWN, radius))) + abort_in_shame(); + Pillar &plr = m_result.add_pillar(endp, pgnd, radius); if (can_add_base) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index bff4c95876..99e2915ea0 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -439,12 +439,10 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf update_apply_status(this->invalidate_all_steps()); m_objects = print_objects_new; // Delete the PrintObjects marked as Unknown or Deleted. - bool deleted_objects = false; for (auto &pos : print_object_status) if (pos.status == PrintObjectStatus::Unknown || pos.status == PrintObjectStatus::Deleted) { update_apply_status(pos.print_object->invalidate_all_steps()); delete pos.print_object; - deleted_objects = true; } if (new_objects) update_apply_status(false); @@ -870,19 +868,22 @@ void SLAPrint::process() po.m_supportdata->support_points = po.transformed_support_points(); } - // If the builtin pad mode is engaged, we have to filter out all the + // If the zero elevation mode is engaged, we have to filter out all the // points that are on the bottom of the object - if(builtin_pad_cfg(po.m_config)) { - double gnd = po.m_supportdata->emesh.ground_level(); - auto & pts = po.m_supportdata->support_points; - + if (po.config().support_object_elevation.getFloat() <= EPSILON) { + double gnd = po.m_supportdata->emesh.ground_level(); + auto & pts = po.m_supportdata->support_points; + double tolerance = po.config().pad_enable.getBool() + ? po.m_config.pad_wall_thickness.getFloat() + : po.m_config.support_base_height.getFloat(); + // get iterator to the reorganized vector end auto endit = std::remove_if( pts.begin(), pts.end(), - [&po, gnd](const sla::SupportPoint &sp) { + [tolerance, gnd](const sla::SupportPoint &sp) { double diff = std::abs(gnd - double(sp.pos(Z))); - return diff <= po.m_config.pad_wall_thickness.getFloat(); + return diff <= tolerance; }); // erase all elements after the new end @@ -1352,7 +1353,7 @@ void SLAPrint::process() }; // Rasterizing the model objects, and their supports - auto rasterize = [this, max_objstatus]() { + auto rasterize = [this]() { if(canceled()) return; // collect all the keys From 4ffe3278bee9bd7441fd3a5410376cd0586947db Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 12 Jun 2019 17:09:40 +0200 Subject: [PATCH 07/28] Hotfix for pad shape deduction. --- src/libslic3r/SLA/SLASupportTree.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index c2540ba282..4910226cc7 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -580,9 +580,8 @@ struct Pad { for (const ExPolygon &bp : platetmp) basep.emplace_back(bp.contour); - if(pcfg.embed_object) { - auto modelbase_sticks = modelbase; + ExPolygons modelbase_sticks = modelbase; if (pcfg.embed_object.object_gap_mm > 0.0) modelbase_sticks @@ -591,7 +590,7 @@ struct Pad { / SCALING_FACTOR)); for(auto& poly : modelbase_sticks) { - basep.emplace_back(poly); + basep.emplace_back(poly.contour); sla::breakstick_holes( poly, pcfg.embed_object.object_gap_mm, // padding From d1ed3d40c1c1da26f6d0b0da9e2d54a928050796 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 12 Jun 2019 17:23:12 +0200 Subject: [PATCH 08/28] Fix build on windows. This issue is annoying. --- src/libslic3r/SLAPrint.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 99e2915ea0..3c73416568 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1353,7 +1353,7 @@ void SLAPrint::process() }; // Rasterizing the model objects, and their supports - auto rasterize = [this]() { + auto rasterize = [this, max_objstatus]() { if(canceled()) return; // collect all the keys From e4cb75eddeaecb6a6c2b6d9694113c8fd82b59f4 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 12 Jun 2019 17:33:04 +0200 Subject: [PATCH 09/28] Fix build on Mac --- src/libslic3r/SLA/SLASupportTree.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index 4910226cc7..b74f73d172 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -1472,8 +1472,8 @@ class SLASupportTree::Algorithm { endp = endp - SQR2 * (gndlvl - endp(Z)) * dir; // back off else { - if (!std::isinf(bridge_mesh_intersect(endp, DOWN, radius))) - abort_in_shame(); + auto hit = bridge_mesh_intersect(endp, DOWN, radius); + if (!std::isinf(hit.distance())) abort_in_shame(); Pillar &plr = m_result.add_pillar(endp, pgnd, radius); From 90a854f7045b4b4295d2e0a31a5007175c7267bc Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 17 Jun 2019 13:02:49 +0200 Subject: [PATCH 10/28] Fix levitation when supports are disabled. --- src/libslic3r/SLAPrint.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index d3c931d346..9fe0687b53 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -604,8 +604,8 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) { sla::PoolConfig::EmbedObject builtin_pad_cfg(const SLAPrintObjectConfig& c) { sla::PoolConfig::EmbedObject ret; - ret.enabled = c.support_object_elevation.getFloat() <= EPSILON && - c.pad_enable.getBool(); + ret.enabled = c.support_object_elevation.getFloat() <= EPSILON && + c.pad_enable.getBool() && c.supports_enable.getBool(); if(ret.enabled) { ret.object_gap_mm = c.pad_object_gap.getFloat(); @@ -1737,7 +1737,8 @@ bool SLAPrintObject::invalidate_all_steps() } double SLAPrintObject::get_elevation() const { - double ret = m_config.support_object_elevation.getFloat(); + bool en = m_config.supports_enable.getBool(); + double ret = en ? m_config.support_object_elevation.getFloat() : 0.; if(m_config.pad_enable.getBool()) { // Normally the elevation for the pad itself would be the thickness of From 778b2cf293d3082162b97a2c7d40add410f0fde7 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 17 Jun 2019 18:06:52 +0200 Subject: [PATCH 11/28] WIP on removing unused parts of pad --- src/libslic3r/SLA/SLABasePool.cpp | 45 +++++--- src/libslic3r/SLA/SLABasePool.hpp | 7 +- src/libslic3r/SLA/SLASpatIndex.hpp | 65 ++++++++--- src/libslic3r/SLA/SLASupportTree.cpp | 93 +++++++++++----- src/libslic3r/SLA/SLASupportTreeIGL.cpp | 136 ++++++++++++++++++------ 5 files changed, 254 insertions(+), 92 deletions(-) diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp index 4e1e030185..48d615a29d 100644 --- a/src/libslic3r/SLA/SLABasePool.cpp +++ b/src/libslic3r/SLA/SLABasePool.cpp @@ -666,24 +666,19 @@ Polygons concave_hull(const Polygons& polys, double max_dist_mm = 50, return punion; } -void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h, - float layerh, ThrowOnCancel thrfn) +void base_plate(const TriangleMesh & mesh, + ExPolygons & output, + const std::vector &heights, + ThrowOnCancel thrfn) { - TriangleMesh m = mesh; - m.require_shared_vertices(); // TriangleMeshSlicer needs this - TriangleMeshSlicer slicer(&m); - - auto bb = mesh.bounding_box(); - float gnd = float(bb.min(Z)); - std::vector heights = {float(bb.min(Z))}; - for(float hi = gnd + layerh; hi <= gnd + h; hi += layerh) - heights.emplace_back(hi); - - std::vector out; out.reserve(size_t(std::ceil(h/layerh))); + // m.require_shared_vertices(); // TriangleMeshSlicer needs this + TriangleMeshSlicer slicer(&mesh); + + std::vector out; out.reserve(heights.size()); slicer.slice(heights, 0.f, &out, thrfn); - + size_t count = 0; for(auto& o : out) count += o.size(); - + // Now we have to unify all slice layers which can be an expensive operation // so we will try to simplify the polygons ExPolygons tmp; tmp.reserve(count); @@ -692,15 +687,31 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h, auto&& exss = e.simplify(scaled(0.1)); for(ExPolygon& ep : exss) tmp.emplace_back(std::move(ep)); } - + ExPolygons utmp = unify(tmp); - + for(auto& o : utmp) { auto&& smp = o.simplify(scaled(0.1)); output.insert(output.end(), smp.begin(), smp.end()); } } +void base_plate(const TriangleMesh &mesh, + ExPolygons & output, + float h, + float layerh, + ThrowOnCancel thrfn) +{ + auto bb = mesh.bounding_box(); + float gnd = float(bb.min(Z)); + std::vector heights = {float(bb.min(Z))}; + + for(float hi = gnd + layerh; hi <= gnd + h; hi += layerh) + heights.emplace_back(hi); + + base_plate(mesh, output, heights, thrfn); +} + Contour3D create_base_pool(const Polygons &ground_layer, const ExPolygons &obj_self_pad = {}, const PoolConfig& cfg = PoolConfig()) diff --git a/src/libslic3r/SLA/SLABasePool.hpp b/src/libslic3r/SLA/SLABasePool.hpp index 8aa4f5f412..67b9ccdcb5 100644 --- a/src/libslic3r/SLA/SLABasePool.hpp +++ b/src/libslic3r/SLA/SLABasePool.hpp @@ -21,10 +21,15 @@ using ThrowOnCancel = std::function; /// Calculate the polygon representing the silhouette from the specified height void base_plate(const TriangleMesh& mesh, // input mesh ExPolygons& output, // Output will be merged with - float zlevel = 0.1f, // Plate creation level + float samplingheight = 0.1f, // The height range to sample float layerheight = 0.05f, // The sampling height ThrowOnCancel thrfn = [](){}); // Will be called frequently +void base_plate(const TriangleMesh& mesh, // input mesh + ExPolygons& output, // Output will be merged with + const std::vector&, // Exact Z levels to sample + ThrowOnCancel thrfn = [](){}); // Will be called frequently + // Function to cut tiny connector cavities for a given polygon. The input poly // will be offsetted by "padding" and small rectangle shaped cavities will be // inserted along the perimeter in every "stride" distance. The stick rectangles diff --git a/src/libslic3r/SLA/SLASpatIndex.hpp b/src/libslic3r/SLA/SLASpatIndex.hpp index e5fbfa7d4b..90dcdc3627 100644 --- a/src/libslic3r/SLA/SLASpatIndex.hpp +++ b/src/libslic3r/SLA/SLASpatIndex.hpp @@ -7,13 +7,15 @@ #include +#include + namespace Slic3r { namespace sla { typedef Eigen::Matrix Vec3d; -using SpatElement = std::pair; +using PointIndexEl = std::pair; -class SpatIndex { +class PointIndex { class Impl; // We use Pimpl because it takes a long time to compile boost headers which @@ -21,30 +23,67 @@ class SpatIndex { std::unique_ptr m_impl; public: - SpatIndex(); - ~SpatIndex(); + PointIndex(); + ~PointIndex(); - SpatIndex(const SpatIndex&); - SpatIndex(SpatIndex&&); - SpatIndex& operator=(const SpatIndex&); - SpatIndex& operator=(SpatIndex&&); + PointIndex(const PointIndex&); + PointIndex(PointIndex&&); + PointIndex& operator=(const PointIndex&); + PointIndex& operator=(PointIndex&&); - void insert(const SpatElement&); - bool remove(const SpatElement&); + void insert(const PointIndexEl&); + bool remove(const PointIndexEl&); inline void insert(const Vec3d& v, unsigned idx) { insert(std::make_pair(v, unsigned(idx))); } - std::vector query(std::function); - std::vector nearest(const Vec3d&, unsigned k); + std::vector query(std::function); + std::vector nearest(const Vec3d&, unsigned k); // For testing size_t size() const; bool empty() const { return size() == 0; } - void foreach(std::function fn); + void foreach(std::function fn); +}; + +using BoxIndexEl = std::pair; + +class BoxIndex { + class Impl; + + // We use Pimpl because it takes a long time to compile boost headers which + // is the engine of this class. We include it only in the cpp file. + std::unique_ptr m_impl; +public: + + BoxIndex(); + ~BoxIndex(); + + BoxIndex(const BoxIndex&); + BoxIndex(BoxIndex&&); + BoxIndex& operator=(const BoxIndex&); + BoxIndex& operator=(BoxIndex&&); + + void insert(const BoxIndexEl&); + inline void insert(const BoundingBox& bb, unsigned idx) + { + insert(std::make_pair(bb, unsigned(idx))); + } + + bool remove(const BoxIndexEl&); + + enum QueryType { qtIntersects, qtWithin }; + + std::vector query(const BoundingBox&, QueryType qt); + + // For testing + size_t size() const; + bool empty() const { return size() == 0; } + + void foreach(std::function fn); }; } diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index 41040e89ea..c38ff34e19 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -569,37 +569,74 @@ struct Pad { sla::get_pad_elevation(pcfg)) { Polygons basep; - cfg.throw_on_cancel(); + auto &thr = cfg.throw_on_cancel; - // The 0.1f is the layer height with which the mesh is sampled and then - // the layers are unified into one vector of polygons. - ExPolygons platetmp; - base_plate(object_support_mesh, platetmp, - float(cfg.min_wall_height_mm + cfg.min_wall_thickness_mm), - 0.1f, pcfg.throw_on_cancel); + thr(); - for (const ExPolygon &bp : platetmp) basep.emplace_back(bp.contour); + // Get a sample for the pad from the support mesh + { + ExPolygons platetmp; + float plateZ = float(get_pad_fullheight(pcfg) + EPSILON); + + base_plate(object_support_mesh, platetmp, plateZ, 0.1f, thr); + + // We don't need no... holes control... + for (const ExPolygon &bp : platetmp) + basep.emplace_back(std::move(bp.contour)); + } if(pcfg.embed_object) { - ExPolygons modelbase_sticks = modelbase; + // If the zero elevation mode is ON, we need to process the model + // base silhouette. Create the offsetted version and punch the + // breaksticks across its perimeter. + + ExPolygons modelbase_sticks = modelbase; + if (pcfg.embed_object.object_gap_mm > 0.0) modelbase_sticks = offset_ex(modelbase_sticks, - coord_t(pcfg.embed_object.object_gap_mm - / SCALING_FACTOR)); + float(scaled(pcfg.embed_object.object_gap_mm))); + BoxIndex bindex; + { + unsigned idx = 0; + for(auto &bp : basep) { + auto bb = bp.bounding_box(); + bb.offset(float(scaled(pcfg.min_wall_thickness_mm))); + bindex.insert(bb, idx++); + } + } + + ExPolygons pad_stickholes; pad_stickholes.reserve(modelbase.size()); for(auto& poly : modelbase_sticks) { - basep.emplace_back(poly.contour); - sla::breakstick_holes( - poly, - pcfg.embed_object.object_gap_mm, // padding - pcfg.embed_object.stick_stride_mm, - pcfg.embed_object.stick_width_mm, - pcfg.embed_object.stick_penetration_mm); + + if (!bindex.query(poly.contour.bounding_box(), + BoxIndex::qtIntersects).empty()) { + + basep.emplace_back(poly.contour); + + auto it = poly.holes.begin(); + while(it != poly.holes.end()) { + if (bindex.query(it->bounding_box(), + BoxIndex::qtIntersects).empty()) + it = poly.holes.erase(it); + else + ++it; + } + + sla::breakstick_holes( + poly, + pcfg.embed_object.object_gap_mm, // padding + pcfg.embed_object.stick_stride_mm, + pcfg.embed_object.stick_width_mm, + pcfg.embed_object.stick_penetration_mm); + + pad_stickholes.emplace_back(poly); + } } - create_base_pool(basep, tmesh, modelbase_sticks, cfg); + create_base_pool(basep, tmesh, pad_stickholes, cfg); } else { for (const ExPolygon &bp : modelbase) basep.emplace_back(bp.contour); create_base_pool(basep, tmesh, {}, cfg); @@ -630,7 +667,7 @@ inline Vec2d to_vec2(const Vec3d& v3) { return {v3(X), v3(Y)}; } -bool operator==(const SpatElement& e1, const SpatElement& e2) { +bool operator==(const PointIndexEl& e1, const PointIndexEl& e2) { return e1.second == e2.second; } @@ -647,7 +684,7 @@ ClusteredPoints cluster(const PointSet& points, ClusteredPoints cluster( const std::vector& indices, std::function pointfn, - std::function predicate, + std::function predicate, unsigned max_points); // This class will hold the support tree meshes with some additional bookkeeping @@ -974,7 +1011,7 @@ class SLASupportTree::Algorithm { ThrowOnCancel m_thr; // A spatial index to easily find strong pillars to connect to. - SpatIndex m_pillar_index; + PointIndex m_pillar_index; inline double ray_mesh_intersect(const Vec3d& s, const Vec3d& dir) @@ -1367,7 +1404,7 @@ class SLASupportTree::Algorithm { } bool search_pillar_and_connect(const Head& head) { - SpatIndex spindex = m_pillar_index; + PointIndex spindex = m_pillar_index; long nearest_id = -1; @@ -1747,8 +1784,8 @@ public: return m_result.head(i).junction_point(); }; - auto predicate = [this](const SpatElement &e1, - const SpatElement &e2) { + auto predicate = [this](const PointIndexEl &e1, + const PointIndexEl &e2) { double d2d = distance(to_2d(e1.first), to_2d(e2.first)); double d3d = distance(e1.first, e2.first); return d2d < 2 * m_cfg.base_radius_mm @@ -2070,7 +2107,7 @@ public: // be connected multiple times this is ensured by the 'pairs' set which // remembers the processed pillar pairs auto cascadefn = - [this, d, &pairs, min_height_ratio, H1] (const SpatElement& el) + [this, d, &pairs, min_height_ratio, H1] (const PointIndexEl& el) { Vec3d qp = el.first; // endpoint of the pillar @@ -2083,13 +2120,13 @@ public: if(pillar.links >= neighbors) return; // Query all remaining points within reach - auto qres = m_pillar_index.query([qp, d](const SpatElement& e){ + auto qres = m_pillar_index.query([qp, d](const PointIndexEl& e){ return distance(e.first, qp) < d; }); // sort the result by distance (have to check if this is needed) std::sort(qres.begin(), qres.end(), - [qp](const SpatElement& e1, const SpatElement& e2){ + [qp](const PointIndexEl& e1, const PointIndexEl& e2){ return distance(e1.first, qp) < distance(e2.first, qp); }); diff --git a/src/libslic3r/SLA/SLASupportTreeIGL.cpp b/src/libslic3r/SLA/SLASupportTreeIGL.cpp index c368b8604d..04e6f79c75 100644 --- a/src/libslic3r/SLA/SLASupportTreeIGL.cpp +++ b/src/libslic3r/SLA/SLASupportTreeIGL.cpp @@ -29,69 +29,137 @@ namespace sla { using igl::PI; /* ************************************************************************** - * SpatIndex implementation + * PointIndex implementation * ************************************************************************** */ -class SpatIndex::Impl { +class PointIndex::Impl { public: - using BoostIndex = boost::geometry::index::rtree< SpatElement, + using BoostIndex = boost::geometry::index::rtree< PointIndexEl, boost::geometry::index::rstar<16, 4> /* ? */ >; BoostIndex m_store; }; -SpatIndex::SpatIndex(): m_impl(new Impl()) {} -SpatIndex::~SpatIndex() {} +PointIndex::PointIndex(): m_impl(new Impl()) {} +PointIndex::~PointIndex() {} -SpatIndex::SpatIndex(const SpatIndex &cpy): m_impl(new Impl(*cpy.m_impl)) {} -SpatIndex::SpatIndex(SpatIndex&& cpy): m_impl(std::move(cpy.m_impl)) {} +PointIndex::PointIndex(const PointIndex &cpy): m_impl(new Impl(*cpy.m_impl)) {} +PointIndex::PointIndex(PointIndex&& cpy): m_impl(std::move(cpy.m_impl)) {} -SpatIndex& SpatIndex::operator=(const SpatIndex &cpy) +PointIndex& PointIndex::operator=(const PointIndex &cpy) { m_impl.reset(new Impl(*cpy.m_impl)); return *this; } -SpatIndex& SpatIndex::operator=(SpatIndex &&cpy) +PointIndex& PointIndex::operator=(PointIndex &&cpy) { m_impl.swap(cpy.m_impl); return *this; } -void SpatIndex::insert(const SpatElement &el) +void PointIndex::insert(const PointIndexEl &el) { m_impl->m_store.insert(el); } -bool SpatIndex::remove(const SpatElement& el) +bool PointIndex::remove(const PointIndexEl& el) { return m_impl->m_store.remove(el) == 1; } -std::vector -SpatIndex::query(std::function fn) +std::vector +PointIndex::query(std::function fn) { namespace bgi = boost::geometry::index; - std::vector ret; + std::vector ret; m_impl->m_store.query(bgi::satisfies(fn), std::back_inserter(ret)); return ret; } -std::vector SpatIndex::nearest(const Vec3d &el, unsigned k = 1) +std::vector PointIndex::nearest(const Vec3d &el, unsigned k = 1) { namespace bgi = boost::geometry::index; - std::vector ret; ret.reserve(k); + std::vector ret; ret.reserve(k); m_impl->m_store.query(bgi::nearest(el, k), std::back_inserter(ret)); return ret; } -size_t SpatIndex::size() const +size_t PointIndex::size() const { return m_impl->m_store.size(); } -void SpatIndex::foreach(std::function fn) +void PointIndex::foreach(std::function fn) +{ + for(auto& el : m_impl->m_store) fn(el); +} + +/* ************************************************************************** + * BoxIndex implementation + * ************************************************************************** */ + +class BoxIndex::Impl { +public: + using BoostIndex = boost::geometry::index:: + rtree /* ? */>; + + BoostIndex m_store; +}; + +BoxIndex::BoxIndex(): m_impl(new Impl()) {} +BoxIndex::~BoxIndex() {} + +BoxIndex::BoxIndex(const BoxIndex &cpy): m_impl(new Impl(*cpy.m_impl)) {} +BoxIndex::BoxIndex(BoxIndex&& cpy): m_impl(std::move(cpy.m_impl)) {} + +BoxIndex& BoxIndex::operator=(const BoxIndex &cpy) +{ + m_impl.reset(new Impl(*cpy.m_impl)); + return *this; +} + +BoxIndex& BoxIndex::operator=(BoxIndex &&cpy) +{ + m_impl.swap(cpy.m_impl); + return *this; +} + +void BoxIndex::insert(const BoxIndexEl &el) +{ + m_impl->m_store.insert(el); +} + +bool BoxIndex::remove(const BoxIndexEl& el) +{ + return m_impl->m_store.remove(el) == 1; +} + +std::vector BoxIndex::query(const BoundingBox &qrbb, + BoxIndex::QueryType qt) +{ + namespace bgi = boost::geometry::index; + + std::vector ret; ret.reserve(m_impl->m_store.size()); + + switch (qt) { + case qtIntersects: + m_impl->m_store.query(bgi::intersects(qrbb), std::back_inserter(ret)); + break; + case qtWithin: + m_impl->m_store.query(bgi::within(qrbb), std::back_inserter(ret)); + } + + return ret; +} + +size_t BoxIndex::size() const +{ + return m_impl->m_store.size(); +} + +void BoxIndex::foreach(std::function fn) { for(auto& el : m_impl->m_store) fn(el); } @@ -352,12 +420,14 @@ PointSet normals(const PointSet& points, return ret; } namespace bgi = boost::geometry::index; -using Index3D = bgi::rtree< SpatElement, bgi::rstar<16, 4> /* ? */ >; +using Index3D = bgi::rtree< PointIndexEl, bgi::rstar<16, 4> /* ? */ >; -ClusteredPoints cluster(Index3D& sindex, unsigned max_points, - std::function(const Index3D&, const SpatElement&)> qfn) +ClusteredPoints cluster(Index3D &sindex, + unsigned max_points, + std::function( + const Index3D &, const PointIndexEl &)> qfn) { - using Elems = std::vector; + using Elems = std::vector; // Recursive function for visiting all the points in a given distance to // each other @@ -365,8 +435,8 @@ ClusteredPoints cluster(Index3D& sindex, unsigned max_points, [&sindex, &group, max_points, qfn](Elems& pts, Elems& cluster) { for(auto& p : pts) { - std::vector tmp = qfn(sindex, p); - auto cmp = [](const SpatElement& e1, const SpatElement& e2){ + std::vector tmp = qfn(sindex, p); + auto cmp = [](const PointIndexEl& e1, const PointIndexEl& e2){ return e1.second < e2.second; }; @@ -410,12 +480,12 @@ ClusteredPoints cluster(Index3D& sindex, unsigned max_points, } namespace { -std::vector distance_queryfn(const Index3D& sindex, - const SpatElement& p, +std::vector distance_queryfn(const Index3D& sindex, + const PointIndexEl& p, double dist, unsigned max_points) { - std::vector tmp; tmp.reserve(max_points); + std::vector tmp; tmp.reserve(max_points); sindex.query( bgi::nearest(p.first, max_points), std::back_inserter(tmp) @@ -442,7 +512,7 @@ ClusteredPoints cluster( for(auto idx : indices) sindex.insert( std::make_pair(pointfn(idx), idx)); return cluster(sindex, max_points, - [dist, max_points](const Index3D& sidx, const SpatElement& p) + [dist, max_points](const Index3D& sidx, const PointIndexEl& p) { return distance_queryfn(sidx, p, dist, max_points); }); @@ -452,7 +522,7 @@ ClusteredPoints cluster( ClusteredPoints cluster( const std::vector& indices, std::function pointfn, - std::function predicate, + std::function predicate, unsigned max_points) { // A spatial index for querying the nearest points @@ -462,10 +532,10 @@ ClusteredPoints cluster( for(auto idx : indices) sindex.insert( std::make_pair(pointfn(idx), idx)); return cluster(sindex, max_points, - [max_points, predicate](const Index3D& sidx, const SpatElement& p) + [max_points, predicate](const Index3D& sidx, const PointIndexEl& p) { - std::vector tmp; tmp.reserve(max_points); - sidx.query(bgi::satisfies([p, predicate](const SpatElement& e){ + std::vector tmp; tmp.reserve(max_points); + sidx.query(bgi::satisfies([p, predicate](const PointIndexEl& e){ return predicate(p, e); }), std::back_inserter(tmp)); return tmp; @@ -482,7 +552,7 @@ ClusteredPoints cluster(const PointSet& pts, double dist, unsigned max_points) sindex.insert(std::make_pair(Vec3d(pts.row(i)), unsigned(i))); return cluster(sindex, max_points, - [dist, max_points](const Index3D& sidx, const SpatElement& p) + [dist, max_points](const Index3D& sidx, const PointIndexEl& p) { return distance_queryfn(sidx, p, dist, max_points); }); From d7684188f90c8eb2ae1f7bc881aa918d3177ecd6 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 18 Jun 2019 11:24:50 +0200 Subject: [PATCH 12/28] Removing unused pad parts working --- src/libslic3r/MTUtils.hpp | 54 ++++++++++++++++++++++++++++ src/libslic3r/SLA/SLASupportTree.cpp | 9 +++-- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/MTUtils.hpp b/src/libslic3r/MTUtils.hpp index 7e91ace328..ee70f535d4 100644 --- a/src/libslic3r/MTUtils.hpp +++ b/src/libslic3r/MTUtils.hpp @@ -5,6 +5,9 @@ #include // for std::lock_guard #include // for std::function #include // for std::forward +#include +#include +#include namespace Slic3r { @@ -182,6 +185,57 @@ public: inline bool empty() const { return size() == 0; } }; +template +struct remove_cvref +{ + using type = + typename std::remove_cv::type>::type; +}; + +template +using remove_cvref_t = typename remove_cvref::type; + +template class C, class T> +class Container: public C> { +public: + explicit Container(size_t count, T&& initval): + C>(count, initval) {} +}; + +template using DefaultContainer = std::vector; + +/// Exactly like Matlab https://www.mathworks.com/help/matlab/ref/linspace.html +template class C = DefaultContainer> +inline C> linspace(const T &start, const T &stop, const I &n) +{ + Container vals(n, T()); + T stride = (stop - start) / n; + + size_t i = 0; + std::generate(vals.begin(), vals.end(), [&i, start, stride] { + return start + i++ * stride; + }); + + return vals; +} + +/// A set of equidistant values starting from 'start' (inclusive), ending +/// in the closest multiple of 'stride' less than or equal to 'end' and +/// leaving 'stride' space between each value. +/// Very similar to Matlab [start:stride:end] notation. +template class C = DefaultContainer> +inline C> grid(const T &start, const T &stop, const T &stride) +{ + Container vals(size_t(std::ceil((stop - start) / stride)), T()); + + int i = 0; + std::generate(vals.begin(), vals.end(), [&i, start, stride] { + return start + i++ * stride; + }); + + return vals; +} + } #endif // MTUTILS_HPP diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index c38ff34e19..cfb5c2e743 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -9,6 +9,7 @@ #include "SLASpatIndex.hpp" #include "SLABasePool.hpp" +#include #include #include @@ -559,7 +560,7 @@ struct Pad { Pad() = default; - Pad(const TriangleMesh& object_support_mesh, + Pad(const TriangleMesh& support_mesh, const ExPolygons& modelbase, double ground_level, const PoolConfig& pcfg) : @@ -576,9 +577,11 @@ struct Pad { // Get a sample for the pad from the support mesh { ExPolygons platetmp; - float plateZ = float(get_pad_fullheight(pcfg) + EPSILON); - base_plate(object_support_mesh, platetmp, plateZ, 0.1f, thr); + float zstart = float(zlevel); + float zend = zstart + float(get_pad_fullheight(pcfg) + EPSILON); + + base_plate(support_mesh, platetmp, grid(zstart, zend, 0.1f), thr); // We don't need no... holes control... for (const ExPolygon &bp : platetmp) From 5a1e1bc10c887a3408194cd546b2a704b94d08f3 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 19 Jun 2019 10:15:01 +0200 Subject: [PATCH 13/28] GUI_ObjectManipulation.cpp - Removed implicit capture by value in some of the lambdas --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 310000ecc3..4ccaa68479 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -185,7 +185,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : unsigned int axis_idx = (axis[0] - 'x'); // 0, 1 or 2 // We will add a button to toggle mirroring to each axis: - auto mirror_button = [=](wxWindow* parent) { + auto mirror_button = [this, mirror_btn_width, axis_idx, &label](wxWindow* parent) { wxSize btn_size(em_unit(parent) * mirror_btn_width, em_unit(parent) * mirror_btn_width); auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off.png", wxEmptyString, btn_size, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW); btn->SetToolTip(wxString::Format(_(L("Toggle %s axis mirroring")), label)); @@ -195,7 +195,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(btn); - btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) { + btn->Bind(wxEVT_BUTTON, [this, axis_idx](wxCommandEvent &e) { Axis axis = (Axis)(axis_idx + X); if (m_mirror_buttons[axis_idx].second == mbHidden) return; @@ -258,13 +258,13 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : return btn; }; // Add reset scale button - auto reset_scale_button = [=](wxWindow* parent) { + auto reset_scale_button = [this](wxWindow* parent) { auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo")); btn->SetToolTip(_(L("Reset scale"))); m_reset_scale_button = btn; auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(btn, wxBU_EXACTFIT); - btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) { + btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { change_scale_value(0, 100.); change_scale_value(1, 100.); change_scale_value(2, 100.); @@ -275,13 +275,13 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : } else if (option_name == "Rotation") { // Add reset rotation button - auto reset_rotation_button = [=](wxWindow* parent) { + auto reset_rotation_button = [this](wxWindow* parent) { auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo")); btn->SetToolTip(_(L("Reset rotation"))); m_reset_rotation_button = btn; auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(btn, wxBU_EXACTFIT); - btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) { + btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); Selection& selection = canvas->get_selection(); From 3d8c3804fab810568adedce76836ea97e7e1c71d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 19 Jun 2019 10:46:42 +0200 Subject: [PATCH 14/28] Added 'drop to bed' button into object manipulation panel --- resources/icons/drop_to_bed.png | Bin 0 -> 528 bytes src/slic3r/GUI/3DScene.hpp | 2 + src/slic3r/GUI/GUI_ObjectManipulation.cpp | 57 +++++++++++++++++++++- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 1 + 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 resources/icons/drop_to_bed.png diff --git a/resources/icons/drop_to_bed.png b/resources/icons/drop_to_bed.png new file mode 100644 index 0000000000000000000000000000000000000000..b60e1b137d9d12a1cfc177de1d51eb7c7093aa7b GIT binary patch literal 528 zcmV+r0`L8aP)pZ4MY$`uvwNR!r;okMbKJk8Mr7Sc?B_4 zw3vhk*&h#jJRY=Z9WH}5j=0iAViLGQMuMqqF{$nne8*(H`8hk~-;c&PlNg4nEF!8fo zAB{$(kqK(G+PT~9o+ZhoNVD0z(sliTyuVApvaFM$sJEMv_I2*lK8?hfruj57K`9N$uNw6@pwG@@d=4U;%B$pZI{dCsB#M&HN# z(T$${eQO-sVHtp7jYUy>bJR3V$(^0?{b#F314aL;=?9riril=m#u&2t-indexed_vertex_array.empty(); } bool indexed() const { return this->indexed_vertex_array.indexed(); } diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 4ccaa68479..7363b2c166 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -17,6 +17,28 @@ namespace Slic3r namespace GUI { + +// Helper function to be used by drop to bed button. Returns lowest point of this +// volume in world coordinate system. +static double get_volume_min_z(const GLVolume* volume) +{ + const Transform3f& world_matrix = volume->world_matrix().cast(); + + // need to get the ModelVolume pointer + const ModelObject* mo = wxGetApp().model_objects()->at(volume->composite_id.object_id); + const ModelVolume* mv = mo->volumes[volume->composite_id.volume_id]; + const TriangleMesh& hull = mv->get_convex_hull(); + + float min_z = std::numeric_limits::max(); + for (const stl_facet& facet : hull.stl.facet_start) { + for (int i = 0; i < 3; ++ i) + min_z = std::min(min_z, Vec3f::UnitZ().dot(world_matrix * facet.vertex[i])); + } + return min_z; +} + + + static wxBitmapComboBox* create_word_local_combo(wxWindow *parent) { wxSize size(15 * wxGetApp().em_unit(), -1); @@ -310,6 +332,33 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : }; line.append_widget(reset_rotation_button); } + else if (option_name == "Position") { + // Add drop to bed button + auto drop_to_bed_button = [=](wxWindow* parent) { + auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "drop_to_bed.png")); + btn->SetToolTip(_(L("Drop to bed"))); + m_drop_to_bed_button = btn; + auto sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(btn, wxBU_EXACTFIT); + btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) { + // ??? + GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); + Selection& selection = canvas->get_selection(); + + if (selection.is_single_volume() || selection.is_single_modifier()) { + const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + + Vec3d diff = m_cache.position - Vec3d(0., 0., get_volume_min_z(volume)); + + change_position_value(0, diff.x()); + change_position_value(1, diff.y()); + change_position_value(2, diff.z()); + } + }); + return sizer; + }; + line.append_widget(drop_to_bed_button); + } // Add empty bmp (Its size have to be equal to PrusaLockButton) in front of "Size" option to label alignment else if (option_name == "Size") { line.near_label_widget = [this](wxWindow* parent) { @@ -534,11 +583,13 @@ void ObjectManipulation::update_reset_buttons_visibility() bool show_rotation = false; bool show_scale = false; + bool show_drop_to_bed = false; if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) { const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); Vec3d rotation; Vec3d scale; + double min_z = 0.; if (selection.is_single_full_instance()) { rotation = volume->get_instance_rotation(); @@ -547,14 +598,17 @@ void ObjectManipulation::update_reset_buttons_visibility() else { rotation = volume->get_volume_rotation(); scale = volume->get_volume_scaling_factor(); + min_z = get_volume_min_z(volume); } show_rotation = !rotation.isApprox(Vec3d::Zero()); show_scale = !scale.isApprox(Vec3d::Ones()); + show_drop_to_bed = (std::abs(min_z) > EPSILON); } - wxGetApp().CallAfter([this, show_rotation, show_scale]{ + wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed]{ m_reset_rotation_button->Show(show_rotation); m_reset_scale_button->Show(show_scale); + m_drop_to_bed_button->Show(show_drop_to_bed); }); } @@ -867,6 +921,7 @@ void ObjectManipulation::msw_rescale() m_mirror_bitmap_hidden.msw_rescale(); m_reset_scale_button->msw_rescale(); m_reset_rotation_button->msw_rescale(); + m_drop_to_bed_button->msw_rescale(); get_og()->msw_rescale(); } diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index cc2154514d..e4e190b5bc 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -56,6 +56,7 @@ class ObjectManipulation : public OG_Settings // Non-owning pointers to the reset buttons, so we can hide and show them. ScalableButton* m_reset_scale_button = nullptr; ScalableButton* m_reset_rotation_button = nullptr; + ScalableButton* m_drop_to_bed_button = nullptr; // Mirroring buttons and their current state enum MirrorButtonState { From 0481f33ceb4dd64098e3b0c9c324bc32a82ba5f3 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 19 Jun 2019 11:52:37 +0200 Subject: [PATCH 15/28] Drop to bed function now accounts for instance transformation --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 7363b2c166..d5445c6afe 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -348,7 +348,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : if (selection.is_single_volume() || selection.is_single_modifier()) { const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - Vec3d diff = m_cache.position - Vec3d(0., 0., get_volume_min_z(volume)); + const Geometry::Transformation& instance_trafo = volume->get_instance_transformation(); + Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., get_volume_min_z(volume)); change_position_value(0, diff.x()); change_position_value(1, diff.y()); From 3b0e0aaed43389c66bf3eebed035353b94da2dc7 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 20 Jun 2019 13:01:48 +0200 Subject: [PATCH 16/28] Fixes for degenerate cases. --- src/libslic3r/SLA/SLABasePool.cpp | 75 ++++++++++++++-------------- src/libslic3r/SLA/SLACommon.hpp | 1 + src/libslic3r/SLA/SLASupportTree.cpp | 59 +++++++++++++++------- src/libslic3r/SLAPrint.cpp | 8 --- 4 files changed, 80 insertions(+), 63 deletions(-) diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp index 48d615a29d..ace9cdd85a 100644 --- a/src/libslic3r/SLA/SLABasePool.cpp +++ b/src/libslic3r/SLA/SLABasePool.cpp @@ -239,48 +239,49 @@ void offset(ExPolygon& sh, coord_t distance, bool edgerounding = true) { } } - void offset(Polygon& sh, coord_t distance, bool edgerounding = true) { - using ClipperLib::ClipperOffset; - using ClipperLib::jtRound; - using ClipperLib::jtMiter; - using ClipperLib::etClosedPolygon; - using ClipperLib::Paths; - using ClipperLib::Path; +void offset(Polygon &sh, coord_t distance, bool edgerounding = true) +{ + using ClipperLib::ClipperOffset; + using ClipperLib::jtRound; + using ClipperLib::jtMiter; + using ClipperLib::etClosedPolygon; + using ClipperLib::Paths; + using ClipperLib::Path; - auto&& ctour = Slic3rMultiPoint_to_ClipperPath(sh); + auto &&ctour = Slic3rMultiPoint_to_ClipperPath(sh); - // If the input is not at least a triangle, we can not do this algorithm - if(ctour.size() < 3) { - BOOST_LOG_TRIVIAL(error) << "Invalid geometry for offsetting!"; - return; - } + // If the input is not at least a triangle, we can not do this algorithm + if (ctour.size() < 3) { + BOOST_LOG_TRIVIAL(error) << "Invalid geometry for offsetting!"; + return; + } - ClipperOffset offs; - offs.ArcTolerance = 0.01*scaled(1.); - Paths result; - offs.AddPath(ctour, edgerounding ? jtRound : jtMiter, etClosedPolygon); - offs.Execute(result, static_cast(distance)); + ClipperOffset offs; + offs.ArcTolerance = 0.01 * scaled(1.); + Paths result; + offs.AddPath(ctour, edgerounding ? jtRound : jtMiter, etClosedPolygon); + offs.Execute(result, static_cast(distance)); - // Offsetting reverts the orientation and also removes the last vertex - // so boost will not have a closed polygon. + // Offsetting reverts the orientation and also removes the last vertex + // so boost will not have a closed polygon. - bool found_the_contour = false; - for(auto& r : result) { - if(ClipperLib::Orientation(r)) { - // We don't like if the offsetting generates more than one contour - // but throwing would be an overkill. Instead, we should warn the - // caller about the inability to create correct geometries - if(!found_the_contour) { - auto rr = ClipperPath_to_Slic3rPolygon(r); - sh.points.swap(rr.points); - found_the_contour = true; - } else { - BOOST_LOG_TRIVIAL(warning) - << "Warning: offsetting result is invalid!"; - } - } - } - } + bool found_the_contour = false; + for (auto &r : result) { + if (ClipperLib::Orientation(r)) { + // We don't like if the offsetting generates more than one contour + // but throwing would be an overkill. Instead, we should warn the + // caller about the inability to create correct geometries + if (!found_the_contour) { + auto rr = ClipperPath_to_Slic3rPolygon(r); + sh.points.swap(rr.points); + found_the_contour = true; + } else { + BOOST_LOG_TRIVIAL(warning) + << "Warning: offsetting result is invalid!"; + } + } + } +} /// Unification of polygons (with clipper) preserving holes as well. ExPolygons unify(const ExPolygons& shapes) { diff --git a/src/libslic3r/SLA/SLACommon.hpp b/src/libslic3r/SLA/SLACommon.hpp index 2666f2a9c3..eb986a259b 100644 --- a/src/libslic3r/SLA/SLACommon.hpp +++ b/src/libslic3r/SLA/SLACommon.hpp @@ -73,6 +73,7 @@ public: inline double ground_level() const { return m_ground_level + m_gnd_offset; } inline void ground_level_offset(double o) { m_gnd_offset = o; } + inline double ground_level_offset() const { return m_gnd_offset; } inline const Eigen::MatrixXd& V() const { return m_V; } inline const Eigen::MatrixXi& F() const { return m_F; } diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index cfb5c2e743..4de5c4c594 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -530,6 +530,7 @@ struct CompactBridge { const Vec3d& ep, const Vec3d& n, double r, + bool endball = true, size_t steps = 45) { Vec3d startp = sp + r * n; @@ -543,12 +544,14 @@ struct CompactBridge { double fa = 2*PI/steps; auto upperball = sphere(r, Portion{PI / 2 - fa, PI}, fa); for(auto& p : upperball.points) p += startp; - - auto lowerball = sphere(r, Portion{0, PI/2 + 2*fa}, fa); - for(auto& p : lowerball.points) p += endp; - + + if(endball) { + auto lowerball = sphere(r, Portion{0, PI/2 + 2*fa}, fa); + for(auto& p : lowerball.points) p += endp; + mesh.merge(lowerball); + } + mesh.merge(upperball); - mesh.merge(lowerball); } }; @@ -594,13 +597,17 @@ struct Pad { // base silhouette. Create the offsetted version and punch the // breaksticks across its perimeter. - ExPolygons modelbase_sticks = modelbase; - + ExPolygons modelbase_offs = modelbase; + if (pcfg.embed_object.object_gap_mm > 0.0) - modelbase_sticks - = offset_ex(modelbase_sticks, + modelbase_offs + = offset_ex(modelbase_offs, float(scaled(pcfg.embed_object.object_gap_mm))); + // Create a spatial index of the support silhouette polygons. + // This will be used to check for intersections with the model + // silhouette polygons. If there is no intersection, then a certain + // part of the pad is redundant as it does not host any supports. BoxIndex bindex; { unsigned idx = 0; @@ -611,14 +618,27 @@ struct Pad { } } + // Punching the breaksticks across the offsetted polygon perimeters ExPolygons pad_stickholes; pad_stickholes.reserve(modelbase.size()); - for(auto& poly : modelbase_sticks) { + for(auto& poly : modelbase_offs) { - if (!bindex.query(poly.contour.bounding_box(), - BoxIndex::qtIntersects).empty()) { + std::vector qres = + bindex.query(poly.contour.bounding_box(), + BoxIndex::qtIntersects); + + if (!qres.empty()) { + + // The model silhouette polygon 'poly' HAS an intersection + // with the support silhouettes. Include this polygon + // in the pad holes with the breaksticks and merge the + // original (offsetted) version with the rest of the pad + // base plate. basep.emplace_back(poly.contour); + // The holes of 'poly' will become positive parts of the + // pad, so they has to be checked for intersections as well + // and erased if there is no intersection with the supports auto it = poly.holes.begin(); while(it != poly.holes.end()) { if (bindex.query(it->bounding_box(), @@ -627,7 +647,8 @@ struct Pad { else ++it; } - + + // Punch the breaksticks sla::breakstick_holes( poly, pcfg.embed_object.object_gap_mm, // padding @@ -638,7 +659,7 @@ struct Pad { pad_stickholes.emplace_back(poly); } } - + create_base_pool(basep, tmesh, pad_stickholes, cfg); } else { for (const ExPolygon &bp : modelbase) basep.emplace_back(bp.contour); @@ -1495,12 +1516,13 @@ class SLASupportTree::Algorithm { Vec3d pgnd = {endp(X), endp(Y), gndlvl}; can_add_base = result.score > min_dist; + double gnd_offs = m_mesh.ground_level_offset(); auto abort_in_shame = - [&normal_mode, &can_add_base, &endp, jp, gndlvl]() + [gnd_offs, &normal_mode, &can_add_base, &endp, jp, gndlvl]() { normal_mode = true; can_add_base = false; // Nothing left to do, hope for the best - endp = {jp(X), jp(Y), gndlvl}; + endp = {jp(X), jp(Y), gndlvl - gnd_offs }; }; // We have to check if the bridge is feasible. @@ -2317,7 +2339,8 @@ public: double idist = bridge_mesh_intersect(sph, dir, R, true); double dist = ray_mesh_intersect(sj, dir); if (std::isinf(dist)) - dist = sph(Z) - m_result.ground_level - HWIDTH_MM; + dist = sph(Z) - m_mesh.ground_level() + + m_mesh.ground_level_offset(); if(std::isnan(idist) || idist < 2*R || std::isnan(dist) || dist < 2*R) @@ -2329,7 +2352,7 @@ public: } Vec3d ej = sj + (dist + HWIDTH_MM)* dir; - m_result.add_compact_bridge(sp, ej, n, R); + m_result.add_compact_bridge(sp, ej, n, R, !std::isinf(dist)); } } }; diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 789a8120f6..9e8b4bea25 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1084,9 +1084,6 @@ void SLAPrint::process() using ClipperPolygons = std::vector; namespace sl = libnest2d::shapelike; // For algorithms - // If the raster has vertical orientation, we will flip the coordinates -// bool flpXY = m_printer_config.display_orientation.getInt() == SLADisplayOrientation::sladoPortrait; - // Set up custom union and diff functions for clipper polygons auto polyunion = [] (const ClipperPolygons& subjects) { @@ -1194,11 +1191,6 @@ void SLAPrint::process() sl::translate(poly, ClipperPoint{instances[i].shift(X), instances[i].shift(Y)}); -// if (flpXY) { -// for(auto& p : poly.Contour) std::swap(p.X, p.Y); -// for(auto& h : poly.Holes) for(auto& p : h) std::swap(p.X, p.Y); -// } - polygons.emplace_back(std::move(poly)); } } From 548f19462a9b55fd573a1e529a6be2fe0343b169 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 28 Jun 2019 15:42:59 +0200 Subject: [PATCH 17/28] Fix formatting --- src/libslic3r/MTUtils.hpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/MTUtils.hpp b/src/libslic3r/MTUtils.hpp index f83d38a423..42992223fd 100644 --- a/src/libslic3r/MTUtils.hpp +++ b/src/libslic3r/MTUtils.hpp @@ -244,21 +244,21 @@ template bool all_of(const C &container) }); } -template -struct remove_cvref +template struct remove_cvref { using type = typename std::remove_cv::type>::type; }; -template -using remove_cvref_t = typename remove_cvref::type; +template using remove_cvref_t = typename remove_cvref::type; template class C, class T> -class Container: public C> { +class Container : public C> +{ public: - explicit Container(size_t count, T&& initval): - C>(count, initval) {} + explicit Container(size_t count, T &&initval) + : C>(count, initval) + {} }; template using DefaultContainer = std::vector; @@ -268,13 +268,13 @@ template class C = DefaultContainer> inline C> linspace(const T &start, const T &stop, const I &n) { Container vals(n, T()); - T stride = (stop - start) / n; - - size_t i = 0; + + T stride = (stop - start) / n; + size_t i = 0; std::generate(vals.begin(), vals.end(), [&i, start, stride] { - return start + i++ * stride; + return start + i++ * stride; }); - + return vals; } From 25d916f144a868c28dc9c433b281d53f84afdd6b Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 8 Jul 2019 08:40:20 +0200 Subject: [PATCH 18/28] Color change time estimates --- src/libslic3r/GCode.cpp | 4 + src/libslic3r/GCodeTimeEstimator.cpp | 323 ++++++++++++++++----------- src/libslic3r/GCodeTimeEstimator.hpp | 35 ++- src/libslic3r/Print.hpp | 4 + src/slic3r/GUI/Plater.cpp | 10 + 5 files changed, 233 insertions(+), 143 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index c03431a308..d2e5814935 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1057,6 +1057,10 @@ void GCode::_do_export(Print &print, FILE *file) print.m_print_statistics.clear(); print.m_print_statistics.estimated_normal_print_time = m_normal_time_estimator.get_time_dhms(); print.m_print_statistics.estimated_silent_print_time = m_silent_time_estimator_enabled ? m_silent_time_estimator.get_time_dhms() : "N/A"; + print.m_print_statistics.estimated_normal_color_print_times = m_normal_time_estimator.get_color_times_dhms(); + if (m_silent_time_estimator_enabled) + print.m_print_statistics.estimated_silent_color_print_times = m_silent_time_estimator.get_color_times_dhms(); + std::vector extruders = m_writer.extruders(); if (! extruders.empty()) { std::pair out_filament_used_mm ("; filament used [mm] = ", 0); diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index b87305da87..33dc9f4b7d 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -174,7 +174,7 @@ namespace Slic3r { const std::string GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag = "; SILENT_LAST_M73_OUTPUT_PLACEHOLDER"; GCodeTimeEstimator::GCodeTimeEstimator(EMode mode) - : _mode(mode) + : m_mode(mode) { reset(); set_default(); @@ -183,7 +183,7 @@ namespace Slic3r { void GCodeTimeEstimator::add_gcode_line(const std::string& gcode_line) { PROFILE_FUNC(); - _parser.parse_line(gcode_line, + m_parser.parse_line(gcode_line, [this](GCodeReader &reader, const GCodeReader::GCodeLine &line) { this->_process_gcode_line(reader, line); }); } @@ -196,7 +196,7 @@ namespace Slic3r { { this->_process_gcode_line(reader, line); }; for (; *ptr != 0;) { gline.reset(); - ptr = _parser.parse_line(ptr, gline, action); + ptr = m_parser.parse_line(ptr, gline, action); } } @@ -206,10 +206,13 @@ namespace Slic3r { if (start_from_beginning) { _reset_time(); - _last_st_synchronized_block_id = -1; + m_last_st_synchronized_block_id = -1; } _calculate_time(); + if (m_needs_color_times && (m_color_time_cache != 0.0f)) + m_color_times.push_back(m_color_time_cache); + #if ENABLE_MOVE_STATS _log_moves_stats(); #endif // ENABLE_MOVE_STATS @@ -219,12 +222,15 @@ namespace Slic3r { { reset(); - _parser.parse_buffer(gcode, + m_parser.parse_buffer(gcode, [this](GCodeReader &reader, const GCodeReader::GCodeLine &line) { this->_process_gcode_line(reader, line); }); _calculate_time(); + if (m_needs_color_times && (m_color_time_cache != 0.0f)) + m_color_times.push_back(m_color_time_cache); + #if ENABLE_MOVE_STATS _log_moves_stats(); #endif // ENABLE_MOVE_STATS @@ -234,9 +240,12 @@ namespace Slic3r { { reset(); - _parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2)); + m_parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2)); _calculate_time(); + if (m_needs_color_times && (m_color_time_cache != 0.0f)) + m_color_times.push_back(m_color_time_cache); + #if ENABLE_MOVE_STATS _log_moves_stats(); #endif // ENABLE_MOVE_STATS @@ -249,9 +258,12 @@ namespace Slic3r { auto action = [this](GCodeReader &reader, const GCodeReader::GCodeLine &line) { this->_process_gcode_line(reader, line); }; for (const std::string& line : gcode_lines) - _parser.parse_line(line, action); + m_parser.parse_line(line, action); _calculate_time(); + if (m_needs_color_times && (m_color_time_cache != 0.0f)) + m_color_times.push_back(m_color_time_cache); + #if ENABLE_MOVE_STATS _log_moves_stats(); #endif // ENABLE_MOVE_STATS @@ -270,7 +282,7 @@ namespace Slic3r { throw std::runtime_error(std::string("Remaining times export failed.\nCannot open file for writing.\n")); std::string time_mask; - switch (_mode) + switch (m_mode) { default: case Normal: @@ -291,7 +303,7 @@ namespace Slic3r { // buffer line to export only when greater than 64K to reduce writing calls std::string export_line; char time_line[64]; - G1LineIdToBlockIdMap::const_iterator it_line_id = _g1_line_ids.begin(); + G1LineIdToBlockIdMap::const_iterator it_line_id = m_g1_line_ids.begin(); while (std::getline(in, gcode_line)) { if (!in.good()) @@ -301,15 +313,15 @@ namespace Slic3r { } // replaces placeholders for initial line M73 with the real lines - if (((_mode == Normal) && (gcode_line == Normal_First_M73_Output_Placeholder_Tag)) || - ((_mode == Silent) && (gcode_line == Silent_First_M73_Output_Placeholder_Tag))) + if (((m_mode == Normal) && (gcode_line == Normal_First_M73_Output_Placeholder_Tag)) || + ((m_mode == Silent) && (gcode_line == Silent_First_M73_Output_Placeholder_Tag))) { - sprintf(time_line, time_mask.c_str(), "0", _get_time_minutes(_time).c_str()); + sprintf(time_line, time_mask.c_str(), "0", _get_time_minutes(m_time).c_str()); gcode_line = time_line; } // replaces placeholders for final line M73 with the real lines - else if (((_mode == Normal) && (gcode_line == Normal_Last_M73_Output_Placeholder_Tag)) || - ((_mode == Silent) && (gcode_line == Silent_Last_M73_Output_Placeholder_Tag))) + else if (((m_mode == Normal) && (gcode_line == Normal_Last_M73_Output_Placeholder_Tag)) || + ((m_mode == Silent) && (gcode_line == Silent_Last_M73_Output_Placeholder_Tag))) { sprintf(time_line, time_mask.c_str(), "100", "0"); gcode_line = time_line; @@ -319,27 +331,27 @@ namespace Slic3r { // add remaining time lines where needed - _parser.parse_line(gcode_line, + m_parser.parse_line(gcode_line, [this, &it_line_id, &g1_lines_count, &last_recorded_time, &time_line, &gcode_line, time_mask, interval](GCodeReader& reader, const GCodeReader::GCodeLine& line) { if (line.cmd_is("G1")) { ++g1_lines_count; - assert(it_line_id == _g1_line_ids.end() || it_line_id->first >= g1_lines_count); + assert(it_line_id == m_g1_line_ids.end() || it_line_id->first >= g1_lines_count); const Block *block = nullptr; - if (it_line_id != _g1_line_ids.end() && it_line_id->first == g1_lines_count) { - if (line.has_e() && it_line_id->second < (unsigned int)_blocks.size()) - block = &_blocks[it_line_id->second]; + if (it_line_id != m_g1_line_ids.end() && it_line_id->first == g1_lines_count) { + if (line.has_e() && it_line_id->second < (unsigned int)m_blocks.size()) + block = &m_blocks[it_line_id->second]; ++it_line_id; } if (block != nullptr && block->elapsed_time != -1.0f) { - float block_remaining_time = _time - block->elapsed_time; + float block_remaining_time = m_time - block->elapsed_time; if (std::abs(last_recorded_time - block_remaining_time) > interval) { - sprintf(time_line, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / _time)).c_str(), _get_time_minutes(block_remaining_time).c_str()); + sprintf(time_line, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / m_time)).c_str(), _get_time_minutes(block_remaining_time).c_str()); gcode_line += time_line; last_recorded_time = block_remaining_time; @@ -387,240 +399,240 @@ namespace Slic3r { void GCodeTimeEstimator::set_axis_position(EAxis axis, float position) { - _state.axis[axis].position = position; + m_state.axis[axis].position = position; } void GCodeTimeEstimator::set_axis_max_feedrate(EAxis axis, float feedrate_mm_sec) { - _state.axis[axis].max_feedrate = feedrate_mm_sec; + m_state.axis[axis].max_feedrate = feedrate_mm_sec; } void GCodeTimeEstimator::set_axis_max_acceleration(EAxis axis, float acceleration) { - _state.axis[axis].max_acceleration = acceleration; + m_state.axis[axis].max_acceleration = acceleration; } void GCodeTimeEstimator::set_axis_max_jerk(EAxis axis, float jerk) { - _state.axis[axis].max_jerk = jerk; + m_state.axis[axis].max_jerk = jerk; } float GCodeTimeEstimator::get_axis_position(EAxis axis) const { - return _state.axis[axis].position; + return m_state.axis[axis].position; } float GCodeTimeEstimator::get_axis_max_feedrate(EAxis axis) const { - return _state.axis[axis].max_feedrate; + return m_state.axis[axis].max_feedrate; } float GCodeTimeEstimator::get_axis_max_acceleration(EAxis axis) const { - return _state.axis[axis].max_acceleration; + return m_state.axis[axis].max_acceleration; } float GCodeTimeEstimator::get_axis_max_jerk(EAxis axis) const { - return _state.axis[axis].max_jerk; + return m_state.axis[axis].max_jerk; } void GCodeTimeEstimator::set_feedrate(float feedrate_mm_sec) { - _state.feedrate = feedrate_mm_sec; + m_state.feedrate = feedrate_mm_sec; } float GCodeTimeEstimator::get_feedrate() const { - return _state.feedrate; + return m_state.feedrate; } void GCodeTimeEstimator::set_acceleration(float acceleration_mm_sec2) { - _state.acceleration = (_state.max_acceleration == 0) ? + m_state.acceleration = (m_state.max_acceleration == 0) ? acceleration_mm_sec2 : // Clamp the acceleration with the maximum. - std::min(_state.max_acceleration, acceleration_mm_sec2); + std::min(m_state.max_acceleration, acceleration_mm_sec2); } float GCodeTimeEstimator::get_acceleration() const { - return _state.acceleration; + return m_state.acceleration; } void GCodeTimeEstimator::set_max_acceleration(float acceleration_mm_sec2) { - _state.max_acceleration = acceleration_mm_sec2; + m_state.max_acceleration = acceleration_mm_sec2; if (acceleration_mm_sec2 > 0) - _state.acceleration = acceleration_mm_sec2; + m_state.acceleration = acceleration_mm_sec2; } float GCodeTimeEstimator::get_max_acceleration() const { - return _state.max_acceleration; + return m_state.max_acceleration; } void GCodeTimeEstimator::set_retract_acceleration(float acceleration_mm_sec2) { - _state.retract_acceleration = acceleration_mm_sec2; + m_state.retract_acceleration = acceleration_mm_sec2; } float GCodeTimeEstimator::get_retract_acceleration() const { - return _state.retract_acceleration; + return m_state.retract_acceleration; } void GCodeTimeEstimator::set_minimum_feedrate(float feedrate_mm_sec) { - _state.minimum_feedrate = feedrate_mm_sec; + m_state.minimum_feedrate = feedrate_mm_sec; } float GCodeTimeEstimator::get_minimum_feedrate() const { - return _state.minimum_feedrate; + return m_state.minimum_feedrate; } void GCodeTimeEstimator::set_minimum_travel_feedrate(float feedrate_mm_sec) { - _state.minimum_travel_feedrate = feedrate_mm_sec; + m_state.minimum_travel_feedrate = feedrate_mm_sec; } float GCodeTimeEstimator::get_minimum_travel_feedrate() const { - return _state.minimum_travel_feedrate; + return m_state.minimum_travel_feedrate; } void GCodeTimeEstimator::set_filament_load_times(const std::vector &filament_load_times) { - _state.filament_load_times.clear(); + m_state.filament_load_times.clear(); for (double t : filament_load_times) - _state.filament_load_times.push_back((float)t); + m_state.filament_load_times.push_back((float)t); } void GCodeTimeEstimator::set_filament_unload_times(const std::vector &filament_unload_times) { - _state.filament_unload_times.clear(); + m_state.filament_unload_times.clear(); for (double t : filament_unload_times) - _state.filament_unload_times.push_back((float)t); + m_state.filament_unload_times.push_back((float)t); } float GCodeTimeEstimator::get_filament_load_time(unsigned int id_extruder) { return - (_state.filament_load_times.empty() || id_extruder == _state.extruder_id_unloaded) ? + (m_state.filament_load_times.empty() || id_extruder == m_state.extruder_id_unloaded) ? 0 : - (_state.filament_load_times.size() <= id_extruder) ? - _state.filament_load_times.front() : - _state.filament_load_times[id_extruder]; + (m_state.filament_load_times.size() <= id_extruder) ? + m_state.filament_load_times.front() : + m_state.filament_load_times[id_extruder]; } float GCodeTimeEstimator::get_filament_unload_time(unsigned int id_extruder) { return - (_state.filament_unload_times.empty() || id_extruder == _state.extruder_id_unloaded) ? + (m_state.filament_unload_times.empty() || id_extruder == m_state.extruder_id_unloaded) ? 0 : - (_state.filament_unload_times.size() <= id_extruder) ? - _state.filament_unload_times.front() : - _state.filament_unload_times[id_extruder]; + (m_state.filament_unload_times.size() <= id_extruder) ? + m_state.filament_unload_times.front() : + m_state.filament_unload_times[id_extruder]; } void GCodeTimeEstimator::set_extrude_factor_override_percentage(float percentage) { - _state.extrude_factor_override_percentage = percentage; + m_state.extrude_factor_override_percentage = percentage; } float GCodeTimeEstimator::get_extrude_factor_override_percentage() const { - return _state.extrude_factor_override_percentage; + return m_state.extrude_factor_override_percentage; } void GCodeTimeEstimator::set_dialect(GCodeFlavor dialect) { - _state.dialect = dialect; + m_state.dialect = dialect; } GCodeFlavor GCodeTimeEstimator::get_dialect() const { PROFILE_FUNC(); - return _state.dialect; + return m_state.dialect; } void GCodeTimeEstimator::set_units(GCodeTimeEstimator::EUnits units) { - _state.units = units; + m_state.units = units; } GCodeTimeEstimator::EUnits GCodeTimeEstimator::get_units() const { - return _state.units; + return m_state.units; } void GCodeTimeEstimator::set_global_positioning_type(GCodeTimeEstimator::EPositioningType type) { - _state.global_positioning_type = type; + m_state.global_positioning_type = type; } GCodeTimeEstimator::EPositioningType GCodeTimeEstimator::get_global_positioning_type() const { - return _state.global_positioning_type; + return m_state.global_positioning_type; } void GCodeTimeEstimator::set_e_local_positioning_type(GCodeTimeEstimator::EPositioningType type) { - _state.e_local_positioning_type = type; + m_state.e_local_positioning_type = type; } GCodeTimeEstimator::EPositioningType GCodeTimeEstimator::get_e_local_positioning_type() const { - return _state.e_local_positioning_type; + return m_state.e_local_positioning_type; } int GCodeTimeEstimator::get_g1_line_id() const { - return _state.g1_line_id; + return m_state.g1_line_id; } void GCodeTimeEstimator::increment_g1_line_id() { - ++_state.g1_line_id; + ++m_state.g1_line_id; } void GCodeTimeEstimator::reset_g1_line_id() { - _state.g1_line_id = 0; + m_state.g1_line_id = 0; } void GCodeTimeEstimator::set_extruder_id(unsigned int id) { - _state.extruder_id = id; + m_state.extruder_id = id; } unsigned int GCodeTimeEstimator::get_extruder_id() const { - return _state.extruder_id; + return m_state.extruder_id; } void GCodeTimeEstimator::reset_extruder_id() { // Set the initial extruder ID to unknown. For the multi-material setup it means // that all the filaments are parked in the MMU and no filament is loaded yet. - _state.extruder_id = _state.extruder_id_unloaded; + m_state.extruder_id = m_state.extruder_id_unloaded; } void GCodeTimeEstimator::add_additional_time(float timeSec) { PROFILE_FUNC(); - _state.additional_time += timeSec; + m_state.additional_time += timeSec; } void GCodeTimeEstimator::set_additional_time(float timeSec) { - _state.additional_time = timeSec; + m_state.additional_time = timeSec; } float GCodeTimeEstimator::get_additional_time() const { - return _state.additional_time; + return m_state.additional_time; } void GCodeTimeEstimator::set_default() @@ -648,8 +660,8 @@ namespace Slic3r { set_axis_max_jerk(axis, DEFAULT_AXIS_MAX_JERK[a]); } - _state.filament_load_times.clear(); - _state.filament_unload_times.clear(); + m_state.filament_load_times.clear(); + m_state.filament_unload_times.clear(); } void GCodeTimeEstimator::reset() @@ -664,7 +676,7 @@ namespace Slic3r { float GCodeTimeEstimator::get_time() const { - return _time; + return m_time; } std::string GCodeTimeEstimator::get_time_dhms() const @@ -677,19 +689,44 @@ namespace Slic3r { return _get_time_minutes(get_time()); } + std::vector GCodeTimeEstimator::get_color_times() const + { + return m_color_times; + } + + std::vector GCodeTimeEstimator::get_color_times_dhms() const + { + std::vector ret; + for (float t : m_color_times) + { + ret.push_back(_get_time_dhms(t)); + } + return ret; + } + + std::vector GCodeTimeEstimator::get_color_times_minutes() const + { + std::vector ret; + for (float t : m_color_times) + { + ret.push_back(_get_time_minutes(t)); + } + return ret; + } + // Return an estimate of the memory consumed by the time estimator. size_t GCodeTimeEstimator::memory_used() const { size_t out = sizeof(*this); - out += SLIC3R_STDVEC_MEMSIZE(this->_blocks, Block); - out += SLIC3R_STDVEC_MEMSIZE(this->_g1_line_ids, G1LineIdToBlockId); + out += SLIC3R_STDVEC_MEMSIZE(this->m_blocks, Block); + out += SLIC3R_STDVEC_MEMSIZE(this->m_g1_line_ids, G1LineIdToBlockId); return out; } void GCodeTimeEstimator::_reset() { - _curr.reset(); - _prev.reset(); + m_curr.reset(); + m_prev.reset(); set_axis_position(X, 0.0f); set_axis_position(Y, 0.0f); @@ -701,19 +738,23 @@ namespace Slic3r { reset_extruder_id(); reset_g1_line_id(); - _g1_line_ids.clear(); + m_g1_line_ids.clear(); - _last_st_synchronized_block_id = -1; + m_last_st_synchronized_block_id = -1; + + m_needs_color_times = false; + m_color_times.clear(); + m_color_time_cache = 0.0f; } void GCodeTimeEstimator::_reset_time() { - _time = 0.0f; + m_time = 0.0f; } void GCodeTimeEstimator::_reset_blocks() { - _blocks.clear(); + m_blocks.clear(); } void GCodeTimeEstimator::_calculate_time() @@ -723,35 +764,32 @@ namespace Slic3r { _reverse_pass(); _recalculate_trapezoids(); - _time += get_additional_time(); + m_time += get_additional_time(); + m_color_time_cache += get_additional_time(); - for (int i = _last_st_synchronized_block_id + 1; i < (int)_blocks.size(); ++i) + for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i) { - Block& block = _blocks[i]; - -#if ENABLE_MOVE_STATS + Block& block = m_blocks[i]; float block_time = 0.0f; block_time += block.acceleration_time(); block_time += block.cruise_time(); block_time += block.deceleration_time(); - _time += block_time; - block.elapsed_time = _time; + m_time += block_time; + block.elapsed_time = m_time; +#if ENABLE_MOVE_STATS MovesStatsMap::iterator it = _moves_stats.find(block.move_type); if (it == _moves_stats.end()) it = _moves_stats.insert(MovesStatsMap::value_type(block.move_type, MoveStats())).first; it->second.count += 1; it->second.time += block_time; -#else - _time += block.acceleration_time(); - _time += block.cruise_time(); - _time += block.deceleration_time(); - block.elapsed_time = _time; #endif // ENABLE_MOVE_STATS + + m_color_time_cache += block_time; } - _last_st_synchronized_block_id = (int)_blocks.size() - 1; + m_last_st_synchronized_block_id = (int)m_blocks.size() - 1; // The additional time has been consumed (added to the total time), reset it to zero. set_additional_time(0.); } @@ -866,6 +904,11 @@ namespace Slic3r { _processM566(line); break; } + case 600: // Set color change + { + _processM600(line); + break; + } case 702: // MK3 MMU2: Process the final filament unload. { _processM702(line); @@ -934,7 +977,7 @@ namespace Slic3r { return; // calculates block feedrate - _curr.feedrate = std::max(get_feedrate(), block.is_travel_move() ? get_minimum_travel_feedrate() : get_minimum_feedrate()); + m_curr.feedrate = std::max(get_feedrate(), block.is_travel_move() ? get_minimum_travel_feedrate() : get_minimum_feedrate()); float distance = block.move_length(); float invDistance = 1.0f / distance; @@ -942,23 +985,23 @@ namespace Slic3r { float min_feedrate_factor = 1.0f; for (unsigned char a = X; a < Num_Axis; ++a) { - _curr.axis_feedrate[a] = _curr.feedrate * block.delta_pos[a] * invDistance; + m_curr.axis_feedrate[a] = m_curr.feedrate * block.delta_pos[a] * invDistance; if (a == E) - _curr.axis_feedrate[a] *= get_extrude_factor_override_percentage(); + m_curr.axis_feedrate[a] *= get_extrude_factor_override_percentage(); - _curr.abs_axis_feedrate[a] = std::abs(_curr.axis_feedrate[a]); - if (_curr.abs_axis_feedrate[a] > 0.0f) - min_feedrate_factor = std::min(min_feedrate_factor, get_axis_max_feedrate((EAxis)a) / _curr.abs_axis_feedrate[a]); + m_curr.abs_axis_feedrate[a] = std::abs(m_curr.axis_feedrate[a]); + if (m_curr.abs_axis_feedrate[a] > 0.0f) + min_feedrate_factor = std::min(min_feedrate_factor, get_axis_max_feedrate((EAxis)a) / m_curr.abs_axis_feedrate[a]); } - block.feedrate.cruise = min_feedrate_factor * _curr.feedrate; + block.feedrate.cruise = min_feedrate_factor * m_curr.feedrate; if (min_feedrate_factor < 1.0f) { for (unsigned char a = X; a < Num_Axis; ++a) { - _curr.axis_feedrate[a] *= min_feedrate_factor; - _curr.abs_axis_feedrate[a] *= min_feedrate_factor; + m_curr.axis_feedrate[a] *= min_feedrate_factor; + m_curr.abs_axis_feedrate[a] *= min_feedrate_factor; } } @@ -975,25 +1018,25 @@ namespace Slic3r { block.acceleration = acceleration; // calculates block exit feedrate - _curr.safe_feedrate = block.feedrate.cruise; + m_curr.safe_feedrate = block.feedrate.cruise; for (unsigned char a = X; a < Num_Axis; ++a) { float axis_max_jerk = get_axis_max_jerk((EAxis)a); - if (_curr.abs_axis_feedrate[a] > axis_max_jerk) - _curr.safe_feedrate = std::min(_curr.safe_feedrate, axis_max_jerk); + if (m_curr.abs_axis_feedrate[a] > axis_max_jerk) + m_curr.safe_feedrate = std::min(m_curr.safe_feedrate, axis_max_jerk); } - block.feedrate.exit = _curr.safe_feedrate; + block.feedrate.exit = m_curr.safe_feedrate; // calculates block entry feedrate - float vmax_junction = _curr.safe_feedrate; - if (!_blocks.empty() && (_prev.feedrate > PREVIOUS_FEEDRATE_THRESHOLD)) + float vmax_junction = m_curr.safe_feedrate; + if (!m_blocks.empty() && (m_prev.feedrate > PREVIOUS_FEEDRATE_THRESHOLD)) { - bool prev_speed_larger = _prev.feedrate > block.feedrate.cruise; - float smaller_speed_factor = prev_speed_larger ? (block.feedrate.cruise / _prev.feedrate) : (_prev.feedrate / block.feedrate.cruise); + bool prev_speed_larger = m_prev.feedrate > block.feedrate.cruise; + float smaller_speed_factor = prev_speed_larger ? (block.feedrate.cruise / m_prev.feedrate) : (m_prev.feedrate / block.feedrate.cruise); // Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting. - vmax_junction = prev_speed_larger ? block.feedrate.cruise : _prev.feedrate; + vmax_junction = prev_speed_larger ? block.feedrate.cruise : m_prev.feedrate; float v_factor = 1.0f; bool limited = false; @@ -1001,8 +1044,8 @@ namespace Slic3r { for (unsigned char a = X; a < Num_Axis; ++a) { // Limit an axis. We have to differentiate coasting from the reversal of an axis movement, or a full stop. - float v_exit = _prev.axis_feedrate[a]; - float v_entry = _curr.axis_feedrate[a]; + float v_exit = m_prev.axis_feedrate[a]; + float v_entry = m_curr.axis_feedrate[a]; if (prev_speed_larger) v_exit *= smaller_speed_factor; @@ -1044,23 +1087,23 @@ namespace Slic3r { float vmax_junction_threshold = vmax_junction * 0.99f; // Not coasting. The machine will stop and start the movements anyway, better to start the segment from start. - if ((_prev.safe_feedrate > vmax_junction_threshold) && (_curr.safe_feedrate > vmax_junction_threshold)) - vmax_junction = _curr.safe_feedrate; + if ((m_prev.safe_feedrate > vmax_junction_threshold) && (m_curr.safe_feedrate > vmax_junction_threshold)) + vmax_junction = m_curr.safe_feedrate; } - float v_allowable = Block::max_allowable_speed(-acceleration, _curr.safe_feedrate, distance); + float v_allowable = Block::max_allowable_speed(-acceleration, m_curr.safe_feedrate, distance); block.feedrate.entry = std::min(vmax_junction, v_allowable); block.max_entry_speed = vmax_junction; block.flags.nominal_length = (block.feedrate.cruise <= v_allowable); block.flags.recalculate = true; - block.safe_feedrate = _curr.safe_feedrate; + block.safe_feedrate = m_curr.safe_feedrate; // calculates block trapezoid block.calculate_trapezoid(); // updates previous - _prev = _curr; + m_prev = m_curr; // updates axis positions for (unsigned char a = X; a < Num_Axis; ++a) @@ -1091,8 +1134,8 @@ namespace Slic3r { #endif // ENABLE_MOVE_STATS // adds block to blocks list - _blocks.emplace_back(block); - _g1_line_ids.emplace_back(G1LineIdToBlockIdMap::value_type(get_g1_line_id(), (unsigned int)_blocks.size() - 1)); + m_blocks.emplace_back(block); + m_g1_line_ids.emplace_back(G1LineIdToBlockIdMap::value_type(get_g1_line_id(), (unsigned int)m_blocks.size() - 1)); } void GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line) @@ -1336,6 +1379,18 @@ namespace Slic3r { set_axis_max_jerk(E, line.e() * MMMIN_TO_MMSEC); } + void GCodeTimeEstimator::_processM600(const GCodeReader::GCodeLine& line) + { + PROFILE_FUNC(); + m_needs_color_times = true; + _calculate_time(); + if (m_color_time_cache != 0.0f) + { + m_color_times.push_back(m_color_time_cache); + m_color_time_cache = 0.0f; + } + } + void GCodeTimeEstimator::_processM702(const GCodeReader::GCodeLine& line) { PROFILE_FUNC(); @@ -1376,11 +1431,11 @@ namespace Slic3r { void GCodeTimeEstimator::_forward_pass() { PROFILE_FUNC(); - if (_blocks.size() > 1) + if (m_blocks.size() > 1) { - for (int i = _last_st_synchronized_block_id + 1; i < (int)_blocks.size() - 1; ++i) + for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size() - 1; ++i) { - _planner_forward_pass_kernel(_blocks[i], _blocks[i + 1]); + _planner_forward_pass_kernel(m_blocks[i], m_blocks[i + 1]); } } } @@ -1388,11 +1443,11 @@ namespace Slic3r { void GCodeTimeEstimator::_reverse_pass() { PROFILE_FUNC(); - if (_blocks.size() > 1) + if (m_blocks.size() > 1) { - for (int i = (int)_blocks.size() - 1; i >= _last_st_synchronized_block_id + 2; --i) + for (int i = (int)m_blocks.size() - 1; i >= m_last_st_synchronized_block_id + 2; --i) { - _planner_reverse_pass_kernel(_blocks[i - 1], _blocks[i]); + _planner_reverse_pass_kernel(m_blocks[i - 1], m_blocks[i]); } } } @@ -1444,9 +1499,9 @@ namespace Slic3r { Block* curr = nullptr; Block* next = nullptr; - for (int i = _last_st_synchronized_block_id + 1; i < (int)_blocks.size(); ++i) + for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i) { - Block& b = _blocks[i]; + Block& b = m_blocks[i]; curr = next; next = &b; @@ -1517,7 +1572,7 @@ namespace Slic3r { { std::cout << MOVE_TYPE_STR[move.first]; std::cout << ": count " << move.second.count << " (" << 100.0f * (float)move.second.count / moves_count << "%)"; - std::cout << " - time: " << move.second.time << "s (" << 100.0f * move.second.time / _time << "%)"; + std::cout << " - time: " << move.second.time << "s (" << 100.0f * move.second.time / m_time << "%)"; std::cout << std::endl; } std::cout << std::endl; diff --git a/src/libslic3r/GCodeTimeEstimator.hpp b/src/libslic3r/GCodeTimeEstimator.hpp index 1fbc1c14bf..840d587784 100644 --- a/src/libslic3r/GCodeTimeEstimator.hpp +++ b/src/libslic3r/GCodeTimeEstimator.hpp @@ -215,17 +215,22 @@ namespace Slic3r { typedef std::vector G1LineIdToBlockIdMap; private: - EMode _mode; - GCodeReader _parser; - State _state; - Feedrates _curr; - Feedrates _prev; - BlocksList _blocks; + EMode m_mode; + GCodeReader m_parser; + State m_state; + Feedrates m_curr; + Feedrates m_prev; + BlocksList m_blocks; // Map between g1 line id and blocks id, used to speed up export of remaining times - G1LineIdToBlockIdMap _g1_line_ids; + G1LineIdToBlockIdMap m_g1_line_ids; // Index of the last block already st_synchronized - int _last_st_synchronized_block_id; - float _time; // s + int m_last_st_synchronized_block_id; + float m_time; // s + + // data to calculate color print times + bool m_needs_color_times; + std::vector m_color_times; + float m_color_time_cache; #if ENABLE_MOVE_STATS MovesStatsMap _moves_stats; @@ -341,6 +346,15 @@ namespace Slic3r { // Returns the estimated time, in minutes (integer) std::string get_time_minutes() const; + // Returns the estimated time, in seconds, for each color + std::vector get_color_times() const; + + // Returns the estimated time, in format DDd HHh MMm SSs, for each color + std::vector get_color_times_dhms() const; + + // Returns the estimated time, in minutes (integer), for each color + std::vector get_color_times_minutes() const; + // Return an estimate of the memory consumed by the time estimator. size_t memory_used() const; @@ -409,6 +423,9 @@ namespace Slic3r { // Set allowable instantaneous speed change void _processM566(const GCodeReader::GCodeLine& line); + // Set color change + void _processM600(const GCodeReader::GCodeLine& line); + // Unload the current filament into the MK3 MMU2 unit at the end of print. void _processM702(const GCodeReader::GCodeLine& line); diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 53d6d692db..7fe0eb7a3c 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -238,6 +238,8 @@ struct PrintStatistics PrintStatistics() { clear(); } std::string estimated_normal_print_time; std::string estimated_silent_print_time; + std::vector estimated_normal_color_print_times; + std::vector estimated_silent_color_print_times; double total_used_filament; double total_extruded_volume; double total_cost; @@ -256,6 +258,8 @@ struct PrintStatistics void clear() { estimated_normal_print_time.clear(); estimated_silent_print_time.clear(); + estimated_normal_color_print_times.clear(); + estimated_silent_color_print_times.clear(); total_used_filament = 0.; total_extruded_volume = 0.; total_cost = 0.; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 09ab91ef10..217937123a 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1116,10 +1116,20 @@ void Sidebar::show_sliced_info_sizer(const bool show) if (ps.estimated_normal_print_time != "N/A") { new_label += wxString::Format("\n - %s", _(L("normal mode"))); info_text += wxString::Format("\n%s", ps.estimated_normal_print_time); + for (unsigned int i = 0; i < (unsigned int)ps.estimated_normal_color_print_times.size(); ++i) + { + new_label += wxString::Format("\n - %s%d", _(L("Color ")), i + 1); + info_text += wxString::Format("\n%s", ps.estimated_normal_color_print_times[i]); + } } if (ps.estimated_silent_print_time != "N/A") { new_label += wxString::Format("\n - %s", _(L("stealth mode"))); info_text += wxString::Format("\n%s", ps.estimated_silent_print_time); + for (unsigned int i = 0; i < (unsigned int)ps.estimated_normal_color_print_times.size(); ++i) + { + new_label += wxString::Format("\n - %s%d", _(L("Color ")), i + 1); + info_text += wxString::Format("\n%s", ps.estimated_normal_color_print_times[i]); + } } p->sliced_info->SetTextAndShow(siEstimatedTime, info_text, new_label); } From 386a42b4c5aea6d7beeb55831c706d3680a77eb6 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 9 Jul 2019 10:15:40 +0200 Subject: [PATCH 19/28] Disable dep_libigl in deps. Include dir collisions... --- deps/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index d8e72370b5..8b41c853d6 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -105,7 +105,7 @@ else() dep_gtest dep_nlopt dep_qhull - dep_libigl + # dep_libigl # Not working, static build has different Eigen ) endif() From 18fcb6468120d76e524ea54e4a0cf569bf19292c Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 9 Jul 2019 13:12:55 +0200 Subject: [PATCH 20/28] Fixing broken SLA slicing: SPE-984 --- src/libslic3r/SLA/SLABasePool.cpp | 6 +-- src/libslic3r/SLA/SLASupportTree.cpp | 7 ++-- src/libslic3r/SLAPrint.cpp | 57 +++++++++++++++++----------- 3 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp index 04cbd78243..b1fbec8395 100644 --- a/src/libslic3r/SLA/SLABasePool.cpp +++ b/src/libslic3r/SLA/SLABasePool.cpp @@ -510,9 +510,9 @@ ExPolygons concave_hull(const ExPolygons& polys, double max_dist_mm = 50, void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h, float layerh, ThrowOnCancel thrfn) { - TriangleMesh m = mesh; - m.require_shared_vertices(); // TriangleMeshSlicer needs this - TriangleMeshSlicer slicer(&m); + if (mesh.empty()) return; + + TriangleMeshSlicer slicer(&mesh); auto bb = mesh.bounding_box(); float gnd = float(bb.min(Z)); diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index ae033c62fc..1f7ef07cb8 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -808,7 +808,6 @@ public: merged.merge(bs.mesh); } - if(m_ctl.stopcondition()) { // In case of failure we have to return an empty mesh meshcache = TriangleMesh(); @@ -819,7 +818,7 @@ public: // The mesh will be passed by const-pointer to TriangleMeshSlicer, // which will need this. - meshcache.require_shared_vertices(); + if (!meshcache.empty()) meshcache.require_shared_vertices(); // TODO: Is this necessary? //meshcache.repair(); @@ -2245,7 +2244,7 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const TriangleMesh fullmesh = m_impl->merged_mesh(); fullmesh.merge(get_pad()); - fullmesh.require_shared_vertices(); // TriangleMeshSlicer needs this + if (!fullmesh.empty()) fullmesh.require_shared_vertices(); TriangleMeshSlicer slicer(&fullmesh); SlicedSupports ret; slicer.slice(heights, 0.f, &ret, get().ctl().cancelfn); @@ -2258,7 +2257,7 @@ SlicedSupports SLASupportTree::slice(const std::vector &heights, { TriangleMesh fullmesh = m_impl->merged_mesh(); fullmesh.merge(get_pad()); - fullmesh.require_shared_vertices(); // TriangleMeshSlicer needs this + if (!fullmesh.empty()) fullmesh.require_shared_vertices(); TriangleMeshSlicer slicer(&fullmesh); SlicedSupports ret; slicer.slice(heights, cr, &ret, get().ctl().cancelfn); diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 1902e74ae6..8d7534df0d 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -751,18 +751,27 @@ void SLAPrint::process() mit->set_model_slice_idx(po, id); ++mit; } + + if(po.m_config.supports_enable.getBool() || + po.m_config.pad_enable.getBool()) + { + po.m_supportdata.reset( + new SLAPrintObject::SupportData(po.transformed_mesh()) ); + } }; // In this step we check the slices, identify island and cover them with // support points. Then we sprinkle the rest of the mesh. auto support_points = [this, ostepd](SLAPrintObject& po) { - const ModelObject& mo = *po.m_model_object; - po.m_supportdata.reset( - new SLAPrintObject::SupportData(po.transformed_mesh()) ); - // If supports are disabled, we can skip the model scan. if(!po.m_config.supports_enable.getBool()) return; + if (!po.m_supportdata) + po.m_supportdata.reset( + new SLAPrintObject::SupportData(po.transformed_mesh())); + + const ModelObject& mo = *po.m_model_object; + BOOST_LOG_TRIVIAL(debug) << "Support point count " << mo.sla_support_points.size(); @@ -771,7 +780,7 @@ void SLAPrint::process() // into the backend cache. if (mo.sla_points_status != sla::PointsStatus::UserModified) { - // Hypotetical use of the slice index: + // Hypothetical use of the slice index: // auto bb = po.transformed_mesh().bounding_box(); // auto range = po.get_slice_records(bb.min(Z)); // std::vector heights; heights.reserve(range.size()); @@ -888,12 +897,6 @@ void SLAPrint::process() // and before the supports had been sliced. (or the slicing has to be // repeated) - if(!po.m_supportdata || !po.m_supportdata->support_tree_ptr) { - BOOST_LOG_TRIVIAL(error) << "Uninitialized support data at " - << "pad creation."; - return; - } - if(po.m_config.pad_enable.getBool()) { double wt = po.m_config.pad_wall_thickness.getFloat(); @@ -921,7 +924,7 @@ void SLAPrint::process() pcfg.throw_on_cancel = thrfn; po.m_supportdata->support_tree_ptr->add_pad(bp, pcfg); - } else { + } else if(po.m_supportdata && po.m_supportdata->support_tree_ptr) { po.m_supportdata->support_tree_ptr->remove_pad(); } @@ -938,6 +941,11 @@ void SLAPrint::process() if(sd) sd->support_slices.clear(); + // Don't bother if no supports and no pad is present. + if (!po.m_config.supports_enable.getBool() && + !po.m_config.pad_enable.getBool()) + return; + if(sd && sd->support_tree_ptr) { std::vector heights; heights.reserve(po.m_slice_index.size()); @@ -964,7 +972,8 @@ void SLAPrint::process() po.m_slice_index[i].set_support_slice_idx(po, i); } - // Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update status to the 3D preview to load the SLA slices. + // Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update + // status to the 3D preview to load the SLA slices. m_report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); }; @@ -1536,14 +1545,17 @@ bool SLAPrint::is_step_done(SLAPrintObjectStep step) const return true; } -SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object): - Inherited(print, model_object), - m_stepmask(slaposCount, true), - m_transformed_rmesh( [this](TriangleMesh& obj){ - obj = m_model_object->raw_mesh(); obj.transform(m_trafo); obj.require_shared_vertices(); - }) -{ -} +SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object) + : Inherited(print, model_object) + , m_stepmask(slaposCount, true) + , m_transformed_rmesh([this](TriangleMesh &obj) { + obj = m_model_object->raw_mesh(); + if (!obj.empty()) { + obj.transform(m_trafo); + obj.require_shared_vertices(); + } + }) +{} SLAPrintObject::~SLAPrintObject() {} @@ -1682,13 +1694,14 @@ namespace { // dummy empty static containers for return values in some methods const std::vector EMPTY_SLICES; const TriangleMesh EMPTY_MESH; const ExPolygons EMPTY_SLICE; +const std::vector EMPTY_SUPPORT_POINTS; } const SliceRecord SliceRecord::EMPTY(0, std::nanf(""), 0.f); const std::vector& SLAPrintObject::get_support_points() const { - return m_supportdata->support_points; + return m_supportdata? m_supportdata->support_points : EMPTY_SUPPORT_POINTS; } const std::vector &SLAPrintObject::get_support_slices() const From 52dc8547aca48764b4c40bbb020dcfaafaedaa72 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 9 Jul 2019 15:08:34 +0200 Subject: [PATCH 21/28] Reverder order of rendering of color print time estimates --- src/slic3r/GUI/Plater.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 7ba9e585ad..dee78aef74 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1132,7 +1132,7 @@ void Sidebar::show_sliced_info_sizer(const bool show) if (ps.estimated_normal_print_time != "N/A") { new_label += wxString::Format("\n - %s", _(L("normal mode"))); info_text += wxString::Format("\n%s", ps.estimated_normal_print_time); - for (unsigned int i = 0; i < (unsigned int)ps.estimated_normal_color_print_times.size(); ++i) + for (int i = (int)ps.estimated_normal_color_print_times.size() - 1; i >= 0; --i) { new_label += wxString::Format("\n - %s%d", _(L("Color ")), i + 1); info_text += wxString::Format("\n%s", ps.estimated_normal_color_print_times[i]); @@ -1141,7 +1141,7 @@ void Sidebar::show_sliced_info_sizer(const bool show) if (ps.estimated_silent_print_time != "N/A") { new_label += wxString::Format("\n - %s", _(L("stealth mode"))); info_text += wxString::Format("\n%s", ps.estimated_silent_print_time); - for (unsigned int i = 0; i < (unsigned int)ps.estimated_normal_color_print_times.size(); ++i) + for (int i = (int)ps.estimated_normal_color_print_times.size() - 1; i >= 0; --i) { new_label += wxString::Format("\n - %s%d", _(L("Color ")), i + 1); info_text += wxString::Format("\n%s", ps.estimated_normal_color_print_times[i]); From 1f74d7fdfc548fc168d2a71e1a341108639516e1 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 9 Jul 2019 15:47:34 +0200 Subject: [PATCH 22/28] Added color number in legend texture for color prints --- src/libslic3r/GCode/PreviewData.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/GCode/PreviewData.cpp b/src/libslic3r/GCode/PreviewData.cpp index 8eba6801e4..8ea52714b2 100644 --- a/src/libslic3r/GCode/PreviewData.cpp +++ b/src/libslic3r/GCode/PreviewData.cpp @@ -466,7 +466,7 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std:: } case Extrusion::Tool: { - unsigned int tools_colors_count = tool_colors.size() / 4; + unsigned int tools_colors_count = (unsigned int)tool_colors.size() / 4; items.reserve(tools_colors_count); for (unsigned int i = 0; i < tools_colors_count; ++i) { @@ -491,17 +491,20 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std:: items.emplace_back(Slic3r::I18N::translate(L("Default print color")), color); break; } + + std::string id_str = std::to_string(i + 1) + ": "; + if (i == 0) { - items.emplace_back((boost::format(Slic3r::I18N::translate(L("up to %.2f mm"))) % cp_values[0].first).str(), color); + items.emplace_back(id_str + (boost::format(Slic3r::I18N::translate(L("up to %.2f mm"))) % cp_values[0].first).str(), color); break; } if (i == color_print_cnt) { - items.emplace_back((boost::format(Slic3r::I18N::translate(L("above %.2f mm"))) % cp_values[i-1].second).str(), color); + items.emplace_back(id_str + (boost::format(Slic3r::I18N::translate(L("above %.2f mm"))) % cp_values[i - 1].second).str(), color); continue; } // items.emplace_back((boost::format(Slic3r::I18N::translate(L("%.2f - %.2f mm"))) % cp_values[i-1] % cp_values[i]).str(), color); - items.emplace_back((boost::format(Slic3r::I18N::translate(L("%.2f - %.2f mm"))) % cp_values[i-1].second % cp_values[i].first).str(), color); + items.emplace_back(id_str + (boost::format(Slic3r::I18N::translate(L("%.2f - %.2f mm"))) % cp_values[i - 1].second% cp_values[i].first).str(), color); } break; } From 1dc0439a31562d901db266a039ca166ba3f7d08e Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 10 Jul 2019 15:55:53 +0200 Subject: [PATCH 23/28] Fixed margins for FreqChangedParams --- src/slic3r/GUI/OptionsGroup.hpp | 6 ++++++ src/slic3r/GUI/Plater.cpp | 15 ++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp index 422a5c2a28..d720787b6c 100644 --- a/src/slic3r/GUI/OptionsGroup.hpp +++ b/src/slic3r/GUI/OptionsGroup.hpp @@ -162,6 +162,12 @@ public: void clear_fields_except_of(const std::vector left_fields); + void hide_labels() { + label_width = 0; + m_grid_sizer->SetCols(m_grid_sizer->GetEffectiveColsCount()-1); + static_cast(m_grid_sizer)->AddGrowableCol(!extra_column ? 0 : 1); + } + OptionsGroup( wxWindow* _parent, const wxString& title, bool is_tab_opt = false, column_t extra_clmn = nullptr) : m_parent(_parent), title(title), diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index dee78aef74..3a155c9b0b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -245,6 +245,7 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 * last_selected(wxNOT_FOUND), m_em_unit(wxGetApp().em_unit()) { + SetFont(wxGetApp().normal_font()); Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &evt) { auto selected_item = this->GetSelection(); @@ -373,7 +374,7 @@ class FreqChangedParams : public OG_Settings std::shared_ptr m_og_sla; public: - FreqChangedParams(wxWindow* parent, const int label_width); + FreqChangedParams(wxWindow* parent); ~FreqChangedParams() {} wxButton* get_wiping_dialog_button() { return m_wiping_dialog_button; } @@ -382,14 +383,14 @@ public: void Show(const bool is_fff); }; -FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) : +FreqChangedParams::FreqChangedParams(wxWindow* parent) : OG_Settings(parent, false) { DynamicPrintConfig* config = &wxGetApp().preset_bundle->prints.get_edited_preset().config; // Frequently changed parameters for FFF_technology m_og->set_config(config); - m_og->label_width = label_width == 0 ? 1 : label_width; + m_og->hide_labels(); m_og->m_on_change = [config, this](t_config_option_key opt_key, boost::any value) { Tab* tab_print = wxGetApp().get_tab(Preset::TYPE_PRINT); @@ -485,6 +486,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) : auto wiping_dialog_btn = [config, this](wxWindow* parent) { m_wiping_dialog_button = new wxButton(parent, wxID_ANY, _(L("Purging volumes")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + m_wiping_dialog_button->SetFont(wxGetApp().normal_font()); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(m_wiping_dialog_button); m_wiping_dialog_button->Bind(wxEVT_BUTTON, ([parent](wxCommandEvent& e) @@ -512,9 +514,9 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) : // Frequently changed parameters for SLA_technology m_og_sla = std::make_shared(parent, ""); + m_og_sla->hide_labels(); DynamicPrintConfig* config_sla = &wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; m_og_sla->set_config(config_sla); - m_og_sla->label_width = label_width == 0 ? 1 : label_width; m_og_sla->m_on_change = [config_sla, this](t_config_option_key opt_key, boost::any value) { Tab* tab = wxGetApp().get_tab(Preset::TYPE_SLA_PRINT); @@ -733,13 +735,12 @@ Sidebar::Sidebar(Plater *parent) init_combo(&p->combo_printer, _(L("Printer")), Preset::TYPE_PRINTER, false); const int margin_5 = int(0.5*wxGetApp().em_unit());// 5; - const int margin_10 = 10;//int(1.5*wxGetApp().em_unit());// 15; p->sizer_params = new wxBoxSizer(wxVERTICAL); // Frequently changed parameters - p->frequently_changed_parameters = new FreqChangedParams(p->scrolled, 0/*label_width*/); - p->sizer_params->Add(p->frequently_changed_parameters->get_sizer(), 0, wxEXPAND | wxTOP | wxBOTTOM, margin_10); + p->frequently_changed_parameters = new FreqChangedParams(p->scrolled); + p->sizer_params->Add(p->frequently_changed_parameters->get_sizer(), 0, wxEXPAND | wxTOP | wxBOTTOM, wxOSX ? 1 : margin_5); // Object List p->object_list = new ObjectList(p->scrolled); From 5cbaa7b08129899ff207d660aed42e22531ef9b4 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 10 Jul 2019 17:50:24 +0200 Subject: [PATCH 24/28] FreqChangedParams : workaround for right border alignment --- src/slic3r/GUI/OptionsGroup.cpp | 4 ++-- src/slic3r/GUI/Plater.cpp | 42 +++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 0ed23889e6..9feca2f3d7 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -266,7 +266,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n is_sizer_field(field) ? v_sizer->Add(field->getSizer(), 0, wxEXPAND) : v_sizer->Add(field->getWindow(), 0, wxEXPAND); - return; + break;//return; } is_sizer_field(field) ? @@ -300,7 +300,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n { // extra widget for non-staticbox option group (like for the frequently used parameters on the sidebar) should be wxALIGN_RIGHT const auto v_sizer = new wxBoxSizer(wxVERTICAL); - sizer->Add(v_sizer, 1, wxEXPAND); + sizer->Add(v_sizer, option_set.size() == 1 ? 0 : 1, wxEXPAND); v_sizer->Add(extra_widget(this->ctrl_parent()), 0, wxALIGN_RIGHT); return; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 3a155c9b0b..2988278d79 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -373,6 +373,7 @@ class FreqChangedParams : public OG_Settings wxSizer* m_sizer {nullptr}; std::shared_ptr m_og_sla; + std::vector m_empty_buttons; public: FreqChangedParams(wxWindow* parent); ~FreqChangedParams() {} @@ -381,8 +382,19 @@ public: wxSizer* get_sizer() override; ConfigOptionsGroup* get_og(const bool is_fff); void Show(const bool is_fff); + + void msw_rescale(); }; +void FreqChangedParams::msw_rescale() +{ + m_og->msw_rescale(); + m_og_sla->msw_rescale(); + + for (auto btn: m_empty_buttons) + btn->msw_rescale(); +} + FreqChangedParams::FreqChangedParams(wxWindow* parent) : OG_Settings(parent, false) { @@ -462,6 +474,20 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : Option option = Option(support_def, "support"); option.opt.full_width = true; line.append_option(option); + + /* Not a best solution, but + * Temporary workaround for right border alignment + */ + auto empty_widget = [this] (wxWindow* parent) { + auto sizer = new wxBoxSizer(wxHORIZONTAL); + auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_transparent.png", wxEmptyString, + wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW); + sizer->Add(btn, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, int(0.3 * wxGetApp().em_unit())); + m_empty_buttons.push_back(btn); + return sizer; + }; + line.append_widget(empty_widget); + m_og->append_line(line); @@ -488,7 +514,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : m_wiping_dialog_button = new wxButton(parent, wxID_ANY, _(L("Purging volumes")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); m_wiping_dialog_button->SetFont(wxGetApp().normal_font()); auto sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(m_wiping_dialog_button); + sizer->Add(m_wiping_dialog_button, 0, wxALIGN_CENTER_VERTICAL); m_wiping_dialog_button->Bind(wxEVT_BUTTON, ([parent](wxCommandEvent& e) { auto &config = wxGetApp().preset_bundle->project_config; @@ -505,6 +531,13 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : wxPostEvent(parent, SimpleEvent(EVT_SCHEDULE_BACKGROUND_PROCESS, parent)); } })); + + auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_transparent.png", wxEmptyString, + wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW); + sizer->Add(btn , 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, + int(0.3 * wxGetApp().em_unit())); + m_empty_buttons.push_back(btn); + return sizer; }; line.append_widget(wiping_dialog_btn); @@ -554,7 +587,8 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : support_def_sla.enum_labels.erase(support_def_sla.enum_labels.begin() + 2); option = Option(support_def_sla, "support"); option.opt.full_width = true; - line.append_option(option); + line.append_option(option); + line.append_widget(empty_widget); m_og_sla->append_line(line); line = Line{ "", "" }; @@ -947,9 +981,7 @@ void Sidebar::msw_rescale() // ... then refill them and set min size to correct layout of the sidebar update_all_preset_comboboxes(); - p->frequently_changed_parameters->get_og(true)->msw_rescale(); - p->frequently_changed_parameters->get_og(false)->msw_rescale(); - + p->frequently_changed_parameters->msw_rescale(); p->object_list->msw_rescale(); p->object_manipulation->msw_rescale(); p->object_settings->msw_rescale(); From cc70c8dff9c6b9395845caba0542954276081613 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 12 Jul 2019 10:13:35 +0200 Subject: [PATCH 25/28] Tech ENABLE_SVG_ICONS set as default --- src/libslic3r/Technologies.hpp | 9 -- src/slic3r/GUI/GLCanvas3D.cpp | 124 -------------- src/slic3r/GUI/GLCanvas3D.hpp | 4 - src/slic3r/GUI/GLToolbar.cpp | 161 +------------------ src/slic3r/GUI/GLToolbar.hpp | 52 ------ src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 6 - src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 8 - src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 5 - src/slic3r/GUI/Gizmos/GLGizmoCut.hpp | 4 - src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 5 - src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp | 4 - src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 5 - src/slic3r/GUI/Gizmos/GLGizmoMove.hpp | 4 - src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 13 -- src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 4 - src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 5 - src/slic3r/GUI/Gizmos/GLGizmoScale.hpp | 4 - src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 5 - src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 4 - src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 152 +---------------- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 14 -- src/slic3r/GUI/Plater.cpp | 18 --- 22 files changed, 2 insertions(+), 608 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index f05bc0b577..ae43369d22 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -41,13 +41,4 @@ #define ENABLE_TEXTURES_FROM_SVG (1 && ENABLE_1_42_0_ALPHA7) -//==================== -// 1.42.0.alpha8 techs -//==================== -#define ENABLE_1_42_0_ALPHA8 1 - -// Toolbars and Gizmos use icons imported from svg files -#define ENABLE_SVG_ICONS (1 && ENABLE_1_42_0_ALPHA8 && ENABLE_TEXTURES_FROM_SVG) - - #endif // _technologies_h_ diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d15d9aa4d3..ec77460921 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1199,11 +1199,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar , m_bed(bed) , m_camera(camera) , m_view_toolbar(view_toolbar) -#if ENABLE_SVG_ICONS , m_toolbar(GLToolbar::Normal, "Top") -#else - , m_toolbar(GLToolbar::Normal) -#endif // ENABLE_SVG_ICONS , m_use_clipping_planes(false) , m_sidebar_field("") , m_keep_dirty(false) @@ -3422,12 +3418,6 @@ bool GLCanvas3D::_init_toolbar() if (!m_toolbar.is_enabled()) return true; -#if !ENABLE_SVG_ICONS - ItemsIconsTexture::Metadata icons_data; - icons_data.filename = "toolbar.png"; - icons_data.icon_size = 37; -#endif // !ENABLE_SVG_ICONS - BackgroundTexture::Metadata background_data; background_data.filename = "toolbar_background.png"; background_data.left = 16; @@ -3435,11 +3425,7 @@ bool GLCanvas3D::_init_toolbar() background_data.right = 16; background_data.bottom = 16; -#if ENABLE_SVG_ICONS if (!m_toolbar.init(background_data)) -#else - if (!m_toolbar.init(icons_data, background_data)) -#endif // ENABLE_SVG_ICONS { // unable to init the toolbar texture, disable it m_toolbar.set_enabled(false); @@ -3456,9 +3442,7 @@ bool GLCanvas3D::_init_toolbar() GLToolbarItem::Data item; item.name = "add"; -#if ENABLE_SVG_ICONS item.icon_filename = "add.svg"; -#endif // ENABLE_SVG_ICONS item.tooltip = _utf8(L("Add...")) + " [" + GUI::shortkey_ctrl_prefix() + "I]"; item.sprite_id = 0; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ADD)); }; @@ -3466,9 +3450,7 @@ bool GLCanvas3D::_init_toolbar() return false; item.name = "delete"; -#if ENABLE_SVG_ICONS item.icon_filename = "remove.svg"; -#endif // ENABLE_SVG_ICONS item.tooltip = _utf8(L("Delete")) + " [Del]"; item.sprite_id = 1; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE)); }; @@ -3477,9 +3459,7 @@ bool GLCanvas3D::_init_toolbar() return false; item.name = "deleteall"; -#if ENABLE_SVG_ICONS item.icon_filename = "delete_all.svg"; -#endif // ENABLE_SVG_ICONS item.tooltip = _utf8(L("Delete all")) + " [" + GUI::shortkey_ctrl_prefix() + "Del]"; item.sprite_id = 2; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE_ALL)); }; @@ -3488,9 +3468,7 @@ bool GLCanvas3D::_init_toolbar() return false; item.name = "arrange"; -#if ENABLE_SVG_ICONS item.icon_filename = "arrange.svg"; -#endif // ENABLE_SVG_ICONS item.tooltip = _utf8(L("Arrange")) + " [A]"; item.sprite_id = 3; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ARRANGE)); }; @@ -3502,9 +3480,7 @@ bool GLCanvas3D::_init_toolbar() return false; item.name = "copy"; -#if ENABLE_SVG_ICONS item.icon_filename = "copy.svg"; -#endif // ENABLE_SVG_ICONS item.tooltip = _utf8(L("Copy")) + " [" + GUI::shortkey_ctrl_prefix() + "C]"; item.sprite_id = 4; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_COPY)); }; @@ -3513,9 +3489,7 @@ bool GLCanvas3D::_init_toolbar() return false; item.name = "paste"; -#if ENABLE_SVG_ICONS item.icon_filename = "paste.svg"; -#endif // ENABLE_SVG_ICONS item.tooltip = _utf8(L("Paste")) + " [" + GUI::shortkey_ctrl_prefix() + "V]"; item.sprite_id = 5; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_PASTE)); }; @@ -3527,9 +3501,7 @@ bool GLCanvas3D::_init_toolbar() return false; item.name = "more"; -#if ENABLE_SVG_ICONS item.icon_filename = "instance_add.svg"; -#endif // ENABLE_SVG_ICONS item.tooltip = _utf8(L("Add instance")) + " [+]"; item.sprite_id = 6; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_MORE)); }; @@ -3539,9 +3511,7 @@ bool GLCanvas3D::_init_toolbar() return false; item.name = "fewer"; -#if ENABLE_SVG_ICONS item.icon_filename = "instance_remove.svg"; -#endif // ENABLE_SVG_ICONS item.tooltip = _utf8(L("Remove instance")) + " [-]"; item.sprite_id = 7; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_FEWER)); }; @@ -3554,9 +3524,7 @@ bool GLCanvas3D::_init_toolbar() return false; item.name = "splitobjects"; -#if ENABLE_SVG_ICONS item.icon_filename = "split_objects.svg"; -#endif // ENABLE_SVG_ICONS item.tooltip = _utf8(L("Split to objects")); item.sprite_id = 8; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_OBJECTS)); }; @@ -3566,9 +3534,7 @@ bool GLCanvas3D::_init_toolbar() return false; item.name = "splitvolumes"; -#if ENABLE_SVG_ICONS item.icon_filename = "split_parts.svg"; -#endif // ENABLE_SVG_ICONS item.tooltip = _utf8(L("Split to parts")); item.sprite_id = 9; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_VOLUMES)); }; @@ -3581,9 +3547,7 @@ bool GLCanvas3D::_init_toolbar() return false; item.name = "layersediting"; -#if ENABLE_SVG_ICONS item.icon_filename = "layers_white.svg"; -#endif // ENABLE_SVG_ICONS item.tooltip = _utf8(L("Layers editing")); item.sprite_id = 10; item.is_toggable = true; @@ -3921,9 +3885,6 @@ void GLCanvas3D::_render_overlays() const _render_gizmos_overlay(); _render_warning_texture(); _render_legend_texture(); -#if !ENABLE_SVG_ICONS - _resize_toolbars(); -#endif // !ENABLE_SVG_ICONS _render_toolbar(); _render_view_toolbar(); @@ -4000,7 +3961,6 @@ void GLCanvas3D::_render_current_gizmo() const void GLCanvas3D::_render_gizmos_overlay() const { -#if ENABLE_SVG_ICONS #if ENABLE_RETINA_GL // m_gizmos.set_overlay_scale(m_retina_helper->get_scale_factor()); const float scale = m_retina_helper->get_scale_factor()*wxGetApp().toolbar_icon_scale(); @@ -4011,14 +3971,12 @@ void GLCanvas3D::_render_gizmos_overlay() const const float size = int(GLGizmosManager::Default_Icons_Size*wxGetApp().toolbar_icon_scale()); m_gizmos.set_overlay_icon_size(size); //! #ys_FIXME_experiment #endif /* __WXMSW__ */ -#endif // ENABLE_SVG_ICONS m_gizmos.render_overlay(*this, m_selection); } void GLCanvas3D::_render_toolbar() const { -#if ENABLE_SVG_ICONS #if ENABLE_RETINA_GL // m_toolbar.set_scale(m_retina_helper->get_scale_factor()); const float scale = m_retina_helper->get_scale_factor() * wxGetApp().toolbar_icon_scale(true); @@ -4073,20 +4031,12 @@ void GLCanvas3D::_render_toolbar() const } } m_toolbar.set_position(top, left); -#else -#if ENABLE_RETINA_GL - m_toolbar.set_icons_scale(m_retina_helper->get_scale_factor()); -#else - m_toolbar.set_icons_scale(m_canvas->GetContentScaleFactor()); -#endif /* __WXMSW__ */ -#endif // ENABLE_SVG_ICONS m_toolbar.render(*this); } void GLCanvas3D::_render_view_toolbar() const { -#if ENABLE_SVG_ICONS #if ENABLE_RETINA_GL // m_view_toolbar.set_scale(m_retina_helper->get_scale_factor()); const float scale = m_retina_helper->get_scale_factor() * wxGetApp().toolbar_icon_scale(); @@ -4106,13 +4056,6 @@ void GLCanvas3D::_render_view_toolbar() const float top = (-0.5f * (float)cnv_size.get_height() + m_view_toolbar.get_height()) * inv_zoom; float left = -0.5f * (float)cnv_size.get_width() * inv_zoom; m_view_toolbar.set_position(top, left); -#else -#if ENABLE_RETINA_GL - m_view_toolbar.set_icons_scale(m_retina_helper->get_scale_factor()); -#else - m_view_toolbar.set_icons_scale(m_canvas->GetContentScaleFactor()); -#endif /* __WXMSW__ */ -#endif // ENABLE_SVG_ICONS m_view_toolbar.render(*this); } @@ -5555,73 +5498,6 @@ bool GLCanvas3D::_is_any_volume_outside() const return false; } -#if !ENABLE_SVG_ICONS -void GLCanvas3D::_resize_toolbars() const -{ - Size cnv_size = get_canvas_size(); - float zoom = (float)m_camera.get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; - -#if ENABLE_RETINA_GL - m_toolbar.set_icons_scale(m_retina_helper->get_scale_factor()); -#else - m_toolbar.set_icons_scale(m_canvas->GetContentScaleFactor()); -#endif /* __WXMSW__ */ - - GLToolbar::Layout::EOrientation orientation = m_toolbar.get_layout_orientation(); - - switch (m_toolbar.get_layout_type()) - { - default: - case GLToolbar::Layout::Horizontal: - { - // centers the toolbar on the top edge of the 3d scene - float top, left; - if (orientation == GLToolbar::Layout::Top) - { - top = 0.5f * (float)cnv_size.get_height() * inv_zoom; - left = -0.5f * m_toolbar.get_width() * inv_zoom; - } - else - { - top = (-0.5f * (float)cnv_size.get_height() + m_view_toolbar.get_height()) * inv_zoom; - left = -0.5f * m_toolbar.get_width() * inv_zoom; - } - m_toolbar.set_position(top, left); - break; - } - case GLToolbar::Layout::Vertical: - { - // centers the toolbar on the right edge of the 3d scene - float top, left; - if (orientation == GLToolbar::Layout::Left) - { - top = 0.5f * m_toolbar.get_height() * inv_zoom; - left = (-0.5f * (float)cnv_size.get_width()) * inv_zoom; - } - else - { - top = 0.5f * m_toolbar.get_height() * inv_zoom; - left = (0.5f * (float)cnv_size.get_width() - m_toolbar.get_width()) * inv_zoom; - } - m_toolbar.set_position(top, left); - break; - } - } - -#if ENABLE_RETINA_GL - m_view_toolbar.set_icons_scale(m_retina_helper->get_scale_factor()); -#else - m_view_toolbar.set_icons_scale(m_canvas->GetContentScaleFactor()); -#endif /* __WXMSW__ */ - - // places the toolbar on the bottom-left corner of the 3d scene - float top = (-0.5f * (float)cnv_size.get_height() + m_view_toolbar.get_height()) * inv_zoom; - float left = -0.5f * (float)cnv_size.get_width() * inv_zoom; - m_view_toolbar.set_position(top, left); -} -#endif // !ENABLE_SVG_ICONS - void GLCanvas3D::_update_selection_from_hover() { bool ctrl_pressed = wxGetKeyState(WXK_CONTROL); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 882455a019..2408e02730 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -728,10 +728,6 @@ private: bool _is_any_volume_outside() const; -#if !ENABLE_SVG_ICONS - void _resize_toolbars() const; -#endif // !ENABLE_SVG_ICONS - // updates the selection from the content of m_hover_volume_idxs void _update_selection_from_hover(); diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index a927eba9b1..97bb957ea2 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -38,9 +38,7 @@ const GLToolbarItem::EnabledStateCallback GLToolbarItem::Default_Enabled_State_C GLToolbarItem::Data::Data() : name("") -#if ENABLE_SVG_ICONS , icon_filename("") -#endif // ENABLE_SVG_ICONS , tooltip("") , sprite_id(-1) , is_toggable(false) @@ -105,14 +103,6 @@ GLTexture::Quad_UVs GLToolbarItem::get_uvs(unsigned int tex_width, unsigned int return uvs; } -#if !ENABLE_SVG_ICONS -ItemsIconsTexture::Metadata::Metadata() - : filename("") - , icon_size(0) -{ -} -#endif // !ENABLE_SVG_ICONS - BackgroundTexture::Metadata::Metadata() : filename("") , left(0) @@ -122,9 +112,7 @@ BackgroundTexture::Metadata::Metadata() { } -#if ENABLE_SVG_ICONS const float GLToolbar::Default_Icons_Size = 40.0f; -#endif // ENABLE_SVG_ICONS GLToolbar::Layout::Layout() : type(Horizontal) @@ -134,31 +122,19 @@ GLToolbar::Layout::Layout() , border(0.0f) , separator_size(0.0f) , gap_size(0.0f) -#if ENABLE_SVG_ICONS , icons_size(Default_Icons_Size) , scale(1.0f) -#else - , icons_scale(1.0f) -#endif // ENABLE_SVG_ICONS , width(0.0f) , height(0.0f) , dirty(true) { } -#if ENABLE_SVG_ICONS GLToolbar::GLToolbar(GLToolbar::EType type, const std::string& name) -#else -GLToolbar::GLToolbar(GLToolbar::EType type) -#endif // ENABLE_SVG_ICONS : m_type(type) -#if ENABLE_SVG_ICONS , m_name(name) -#endif // ENABLE_SVG_ICONS , m_enabled(false) -#if ENABLE_SVG_ICONS , m_icons_texture_dirty(true) -#endif // ENABLE_SVG_ICONS , m_tooltip("") { } @@ -171,27 +147,13 @@ GLToolbar::~GLToolbar() } } -#if ENABLE_SVG_ICONS bool GLToolbar::init(const BackgroundTexture::Metadata& background_texture) -#else -bool GLToolbar::init(const ItemsIconsTexture::Metadata& icons_texture, const BackgroundTexture::Metadata& background_texture) -#endif // ENABLE_SVG_ICONS { -#if ENABLE_SVG_ICONS if (m_background_texture.texture.get_id() != 0) return true; std::string path = resources_dir() + "/icons/"; bool res = false; -#else - if (m_icons_texture.texture.get_id() != 0) - return true; - - std::string path = resources_dir() + "/icons/"; - bool res = !icons_texture.filename.empty() && m_icons_texture.texture.load_from_file(path + icons_texture.filename, false, true); - if (res) - m_icons_texture.metadata = icons_texture; -#endif // ENABLE_SVG_ICONS if (!background_texture.filename.empty()) res = m_background_texture.texture.load_from_file(path + background_texture.filename, false, true); @@ -247,7 +209,6 @@ void GLToolbar::set_gap_size(float size) m_layout.dirty = true; } -#if ENABLE_SVG_ICONS void GLToolbar::set_icons_size(float size) { if (m_layout.icons_size != size) @@ -267,13 +228,6 @@ void GLToolbar::set_scale(float scale) m_icons_texture_dirty = true; } } -#else -void GLToolbar::set_icons_scale(float scale) -{ - m_layout.icons_scale = scale; - m_layout.dirty = true; -} -#endif // ENABLE_SVG_ICONS bool GLToolbar::is_enabled() const { @@ -385,10 +339,8 @@ void GLToolbar::render(const GLCanvas3D& parent) const if (!m_enabled || m_items.empty()) return; -#if ENABLE_SVG_ICONS if (m_icons_texture_dirty) generate_icons_texture(); -#endif // ENABLE_SVG_ICONS switch (m_layout.type) { @@ -492,20 +444,12 @@ float GLToolbar::get_width_horizontal() const float GLToolbar::get_width_vertical() const { -#if ENABLE_SVG_ICONS return (2.0f * m_layout.border + m_layout.icons_size) * m_layout.scale; -#else - return 2.0f * m_layout.border * m_layout.icons_scale + m_icons_texture.metadata.icon_size * m_layout.icons_scale; -#endif // ENABLE_SVG_ICONS } float GLToolbar::get_height_horizontal() const { -#if ENABLE_SVG_ICONS return (2.0f * m_layout.border + m_layout.icons_size) * m_layout.scale; -#else - return 2.0f * m_layout.border * m_layout.icons_scale + m_icons_texture.metadata.icon_size * m_layout.icons_scale; -#endif // ENABLE_SVG_ICONS } float GLToolbar::get_height_vertical() const @@ -515,7 +459,6 @@ float GLToolbar::get_height_vertical() const float GLToolbar::get_main_size() const { -#if ENABLE_SVG_ICONS float size = 2.0f * m_layout.border; for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i) { @@ -531,25 +474,7 @@ float GLToolbar::get_main_size() const if (m_items.size() > 1) size += ((float)m_items.size() - 1.0f) * m_layout.gap_size; - size *= m_layout.scale; -#else - float size = 2.0f * m_layout.border * m_layout.icons_scale; - for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i) - { - if (!m_items[i]->is_visible()) - continue; - - if (m_items[i]->is_separator()) - size += m_layout.separator_size * m_layout.icons_scale; - else - size += (float)m_icons_texture.metadata.icon_size * m_layout.icons_scale; - } - - if (m_items.size() > 1) - size += ((float)m_items.size() - 1.0f) * m_layout.gap_size * m_layout.icons_scale; -#endif // ENABLE_SVG_ICONS - - return size; + return size * m_layout.scale; } void GLToolbar::do_action(unsigned int item_id, GLCanvas3D& parent) @@ -609,20 +534,12 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC float zoom = (float)parent.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; -#if ENABLE_SVG_ICONS float factor = m_layout.scale * inv_zoom; -#else - float factor = m_layout.icons_scale * inv_zoom; -#endif // ENABLE_SVG_ICONS Size cnv_size = parent.get_canvas_size(); Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom); -#if ENABLE_SVG_ICONS float scaled_icons_size = m_layout.icons_size * factor; -#else - float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor; -#endif // ENABLE_SVG_ICONS float scaled_separator_size = m_layout.separator_size * factor; float scaled_gap_size = m_layout.gap_size * factor; float scaled_border = m_layout.border * factor; @@ -714,20 +631,12 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan float zoom = (float)parent.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; -#if ENABLE_SVG_ICONS float factor = m_layout.scale * inv_zoom; -#else - float factor = m_layout.icons_scale * inv_zoom; -#endif // ENABLE_SVG_ICONS Size cnv_size = parent.get_canvas_size(); Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom); -#if ENABLE_SVG_ICONS float scaled_icons_size = m_layout.icons_size * factor; -#else - float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor; -#endif // ENABLE_SVG_ICONS float scaled_separator_size = m_layout.separator_size * factor; float scaled_gap_size = m_layout.gap_size * factor; float scaled_border = m_layout.border * factor; @@ -831,20 +740,12 @@ int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3 float zoom = (float)parent.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; -#if ENABLE_SVG_ICONS float factor = m_layout.scale * inv_zoom; -#else - float factor = m_layout.icons_scale * inv_zoom; -#endif // ENABLE_SVG_ICONS Size cnv_size = parent.get_canvas_size(); Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom); -#if ENABLE_SVG_ICONS float scaled_icons_size = m_layout.icons_size * factor; -#else - float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor; -#endif // ENABLE_SVG_ICONS float scaled_separator_size = m_layout.separator_size * factor; float scaled_gap_size = m_layout.gap_size * factor; float scaled_border = m_layout.border * factor; @@ -914,20 +815,12 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D& float zoom = (float)parent.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; -#if ENABLE_SVG_ICONS float factor = m_layout.scale * inv_zoom; -#else - float factor = m_layout.icons_scale * inv_zoom; -#endif // ENABLE_SVG_ICONS Size cnv_size = parent.get_canvas_size(); Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom); -#if ENABLE_SVG_ICONS float scaled_icons_size = m_layout.icons_size * factor; -#else - float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor; -#endif // ENABLE_SVG_ICONS float scaled_separator_size = m_layout.separator_size * factor; float scaled_gap_size = m_layout.gap_size * factor; float scaled_border = m_layout.border * factor; @@ -993,34 +886,15 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D& void GLToolbar::render_horizontal(const GLCanvas3D& parent) const { -#if ENABLE_SVG_ICONS unsigned int tex_id = m_icons_texture.get_id(); int tex_width = m_icons_texture.get_width(); int tex_height = m_icons_texture.get_height(); -#else - unsigned int tex_id = m_icons_texture.texture.get_id(); - int tex_width = m_icons_texture.texture.get_width(); - int tex_height = m_icons_texture.texture.get_height(); -#endif // ENABLE_SVG_ICONS - -#if !ENABLE_SVG_ICONS - if ((tex_id == 0) || (tex_width <= 0) || (tex_height <= 0)) - return; -#endif // !ENABLE_SVG_ICONS float zoom = (float)parent.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; -#if ENABLE_SVG_ICONS float factor = inv_zoom * m_layout.scale; -#else - float factor = inv_zoom * m_layout.icons_scale; -#endif // ENABLE_SVG_ICONS -#if ENABLE_SVG_ICONS float scaled_icons_size = m_layout.icons_size * factor; -#else - float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor; -#endif // ENABLE_SVG_ICONS float scaled_separator_size = m_layout.separator_size * factor; float scaled_gap_size = m_layout.gap_size * factor; float scaled_border = m_layout.border * factor; @@ -1121,10 +995,8 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const left += scaled_border; top -= scaled_border; -#if ENABLE_SVG_ICONS if ((tex_id == 0) || (tex_width <= 0) || (tex_height <= 0)) return; -#endif // ENABLE_SVG_ICONS // renders icons for (const GLToolbarItem* item : m_items) @@ -1136,11 +1008,7 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const left += separator_stride; else { -#if ENABLE_SVG_ICONS item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_width, (unsigned int)tex_height, (unsigned int)(m_layout.icons_size * m_layout.scale)); -#else - item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_width, (unsigned int)tex_height, m_icons_texture.metadata.icon_size); -#endif // ENABLE_SVG_ICONS left += icon_stride; } } @@ -1148,34 +1016,15 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const void GLToolbar::render_vertical(const GLCanvas3D& parent) const { -#if ENABLE_SVG_ICONS unsigned int tex_id = m_icons_texture.get_id(); int tex_width = m_icons_texture.get_width(); int tex_height = m_icons_texture.get_height(); -#else - unsigned int tex_id = m_icons_texture.texture.get_id(); - int tex_width = m_icons_texture.texture.get_width(); - int tex_height = m_icons_texture.texture.get_height(); -#endif // ENABLE_SVG_ICONS - -#if !ENABLE_SVG_ICONS - if ((tex_id == 0) || (tex_width <= 0) || (tex_height <= 0)) - return; -#endif // !ENABLE_SVG_ICONS float zoom = (float)parent.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; -#if ENABLE_SVG_ICONS float factor = inv_zoom * m_layout.scale; -#else - float factor = inv_zoom * m_layout.icons_scale; -#endif // ENABLE_SVG_ICONS -#if ENABLE_SVG_ICONS float scaled_icons_size = m_layout.icons_size * factor; -#else - float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_layout.icons_scale * factor; -#endif // ENABLE_SVG_ICONS float scaled_separator_size = m_layout.separator_size * factor; float scaled_gap_size = m_layout.gap_size * factor; float scaled_border = m_layout.border * factor; @@ -1276,10 +1125,8 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const left += scaled_border; top -= scaled_border; -#if ENABLE_SVG_ICONS if ((tex_id == 0) || (tex_width <= 0) || (tex_height <= 0)) return; -#endif // ENABLE_SVG_ICONS // renders icons for (const GLToolbarItem* item : m_items) @@ -1291,17 +1138,12 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const top -= separator_stride; else { -#if ENABLE_SVG_ICONS item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_width, (unsigned int)tex_height, (unsigned int)(m_layout.icons_size * m_layout.scale)); -#else - item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_width, (unsigned int)tex_height, m_icons_texture.metadata.icon_size); -#endif // ENABLE_SVG_ICONS top -= icon_stride; } } } -#if ENABLE_SVG_ICONS bool GLToolbar::generate_icons_texture() const { std::string path = resources_dir() + "/icons/"; @@ -1337,7 +1179,6 @@ bool GLToolbar::generate_icons_texture() const return res; } -#endif // ENABLE_SVG_ICONS bool GLToolbar::update_items_visibility() { diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp index 24314d60ff..7b4cf8b10f 100644 --- a/src/slic3r/GUI/GLToolbar.hpp +++ b/src/slic3r/GUI/GLToolbar.hpp @@ -58,9 +58,7 @@ public: struct Data { std::string name; -#if ENABLE_SVG_ICONS std::string icon_filename; -#endif // ENABLE_SVG_ICONS std::string tooltip; unsigned int sprite_id; bool is_toggable; @@ -88,9 +86,7 @@ public: void set_state(EState state) { m_state = state; } const std::string& get_name() const { return m_data.name; } -#if ENABLE_SVG_ICONS const std::string& get_icon_filename() const { return m_data.icon_filename; } -#endif // ENABLE_SVG_ICONS const std::string& get_tooltip() const { return m_data.tooltip; } void do_action() { m_data.action_callback(); } @@ -118,27 +114,6 @@ private: friend class GLToolbar; }; -#if !ENABLE_SVG_ICONS -// items icon textures are assumed to be square and all with the same size in pixels, no internal check is done -// icons are layed-out into the texture starting from the top-left corner in the same order as enum GLToolbarItem::EState -// from left to right -struct ItemsIconsTexture -{ - struct Metadata - { - // path of the file containing the icons' texture - std::string filename; - // size of the square icons, in pixels - unsigned int icon_size; - - Metadata(); - }; - - GLTexture texture; - Metadata metadata; -}; -#endif // !ENABLE_SVG_ICONS - struct BackgroundTexture { struct Metadata @@ -164,9 +139,7 @@ struct BackgroundTexture class GLToolbar { public: -#if ENABLE_SVG_ICONS static const float Default_Icons_Size; -#endif // ENABLE_SVG_ICONS enum EType : unsigned char { @@ -201,12 +174,8 @@ public: float border; float separator_size; float gap_size; -#if ENABLE_SVG_ICONS float icons_size; float scale; -#else - float icons_scale; -#endif // ENABLE_SVG_ICONS float width; float height; @@ -219,16 +188,10 @@ private: typedef std::vector ItemsList; EType m_type; -#if ENABLE_SVG_ICONS std::string m_name; -#endif // ENABLE_SVG_ICONS bool m_enabled; -#if ENABLE_SVG_ICONS mutable GLTexture m_icons_texture; mutable bool m_icons_texture_dirty; -#else - ItemsIconsTexture m_icons_texture; -#endif // ENABLE_SVG_ICONS BackgroundTexture m_background_texture; mutable Layout m_layout; @@ -251,18 +214,10 @@ private: std::string m_tooltip; public: -#if ENABLE_SVG_ICONS GLToolbar(EType type, const std::string& name); -#else - explicit GLToolbar(EType type); -#endif // ENABLE_SVG_ICONS ~GLToolbar(); -#if ENABLE_SVG_ICONS bool init(const BackgroundTexture::Metadata& background_texture); -#else - bool init(const ItemsIconsTexture::Metadata& icons_texture, const BackgroundTexture::Metadata& background_texture); -#endif // ENABLE_SVG_ICONS Layout::EType get_layout_type() const; void set_layout_type(Layout::EType type); @@ -273,12 +228,8 @@ public: void set_border(float border); void set_separator_size(float size); void set_gap_size(float size); -#if ENABLE_SVG_ICONS void set_icons_size(float size); void set_scale(float scale); -#else - void set_icons_scale(float scale); -#endif // ENABLE_SVG_ICONS bool is_enabled() const; void set_enabled(bool enable); @@ -297,7 +248,6 @@ public: const std::string& get_tooltip() const { return m_tooltip; } - // returns true if any item changed its state bool update_items_state(); @@ -324,9 +274,7 @@ private: void render_horizontal(const GLCanvas3D& parent) const; void render_vertical(const GLCanvas3D& parent) const; -#if ENABLE_SVG_ICONS bool generate_icons_texture() const; -#endif // ENABLE_SVG_ICONS // returns true if any item changed its state bool update_items_visibility(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 030bd0146e..7da3dec8aa 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -132,18 +132,12 @@ void GLGizmoBase::Grabber::render_face(float half_size) const glsafe(::glEnd()); } -#if ENABLE_SVG_ICONS GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) -#else -GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, unsigned int sprite_id) -#endif // ENABLE_SVG_ICONS : m_parent(parent) , m_group_id(-1) , m_state(Off) , m_shortcut_key(0) -#if ENABLE_SVG_ICONS , m_icon_filename(icon_filename) -#endif // ENABLE_SVG_ICONS , m_sprite_id(sprite_id) , m_hover_id(-1) , m_dragging(false) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index a29aaed3fe..73c73a2c96 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -89,9 +89,7 @@ protected: int m_group_id; EState m_state; int m_shortcut_key; -#if ENABLE_SVG_ICONS std::string m_icon_filename; -#endif // ENABLE_SVG_ICONS unsigned int m_sprite_id; int m_hover_id; bool m_dragging; @@ -102,11 +100,7 @@ protected: ImGuiWrapper* m_imgui; public: -#if ENABLE_SVG_ICONS GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); -#else - GLGizmoBase(GLCanvas3D& parent, unsigned int sprite_id); -#endif // ENABLE_SVG_ICONS virtual ~GLGizmoBase() {} bool init() { return on_init(); } @@ -122,9 +116,7 @@ public: int get_shortcut_key() const { return m_shortcut_key; } void set_shortcut_key(int key) { m_shortcut_key = key; } -#if ENABLE_SVG_ICONS const std::string& get_icon_filename() const { return m_icon_filename; } -#endif // ENABLE_SVG_ICONS bool is_activable(const Selection& selection) const { return on_is_activable(selection); } bool is_selectable() const { return on_is_selectable(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 17db953d46..b1c2950983 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -19,13 +19,8 @@ const double GLGizmoCut::Offset = 10.0; const double GLGizmoCut::Margin = 20.0; const std::array GLGizmoCut::GrabberColor = { 1.0, 0.5, 0.0 }; -#if ENABLE_SVG_ICONS GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -#else -GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, unsigned int sprite_id) - : GLGizmoBase(parent, sprite_id) -#endif // ENABLE_SVG_ICONS , m_cut_z(0.0) , m_max_z(0.0) , m_keep_upper(true) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index fd4e8d8dc0..79a7c58e27 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -23,11 +23,7 @@ class GLGizmoCut : public GLGizmoBase bool m_rotate_lower; public: -#if ENABLE_SVG_ICONS GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); -#else - GLGizmoCut(GLCanvas3D& parent, unsigned int sprite_id); -#endif // ENABLE_SVG_ICONS protected: virtual bool on_init(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index ec991a2413..6bb81a7032 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -9,13 +9,8 @@ namespace Slic3r { namespace GUI { -#if ENABLE_SVG_ICONS GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -#else -GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, unsigned int sprite_id) - : GLGizmoBase(parent, sprite_id) -#endif // ENABLE_SVG_ICONS , m_normal(Vec3d::Zero()) , m_starting_center(Vec3d::Zero()) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp index 1bd17e5ef1..926dc34576 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp @@ -37,11 +37,7 @@ private: bool is_plane_update_necessary() const; public: -#if ENABLE_SVG_ICONS GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); -#else - GLGizmoFlatten(GLCanvas3D& parent, unsigned int sprite_id); -#endif // ENABLE_SVG_ICONS void set_flattening_data(const ModelObject* model_object); Vec3d get_flattening_normal() const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index a2ea738f5f..b97f578b3a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -10,13 +10,8 @@ namespace GUI { const double GLGizmoMove3D::Offset = 10.0; -#if ENABLE_SVG_ICONS GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -#else -GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, unsigned int sprite_id) - : GLGizmoBase(parent, sprite_id) -#endif // ENABLE_SVG_ICONS , m_displacement(Vec3d::Zero()) , m_snap_step(1.0) , m_starting_drag_position(Vec3d::Zero()) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp index ddab2b777d..7714967808 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp @@ -22,11 +22,7 @@ class GLGizmoMove3D : public GLGizmoBase GLUquadricObj* m_quadric; public: -#if ENABLE_SVG_ICONS GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); -#else - GLGizmoMove3D(GLCanvas3D& parent, unsigned int sprite_id); -#endif // ENABLE_SVG_ICONS virtual ~GLGizmoMove3D(); double get_snap_step(double step) const { return m_snap_step; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 68b9a8c332..f84c3886d7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -19,11 +19,7 @@ const unsigned int GLGizmoRotate::SnapRegionsCount = 8; const float GLGizmoRotate::GrabberOffset = 0.15f; // in percent of radius GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis) -#if ENABLE_SVG_ICONS : GLGizmoBase(parent, "", -1) -#else - : GLGizmoBase(parent, -1) -#endif // ENABLE_SVG_ICONS , m_axis(axis) , m_angle(0.0) , m_quadric(nullptr) @@ -40,11 +36,7 @@ GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis) } GLGizmoRotate::GLGizmoRotate(const GLGizmoRotate& other) -#if ENABLE_SVG_ICONS : GLGizmoBase(other.m_parent, other.m_icon_filename, other.m_sprite_id) -#else - : GLGizmoBase(other.m_parent, other.m_sprite_id) -#endif // ENABLE_SVG_ICONS , m_axis(other.m_axis) , m_angle(other.m_angle) , m_quadric(nullptr) @@ -417,13 +409,8 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, cons return transform(mouse_ray, m).intersect_plane(0.0); } -#if ENABLE_SVG_ICONS GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -#else -GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent, unsigned int sprite_id) - : GLGizmoBase(parent, sprite_id) -#endif // ENABLE_SVG_ICONS { m_gizmos.emplace_back(parent, GLGizmoRotate::X); m_gizmos.emplace_back(parent, GLGizmoRotate::Y); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index c65dee4d89..d2e5649669 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -76,11 +76,7 @@ class GLGizmoRotate3D : public GLGizmoBase std::vector m_gizmos; public: -#if ENABLE_SVG_ICONS GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); -#else - GLGizmoRotate3D(GLCanvas3D& parent, unsigned int sprite_id); -#endif // ENABLE_SVG_ICONS Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); } void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index ca5383b0d5..d30ceb092a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -13,13 +13,8 @@ namespace GUI { const float GLGizmoScale3D::Offset = 5.0f; -#if ENABLE_SVG_ICONS GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -#else -GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, unsigned int sprite_id) - : GLGizmoBase(parent, sprite_id) -#endif // ENABLE_SVG_ICONS , m_scale(Vec3d::Ones()) , m_offset(Vec3d::Zero()) , m_snap_step(0.05) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp index 3b0717f04f..16307165f6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp @@ -32,11 +32,7 @@ class GLGizmoScale3D : public GLGizmoBase StartingData m_starting; public: -#if ENABLE_SVG_ICONS GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); -#else - GLGizmoScale3D(GLCanvas3D& parent, unsigned int sprite_id); -#endif // ENABLE_SVG_ICONS double get_snap_step(double step) const { return m_snap_step; } void set_snap_step(double step) { m_snap_step = step; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 7e2b558d94..7b6cb0cc23 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -19,13 +19,8 @@ namespace Slic3r { namespace GUI { -#if ENABLE_SVG_ICONS GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -#else -GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, unsigned int sprite_id) - : GLGizmoBase(parent, sprite_id) -#endif // ENABLE_SVG_ICONS , m_quadric(nullptr) , m_its(nullptr) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 30238cc9dd..f4b2fbb0e5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -58,11 +58,7 @@ private: }; public: -#if ENABLE_SVG_ICONS GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); -#else - GLGizmoSlaSupports(GLCanvas3D& parent, unsigned int sprite_id); -#endif // ENABLE_SVG_ICONS virtual ~GLGizmoSlaSupports(); void set_sla_support_data(ModelObject* model_object, const Selection& selection); bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index c9005807de..315027dadf 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -12,17 +12,12 @@ namespace Slic3r { namespace GUI { -#if ENABLE_SVG_ICONS - const float GLGizmosManager::Default_Icons_Size = 64; -#endif // ENABLE_SVG_ICONS +const float GLGizmosManager::Default_Icons_Size = 64; GLGizmosManager::GLGizmosManager() : m_enabled(false) -#if ENABLE_SVG_ICONS , m_icons_texture_dirty(true) -#endif // ENABLE_SVG_ICONS , m_current(Undefined) -#if ENABLE_SVG_ICONS , m_overlay_icons_size(Default_Icons_Size) , m_overlay_scale(1.0f) , m_overlay_border(5.0f) @@ -30,11 +25,6 @@ GLGizmosManager::GLGizmosManager() , m_tooltip("") { } -#else -{ - set_overlay_scale(1.0); -} -#endif // ENABLE_SVG_ICONS GLGizmosManager::~GLGizmosManager() { @@ -43,20 +33,6 @@ GLGizmosManager::~GLGizmosManager() bool GLGizmosManager::init(GLCanvas3D& parent) { -#if !ENABLE_SVG_ICONS - m_icons_texture.metadata.filename = "gizmos.png"; - m_icons_texture.metadata.icon_size = 64; - - if (!m_icons_texture.metadata.filename.empty()) - { - if (!m_icons_texture.texture.load_from_file(resources_dir() + "/icons/" + m_icons_texture.metadata.filename, false, true)) - { - reset(); - return false; - } - } -#endif // !ENABLE_SVG_ICONS - m_background_texture.metadata.filename = "toolbar_background.png"; m_background_texture.metadata.left = 16; m_background_texture.metadata.top = 16; @@ -72,11 +48,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent) } } -#if ENABLE_SVG_ICONS GLGizmoBase* gizmo = new GLGizmoMove3D(parent, "move.svg", 0); -#else - GLGizmoBase* gizmo = new GLGizmoMove3D(parent, 0); -#endif // ENABLE_SVG_ICONS if (gizmo == nullptr) return false; @@ -85,11 +57,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent) m_gizmos.insert(GizmosMap::value_type(Move, gizmo)); -#if ENABLE_SVG_ICONS gizmo = new GLGizmoScale3D(parent, "scale.svg", 1); -#else - gizmo = new GLGizmoScale3D(parent, 1); -#endif // ENABLE_SVG_ICONS if (gizmo == nullptr) return false; @@ -98,11 +66,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent) m_gizmos.insert(GizmosMap::value_type(Scale, gizmo)); -#if ENABLE_SVG_ICONS gizmo = new GLGizmoRotate3D(parent, "rotate.svg", 2); -#else - gizmo = new GLGizmoRotate3D(parent, 2); -#endif // ENABLE_SVG_ICONS if (gizmo == nullptr) { reset(); @@ -117,11 +81,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent) m_gizmos.insert(GizmosMap::value_type(Rotate, gizmo)); -#if ENABLE_SVG_ICONS gizmo = new GLGizmoFlatten(parent, "place.svg", 3); -#else - gizmo = new GLGizmoFlatten(parent, 3); -#endif // ENABLE_SVG_ICONS if (gizmo == nullptr) return false; @@ -132,11 +92,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent) m_gizmos.insert(GizmosMap::value_type(Flatten, gizmo)); -#if ENABLE_SVG_ICONS gizmo = new GLGizmoCut(parent, "cut.svg", 4); -#else - gizmo = new GLGizmoCut(parent, 4); -#endif // ENABLE_SVG_ICONS if (gizmo == nullptr) return false; @@ -147,11 +103,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent) m_gizmos.insert(GizmosMap::value_type(Cut, gizmo)); -#if ENABLE_SVG_ICONS gizmo = new GLGizmoSlaSupports(parent, "sla_supports.svg", 5); -#else - gizmo = new GLGizmoSlaSupports(parent, 5); -#endif // ENABLE_SVG_ICONS if (gizmo == nullptr) return false; @@ -165,7 +117,6 @@ bool GLGizmosManager::init(GLCanvas3D& parent) return true; } -#if ENABLE_SVG_ICONS void GLGizmosManager::set_overlay_icon_size(float size) { if (m_overlay_icons_size != size) @@ -174,21 +125,14 @@ void GLGizmosManager::set_overlay_icon_size(float size) m_icons_texture_dirty = true; } } -#endif // ENABLE_SVG_ICONS void GLGizmosManager::set_overlay_scale(float scale) { -#if ENABLE_SVG_ICONS if (m_overlay_scale != scale) { m_overlay_scale = scale; m_icons_texture_dirty = true; } -#else - m_overlay_icons_scale = scale; - m_overlay_border = 5.0f * scale; - m_overlay_gap_y = 5.0f * scale; -#endif // ENABLE_SVG_ICONS } void GLGizmosManager::refresh_on_off_state(const Selection& selection) @@ -526,10 +470,8 @@ void GLGizmosManager::render_overlay(const GLCanvas3D& canvas, const Selection& if (!m_enabled) return; -#if ENABLE_SVG_ICONS if (m_icons_texture_dirty) generate_icons_texture(); -#endif // ENABLE_SVG_ICONS do_render_overlay(canvas, selection); } @@ -935,11 +877,7 @@ void GLGizmosManager::do_render_overlay(const GLCanvas3D& canvas, const Selectio float height = get_total_overlay_height(); float width = get_total_overlay_width(); -#if ENABLE_SVG_ICONS float scaled_border = m_overlay_border * m_overlay_scale * inv_zoom; -#else - float scaled_border = m_overlay_border * inv_zoom; -#endif // ENABLE_SVG_ICONS float top_x = (-0.5f * cnv_w) * inv_zoom; float top_y = (0.5f * height) * inv_zoom; @@ -1015,7 +953,6 @@ void GLGizmosManager::do_render_overlay(const GLCanvas3D& canvas, const Selectio } } -#if ENABLE_SVG_ICONS top_x += scaled_border; top_y -= scaled_border; float scaled_gap_y = m_overlay_gap_y * m_overlay_scale * inv_zoom; @@ -1027,21 +964,9 @@ void GLGizmosManager::do_render_overlay(const GLCanvas3D& canvas, const Selectio unsigned int tex_height = m_icons_texture.get_height(); float inv_tex_width = (tex_width != 0) ? 1.0f / (float)tex_width : 0.0f; float inv_tex_height = (tex_height != 0) ? 1.0f / (float)tex_height : 0.0f; -#else - top_x += m_overlay_border * inv_zoom; - top_y -= m_overlay_border * inv_zoom; - float scaled_gap_y = m_overlay_gap_y * inv_zoom; - float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale * inv_zoom; - unsigned int icons_texture_id = m_icons_texture.texture.get_id(); - unsigned int texture_size = m_icons_texture.texture.get_width(); - float inv_texture_size = (texture_size != 0) ? 1.0f / (float)texture_size : 0.0f; -#endif // ENABLE_SVG_ICONS - -#if ENABLE_SVG_ICONS if ((icons_texture_id == 0) || (tex_width <= 0) || (tex_height <= 0)) return; -#endif // ENABLE_SVG_ICONS for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) { @@ -1051,78 +976,44 @@ void GLGizmosManager::do_render_overlay(const GLCanvas3D& canvas, const Selectio unsigned int sprite_id = it->second->get_sprite_id(); GLGizmoBase::EState state = it->second->get_state(); -#if ENABLE_SVG_ICONS float u_icon_size = m_overlay_icons_size * m_overlay_scale * inv_tex_width; float v_icon_size = m_overlay_icons_size * m_overlay_scale * inv_tex_height; float v_top = sprite_id * v_icon_size; float u_left = state * u_icon_size; float v_bottom = v_top + v_icon_size; float u_right = u_left + u_icon_size; -#else - float uv_icon_size = (float)m_icons_texture.metadata.icon_size * inv_texture_size; - float v_top = sprite_id * uv_icon_size; - float u_left = state * uv_icon_size; - float v_bottom = v_top + uv_icon_size; - float u_right = u_left + uv_icon_size; -#endif // ENABLE_SVG_ICONS GLTexture::render_sub_texture(icons_texture_id, top_x, top_x + scaled_icons_size, top_y - scaled_icons_size, top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } }); if (it->second->get_state() == GLGizmoBase::On) { float toolbar_top = (float)cnv_h - canvas.get_view_toolbar_height(); -#if ENABLE_SVG_ICONS it->second->render_input_window(width, 0.5f * cnv_h - top_y * zoom, toolbar_top, selection); -#else - it->second->render_input_window(2.0f * m_overlay_border + scaled_icons_size * zoom, 0.5f * cnv_h - top_y * zoom, toolbar_top, selection); -#endif // ENABLE_SVG_ICONS } -#if ENABLE_SVG_ICONS top_y -= scaled_stride_y; -#else - top_y -= (scaled_icons_size + scaled_gap_y); -#endif // ENABLE_SVG_ICONS } } float GLGizmosManager::get_total_overlay_height() const { -#if ENABLE_SVG_ICONS float scaled_icons_size = m_overlay_icons_size * m_overlay_scale; float scaled_border = m_overlay_border * m_overlay_scale; float scaled_gap_y = m_overlay_gap_y * m_overlay_scale; float scaled_stride_y = scaled_icons_size + scaled_gap_y; float height = 2.0f * scaled_border; -#else - float height = 2.0f * m_overlay_border; - - float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale; -#endif // ENABLE_SVG_ICONS for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) { if ((it->second == nullptr) || !it->second->is_selectable()) continue; -#if ENABLE_SVG_ICONS height += scaled_stride_y; -#else - height += (scaled_icons_size + m_overlay_gap_y); -#endif // ENABLE_SVG_ICONS } -#if ENABLE_SVG_ICONS return height - scaled_gap_y; -#else - return height - m_overlay_gap_y; -#endif // ENABLE_SVG_ICONS } float GLGizmosManager::get_total_overlay_width() const { -#if ENABLE_SVG_ICONS return (2.0f * m_overlay_border + m_overlay_icons_size) * m_overlay_scale; -#else - return (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale + 2.0f * m_overlay_border; -#endif // ENABLE_SVG_ICONS } GLGizmoBase* GLGizmosManager::get_current() const @@ -1131,7 +1022,6 @@ GLGizmoBase* GLGizmosManager::get_current() const return (it != m_gizmos.end()) ? it->second : nullptr; } -#if ENABLE_SVG_ICONS bool GLGizmosManager::generate_icons_texture() const { std::string path = resources_dir() + "/icons/"; @@ -1157,7 +1047,6 @@ bool GLGizmosManager::generate_icons_texture() const return res; } -#endif // ENABLE_SVG_ICONS void GLGizmosManager::update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection) { @@ -1167,27 +1056,18 @@ void GLGizmosManager::update_on_off_state(const GLCanvas3D& canvas, const Vec2d& float cnv_h = (float)canvas.get_canvas_size().get_height(); float height = get_total_overlay_height(); -#if ENABLE_SVG_ICONS float scaled_icons_size = m_overlay_icons_size * m_overlay_scale; float scaled_border = m_overlay_border * m_overlay_scale; float scaled_gap_y = m_overlay_gap_y * m_overlay_scale; float scaled_stride_y = scaled_icons_size + scaled_gap_y; float top_y = 0.5f * (cnv_h - height) + scaled_border; -#else - float top_y = 0.5f * (cnv_h - height) + m_overlay_border; - float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale; -#endif // ENABLE_SVG_ICONS for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) { if ((it->second == nullptr) || !it->second->is_selectable()) continue; -#if ENABLE_SVG_ICONS bool inside = (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size); -#else - bool inside = (m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size); -#endif // ENABLE_SVG_ICONS if (it->second->is_activable(selection) && inside) { if ((it->second->get_state() == GLGizmoBase::On)) @@ -1204,11 +1084,7 @@ void GLGizmosManager::update_on_off_state(const GLCanvas3D& canvas, const Vec2d& else it->second->set_state(GLGizmoBase::Off); -#if ENABLE_SVG_ICONS top_y += scaled_stride_y; -#else - top_y += (scaled_icons_size + m_overlay_gap_y); -#endif // ENABLE_SVG_ICONS } GizmosMap::iterator it = m_gizmos.find(m_current); @@ -1227,38 +1103,25 @@ std::string GLGizmosManager::update_hover_state(const GLCanvas3D& canvas, const float cnv_h = (float)canvas.get_canvas_size().get_height(); float height = get_total_overlay_height(); -#if ENABLE_SVG_ICONS float scaled_icons_size = m_overlay_icons_size * m_overlay_scale; float scaled_border = m_overlay_border * m_overlay_scale; float scaled_gap_y = m_overlay_gap_y * m_overlay_scale; float scaled_stride_y = scaled_icons_size + scaled_gap_y; float top_y = 0.5f * (cnv_h - height) + scaled_border; -#else - float top_y = 0.5f * (cnv_h - height) + m_overlay_border; - float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale; -#endif // ENABLE_SVG_ICONS for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) { if ((it->second == nullptr) || !it->second->is_selectable()) continue; -#if ENABLE_SVG_ICONS bool inside = (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size); -#else - bool inside = (m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size); -#endif // ENABLE_SVG_ICONS if (inside) name = it->second->get_name(); if (it->second->is_activable(selection) && (it->second->get_state() != GLGizmoBase::On)) it->second->set_state(inside ? GLGizmoBase::Hover : GLGizmoBase::Off); -#if ENABLE_SVG_ICONS top_y += scaled_stride_y; -#else - top_y += (scaled_icons_size + m_overlay_gap_y); -#endif // ENABLE_SVG_ICONS } return name; @@ -1272,34 +1135,21 @@ bool GLGizmosManager::overlay_contains_mouse(const GLCanvas3D& canvas, const Vec float cnv_h = (float)canvas.get_canvas_size().get_height(); float height = get_total_overlay_height(); -#if ENABLE_SVG_ICONS float scaled_icons_size = m_overlay_icons_size * m_overlay_scale; float scaled_border = m_overlay_border * m_overlay_scale; float scaled_gap_y = m_overlay_gap_y * m_overlay_scale; float scaled_stride_y = scaled_icons_size + scaled_gap_y; float top_y = 0.5f * (cnv_h - height) + scaled_border; -#else - float top_y = 0.5f * (cnv_h - height) + m_overlay_border; - float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale; -#endif // ENABLE_SVG_ICONS for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) { if ((it->second == nullptr) || !it->second->is_selectable()) continue; -#if ENABLE_SVG_ICONS if ((scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size)) -#else - if ((m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size)) -#endif // ENABLE_SVG_ICONS return true; -#if ENABLE_SVG_ICONS top_y += scaled_stride_y; -#else - top_y += (scaled_icons_size + m_overlay_gap_y); -#endif // ENABLE_SVG_ICONS } return false; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 1e42a29e68..87be7da41e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -46,9 +46,7 @@ public: class GLGizmosManager { public: -#if ENABLE_SVG_ICONS static const float Default_Icons_Size; -#endif // ENABLE_SVG_ICONS enum EType : unsigned char { @@ -66,21 +64,13 @@ private: bool m_enabled; typedef std::map GizmosMap; GizmosMap m_gizmos; -#if ENABLE_SVG_ICONS mutable GLTexture m_icons_texture; mutable bool m_icons_texture_dirty; -#else - ItemsIconsTexture m_icons_texture; -#endif // ENABLE_SVG_ICONS BackgroundTexture m_background_texture; EType m_current; -#if ENABLE_SVG_ICONS float m_overlay_icons_size; float m_overlay_scale; -#else - float m_overlay_icons_scale; -#endif // ENABLE_SVG_ICONS float m_overlay_border; float m_overlay_gap_y; @@ -109,9 +99,7 @@ public: bool is_enabled() const { return m_enabled; } void set_enabled(bool enable) { m_enabled = enable; } -#if ENABLE_SVG_ICONS void set_overlay_icon_size(float size); -#endif // ENABLE_SVG_ICONS void set_overlay_scale(float scale); void refresh_on_off_state(const Selection& selection); @@ -173,9 +161,7 @@ private: GLGizmoBase* get_current() const; -#if ENABLE_SVG_ICONS bool generate_icons_texture() const; -#endif // ENABLE_SVG_ICONS void update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection); std::string update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 2988278d79..402acd59cf 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1736,11 +1736,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) })) , sidebar(new Sidebar(q)) , delayed_scene_refresh(false) -#if ENABLE_SVG_ICONS , view_toolbar(GLToolbar::Radio, "View") -#else - , view_toolbar(GLToolbar::Radio) -#endif // ENABLE_SVG_ICONS , m_project_filename(wxEmptyString) { this->q->SetFont(Slic3r::GUI::wxGetApp().normal_font()); @@ -3395,12 +3391,6 @@ bool Plater::priv::complit_init_part_menu() void Plater::priv::init_view_toolbar() { -#if !ENABLE_SVG_ICONS - ItemsIconsTexture::Metadata icons_data; - icons_data.filename = "view_toolbar.png"; - icons_data.icon_size = 64; -#endif // !ENABLE_SVG_ICONS - BackgroundTexture::Metadata background_data; background_data.filename = "toolbar_background.png"; background_data.left = 16; @@ -3408,11 +3398,7 @@ void Plater::priv::init_view_toolbar() background_data.right = 16; background_data.bottom = 16; -#if ENABLE_SVG_ICONS if (!view_toolbar.init(background_data)) -#else - if (!view_toolbar.init(icons_data, background_data)) -#endif // ENABLE_SVG_ICONS return; view_toolbar.set_layout_orientation(GLToolbar::Layout::Bottom); @@ -3422,9 +3408,7 @@ void Plater::priv::init_view_toolbar() GLToolbarItem::Data item; item.name = "3D"; -#if ENABLE_SVG_ICONS item.icon_filename = "editor.svg"; -#endif // ENABLE_SVG_ICONS item.tooltip = _utf8(L("3D editor view")) + " [" + GUI::shortkey_ctrl_prefix() + "5]"; item.sprite_id = 0; item.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_3D)); }; @@ -3433,9 +3417,7 @@ void Plater::priv::init_view_toolbar() return; item.name = "Preview"; -#if ENABLE_SVG_ICONS item.icon_filename = "preview.svg"; -#endif // ENABLE_SVG_ICONS item.tooltip = _utf8(L("Preview")) + " [" + GUI::shortkey_ctrl_prefix() + "6]"; item.sprite_id = 1; item.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); }; From 2ee572bd31d38a90d87c85794c7d0a6fa71e552c Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 12 Jul 2019 12:38:00 +0200 Subject: [PATCH 26/28] GCodeAnalyzer now recognizes tool-changing commands with MakerWare and Sailfish flavor These firmwares use M135 Tn and M108 Tn commands for changing active tool, which the analyzer did not recognize. The toolpaths were then rendered in wrong color, extruder offset etc. This surfaced in issue https://github.com/prusa3d/PrusaSlicer/issues/2566 --- src/libslic3r/GCode.cpp | 3 +++ src/libslic3r/GCode/Analyzer.cpp | 40 ++++++++++++++++++++++++++++++-- src/libslic3r/GCode/Analyzer.hpp | 7 ++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index d2e5814935..5af90bc3f5 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -586,6 +586,9 @@ void GCode::_do_export(Print &print, FILE *file) } m_analyzer.set_extruder_offsets(extruder_offsets); + // tell analyzer about the gcode flavor + m_analyzer.set_gcode_flavor(print.config().gcode_flavor); + // resets analyzer's tracking data m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm; m_last_width = GCodeAnalyzer::Default_Width; diff --git a/src/libslic3r/GCode/Analyzer.cpp b/src/libslic3r/GCode/Analyzer.cpp index 321d9a3427..6cf118cc25 100644 --- a/src/libslic3r/GCode/Analyzer.cpp +++ b/src/libslic3r/GCode/Analyzer.cpp @@ -106,6 +106,11 @@ void GCodeAnalyzer::set_extruder_offsets(const GCodeAnalyzer::ExtruderOffsetsMap m_extruder_offsets = extruder_offsets; } +void GCodeAnalyzer::set_gcode_flavor(const GCodeFlavor& flavor) +{ + m_gcode_flavor = flavor; +} + void GCodeAnalyzer::reset() { _set_units(Millimeters); @@ -249,6 +254,14 @@ void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLi _processM83(line); break; } + case 108: + case 135: + { + // these are used by MakerWare and Sailfish firmwares + // for tool changing - we can process it in one place + _processM108orM135(line); + break; + } } break; @@ -426,9 +439,27 @@ void GCodeAnalyzer::_processM600(const GCodeReader::GCodeLine& line) _set_cp_color_id(m_state.cur_cp_color_id); } -void GCodeAnalyzer::_processT(const GCodeReader::GCodeLine& line) +void GCodeAnalyzer::_processM108orM135(const GCodeReader::GCodeLine& line) +{ + // These M-codes are used by MakerWare and Sailfish to change active tool. + // They have to be processed otherwise toolchanges will be unrecognised + // by the analyzer - see https://github.com/prusa3d/PrusaSlicer/issues/2566 + + size_t code = ::atoi(&(line.cmd()[1])); + if ((code == 108 && m_gcode_flavor == gcfSailfish) + || (code == 135 && m_gcode_flavor == gcfMakerWare)) { + + std::string cmd = line.raw(); + size_t T_pos = cmd.find("T"); + if (T_pos != std::string::npos) { + cmd = cmd.substr(T_pos); + _processT(cmd); + } + } +} + +void GCodeAnalyzer::_processT(const std::string& cmd) { - std::string cmd = line.cmd(); if (cmd.length() > 1) { unsigned int id = (unsigned int)::strtol(cmd.substr(1).c_str(), nullptr, 10); @@ -442,6 +473,11 @@ void GCodeAnalyzer::_processT(const GCodeReader::GCodeLine& line) } } +void GCodeAnalyzer::_processT(const GCodeReader::GCodeLine& line) +{ + _processT(line.cmd()); +} + bool GCodeAnalyzer::_process_tags(const GCodeReader::GCodeLine& line) { std::string comment = line.comment(); diff --git a/src/libslic3r/GCode/Analyzer.hpp b/src/libslic3r/GCode/Analyzer.hpp index 4c201c6403..ab8bade71b 100644 --- a/src/libslic3r/GCode/Analyzer.hpp +++ b/src/libslic3r/GCode/Analyzer.hpp @@ -106,6 +106,7 @@ private: GCodeReader m_parser; TypeToMovesMap m_moves_map; ExtruderOffsetsMap m_extruder_offsets; + GCodeFlavor m_gcode_flavor; // The output of process_layer() std::string m_process_output; @@ -115,6 +116,8 @@ public: void set_extruder_offsets(const ExtruderOffsetsMap& extruder_offsets); + void set_gcode_flavor(const GCodeFlavor& flavor); + // Reinitialize the analyzer void reset(); @@ -164,10 +167,14 @@ private: // Set extruder to relative mode void _processM83(const GCodeReader::GCodeLine& line); + // Set tool (MakerWare and Sailfish flavor) + void _processM108orM135(const GCodeReader::GCodeLine& line); + // Set color change void _processM600(const GCodeReader::GCodeLine& line); // Processes T line (Select Tool) + void _processT(const std::string& command); void _processT(const GCodeReader::GCodeLine& line); // Processes the tags From de88db59180822ddffd3b94bbd7b370a4971f196 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 12 Jul 2019 15:36:01 +0200 Subject: [PATCH 27/28] #2616 - Added Recent projects item to File menu --- src/slic3r/GUI/AppConfig.cpp | 27 +++++++++++++++++++ src/slic3r/GUI/AppConfig.hpp | 3 +++ src/slic3r/GUI/MainFrame.cpp | 52 ++++++++++++++++++++++++++++++++++++ src/slic3r/GUI/MainFrame.hpp | 5 ++++ src/slic3r/GUI/Plater.cpp | 13 ++++++--- src/slic3r/GUI/Plater.hpp | 1 + 6 files changed, 98 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 3b62100582..dfdc79677d 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -229,6 +229,33 @@ std::string AppConfig::get_last_dir() const return std::string(); } +std::vector AppConfig::get_recent_projects() const +{ + std::vector ret; + const auto it = m_storage.find("recent_projects"); + if (it != m_storage.end()) + { + for (const std::map::value_type& item : it->second) + { + ret.push_back(item.second); + } + } + return ret; +} + +void AppConfig::set_recent_projects(const std::vector& recent_projects) +{ + auto it = m_storage.find("recent_projects"); + if (it == m_storage.end()) + it = m_storage.insert(std::map>::value_type("recent_projects", std::map())).first; + + it->second.clear(); + for (unsigned int i = 0; i < (unsigned int)recent_projects.size(); ++i) + { + it->second[std::to_string(i + 1)] = recent_projects[i]; + } +} + void AppConfig::update_config_dir(const std::string &dir) { this->set("recent", "config_directory", dir); diff --git a/src/slic3r/GUI/AppConfig.hpp b/src/slic3r/GUI/AppConfig.hpp index 5af635a12c..230a922940 100644 --- a/src/slic3r/GUI/AppConfig.hpp +++ b/src/slic3r/GUI/AppConfig.hpp @@ -122,6 +122,9 @@ public: // Does the config file exist? static bool exists(); + std::vector get_recent_projects() const; + void set_recent_projects(const std::vector& recent_projects); + private: // Map of section, name -> value std::map> m_storage; diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index d800f6f380..99389da410 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -35,6 +35,7 @@ namespace GUI { MainFrame::MainFrame() : DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "mainframe"), m_printhost_queue_dlg(new PrintHostQueueDialog(this)) + , m_recent_projects(9) { // Fonts were created by the DPIFrame constructor for the monitor, on which the window opened. wxGetApp().update_fonts(this); @@ -383,6 +384,40 @@ void MainFrame::init_menubar() append_menu_item(fileMenu, wxID_ANY, _(L("&Open Project")) + dots + "\tCtrl+O", _(L("Open a project file")), [this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, menu_icon("open"), nullptr, [this](){return m_plater != nullptr; }, this); + + wxMenu* recent_projects_menu = new wxMenu(); + wxMenuItem* recent_projects_submenu = append_submenu(fileMenu, recent_projects_menu, wxID_ANY, _(L("Recent projects")), ""); + m_recent_projects.UseMenu(recent_projects_menu); + Bind(wxEVT_MENU, [this](wxCommandEvent& evt) { + size_t file_id = evt.GetId() - wxID_FILE1; + wxString filename = m_recent_projects.GetHistoryFile(file_id); + if (wxFileExists(filename)) + m_plater->load_project(filename); + else + { + wxMessageDialog msg(this, _(L("The selected project is no more available")), _(L("Error"))); + msg.ShowModal(); + + m_recent_projects.RemoveFileFromHistory(file_id); + std::vector recent_projects; + size_t count = m_recent_projects.GetCount(); + for (size_t i = 0; i < count; ++i) + { + recent_projects.push_back(into_u8(m_recent_projects.GetHistoryFile(i))); + } + wxGetApp().app_config->set_recent_projects(recent_projects); + wxGetApp().app_config->save(); + } + }, wxID_FILE1, wxID_FILE9); + + std::vector recent_projects = wxGetApp().app_config->get_recent_projects(); + for (const std::string& project : recent_projects) + { + m_recent_projects.AddFileToHistory(from_u8(project)); + } + + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_recent_projects.GetCount() > 0); }, recent_projects_submenu->GetId()); + append_menu_item(fileMenu, wxID_ANY, _(L("&Save Project")) + "\tCtrl+S", _(L("Save current project file")), [this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(into_path(m_plater->get_project_filename(".3mf"))); }, menu_icon("save"), nullptr, [this](){return m_plater != nullptr && can_save(); }, this); @@ -1046,6 +1081,23 @@ void MainFrame::on_config_changed(DynamicPrintConfig* config) const m_plater->on_config_change(*config); // propagate config change events to the plater } +void MainFrame::add_to_recent_projects(const wxString& filename) +{ + if (wxFileExists(filename)) + { + m_recent_projects.AddFileToHistory(filename); + std::vector recent_projects; + size_t count = m_recent_projects.GetCount(); + for (size_t i = 0; i < count; ++i) + { + recent_projects.push_back(into_u8(m_recent_projects.GetHistoryFile(i))); + } + wxGetApp().app_config->set_recent_projects(recent_projects); + wxGetApp().app_config->save(); + } +} + +// // Called after the Preferences dialog is closed and the program settings are saved. // Update the UI based on the current preferences. void MainFrame::update_ui_from_settings() diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 805b663bb2..a41f33824d 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -84,6 +85,8 @@ class MainFrame : public DPIFrame // vector of a MenuBar items changeable in respect to printer technology std::vector m_changeable_menu_items; + wxFileHistory m_recent_projects; + protected: virtual void on_dpi_changed(const wxRect &suggested_rect); @@ -121,6 +124,8 @@ public: // Propagate changed configuration from the Tab to the Platter and save changes to the AppConfig void on_config_changed(DynamicPrintConfig* cfg) const ; + void add_to_recent_projects(const wxString& filename); + PrintHostQueueDialog* printhost_queue_dlg() { return m_printhost_queue_dlg; } Plater* m_plater { nullptr }; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 402acd59cf..b99b3a6aff 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3277,6 +3277,9 @@ void Plater::priv::set_project_filename(const wxString& filename) m_project_filename = from_path(full_path); wxGetApp().mainframe->update_title(); + + if (!filename.empty()) + wxGetApp().mainframe->add_to_recent_projects(filename); } bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/) @@ -3590,15 +3593,19 @@ void Plater::load_project() { wxString input_file; wxGetApp().load_project(this, input_file); + load_project(input_file); +} - if (input_file.empty()) +void Plater::load_project(const wxString& filename) +{ + if (filename.empty()) return; p->reset(); - p->set_project_filename(input_file); + p->set_project_filename(filename); std::vector input_paths; - input_paths.push_back(into_path(input_file)); + input_paths.push_back(into_path(filename)); load_files(input_paths); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 34fd7984e2..9ba63461e0 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -138,6 +138,7 @@ public: void new_project(); void load_project(); + void load_project(const wxString& filename); void add_model(); void extract_config_from_project(); From 44f0e387dcb42b279fb561238aa49fac00dc5bd3 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Sat, 13 Jul 2019 10:37:21 +0200 Subject: [PATCH 28/28] Fix of #2621 --- src/slic3r/GUI/Plater.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b99b3a6aff..8c074709f7 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -496,7 +496,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : option = m_og->get_option("fill_density"); option.opt.label = L("Infill"); option.opt.width = 7/*6*/; - option.opt.sidetext = " "; + option.opt.sidetext = " "; line.append_option(option); m_brim_width = config->opt_float("brim_width"); @@ -507,7 +507,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : def.gui_type = ""; def.set_default_value(new ConfigOptionBool{ m_brim_width > 0.0 ? true : false }); option = Option(def, "brim"); - option.opt.sidetext = " "; + option.opt.sidetext = ""; line.append_option(option); auto wiping_dialog_btn = [config, this](wxWindow* parent) {