mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 13:25:56 +08:00
New --cut-grid command for cutting a mesh in multiple tiles according to a XY grid
This commit is contained in:
parent
a778cd9820
commit
27e456039c
50
slic3r.pl
50
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);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#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<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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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.";
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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<Z> mslicer(THIS);
|
||||
mslicer.cut(z, upper, lower);
|
||||
if (axis == X) {
|
||||
TriangleMeshSlicer<X>(THIS).cut(z, upper, lower);
|
||||
} else if (axis == Y) {
|
||||
TriangleMeshSlicer<Y>(THIS).cut(z, upper, lower);
|
||||
} else {
|
||||
TriangleMeshSlicer<Z>(THIS).cut(z, upper, lower);
|
||||
}
|
||||
|
||||
std::vector<double>
|
||||
TriangleMesh::bb3()
|
||||
|
Loading…
x
Reference in New Issue
Block a user