mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Merge branch 'tm_rotfinder_fixes'
This commit is contained in:
		
						commit
						db7f424e46
					
				
					 4 changed files with 91 additions and 69 deletions
				
			
		|  | @ -58,29 +58,6 @@ T sum_score(AccessFn &&accessfn, size_t facecount, size_t Nthreads) | |||
|     return execution::reduce(ex_tbb, from, to, initv, mergefn, accessfn, grainsize); | ||||
| } | ||||
| 
 | ||||
| // Try to guess the number of support points needed to support a mesh
 | ||||
| double get_misalginment_score(const TriangleMesh &mesh, const Transform3f &tr) | ||||
| { | ||||
|     if (mesh.its.vertices.empty()) return std::nan(""); | ||||
| 
 | ||||
|     auto accessfn = [&mesh, &tr](size_t fi) { | ||||
|         auto triangle = get_transformed_triangle(mesh, tr, fi); | ||||
|         Vec3f U = triangle[1] - triangle[0]; | ||||
|         Vec3f V = triangle[2] - triangle[0]; | ||||
|         Vec3f C = U.cross(V); | ||||
| 
 | ||||
|         // We should score against the alignment with the reference planes
 | ||||
|         return scaled<int_fast64_t>(std::abs(C.dot(Vec3f::UnitX())) + | ||||
|                                     std::abs(C.dot(Vec3f::UnitY()))); | ||||
|     }; | ||||
| 
 | ||||
|     size_t facecount = mesh.its.indices.size(); | ||||
|     size_t Nthreads  = std::thread::hardware_concurrency(); | ||||
|     double S = unscaled(sum_score<int_fast64_t>(accessfn, facecount, Nthreads)); | ||||
| 
 | ||||
|     return S / facecount; | ||||
| } | ||||
| 
 | ||||
| // Get area and normal of a triangle
 | ||||
