mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-01 04:51:59 +08:00
Cut by Grid also in GUI
This commit is contained in:
parent
54f782c121
commit
5cbdb7865d
@ -618,7 +618,7 @@ sub load_model_objects {
|
||||
$o->repair;
|
||||
|
||||
push @{ $self->{objects} }, Slic3r::GUI::Plater::Object->new(
|
||||
name => basename($model_object->input_file),
|
||||
name => $model_object->name || basename($model_object->input_file),
|
||||
);
|
||||
push @obj_idx, $#{ $self->{objects} };
|
||||
|
||||
@ -1649,9 +1649,14 @@ sub object_cut_dialog {
|
||||
return unless $dlg->ShowModal == wxID_OK;
|
||||
|
||||
if (my @new_objects = $dlg->NewModelObjects) {
|
||||
my $process_dialog = Wx::ProgressDialog->new('Loading…', "Loading new objects…", 100, $self, 0);
|
||||
$process_dialog->Pulse;
|
||||
|
||||
$self->remove($obj_idx);
|
||||
$self->load_model_objects(grep defined($_), @new_objects);
|
||||
$self->arrange;
|
||||
$self->arrange if @new_objects <= 2; # don't arrange for grid cuts
|
||||
|
||||
$process_dialog->Destroy;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,8 @@ use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
use POSIX qw(ceil);
|
||||
use Scalar::Util qw(looks_like_number);
|
||||
use Slic3r::Geometry qw(PI X Y Z);
|
||||
use Wx qw(wxTheApp :dialog :id :misc :sizer wxTAB_TRAVERSAL);
|
||||
use Wx::Event qw(EVT_CLOSE EVT_BUTTON);
|
||||
@ -109,8 +111,14 @@ sub new {
|
||||
));
|
||||
{
|
||||
my $cut_button_sizer = Wx::BoxSizer->new(wxVERTICAL);
|
||||
|
||||
$self->{btn_cut} = Wx::Button->new($self, -1, "Perform cut", wxDefaultPosition, wxDefaultSize);
|
||||
$self->{btn_cut}->SetDefault;
|
||||
$cut_button_sizer->Add($self->{btn_cut}, 0, wxALIGN_RIGHT | wxALL, 10);
|
||||
|
||||
$self->{btn_cut_grid} = Wx::Button->new($self, -1, "Cut by grid…", wxDefaultPosition, wxDefaultSize);
|
||||
$cut_button_sizer->Add($self->{btn_cut_grid}, 0, wxALIGN_RIGHT | wxALL, 10);
|
||||
|
||||
$optgroup->append_line(Slic3r::GUI::OptionsGroup::Line->new(
|
||||
sizer => $cut_button_sizer,
|
||||
));
|
||||
@ -144,14 +152,14 @@ sub new {
|
||||
$self->_perform_cut() unless $self->{mesh_cut_valid};
|
||||
|
||||
# Adjust position / orientation of the split object halves.
|
||||
if ($self->{new_model_objects}{lower}) {
|
||||
if (my $lower = $self->{new_model_objects}[0]) {
|
||||
if ($self->{cut_options}{rotate_lower} && $self->{cut_options}{axis} == Z) {
|
||||
$self->{new_model_objects}{lower}->rotate(PI, X);
|
||||
$lower->rotate(PI, X);
|
||||
}
|
||||
$self->{new_model_objects}{lower}->center_around_origin; # align to Z = 0
|
||||
$lower->center_around_origin; # align to Z = 0
|
||||
}
|
||||
if ($self->{new_model_objects}{upper}) {
|
||||
$self->{new_model_objects}{upper}->center_around_origin; # align to Z = 0
|
||||
if (my $upper = $self->{new_model_objects}[1]) {
|
||||
$upper->center_around_origin; # align to Z = 0
|
||||
}
|
||||
|
||||
# Note that the window was already closed, so a pending update will not be executed.
|
||||
@ -160,6 +168,48 @@ sub new {
|
||||
$self->Destroy();
|
||||
});
|
||||
|
||||
EVT_BUTTON($self, $self->{btn_cut_grid}, sub {
|
||||
my $grid_x = Wx::GetTextFromUser("Enter the width of the desired tiles along the X axis:",
|
||||
"Cut by Grid", 100, $self);
|
||||
return if !looks_like_number($grid_x) || $grid_x <= 0;
|
||||
|
||||
my $grid_y = Wx::GetTextFromUser("Enter the width of the desired tiles along the Y axis:",
|
||||
"Cut by Grid", 100, $self);
|
||||
return if !looks_like_number($grid_y) || $grid_y <= 0;
|
||||
|
||||
my $process_dialog = Wx::ProgressDialog->new('Cutting…', "Cutting model by grid…", 100, $self, 0);
|
||||
$process_dialog->Pulse;
|
||||
|
||||
my $meshes = $self->{model_object}->mesh->cut_by_grid(Slic3r::Pointf->new($grid_x, $grid_y));
|
||||
$self->{new_model_objects} = [];
|
||||
|
||||
my $bb = $self->{model_object}->bounding_box;
|
||||
$self->{new_model} = my $model = Slic3r::Model->new;
|
||||
for my $i (0..$#$meshes) {
|
||||
push @{$self->{new_model_objects}}, my $o = $model->add_object(
|
||||
name => sprintf('%s (%d)', $self->{model_object}->name, $i+1),
|
||||
);
|
||||
my $v = $o->add_volume(
|
||||
mesh => $meshes->[$i],
|
||||
name => $o->name,
|
||||
);
|
||||
my $min = $v->mesh->bounding_box->min_point->clone;
|
||||
$o->center_around_origin;
|
||||
my $i = $o->add_instance(offset => Slic3r::Pointf->new(@{$min}[X,Y]));
|
||||
$i->offset->translate(
|
||||
5 * ceil(($i->offset->x - $bb->center->x) / $grid_x),
|
||||
5 * ceil(($i->offset->y - $bb->center->y) / $grid_y),
|
||||
);
|
||||
}
|
||||
|
||||
$process_dialog->Destroy;
|
||||
|
||||
# Note that the window was already closed, so a pending update will not be executed.
|
||||
$self->{already_closed} = 1;
|
||||
$self->EndModal(wxID_OK);
|
||||
$self->Destroy();
|
||||
});
|
||||
|
||||
EVT_CLOSE($self, sub {
|
||||
# Note that the window was already closed, so a pending update will not be executed.
|
||||
$self->{already_closed} = 1;
|
||||
@ -208,12 +258,12 @@ sub _perform_cut
|
||||
my ($new_model) = $self->{model_object}->cut($self->{cut_options}{axis}, $z);
|
||||
my ($upper_object, $lower_object) = @{$new_model->objects};
|
||||
$self->{new_model} = $new_model;
|
||||
$self->{new_model_objects} = {};
|
||||
$self->{new_model_objects} = [];
|
||||
if ($self->{cut_options}{keep_upper} && $upper_object->volumes_count > 0) {
|
||||
$self->{new_model_objects}{upper} = $upper_object;
|
||||
$self->{new_model_objects}[1] = $upper_object;
|
||||
}
|
||||
if ($self->{cut_options}{keep_lower} && $lower_object->volumes_count > 0) {
|
||||
$self->{new_model_objects}{lower} = $lower_object;
|
||||
$self->{new_model_objects}[0] = $lower_object;
|
||||
}
|
||||
|
||||
$self->{mesh_cut_valid} = 1;
|
||||
@ -241,7 +291,7 @@ sub _update {
|
||||
# get volumes to render
|
||||
my @objects = ();
|
||||
if ($life_preview_active) {
|
||||
push @objects, values %{$self->{new_model_objects}};
|
||||
push @objects, grep defined, @{$self->{new_model_objects}};
|
||||
} else {
|
||||
push @objects, $self->{model_object};
|
||||
}
|
||||
@ -311,7 +361,7 @@ sub _update {
|
||||
|
||||
sub NewModelObjects {
|
||||
my ($self) = @_;
|
||||
return values %{ $self->{new_model_objects} };
|
||||
return grep defined, @{ $self->{new_model_objects} };
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -160,41 +160,12 @@ main(const int argc, const char **argv)
|
||||
TriangleMesh mesh = model->mesh();
|
||||
mesh.repair();
|
||||
|
||||
const BoundingBoxf3 bb = mesh.bounding_box();
|
||||
mesh.translate(0, 0, -bb.min.z);
|
||||
|
||||
const Sizef3 size = bb.size();
|
||||
const size_t x_parts = ceil((size.x - EPSILON)/cli_config.cut_grid.value.x);
|
||||
const size_t y_parts = ceil((size.y - EPSILON)/cli_config.cut_grid.value.y);
|
||||
|
||||
for (size_t i = 1; i <= x_parts; ++i) {
|
||||
TriangleMesh curr;
|
||||
if (i == x_parts) {
|
||||
curr = mesh;
|
||||
} else {
|
||||
TriangleMesh next;
|
||||
TriangleMeshSlicer<X>(&mesh).cut(bb.min.x + (cli_config.cut_grid.value.x * i), &next, &curr);
|
||||
curr.repair();
|
||||
next.repair();
|
||||
mesh = next;
|
||||
}
|
||||
|
||||
for (size_t j = 1; j <= y_parts; ++j) {
|
||||
TriangleMesh tile;
|
||||
if (j == y_parts) {
|
||||
tile = curr;
|
||||
} else {
|
||||
TriangleMesh next;
|
||||
TriangleMeshSlicer<Y>(&curr).cut(bb.min.y + (cli_config.cut_grid.value.y * j), &next, &tile);
|
||||
tile.repair();
|
||||
next.repair();
|
||||
curr = next;
|
||||
}
|
||||
|
||||
TriangleMeshPtrs meshes = mesh.cut_by_grid(cli_config.cut_grid.value);
|
||||
for (TriangleMeshPtrs::iterator m = meshes.begin(); m != meshes.end(); ++m) {
|
||||
std::ostringstream ss;
|
||||
ss << model->objects.front()->input_file << "_" << i << "_" << j << ".stl";
|
||||
IO::STL::write(tile, ss.str());
|
||||
}
|
||||
ss << model->objects.front()->input_file << "_" << (m - meshes.begin()) << ".stl";
|
||||
IO::STL::write(**m, ss.str());
|
||||
delete *m;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "error: command not supported" << std::endl;
|
||||
|
@ -395,6 +395,47 @@ TriangleMesh::split() const
|
||||
return meshes;
|
||||
}
|
||||
|
||||
TriangleMeshPtrs
|
||||
TriangleMesh::cut_by_grid(const Pointf &grid) const
|
||||
{
|
||||
TriangleMesh mesh = *this;
|
||||
const BoundingBoxf3 bb = mesh.bounding_box();
|
||||
const Sizef3 size = bb.size();
|
||||
const size_t x_parts = ceil((size.x - EPSILON)/grid.x);
|
||||
const size_t y_parts = ceil((size.y - EPSILON)/grid.y);
|
||||
|
||||
TriangleMeshPtrs meshes;
|
||||
for (size_t i = 1; i <= x_parts; ++i) {
|
||||
TriangleMesh curr;
|
||||
if (i == x_parts) {
|
||||
curr = mesh;
|
||||
} else {
|
||||
TriangleMesh next;
|
||||
TriangleMeshSlicer<X>(&mesh).cut(bb.min.x + (grid.x * i), &next, &curr);
|
||||
curr.repair();
|
||||
next.repair();
|
||||
mesh = next;
|
||||
}
|
||||
|
||||
for (size_t j = 1; j <= y_parts; ++j) {
|
||||
TriangleMesh* tile;
|
||||
if (j == y_parts) {
|
||||
tile = new TriangleMesh(curr);
|
||||
} else {
|
||||
TriangleMesh next;
|
||||
tile = new TriangleMesh;
|
||||
TriangleMeshSlicer<Y>(&curr).cut(bb.min.y + (grid.y * j), &next, tile);
|
||||
tile->repair();
|
||||
next.repair();
|
||||
curr = next;
|
||||
}
|
||||
|
||||
meshes.push_back(tile);
|
||||
}
|
||||
}
|
||||
return meshes;
|
||||
}
|
||||
|
||||
void
|
||||
TriangleMesh::merge(const TriangleMesh &mesh)
|
||||
{
|
||||
|
@ -49,6 +49,7 @@ class TriangleMesh
|
||||
void center_around_origin();
|
||||
void rotate(double angle, Point* center);
|
||||
TriangleMeshPtrs split() const;
|
||||
TriangleMeshPtrs cut_by_grid(const Pointf &grid) const;
|
||||
void merge(const TriangleMesh &mesh);
|
||||
ExPolygons horizontal_projection() const;
|
||||
Polygon convex_hull();
|
||||
@ -112,8 +113,6 @@ class TriangleMeshSlicer
|
||||
|
||||
void cut(float z, TriangleMesh* upper, TriangleMesh* lower) const;
|
||||
|
||||
static void cut(TriangleMesh* mesh, Axis axis, float z, TriangleMesh* upper, TriangleMesh* lower);
|
||||
|
||||
private:
|
||||
typedef std::vector< std::vector<int> > t_facets_edges;
|
||||
t_facets_edges facets_edges;
|
||||
|
@ -30,6 +30,8 @@
|
||||
void align_to_origin();
|
||||
void rotate(double angle, Point* center);
|
||||
TriangleMeshPtrs split();
|
||||
TriangleMeshPtrs cut_by_grid(Pointf* grid)
|
||||
%code{% RETVAL = THIS->cut_by_grid(*grid); %};
|
||||
void merge(TriangleMesh* mesh)
|
||||
%code{% THIS->merge(*mesh); %};
|
||||
ExPolygons horizontal_projection();
|
||||
|
Loading…
x
Reference in New Issue
Block a user