New feature: Splitting an object into a multi-part volume.

This commit is contained in:
bubnikv 2017-06-15 15:38:15 +02:00
parent a1f6403463
commit b724d789fd
6 changed files with 95 additions and 30 deletions

View File

@ -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) = @_;

View File

@ -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

View File

@ -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.

View File

@ -78,28 +78,11 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Point3>& 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<int> facet_queue;
std::deque<int> facets;

View File

@ -24,7 +24,7 @@ public:
TriangleMesh(const Pointf3s &points, const std::vector<Point3> &facets);
TriangleMesh(const TriangleMesh &other);
TriangleMesh(TriangleMesh &&other);
TriangleMesh& operator= (TriangleMesh other);
TriangleMesh& operator=(const TriangleMesh &other);
TriangleMesh& operator=(TriangleMesh &&other);
void swap(TriangleMesh &other);
~TriangleMesh();

View File

@ -298,6 +298,8 @@ ModelMaterial::attributes()
void set_modifier(bool modifier)
%code%{ THIS->modifier = modifier; %};
size_t split();
ModelMaterial* assign_unique_material();
};