| struct Facestats { | ||||
|     Vec3f  normal; | ||||
|  | @ -96,18 +73,45 @@ struct Facestats { | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| // Try to guess the number of support points needed to support a mesh
 | ||||
| double get_misalginment_score(const TriangleMesh &mesh, const Transform3f &tr) | ||||
| { | ||||
|     if (mesh.its.vertices.empty()) return std::nan(""); | ||||
| 
 | ||||
|     auto accessfn = [&mesh, &tr](size_t fi) { | ||||
|         Facestats fc{get_transformed_triangle(mesh, tr, fi)}; | ||||
| 
 | ||||
|         float score = fc.area | ||||
|                       * (std::abs(fc.normal.dot(Vec3f::UnitX())) | ||||
|                          + std::abs(fc.normal.dot(Vec3f::UnitY())) | ||||
|                          + std::abs(fc.normal.dot(Vec3f::UnitZ()))); | ||||
| 
 | ||||
|         // We should score against the alignment with the reference planes
 | ||||
|         return scaled<int_fast64_t>(score); | ||||
|     }; | ||||
| 
 | ||||
|     size_t facecount = mesh.its.indices.size(); | ||||
|     size_t Nthreads  = std::thread::hardware_concurrency(); | ||||
|     double S = unscaled(sum_score<int_fast64_t>(accessfn, facecount, Nthreads)); | ||||
| 
 | ||||
|     return S / facecount; | ||||
| } | ||||
| 
 | ||||
| // The score function for a particular face
 | ||||
| inline double get_supportedness_score(const Facestats &fc) | ||||
| { | ||||
|     // Simply get the angle (acos of dot product) between the face normal and
 | ||||
|     // the DOWN vector.
 | ||||
|     float phi = 1. - std::acos(fc.normal.dot(DOWN)) / float(PI); | ||||
|     float cosphi = fc.normal.dot(DOWN); | ||||
|     float phi = 1.f - std::acos(cosphi) / float(PI); | ||||
| 
 | ||||
|     // Only consider faces that have slopes below 90 deg:
 | ||||
|     phi = phi * (phi >= 0.5f); | ||||
|     // Phi is raised by 1.0 to not be less than zero when squared in the next
 | ||||
|     // step. If phi is greater than 0.5 (slope is > 90 deg) make phi zero
 | ||||
|     // to not skip this face in the overall score.
 | ||||
|     phi = (1.f + phi) * (phi >= 0.5f); | ||||
| 
 | ||||
|     // Make the huge slopes more significant than the smaller slopes
 | ||||
|     phi = phi * phi * phi; | ||||
|     phi = phi * phi; | ||||
| 
 | ||||
|     // Multiply with the area of the current face
 | ||||
|     return fc.area * POINTS_PER_UNIT_AREA * phi; | ||||
|  | @ -121,7 +125,7 @@ double get_supportedness_score(const TriangleMesh &mesh, const Transform3f &tr) | |||
|     auto accessfn = [&mesh, &tr](size_t fi) { | ||||
|         Facestats fc{get_transformed_triangle(mesh, tr, fi)}; | ||||
| 
 | ||||
|         return get_supportedness_score(fc); | ||||
|         return scaled<int_fast64_t>(get_supportedness_score(fc)); | ||||
|     }; | ||||
| 
 | ||||
|     size_t facecount = mesh.its.indices.size(); | ||||
|  | @ -164,7 +168,7 @@ float get_supportedness_onfloor_score(const TriangleMesh &mesh, | |||
|         Facestats fc{tri}; | ||||
| 
 | ||||
|         if (tri[0].z() <= zlvl && tri[1].z() <= zlvl && tri[2].z() <= zlvl) | ||||
|             return -fc.area * POINTS_PER_UNIT_AREA; | ||||
|             return -2 * fc.area * POINTS_PER_UNIT_AREA; | ||||
| 
 | ||||
|         return get_supportedness_score(fc); | ||||
|     }; | ||||
|  | @ -283,6 +287,26 @@ std::array<double, N> find_min_score(Fn &&fn, It from, It to, StopCond &&stopfn) | |||
| 
 | ||||
| } // namespace
 | ||||
| 
 | ||||
| // Assemble the mesh with the correct transformation to be used in rotation
 | ||||
| // optimization.
 | ||||
| TriangleMesh get_mesh_to_rotate(const ModelObject &mo) | ||||
| { | ||||
|     TriangleMesh mesh = mo.raw_mesh(); | ||||
|     mesh.require_shared_vertices(); | ||||
| 
 | ||||
|     ModelInstance *mi = mo.instances[0]; | ||||
|     auto rotation = Vec3d::Zero(); | ||||
|     auto offset = Vec3d::Zero(); | ||||
|     Transform3d trafo_instance = Geometry::assemble_transform(offset, | ||||
|                                                               rotation, | ||||
|                                                               mi->get_scaling_factor(), | ||||
|                                                               mi->get_mirror()); | ||||
| 
 | ||||
|     mesh.transform(trafo_instance); | ||||
| 
 | ||||
|     return mesh; | ||||
| } | ||||
| 
 | ||||
| Vec2d find_best_misalignment_rotation(const ModelObject &      mo, | ||||
|                                       const RotOptimizeParams ¶ms) | ||||
| { | ||||
|  | @ -293,8 +317,7 @@ Vec2d find_best_misalignment_rotation(const ModelObject &      mo, | |||
| 
 | ||||
|     // We will use only one instance of this converted mesh to examine different
 | ||||
|     // rotations
 | ||||
|     TriangleMesh mesh = mo.raw_mesh(); | ||||
|     mesh.require_shared_vertices(); | ||||
|     TriangleMesh mesh = get_mesh_to_rotate(mo); | ||||
| 
 | ||||
|     // To keep track of the number of iterations
 | ||||
|     int status = 0; | ||||
|  | @ -350,8 +373,7 @@ Vec2d find_least_supports_rotation(const ModelObject &      mo, | |||
| 
 | ||||
|     // We will use only one instance of this converted mesh to examine different
 | ||||
|     // rotations
 | ||||
|     TriangleMesh mesh = mo.raw_mesh(); | ||||
|     mesh.require_shared_vertices(); | ||||
|     TriangleMesh mesh = get_mesh_to_rotate(mo); | ||||
| 
 | ||||
|     // To keep track of the number of iterations
 | ||||
|     unsigned status = 0; | ||||
|  |  | |||
|  | @ -497,9 +497,6 @@ void GLGizmoRotate3D::on_render() | |||
|         m_gizmos[Z].render(); | ||||
| } | ||||
| 
 | ||||
| const char * GLGizmoRotate3D::RotoptimzeWindow::options[RotoptimizeJob::get_methods_count()]; | ||||
| bool GLGizmoRotate3D::RotoptimzeWindow::options_valid = false; | ||||
| 
 | ||||
| GLGizmoRotate3D::RotoptimzeWindow::RotoptimzeWindow(ImGuiWrapper *   imgui, | ||||
|                                                     State &          state, | ||||
|                                                     const Alignment &alignment) | ||||
|  | @ -517,19 +514,24 @@ GLGizmoRotate3D::RotoptimzeWindow::RotoptimzeWindow(ImGuiWrapper *   imgui, | |||
| 
 | ||||
|     ImGui::PushItemWidth(200.f); | ||||
| 
 | ||||
|     size_t methods_cnt = RotoptimizeJob::get_methods_count(); | ||||
|     if (!options_valid) { | ||||
|         for (size_t i = 0; i < methods_cnt; ++i) | ||||
|             options[i] = RotoptimizeJob::get_method_names()[i].c_str(); | ||||
|     if (ImGui::BeginCombo(_L("Choose goal").c_str(), RotoptimizeJob::get_method_name(state.method_id).c_str())) { | ||||
|         for (size_t i = 0; i < RotoptimizeJob::get_methods_count(); ++i) { | ||||
|             if (ImGui::Selectable(RotoptimizeJob::get_method_name(i).c_str())) { | ||||
|                 state.method_id = i; | ||||
|                 wxGetApp().app_config->set("sla_auto_rotate", | ||||
|                                            "method_id", | ||||
|                                            std::to_string(state.method_id)); | ||||
|             } | ||||
| 
 | ||||
|         options_valid = true; | ||||
|             if (ImGui::IsItemHovered()) | ||||
|                 ImGui::SetTooltip("%s", RotoptimizeJob::get_method_description(i).c_str()); | ||||
|         } | ||||
| 
 | ||||
|         ImGui::EndCombo(); | ||||
|     } | ||||
| 
 | ||||
|     int citem = state.method_id; | ||||
|     if (ImGui::Combo(_L("Choose goal").c_str(), &citem, options, methods_cnt) ) { | ||||
|         state.method_id = citem; | ||||
|         wxGetApp().app_config->set("sla_auto_rotate", "method_id", std::to_string(state.method_id)); | ||||
|     } | ||||
|     if (ImGui::IsItemHovered()) | ||||
|         ImGui::SetTooltip("%s", RotoptimizeJob::get_method_description(state.method_id).c_str()); | ||||
| 
 | ||||
|     ImGui::Separator(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -138,10 +138,6 @@ private: | |||
| 
 | ||||
|     class RotoptimzeWindow { | ||||
|         ImGuiWrapper *m_imgui = nullptr; | ||||
| 
 | ||||
|         static const char * options []; | ||||
|         static bool options_valid; | ||||
| 
 | ||||
|     public: | ||||
| 
 | ||||
|         struct State { | ||||
|  |  | |||
|  | @ -15,14 +15,21 @@ class RotoptimizeJob : public PlaterJob | |||
|     using FindFn = std::function<Vec2d(const ModelObject &           mo, | ||||
|                                        const sla::RotOptimizeParams ¶ms)>; | ||||
| 
 | ||||
|     struct FindMethod { std::string name; FindFn findfn; }; | ||||
|     struct FindMethod { std::string name; FindFn findfn; std::string descr; }; | ||||
| 
 | ||||
|     static inline const FindMethod Methods[] = { | ||||
|         { L("Best surface quality"), sla::find_best_misalignment_rotation }, | ||||
|         { L("Least supports"), sla::find_least_supports_rotation }, | ||||
|         // Just a min area bounding box that is done for all methods anyway.
 | ||||
|         { L("Z axis only"), nullptr } | ||||
|     }; | ||||
|     static inline const FindMethod Methods[] | ||||
|         = {{L("Best surface quality"), | ||||
|             sla::find_best_misalignment_rotation, | ||||
|             L("Optimize object rotation for best surface quality.")}, | ||||
|            {L("Least supports"), | ||||
|             sla::find_least_supports_rotation, | ||||
|             L("Optimize object rotation to have minimum amount of overhangs needing support " | ||||
|               "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("Z axis only"), | ||||
|             nullptr, | ||||
|             L("Rotate the object only in Z axis to have the smallest bounding box.")}}; | ||||
| 
 | ||||
|     size_t m_method_id = 0; | ||||
|     float  m_accuracy  = 0.75; | ||||
|  | @ -52,20 +59,15 @@ public: | |||
|     void finalize() override; | ||||
| 
 | ||||
|     static constexpr size_t get_methods_count() { return std::size(Methods); } | ||||
|     static const auto & get_method_names() | ||||
| 
 | ||||
|     static std::string get_method_name(size_t i) | ||||
|     { | ||||
|         static bool m_method_names_valid = false; | ||||
|         static std::array<std::string, std::size(Methods)> m_method_names; | ||||
|         return _utf8(Methods[i].name); | ||||
|     } | ||||
| 
 | ||||
|         if (!m_method_names_valid) { | ||||
| 
 | ||||
|             for (size_t i = 0; i < std::size(Methods); ++i) | ||||
|                 m_method_names[i] = _utf8(Methods[i].name); | ||||
| 
 | ||||
|             m_method_names_valid = true; | ||||
|         } | ||||
| 
 | ||||
|         return m_method_names; | ||||
|     static std::string get_method_description(size_t i) | ||||
|     { | ||||
|         return _utf8(Methods[i].descr); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 tamasmeszaros
						tamasmeszaros