Follow-up of dc75a59115 - Use a unique command and method to export to STL and OBJ - Added export to OBJ also for Export plater to STL commands

This commit is contained in:
enricoturri1966 2022-01-19 14:23:03 +01:00
parent 71f08841f9
commit c74ae1c513
6 changed files with 16 additions and 155 deletions

View file

@ -483,6 +483,7 @@ struct FileWildcards {
static const FileWildcards file_wildcards_by_type[FT_SIZE] = {
/* FT_STL */ { "STL files"sv, { ".stl"sv } },
/* FT_OBJ */ { "OBJ files"sv, { ".obj"sv } },
/* FT_OBJECT */ { "Object files"sv, { ".stl"sv, ".obj"sv } },
/* FT_AMF */ { "AMF files"sv, { ".amf"sv, ".zip.amf"sv, ".xml"sv } },
/* FT_3MF */ { "3MF files"sv, { ".3mf"sv } },
/* FT_GCODE */ { "G-code files"sv, { ".gcode"sv, ".gco"sv, ".g"sv, ".ngc"sv } },

View file

@ -53,6 +53,7 @@ enum FileType
{
FT_STL,
FT_OBJ,
FT_OBJECT,
FT_AMF,
FT_3MF,
FT_GCODE,

View file

@ -712,14 +712,8 @@ wxMenuItem* MenuFactory::append_menu_item_simplify(wxMenu* menu)
void MenuFactory::append_menu_item_export_stl(wxMenu* menu)
{
append_menu_item(menu, wxID_ANY, _L("Export as STL") + dots, "",
[](wxCommandEvent&) { plater()->export_stl(false, true); }, "", nullptr,
[]() {
const Selection& selection = plater()->canvas3D()->get_selection();
return selection.is_single_full_instance() || selection.is_single_full_object() || selection.is_single_volume() || selection.is_single_modifier();
}, m_parent);
append_menu_item(menu, wxID_ANY, _L("Export as OBJ") + dots, "",
[](wxCommandEvent&) { plater()->export_obj(false, true); }, "", nullptr,
append_menu_item(menu, wxID_ANY, _L("Export as STL/OBJ") + dots, "",
[](wxCommandEvent&) { plater()->export_stl_obj(false, true); }, "", nullptr,
[]() {
const Selection& selection = plater()->canvas3D()->get_selection();
return selection.is_single_full_instance() || selection.is_single_full_object() || selection.is_single_volume() || selection.is_single_modifier();

View file

@ -1239,11 +1239,11 @@ void MainFrame::init_menubar_as_editor()
[this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(true); }, "export_to_sd", nullptr,
[this]() {return can_export_gcode_sd(); }, this);
export_menu->AppendSeparator();
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(); }, "export_plater", nullptr,
append_menu_item(export_menu, wxID_ANY, _L("Export Plate as &STL/OBJ") + dots, _L("Export current plate as STL/OBJ"),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl_obj(); }, "export_plater", nullptr,
[this](){return can_export_model(); }, this);
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); }, "export_plater", nullptr,
append_menu_item(export_menu, wxID_ANY, _L("Export Plate as STL/OBJ &Including Supports") + dots, _L("Export current plate as STL/OBJ including supports"),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl_obj(true); }, "export_plater", nullptr,
[this](){return can_export_supports(); }, this);
// Deprecating AMF export. Let's wait for user feedback.
// append_menu_item(export_menu, wxID_ANY, _L("Export Plate as &AMF") + dots, _L("Export current plate as AMF"),

View file

@ -2803,6 +2803,7 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type)
case FT_3MF:
case FT_GCODE:
case FT_OBJ:
case FT_OBJECT:
wildcard = file_wildcards(file_type);
break;
default:
@ -5733,11 +5734,11 @@ void Plater::export_gcode(bool prefer_removable)
}
}
void Plater::export_stl(bool extended, bool selection_only)
void Plater::export_stl_obj(bool extended, bool selection_only)
{
if (p->model.objects.empty()) { return; }
wxString path = p->get_export_file(FT_STL);
wxString path = p->get_export_file(FT_OBJECT);
if (path.empty()) { return; }
const std::string path_u8 = into_u8(path);
@ -5868,148 +5869,13 @@ void Plater::export_stl(bool extended, bool selection_only)
}
}
Slic3r::store_stl(path_u8.c_str(), &mesh, true);
if (path.EndsWith(".stl"))
Slic3r::store_stl(path_u8.c_str(), &mesh, true);
else if (path.EndsWith(".obj"))
Slic3r::store_obj(path_u8.c_str(), &mesh);
// p->statusbar()->set_status_text(format_wxstr(_L("STL file exported to %s"), path));
}
void Plater::export_obj(bool extended, bool selection_only)
{
if (p->model.objects.empty()) { return; }
wxString path = p->get_export_file(FT_OBJ);
if (path.empty()) { return; }
const std::string path_u8 = into_u8(path);
wxBusyCursor wait;
const auto& selection = p->get_selection();
const auto obj_idx = selection.get_object_idx();
if (selection_only && (obj_idx == -1 || selection.is_wipe_tower()))
return;
// Following lambda generates a combined mesh for export with normals pointing outwards.
auto mesh_to_export = [](const ModelObject& mo, int instance_id) {
TriangleMesh mesh;
for (const ModelVolume* v : mo.volumes)
if (v->is_model_part()) {
TriangleMesh vol_mesh(v->mesh());
vol_mesh.transform(v->get_matrix(), true);
mesh.merge(vol_mesh);
}
if (instance_id == -1) {
TriangleMesh vols_mesh(mesh);
mesh = TriangleMesh();
for (const ModelInstance* i : mo.instances) {
TriangleMesh m = vols_mesh;
m.transform(i->get_matrix(), true);
mesh.merge(m);
}
}
else if (0 <= instance_id && instance_id < int(mo.instances.size()))
mesh.transform(mo.instances[instance_id]->get_matrix(), true);
return mesh;
};
TriangleMesh mesh;
if (p->printer_technology == ptFFF) {
if (selection_only) {
const ModelObject* model_object = p->model.objects[obj_idx];
if (selection.get_mode() == Selection::Instance)
mesh = mesh_to_export(*model_object, (selection.is_single_full_object() && model_object->instances.size() > 1) ? -1 : selection.get_instance_idx());
else {
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
mesh = model_object->volumes[volume->volume_idx()]->mesh();
mesh.transform(volume->get_volume_transformation().get_matrix(), true);
}
if (!selection.is_single_full_object() || model_object->instances.size() == 1)
mesh.translate(-model_object->origin_translation.cast<float>());
}
else {
for (const ModelObject* o : p->model.objects) {
mesh.merge(mesh_to_export(*o, -1));
}
}
}
else {
// This is SLA mode, all objects have only one volume.
// However, we must have a look at the backend to load
// hollowed mesh and/or supports
const PrintObjects& objects = p->sla_print.objects();
for (const SLAPrintObject* object : objects) {
const ModelObject* model_object = object->model_object();
if (selection_only) {
if (model_object->id() != p->model.objects[obj_idx]->id())
continue;
}
const Transform3d mesh_trafo_inv = object->trafo().inverse();
const bool is_left_handed = object->is_left_handed();
TriangleMesh pad_mesh;
const bool has_pad_mesh = extended && object->has_mesh(slaposPad);
if (has_pad_mesh) {
pad_mesh = object->get_mesh(slaposPad);
pad_mesh.transform(mesh_trafo_inv);
}
TriangleMesh supports_mesh;
const bool has_supports_mesh = extended && 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()) {
const bool one_inst_only = selection_only && !selection.is_single_full_object();
const int instance_idx = it - model_object->instances.begin();
const Transform3d& inst_transform = one_inst_only
? Transform3d::Identity()
: object->model_object()->instances[instance_idx]->get_transformation().get_matrix();
TriangleMesh inst_mesh;
if (has_pad_mesh) {
TriangleMesh inst_pad_mesh = pad_mesh;
inst_pad_mesh.transform(inst_transform, is_left_handed);
inst_mesh.merge(inst_pad_mesh);
}
if (has_supports_mesh) {
TriangleMesh inst_supports_mesh = supports_mesh;
inst_supports_mesh.transform(inst_transform, is_left_handed);
inst_mesh.merge(inst_supports_mesh);
}
TriangleMesh inst_object_mesh = object->get_mesh_to_slice();
inst_object_mesh.transform(mesh_trafo_inv);
inst_object_mesh.transform(inst_transform, is_left_handed);
inst_mesh.merge(inst_object_mesh);
// ensure that the instance lays on the bed
inst_mesh.translate(0.0f, 0.0f, -inst_mesh.bounding_box().min.z());
// merge instance with global mesh
mesh.merge(inst_mesh);
if (one_inst_only)
break;
}
}
}
}
Slic3r::store_obj(path_u8.c_str(), &mesh);
}
void Plater::export_amf()
{
if (p->model.objects.empty()) { return; }

View file

@ -256,8 +256,7 @@ public:
void cut(size_t obj_idx, size_t instance_idx, coordf_t z, ModelObjectCutAttributes attributes);
void export_gcode(bool prefer_removable);
void export_stl(bool extended = false, bool selection_only = false);
void export_obj(bool extended = false, bool selection_only = false);
void export_stl_obj(bool extended = false, bool selection_only = false);
void export_amf();
bool export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path());
void reload_from_disk();