diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 7108b677f..064a05eb3 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -115,6 +115,7 @@ static constexpr const char* SOURCE_OFFSET_X_KEY = "source_offset_x"; static constexpr const char* SOURCE_OFFSET_Y_KEY = "source_offset_y"; static constexpr const char* SOURCE_OFFSET_Z_KEY = "source_offset_z"; static constexpr const char* SOURCE_IN_INCHES = "source_in_inches"; +static constexpr const char* SOURCE_IN_METERS = "source_in_meters"; const unsigned int VALID_OBJECT_TYPES_COUNT = 1; const char* VALID_OBJECT_TYPES[] = @@ -1913,6 +1914,8 @@ namespace Slic3r { volume->source.mesh_offset(2) = ::atof(metadata.value.c_str()); else if (metadata.key == SOURCE_IN_INCHES) volume->source.is_converted_from_inches = metadata.value == "1"; + else if (metadata.key == SOURCE_IN_METERS) + volume->source.is_converted_from_meters = metadata.value == "1"; else volume->config.set_deserialize(metadata.key, metadata.value); } @@ -2822,6 +2825,8 @@ namespace Slic3r { } if (volume->source.is_converted_from_inches) stream << prefix << SOURCE_IN_INCHES << "\" " << VALUE_ATTR << "=\"1\"/>\n"; + if (volume->source.is_converted_from_meters) + stream << prefix << SOURCE_IN_METERS << "\" " << VALUE_ATTR << "=\"1\"/>\n"; } // stores volume's config data diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 9b71990ea..1c9b6b27d 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -798,6 +798,9 @@ void AMFParserContext::endElement(const char * /* name */) else if (strcmp(opt_key, "source_in_inches") == 0) { m_volume->source.is_converted_from_inches = m_value[1] == "1"; } + else if (strcmp(opt_key, "source_in_meters") == 0) { + m_volume->source.is_converted_from_meters = m_value[1] == "1"; + } } } else if (m_path.size() == 3) { if (m_path[1] == NODE_TYPE_MATERIAL) { @@ -1232,6 +1235,8 @@ bool store_amf(const char* path, Model* model, const DynamicPrintConfig* config, } if (volume->source.is_converted_from_inches) stream << " <metadata type=\"slic3r.source_in_inches\">1</metadata>\n"; + if (volume->source.is_converted_from_meters) + stream << " <metadata type=\"slic3r.source_in_meters\">1</metadata>\n"; stream << std::setprecision(std::numeric_limits<float>::max_digits10); const indexed_triangle_set &its = volume->mesh().its; for (size_t i = 0; i < its.indices.size(); ++i) { diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 807221964..5f806955e 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -491,7 +491,7 @@ void Model::convert_from_meters(bool only_small_volumes) if (! only_small_volumes || obj->get_object_stl_stats().volume < 0.001) { // 0.001 = 0.1*0.1*0.1; obj->scale_mesh_after_creation(Vec3d(m_to_mm, m_to_mm, m_to_mm)); for (ModelVolume* v : obj->volumes) - v->source.is_converted_from_inches = true; + v->source.is_converted_from_meters = true; } } @@ -1046,13 +1046,14 @@ void ModelObject::scale_mesh_after_creation(const Vec3d &versor) this->invalidate_bounding_box(); } -void ModelObject::convert_units(ModelObjectPtrs& new_objects, bool from_imperial, std::vector<int> volume_idxs) +void ModelObject::convert_units(ModelObjectPtrs& new_objects, ConversionType conv_type, std::vector<int> volume_idxs) { BOOST_LOG_TRIVIAL(trace) << "ModelObject::convert_units - start"; ModelObject* new_object = new_clone(*this); - double koef = from_imperial ? 25.4 : 0.0393700787; + double koef = conv_type == ConversionType::CONV_FROM_INCH ? 25.4 : conv_type == ConversionType::CONV_TO_INCH ? 0.0393700787 : + conv_type == ConversionType::CONV_FROM_METER ? 1000 : conv_type == ConversionType::CONV_TO_METER ? 0.001 : 1; const Vec3d versor = Vec3d(koef, koef, koef); new_object->set_model(nullptr); @@ -1080,6 +1081,8 @@ void ModelObject::convert_units(ModelObjectPtrs& new_objects, bool from_imperial vol->source.input_file = volume->source.input_file; vol->source.object_idx = (int)new_objects.size(); vol->source.volume_idx = vol_idx; + vol->source.is_converted_from_inches = volume->source.is_converted_from_inches; + vol->source.is_converted_from_meters = volume->source.is_converted_from_meters; vol->supported_facets.assign(volume->supported_facets); vol->seam_facets.assign(volume->seam_facets); @@ -1091,7 +1094,10 @@ void ModelObject::convert_units(ModelObjectPtrs& new_objects, bool from_imperial std::find(volume_idxs.begin(), volume_idxs.end(), vol_idx) != volume_idxs.end())) { vol->scale_geometry_after_creation(versor); vol->set_offset(versor.cwiseProduct(volume->get_offset())); - vol->source.is_converted_from_inches = from_imperial; + if (conv_type == ConversionType::CONV_FROM_INCH || conv_type == ConversionType::CONV_TO_INCH) + vol->source.is_converted_from_inches = conv_type == ConversionType::CONV_FROM_INCH; + if (conv_type == ConversionType::CONV_FROM_METER || conv_type == ConversionType::CONV_TO_METER) + vol->source.is_converted_from_meters = conv_type == ConversionType::CONV_FROM_METER; } else vol->set_offset(volume->get_offset()); @@ -1841,6 +1847,14 @@ void ModelVolume::convert_from_imperial_units() this->source.is_converted_from_inches = true; } +void ModelVolume::convert_from_meters() +{ + double m_to_mm = 1000; + this->scale_geometry_after_creation(Vec3d(m_to_mm, m_to_mm, m_to_mm)); + this->set_offset(Vec3d(0, 0, 0)); + this->source.is_converted_from_meters = true; +} + void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const { mesh->transform(get_matrix(dont_translate)); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index b06ecf527..868639ee8 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -29,6 +29,7 @@ namespace cereal { } namespace Slic3r { +enum class ConversionType; class Model; class ModelInstance; @@ -325,7 +326,7 @@ public: // This method could only be called before the meshes of this ModelVolumes are not shared! void scale_mesh_after_creation(const Vec3d& versor); - void convert_units(ModelObjectPtrs&new_objects, bool from_imperial, std::vector<int> volume_idxs); + void convert_units(ModelObjectPtrs&new_objects, ConversionType conv_type, std::vector<int> volume_idxs); size_t materials_count() const; size_t facets_count() const; @@ -495,6 +496,13 @@ enum class EnforcerBlockerType : int8_t { BLOCKER = 2 }; +enum class ConversionType : int { + CONV_TO_INCH, + CONV_FROM_INCH, + CONV_TO_METER, + CONV_FROM_METER, +}; + class FacetsAnnotation final : public ObjectWithTimestamp { public: // Assign the content if the timestamp differs, don't assign an ObjectID. @@ -553,11 +561,12 @@ public: Vec3d mesh_offset{ Vec3d::Zero() }; Geometry::Transformation transform; bool is_converted_from_inches = false; + bool is_converted_from_meters = false; template<class Archive> void serialize(Archive& ar) { //FIXME Vojtech: Serialize / deserialize only if the Source is set. // likely testing input_file or object_idx would be sufficient. - ar(input_file, object_idx, volume_idx, mesh_offset, transform, is_converted_from_inches); + ar(input_file, object_idx, volume_idx, mesh_offset, transform, is_converted_from_inches, is_converted_from_meters); } }; Source source; @@ -657,6 +666,7 @@ public: void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); } void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); } void convert_from_imperial_units(); + void convert_from_meters(); const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); } diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 3f8d8fa73..b06821bb0 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1023,7 +1023,7 @@ void ObjectList::show_context_menu(const bool evt_context_menu) printer_technology() == ptFFF ? &m_menu_object : &m_menu_sla_object; if (type & (itObject | itVolume)) - append_menu_item_convert_unit(menu); + append_menu_items_convert_unit(menu); if (!(type & itInstance)) append_menu_item_settings(menu); } @@ -1906,56 +1906,59 @@ void ObjectList::append_menu_item_scale_selection_to_fit_print_volume(wxMenu* me [](wxCommandEvent&) { wxGetApp().plater()->scale_selection_to_fit_print_volume(); }, "", menu); } -void ObjectList::append_menu_item_convert_unit(wxMenu* menu, int insert_pos/* = 1*/) +void ObjectList::append_menu_items_convert_unit(wxMenu* menu, int insert_pos/* = 1*/) { std::vector<int> obj_idxs, vol_idxs; get_selection_indexes(obj_idxs, vol_idxs); if (obj_idxs.empty() && vol_idxs.empty()) return; - auto can_append = [this, obj_idxs, vol_idxs](bool from_imperial_unit) { + auto volume_respects_conversion = [](ModelVolume* volume, ConversionType conver_type) + { + return (conver_type == ConversionType::CONV_FROM_INCH && volume->source.is_converted_from_inches) || + (conver_type == ConversionType::CONV_TO_INCH && !volume->source.is_converted_from_inches) || + (conver_type == ConversionType::CONV_FROM_METER && volume->source.is_converted_from_meters) || + (conver_type == ConversionType::CONV_TO_METER && !volume->source.is_converted_from_meters); + }; + + auto can_append = [this, obj_idxs, vol_idxs, volume_respects_conversion](ConversionType conver_type) + { ModelObjectPtrs objects; for (int obj_idx : obj_idxs) { ModelObject* object = (*m_objects)[obj_idx]; if (vol_idxs.empty()) { for (ModelVolume* volume : object->volumes) - if (volume->source.is_converted_from_inches == from_imperial_unit) + if (volume_respects_conversion(volume, conver_type)) return false; } else { for (int vol_idx : vol_idxs) - if (object->volumes[vol_idx]->source.is_converted_from_inches == from_imperial_unit) + if (volume_respects_conversion(object->volumes[vol_idx], conver_type)) return false; } } return true; }; - wxString convert_menu_name = _L("Convert from imperial units"); - int convert_menu_id = menu->FindItem(convert_menu_name); - wxString revert_menu_name = _L("Revert conversion from imperial units"); - int revert_menu_id = menu->FindItem(revert_menu_name); + std::vector<std::pair<ConversionType, wxString>> items = { + {ConversionType::CONV_FROM_INCH , _L("Convert from imperial units") }, + {ConversionType::CONV_TO_INCH , _L("Revert conversion from imperial units") }, + {ConversionType::CONV_FROM_METER, _L("Convert from meters") }, + {ConversionType::CONV_TO_METER , _L("Revert conversion from meters") } }; - if (can_append(true)) { - // Delete revert menu item - if (revert_menu_id != wxNOT_FOUND) - menu->Destroy(revert_menu_id); - // Add convert menu item if it doesn't exist - if (convert_menu_id == wxNOT_FOUND) - append_menu_item(menu, wxID_ANY, convert_menu_name, convert_menu_name, - [](wxCommandEvent&) { wxGetApp().plater()->convert_unit(true); }, "", menu, - []() {return true;}, nullptr, insert_pos); - } - - if (can_append(false)) { - // Delete convert menu item - if (convert_menu_id != wxNOT_FOUND) - menu->Destroy(convert_menu_id); - // Add convert menu item if it doesn't exist - if (revert_menu_id == wxNOT_FOUND) - append_menu_item(menu, wxID_ANY, revert_menu_name, revert_menu_name, - [](wxCommandEvent&) { wxGetApp().plater()->convert_unit(false); }, "", menu, - []() {return true;}, nullptr, insert_pos); + for (auto item : items) { + int menu_id = menu->FindItem(item.second); + if (can_append(item.first)) { + // Add menu item if it doesn't exist + if (menu_id == wxNOT_FOUND) + append_menu_item(menu, wxID_ANY, item.second, item.second, + [item](wxCommandEvent&) { wxGetApp().plater()->convert_unit(item.first); }, "", menu, + []() {return true; }, nullptr, insert_pos); + } + else if (menu_id != wxNOT_FOUND) { + // Delete menu item + menu->Destroy(menu_id); + } } } @@ -4606,7 +4609,7 @@ void ObjectList::show_multi_selection_menu() return wxGetApp().plater()->can_reload_from_disk(); }, wxGetApp().plater()); - append_menu_item_convert_unit(menu); + append_menu_items_convert_unit(menu); if (can_merge_to_multipart_object()) append_menu_item_merge_to_multipart_object(menu); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 15d5ecb08..0846def53 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -284,7 +284,7 @@ public: void append_menu_item_change_extruder(wxMenu* menu); void append_menu_item_delete(wxMenu* menu); void append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu); - void append_menu_item_convert_unit(wxMenu* menu, int insert_pos = 1); // Add "Conver/Revert..." menu item after "Reload From Disk" + void append_menu_items_convert_unit(wxMenu* menu, int insert_pos = 1); // Add "Conver/Revert..." menu items (from/to inches/meters) after "Reload From Disk" void append_menu_item_merge_to_multipart_object(wxMenu *menu); void append_menu_item_merge_to_single_object(wxMenu *menu); void create_object_popupmenu(wxMenu *menu); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b6dda66fd..5296fd6fa 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3329,6 +3329,8 @@ void Plater::priv::reload_from_disk() new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset)); if (old_volume->source.is_converted_from_inches) new_volume->convert_from_imperial_units(); + if (old_volume->source.is_converted_from_meters) + new_volume->convert_from_meters(); new_volume->supported_facets.assign(old_volume->supported_facets); new_volume->seam_facets.assign(old_volume->seam_facets); std::swap(old_model_object->volumes[sel_v.volume_idx], old_model_object->volumes.back()); @@ -3871,7 +3873,7 @@ void Plater::priv::on_right_click(RBtnEvent& evt) menu_item_convert_unit_position = 2; } - sidebar->obj_list()->append_menu_item_convert_unit(menu, menu_item_convert_unit_position); + sidebar->obj_list()->append_menu_items_convert_unit(menu, menu_item_convert_unit_position); sidebar->obj_list()->append_menu_item_settings(menu); if (printer_technology != ptSLA) @@ -5246,20 +5248,22 @@ void Plater::scale_selection_to_fit_print_volume() p->scale_selection_to_fit_print_volume(); } -void Plater::convert_unit(bool from_imperial_unit) +void Plater::convert_unit(ConversionType conv_type) { std::vector<int> obj_idxs, volume_idxs; wxGetApp().obj_list()->get_selection_indexes(obj_idxs, volume_idxs); if (obj_idxs.empty() && volume_idxs.empty()) return; - TakeSnapshot snapshot(this, from_imperial_unit ? _L("Convert from imperial units") : _L("Revert conversion from imperial units")); + TakeSnapshot snapshot(this, conv_type == ConversionType::CONV_FROM_INCH ? _L("Convert from imperial units") : + conv_type == ConversionType::CONV_TO_INCH ? _L("Revert conversion from imperial units") : + conv_type == ConversionType::CONV_FROM_METER ? _L("Convert from meters") : _L("Revert conversion from meters")); wxBusyCursor wait; ModelObjectPtrs objects; for (int obj_idx : obj_idxs) { ModelObject *object = p->model.objects[obj_idx]; - object->convert_units(objects, from_imperial_unit, volume_idxs); + object->convert_units(objects, conv_type, volume_idxs); remove(obj_idx); } p->load_model_objects(objects); diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 5407a6e85..f40acc215 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -28,6 +28,7 @@ class ModelInstance; class Print; class SLAPrint; enum SLAPrintObjectStep : unsigned int; +enum class ConversionType : int; using ModelInstancePtrs = std::vector<ModelInstance*>; @@ -191,7 +192,7 @@ public: void fill_bed_with_instances(); bool is_selection_empty() const; void scale_selection_to_fit_print_volume(); - void convert_unit(bool from_imperial_unit); + void convert_unit(ConversionType conv_type); 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);