diff --git a/src/libslic3r/SLA/Rotfinder.cpp b/src/libslic3r/SLA/Rotfinder.cpp index d18d2fe6b..804908ab8 100644 --- a/src/libslic3r/SLA/Rotfinder.cpp +++ b/src/libslic3r/SLA/Rotfinder.cpp @@ -442,4 +442,92 @@ Vec2d find_least_supports_rotation(const ModelObject & mo, return {rot[0], rot[1]}; } +inline BoundingBoxf3 bounding_box_with_tr(const indexed_triangle_set& its, const Transform3f &tr) +{ + if (its.vertices.empty()) + return {}; + + Vec3f bmin = tr * its.vertices.front(), bmax = tr * its.vertices.front(); + + for (const Vec3f &p : its.vertices) { + Vec3f pp = tr * p; + bmin = pp.cwiseMin(bmin); + bmax = pp.cwiseMax(bmax); + } + + return {bmin.cast(), bmax.cast()}; +} + +Vec2d find_min_z_height_rotation(const ModelObject &mo, const RotOptimizeParams ¶ms) +{ + static const unsigned MAX_TRIES = 1000; + + // return value + XYRotation rot; + + // We will use only one instance of this converted mesh to examine different + // rotations + TriangleMesh mesh = get_mesh_to_rotate(mo); + + // To keep track of the number of iterations + unsigned status = 0; + + // The maximum number of iterations + auto max_tries = unsigned(params.accuracy() * MAX_TRIES); + + auto &statuscb = params.statuscb(); + + // call status callback with zero, because we are at the start + statuscb(status); + + auto statusfn = [&statuscb, &status, &max_tries] { + // report status + statuscb(unsigned(++status * 100.0/max_tries) ); + }; + + auto stopcond = [&statuscb] { + return ! statuscb(-1); + }; + + TriangleMesh chull = mesh.convex_hull_3d(); + chull.require_shared_vertices(); + auto inputs = reserve_vector(chull.its.indices.size()); + auto rotcmp = [](const XYRotation &r1, const XYRotation &r2) { + double xdiff = r1[X] - r2[X], ydiff = r1[Y] - r2[Y]; + return std::abs(xdiff) < EPSILON ? ydiff < 0. : xdiff < 0.; + }; + auto eqcmp = [](const XYRotation &r1, const XYRotation &r2) { + double xdiff = r1[X] - r2[X], ydiff = r1[Y] - r2[Y]; + return std::abs(xdiff) < EPSILON && std::abs(ydiff) < EPSILON; + }; + + for (size_t fi = 0; fi < chull.its.indices.size(); ++fi) { + Facestats fc{get_triangle_vertices(chull, fi)}; + + auto q = Eigen::Quaternionf{}.FromTwoVectors(fc.normal, DOWN); + XYRotation rot = from_transform3f(Transform3f::Identity() * q); + + auto it = std::lower_bound(inputs.begin(), inputs.end(), rot, rotcmp); + + if (it == inputs.end() || !eqcmp(*it, rot)) + inputs.insert(it, rot); + } + + inputs.shrink_to_fit(); + max_tries = inputs.size(); + + // If the model can be placed on the bed directly, we only need to + // check the 3D convex hull face rotations. + + auto objfn = [&chull, &statusfn](const XYRotation &rot) { + statusfn(); + Transform3f tr = to_transform3f(rot); + return bounding_box_with_tr(chull.its, tr).size().z(); + }; + + rot = find_min_score<2>(objfn, inputs.begin(), inputs.end(), stopcond); + + return {rot[0], rot[1]}; +} + }} // namespace Slic3r::sla diff --git a/src/libslic3r/SLA/Rotfinder.hpp b/src/libslic3r/SLA/Rotfinder.hpp index 77a39016d..d632419fb 100644 --- a/src/libslic3r/SLA/Rotfinder.hpp +++ b/src/libslic3r/SLA/Rotfinder.hpp @@ -63,7 +63,8 @@ Vec2d find_best_misalignment_rotation(const ModelObject &modelobj, Vec2d find_least_supports_rotation(const ModelObject &modelobj, const RotOptimizeParams & = {}); -double find_Z_fit_to_bed_rotation(const ModelObject &mo, const BoundingBox &bed); +Vec2d find_min_z_height_rotation(const ModelObject &mo, + const RotOptimizeParams ¶ms = {}); } // namespace sla } // namespace Slic3r diff --git a/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp b/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp index edabb7cae..d703ff0e3 100644 --- a/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp +++ b/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp @@ -27,9 +27,9 @@ class RotoptimizeJob : public PlaterJob "structures.\nNote that this method will try to find the best surface of the object " "for touching the print bed if no elevation is set.")}, // Just a min area bounding box that is done for all methods anyway. - {L("Smallest bounding box (Z axis only)"), - nullptr, - L("Rotate the object only in Z axis to have the smallest bounding box.")}}; + {L("Smallest Z height"), + sla::find_min_z_height_rotation, + L("Rotate the model to have least z height for faster print time.")}}; size_t m_method_id = 0; float m_accuracy = 0.75;