From b724d789fd6769fdf868a987ca5573bb0bf23eaa Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 15 Jun 2017 15:38:15 +0200 Subject: [PATCH] New feature: Splitting an object into a multi-part volume. --- lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm | 30 +++++++++++-- xs/src/libslic3r/Model.cpp | 30 +++++++++++++ xs/src/libslic3r/Model.hpp | 7 +++ xs/src/libslic3r/TriangleMesh.cpp | 52 ++++++++++++----------- xs/src/libslic3r/TriangleMesh.hpp | 4 +- xs/xsp/Model.xsp | 2 + 6 files changed, 95 insertions(+), 30 deletions(-) diff --git a/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm b/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm index f4f610d6a..a362f7ad1 100644 --- a/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm +++ b/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm @@ -56,13 +56,15 @@ sub new { $self->{btn_load_modifier} = Wx::Button->new($self, -1, "Load modifier…", wxDefaultPosition, wxDefaultSize, wxBU_LEFT); $self->{btn_load_lambda_modifier} = Wx::Button->new($self, -1, "Load generic…", wxDefaultPosition, wxDefaultSize, wxBU_LEFT); $self->{btn_delete} = Wx::Button->new($self, -1, "Delete part", wxDefaultPosition, wxDefaultSize, wxBU_LEFT); - $self->{btn_move_up} = Wx::Button->new($self, -1, $Slic3r::GUI::have_button_icons ? "" : "Up", wxDefaultPosition, wxDefaultSize, wxBU_LEFT); - $self->{btn_move_down} = Wx::Button->new($self, -1, $Slic3r::GUI::have_button_icons ? "" : "Down", wxDefaultPosition, wxDefaultSize, wxBU_LEFT); + $self->{btn_split} = Wx::Button->new($self, -1, "Split part", wxDefaultPosition, wxDefaultSize, wxBU_LEFT); + $self->{btn_move_up} = Wx::Button->new($self, -1, $Slic3r::GUI::have_button_icons ? "" : "Up", wxDefaultPosition, [40, -1], wxBU_LEFT); + $self->{btn_move_down} = Wx::Button->new($self, -1, $Slic3r::GUI::have_button_icons ? "" : "Down", wxDefaultPosition, [40, -1], wxBU_LEFT); if ($Slic3r::GUI::have_button_icons) { $self->{btn_load_part}->SetBitmap(Wx::Bitmap->new($Slic3r::var->("brick_add.png"), wxBITMAP_TYPE_PNG)); $self->{btn_load_modifier}->SetBitmap(Wx::Bitmap->new($Slic3r::var->("brick_add.png"), wxBITMAP_TYPE_PNG)); $self->{btn_load_lambda_modifier}->SetBitmap(Wx::Bitmap->new($Slic3r::var->("brick_add.png"), wxBITMAP_TYPE_PNG)); $self->{btn_delete}->SetBitmap(Wx::Bitmap->new($Slic3r::var->("brick_delete.png"), wxBITMAP_TYPE_PNG)); + $self->{btn_split}->SetBitmap(Wx::Bitmap->new($Slic3r::var->("shape_ungroup.png"), wxBITMAP_TYPE_PNG)); $self->{btn_move_up}->SetBitmap(Wx::Bitmap->new($Slic3r::var->("bullet_arrow_up.png"), wxBITMAP_TYPE_PNG)); $self->{btn_move_down}->SetBitmap(Wx::Bitmap->new($Slic3r::var->("bullet_arrow_down.png"), wxBITMAP_TYPE_PNG)); } @@ -73,12 +75,18 @@ sub new { $buttons_sizer->Add($self->{btn_load_modifier}, 0, wxEXPAND | wxBOTTOM | wxRIGHT, 5); $buttons_sizer->Add($self->{btn_load_lambda_modifier}, 0, wxEXPAND | wxBOTTOM, 5); $buttons_sizer->Add($self->{btn_delete}, 0, wxEXPAND | wxRIGHT, 5); - $buttons_sizer->Add($self->{btn_move_up}, 0, wxEXPAND | wxRIGHT, 5); - $buttons_sizer->Add($self->{btn_move_down}, 0, wxEXPAND, 5); + $buttons_sizer->Add($self->{btn_split}, 0, wxEXPAND | wxRIGHT, 5); + { + my $up_down_sizer = Wx::GridSizer->new(1, 2); + $up_down_sizer->Add($self->{btn_move_up}, 0, wxEXPAND | wxRIGHT, 5); + $up_down_sizer->Add($self->{btn_move_down}, 0, wxEXPAND, 5); + $buttons_sizer->Add($up_down_sizer, 0, wxEXPAND, 5); + } $self->{btn_load_part}->SetFont($Slic3r::GUI::small_font); $self->{btn_load_modifier}->SetFont($Slic3r::GUI::small_font); $self->{btn_load_lambda_modifier}->SetFont($Slic3r::GUI::small_font); $self->{btn_delete}->SetFont($Slic3r::GUI::small_font); + $self->{btn_split}->SetFont($Slic3r::GUI::small_font); $self->{btn_move_up}->SetFont($Slic3r::GUI::small_font); $self->{btn_move_down}->SetFont($Slic3r::GUI::small_font); @@ -182,6 +190,7 @@ sub new { EVT_BUTTON($self, $self->{btn_load_modifier}, sub { $self->on_btn_load(1) }); EVT_BUTTON($self, $self->{btn_load_lambda_modifier}, sub { $self->on_btn_lambda(1) }); EVT_BUTTON($self, $self->{btn_delete}, \&on_btn_delete); + EVT_BUTTON($self, $self->{btn_split}, \&on_btn_split); EVT_BUTTON($self, $self->{btn_move_up}, \&on_btn_move_up); EVT_BUTTON($self, $self->{btn_move_down}, \&on_btn_move_down); @@ -279,6 +288,7 @@ sub selection_changed { $self->{canvas}->volumes->[ $itemData->{volume_id} ]->set_selected(1); } $self->{btn_delete}->Enable; + $self->{btn_split}->Enable; $self->{btn_move_up}->Enable if $itemData->{volume_id} > 0; $self->{btn_move_down}->Enable if $itemData->{volume_id} + 1 < $self->{model_object}->volumes_count; @@ -449,6 +459,18 @@ sub on_btn_delete { $self->_parts_changed; } +sub on_btn_split { + my ($self) = @_; + + my $itemData = $self->get_selection; + if ($itemData && $itemData->{type} eq 'volume') { + my $volume = $self->{model_object}->volumes->[$itemData->{volume_id}]; + $self->{parts_changed} = 1 if $volume->split > 1; + } + + $self->_parts_changed; +} + sub _parts_changed { my ($self) = @_; diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index 29a3786fd..6714966e7 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -685,6 +685,36 @@ ModelMaterial* ModelVolume::assign_unique_material() return model->add_material(this->_material_id); } +// Split this volume, append the result to the object owning this volume. +// Return the number of volumes created from this one. +// This is useful to assign different materials to different volumes of an object. +size_t ModelVolume::split() +{ + TriangleMeshPtrs meshptrs = this->mesh.split(); + if (meshptrs.size() <= 1) { + delete meshptrs.front(); + return 1; + } + + size_t idx = 0; + size_t ivolume = std::find(this->object->volumes.begin(), this->object->volumes.end(), this) - this->object->volumes.begin(); + std::string name = this->name; + for (TriangleMesh *mesh : meshptrs) { + mesh->repair(); + if (idx == 0) + this->mesh = std::move(*mesh); + else + this->object->volumes.insert(this->object->volumes.begin() + (++ ivolume), new ModelVolume(object, *this, std::move(*mesh))); + char str_idx[64]; + sprintf(str_idx, "_%d", idx + 1); + this->object->volumes[ivolume]->name = name + str_idx; + delete mesh; + ++ idx; + } + + return idx; +} + void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const { mesh->rotate_z(this->rotation); // rotate around mesh origin diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp index 3ab717a6f..5f3b0eb01 100644 --- a/xs/src/libslic3r/Model.hpp +++ b/xs/src/libslic3r/Model.hpp @@ -161,6 +161,10 @@ public: void material_id(t_model_material_id material_id); ModelMaterial* material() const; void set_material(t_model_material_id material_id, const ModelMaterial &material); + // Split this volume, append the result to the object owning this volume. + // Return the number of volumes created from this one. + // This is useful to assign different materials to different volumes of an object. + size_t split(); ModelMaterial* assign_unique_material(); @@ -174,6 +178,9 @@ private: ModelVolume(ModelObject *object, const ModelVolume &other) : name(other.name), mesh(other.mesh), config(other.config), modifier(other.modifier), object(object) { this->material_id(other.material_id()); } + ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) : + name(other.name), mesh(std::move(mesh)), config(other.config), modifier(other.modifier), object(object) + { this->material_id(other.material_id()); } }; // A single instance of a ModelObject. diff --git a/xs/src/libslic3r/TriangleMesh.cpp b/xs/src/libslic3r/TriangleMesh.cpp index 7e16944d8..ee1dc7315 100644 --- a/xs/src/libslic3r/TriangleMesh.cpp +++ b/xs/src/libslic3r/TriangleMesh.cpp @@ -78,28 +78,11 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector& fa stl_get_size(&stl); } -TriangleMesh::TriangleMesh(const TriangleMesh &other) - : stl(other.stl), repaired(other.repaired) +TriangleMesh::TriangleMesh(const TriangleMesh &other) : + repaired(false) { - this->stl.heads = NULL; - this->stl.tail = NULL; - this->stl.error = other.stl.error; - if (other.stl.facet_start != NULL) { - this->stl.facet_start = (stl_facet*)calloc(other.stl.stats.number_of_facets, sizeof(stl_facet)); - std::copy(other.stl.facet_start, other.stl.facet_start + other.stl.stats.number_of_facets, this->stl.facet_start); - } - if (other.stl.neighbors_start != NULL) { - this->stl.neighbors_start = (stl_neighbors*)calloc(other.stl.stats.number_of_facets, sizeof(stl_neighbors)); - std::copy(other.stl.neighbors_start, other.stl.neighbors_start + other.stl.stats.number_of_facets, this->stl.neighbors_start); - } - if (other.stl.v_indices != NULL) { - this->stl.v_indices = (v_indices_struct*)calloc(other.stl.stats.number_of_facets, sizeof(v_indices_struct)); - std::copy(other.stl.v_indices, other.stl.v_indices + other.stl.stats.number_of_facets, this->stl.v_indices); - } - if (other.stl.v_shared != NULL) { - this->stl.v_shared = (stl_vertex*)calloc(other.stl.stats.shared_vertices, sizeof(stl_vertex)); - std::copy(other.stl.v_shared, other.stl.v_shared + other.stl.stats.shared_vertices, this->stl.v_shared); - } + stl_initialize(&this->stl); + *this = other; } TriangleMesh::TriangleMesh(TriangleMesh &&other) : @@ -109,9 +92,30 @@ TriangleMesh::TriangleMesh(TriangleMesh &&other) : this->swap(other); } -TriangleMesh& TriangleMesh::operator= (TriangleMesh other) +TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other) { - this->swap(other); + stl_close(&this->stl); + this->stl = other.stl; + this->repaired = other.repaired; + this->stl.heads = nullptr; + this->stl.tail = nullptr; + this->stl.error = other.stl.error; + if (other.stl.facet_start != nullptr) { + this->stl.facet_start = (stl_facet*)calloc(other.stl.stats.number_of_facets, sizeof(stl_facet)); + std::copy(other.stl.facet_start, other.stl.facet_start + other.stl.stats.number_of_facets, this->stl.facet_start); + } + if (other.stl.neighbors_start != nullptr) { + this->stl.neighbors_start = (stl_neighbors*)calloc(other.stl.stats.number_of_facets, sizeof(stl_neighbors)); + std::copy(other.stl.neighbors_start, other.stl.neighbors_start + other.stl.stats.number_of_facets, this->stl.neighbors_start); + } + if (other.stl.v_indices != nullptr) { + this->stl.v_indices = (v_indices_struct*)calloc(other.stl.stats.number_of_facets, sizeof(v_indices_struct)); + std::copy(other.stl.v_indices, other.stl.v_indices + other.stl.stats.number_of_facets, this->stl.v_indices); + } + if (other.stl.v_shared != nullptr) { + this->stl.v_shared = (stl_vertex*)calloc(other.stl.stats.shared_vertices, sizeof(stl_vertex)); + std::copy(other.stl.v_shared, other.stl.v_shared + other.stl.stats.shared_vertices, this->stl.v_shared); + } return *this; } @@ -427,7 +431,7 @@ TriangleMesh::split() const if (!this->repaired) CONFESS("split() requires repair()"); // loop while we have remaining facets - while (1) { + for (;;) { // get the first facet std::queue facet_queue; std::deque facets; diff --git a/xs/src/libslic3r/TriangleMesh.hpp b/xs/src/libslic3r/TriangleMesh.hpp index 907b1f7e9..8072059cf 100644 --- a/xs/src/libslic3r/TriangleMesh.hpp +++ b/xs/src/libslic3r/TriangleMesh.hpp @@ -24,8 +24,8 @@ public: TriangleMesh(const Pointf3s &points, const std::vector &facets); TriangleMesh(const TriangleMesh &other); TriangleMesh(TriangleMesh &&other); - TriangleMesh& operator= (TriangleMesh other); - TriangleMesh& operator= (TriangleMesh &&other); + TriangleMesh& operator=(const TriangleMesh &other); + TriangleMesh& operator=(TriangleMesh &&other); void swap(TriangleMesh &other); ~TriangleMesh(); void ReadSTLFile(const char* input_file); diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index c38b45ed8..855d40d32 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -297,6 +297,8 @@ ModelMaterial::attributes() %code%{ RETVAL = THIS->modifier; %}; void set_modifier(bool modifier) %code%{ THIS->modifier = modifier; %}; + + size_t split(); ModelMaterial* assign_unique_material(); };