mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 12:41:20 -06:00 
			
		
		
		
	Export to STL of SLA supports and pad
This commit is contained in:
		
							parent
							
								
									4a5992ba6e
								
							
						
					
					
						commit
						a3385278e5
					
				
					 5 changed files with 95 additions and 15 deletions
				
			
		|  | @ -1147,7 +1147,7 @@ void ObjectList::append_menu_item_fix_through_netfabb(wxMenu* menu) | |||
| void ObjectList::append_menu_item_export_stl(wxMenu* menu) const  | ||||
| { | ||||
|     append_menu_item(menu, wxID_ANY, _(L("Export as STL")) + dots, "", | ||||
|         [](wxCommandEvent&) { wxGetApp().plater()->export_stl(true); }, "", menu); | ||||
|         [](wxCommandEvent&) { wxGetApp().plater()->export_stl(false, true); }, "", menu); | ||||
|     menu->AppendSeparator(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ | |||
| 
 | ||||
| #include "libslic3r/Print.hpp" | ||||
| #include "libslic3r/Polygon.hpp" | ||||
| #include "libslic3r/SLAPrint.hpp" | ||||
| 
 | ||||
| #include "Tab.hpp" | ||||
| #include "PresetBundle.hpp" | ||||
|  | @ -205,12 +206,30 @@ void MainFrame::add_created_tab(Tab* panel) | |||
| 
 | ||||
| bool MainFrame::can_save() const | ||||
| { | ||||
|     return (m_plater != nullptr) ? !m_plater->model().objects.empty() : false; | ||||
|     return (m_plater != nullptr) && !m_plater->model().objects.empty(); | ||||
| } | ||||
| 
 | ||||
| bool MainFrame::can_export_model() const | ||||
| { | ||||
|     return (m_plater != nullptr) ? !m_plater->model().objects.empty() : false; | ||||
|     return (m_plater != nullptr) && !m_plater->model().objects.empty(); | ||||
| } | ||||
| 
 | ||||
| bool MainFrame::can_export_supports() const | ||||
| { | ||||
|     if ((m_plater == nullptr) || (m_plater->printer_technology() != ptSLA) || m_plater->model().objects.empty()) | ||||
|         return false; | ||||
| 
 | ||||
|     bool can_export = false; | ||||
|     const PrintObjects& objects = m_plater->sla_print().objects(); | ||||
|     for (const SLAPrintObject* object : objects) | ||||
|     { | ||||
|         if (object->has_mesh(slaposBasePool) || object->has_mesh(slaposSupportTree)) | ||||
|         { | ||||
|             can_export = true; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     return can_export; | ||||
| } | ||||
| 
 | ||||
| bool MainFrame::can_export_gcode() const | ||||
|  | @ -243,17 +262,17 @@ bool MainFrame::can_change_view() const | |||
| 
 | ||||
| bool MainFrame::can_select() const | ||||
| { | ||||
|     return (m_plater != nullptr) ? !m_plater->model().objects.empty() : false; | ||||
|     return (m_plater != nullptr) && !m_plater->model().objects.empty(); | ||||
| } | ||||
| 
 | ||||
| bool MainFrame::can_delete() const | ||||
| { | ||||
|     return (m_plater != nullptr) ? !m_plater->is_selection_empty() : false; | ||||
|     return (m_plater != nullptr) && !m_plater->is_selection_empty(); | ||||
| } | ||||
| 
 | ||||
| bool MainFrame::can_delete_all() const | ||||
| { | ||||
|     return (m_plater != nullptr) ? !m_plater->model().objects.empty() : false; | ||||
|     return (m_plater != nullptr) && !m_plater->model().objects.empty(); | ||||
| } | ||||
| 
 | ||||
| void MainFrame::on_dpi_changed(const wxRect &suggested_rect) | ||||
|  | @ -346,6 +365,8 @@ void MainFrame::init_menubar() | |||
|         export_menu->AppendSeparator(); | ||||
|         wxMenuItem* item_export_stl = append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &STL")) + dots, _(L("Export current plate as STL")), | ||||
|             [this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, menu_icon("export_plater")); | ||||
|         wxMenuItem* item_export_stl_sla = append_menu_item(export_menu, wxID_ANY, _(L("Export plate as STL including supports")) + dots, _(L("Export current plate as STL including supports")), | ||||
|             [this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(true); }, menu_icon("export_plater")); | ||||
|         wxMenuItem* item_export_amf = append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &AMF")) + dots, _(L("Export current plate as AMF")), | ||||
|             [this](wxCommandEvent&) { if (m_plater) m_plater->export_amf(); }, menu_icon("export_plater")); | ||||
|         export_menu->AppendSeparator(); | ||||
|  | @ -389,13 +410,14 @@ void MainFrame::init_menubar() | |||
|             [this](wxCommandEvent&) { Close(false); }); | ||||
| 
 | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_plater != nullptr); }, item_open->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_save()); }, item_save->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_save()); }, item_save_as->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_save()); }, item_save->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_save()); }, item_save_as->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_plater != nullptr); }, item_import_model->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_export_gcode()); }, item_export_gcode->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_export_model()); }, item_export_stl->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_export_model()); }, item_export_amf->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_slice()); }, m_menu_item_reslice_now->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_export_gcode()); }, item_export_gcode->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_export_model()); }, item_export_stl->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_export_supports()); }, item_export_stl_sla->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_export_model()); }, item_export_amf->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_slice()); }, m_menu_item_reslice_now->GetId()); | ||||
