Cut along X and Y axes too

This commit is contained in:
Alessandro Ranellucci 2016-12-17 19:51:29 +01:00
parent b23e50603e
commit a778cd9820
16 changed files with 346 additions and 130 deletions

View File

@ -23,6 +23,7 @@ __PACKAGE__->mk_accessors( qw(_quat _dirty init
on_move on_move
volumes volumes
_sphi _stheta _sphi _stheta
cutting_plane_axis
cutting_plane_z cutting_plane_z
cut_lines_vertices cut_lines_vertices
bed_shape bed_shape
@ -505,19 +506,35 @@ sub select_volume {
} }
sub SetCuttingPlane { sub SetCuttingPlane {
my ($self, $z, $expolygons) = @_; my ($self, $axis, $z, $expolygons) = @_;
$self->cutting_plane_axis($axis);
$self->cutting_plane_z($z); $self->cutting_plane_z($z);
# grow slices in order to display them better # grow slices in order to display them better
$expolygons = offset_ex([ map @$_, @$expolygons ], scale 0.1); $expolygons = offset_ex([ map @$_, @$expolygons ], scale 0.1);
my $bb = $self->volumes_bounding_box;
my @verts = (); my @verts = ();
foreach my $line (map @{$_->lines}, map @$_, @$expolygons) { foreach my $line (map @{$_->lines}, map @$_, @$expolygons) {
push @verts, ( if ($axis == X) {
unscale($line->a->x), unscale($line->a->y), $z, #)) push @verts, (
unscale($line->b->x), unscale($line->b->y), $z, #)) $bb->x_min + $z, unscale($line->a->x), unscale($line->a->y), #))
); $bb->x_min + $z, unscale($line->b->x), unscale($line->b->y), #))
);
} elsif ($axis == Y) {
push @verts, (
unscale($line->a->y), $bb->y_min + $z, unscale($line->a->x), #))
unscale($line->b->y), $bb->y_min + $z, unscale($line->b->x), #))
);
} else {
push @verts, (
unscale($line->a->x), unscale($line->a->y), $z, #))
unscale($line->b->x), unscale($line->b->y), $z, #))
);
}
} }
$self->cut_lines_vertices(OpenGL::Array->new_list(GL_FLOAT, @verts)); $self->cut_lines_vertices(OpenGL::Array->new_list(GL_FLOAT, @verts));
} }
@ -932,10 +949,22 @@ sub Render {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin(GL_QUADS); glBegin(GL_QUADS);
glColor4f(0.8, 0.8, 0.8, 0.5); glColor4f(0.8, 0.8, 0.8, 0.5);
glVertex3f($bb->x_min-20, $bb->y_min-20, $plane_z); if ($self->cutting_plane_axis == X) {
glVertex3f($bb->x_max+20, $bb->y_min-20, $plane_z); glVertex3f($bb->x_min+$plane_z, $bb->y_min-20, $bb->z_min-20);
glVertex3f($bb->x_max+20, $bb->y_max+20, $plane_z); glVertex3f($bb->x_min+$plane_z, $bb->y_max+20, $bb->z_min-20);
glVertex3f($bb->x_min-20, $bb->y_max+20, $plane_z); glVertex3f($bb->x_min+$plane_z, $bb->y_max+20, $bb->z_max+20);
glVertex3f($bb->x_min+$plane_z, $bb->y_min-20, $bb->z_max+20);
} elsif ($self->cutting_plane_axis == Y) {
glVertex3f($bb->x_min-20, $bb->y_min+$plane_z, $bb->z_min-20);
glVertex3f($bb->x_max+20, $bb->y_min+$plane_z, $bb->z_min-20);
glVertex3f($bb->x_max+20, $bb->y_min+$plane_z, $bb->z_max+20);
glVertex3f($bb->x_min-20, $bb->y_min+$plane_z, $bb->z_max+20);
} elsif ($self->cutting_plane_axis == Z) {
glVertex3f($bb->x_min-20, $bb->y_min-20, $bb->z_min+$plane_z);
glVertex3f($bb->x_max+20, $bb->y_min-20, $bb->z_min+$plane_z);
glVertex3f($bb->x_max+20, $bb->y_max+20, $bb->z_min+$plane_z);
glVertex3f($bb->x_min-20, $bb->y_max+20, $bb->z_min+$plane_z);
}
glEnd(); glEnd();
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glDisable(GL_BLEND); glDisable(GL_BLEND);

View File

@ -592,4 +592,10 @@ sub disable {
$self->textctrl->SetEditable(0); $self->textctrl->SetEditable(0);
} }
sub set_range {
my ($self, $min, $max) = @_;
$self->slider->SetRange($min * $self->scale, $max * $self->scale);
}
1; 1;

View File

