mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Merge branch 'master' of https://github.com/prusa3d/Slic3r
This commit is contained in:
		
						commit
						a71f05cdc0
					
				
					 12 changed files with 221 additions and 100 deletions
				
			
		|  | @ -556,19 +556,9 @@ std::string Model::propose_export_file_name_and_path() const | |||
|     for (const ModelObject *model_object : this->objects) | ||||
|         for (ModelInstance *model_instance : model_object->instances) | ||||
|             if (model_instance->is_printable()) { | ||||
|                 input_file = model_object->input_file; | ||||
|                 if (! model_object->name.empty()) { | ||||
|                     if (input_file.empty()) | ||||
|                         // model_object->input_file was empty, just use model_object->name
 | ||||
|                         input_file = model_object->name; | ||||
|                     else { | ||||
|                         // Replace file name in input_file with model_object->name, but keep the path and file extension.
 | ||||
| 						input_file = (boost::filesystem::path(model_object->name).parent_path().empty()) ? | ||||
| 							(boost::filesystem::path(input_file).parent_path() / model_object->name).make_preferred().string() : | ||||
| 							model_object->name; | ||||
| 					} | ||||
|                 } | ||||
|                 if (! input_file.empty()) | ||||
|                 input_file = model_object->get_export_filename(); | ||||
| 
 | ||||
|                 if (!input_file.empty()) | ||||
|                     goto end; | ||||
|                 // Other instances will produce the same name, skip them.
 | ||||
|                 break; | ||||
|  | @ -1433,6 +1423,26 @@ void ModelObject::print_info() const | |||
|     cout << "volume = "           << mesh.volume()                  << endl; | ||||
| } | ||||
| 
 | ||||
