mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 12:41:20 -06:00 
			
		
		
		
	Mostly working, inefficiencies remain, status indication partly broken
This commit is contained in:
		
							parent
							
								
									9f3e7617d8
								
							
						
					
					
						commit
						0d4c67b9a3
					
				
					 5 changed files with 264 additions and 124 deletions
				
			
		|  | @ -5,27 +5,23 @@ | |||
| #include <libslic3r/Optimize/BruteforceOptimizer.hpp> | ||||
| #include <libslic3r/SLA/Rotfinder.hpp> | ||||
| #include <libslic3r/SLA/Concurrency.hpp> | ||||
| #include <libslic3r/SLA/SupportTree.hpp> | ||||
| 
 | ||||
| #include "libslic3r/SLAPrint.hpp" | ||||
| #include "libslic3r/PrintConfig.hpp" | ||||
| 
 | ||||
| #include <libslic3r/Geometry.hpp> | ||||
| #include "Model.hpp" | ||||
| 
 | ||||
| #include <thread> | ||||
| 
 | ||||
| namespace Slic3r { namespace sla { | ||||
| 
 | ||||
| using VertexFaceMap = std::vector<std::vector<size_t>>; | ||||
| inline bool is_on_floor(const SLAPrintObject &mo) | ||||
| { | ||||
|     auto opt_elevation = mo.config().support_object_elevation.getFloat(); | ||||
|     auto opt_padaround = mo.config().pad_around_object.getBool(); | ||||
| 
 | ||||
| VertexFaceMap create_vertex_face_map(const TriangleMesh &mesh) { | ||||
|     std::vector<std::vector<size_t>> vmap(mesh.its.vertices.size()); | ||||
| 
 | ||||
|     size_t fi = 0; | ||||
|     for (const Vec3i &tri : mesh.its.indices) { | ||||
|         for (int vi = 0; vi < tri.size(); ++vi) { | ||||
|             auto from = vmap[tri(vi)].begin(), to = vmap[tri(vi)].end(); | ||||
|             vmap[tri(vi)].insert(std::lower_bound(from, to, fi), fi); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return vmap; | ||||
|     return opt_elevation < EPSILON || opt_padaround; | ||||
| } | ||||
| 
 | ||||
| // Find transformed mesh ground level without copy and with parallel reduce.
 | ||||
|  | @ -41,62 +37,163 @@ double find_ground_level(const TriangleMesh &mesh, | |||
|         return (tr * mesh.its.vertices[vi].template cast<double>()).z(); | ||||
|     }; | ||||
| 
 | ||||
|     double zmin = mesh.its.vertices.front().z(); | ||||
|     double zmin = std::numeric_limits<double>::max(); | ||||
|     size_t granularity = vsize / threads; | ||||
|     return ccr_par::reduce(size_t(0), vsize, zmin, minfn, accessfn, granularity); | ||||
| } | ||||
| 
 | ||||
| // Try to guess the number of support points needed to support a mesh
 | ||||
| double calculate_model_supportedness(const TriangleMesh & mesh, | ||||
|                                      const Transform3d &  tr) | ||||
| // Get the vertices of a triangle directly in an array of 3 points
 | ||||
| std::array<Vec3d, 3> get_triangle_vertices(const TriangleMesh &mesh, | ||||
|                                            size_t              faceidx) | ||||
| { | ||||
|     static constexpr double POINTS_PER_UNIT_AREA = 1.; | ||||
| 
 | ||||
|     if (mesh.its.vertices.empty()) return std::nan(""); | ||||
| 
 | ||||
|     size_t Nthr = std::thread::hardware_concurrency(); | ||||
|     size_t facesize = mesh.its.indices.size(); | ||||
| 
 | ||||
|     double zmin = find_ground_level(mesh, tr, Nthr); | ||||
| 
 | ||||
|     auto accessfn = [&mesh, &tr, zmin](size_t fi) { | ||||
| 
 | ||||
|         static const Vec3d DOWN = {0., 0., -1.}; | ||||
| 
 | ||||
|         const auto &face = mesh.its.indices[fi]; | ||||
|         Vec3d p1 = tr * mesh.its.vertices[face(0)].template cast<double>(); | ||||
|         Vec3d p2 = tr * mesh.its.vertices[face(1)].template cast<double>(); | ||||
|         Vec3d p3 = tr * mesh.its.vertices[face(2)].template cast<double>(); | ||||
| 
 | ||||
|         Vec3d U = p2 - p1; | ||||
|         Vec3d V = p3 - p1; | ||||
|         Vec3d C = U.cross(V); | ||||
|         Vec3d N = C.normalized(); | ||||
|         double area = 0.5 * C.norm(); | ||||
| 
 | ||||
|         double zlvl = zmin + 0.1; | ||||
|         if (p1.z() <= zlvl && p2.z() <= zlvl && p3.z() <= zlvl) { | ||||
|             //                score += area * POINTS_PER_UNIT_AREA;
 | ||||
|             return 0.; | ||||
|         } | ||||
| 
 | ||||
|         double phi = 1. - std::acos(N.dot(DOWN)) / PI; | ||||
| //        phi = phi * (phi > 0.5);
 | ||||
| 
 | ||||
|         //                    std::cout << "area: " << area << std::endl;
 | ||||
| 
 | ||||
|         return area * POINTS_PER_UNIT_AREA * phi; | ||||
|     }; | ||||
| 
 | ||||
|     double score = ccr_par::reduce(size_t(0), facesize, 0., std::plus<double>{}, accessfn, facesize / Nthr); | ||||
| 
 | ||||
|     return score / mesh.its.indices.size(); | ||||
|     const auto &face = mesh.its.indices[faceidx]; | ||||
|     return {Vec3d{mesh.its.vertices[face(0)].cast<double>()}, | ||||
|             Vec3d{mesh.its.vertices[face(1)].cast<double>()}, | ||||
|             Vec3d{mesh.its.vertices[face(2)].cast<double>()}}; | ||||
| } | ||||
| 
 | ||||
| std::array<double, 2> find_best_rotation(const ModelObject& modelobj, | ||||
|                                          float accuracy, | ||||
|                                          std::function<void(unsigned)> statuscb, | ||||
|                                          std::function<bool()> stopcond) | ||||
| std::array<Vec3d, 3> get_transformed_triangle(const TriangleMesh &mesh, | ||||
|                                               const Transform3d & tr, | ||||
|                                               size_t              faceidx) | ||||
| { | ||||
|     const auto &tri = get_triangle_vertices(mesh, faceidx); | ||||
|     return {tr * tri[0], tr * tri[1], tr * tri[2]}; | ||||
| } | ||||
| 
 | ||||
| // Get area and normal of a triangle
 | ||||
| struct Face { Vec3d normal; double area; }; | ||||
| inline Face facestats(const std::array<Vec3d, 3> &triangle) | ||||
| { | ||||
|     Vec3d U = triangle[1] - triangle[0]; | ||||
|     Vec3d V = triangle[2] - triangle[0]; | ||||
|     Vec3d C = U.cross(V); | ||||
|     Vec3d N = C.normalized(); | ||||
|     double area = 0.5 * C.norm(); | ||||
| 
 | ||||
|     return {N, area}; | ||||
| } | ||||
| 
 | ||||
| inline const Vec3d DOWN = {0., 0., -1.}; | ||||
| constexpr double POINTS_PER_UNIT_AREA = 1.; | ||||
| 
 | ||||
| inline double get_score(const Face &fc) | ||||
| { | ||||
|     double phi = 1. - std::acos(fc.normal.dot(DOWN)) / PI; | ||||
|     phi = phi * (phi > 0.5); | ||||
|     phi = phi * phi * phi; | ||||
| 
 | ||||
|     return fc.area * POINTS_PER_UNIT_AREA * phi; | ||||
| } | ||||
| 
 | ||||
| template<class AccessFn> | ||||
| double sum_score(AccessFn &&accessfn, size_t facecount, size_t Nthreads) | ||||
| { | ||||
|     double initv     = 0.; | ||||
|     auto   mergefn   = std::plus<double>{}; | ||||
|     size_t grainsize = facecount / Nthreads; | ||||
|     size_t from = 0, to = facecount; | ||||
| 
 | ||||
|     return ccr_par::reduce(from, to, initv, mergefn, accessfn, grainsize); | ||||
| } | ||||
| 
 | ||||
| // Try to guess the number of support points needed to support a mesh
 | ||||
| double get_model_supportedness(const TriangleMesh &mesh, const Transform3d &tr) | ||||
| { | ||||
|     if (mesh.its.vertices.empty()) return std::nan(""); | ||||
| 
 | ||||
|     auto accessfn = [&mesh, &tr](size_t fi) { | ||||
|         Face fc = facestats(get_transformed_triangle(mesh, tr, fi)); | ||||
|         return get_score(fc); | ||||
|     }; | ||||
| 
 | ||||
|     size_t facecount = mesh.its.indices.size(); | ||||
|     size_t Nthreads  = std::thread::hardware_concurrency(); | ||||
|     return sum_score(accessfn, facecount, Nthreads) / facecount; | ||||
| } | ||||
| 
 | ||||
| double get_model_supportedness_onfloor(const TriangleMesh &mesh, | ||||
|                                        const Transform3d & tr) | ||||
| { | ||||
|     if (mesh.its.vertices.empty()) return std::nan(""); | ||||
| 
 | ||||
|     size_t Nthreads = std::thread::hardware_concurrency(); | ||||
| 
 | ||||
|     double zmin = find_ground_level(mesh, tr, Nthreads); | ||||
|     double zlvl = zmin + 0.1; // Set up a slight tolerance from z level
 | ||||
| 
 | ||||
|     auto accessfn = [&mesh, &tr, zlvl](size_t fi) { | ||||
|         std::array<Vec3d, 3> tri = get_transformed_triangle(mesh, tr, fi); | ||||
|         Face fc = facestats(tri); | ||||
| 
 | ||||
|         if (tri[0].z() <= zlvl && tri[1].z() <= zlvl && tri[2].z() <= zlvl) | ||||
|             return -fc.area * POINTS_PER_UNIT_AREA; | ||||
| 
 | ||||
|         return get_score(fc); | ||||
|     }; | ||||
| 
 | ||||
|     size_t facecount = mesh.its.indices.size(); | ||||
|     return sum_score(accessfn, facecount, Nthreads) / facecount; | ||||
| } | ||||
| 
 | ||||
| using XYRotation = std::array<double, 2>; | ||||
| 
 | ||||
| // prepare the rotation transformation
 | ||||
| Transform3d to_transform3d(const XYRotation &rot) | ||||
| { | ||||
|     Transform3d rt = Transform3d::Identity(); | ||||
|     rt.rotate(Eigen::AngleAxisd(rot[1], Vec3d::UnitY())); | ||||
|     rt.rotate(Eigen::AngleAxisd(rot[0], Vec3d::UnitX())); | ||||
|     return rt; | ||||
| } | ||||
| 
 | ||||
| XYRotation from_transform3d(const Transform3d &tr) | ||||
| { | ||||
|     Vec3d rot3d = Geometry::Transformation {tr}.get_rotation(); | ||||
|     return {rot3d.x(), rot3d.y()}; | ||||
| } | ||||
| 
 | ||||
| // Find the best score from a set of function inputs. Evaluate for every point.
 | ||||
| template<size_t N, class Fn, class Cmp, class It> | ||||
| std::array<double, N> find_min_score(Fn &&fn, Cmp &&cmp, It from, It to) | ||||
| { | ||||
|     std::array<double, N> ret; | ||||
| 
 | ||||
|     double score = std::numeric_limits<double>::max(); | ||||
| 
 | ||||
|     for (auto it = from; it != to; ++it) { | ||||
|         double sc = fn(*it); | ||||
|         if (cmp(sc, score)) { | ||||
|             score = sc; | ||||
|             ret = *it; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| // collect the rotations for each face of the convex hull
 | ||||
| std::vector<XYRotation> get_chull_rotations(const TriangleMesh &mesh) | ||||
| { | ||||
|     TriangleMesh chull = mesh.convex_hull_3d(); | ||||
|     chull.require_shared_vertices(); | ||||
| 
 | ||||
|     size_t facecount = chull.its.indices.size(); | ||||
|     auto inputs = reserve_vector<XYRotation>(facecount); | ||||
| 
 | ||||
|     for (size_t fi = 0; fi < facecount; ++fi) { | ||||
|         Face fc = facestats(get_triangle_vertices(chull, fi)); | ||||
| 
 | ||||
|         auto q = Eigen::Quaterniond{}.FromTwoVectors(fc.normal, DOWN); | ||||
|         inputs.emplace_back(from_transform3d(Transform3d::Identity() * q)); | ||||
|     } | ||||
| 
 | ||||
|     return inputs; | ||||
| } | ||||
| 
 | ||||
| XYRotation find_best_rotation(const SLAPrintObject &        po, | ||||
|                               float                         accuracy, | ||||
|                               std::function<void(unsigned)> statuscb, | ||||
|                               std::function<bool()>         stopcond) | ||||
| { | ||||
|     static const unsigned MAX_TRIES = 10000; | ||||
| 
 | ||||
|  | @ -105,10 +202,10 @@ std::array<double, 2> find_best_rotation(const ModelObject& modelobj, | |||
| 
 | ||||
|     // We will use only one instance of this converted mesh to examine different
 | ||||
|     // rotations
 | ||||
|     TriangleMesh mesh = modelobj.raw_mesh(); | ||||
|     TriangleMesh mesh = po.model_object()->raw_mesh(); | ||||
|     mesh.require_shared_vertices(); | ||||
| 
 | ||||
|     // For current iteration number
 | ||||
|     // To keep track of the number of iterations
 | ||||
|     unsigned status = 0; | ||||
| 
 | ||||
|     // The maximum number of iterations
 | ||||
|  | @ -117,51 +214,66 @@ std::array<double, 2> find_best_rotation(const ModelObject& modelobj, | |||
|     // call status callback with zero, because we are at the start
 | ||||
|     statuscb(status); | ||||
| 
 | ||||
|     // So this is the object function which is called by the solver many times
 | ||||
|     // It has to yield a single value representing the current score. We will
 | ||||
|     // call the status callback in each iteration but the actual value may be
 | ||||
|     // the same for subsequent iterations (status goes from 0 to 100 but
 | ||||
|     // iterations can be many more)
 | ||||
|     auto objfunc = [&mesh, &status, &statuscb, &stopcond, max_tries] | ||||
|         (const opt::Input<2> &in) | ||||
|     { | ||||
|         std::cout << "in: " << in[0] << " " << in[1] << std::endl; | ||||
| 
 | ||||
|         // prepare the rotation transformation
 | ||||
|         Transform3d rt = Transform3d::Identity(); | ||||
|         rt.rotate(Eigen::AngleAxisd(in[1], Vec3d::UnitY())); | ||||
|         rt.rotate(Eigen::AngleAxisd(in[0], Vec3d::UnitX())); | ||||
| 
 | ||||
|         double score = sla::calculate_model_supportedness(mesh, rt); | ||||
|         std::cout << score << std::endl; | ||||
| 
 | ||||
|     auto statusfn = [&statuscb, &status, max_tries] { | ||||
|         // report status
 | ||||
|         if(!stopcond()) statuscb( unsigned(++status * 100.0/max_tries) ); | ||||
| 
 | ||||
|         return score; | ||||
|         statuscb(unsigned(++status * 100.0/max_tries) ); | ||||
|     }; | ||||
| 
 | ||||
|     // Firing up the optimizer.
 | ||||
|     opt::Optimizer<opt::AlgBruteForce> solver(opt::StopCriteria{} | ||||
|                                                   .max_iterations(max_tries) | ||||
|                                                   .rel_score_diff(1e-6) | ||||
|                                                   .stop_condition(stopcond), | ||||
|                                               std::sqrt(max_tries)/*grid size*/); | ||||
|     // Different search methods have to be used depending on the model elevation
 | ||||
|     if (is_on_floor(po)) { | ||||
| 
 | ||||
|     // We are searching rotations around only two axes x, y. Thus the
 | ||||
|     // problem becomes a 2 dimensional optimization task.
 | ||||
|     // We can specify the bounds for a dimension in the following way:
 | ||||
|     auto b = opt::Bound{-PI, PI}; | ||||
|         // If the model can be placed on the bed directly, we only need to
 | ||||
|         // check the 3D convex hull face rotations.
 | ||||
| 
 | ||||
|     // Now we start the optimization process with initial angles (0, 0)
 | ||||
|     auto result = solver.to_min().optimize(objfunc, opt::initvals({0., 0.}), | ||||
|                                            opt::bounds({b, b})); | ||||
|         auto inputs = get_chull_rotations(mesh); | ||||
| 
 | ||||
|     // Save the result and fck off
 | ||||
|     rot[0] = std::get<0>(result.optimum); | ||||
|     rot[1] = std::get<1>(result.optimum); | ||||
|         auto cmpfn = [](double a, double b) { return a < b; }; | ||||
|         auto objfn = [&mesh, &statusfn](const XYRotation &rot) { | ||||
|             statusfn(); | ||||
|             // We actually need the reverserotation to make the object lie on
 | ||||
|             // this face
 | ||||
|             Transform3d tr = to_transform3d(rot); | ||||
|             return get_model_supportedness_onfloor(mesh, tr); | ||||
|         }; | ||||
| 
 | ||||
|         rot = find_min_score<2>(objfn, cmpfn, inputs.begin(), inputs.end()); | ||||
|     } else { | ||||
| 
 | ||||
|         // Preparing the optimizer.
 | ||||
|         size_t grid_size = std::sqrt(max_tries); | ||||
|         opt::Optimizer<opt::AlgBruteForce> solver(opt::StopCriteria{} | ||||
|                                                       .max_iterations(max_tries) | ||||
|                                                       .stop_condition(stopcond), | ||||
|                                                   grid_size); | ||||
| 
 | ||||
|         // We are searching rotations around only two axes x, y. Thus the
 | ||||
|         // problem becomes a 2 dimensional optimization task.
 | ||||
|         // We can specify the bounds for a dimension in the following way:
 | ||||
|         auto bounds = opt::bounds({ {-PI, PI}, {-PI, PI} }); | ||||
| 
 | ||||
|         auto result = solver.to_min().optimize( | ||||
|             [&mesh, &statusfn] (const XYRotation &rot) | ||||
|             { | ||||
|                 statusfn(); | ||||
|                 return get_model_supportedness(mesh, to_transform3d(rot)); | ||||
|             }, opt::initvals({0., 0.}), bounds); | ||||
| 
 | ||||
|         // Save the result and fck off
 | ||||
|         rot = result.optimum; | ||||
| 
 | ||||
|         std::cout << "best score: " << result.score << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     return rot; | ||||
| } | ||||
| 
 | ||||
| double get_model_supportedness(const SLAPrintObject &po, const Transform3d &tr) | ||||
| { | ||||
|     TriangleMesh mesh = po.model_object()->raw_mesh(); | ||||
|     mesh.require_shared_vertices(); | ||||
| 
 | ||||
|     return is_on_floor(po) ? get_model_supportedness_onfloor(mesh, tr) : | ||||
|                              get_model_supportedness(mesh, tr); | ||||
| } | ||||
| 
 | ||||
| }} // namespace Slic3r::sla
 | ||||
|  |  | |||
|  | @ -4,9 +4,11 @@ | |||
| #include <functional> | ||||
| #include <array> | ||||
| 
 | ||||
| #include <libslic3r/Point.hpp> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| class ModelObject; | ||||
| class SLAPrintObject; | ||||
| 
 | ||||
| namespace sla { | ||||
| 
 | ||||
|  | @ -26,13 +28,16 @@ namespace sla { | |||
|   * @return Returns the rotations around each axis (x, y, z) | ||||
|   */ | ||||
| std::array<double, 2> find_best_rotation( | ||||
|         const ModelObject& modelobj, | ||||
|         const SLAPrintObject& modelobj, | ||||
|         float accuracy = 1.0f, | ||||
|         std::function<void(unsigned)> statuscb = [] (unsigned) {}, | ||||
|         std::function<bool()> stopcond = [] () { return false; } | ||||
|         ); | ||||
| 
 | ||||
| } | ||||
| } | ||||
| double get_model_supportedness(const SLAPrintObject &mesh, | ||||
|                                const Transform3d & tr); | ||||
| 
 | ||||
| } // namespace sla
 | ||||
| } // namespace Slic3r
 | ||||
| 
 | ||||
| #endif // SLAROTFINDER_HPP
 | ||||
|  |  | |||
|  | @ -200,6 +200,8 @@ void GLGizmoRotate::on_render_for_picking() const | |||
|     glsafe(::glPopMatrix()); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| GLGizmoRotate3D::RotoptimzeWindow::RotoptimzeWindow(ImGuiWrapper *   imgui, | ||||
|                                                     State &          state, | ||||
|                                                     const Alignment &alignment) | ||||
|  | @ -215,20 +217,26 @@ GLGizmoRotate3D::RotoptimzeWindow::RotoptimzeWindow(ImGuiWrapper *   imgui, | |||
|     y = std::min(y, alignment.bottom_limit - win_h); | ||||
|     ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); | ||||
| 
 | ||||
|     ImGui::SliderFloat(_L("Accuracy").c_str(), &state.accuracy, 0.01f, 1.f, "%.1f"); | ||||
|     static constexpr const char * button_txt = L("Optimize orientation"); | ||||
|     static constexpr const char * slider_txt = L("Accuracy"); | ||||
| 
 | ||||
|     if (imgui->button(_L("Optimize orientation"))) { | ||||
|     float button_width = imgui->calc_text_size(_(button_txt)).x; | ||||
|     ImGui::PushItemWidth(100.); | ||||
|     //if (imgui->button(_(button_txt))) {
 | ||||
|     if (ImGui::ArrowButton(_(button_txt).c_str(), ImGuiDir_Down)){ | ||||
|         std::cout << "Blip" << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     ImGui::SliderFloat(_(slider_txt).c_str(), &state.accuracy, 0.01f, 1.f, "%.1f"); | ||||
| 
 | ||||
|     static const std::vector<std::string> options = { | ||||
|         _L("Least supports").ToStdString(), | ||||
|         _L("Suface quality").ToStdString() | ||||
|     }; | ||||
| 
 | ||||
|     if (imgui->combo(_L("Choose method"), options, state.method) ) { | ||||
|         std::cout << "method: " << state.method << std::endl; | ||||
|     } | ||||
| //    if (imgui->combo(_L("Choose method"), options, state.method) ) {
 | ||||
| //        std::cout << "method: " << state.method << std::endl;
 | ||||
| //    }
 | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | @ -243,18 +251,10 @@ void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limi | |||
|     if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) | ||||
|         return; | ||||
| 
 | ||||
| //    m_rotoptimizewin_state.mobj = ;
 | ||||
|     RotoptimzeWindow popup{m_imgui, m_rotoptimizewin_state, {x, y, bottom_limit}}; | ||||
| // TODO:
 | ||||
| 
 | ||||
| //    if ((last_h != win_h) || (last_y != y))
 | ||||
| //    {
 | ||||
| //        // ask canvas for another frame to render the window in the correct position
 | ||||
| //        m_parent.request_extra_frame();
 | ||||
| //        if (last_h != win_h)
 | ||||
| //            last_h = win_h;
 | ||||
| //        if (last_y != y)
 | ||||
| //            last_y = y;
 | ||||
| //    }
 | ||||
| //    m_rotoptimizewin_state.mobj = ?;
 | ||||
| //    RotoptimzeWindow popup{m_imgui, m_rotoptimizewin_state, {x, y, bottom_limit}};
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -136,12 +136,14 @@ protected: | |||
|     } | ||||
| 
 | ||||
|     void on_render_input_window(float x, float y, float bottom_limit) override; | ||||
| 
 | ||||
| private: | ||||
| 
 | ||||
|     class RotoptimzeWindow { | ||||
|         ImGuiWrapper *m_imgui = nullptr; | ||||
| 
 | ||||
|     public: | ||||
| 
 | ||||
|         struct State { | ||||
|             enum Metods { mMinSupportPoints, mLegacy }; | ||||
| 
 | ||||
|  | @ -152,7 +154,10 @@ private: | |||
| 
 | ||||
|         struct Alignment { float x, y, bottom_limit; }; | ||||
| 
 | ||||
|         RotoptimzeWindow(ImGuiWrapper *imgui, State &settings, const Alignment &bottom_limit); | ||||
|         RotoptimzeWindow(ImGuiWrapper *   imgui, | ||||
|                          State &          state, | ||||
|                          const Alignment &bottom_limit); | ||||
| 
 | ||||
|         ~RotoptimzeWindow(); | ||||
| 
 | ||||
|         RotoptimzeWindow(const RotoptimzeWindow&) = delete; | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| #include "libslic3r/SLA/Rotfinder.hpp" | ||||
| #include "libslic3r/MinAreaBoundingBox.hpp" | ||||
| #include "libslic3r/Model.hpp" | ||||
| #include "libslic3r/SLAPrint.hpp" | ||||
| 
 | ||||
| #include "slic3r/GUI/Plater.hpp" | ||||
| 
 | ||||
|  | @ -15,9 +16,26 @@ void RotoptimizeJob::process() | |||
|     if (obj_idx < 0) { return; } | ||||
|      | ||||
|     ModelObject *o = m_plater->model().objects[size_t(obj_idx)]; | ||||
|     const SLAPrintObject *po = m_plater->sla_print().objects()[size_t(obj_idx)]; | ||||
| 
 | ||||
|     if (!o || !po) return; | ||||
| 
 | ||||
|     TriangleMesh mesh = o->raw_mesh(); | ||||
|     mesh.require_shared_vertices(); | ||||
| 
 | ||||
| //    for (auto inst : o->instances) {
 | ||||
| //        Transform3d tr = Transform3d::Identity();
 | ||||
| //        tr.rotate(Eigen::AngleAxisd(inst->get_rotation(Z), Vec3d::UnitZ()));
 | ||||
| //        tr.rotate(Eigen::AngleAxisd(inst->get_rotation(Y), Vec3d::UnitY()));
 | ||||
| //        tr.rotate(Eigen::AngleAxisd(inst->get_rotation(X), Vec3d::UnitX()));
 | ||||
| 
 | ||||
| //        double score = sla::get_model_supportedness(*po, tr);
 | ||||
| 
 | ||||
| //        std::cout << "Model supportedness before: " << score << std::endl;
 | ||||
| //    }
 | ||||
| 
 | ||||
|     auto r = sla::find_best_rotation( | ||||
|         *o, | ||||
|         *po, | ||||
|         1.f, | ||||
|         [this](unsigned s) { | ||||
|             if (s < 100) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 tamasmeszaros
						tamasmeszaros