@ -812,15 +812,12 @@ sub rotate {
if ($axis == Z) { if ($axis == Z) {
my $new_angle = deg2rad($angle); my $new_angle = deg2rad($angle);
$_->set_rotation($new_angle) for @{ $model_object->instances }; $_->set_rotation($_->rotation + $new_angle) for @{ $model_object->instances };
$object->transform_thumbnail($self->{model}, $obj_idx); $object->transform_thumbnail($self->{model}, $obj_idx);
} else { } else {
# rotation around X and Y needs to be performed on mesh # rotation around X and Y needs to be performed on mesh
# so we first apply any Z rotation # so we first apply any Z rotation
if ($model_instance->rotation != 0) { $model_object->transform_by_instance($model_instance, 1);
$model_object->rotate($model_instance->rotation, Z);
$_->set_rotation(0) for @{ $model_object->instances };
}
$model_object->rotate(deg2rad($angle), $axis); $model_object->rotate(deg2rad($angle), $axis);
# realign object to Z = 0 # realign object to Z = 0
@ -847,10 +844,7 @@ sub mirror {
my $model_instance = $model_object->instances->[0]; my $model_instance = $model_object->instances->[0];
# apply Z rotation before mirroring # apply Z rotation before mirroring
if ($model_instance->rotation != 0) { $model_object->transform_by_instance($model_instance, 1);
$model_object->rotate($model_instance->rotation, Z);
$_->set_rotation(0) for @{ $model_object->instances };
}
$model_object->mirror($axis); $model_object->mirror($axis);
$model_object->update_bounding_box; $model_object->update_bounding_box;
@ -904,10 +898,7 @@ sub changescale {
} }
# apply Z rotation before scaling # apply Z rotation before scaling
if ($model_instance->rotation != 0) { $model_object->transform_by_instance($model_instance, 1);
$model_object->rotate($model_instance->rotation, Z);
$_->set_rotation(0) for @{ $model_object->instances };
}
my $versor = [1,1,1]; my $versor = [1,1,1];
$versor->[$axis] = $scale/100; $versor->[$axis] = $scale/100;

View File

@ -6,7 +6,7 @@ use strict;
use warnings; use warnings;
use utf8; use utf8;
use Slic3r::Geometry qw(PI X); use Slic3r::Geometry qw(PI X Y Z);
use Wx qw(wxTheApp :dialog :id :misc :sizer wxTAB_TRAVERSAL); use Wx qw(wxTheApp :dialog :id :misc :sizer wxTAB_TRAVERSAL);
use Wx::Event qw(EVT_CLOSE EVT_BUTTON); use Wx::Event qw(EVT_CLOSE EVT_BUTTON);
use base 'Wx::Dialog'; use base 'Wx::Dialog';
@ -24,12 +24,16 @@ sub new {
# Note whether the window was already closed, so a pending update is not executed. # Note whether the window was already closed, so a pending update is not executed.
$self->{already_closed} = 0; $self->{already_closed} = 0;
$self->{model_object}->transform_by_instance($self->{model_object}->get_instance(0), 1);
# cut options # cut options
my $size_z = $self->{model_object}->instance_bounding_box(0)->size->z;
$self->{cut_options} = { $self->{cut_options} = {
z => 0, axis => Z,
keep_upper => 1, z => $size_z/2,
keep_upper => 0,
keep_lower => 1, keep_lower => 1,
rotate_lower => 1, rotate_lower => 0,
preview => 1, preview => 1,
}; };
@ -54,13 +58,21 @@ sub new {
}, },
label_width => 120, label_width => 120,
); );
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
opt_id => 'axis',
type => 'select',
label => 'Axis',
labels => ['X','Y','Z'],
values => [X,Y,Z],
default => $self->{cut_options}{axis},
));
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
opt_id => 'z', opt_id => 'z',
type => 'slider', type => 'slider',
label => 'Z', label => 'Z',
default => $self->{cut_options}{z}, default => $self->{cut_options}{z},
min => 0, min => 0,
max => $self->{model_object}->bounding_box->size->z, max => $size_z,
full_width => 1, full_width => 1,
)); ));
{ {
@ -133,10 +145,10 @@ sub new {
# Adjust position / orientation of the split object halves. # Adjust position / orientation of the split object halves.
if ($self->{new_model_objects}{lower}) { if ($self->{new_model_objects}{lower}) {
if ($self->{cut_options}{rotate_lower}) { if ($self->{cut_options}{rotate_lower} && $self->{cut_options}{axis} == Z) {
$self->{new_model_objects}{lower}->rotate(PI, X); $self->{new_model_objects}{lower}->rotate(PI, X);
$self->{new_model_objects}{lower}->center_around_origin; # align to Z = 0
} }
$self->{new_model_objects}{lower}->center_around_origin; # align to Z = 0
} }
if ($self->{new_model_objects}{upper}) { if ($self->{new_model_objects}{upper}) {
$self->{new_model_objects}{upper}->center_around_origin; # align to Z = 0 $self->{new_model_objects}{upper}->center_around_origin; # align to Z = 0
@ -165,7 +177,15 @@ sub new {
sub _mesh_slice_z_pos sub _mesh_slice_z_pos
{ {
my ($self) = @_; my ($self) = @_;
return $self->{cut_options}{z} / $self->{model_object}->instances->[0]->scaling_factor;
my $bb = $self->{model_object}->instance_bounding_box(0);
my $z = $self->{cut_options}{axis} == X ? $bb->x_min
: $self->{cut_options}{axis} == Y ? $bb->y_min
: $bb->z_min;
$z += $self->{cut_options}{z} / $self->{model_object}->instances->[0]->scaling_factor;
return $z;
} }
# Only perform live preview if just a single part of the object shall survive. # Only perform live preview if just a single part of the object shall survive.
@ -185,7 +205,7 @@ sub _perform_cut
my $z = $self->_mesh_slice_z_pos(); my $z = $self->_mesh_slice_z_pos();
my ($new_model) = $self->{model_object}->cut($z); my ($new_model) = $self->{model_object}->cut($self->{cut_options}{axis}, $z);
my ($upper_object, $lower_object) = @{$new_model->objects}; my ($upper_object, $lower_object) = @{$new_model->objects};
$self->{new_model} = $new_model; $self->{new_model} = $new_model;
$self->{new_model_objects} = {}; $self->{new_model_objects} = {};
@ -216,7 +236,6 @@ sub _update {
# and cut dialog but ModelObject::cut() needs Z without any instance transformation # and cut dialog but ModelObject::cut() needs Z without any instance transformation
my $z = $self->_mesh_slice_z_pos(); my $z = $self->_mesh_slice_z_pos();
# update canvas # update canvas
if ($self->{canvas}) { if ($self->{canvas}) {
# get volumes to render # get volumes to render
@ -232,19 +251,32 @@ sub _update {
foreach my $volume (@{$self->{model_object}->volumes}) { foreach my $volume (@{$self->{model_object}->volumes}) {
next if !$volume->mesh; next if !$volume->mesh;
next if $volume->modifier; next if $volume->modifier;
my $expp = $volume->mesh->slice([ $z + $volume->mesh->bounding_box->z_min ])->[0]; my $expp = $volume->mesh->slice_at($self->{cut_options}{axis}, $z);
push @expolygons, @$expp; push @expolygons, @$expp;
} }
my $offset = $self->{model_object}->instances->[0]->offset;
foreach my $expolygon (@expolygons) { foreach my $expolygon (@expolygons) {
$self->{model_object}->instances->[0]->transform_polygon($_) $self->{model_object}->instances->[0]->transform_polygon($_)
for @$expolygon; for @$expolygon;
$expolygon->translate(map Slic3r::Geometry::scale($_), @{ $self->{model_object}->instances->[0]->offset });
if ($self->{cut_options}{axis} != X) {
$expolygon->translate(0, Slic3r::Geometry::scale($offset->y)); #)
}
if ($self->{cut_options}{axis} != Y) {
$expolygon->translate(Slic3r::Geometry::scale($offset->x), 0);
}
} }
$self->{canvas}->reset_objects; $self->{canvas}->reset_objects;
$self->{canvas}->load_object($_, undef, [0]) for @objects; $self->{canvas}->load_object($_, undef, [0]) for @objects;
my $plane_z = $self->{cut_options}{z};
$plane_z += 0.02 if !$self->{cut_options}{keep_upper};
$plane_z -= 0.02 if !$self->{cut_options}{keep_lower};
$self->{canvas}->SetCuttingPlane( $self->{canvas}->SetCuttingPlane(
$self->{cut_options}{z}, $self->{cut_options}{axis},
$plane_z,
[@expolygons], [@expolygons],
); );
$self->{canvas}->Render; $self->{canvas}->Render;
@ -255,9 +287,16 @@ sub _update {
{ {
my $z = $self->{cut_options}{z}; my $z = $self->{cut_options}{z};
my $optgroup = $self->{optgroup}; my $optgroup = $self->{optgroup};
{
my $bb = $self->{model_object}->instance_bounding_box(0);
my $max = $self->{cut_options}{axis} == X ? $bb->size->x
: $self->{cut_options}{axis} == Y ? $bb->size->y ###
: $bb->size->z;
$optgroup->get_field('z')->set_range(0, $max);
}
$optgroup->get_field('keep_upper')->toggle(my $have_upper = abs($z - $optgroup->get_option('z')->max) > 0.1); $optgroup->get_field('keep_upper')->toggle(my $have_upper = abs($z - $optgroup->get_option('z')->max) > 0.1);
$optgroup->get_field('keep_lower')->toggle(my $have_lower = $z > 0.1); $optgroup->get_field('keep_lower')->toggle(my $have_lower = $z > 0.1);
$optgroup->get_field('rotate_lower')->toggle($z > 0 && $self->{cut_options}{keep_lower}); $optgroup->get_field('rotate_lower')->toggle($z > 0 && $self->{cut_options}{keep_lower} && $self->{cut_options}{axis} == Z);
$optgroup->get_field('preview')->toggle($self->{cut_options}{keep_upper} != $self->{cut_options}{keep_lower}); $optgroup->get_field('preview')->toggle($self->{cut_options}{keep_upper} != $self->{cut_options}{keep_lower});
# update cut button # update cut button

View File

@ -1,8 +1,9 @@
#include "Config.hpp" #include "Config.hpp"
#include "Model.hpp" #include "Geometry.hpp"
#include "IO.hpp" #include "IO.hpp"
#include "TriangleMesh.hpp" #include "Model.hpp"
#include "SLAPrint.hpp" #include "SLAPrint.hpp"
#include "TriangleMesh.hpp"
#include "libslic3r.h" #include "libslic3r.h"
#include <cstdio> #include <cstdio>
#include <string> #include <string>
@ -69,7 +70,7 @@ main(const int argc, const char **argv)
Model model; Model model;
// TODO: read other file formats with Model::read_from_file() // TODO: read other file formats with Model::read_from_file()
try { try {
Slic3r::IO::STL::read(*it, &model); IO::STL::read(*it, &model);
} catch (std::exception &e) { } catch (std::exception &e) {
std::cout << *it << ": " << e.what() << std::endl; std::cout << *it << ": " << e.what() << std::endl;
exit(1); exit(1);
@ -88,7 +89,7 @@ main(const int argc, const char **argv)
(*o)->scale_to_fit(cli_config.scale_to_fit.value); (*o)->scale_to_fit(cli_config.scale_to_fit.value);
(*o)->scale(cli_config.scale.value); (*o)->scale(cli_config.scale.value);
(*o)->rotate(deg2rad(cli_config.rotate.value), Z); (*o)->rotate(Geometry::deg2rad(cli_config.rotate.value), Z);
} }
// TODO: handle --merge // TODO: handle --merge
@ -105,7 +106,7 @@ main(const int argc, const char **argv)
TriangleMesh mesh = model->mesh(); TriangleMesh mesh = model->mesh();
mesh.repair(); mesh.repair();
Slic3r::IO::OBJ::write(mesh, outfile); IO::OBJ::write(mesh, outfile);
printf("File exported to %s\n", outfile.c_str()); printf("File exported to %s\n", outfile.c_str());
} else if (cli_config.export_pov) { } else if (cli_config.export_pov) {
std::string outfile = cli_config.output.value; std::string outfile = cli_config.output.value;
@ -113,7 +114,7 @@ main(const int argc, const char **argv)
TriangleMesh mesh = model->mesh(); TriangleMesh mesh = model->mesh();
mesh.repair(); mesh.repair();
Slic3r::IO::POV::write(mesh, outfile); IO::POV::write(mesh, outfile);
printf("File exported to %s\n", outfile.c_str()); printf("File exported to %s\n", outfile.c_str());
} else if (cli_config.export_svg) { } else if (cli_config.export_svg) {
std::string outfile = cli_config.output.value; std::string outfile = cli_config.output.value;
@ -124,8 +125,35 @@ main(const int argc, const char **argv)
print.slice(); print.slice();
print.write_svg(outfile); print.write_svg(outfile);
printf("SVG file exported to %s\n", outfile.c_str()); printf("SVG file exported to %s\n", outfile.c_str());
} else if (cli_config.cut_x > 0 || cli_config.cut_y > 0 || cli_config.cut > 0) {
model->repair();
model->translate(0, 0, -model->bounding_box().min.z);
if (!model->objects.empty()) {
// FIXME: cut all objects
Model out;
if (cli_config.cut_x > 0) {
model->objects.front()->cut(X, cli_config.cut_x, &out);
} else if (cli_config.cut_y > 0) {
model->objects.front()->cut(Y, cli_config.cut_y, &out);
} else {
model->objects.front()->cut(Z, cli_config.cut, &out);
}
ModelObject &upper = *out.objects[0];
ModelObject &lower = *out.objects[1];
if (upper.facets_count() > 0) {
TriangleMesh m = upper.mesh();
IO::STL::write(m, upper.input_file + "_upper.stl");
}
if (lower.facets_count() > 0) {
TriangleMesh m = lower.mesh();
IO::STL::write(m, lower.input_file + "_lower.stl");
}
}
} else { } else {
std::cerr << "error: only --export-svg and --export-obj are currently supported" << std::endl; std::cerr << "error: command not supported" << std::endl;
return 1; return 1;
} }
} }

View File

@ -12,6 +12,7 @@ BEGIN {
use Getopt::Long qw(:config no_auto_abbrev); use Getopt::Long qw(:config no_auto_abbrev);
use Slic3r; use Slic3r;
use Slic3r::Geometry qw(Z);
use Slic3r::GUI; use Slic3r::GUI;
use Slic3r::GUI::3DScene; use Slic3r::GUI::3DScene;
$|++; $|++;
@ -40,7 +41,7 @@ my %opt = ();
$app->{canvas}->load_object($model, 0); $app->{canvas}->load_object($model, 0);
$app->{canvas}->set_auto_bed_shape; $app->{canvas}->set_auto_bed_shape;
$app->{canvas}->zoom_to_volumes; $app->{canvas}->zoom_to_volumes;
$app->{canvas}->SetCuttingPlane($opt{cut}) if defined $opt{cut}; $app->{canvas}->SetCuttingPlane(Z, $opt{cut}) if defined $opt{cut};
$app->MainLoop; $app->MainLoop;
} }

View File

@ -61,15 +61,7 @@ typedef struct {
static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect"); static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect");
#endif #endif
typedef struct { typedef stl_vertex stl_normal;
float x;
float y;
float z;
} stl_normal;
#ifdef static_assert
static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect");
#endif
typedef char stl_extra[2]; typedef char stl_extra[2];

View File

@ -660,6 +660,24 @@ ModelObject::mirror(const Axis &axis)
this->invalidate_bounding_box(); this->invalidate_bounding_box();
} }
void
ModelObject::transform_by_instance(const ModelInstance &instance, bool dont_translate)
{
this->rotate(instance.rotation, Z);
this->scale(instance.scaling_factor);
if (!dont_translate)
this->translate(instance.offset.x, instance.offset.y, 0);
for (ModelInstancePtrs::iterator i = this->instances.begin(); i != this->instances.end(); ++i) {
(*i)->rotation -= instance.rotation;
(*i)->scaling_factor /= instance.scaling_factor;
if (!dont_translate)
(*i)->offset.translate(-instance.offset.x, -instance.offset.y);
}
this->origin_translation = Pointf3(0,0,0);
this->invalidate_bounding_box();
}
size_t size_t
ModelObject::materials_count() const ModelObject::materials_count() const
{ {
@ -692,7 +710,7 @@ ModelObject::needed_repair() const
} }
void void
ModelObject::cut(coordf_t z, Model* model) const ModelObject::cut(Axis axis, coordf_t z, Model* model) const
{ {
// clone this one to duplicate instances, materials etc. // clone this one to duplicate instances, materials etc.
ModelObject* upper = model->add_object(*this); ModelObject* upper = model->add_object(*this);
@ -707,10 +725,16 @@ ModelObject::cut(coordf_t z, Model* model) const
upper->add_volume(*volume); upper->add_volume(*volume);
lower->add_volume(*volume); lower->add_volume(*volume);
} else { } else {
TriangleMeshSlicer tms(&volume->mesh);
TriangleMesh upper_mesh, lower_mesh; TriangleMesh upper_mesh, lower_mesh;
// TODO: shouldn't we use object bounding box instead of per-volume bb?
tms.cut(z + volume->mesh.bounding_box().min.z, &upper_mesh, &lower_mesh); if (axis == X) {
TriangleMeshSlicer<X>(&volume->mesh).cut(z, &upper_mesh, &lower_mesh);
} else if (axis == Y) {
TriangleMeshSlicer<Y>(&volume->mesh).cut(z, &upper_mesh, &lower_mesh);
} else if (axis == Z) {
TriangleMeshSlicer<Z>(&volume->mesh).cut(z, &upper_mesh, &lower_mesh);
}
upper_mesh.repair(); upper_mesh.repair();
lower_mesh.repair(); lower_mesh.repair();
upper_mesh.reset_repair_stats(); upper_mesh.reset_repair_stats();

View File

@ -156,10 +156,11 @@ class ModelObject
void scale_to_fit(const Sizef3 &size); void scale_to_fit(const Sizef3 &size);
void rotate(float angle, const Axis &axis); void rotate(float angle, const Axis &axis);
void mirror(const Axis &axis); void mirror(const Axis &axis);
void transform_by_instance(const ModelInstance &instance, bool dont_translate = false);
size_t materials_count() const; size_t materials_count() const;
size_t facets_count() const; size_t facets_count() const;
bool needed_repair() const; bool needed_repair() const;
void cut(coordf_t z, Model* model) const; void cut(Axis axis, coordf_t z, Model* model) const;
void split(ModelObjectPtrs* new_objects); void split(ModelObjectPtrs* new_objects);
void update_bounding_box(); // this is a private method but we expose it until we need to expose it via XS void update_bounding_box(); // this is a private method but we expose it until we need to expose it via XS
void print_info() const; void print_info() const;

View File

@ -1398,6 +1398,24 @@ CLIConfigDef::CLIConfigDef()
{ {
ConfigOptionDef* def; ConfigOptionDef* def;
def = this->add("cut", coFloat);
def->label = "Cut";
def->tooltip = "Cut model at the given Z.";
def->cli = "cut";
def->default_value = new ConfigOptionFloat(0);
def = this->add("cut_x", coFloat);
def->label = "Cut";
def->tooltip = "Cut model at the given X.";
def->cli = "cut-x";
def->default_value = new ConfigOptionFloat(0);
def = this->add("cut_y", coFloat);
def->label = "Cut";
def->tooltip = "Cut model at the given Y.";
def->cli = "cut-y";
def->default_value = new ConfigOptionFloat(0);
def = this->add("export_obj", coBool); def = this->add("export_obj", coBool);
def->label = "Export SVG"; def->label = "Export SVG";
def->tooltip = "Export the model as OBJ."; def->tooltip = "Export the model as OBJ.";

View File

@ -589,6 +589,9 @@ class CLIConfig
: public virtual ConfigBase, public StaticConfig : public virtual ConfigBase, public StaticConfig
{ {
public: public:
ConfigOptionFloat cut;
ConfigOptionFloat cut_x;
ConfigOptionFloat cut_y;
ConfigOptionBool export_obj; ConfigOptionBool export_obj;
ConfigOptionBool export_pov; ConfigOptionBool export_pov;
ConfigOptionBool export_svg; ConfigOptionBool export_svg;
@ -606,6 +609,9 @@ class CLIConfig
}; };
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) { virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
OPT_PTR(cut);
OPT_PTR(cut_x);
OPT_PTR(cut_y);
OPT_PTR(export_obj); OPT_PTR(export_obj);
OPT_PTR(export_pov); OPT_PTR(export_pov);
OPT_PTR(export_svg); OPT_PTR(export_svg);

View File

@ -49,7 +49,7 @@ SLAPrint::slice()
slice_z.push_back(this->layers[i].slice_z); slice_z.push_back(this->layers[i].slice_z);
std::vector<ExPolygons> slices; std::vector<ExPolygons> slices;
TriangleMeshSlicer(&mesh).slice(slice_z, &slices); TriangleMeshSlicer<Z>(&mesh).slice(slice_z, &slices);
for (size_t i = 0; i < slices.size(); ++i) for (size_t i = 0; i < slices.size(); ++i)
this->layers[i].slices.expolygons = slices[i]; this->layers[i].slices.expolygons = slices[i];

View File

@ -477,8 +477,9 @@ TriangleMesh::extrude_tin(float offset)
this->repair(); this->repair();
} }
template <Axis A>
void void
TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers) const TriangleMeshSlicer<A>::slice(const std::vector<float> &z, std::vector<Polygons>* layers) const
{ {
/* /*
This method gets called with a list of unscaled Z coordinates and outputs This method gets called with a list of unscaled Z coordinates and outputs
@ -513,7 +514,7 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* la
parallelize<int>( parallelize<int>(
0, 0,
this->mesh->stl.stats.number_of_facets-1, this->mesh->stl.stats.number_of_facets-1,
boost::bind(&TriangleMeshSlicer::_slice_do, this, _1, &lines, &lines_mutex, z) boost::bind(&TriangleMeshSlicer<A>::_slice_do, this, _1, &lines, &lines_mutex, z)
); );
} }
@ -524,25 +525,26 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* la
parallelize<size_t>( parallelize<size_t>(
0, 0,
lines.size()-1, lines.size()-1,
boost::bind(&TriangleMeshSlicer::_make_loops_do, this, _1, &lines, layers) boost::bind(&TriangleMeshSlicer<A>::_make_loops_do, this, _1, &lines, layers)
); );
} }
template <Axis A>
void void
TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLines>* lines, boost::mutex* lines_mutex, TriangleMeshSlicer<A>::_slice_do(size_t facet_idx, std::vector<IntersectionLines>* lines, boost::mutex* lines_mutex,
const std::vector<float> &z) const const std::vector<float> &z) const
{ {
const stl_facet &facet = this->mesh->stl.facet_start[facet_idx]; const stl_facet &facet = this->mesh->stl.facet_start[facet_idx];
// find facet extents // find facet extents
const float min_z = fminf(facet.vertex[0].z, fminf(facet.vertex[1].z, facet.vertex[2].z)); const float min_z = fminf(_z(facet.vertex[0]), fminf(_z(facet.vertex[1]), _z(facet.vertex[2])));
const float max_z = fmaxf(facet.vertex[0].z, fmaxf(facet.vertex[1].z, facet.vertex[2].z)); const float max_z = fmaxf(_z(facet.vertex[0]), fmaxf(_z(facet.vertex[1]), _z(facet.vertex[2])));
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG
printf("\n==> FACET %d (%f,%f,%f - %f,%f,%f - %f,%f,%f):\n", facet_idx, printf("\n==> FACET %zu (%f,%f,%f - %f,%f,%f - %f,%f,%f):\n", facet_idx,
facet.vertex[0].x, facet.vertex[0].y, facet.vertex[0].z, _x(facet.vertex[0]), _y(facet.vertex[0]), _z(facet.vertex[0]),
facet.vertex[1].x, facet.vertex[1].y, facet.vertex[1].z, _x(facet.vertex[1]), _y(facet.vertex[1]), _z(facet.vertex[1]),
facet.vertex[2].x, facet.vertex[2].y, facet.vertex[2].z); _x(facet.vertex[2]), _y(facet.vertex[2]), _z(facet.vertex[2]));
printf("z: min = %.2f, max = %.2f\n", min_z, max_z); printf("z: min = %.2f, max = %.2f\n", min_z, max_z);
#endif #endif
@ -560,8 +562,9 @@ TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLines>*
} }
} }
template <Axis A>
void void
TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<ExPolygons>* layers) const TriangleMeshSlicer<A>::slice(const std::vector<float> &z, std::vector<ExPolygons>* layers) const
{ {
std::vector<Polygons> layers_p; std::vector<Polygons> layers_p;
this->slice(z, &layers_p); this->slice(z, &layers_p);
@ -577,8 +580,20 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<ExPolygons>*
} }
} }
template <Axis A>
void void
TriangleMeshSlicer::slice_facet(float slice_z, const stl_facet &facet, const int &facet_idx, TriangleMeshSlicer<A>::slice(float z, ExPolygons* slices) const
{
std::vector<float> zz;
zz.push_back(z);
std::vector<ExPolygons> layers;
this->slice(zz, &layers);
append_to(*slices, layers.front());
}
template <Axis A>
void
TriangleMeshSlicer<A>::slice_facet(float slice_z, const stl_facet &facet, const int &facet_idx,
const float &min_z, const float &max_z, std::vector<IntersectionLine>* lines, const float &min_z, const float &max_z, std::vector<IntersectionLine>* lines,
boost::mutex* lines_mutex) const boost::mutex* lines_mutex) const
{ {
@ -590,10 +605,10 @@ TriangleMeshSlicer::slice_facet(float slice_z, const stl_facet &facet, const int
this is needed to get all intersection lines in a consistent order this is needed to get all intersection lines in a consistent order
(external on the right of the line) */ (external on the right of the line) */
int i = 0; int i = 0;
if (facet.vertex[1].z == min_z) { if (_z(facet.vertex[1]) == min_z) {
// vertex 1 has lowest Z // vertex 1 has lowest Z
i = 1; i = 1;
} else if (facet.vertex[2].z == min_z) { } else if (_z(facet.vertex[2]) == min_z) {
// vertex 2 has lowest Z // vertex 2 has lowest Z
i = 2; i = 2;
} }
@ -604,7 +619,7 @@ TriangleMeshSlicer::slice_facet(float slice_z, const stl_facet &facet, const int
stl_vertex* a = &this->v_scaled_shared[a_id]; stl_vertex* a = &this->v_scaled_shared[a_id];
stl_vertex* b = &this->v_scaled_shared[b_id]; stl_vertex* b = &this->v_scaled_shared[b_id];
if (a->z == b->z && a->z == slice_z) { if (_z(*a) == _z(*b) && _z(*a) == slice_z) {
// edge is horizontal and belongs to the current layer // edge is horizontal and belongs to the current layer
stl_vertex &v0 = this->v_scaled_shared[ this->mesh->stl.v_indices[facet_idx].vertex[0] ]; stl_vertex &v0 = this->v_scaled_shared[ this->mesh->stl.v_indices[facet_idx].vertex[0] ];
@ -613,23 +628,23 @@ TriangleMeshSlicer::slice_facet(float slice_z, const stl_facet &facet, const int
IntersectionLine line; IntersectionLine line;
if (min_z == max_z) { if (min_z == max_z) {
line.edge_type = feHorizontal; line.edge_type = feHorizontal;
if (this->mesh->stl.facet_start[facet_idx].normal.z < 0) { if (_z(this->mesh->stl.facet_start[facet_idx].normal) < 0) {
/* if normal points downwards this is a bottom horizontal facet so we reverse /* if normal points downwards this is a bottom horizontal facet so we reverse
its point order */ its point order */
std::swap(a, b); std::swap(a, b);
std::swap(a_id, b_id); std::swap(a_id, b_id);
} }
} else if (v0.z < slice_z || v1.z < slice_z || v2.z < slice_z) { } else if (_z(v0) < slice_z || _z(v1) < slice_z || _z(v2) < slice_z) {
line.edge_type = feTop; line.edge_type = feTop;
std::swap(a, b); std::swap(a, b);
std::swap(a_id, b_id); std::swap(a_id, b_id);
} else { } else {
line.edge_type = feBottom; line.edge_type = feBottom;
} }
line.a.x = a->x; line.a.x = _x(*a);
line.a.y = a->y; line.a.y = _y(*a);
line.b.x = b->x; line.b.x = _x(*b);
line.b.y = b->y; line.b.y = _y(*b);
line.a_id = a_id; line.a_id = a_id;
line.b_id = b_id; line.b_id = b_id;
if (lines_mutex != NULL) { if (lines_mutex != NULL) {
@ -645,26 +660,26 @@ TriangleMeshSlicer::slice_facet(float slice_z, const stl_facet &facet, const int
// because we won't find anything interesting // because we won't find anything interesting
if (line.edge_type != feHorizontal) return; if (line.edge_type != feHorizontal) return;
} else if (a->z == slice_z) { } else if (_z(*a) == slice_z) {
IntersectionPoint point; IntersectionPoint point;
point.x = a->x; point.x = _x(*a);
point.y = a->y; point.y = _y(*a);
point.point_id = a_id; point.point_id = a_id;
points.push_back(point); points.push_back(point);
points_on_layer.push_back(points.size()-1); points_on_layer.push_back(points.size()-1);
} else if (b->z == slice_z) { } else if (_z(*b) == slice_z) {
IntersectionPoint point; IntersectionPoint point;
point.x = b->x; point.x = _x(*b);
point.y = b->y; point.y = _y(*b);
point.point_id = b_id; point.point_id = b_id;
points.push_back(point); points.push_back(point);
points_on_layer.push_back(points.size()-1); points_on_layer.push_back(points.size()-1);
} else if ((a->z < slice_z && b->z > slice_z) || (b->z < slice_z && a->z > slice_z)) { } else if ((_z(*a) < slice_z && _z(*b) > slice_z) || (_z(*b) < slice_z && _z(*a) > slice_z)) {
// edge intersects the current layer; calculate intersection // edge intersects the current layer; calculate intersection
IntersectionPoint point; IntersectionPoint point;
point.x = b->x + (a->x - b->x) * (slice_z - b->z) / (a->z - b->z); point.x = _x(*b) + (_x(*a) - _x(*b)) * (slice_z - _z(*b)) / (_z(*a) - _z(*b));
point.y = b->y + (a->y - b->y) * (slice_z - b->z) / (a->z - b->z); point.y = _y(*b) + (_y(*a) - _y(*b)) * (slice_z - _z(*b)) / (_z(*a) - _z(*b));
point.edge_id = edge_id; point.edge_id = edge_id;
points.push_back(point); points.push_back(point);
} }
@ -700,14 +715,16 @@ TriangleMeshSlicer::slice_facet(float slice_z, const stl_facet &facet, const int
} }
} }
template <Axis A>
void void
TriangleMeshSlicer::_make_loops_do(size_t i, std::vector<IntersectionLines>* lines, std::vector<Polygons>* layers) const TriangleMeshSlicer<A>::_make_loops_do(size_t i, std::vector<IntersectionLines>* lines, std::vector<Polygons>* layers) const
{ {
this->make_loops((*lines)[i], &(*layers)[i]); this->make_loops((*lines)[i], &(*layers)[i]);
} }
template <Axis A>
void void
TriangleMeshSlicer::make_loops(std::vector<IntersectionLine> &lines, Polygons* loops) const TriangleMeshSlicer<A>::make_loops(std::vector<IntersectionLine> &lines, Polygons* loops) const
{ {
/* /*
SVG svg("lines.svg"); SVG svg("lines.svg");
@ -847,8 +864,9 @@ class _area_comp {
std::vector<double>* abs_area; std::vector<double>* abs_area;
}; };
template <Axis A>
void void
TriangleMeshSlicer::make_expolygons_simple(std::vector<IntersectionLine> &lines, ExPolygons* slices) const TriangleMeshSlicer<A>::make_expolygons_simple(std::vector<IntersectionLine> &lines, ExPolygons* slices) const
{ {
Polygons loops; Polygons loops;
this->make_loops(lines, &loops); this->make_loops(lines, &loops);
@ -881,8 +899,9 @@ TriangleMeshSlicer::make_expolygons_simple(std::vector<IntersectionLine> &lines,
} }
} }
template <Axis A>
void void
TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slices) const TriangleMeshSlicer<A>::make_expolygons(const Polygons &loops, ExPolygons* slices) const
{ {
/* /*
Input loops are not suitable for evenodd nor nonzero fill types, as we might get Input loops are not suitable for evenodd nor nonzero fill types, as we might get
@ -944,26 +963,28 @@ TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slices) c
slices->insert(slices->end(), ex_slices.begin(), ex_slices.end()); slices->insert(slices->end(), ex_slices.begin(), ex_slices.end());
} }
template <Axis A>
void void
TriangleMeshSlicer::make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) const TriangleMeshSlicer<A>::make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) const
{ {
Polygons pp; Polygons pp;
this->make_loops(lines, &pp); this->make_loops(lines, &pp);
this->make_expolygons(pp, slices); this->make_expolygons(pp, slices);
} }
template <Axis A>
void void
TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const TriangleMeshSlicer<A>::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const
{ {
IntersectionLines upper_lines, lower_lines; IntersectionLines upper_lines, lower_lines;
float scaled_z = scale_(z); const 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++) {
stl_facet* facet = &this->mesh->stl.facet_start[facet_idx]; stl_facet* facet = &this->mesh->stl.facet_start[facet_idx];
// find facet extents // find facet extents
float min_z = fminf(facet->vertex[0].z, fminf(facet->vertex[1].z, facet->vertex[2].z)); float min_z = fminf(_z(facet->vertex[0]), fminf(_z(facet->vertex[1]), _z(facet->vertex[2])));
float max_z = fmaxf(facet->vertex[0].z, fmaxf(facet->vertex[1].z, facet->vertex[2].z)); float max_z = fmaxf(_z(facet->vertex[0]), fmaxf(_z(facet->vertex[1]), _z(facet->vertex[2])));
// intersect facet with cutting plane // intersect facet with cutting plane
IntersectionLines lines; IntersectionLines lines;
@ -992,9 +1013,9 @@ TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const
// look for the vertex on whose side of the slicing plane there are no other vertices // look for the vertex on whose side of the slicing plane there are no other vertices
int isolated_vertex; int isolated_vertex;
if ( (facet->vertex[0].z > z) == (facet->vertex[1].z > z) ) { if ( (_z(facet->vertex[0]) > z) == (_z(facet->vertex[1]) > z) ) {
isolated_vertex = 2; isolated_vertex = 2;
} else if ( (facet->vertex[1].z > z) == (facet->vertex[2].z > z) ) { } else if ( (_z(facet->vertex[1]) > z) == (_z(facet->vertex[2]) > z) ) {
isolated_vertex = 0; isolated_vertex = 0;
} else { } else {
isolated_vertex = 1; isolated_vertex = 1;
@ -1007,12 +1028,12 @@ TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const
// intersect v0-v1 and v2-v0 with cutting plane and make new vertices // intersect v0-v1 and v2-v0 with cutting plane and make new vertices
stl_vertex v0v1, v2v0; stl_vertex v0v1, v2v0;
v0v1.x = v1->x + (v0->x - v1->x) * (z - v1->z) / (v0->z - v1->z); _x(v0v1) = _x(*v1) + (_x(*v0) - _x(*v1)) * (z - _z(*v1)) / (_z(*v0) - _z(*v1));
v0v1.y = v1->y + (v0->y - v1->y) * (z - v1->z) / (v0->z - v1->z); _y(v0v1) = _y(*v1) + (_y(*v0) - _y(*v1)) * (z - _z(*v1)) / (_z(*v0) - _z(*v1));
v0v1.z = z; _z(v0v1) = z;
v2v0.x = v2->x + (v0->x - v2->x) * (z - v2->z) / (v0->z - v2->z); _x(v2v0) = _x(*v2) + (_x(*v0) - _x(*v2)) * (z - _z(*v2)) / (_z(*v0) - _z(*v2));
v2v0.y = v2->y + (v0->y - v2->y) * (z - v2->z) / (v0->z - v2->z); _y(v2v0) = _y(*v2) + (_y(*v0) - _y(*v2)) * (z - _z(*v2)) / (_z(*v0) - _z(*v2));
v2v0.z = z; _z(v2v0) = z;
// build the triangular facet // build the triangular facet
stl_facet triangle; stl_facet triangle;
@ -1032,7 +1053,7 @@ TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const
quadrilateral[1].vertex[1] = v2v0; quadrilateral[1].vertex[1] = v2v0;
quadrilateral[1].vertex[2] = v0v1; quadrilateral[1].vertex[2] = v0v1;
if (v0->z > z) { if (_z(*v0) > z) {
if (upper != NULL) stl_add_facet(&upper->stl, &triangle); if (upper != NULL) stl_add_facet(&upper->stl, &triangle);
if (lower != NULL) { if (lower != NULL) {
stl_add_facet(&lower->stl, &quadrilateral[0]); stl_add_facet(&lower->stl, &quadrilateral[0]);
@ -1064,13 +1085,13 @@ TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const
Polygon p = *polygon; Polygon p = *polygon;
p.reverse(); p.reverse();
stl_facet facet; stl_facet facet;
facet.normal.x = 0; _x(facet.normal) = 0;
facet.normal.y = 0; _y(facet.normal) = 0;
facet.normal.z = -1; _z(facet.normal) = -1;
for (size_t i = 0; i <= 2; ++i) { for (size_t i = 0; i <= 2; ++i) {
facet.vertex[i].x = unscale(p.points[i].x); _x(facet.vertex[i]) = unscale(p.points[i].x);
facet.vertex[i].y = unscale(p.points[i].y); _y(facet.vertex[i]) = unscale(p.points[i].y);
facet.vertex[i].z = z; _z(facet.vertex[i]) = z;
} }
stl_add_facet(&upper->stl, &facet); stl_add_facet(&upper->stl, &facet);
} }
@ -1090,13 +1111,13 @@ TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const
// convert triangles to facets and append them to mesh // convert triangles to facets and append them to mesh
for (Polygons::const_iterator polygon = triangles.begin(); polygon != triangles.end(); ++polygon) { for (Polygons::const_iterator polygon = triangles.begin(); polygon != triangles.end(); ++polygon) {
stl_facet facet; stl_facet facet;
facet.normal.x = 0; _x(facet.normal) = 0;
facet.normal.y = 0; _y(facet.normal) = 0;
facet.normal.z = 1; _z(facet.normal) = 1;
for (size_t i = 0; i <= 2; ++i) { for (size_t i = 0; i <= 2; ++i) {
facet.vertex[i].x = unscale(polygon->points[i].x); _x(facet.vertex[i]) = unscale(polygon->points[i].x);
facet.vertex[i].y = unscale(polygon->points[i].y); _y(facet.vertex[i]) = unscale(polygon->points[i].y);
facet.vertex[i].z = z; _z(facet.vertex[i]) = z;
} }
stl_add_facet(&lower->stl, &facet); stl_add_facet(&lower->stl, &facet);
} }
@ -1107,7 +1128,8 @@ TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const
stl_get_size(&(lower->stl)); stl_get_size(&(lower->stl));
} }
TriangleMeshSlicer::TriangleMeshSlicer(TriangleMesh* _mesh) : mesh(_mesh), v_scaled_shared(NULL) template <Axis A>
TriangleMeshSlicer<A>::TriangleMeshSlicer(TriangleMesh* _mesh) : mesh(_mesh), v_scaled_shared(NULL)
{ {
// build a table to map a facet_idx to its three edge indices // build a table to map a facet_idx to its three edge indices
this->mesh->require_shared_vertices(); this->mesh->require_shared_vertices();
@ -1166,9 +1188,14 @@ TriangleMeshSlicer::TriangleMeshSlicer(TriangleMesh* _mesh) : mesh(_mesh), v_sca
} }
} }
TriangleMeshSlicer::~TriangleMeshSlicer() template <Axis A>
TriangleMeshSlicer<A>::~TriangleMeshSlicer()
{ {
if (this->v_scaled_shared != NULL) free(this->v_scaled_shared); if (this->v_scaled_shared != NULL) free(this->v_scaled_shared);
} }
template class TriangleMeshSlicer<X>;
template class TriangleMeshSlicer<Y>;
template class TriangleMeshSlicer<Z>;
} }

View File

@ -14,7 +14,7 @@
namespace Slic3r { namespace Slic3r {
class TriangleMesh; class TriangleMesh;
class TriangleMeshSlicer; template <Axis A> class TriangleMeshSlicer;
typedef std::vector<TriangleMesh*> TriangleMeshPtrs; typedef std::vector<TriangleMesh*> TriangleMeshPtrs;
class TriangleMesh class TriangleMesh
@ -61,7 +61,9 @@ class TriangleMesh
private: private:
void require_shared_vertices(); void require_shared_vertices();
friend class TriangleMeshSlicer; friend class TriangleMeshSlicer<X>;
friend class TriangleMeshSlicer<Y>;
friend class TriangleMeshSlicer<Z>;
}; };
enum FacetEdgeType { feNone, feTop, feBottom, feHorizontal }; enum FacetEdgeType { feNone, feTop, feBottom, feHorizontal };
@ -88,6 +90,7 @@ class IntersectionLine : public Line
typedef std::vector<IntersectionLine> IntersectionLines; typedef std::vector<IntersectionLine> IntersectionLines;
typedef std::vector<IntersectionLine*> IntersectionLinePtrs; typedef std::vector<IntersectionLine*> IntersectionLinePtrs;
template <Axis A>
class TriangleMeshSlicer class TriangleMeshSlicer
{ {
public: public:
@ -96,11 +99,15 @@ class TriangleMeshSlicer
~TriangleMeshSlicer(); ~TriangleMeshSlicer();
void slice(const std::vector<float> &z, std::vector<Polygons>* layers) const; void slice(const std::vector<float> &z, std::vector<Polygons>* layers) const;
void slice(const std::vector<float> &z, std::vector<ExPolygons>* layers) const; void slice(const std::vector<float> &z, std::vector<ExPolygons>* layers) const;
void slice(float z, ExPolygons* slices) const;
void slice_facet(float slice_z, const stl_facet &facet, const int &facet_idx, void slice_facet(float slice_z, const stl_facet &facet, const int &facet_idx,
const float &min_z, const float &max_z, std::vector<IntersectionLine>* lines, const float &min_z, const float &max_z, std::vector<IntersectionLine>* lines,
boost::mutex* lines_mutex = NULL) const; boost::mutex* lines_mutex = NULL) const;
void cut(float z, TriangleMesh* upper, TriangleMesh* lower) const; void cut(float z, TriangleMesh* upper, TriangleMesh* lower) const;
static void cut(TriangleMesh* mesh, Axis axis, float z, TriangleMesh* upper, TriangleMesh* lower);
private: private:
typedef std::vector< std::vector<int> > t_facets_edges; typedef std::vector< std::vector<int> > t_facets_edges;
t_facets_edges facets_edges; t_facets_edges facets_edges;
@ -111,8 +118,36 @@ class TriangleMeshSlicer
void make_expolygons(const Polygons &loops, ExPolygons* slices) const; void make_expolygons(const Polygons &loops, ExPolygons* slices) const;
void make_expolygons_simple(std::vector<IntersectionLine> &lines, ExPolygons* slices) const; void make_expolygons_simple(std::vector<IntersectionLine> &lines, ExPolygons* slices) const;
void make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) const; void make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) const;
float& _x(stl_vertex &vertex) const;
float& _y(stl_vertex &vertex) const;
float& _z(stl_vertex &vertex) const;
const float& _x(stl_vertex const &vertex) const;
const float& _y(stl_vertex const &vertex) const;
const float& _z(stl_vertex const &vertex) const;
}; };
template<> inline float& TriangleMeshSlicer<X>::_x(stl_vertex &vertex) const { return vertex.y; }
template<> inline float& TriangleMeshSlicer<X>::_y(stl_vertex &vertex) const { return vertex.z; }
template<> inline float& TriangleMeshSlicer<X>::_z(stl_vertex &vertex) const { return vertex.x; }
template<> inline float const& TriangleMeshSlicer<X>::_x(stl_vertex const &vertex) const { return vertex.y; }
template<> inline float const& TriangleMeshSlicer<X>::_y(stl_vertex const &vertex) const { return vertex.z; }
template<> inline float const& TriangleMeshSlicer<X>::_z(stl_vertex const &vertex) const { return vertex.x; }
template<> inline float& TriangleMeshSlicer<Y>::_x(stl_vertex &vertex) const { return vertex.z; }
template<> inline float& TriangleMeshSlicer<Y>::_y(stl_vertex &vertex) const { return vertex.x; }
template<> inline float& TriangleMeshSlicer<Y>::_z(stl_vertex &vertex) const { return vertex.y; }
template<> inline float const& TriangleMeshSlicer<Y>::_x(stl_vertex const &vertex) const { return vertex.z; }
template<> inline float const& TriangleMeshSlicer<Y>::_y(stl_vertex const &vertex) const { return vertex.x; }
template<> inline float const& TriangleMeshSlicer<Y>::_z(stl_vertex const &vertex) const { return vertex.y; }
template<> inline float& TriangleMeshSlicer<Z>::_x(stl_vertex &vertex) const { return vertex.x; }
template<> inline float& TriangleMeshSlicer<Z>::_y(stl_vertex &vertex) const { return vertex.y; }
template<> inline float& TriangleMeshSlicer<Z>::_z(stl_vertex &vertex) const { return vertex.z; }
template<> inline float const& TriangleMeshSlicer<Z>::_x(stl_vertex const &vertex) const { return vertex.x; }
template<> inline float const& TriangleMeshSlicer<Z>::_y(stl_vertex const &vertex) const { return vertex.y; }
template<> inline float const& TriangleMeshSlicer<Z>::_z(stl_vertex const &vertex) const { return vertex.z; }
} }
#endif #endif

View File

@ -153,6 +153,8 @@ ModelMaterial::attributes()
void clear_instances(); void clear_instances();
int instances_count() int instances_count()
%code%{ RETVAL = THIS->instances.size(); %}; %code%{ RETVAL = THIS->instances.size(); %};
Ref<ModelInstance> get_instance(int idx)
%code%{ RETVAL = THIS->instances.at(idx); %};
std::string name() std::string name()
%code%{ RETVAL = THIS->name; %}; %code%{ RETVAL = THIS->name; %};
@ -187,11 +189,13 @@ ModelMaterial::attributes()
%code{% THIS->scale(*versor); %}; %code{% THIS->scale(*versor); %};
void rotate(float angle, Axis axis); void rotate(float angle, Axis axis);
void mirror(Axis axis); void mirror(Axis axis);
void transform_by_instance(ModelInstance* instance, bool dont_translate = false)
%code{% THIS->transform_by_instance(*instance, dont_translate); %};
Model* cut(double z) Model* cut(Axis axis, double z)
%code%{ %code%{
RETVAL = new Model(); RETVAL = new Model();
THIS->cut(z, RETVAL); THIS->cut(axis, z, RETVAL);
%}; %};
ModelObjectPtrs* split_object() ModelObjectPtrs* split_object()

View File

@ -185,7 +185,7 @@ TriangleMesh::slice(z)
std::vector<float> z_f(z.begin(), z.end()); std::vector<float> z_f(z.begin(), z.end());
std::vector<ExPolygons> layers; std::vector<ExPolygons> layers;
TriangleMeshSlicer mslicer(THIS); TriangleMeshSlicer<Z> mslicer(THIS);
mslicer.slice(z_f, &layers); mslicer.slice(z_f, &layers);
AV* layers_av = newAV(); AV* layers_av = newAV();
@ -205,13 +205,28 @@ TriangleMesh::slice(z)
OUTPUT: OUTPUT:
RETVAL RETVAL
ExPolygons
TriangleMesh::slice_at(axis, z)
Axis axis
double z
CODE:
if (axis == X) {
TriangleMeshSlicer<X>(THIS).slice(z, &RETVAL);
} else if (axis == Y) {
TriangleMeshSlicer<Y>(THIS).slice(z, &RETVAL);
} else if (axis == Z) {
TriangleMeshSlicer<Z>(THIS).slice(z, &RETVAL);
}
OUTPUT:
RETVAL
void void
TriangleMesh::cut(z, upper, lower) TriangleMesh::cut(z, upper, lower)
float z; float z;
TriangleMesh* upper; TriangleMesh* upper;
TriangleMesh* lower; TriangleMesh* lower;
CODE: CODE:
TriangleMeshSlicer mslicer(THIS); TriangleMeshSlicer<Z> mslicer(THIS);
mslicer.cut(z, upper, lower); mslicer.cut(z, upper, lower);
std::vector<double> std::vector<double>