New --cut feature
This commit is contained in:
parent
37c7b958d4
commit
fe1691c151
@ -98,6 +98,8 @@ The author of the Silk icon set is Mark James.
|
|||||||
|
|
||||||
Non-slicing actions (no G-code will be generated):
|
Non-slicing actions (no G-code will be generated):
|
||||||
--repair Repair given STL files and save them as <name>_fixed.obj
|
--repair Repair given STL files and save them as <name>_fixed.obj
|
||||||
|
--cut <z> Cut given input files at given Z (relative) and export
|
||||||
|
them as <name>_upper.stl and <name>_lower.stl
|
||||||
--info Output information about the supplied file(s) and exit
|
--info Output information about the supplied file(s) and exit
|
||||||
|
|
||||||
-j, --threads <num> Number of threads to use (1+, default: 2)
|
-j, --threads <num> Number of threads to use (1+, default: 2)
|
||||||
|
@ -25,13 +25,15 @@ sub read_file {
|
|||||||
|
|
||||||
sub write_file {
|
sub write_file {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($file, $model, %params) = @_;
|
my ($file, $mesh, %params) = @_;
|
||||||
|
|
||||||
|
$mesh = $mesh->mesh if $mesh->isa('Slic3r::Model');
|
||||||
|
|
||||||
my $path = Slic3r::encode_path($file);
|
my $path = Slic3r::encode_path($file);
|
||||||
|
|
||||||
$params{binary}
|
$params{binary}
|
||||||
? $model->mesh->write_binary($path)
|
? $mesh->write_binary($path)
|
||||||
: $model->mesh->write_ascii($path);
|
: $mesh->write_ascii($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -191,6 +191,21 @@ sub has_objects_with_no_instances {
|
|||||||
return (first { !defined $_->instances } @{$self->objects}) ? 1 : 0;
|
return (first { !defined $_->instances } @{$self->objects}) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# makes sure all objects have at least one instance
|
||||||
|
sub add_default_instances {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
# apply a default position to all objects not having one
|
||||||
|
my $added = 0;
|
||||||
|
foreach my $object (@{$self->objects}) {
|
||||||
|
if (!defined $object->instances) {
|
||||||
|
$object->add_instance(offset => [0,0]);
|
||||||
|
$added = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $added;
|
||||||
|
}
|
||||||
|
|
||||||
# this returns the bounding box of the *transformed* instances
|
# this returns the bounding box of the *transformed* instances
|
||||||
sub bounding_box {
|
sub bounding_box {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
@ -46,13 +46,8 @@ sub set_model {
|
|||||||
# make method idempotent so that the object is reusable
|
# make method idempotent so that the object is reusable
|
||||||
$self->_print->delete_all_objects;
|
$self->_print->delete_all_objects;
|
||||||
|
|
||||||
my $need_arrange = $model->has_objects_with_no_instances;
|
# make sure all objects have at least one defined instance
|
||||||
if ($need_arrange) {
|
my $need_arrange = $model->add_default_instances;
|
||||||
# apply a default position to all objects not having one
|
|
||||||
foreach my $object (@{$model->objects}) {
|
|
||||||
$object->add_instance(offset => [0,0]) if !defined $object->instances;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# apply scaling and rotation supplied from command line if any
|
# apply scaling and rotation supplied from command line if any
|
||||||
foreach my $instance (map @{$_->instances}, @{$model->objects}) {
|
foreach my $instance (map @{$_->instances}, @{$model->objects}) {
|
||||||
|
22
slic3r.pl
22
slic3r.pl
@ -36,6 +36,7 @@ my %cli_options = ();
|
|||||||
'export-svg' => \$opt{export_svg},
|
'export-svg' => \$opt{export_svg},
|
||||||
'merge|m' => \$opt{merge},
|
'merge|m' => \$opt{merge},
|
||||||
'repair' => \$opt{repair},
|
'repair' => \$opt{repair},
|
||||||
|
'cut=f' => \$opt{cut},
|
||||||
'info' => \$opt{info},
|
'info' => \$opt{info},
|
||||||
|
|
||||||
'scale=f' => \$opt{scale},
|
'scale=f' => \$opt{scale},
|
||||||
@ -120,6 +121,25 @@ if (@ARGV) { # slicing from command line
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($opt{cut}) {
|
||||||
|
foreach my $file (@ARGV) {
|
||||||
|
my $model = Slic3r::Model->read_from_file($file);
|
||||||
|
$model->add_default_instances;
|
||||||
|
my $mesh = $model->mesh;
|
||||||
|
$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);
|
||||||
|
$upper->repair;
|
||||||
|
$lower->repair;
|
||||||
|
Slic3r::Format::STL->write_file("${file}_upper.stl", $upper, binary => 0)
|
||||||
|
if $upper->facets_count > 0;
|
||||||
|
Slic3r::Format::STL->write_file("${file}_lower.stl", $lower, binary => 0)
|
||||||
|
if $lower->facets_count > 0;
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
while (my $input_file = shift @ARGV) {
|
while (my $input_file = shift @ARGV) {
|
||||||
my $model;
|
my $model;
|
||||||
if ($opt{merge}) {
|
if ($opt{merge}) {
|
||||||
@ -203,6 +223,8 @@ Usage: slic3r.pl [ OPTIONS ] [ file.stl ] [ file2.stl ] ...
|
|||||||
|
|
||||||
Non-slicing actions (no G-code will be generated):
|
Non-slicing actions (no G-code will be generated):
|
||||||
--repair Repair given STL files and save them as <name>_fixed.obj
|
--repair Repair given STL files and save them as <name>_fixed.obj
|
||||||
|
--cut <z> Cut given input files at given Z (relative) and export
|
||||||
|
them as <name>_upper.stl and <name>_lower.stl
|
||||||
--info Output information about the supplied file(s) and exit
|
--info Output information about the supplied file(s) and exit
|
||||||
|
|
||||||
$j
|
$j
|
||||||
|
@ -755,7 +755,7 @@ TriangleMeshSlicer::make_expolygons(std::vector<IntersectionLine> &lines, ExPoly
|
|||||||
void
|
void
|
||||||
TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
||||||
{
|
{
|
||||||
std::vector<IntersectionLine> lines;
|
std::vector<IntersectionLine> upper_lines, lower_lines;
|
||||||
|
|
||||||
float scaled_z = scale_(z);
|
float scaled_z = scale_(z);
|
||||||
for (int facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; facet_idx++) {
|
for (int facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; facet_idx++) {
|
||||||
@ -766,13 +766,26 @@ TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
|||||||
float max_z = fmaxf(facet->vertex[0].z, fmaxf(facet->vertex[1].z, facet->vertex[2].z));
|
float max_z = fmaxf(facet->vertex[0].z, fmaxf(facet->vertex[1].z, facet->vertex[2].z));
|
||||||
|
|
||||||
// intersect facet with cutting plane
|
// intersect facet with cutting plane
|
||||||
|
std::vector<IntersectionLine> lines;
|
||||||
this->slice_facet(scaled_z, *facet, facet_idx, min_z, max_z, &lines);
|
this->slice_facet(scaled_z, *facet, facet_idx, min_z, max_z, &lines);
|
||||||
|
|
||||||
|
// save intersection lines for generating correct triangulations
|
||||||
|
for (std::vector<IntersectionLine>::iterator it = lines.begin(); it != lines.end(); ++it) {
|
||||||
|
if (it->edge_type == feTop) {
|
||||||
|
lower_lines.push_back(*it);
|
||||||
|
} else if (it->edge_type == feBottom) {
|
||||||
|
upper_lines.push_back(*it);
|
||||||
|
} else if (it->edge_type != feHorizontal) {
|
||||||
|
lower_lines.push_back(*it);
|
||||||
|
upper_lines.push_back(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (min_z > z || (min_z == z && max_z > min_z)) {
|
if (min_z > z || (min_z == z && max_z > min_z)) {
|
||||||
// facet is above the cut plane but does not belong to it
|
// facet is above the cut plane and does not belong to it
|
||||||
if (upper != NULL) stl_add_facet(&upper->stl, facet);
|
if (upper != NULL) stl_add_facet(&upper->stl, facet);
|
||||||
} else if (max_z < z || (max_z == z && max_z > min_z)) {
|
} else if (max_z < z || (max_z == z && max_z > min_z)) {
|
||||||
// facet is below the cut plane but does not belong to it
|
// facet is below the cut plane and does not belong to it
|
||||||
if (lower != NULL) stl_add_facet(&lower->stl, facet);
|
if (lower != NULL) stl_add_facet(&lower->stl, facet);
|
||||||
} else if (min_z < z && max_z > z) {
|
} else if (min_z < z && max_z > z) {
|
||||||
// facet is cut by the slicing plane
|
// facet is cut by the slicing plane
|
||||||
@ -803,18 +816,21 @@ TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
|||||||
|
|
||||||
// build the triangular facet
|
// build the triangular facet
|
||||||
stl_facet triangle;
|
stl_facet triangle;
|
||||||
|
triangle.normal = facet->normal;
|
||||||
triangle.vertex[0] = *v0;
|
triangle.vertex[0] = *v0;
|
||||||
triangle.vertex[1] = v0v1;
|
triangle.vertex[1] = v0v1;
|
||||||
triangle.vertex[2] = v2v0;
|
triangle.vertex[2] = v2v0;
|
||||||
|
|
||||||
// build the facets forming a quadrilateral on the other side
|
// build the facets forming a quadrilateral on the other side
|
||||||
stl_facet quadrilateral[2];
|
stl_facet quadrilateral[2];
|
||||||
|
quadrilateral[0].normal = facet->normal;
|
||||||
quadrilateral[0].vertex[0] = *v1;
|
quadrilateral[0].vertex[0] = *v1;
|
||||||
quadrilateral[0].vertex[1] = *v2;
|
quadrilateral[0].vertex[1] = *v2;
|
||||||
quadrilateral[0].vertex[2] = v0v1;
|
quadrilateral[0].vertex[2] = v0v1;
|
||||||
|
quadrilateral[1].normal = facet->normal;
|
||||||
quadrilateral[1].vertex[0] = *v2;
|
quadrilateral[1].vertex[0] = *v2;
|
||||||
quadrilateral[1].vertex[0] = v2v0;
|
quadrilateral[1].vertex[1] = v2v0;
|
||||||
quadrilateral[1].vertex[0] = v0v1;
|
quadrilateral[1].vertex[2] = v0v1;
|
||||||
|
|
||||||
if (v0->z > z) {
|
if (v0->z > z) {
|
||||||
if (upper != NULL) stl_add_facet(&upper->stl, &triangle);
|
if (upper != NULL) stl_add_facet(&upper->stl, &triangle);
|
||||||
@ -832,9 +848,53 @@ TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// triangulate holes of upper mesh
|
||||||
|
if (upper != NULL) {
|
||||||
// compute shape of section
|
// compute shape of section
|
||||||
ExPolygons section;
|
ExPolygons section;
|
||||||
this->make_expolygons(lines, §ion);
|
this->make_expolygons(upper_lines, §ion);
|
||||||
|
|
||||||
|
// triangulate section
|
||||||
|
Polygons triangles;
|
||||||
|
for (ExPolygons::const_iterator expolygon = section.begin(); expolygon != section.end(); ++expolygon)
|
||||||
|
expolygon->triangulate(&triangles);
|
||||||
|
|
||||||
|
// convert triangles to facets and append them to mesh
|
||||||
|
for (Polygons::const_iterator polygon = triangles.begin(); polygon != triangles.end(); ++polygon) {
|
||||||
|
Polygon p = *polygon;
|
||||||
|
p.reverse();
|
||||||
|
stl_facet facet;
|
||||||
|
for (size_t i = 0; i <= 2; ++i) {
|
||||||
|
facet.vertex[i].x = unscale(p.points[i].x);
|
||||||
|
facet.vertex[i].y = unscale(p.points[i].y);
|
||||||
|
facet.vertex[i].z = z;
|
||||||
|
}
|
||||||
|
//stl_add_facet(&upper->stl, &facet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// triangulate holes of lower mesh
|
||||||
|
if (lower != NULL) {
|
||||||
|
// compute shape of section
|
||||||
|
ExPolygons section;
|
||||||
|
this->make_expolygons(lower_lines, §ion);
|
||||||
|
|
||||||
|
// triangulate section
|
||||||
|
Polygons triangles;
|
||||||
|
for (ExPolygons::const_iterator expolygon = section.begin(); expolygon != section.end(); ++expolygon)
|
||||||
|
expolygon->triangulate(&triangles);
|
||||||
|
|
||||||
|
// convert triangles to facets and append them to mesh
|
||||||
|
for (Polygons::const_iterator polygon = triangles.begin(); polygon != triangles.end(); ++polygon) {
|
||||||
|
stl_facet facet;
|
||||||
|
for (size_t i = 0; i <= 2; ++i) {
|
||||||
|
facet.vertex[i].x = unscale(polygon->points[i].x);
|
||||||
|
facet.vertex[i].y = unscale(polygon->points[i].y);
|
||||||
|
facet.vertex[i].z = z;
|
||||||
|
}
|
||||||
|
//stl_add_facet(&lower->stl, &facet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
stl_get_size(&(upper->stl));
|
stl_get_size(&(upper->stl));
|
||||||
|
@ -108,7 +108,7 @@ my $cube = {
|
|||||||
my $lower = Slic3r::TriangleMesh->new;
|
my $lower = Slic3r::TriangleMesh->new;
|
||||||
$m->cut(0, $upper, $lower);
|
$m->cut(0, $upper, $lower);
|
||||||
#$upper->repair; $lower->repair;
|
#$upper->repair; $lower->repair;
|
||||||
is $upper->facets_count, 10, 'upper mesh has all facets except those belonging to the slicing plane';
|
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';
|
is $lower->facets_count, 0, 'lower mesh has no facets';
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -116,8 +116,8 @@ my $cube = {
|
|||||||
my $lower = Slic3r::TriangleMesh->new;
|
my $lower = Slic3r::TriangleMesh->new;
|
||||||
$m->cut(10, $upper, $lower);
|
$m->cut(10, $upper, $lower);
|
||||||
#$upper->repair; $lower->repair;
|
#$upper->repair; $lower->repair;
|
||||||
is $upper->facets_count, 14, 'upper mesh has the right number of facets';
|
is $upper->facets_count, 16, 'upper mesh has the right number of facets';
|
||||||
is $lower->facets_count, 14, 'lower mesh has the right number of facets';
|
is $lower->facets_count, 16, 'lower mesh has the right number of facets';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user