| std::string ModelObject::get_export_filename() const | ||||
| { | ||||
|     std::string ret = input_file; | ||||
| 
 | ||||
|     if (!name.empty()) | ||||
|     { | ||||
|         if (ret.empty()) | ||||
|             // input_file was empty, just use name
 | ||||
|             ret = name; | ||||
|         else | ||||
|         { | ||||
|             // Replace file name in input_file with name, but keep the path and file extension.
 | ||||
|             ret = (boost::filesystem::path(name).parent_path().empty()) ? | ||||
|                 (boost::filesystem::path(ret).parent_path() / name).make_preferred().string() : name; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| void ModelVolume::set_material_id(t_model_material_id material_id) | ||||
| { | ||||
|     m_material_id = material_id; | ||||
|  |  | |||
|  | @ -275,6 +275,8 @@ public: | |||
|     // Print object statistics to console.
 | ||||
|     void print_info() const; | ||||
| 
 | ||||
|     std::string get_export_filename() const; | ||||
| 
 | ||||
| protected: | ||||
|     friend class Print; | ||||
|     friend class SLAPrint; | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ | |||
| #include "GCode/WipeTowerPrusaMM.hpp" | ||||
| #include "Utils.hpp" | ||||
| 
 | ||||
| #include "PrintExport.hpp" | ||||
| //#include "PrintExport.hpp"
 | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <limits> | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| #include <vector> | ||||
| 
 | ||||
| #include <boost/log/trivial.hpp> | ||||
| #include <boost/filesystem/path.hpp> | ||||
| 
 | ||||
| #include "Rasterizer/Rasterizer.hpp" | ||||
| //#include <tbb/parallel_for.h>
 | ||||
|  | @ -72,7 +73,8 @@ public: | |||
|     void finish_layer(); | ||||
| 
 | ||||
|     // Save all the layers into the file (or dir) specified in the path argument
 | ||||
|     void save(const std::string& path); | ||||
|     // An optional project name can be added to be used for the layer file names
 | ||||
|     void save(const std::string& path, const std::string& projectname = ""); | ||||
| 
 | ||||
|     // Save only the selected layer to the file specified in path argument.
 | ||||
|     void save_layer(unsigned lyr, const std::string& path); | ||||
|  | @ -86,7 +88,8 @@ template<class T = void> struct VeryFalse { static const bool value = false; }; | |||
| template<class Fmt> class LayerWriter { | ||||
| public: | ||||
| 
 | ||||
|     LayerWriter(const std::string& /*zipfile_path*/) { | ||||
|     LayerWriter(const std::string& /*zipfile_path*/) | ||||
|     { | ||||
|         static_assert(VeryFalse<Fmt>::value, | ||||
|                       "No layer writer implementation provided!"); | ||||
|     } | ||||
|  | @ -99,10 +102,6 @@ public: | |||
|     void binary_entry(const std::string& /*fname*/, | ||||
|                       const std::uint8_t* buf, size_t len); | ||||
| 
 | ||||
|     // Get the name of the archive but only the name part without the path or
 | ||||
|     // the extension.
 | ||||
|     std::string get_name() { return ""; } | ||||
| 
 | ||||
|     // Test whether the object can still be used for writing.
 | ||||
|     bool is_ok() { return false; } | ||||
| 
 | ||||
|  | @ -253,12 +252,14 @@ public: | |||
|     } | ||||
| 
 | ||||
|     template<class LyrFmt> | ||||
|     inline void save(const std::string& path) { | ||||
|     inline void save(const std::string& fpath, const std::string& prjname = "") | ||||
|     { | ||||
|         try { | ||||
|             LayerWriter<LyrFmt> writer(path); | ||||
|             LayerWriter<LyrFmt> writer(fpath); | ||||
|             if(!writer.is_ok()) return; | ||||
| 
 | ||||
|             std::string project = writer.get_name(); | ||||
|             std::string project = prjname.empty()? | ||||
|                        boost::filesystem::path(fpath).stem().string() : prjname; | ||||
| 
 | ||||
|             writer.next_entry("config.ini"); | ||||
|             if(!writer.is_ok()) return; | ||||
|  |  | |||
|  | @ -320,10 +320,8 @@ struct SLAPrintStatistics | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| struct SLAminzZipper {}; | ||||
| 
 | ||||
| // The implementation of creating zipped archives with wxWidgets
 | ||||
| template<> class LayerWriter<SLAminzZipper> { | ||||
| template<> class LayerWriter<Zipper> { | ||||
|     Zipper m_zip; | ||||
| public: | ||||
| 
 | ||||
|  | @ -332,16 +330,12 @@ public: | |||
|     void next_entry(const std::string& fname) { m_zip.add_entry(fname); } | ||||
| 
 | ||||
|     void binary_entry(const std::string& fname, | ||||
|                              const std::uint8_t* buf, | ||||
|                              size_t l) | ||||
|                       const std::uint8_t* buf, | ||||
|                       size_t l) | ||||
|     { | ||||
|         m_zip.add_entry(fname, buf, l); | ||||
|     } | ||||
| 
 | ||||
|     std::string get_name() const { | ||||
|         return m_zip.get_name(); | ||||
|     } | ||||
| 
 | ||||
|     template<class T> inline LayerWriter& operator<<(T&& arg) { | ||||
|         m_zip << std::forward<T>(arg); return *this; | ||||
|     } | ||||
|  | @ -389,9 +383,11 @@ public: | |||
|     // Returns true if the last step was finished with success.
 | ||||
|     bool                finished() const override { return this->is_step_done(slaposSliceSupports) && this->Inherited::is_step_done(slapsRasterize); } | ||||
| 
 | ||||
|     template<class Fmt = SLAminzZipper> | ||||
|     void export_raster(const std::string& fname) { | ||||
|         if(m_printer) m_printer->save<Fmt>(fname); | ||||
|     template<class Fmt = Zipper> | ||||
|     inline void export_raster(const std::string& fpath, | ||||
|                        const std::string& projectname = "") | ||||
|     { | ||||
|         if(m_printer) m_printer->save<Fmt>(fpath, projectname); | ||||
|     } | ||||
| 
 | ||||
|     const PrintObjects& objects() const { return m_objects; } | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ | |||
| 
 | ||||
| #include "Zipper.hpp" | ||||
| #include "miniz/miniz_zip.h" | ||||
| #include <boost/filesystem/path.hpp> | ||||
| #include <boost/log/trivial.hpp> | ||||
| 
 | ||||
| #include "I18N.hpp" | ||||
|  | @ -213,10 +212,6 @@ void Zipper::finish_entry() | |||
|     m_entry.clear(); | ||||
| } | ||||
| 
 | ||||
| std::string Zipper::get_name() const { | ||||
|     return boost::filesystem::path(m_impl->m_zipname).stem().string(); | ||||
| } | ||||
| 
 | ||||
| void Zipper::finalize() | ||||
| { | ||||
|     finish_entry(); | ||||
|  |  | |||
|  | @ -81,9 +81,6 @@ public: | |||
|     /// file is up to minz after the erroneous write.
 | ||||
|     void finish_entry(); | ||||
| 
 | ||||
|     /// Gets the name of the archive without the path or extension.
 | ||||
|     std::string get_name() const; | ||||
| 
 | ||||
|     void finalize(); | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -397,8 +397,9 @@ int CLI::run(int argc, char **argv) | |||
|                             outfile_final = fff_print.print_statistics().finalize_output_path(outfile); | ||||
|                         } else { | ||||
| 							outfile = sla_print.output_filepath(outfile); | ||||
| 							sla_print.export_raster(outfile); | ||||
| 							outfile_final = sla_print.print_statistics().finalize_output_path(outfile); | ||||
|                             // We need to finalize the filename beforehand because the export function sets the filename inside the zip metadata
 | ||||
|                             outfile_final = sla_print.print_statistics().finalize_output_path(outfile); | ||||
| 							sla_print.export_raster(outfile_final); | ||||
|                         } | ||||
|                         if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final) != 0) { | ||||
| 							boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl; | ||||
|  |  | |||
|  | @ -98,8 +98,9 @@ void BackgroundSlicingProcess::process_sla() | |||
|     m_print->process(); | ||||
|     if (this->set_step_started(bspsGCodeFinalize)) { | ||||
|         if (! m_export_path.empty()) { | ||||
|             m_sla_print->export_raster(m_export_path); | ||||
|             m_print->set_status(100, "Masked SLA file exported to " + m_export_path); | ||||
|         	const std::string export_path = m_sla_print->print_statistics().finalize_output_path(m_export_path); | ||||
|             m_sla_print->export_raster(export_path); | ||||
|             m_print->set_status(100, "Masked SLA file exported to " + export_path); | ||||
|         } else if (! m_upload_job.empty()) { | ||||
|             prepare_upload(); | ||||
|         } else { | ||||
|  | @ -389,7 +390,7 @@ void BackgroundSlicingProcess::prepare_upload() | |||
| 
 | ||||
| 	// Generate a unique temp path to which the gcode/zip file is copied/exported
 | ||||
| 	boost::filesystem::path source_path = boost::filesystem::temp_directory_path() | ||||
| 		/ boost::filesystem::unique_path(".printhost.%%%%-%%%%-%%%%-%%%%.gcode"); | ||||
| 		/ boost::filesystem::unique_path(".Slic3rPE.upload.%%%%-%%%%-%%%%-%%%%"); | ||||
| 
 | ||||
| 	if (m_print == m_fff_print) { | ||||
| 		m_print->set_status(95, "Running post-processing scripts"); | ||||
|  | @ -399,8 +400,8 @@ void BackgroundSlicingProcess::prepare_upload() | |||
| 		run_post_process_scripts(source_path.string(), m_fff_print->config()); | ||||
| 		m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string()); | ||||
|     } else { | ||||
|         m_sla_print->export_raster(source_path.string()); | ||||
| 		// TODO: Also finalize upload path like with FFF when there are statistics for SLA print
 | ||||
| 		m_upload_job.upload_data.upload_path = m_sla_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string()); | ||||
|         m_sla_print->export_raster(source_path.string(), m_upload_job.upload_data.upload_path.string()); | ||||
| 	} | ||||
| 
 | ||||
| 	m_print->set_status(100, (boost::format("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue") % m_upload_job.printhost->get_host()).str()); | ||||
|  |  | |||
|  | @ -1025,7 +1025,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 object as STL")) + dots, "", | ||||
|     append_menu_item(menu, wxID_ANY, _(L("Export as STL")) + dots, "", | ||||
|         [](wxCommandEvent&) { wxGetApp().plater()->export_stl(true); }, "", menu); | ||||
|     menu->AppendSeparator(); | ||||
| } | ||||
|  | @ -1101,6 +1101,7 @@ void ObjectList::create_part_popupmenu(wxMenu *menu) | |||
| #endif // __WXOSX__
 | ||||
| 
 | ||||
|     append_menu_item_fix_through_netfabb(menu); | ||||
|     append_menu_item_export_stl(menu); | ||||
| 
 | ||||
|     m_menu_item_split_part = append_menu_item_split(menu); | ||||
| 
 | ||||
|  |  | |||
|  | @ -15,12 +15,6 @@ namespace Slic3r { | |||
| namespace GUI { | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // GLGizmoCut
 | ||||
| 
 | ||||
| class GLGizmoCutPanel : public wxPanel | ||||
| { | ||||
| public: | ||||
|  | @ -192,7 +186,7 @@ void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit, co | |||
|     m_imgui->set_next_window_bg_alpha(0.5f); | ||||
|     m_imgui->begin(_(L("Cut")), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); | ||||
| 
 | ||||
|     ImGui::PushItemWidth(100.0f); | ||||
|     ImGui::PushItemWidth(m_imgui->scaled(5.0f)); | ||||
|     bool _value_changed = ImGui::InputDouble("Z", &m_cut_z, 0.0f, 0.0f, "%.2f"); | ||||
| 
 | ||||
|     m_imgui->checkbox(_(L("Keep upper part")), m_keep_upper); | ||||
|  |  | |||
|  | @ -38,6 +38,8 @@ | |||
| #include "libslic3r/SLA/SLARotfinder.hpp" | ||||
| #include "libslic3r/Utils.hpp" | ||||
| 
 | ||||
| #include "libnest2d/optimizers/nlopt/genetic.hpp" | ||||
| 
 | ||||
| #include "GUI.hpp" | ||||
| #include "GUI_App.hpp" | ||||
| #include "GUI_ObjectList.hpp" | ||||
|  | @ -1199,7 +1201,7 @@ struct Plater::priv | |||
|     BoundingBox scaled_bed_shape_bb() const; | ||||
|     std::vector<size_t> load_files(const std::vector<fs::path>& input_files, bool load_model, bool load_config); | ||||
|     std::vector<size_t> load_model_objects(const ModelObjectPtrs &model_objects); | ||||
|     std::unique_ptr<CheckboxFileDialog> get_export_file(GUI::FileType file_type); | ||||
|     wxString get_export_file(GUI::FileType file_type); | ||||
| 
 | ||||
|     const Selection& get_selection() const; | ||||
|     Selection& get_selection(); | ||||
|  | @ -1617,6 +1619,45 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_ | |||
|                 } | ||||
| #if ENABLE_VOLUMES_CENTERING_FIXES | ||||
|             } | ||||
|             else if ((wxGetApp().get_mode() == comSimple) && (type_3mf || type_any_amf)) | ||||
|             { | ||||
|                 bool advanced = false; | ||||
|                 for (const ModelObject* model_object : model.objects) | ||||
|                 { | ||||
|                     // is there more than one instance ?
 | ||||
|                     if (model_object->instances.size() > 1) | ||||
|                     { | ||||
|                         advanced = true; | ||||
|                         break; | ||||
|                     } | ||||
| 
 | ||||
|                     // is there any modifier ?
 | ||||
|                     for (const ModelVolume* model_volume : model_object->volumes) | ||||
|                     { | ||||
|                         if (!model_volume->is_model_part()) | ||||
|                         { | ||||
|                             advanced = true; | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     if (advanced) | ||||
|                         break; | ||||
|                 } | ||||
| 
 | ||||
|                 if (advanced) | ||||
|                 { | ||||
|                     wxMessageDialog dlg(q, _(L("This file cannot be loaded in simple mode. Do you want to switch to expert mode?\n")), | ||||
|                         _(L("Detected advanced data")), wxICON_WARNING | wxYES | wxNO); | ||||
|                     if (dlg.ShowModal() == wxID_YES) | ||||
|                     { | ||||
|                         Slic3r::GUI::wxGetApp().save_mode(comExpert); | ||||
|                         view3D->set_as_dirty(); | ||||
|                     } | ||||
|                     else | ||||
|                         return obj_idxs; | ||||
|                 } | ||||
|             } | ||||
| #endif // ENABLE_VOLUMES_CENTERING_FIXES
 | ||||
| 
 | ||||
| #if !ENABLE_VOLUMES_CENTERING_FIXES | ||||
|  | @ -1642,7 +1683,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_ | |||
|                         Slic3r::GUI::show_error(nullptr,  | ||||
|                             wxString::Format(_(L("You can't to add the object(s) from %s because of one or some of them is(are) multi-part")),  | ||||
|                                              from_path(filename))); | ||||
|                         return std::vector<size_t>(); | ||||
|                         return obj_idxs; | ||||
|                     } | ||||
|             } | ||||
| 
 | ||||
|  | @ -1784,7 +1825,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode | |||
|     return obj_idxs; | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType file_type) | ||||
| wxString Plater::priv::get_export_file(GUI::FileType file_type) | ||||
| { | ||||
|     wxString wildcard; | ||||
|     switch (file_type) { | ||||
|  | @ -1801,34 +1842,56 @@ std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType | |||
| 
 | ||||
|     // Update printbility state of each of the ModelInstances.
 | ||||
|     this->update_print_volume_state(); | ||||
|     // Find the file name of the first printable object.
 | ||||
| 	fs::path output_file = this->model.propose_export_file_name_and_path(); | ||||
| 
 | ||||
|     const Selection& selection = get_selection(); | ||||
|     int obj_idx = selection.get_object_idx(); | ||||
| 
 | ||||
|     fs::path output_file; | ||||
|     // first try to get the file name from the current selection
 | ||||
|     if ((0 <= obj_idx) && (obj_idx < (int)this->model.objects.size())) | ||||
|         output_file = this->model.objects[obj_idx]->get_export_filename(); | ||||
| 
 | ||||
|     if (output_file.empty()) | ||||
|         // Find the file name of the first printable object.
 | ||||
|         output_file = this->model.propose_export_file_name_and_path(); | ||||
| 
 | ||||
|     wxString dlg_title; | ||||
|     switch (file_type) { | ||||
|         case FT_STL: output_file.replace_extension("stl"); break; | ||||
|         case FT_AMF: output_file.replace_extension("zip.amf"); break;   // XXX: Problem on OS X with double extension?
 | ||||
|         case FT_3MF: output_file.replace_extension("3mf"); break; | ||||
|         case FT_STL: | ||||
|         { | ||||
|             output_file.replace_extension("stl"); | ||||
|             dlg_title = _(L("Export STL file:")); | ||||
|             break; | ||||
|         } | ||||
|         case FT_AMF: | ||||
|         { | ||||
|             // XXX: Problem on OS X with double extension?
 | ||||
|             output_file.replace_extension("zip.amf"); | ||||
|             dlg_title = _(L("Export AMF file:")); | ||||
|             break; | ||||
|         } | ||||
|         case FT_3MF: | ||||
|         { | ||||
|             output_file.replace_extension("3mf"); | ||||
|             dlg_title = _(L("Save file as:")); | ||||
|             break; | ||||
|         } | ||||
|         default: break; | ||||
|     } | ||||
| 
 | ||||
|     auto dlg = Slic3r::make_unique<CheckboxFileDialog>(q, | ||||
|         ((file_type == FT_AMF) || (file_type == FT_3MF)) ? _(L("Export print config")) : "", | ||||
|         true, | ||||
|         _(L("Save file as:")), | ||||
|         from_path(output_file.parent_path()), | ||||
|         from_path(output_file.filename()), | ||||
|         wildcard, | ||||
|         wxFD_SAVE | wxFD_OVERWRITE_PROMPT | ||||
|     ); | ||||
|     wxFileDialog* dlg = new wxFileDialog(q, dlg_title, | ||||
|         from_path(output_file.parent_path()), from_path(output_file.filename()), | ||||
|         wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); | ||||
| 
 | ||||
|     if (dlg->ShowModal() != wxID_OK) { | ||||
|         return nullptr; | ||||
|         return wxEmptyString; | ||||
|     } | ||||
| 
 | ||||
|     fs::path path(into_path(dlg->GetPath())); | ||||
|     wxString out_path = dlg->GetPath(); | ||||
|     fs::path path(into_path(out_path)); | ||||
|     wxGetApp().app_config->update_last_output_dir(path.parent_path().string()); | ||||
| 
 | ||||
|     return dlg; | ||||
|     return out_path; | ||||
| } | ||||
| 
 | ||||
| const Selection& Plater::priv::get_selection() const | ||||
|  | @ -2039,7 +2102,9 @@ void Plater::priv::sla_optimize_rotation() { | |||
|     rotoptimizing.store(true); | ||||
| 
 | ||||
|     int obj_idx = get_selected_object_idx(); | ||||
|     ModelObject * o = model.objects[obj_idx]; | ||||
|     if(obj_idx < 0) { rotoptimizing.store(false); return; } | ||||
| 
 | ||||
|     ModelObject * o = model.objects[size_t(obj_idx)]; | ||||
| 
 | ||||
|     background_process.stop(); | ||||
| 
 | ||||
|  | @ -2047,7 +2112,7 @@ void Plater::priv::sla_optimize_rotation() { | |||
|     statusbar()->set_range(100); | ||||
| 
 | ||||
|     auto stfn = [this] (unsigned st, const std::string& msg) { | ||||
|         statusbar()->set_progress(st); | ||||
|         statusbar()->set_progress(int(st)); | ||||
|         statusbar()->set_status_text(msg); | ||||
| 
 | ||||
|         // could be problematic, but we need the cancel button.
 | ||||
|  | @ -2065,8 +2130,59 @@ void Plater::priv::sla_optimize_rotation() { | |||
|                 [this](){ return !rotoptimizing.load(); } | ||||
|     ); | ||||
| 
 | ||||
|     const auto *bed_shape_opt = config->opt<ConfigOptionPoints>("bed_shape"); | ||||
|     assert(bed_shape_opt); | ||||
| 
 | ||||
|     auto& bedpoints = bed_shape_opt->values; | ||||
|     Polyline bed; bed.points.reserve(bedpoints.size()); | ||||
|     for(auto& v : bedpoints) bed.append(Point::new_scale(v(0), v(1))); | ||||
| 
 | ||||
|     double mindist = 6.0; // FIXME
 | ||||
|     double offs = mindist / 2.0 - EPSILON; | ||||
| 
 | ||||
|     if(rotoptimizing.load()) // wasn't canceled
 | ||||
|     for(ModelInstance * oi : o->instances) oi->set_rotation({r[X], r[Y], r[Z]}); | ||||
|     for(ModelInstance * oi : o->instances) { | ||||
|         oi->set_rotation({r[X], r[Y], r[Z]}); | ||||
| 
 | ||||
|         auto trchull = o->convex_hull_2d(oi->get_transformation().get_matrix()); | ||||
| 
 | ||||
|         namespace opt = libnest2d::opt; | ||||
|         opt::StopCriteria stopcr; | ||||
|         stopcr.relative_score_difference = 0.01; | ||||
|         stopcr.max_iterations = 10000; | ||||
|         stopcr.stop_score = 0.0; | ||||
|         opt::GeneticOptimizer solver(stopcr); | ||||
|         Polygon pbed(bed); | ||||
| 
 | ||||
|         auto bin = pbed.bounding_box(); | ||||
|         double binw = bin.size()(X) * SCALING_FACTOR - offs; | ||||
|         double binh = bin.size()(Y) * SCALING_FACTOR - offs; | ||||
| 
 | ||||
|         auto result = solver.optimize_min([&trchull, binw, binh](double rot){ | ||||
|             auto chull = trchull; | ||||
|             chull.rotate(rot); | ||||
| 
 | ||||
|             auto bb = chull.bounding_box(); | ||||
|             double bbw = bb.size()(X) * SCALING_FACTOR; | ||||
|             double bbh = bb.size()(Y) * SCALING_FACTOR; | ||||
| 
 | ||||
|             auto wdiff = bbw - binw; | ||||
|             auto hdiff = bbh - binh; | ||||
|             double diff = 0; | ||||
|             if(wdiff < 0 && hdiff < 0) diff = wdiff + hdiff; | ||||
|             if(wdiff > 0) diff += wdiff; | ||||
|             if(hdiff > 0) diff += hdiff; | ||||
| 
 | ||||
|             return diff; | ||||
|         }, opt::initvals(0.0), opt::bound(-PI/2, PI/2)); | ||||
| 
 | ||||
|         double r = std::get<0>(result.optimum); | ||||
| 
 | ||||
|         Vec3d rt = oi->get_rotation(); rt(Z) += r; | ||||
|         oi->set_rotation(rt); | ||||
|     } | ||||
| 
 | ||||
|     arr::find_new_position(model, o->instances, coord_t(mindist/SCALING_FACTOR), bed); | ||||
| 
 | ||||
|     // Correct the z offset of the object which was corrupted be the rotation
 | ||||
|     o->ensure_on_bed(); | ||||
|  | @ -2714,7 +2830,10 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ | |||
|     if (is_part) { | ||||
|         item_delete = append_menu_item(menu, wxID_ANY, _(L("Delete")) + "\tDel", _(L("Remove the selected object")), | ||||
|             [this](wxCommandEvent&) { q->remove_selected(); }, "brick_delete.png"); | ||||
|     } else { | ||||
| 
 | ||||
|         sidebar->obj_list()->append_menu_item_export_stl(menu); | ||||
|     } | ||||
|     else { | ||||
|         wxMenuItem* item_increase = append_menu_item(menu, wxID_ANY, _(L("Increase copies")) + "\t+", _(L("Place one more copy of the selected object")), | ||||
|             [this](wxCommandEvent&) { q->increase_instances(); }, "add.png"); | ||||
|         wxMenuItem* item_decrease = append_menu_item(menu, wxID_ANY, _(L("Decrease copies")) + "\t-", _(L("Remove one copy of the selected object")), | ||||
|  | @ -2747,8 +2866,9 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ | |||
| 
 | ||||
|         append_menu_item(menu, wxID_ANY, _(L("Export object as STL")) + dots, _(L("Export this single object as STL file")), | ||||
|             [this](wxCommandEvent&) { q->export_stl(true); }); | ||||
| 
 | ||||
|         menu->AppendSeparator(); | ||||
|     } | ||||
|     menu->AppendSeparator(); | ||||
| 
 | ||||
|     sidebar->obj_list()->append_menu_item_fix_through_netfabb(menu); | ||||
| 
 | ||||
|  | @ -3243,11 +3363,8 @@ void Plater::export_stl(bool selection_only) | |||
| { | ||||
|     if (p->model.objects.empty()) { return; } | ||||
| 
 | ||||
|     auto dialog = p->get_export_file(FT_STL); | ||||
|     if (! dialog) { return; } | ||||
| 
 | ||||
|     // Store a binary STL
 | ||||
|     const wxString path = dialog->GetPath(); | ||||
|     wxString path = p->get_export_file(FT_STL); | ||||
|     if (path.empty()) { return; } | ||||
|     const std::string path_u8 = into_u8(path); | ||||
| 
 | ||||
|     wxBusyCursor wait; | ||||
|  | @ -3259,8 +3376,17 @@ void Plater::export_stl(bool selection_only) | |||
| 
 | ||||
|         const auto obj_idx = selection.get_object_idx(); | ||||
|         if (obj_idx == -1) { return; } | ||||
|         mesh = p->model.objects[obj_idx]->mesh(); | ||||
|     } else { | ||||
| 
 | ||||
|         if (selection.get_mode() == Selection::Instance) | ||||
|             mesh = p->model.objects[obj_idx]->mesh(); | ||||
|         else | ||||
|         { | ||||
|             const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); | ||||
|             mesh = p->model.objects[obj_idx]->volumes[volume->volume_idx()]->mesh; | ||||
|             mesh.transform(volume->get_volume_transformation().get_matrix()); | ||||
|         } | ||||
|     } | ||||
|     else { | ||||
|         mesh = p->model.mesh(); | ||||
|     } | ||||
| 
 | ||||
|  | @ -3272,15 +3398,14 @@ void Plater::export_amf() | |||
| { | ||||
|     if (p->model.objects.empty()) { return; } | ||||
| 
 | ||||
|     auto dialog = p->get_export_file(FT_AMF); | ||||
|     if (! dialog) { return; } | ||||
| 
 | ||||
|     const wxString path = dialog->GetPath(); | ||||
|     wxString path = p->get_export_file(FT_AMF); | ||||
|     if (path.empty()) { return; } | ||||
|     const std::string path_u8 = into_u8(path); | ||||
| 
 | ||||
| 	DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure(); | ||||
|     wxBusyCursor wait; | ||||
| 	if (Slic3r::store_amf(path_u8.c_str(), &p->model, dialog->get_checkbox_value() ? &cfg : nullptr)) { | ||||
|     bool export_config = true; | ||||
|     DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure(); | ||||
|     if (Slic3r::store_amf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) { | ||||
|         // Success
 | ||||
|         p->statusbar()->set_status_text(wxString::Format(_(L("AMF file exported to %s")), path)); | ||||
|     } else { | ||||
|  | @ -3297,10 +3422,8 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) | |||
|     bool export_config = true; | ||||
|     if (output_path.empty()) | ||||
|     { | ||||
|         auto dialog = p->get_export_file(FT_3MF); | ||||
|         if (!dialog) { return; } | ||||
|         path = dialog->GetPath(); | ||||
|         export_config = dialog->get_checkbox_value(); | ||||
|         path = p->get_export_file(FT_3MF); | ||||
|         if (path.empty()) { return; } | ||||
|     } | ||||
|     else | ||||
|         path = from_path(output_path); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv