mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-30 13:26:58 +00:00
Initial Draco write support.
Currently always exports with 16-bit precision and speed 0 (best compression). The back-end function does have arguments to specify them, it's just not hooked into the GUI.
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <boost/iostreams/device/mapped_file.hpp>
|
#include <boost/iostreams/device/mapped_file.hpp>
|
||||||
|
|
||||||
|
#include <draco/compression/encode.h>
|
||||||
#include <draco/compression/decode.h>
|
#include <draco/compression/decode.h>
|
||||||
#include <draco/io/mesh_io.h>
|
#include <draco/io/mesh_io.h>
|
||||||
#include <draco/mesh/mesh.h>
|
#include <draco/mesh/mesh.h>
|
||||||
@@ -96,22 +97,69 @@ bool load_drc(const char *path, Model *model, const char *object_name_in)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool store_drc(const char *path, TriangleMesh *mesh, bool binary)
|
bool store_drc(const char *path, TriangleMesh *mesh, int bits, int speed)
|
||||||
{
|
{
|
||||||
// TODO
|
try {
|
||||||
return false;
|
const std::vector<stl_triangle_vertex_indices>* indices = &(mesh->its.indices);
|
||||||
|
const std::vector<stl_vertex>* vertices = &(mesh->its.vertices);
|
||||||
|
|
||||||
|
Mesh dracoMesh;
|
||||||
|
|
||||||
|
dracoMesh.set_num_points(vertices->size());
|
||||||
|
|
||||||
|
GeometryAttribute gaPos;
|
||||||
|
gaPos.Init(GeometryAttribute::POSITION, nullptr, 3, DT_FLOAT32, false, sizeof(float)*3, 0);
|
||||||
|
int32_t idPos = dracoMesh.AddAttribute(gaPos, true, indices->size() * 3);
|
||||||
|
|
||||||
|
dracoMesh.attribute(idPos)->Resize(vertices->size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < vertices->size(); ++ i) {
|
||||||
|
float vertex[3];
|
||||||
|
vertex[0] = vertices->at(i)(0);
|
||||||
|
vertex[1] = vertices->at(i)(1);
|
||||||
|
vertex[2] = vertices->at(i)(2);
|
||||||
|
dracoMesh.attribute(idPos)->SetAttributeValue(AttributeValueIndex(i), vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
dracoMesh.SetNumFaces(indices->size());
|
||||||
|
for (size_t i = 0; i < indices->size(); ++ i) {
|
||||||
|
Mesh::Face face;
|
||||||
|
face[0] = PointIndex(indices->at(i)[0]);
|
||||||
|
face[1] = PointIndex(indices->at(i)[1]);
|
||||||
|
face[2] = PointIndex(indices->at(i)[2]);
|
||||||
|
dracoMesh.SetFace(FaceIndex(i), face);
|
||||||
|
}
|
||||||
|
|
||||||
|
Encoder encoder;
|
||||||
|
encoder.SetSpeedOptions(speed, speed);
|
||||||
|
encoder.SetAttributeQuantization(GeometryAttribute::POSITION, bits);
|
||||||
|
|
||||||
|
EncoderBuffer buffer;
|
||||||
|
encoder.EncodeMeshToBuffer(dracoMesh, &buffer);
|
||||||
|
|
||||||
|
FILE* fp = boost::nowide::fopen(path, "wb");
|
||||||
|
if (!fp) return false;
|
||||||
|
size_t written = fwrite(buffer.data(), 1, buffer.size(), fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
if (written != buffer.size()) return false;
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "store_drc: " << e.what();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool store_drc(const char *path, ModelObject *model_object, bool binary)
|
bool store_drc(const char *path, ModelObject *model_object, int bits, int speed)
|
||||||
{
|
{
|
||||||
TriangleMesh mesh = model_object->mesh();
|
TriangleMesh mesh = model_object->mesh();
|
||||||
return store_drc(path, &mesh, binary);
|
return store_drc(path, &mesh, bits, speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool store_drc(const char *path, Model *model, bool binary)
|
bool store_drc(const char *path, Model *model, int bits, int speed)
|
||||||
{
|
{
|
||||||
TriangleMesh mesh = model->mesh();
|
TriangleMesh mesh = model->mesh();
|
||||||
return store_drc(path, &mesh, binary);
|
return store_drc(path, &mesh, bits, speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // namespace Slic3r
|
}; // namespace Slic3r
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ class Model;
|
|||||||
extern bool load_drc(const char *path, TriangleMesh *meshptr);
|
extern bool load_drc(const char *path, TriangleMesh *meshptr);
|
||||||
extern bool load_drc(const char *path, Model *model, const char *object_name = nullptr);
|
extern bool load_drc(const char *path, Model *model, const char *object_name = nullptr);
|
||||||
|
|
||||||
extern bool store_drc(const char *path, TriangleMesh *mesh, bool binary);
|
extern bool store_drc(const char *path, TriangleMesh *mesh, int bits, int speed);
|
||||||
extern bool store_drc(const char *path, ModelObject *model_object, bool binary);
|
extern bool store_drc(const char *path, ModelObject *model_object, int bits, int speed);
|
||||||
extern bool store_drc(const char *path, Model *model, bool binary);
|
extern bool store_drc(const char *path, Model *model, int bits, int speed);
|
||||||
|
|
||||||
}; // namespace Slic3r
|
}; // namespace Slic3r
|
||||||
|
|
||||||
|
|||||||
@@ -529,6 +529,7 @@ static const FileWildcards file_wildcards_by_type[FT_SIZE] = {
|
|||||||
/* FT_SVG */ { "SVG files"sv, { ".svg"sv } },
|
/* FT_SVG */ { "SVG files"sv, { ".svg"sv } },
|
||||||
/* FT_TEX */ { "Texture"sv, { ".png"sv, ".svg"sv } },
|
/* FT_TEX */ { "Texture"sv, { ".png"sv, ".svg"sv } },
|
||||||
/* FT_SL1 */ { "Masked SLA files"sv, { ".sl1"sv, ".sl1s"sv } },
|
/* FT_SL1 */ { "Masked SLA files"sv, { ".sl1"sv, ".sl1s"sv } },
|
||||||
|
/* FT_DRC */ { "Draco files"sv, { ".drc"sv } },
|
||||||
};
|
};
|
||||||
|
|
||||||
// This function produces a Win32 file dialog file template mask to be consumed by wxWidgets on all platforms.
|
// This function produces a Win32 file dialog file template mask to be consumed by wxWidgets on all platforms.
|
||||||
|
|||||||
@@ -105,6 +105,8 @@ enum FileType
|
|||||||
|
|
||||||
FT_SL1,
|
FT_SL1,
|
||||||
|
|
||||||
|
FT_DRC,
|
||||||
|
|
||||||
FT_SIZE,
|
FT_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -855,6 +855,27 @@ void MenuFactory::append_menu_item_export_stl(wxMenu* menu, bool is_mulity_menu)
|
|||||||
}, m_parent);
|
}, m_parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MenuFactory::append_menu_item_export_drc(wxMenu* menu, bool is_mulity_menu)
|
||||||
|
{
|
||||||
|
append_menu_item(menu, wxID_ANY, _L("Export as one DRC") + dots, "",
|
||||||
|
[](wxCommandEvent&) { plater()->export_drc(false, true); }, "", nullptr,
|
||||||
|
[is_mulity_menu]() {
|
||||||
|
const Selection& selection = plater()->canvas3D()->get_selection();
|
||||||
|
if (is_mulity_menu)
|
||||||
|
return selection.is_multiple_full_instance() || selection.is_multiple_full_object();
|
||||||
|
else
|
||||||
|
return selection.is_single_full_instance() || selection.is_single_full_object();
|
||||||
|
}, m_parent);
|
||||||
|
if (!is_mulity_menu)
|
||||||
|
return;
|
||||||
|
append_menu_item(menu, wxID_ANY, _L("Export as DRCs") + dots, "",
|
||||||
|
[](wxCommandEvent&) { plater()->export_drc(false, true, true); }, "", nullptr,
|
||||||
|
[]() {
|
||||||
|
const Selection& selection = plater()->canvas3D()->get_selection();
|
||||||
|
return selection.is_multiple_full_instance() || selection.is_multiple_full_object();
|
||||||
|
}, m_parent);
|
||||||
|
}
|
||||||
|
|
||||||
void MenuFactory::append_menu_item_reload_from_disk(wxMenu* menu)
|
void MenuFactory::append_menu_item_reload_from_disk(wxMenu* menu)
|
||||||
{
|
{
|
||||||
append_menu_item(menu, wxID_ANY, _L("Reload from disk"), _L("Reload the selected parts from disk"),
|
append_menu_item(menu, wxID_ANY, _L("Reload from disk"), _L("Reload the selected parts from disk"),
|
||||||
@@ -1269,6 +1290,7 @@ void MenuFactory::create_common_object_menu(wxMenu* menu)
|
|||||||
// BBS
|
// BBS
|
||||||
append_menu_item_reload_from_disk(menu);
|
append_menu_item_reload_from_disk(menu);
|
||||||
append_menu_item_export_stl(menu);
|
append_menu_item_export_stl(menu);
|
||||||
|
append_menu_item_export_drc(menu);
|
||||||
// "Scale to print volume" makes a sense just for whole object
|
// "Scale to print volume" makes a sense just for whole object
|
||||||
append_menu_item_scale_selection_to_fit_print_volume(menu);
|
append_menu_item_scale_selection_to_fit_print_volume(menu);
|
||||||
|
|
||||||
@@ -1348,6 +1370,7 @@ void MenuFactory::create_extra_object_menu()
|
|||||||
append_menu_item_reload_from_disk(&m_object_menu);
|
append_menu_item_reload_from_disk(&m_object_menu);
|
||||||
append_menu_item_replace_with_stl(&m_object_menu);
|
append_menu_item_replace_with_stl(&m_object_menu);
|
||||||
append_menu_item_export_stl(&m_object_menu);
|
append_menu_item_export_stl(&m_object_menu);
|
||||||
|
append_menu_item_export_drc(&m_object_menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuFactory::create_bbl_assemble_object_menu()
|
void MenuFactory::create_bbl_assemble_object_menu()
|
||||||
@@ -1382,6 +1405,7 @@ void MenuFactory::create_part_menu()
|
|||||||
append_menu_item_delete(menu);
|
append_menu_item_delete(menu);
|
||||||
append_menu_item_reload_from_disk(menu);
|
append_menu_item_reload_from_disk(menu);
|
||||||
append_menu_item_export_stl(menu);
|
append_menu_item_export_stl(menu);
|
||||||
|
append_menu_item_export_drc(menu);
|
||||||
append_menu_item_fix_through_netfabb(menu);
|
append_menu_item_fix_through_netfabb(menu);
|
||||||
append_menu_items_mirror(menu);
|
append_menu_items_mirror(menu);
|
||||||
append_menu_item_merge_parts_to_single_part(menu);
|
append_menu_item_merge_parts_to_single_part(menu);
|
||||||
@@ -1697,6 +1721,7 @@ wxMenu* MenuFactory::multi_selection_menu()
|
|||||||
append_menu_item_change_filament(menu);
|
append_menu_item_change_filament(menu);
|
||||||
menu->AppendSeparator();
|
menu->AppendSeparator();
|
||||||
append_menu_item_export_stl(menu, true);
|
append_menu_item_export_stl(menu, true);
|
||||||
|
append_menu_item_export_drc(menu, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
append_menu_item_center(menu);
|
append_menu_item_center(menu);
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ private:
|
|||||||
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
|
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
|
||||||
//wxMenuItem* append_menu_item_simplify(wxMenu* menu);
|
//wxMenuItem* append_menu_item_simplify(wxMenu* menu);
|
||||||
void append_menu_item_export_stl(wxMenu* menu, bool is_mulity_menu = false);
|
void append_menu_item_export_stl(wxMenu* menu, bool is_mulity_menu = false);
|
||||||
|
void append_menu_item_export_drc(wxMenu* menu, bool is_mulity_menu = false);
|
||||||
void append_menu_item_reload_from_disk(wxMenu* menu);
|
void append_menu_item_reload_from_disk(wxMenu* menu);
|
||||||
void append_menu_item_replace_with_stl(wxMenu* menu);
|
void append_menu_item_replace_with_stl(wxMenu* menu);
|
||||||
void append_menu_item_change_extruder(wxMenu* menu);
|
void append_menu_item_change_extruder(wxMenu* menu);
|
||||||
|
|||||||
@@ -2403,6 +2403,12 @@ void MainFrame::init_menubar_as_editor()
|
|||||||
append_menu_item(export_menu, wxID_ANY, _L("Export all objects as STLs") + dots, _L("Export all objects as STLs"),
|
append_menu_item(export_menu, wxID_ANY, _L("Export all objects as STLs") + dots, _L("Export all objects as STLs"),
|
||||||
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(false, false, true); }, "menu_export_stl", nullptr,
|
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(false, false, true); }, "menu_export_stl", nullptr,
|
||||||
[this](){return can_export_model(); }, this);
|
[this](){return can_export_model(); }, this);
|
||||||
|
append_menu_item(export_menu, wxID_ANY, _L("Export all objects as one DRC") + dots, _L("Export all objects as one DRC"),
|
||||||
|
[this](wxCommandEvent&) { if (m_plater) m_plater->export_drc(); }, "menu_export_stl", nullptr,
|
||||||
|
[this](){return can_export_model(); }, this);
|
||||||
|
append_menu_item(export_menu, wxID_ANY, _L("Export all objects as DRCs") + dots, _L("Export all objects as DRCs"),
|
||||||
|
[this](wxCommandEvent&) { if (m_plater) m_plater->export_drc(false, false, true); }, "menu_export_stl", nullptr,
|
||||||
|
[this](){return can_export_model(); }, this);
|
||||||
append_menu_item(export_menu, wxID_ANY, _L("Export Generic 3MF") + dots/* + "\tCtrl+G"*/, _L("Export 3mf file without using some 3mf-extensions"),
|
append_menu_item(export_menu, wxID_ANY, _L("Export Generic 3MF") + dots/* + "\tCtrl+G"*/, _L("Export 3mf file without using some 3mf-extensions"),
|
||||||
[this](wxCommandEvent&) { if (m_plater) m_plater->export_core_3mf(); }, "menu_export_sliced_file", nullptr,
|
[this](wxCommandEvent&) { if (m_plater) m_plater->export_core_3mf(); }, "menu_export_sliced_file", nullptr,
|
||||||
[this](){return can_export_model(); }, this);
|
[this](){return can_export_model(); }, this);
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
|
|
||||||
#include "libslic3r/libslic3r.h"
|
#include "libslic3r/libslic3r.h"
|
||||||
#include "libslic3r/Format/STL.hpp"
|
#include "libslic3r/Format/STL.hpp"
|
||||||
|
#include "libslic3r/Format/DRC.hpp"
|
||||||
#include "libslic3r/Format/STEP.hpp"
|
#include "libslic3r/Format/STEP.hpp"
|
||||||
#include "libslic3r/Format/AMF.hpp"
|
#include "libslic3r/Format/AMF.hpp"
|
||||||
//#include "libslic3r/Format/3mf.hpp"
|
//#include "libslic3r/Format/3mf.hpp"
|
||||||
@@ -4766,6 +4767,7 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type)
|
|||||||
wxString wildcard;
|
wxString wildcard;
|
||||||
switch (file_type) {
|
switch (file_type) {
|
||||||
case FT_STL:
|
case FT_STL:
|
||||||
|
case FT_DRC:
|
||||||
case FT_AMF:
|
case FT_AMF:
|
||||||
case FT_3MF:
|
case FT_3MF:
|
||||||
case FT_GCODE:
|
case FT_GCODE:
|
||||||
@@ -4787,6 +4789,12 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type)
|
|||||||
dlg_title = _L("Export STL file:");
|
dlg_title = _L("Export STL file:");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case FT_DRC:
|
||||||
|
{
|
||||||
|
output_file.replace_extension("drc");
|
||||||
|
dlg_title = _L("Export Draco file:");
|
||||||
|
break;
|
||||||
|
}
|
||||||
case FT_AMF:
|
case FT_AMF:
|
||||||
{
|
{
|
||||||
// XXX: Problem on OS X with double extension?
|
// XXX: Problem on OS X with double extension?
|
||||||
@@ -12135,6 +12143,225 @@ void Plater::export_stl(bool extended, bool selection_only, bool multi_stls)
|
|||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
void Plater::export_drc(bool extended, bool selection_only, bool multi_drcs)
|
||||||
|
{
|
||||||
|
if (p->model.objects.empty()) { return; }
|
||||||
|
|
||||||
|
wxString path;
|
||||||
|
int bits = 16;
|
||||||
|
int speed = 0;
|
||||||
|
if (multi_drcs) {
|
||||||
|
wxDirDialog dlg(this, _L("Choose a directory"), from_u8(wxGetApp().app_config->get_last_dir()),
|
||||||
|
wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
|
||||||
|
if (dlg.ShowModal() == wxID_OK) {
|
||||||
|
path = dlg.GetPath() + "/";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
path = p->get_export_file(FT_DRC);
|
||||||
|
}
|
||||||
|
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 EXPORT_WITH_BOOLEAN
|
||||||
|
if (selection_only && (obj_idx == -1 || selection.is_wipe_tower()))
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
// BBS support selecting multiple objects
|
||||||
|
if (selection_only && selection.is_wipe_tower()) return;
|
||||||
|
|
||||||
|
// BBS
|
||||||
|
if (selection_only) {
|
||||||
|
// only support selection single full object and mulitiple full object
|
||||||
|
if (!selection.is_single_full_object() && !selection.is_multiple_full_object()) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Following lambda generates a combined mesh for export with normals pointing outwards.
|
||||||
|
auto mesh_to_export_fff_no_boolean = [this](const ModelObject &mo, int instance_id) {
|
||||||
|
TriangleMesh mesh;
|
||||||
|
|
||||||
|
//Prusa export negative parts
|
||||||
|
std::vector<csg::CSGPart> csgmesh;
|
||||||
|
csgmesh.reserve(2 * mo.volumes.size());
|
||||||
|
csg::model_to_csgmesh(mo, Transform3d::Identity(), std::back_inserter(csgmesh),
|
||||||
|
csg::mpartsPositive | csg::mpartsNegative | csg::mpartsDoSplits);
|
||||||
|
|
||||||
|
auto csgrange = range(csgmesh);
|
||||||
|
if (csg::is_all_positive(csgrange)) {
|
||||||
|
mesh = TriangleMesh{csg::csgmesh_merge_positive_parts(csgrange)};
|
||||||
|
} else if (std::get<2>(csg::check_csgmesh_booleans(csgrange)) == csgrange.end()) {
|
||||||
|
try {
|
||||||
|
auto cgalm = csg::perform_csgmesh_booleans(csgrange);
|
||||||
|
mesh = MeshBoolean::cgal::cgal_to_triangle_mesh(*cgalm);
|
||||||
|
} catch (...) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mesh.empty()) {
|
||||||
|
get_notification_manager()->push_plater_error_notification(
|
||||||
|
_u8L("Unable to perform boolean operation on model meshes. "
|
||||||
|
"Only positive parts will be exported."));
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
auto mesh_to_export_sla = [&, this](const ModelObject& mo, int instance_id) {
|
||||||
|
TriangleMesh mesh;
|
||||||
|
|
||||||
|
const SLAPrintObject *object = this->p->sla_print.get_print_object_by_model_object_id(mo.id());
|
||||||
|
|
||||||
|
if (auto m = object->get_mesh_to_print(); m.empty())
|
||||||
|
mesh = combine_mesh_fff(mo, instance_id, [this](const std::string& msg) {return get_notification_manager()->push_plater_error_notification(msg); });
|
||||||
|
else {
|
||||||
|
const Transform3d mesh_trafo_inv = object->trafo().inverse();
|
||||||
|
const bool is_left_handed = object->is_left_handed();
|
||||||
|
|
||||||
|
auto pad_mesh = extended? object->pad_mesh() : TriangleMesh{};
|
||||||
|
pad_mesh.transform(mesh_trafo_inv);
|
||||||
|
|
||||||
|
auto supports_mesh = extended ? object->support_mesh() : TriangleMesh{};
|
||||||
|
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(object->model_object()->instances.begin(), object->model_object()->instances.end(),
|
||||||
|
[&obj_instance](const ModelInstance *mi) { return mi->id() == obj_instance.instance_id; });
|
||||||
|
assert(it != object->model_object()->instances.end());
|
||||||
|
|
||||||
|
if (it != object->model_object()->instances.end()) {
|
||||||
|
const bool one_inst_only = selection_only && ! selection.is_single_full_object();
|
||||||
|
|
||||||
|
const int instance_idx = it - object->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 (!pad_mesh.empty()) {
|
||||||
|
TriangleMesh inst_pad_mesh = pad_mesh;
|
||||||
|
inst_pad_mesh.transform(inst_transform, is_left_handed);
|
||||||
|
inst_mesh.merge(inst_pad_mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!supports_mesh.empty()) {
|
||||||
|
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_print();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::function<TriangleMesh(const ModelObject& mo, int instance_id)>
|
||||||
|
mesh_to_export;
|
||||||
|
|
||||||
|
if (p->printer_technology == ptFFF)
|
||||||
|
#if EXPORT_WITH_BOOLEAN
|
||||||
|
mesh_to_export = [this](const ModelObject& mo, int instance_id) {return Plater::combine_mesh_fff(mo, instance_id,
|
||||||
|
[this](const std::string& msg) {return get_notification_manager()->push_plater_error_notification(msg); }); };
|
||||||
|
#else
|
||||||
|
mesh_to_export = mesh_to_export_fff_no_boolean;
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
mesh_to_export = mesh_to_export_sla;
|
||||||
|
|
||||||
|
auto get_save_file = [](std::string const & dir, std::string const & name) {
|
||||||
|
auto path = dir + name + ".drc";
|
||||||
|
int n = 1;
|
||||||
|
while (boost::filesystem::exists(path))
|
||||||
|
path = dir + name + "(" + std::to_string(n++) + ").drc";
|
||||||
|
return path;
|
||||||
|
};
|
||||||
|
|
||||||
|
TriangleMesh mesh;
|
||||||
|
if (selection_only) {
|
||||||
|
if (selection.is_single_full_object()) {
|
||||||
|
const auto obj_idx = selection.get_object_idx();
|
||||||
|
const ModelObject* model_object = p->model.objects[obj_idx];
|
||||||
|
if (selection.get_mode() == Selection::Instance)
|
||||||
|
mesh = mesh_to_export(*model_object, (model_object->instances.size() > 1) ? -1 : selection.get_instance_idx());
|
||||||
|
else {
|
||||||
|
const GLVolume* volume = selection.get_first_volume();
|
||||||
|
mesh = model_object->volumes[volume->volume_idx()]->mesh();
|
||||||
|
mesh.transform(volume->get_volume_transformation().get_matrix(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (model_object->instances.size() == 1) mesh.translate(-model_object->origin_translation.cast<float>());
|
||||||
|
}
|
||||||
|
else if (selection.is_multiple_full_object() && !multi_drcs) {
|
||||||
|
const std::set<std::pair<int, int>>& instances_idxs = p->get_selection().get_selected_object_instances();
|
||||||
|
for (const std::pair<int, int>& i : instances_idxs) {
|
||||||
|
ModelObject* object = p->model.objects[i.first];
|
||||||
|
mesh.merge(mesh_to_export(*object, i.second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (selection.is_multiple_full_object() && multi_drcs) {
|
||||||
|
const std::set<std::pair<int, int>> &instances_idxs = p->get_selection().get_selected_object_instances();
|
||||||
|
for (const std::pair<int, int> &i : instances_idxs) {
|
||||||
|
ModelObject *object = p->model.objects[i.first];
|
||||||
|
auto mesh = mesh_to_export(*object, i.second);
|
||||||
|
mesh.translate(-object->origin_translation.cast<float>());
|
||||||
|
|
||||||
|
Slic3r::store_drc(get_save_file(path_u8, object->name).c_str(), &mesh, bits, speed);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!multi_drcs) {
|
||||||
|
for (const ModelObject* o : p->model.objects) {
|
||||||
|
mesh.merge(mesh_to_export(*o, -1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const ModelObject* o : p->model.objects) {
|
||||||
|
auto mesh = mesh_to_export(*o, -1);
|
||||||
|
mesh.translate(-o->origin_translation.cast<float>());
|
||||||
|
Slic3r::store_drc(get_save_file(path_u8, o->name).c_str(), &mesh, bits, speed);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Slic3r::store_drc(path_u8.c_str(), &mesh, bits, speed);
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
std::string get_file_name(const std::string &file_path)
|
std::string get_file_name(const std::string &file_path)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -414,6 +414,7 @@ public:
|
|||||||
void export_core_3mf();
|
void export_core_3mf();
|
||||||
static TriangleMesh combine_mesh_fff(const ModelObject& mo, int instance_id, std::function<void(const std::string&)> notify_func = {});
|
static TriangleMesh combine_mesh_fff(const ModelObject& mo, int instance_id, std::function<void(const std::string&)> notify_func = {});
|
||||||
void export_stl(bool extended = false, bool selection_only = false, bool multi_stls = false);
|
void export_stl(bool extended = false, bool selection_only = false, bool multi_stls = false);
|
||||||
|
void export_drc(bool extended = false, bool selection_only = false, bool multi_drcs = false);
|
||||||
//BBS: remove amf
|
//BBS: remove amf
|
||||||
//void export_amf();
|
//void export_amf();
|
||||||
//BBS add extra param for exporting 3mf silence
|
//BBS add extra param for exporting 3mf silence
|
||||||
|
|||||||
Reference in New Issue
Block a user