|     } | ||||
| 
 | ||||
| #ifdef _MSC_VER | ||||
|  |  | |||
|  | @ -63,6 +63,7 @@ class MainFrame : public DPIFrame | |||
| 
 | ||||
|     bool can_save() const; | ||||
|     bool can_export_model() const; | ||||
|     bool can_export_supports() const; | ||||
|     bool can_export_gcode() const; | ||||
|     bool can_slice() const; | ||||
|     bool can_change_view() const; | ||||
|  |  | |||
|  | @ -2925,7 +2925,7 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ | |||
|             [this](wxCommandEvent&) { reload_from_disk(); }); | ||||
| 
 | ||||
|         append_menu_item(menu, wxID_ANY, _(L("Export as STL")) + dots, _(L("Export the selected object as STL file")), | ||||
|             [this](wxCommandEvent&) { q->export_stl(true); }); | ||||
|             [this](wxCommandEvent&) { q->export_stl(false, true); }); | ||||
| 
 | ||||
|         menu->AppendSeparator(); | ||||
|     } | ||||
|  | @ -3431,7 +3431,7 @@ void Plater::export_gcode() | |||
|         p->export_gcode(std::move(output_path), PrintHostJob()); | ||||
| } | ||||
| 
 | ||||
| void Plater::export_stl(bool selection_only) | ||||
| void Plater::export_stl(bool extended, bool selection_only) | ||||
| { | ||||
|     if (p->model.objects.empty()) { return; } | ||||
| 
 | ||||
|  | @ -3466,8 +3466,65 @@ void Plater::export_stl(bool selection_only) | |||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         mesh = p->model.mesh(); | ||||
| 
 | ||||
|         if (extended && (p->printer_technology == ptSLA)) | ||||
|         { | ||||
|             const PrintObjects& objects = p->sla_print.objects(); | ||||
|             for (const SLAPrintObject* object : objects) | ||||
|             { | ||||
|                 const ModelObject* model_object = object->model_object(); | ||||
|                 Transform3d mesh_trafo_inv = object->trafo().inverse(); | ||||
|                 bool is_left_handed = object->is_left_handed(); | ||||
| 
 | ||||
|                 TriangleMesh pad_mesh; | ||||
|                 bool has_pad_mesh = object->has_mesh(slaposBasePool); | ||||
|                 if (has_pad_mesh) | ||||
|                 { | ||||
|                     pad_mesh = object->get_mesh(slaposBasePool); | ||||
|                     pad_mesh.transform(mesh_trafo_inv); | ||||
|                 } | ||||
| 
 | ||||
|                 TriangleMesh supports_mesh; | ||||
|                 bool has_supports_mesh = object->has_mesh(slaposSupportTree); | ||||
|                 if (has_supports_mesh) | ||||
|                 { | ||||
|                     supports_mesh = object->get_mesh(slaposSupportTree); | ||||
|                     supports_mesh.transform(mesh_trafo_inv); | ||||
|                 } | ||||
| 
 | ||||
|                 const std::vector<SLAPrintObject::Instance>& obj_instances = object->instances(); | ||||
|                 for (const SLAPrintObject::Instance& obj_instance : obj_instances) | ||||
|                 { | ||||
|                     auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(), | ||||
|                         [&obj_instance](const ModelInstance *mi) { return mi->id() == obj_instance.instance_id; }); | ||||
|                     assert(it != model_object->instances.end()); | ||||
| 
 | ||||
|                     if (it != model_object->instances.end()) | ||||
|                     { | ||||
|                         int instance_idx = it - model_object->instances.begin(); | ||||
|                         const Transform3d& inst_transform = object->model_object()->instances[instance_idx]->get_transformation().get_matrix(); | ||||
| 
 | ||||
|                         if (has_pad_mesh) | ||||
|                         { | ||||
|                             TriangleMesh inst_pad_mesh = pad_mesh; | ||||
|                             inst_pad_mesh.transform(inst_transform, is_left_handed); | ||||
|                             mesh.merge(inst_pad_mesh); | ||||
|                         } | ||||
| 
 | ||||
|                         if (has_supports_mesh) | ||||
|                         { | ||||
|                             TriangleMesh inst_supports_mesh = supports_mesh; | ||||
|                             inst_supports_mesh.transform(inst_transform, is_left_handed); | ||||
|                             mesh.merge(inst_supports_mesh); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     Slic3r::store_stl(path_u8.c_str(), &mesh, true); | ||||
|     p->statusbar()->set_status_text(wxString::Format(_(L("STL file exported to %s")), path)); | ||||
| } | ||||
|  |  | |||
|  | @ -163,7 +163,7 @@ public: | |||
|     void cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false); | ||||
| 
 | ||||
|     void export_gcode(); | ||||
|     void export_stl(bool selection_only = false); | ||||
|     void export_stl(bool extended = false, bool selection_only = false); | ||||
|     void export_amf(); | ||||
|     void export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path()); | ||||
|     void reslice(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Enrico Turri
						Enrico Turri