diff --git a/slic3r.pl b/slic3r.pl index 35773ac4b..9f3ca42fe 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -12,9 +12,9 @@ BEGIN { use File::Basename qw(basename); use Getopt::Long qw(:config no_auto_abbrev); use List::Util qw(first); -use POSIX qw(setlocale LC_NUMERIC); +use POSIX qw(setlocale LC_NUMERIC ceil); use Slic3r; -use Slic3r::Geometry qw(deg2rad); +use Slic3r::Geometry qw(epsilon X Y Z deg2rad); use Time::HiRes qw(gettimeofday tv_interval); $|++; binmode STDOUT, ':utf8'; @@ -42,6 +42,7 @@ my %cli_options = (); 'merge|m' => \$opt{merge}, 'repair' => \$opt{repair}, 'cut=f' => \$opt{cut}, + 'cut-grid=s' => \$opt{cut_grid}, 'split' => \$opt{split}, 'info' => \$opt{info}, @@ -150,7 +151,7 @@ if (@ARGV) { # slicing from command line $mesh->translate(0, 0, -$mesh->bounding_box->z_min); my $upper = Slic3r::TriangleMesh->new; my $lower = Slic3r::TriangleMesh->new; - $mesh->cut($opt{cut}, $upper, $lower); + $mesh->cut(Z, $opt{cut}, $upper, $lower); $upper->repair; $lower->repair; $upper->write_ascii("${file}_upper.stl") @@ -161,6 +162,49 @@ if (@ARGV) { # slicing from command line exit; } + if ($opt{cut_grid}) { + my ($grid_x, $grid_y) = split /[,x]/, $opt{cut_grid}, 2; + foreach my $file (@ARGV) { + $file = Slic3r::decode_path($file); + my $model = Slic3r::Model->read_from_file($file); + $model->add_default_instances; + my $mesh = $model->mesh; + my $bb = $mesh->bounding_box; + $mesh->translate(0, 0, -$bb->z_min); + + my $x_parts = ceil(($bb->size->x - epsilon)/$grid_x); + my $y_parts = ceil(($bb->size->y - epsilon)/$grid_y); #-- + + for my $i (1..$x_parts) { + my $this = Slic3r::TriangleMesh->new; + if ($i == $x_parts) { + $this = $mesh; + } else { + my $next = Slic3r::TriangleMesh->new; + $mesh->cut(X, $bb->x_min + ($grid_x * $i), $next, $this); + $this->repair; + $next->repair; + $mesh = $next; + } + + for my $j (1..$y_parts) { + my $tile = Slic3r::TriangleMesh->new; + if ($j == $y_parts) { + $tile = $this; + } else { + my $next = Slic3r::TriangleMesh->new; + $this->cut(Y, $bb->y_min + ($grid_y * $j), $next, $tile); + $tile->repair; + $next->repair; + $this = $next; + } + $tile->write_ascii("${file}_${i}_${j}.stl"); + } + } + } + exit; + } + if ($opt{split}) { foreach my $file (@ARGV) { $file = Slic3r::decode_path($file); diff --git a/src/slic3r.cpp b/src/slic3r.cpp index f97177187..725c20de6 100644 --- a/src/slic3r.cpp +++ b/src/slic3r.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "boost/filesystem.hpp" using namespace Slic3r; @@ -152,6 +153,46 @@ main(const int argc, const char **argv) IO::STL::write(m, lower.input_file + "_lower.stl"); } } + } else if (cli_config.cut_grid.value.x > 0 && cli_config.cut_grid.value.y > 0) { + 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(&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(&curr).cut(bb.min.y + (cli_config.cut_grid.value.y * j), &next, &tile); + tile.repair(); + next.repair(); + curr = next; + } + + std::ostringstream ss; + ss << model->objects.front()->input_file << "_" << i << "_" << j << ".stl"; + IO::STL::write(tile, ss.str()); + } + } } else { std::cerr << "error: command not supported" << std::endl; return 1; diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 6ffdfefe6..c6e56ee91 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -1404,6 +1404,12 @@ CLIConfigDef::CLIConfigDef() def->cli = "cut"; def->default_value = new ConfigOptionFloat(0); + def = this->add("cut_grid", coFloat); + def->label = "Cut"; + def->tooltip = "Cut model in the XY plane into tiles of the specified max size."; + def->cli = "cut-grid"; + def->default_value = new ConfigOptionPoint(); + def = this->add("cut_x", coFloat); def->label = "Cut"; def->tooltip = "Cut model at the given X."; diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index df2c33af3..2c7fa2d58 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -590,6 +590,7 @@ class CLIConfig { public: ConfigOptionFloat cut; + ConfigOptionPoint cut_grid; ConfigOptionFloat cut_x; ConfigOptionFloat cut_y; ConfigOptionBool export_obj; @@ -610,6 +611,7 @@ class CLIConfig virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) { OPT_PTR(cut); + OPT_PTR(cut_grid); OPT_PTR(cut_x); OPT_PTR(cut_y); OPT_PTR(export_obj); diff --git a/xs/t/01_trianglemesh.t b/xs/t/01_trianglemesh.t index fd57cf805..377d4a022 100644 --- a/xs/t/01_trianglemesh.t +++ b/xs/t/01_trianglemesh.t @@ -6,6 +6,8 @@ use warnings; use Slic3r::XS; use Test::More tests => 49; +use constant Z => 2; + is Slic3r::TriangleMesh::hello_world(), 'Hello world!', 'hello world'; @@ -117,7 +119,7 @@ my $cube = { { my $upper = Slic3r::TriangleMesh->new; my $lower = Slic3r::TriangleMesh->new; - $m->cut(0, $upper, $lower); + $m->cut(Z, 0, $upper, $lower); $upper->repair; $lower->repair; is $upper->facets_count, 12, 'upper mesh has all facets except those belonging to the slicing plane'; is $lower->facets_count, 0, 'lower mesh has no facets'; @@ -125,7 +127,7 @@ my $cube = { { my $upper = Slic3r::TriangleMesh->new; my $lower = Slic3r::TriangleMesh->new; - $m->cut(10, $upper, $lower); + $m->cut(Z, 10, $upper, $lower); #$upper->repair; $lower->repair; # we expect: # 2 facets on external horizontal surfaces diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp index ec76d1aff..1640322df 100644 --- a/xs/xsp/TriangleMesh.xsp +++ b/xs/xsp/TriangleMesh.xsp @@ -221,13 +221,19 @@ TriangleMesh::slice_at(axis, z) RETVAL void -TriangleMesh::cut(z, upper, lower) +TriangleMesh::cut(axis, z, upper, lower) + Axis axis float z; TriangleMesh* upper; TriangleMesh* lower; CODE: - TriangleMeshSlicer mslicer(THIS); - mslicer.cut(z, upper, lower); + if (axis == X) { + TriangleMeshSlicer(THIS).cut(z, upper, lower); + } else if (axis == Y) { + TriangleMeshSlicer(THIS).cut(z, upper, lower); + } else { + TriangleMeshSlicer(THIS).cut(z, upper, lower); + } std::vector TriangleMesh::bb3()