New feature: Splitting an object into a multi-part volume.
This commit is contained in:
parent
a1f6403463
commit
b724d789fd
@ -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) = @_;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -24,8 +24,8 @@ public:
|
||||
TriangleMesh(const Pointf3s &points, const std::vector<Point3> &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);
|
||||
|
@ -298,6 +298,8 @@ ModelMaterial::attributes()
|
||||
void set_modifier(bool modifier)
|
||||
%code%{ THIS->modifier = modifier; %};
|
||||
|
||||
size_t split();
|
||||
|
||||
ModelMaterial* assign_unique_material();
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user