mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-10 03:09:02 +08:00
Cut along X and Y axes too
This commit is contained in:
parent
b23e50603e
commit
a778cd9820
@ -23,6 +23,7 @@ __PACKAGE__->mk_accessors( qw(_quat _dirty init
|
||||
on_move
|
||||
volumes
|
||||
_sphi _stheta
|
||||
cutting_plane_axis
|
||||
cutting_plane_z
|
||||
cut_lines_vertices
|
||||
bed_shape
|
||||
@ -505,19 +506,35 @@ sub select_volume {
|
||||
}
|
||||
|
||||
sub SetCuttingPlane {
|
||||
my ($self, $z, $expolygons) = @_;
|
||||
my ($self, $axis, $z, $expolygons) = @_;
|
||||
|
||||
$self->cutting_plane_axis($axis);
|
||||
$self->cutting_plane_z($z);
|
||||
|
||||
# grow slices in order to display them better
|
||||
$expolygons = offset_ex([ map @$_, @$expolygons ], scale 0.1);
|
||||
|
||||
my $bb = $self->volumes_bounding_box;
|
||||
|
||||
my @verts = ();
|
||||
foreach my $line (map @{$_->lines}, map @$_, @$expolygons) {
|
||||
push @verts, (
|
||||
unscale($line->a->x), unscale($line->a->y), $z, #))
|
||||
unscale($line->b->x), unscale($line->b->y), $z, #))
|
||||
);
|
||||
if ($axis == X) {
|
||||
push @verts, (
|
||||
$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));
|
||||
}
|
||||
@ -932,10 +949,22 @@ sub Render {
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glBegin(GL_QUADS);
|
||||
glColor4f(0.8, 0.8, 0.8, 0.5);
|
||||
glVertex3f($bb->x_min-20, $bb->y_min-20, $plane_z);
|
||||
glVertex3f($bb->x_max+20, $bb->y_min-20, $plane_z);
|
||||
glVertex3f($bb->x_max+20, $bb->y_max+20, $plane_z);
|
||||
glVertex3f($bb->x_min-20, $bb->y_max+20, $plane_z);
|
||||
if ($self->cutting_plane_axis == X) {
|
||||
glVertex3f($bb->x_min+$plane_z, $bb->y_min-20, $bb->z_min-20);
|
||||
glVertex3f($bb->x_min+$plane_z, $bb->y_max+20, $bb->z_min-20);
|
||||
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();
|
||||
glEnable(GL_CULL_FACE);
|
||||
glDisable(GL_BLEND);
|
||||
|
@ -592,4 +592,10 @@ sub disable {
|
||||
$self->textctrl->SetEditable(0);
|
||||
}
|
||||
|
||||
sub set_range {
|
||||
my ($self, $min, $max) = @_;
|
||||
|
||||
$self->slider->SetRange($min * $self->scale, $max * $self->scale);
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -812,15 +812,12 @@ sub rotate {
|
||||
|
||||
if ($axis == Z) {
|
||||
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);
|
||||
} else {
|
||||
# rotation around X and Y needs to be performed on mesh
|
||||
# so we first apply any Z rotation
|
||||
if ($model_instance->rotation != 0) {
|
||||
$model_object->rotate($model_instance->rotation, Z);
|
||||
$_->set_rotation(0) for @{ $model_object->instances };
|
||||
}
|
||||
$model_object->transform_by_instance($model_instance, 1);
|
||||
$model_object->rotate(deg2rad($angle), $axis);
|
||||
|
||||
# realign object to Z = 0
|
||||
@ -847,10 +844,7 @@ sub mirror {
|
||||
my $model_instance = $model_object->instances->[0];
|
||||
|
||||
# apply Z rotation before mirroring
|
||||
if ($model_instance->rotation != 0) {
|
||||
$model_object->rotate($model_instance->rotation, Z);
|
||||
$_->set_rotation(0) for @{ $model_object->instances };
|
||||
}
|
||||
$model_object->transform_by_instance($model_instance, 1);
|
||||
|
||||
$model_object->mirror($axis);
|
||||
$model_object->update_bounding_box;
|
||||
@ -904,10 +898,7 @@ sub changescale {
|
||||
}
|
||||
|
||||
# apply Z rotation before scaling
|
||||
if ($model_instance->rotation != 0) {
|
||||
$model_object->rotate($model_instance->rotation, Z);
|
||||
$_->set_rotation(0) for @{ $model_object->instances };
|
||||
}
|
||||
$model_object->transform_by_instance($model_instance, 1);
|
||||
|
||||
my $versor = [1,1,1];
|
||||
$versor->[$axis] = $scale/100;
|
||||
|
@ -6,7 +6,7 @@ use strict;
|
||||
use warnings;
|
||||
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::Event qw(EVT_CLOSE EVT_BUTTON);
|
||||
use base 'Wx::Dialog';
|
||||
@ -24,12 +24,16 @@ sub new {
|
||||
# Note whether the window was already closed, so a pending update is not executed.
|
||||
$self->{already_closed} = 0;
|
||||
|
||||
$self->{model_object}->transform_by_instance($self->{model_object}->get_instance(0), 1);
|
||||
|
||||
# cut options
|
||||
my $size_z = $self->{model_object}->instance_bounding_box(0)->size->z;
|
||||
$self->{cut_options} = {
|
||||
z => 0,
|
||||
keep_upper => 1,
|
||||
axis => Z,
|
||||
z => $size_z/2,
|
||||
keep_upper => 0,
|
||||
keep_lower => 1,
|
||||
rotate_lower => 1,
|
||||
rotate_lower => 0,
|
||||
preview => 1,
|
||||
};
|
||||
|
||||
@ -54,13 +58,21 @@ sub new {
|
||||
},
|
||||
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(
|
||||
opt_id => 'z',
|
||||
type => 'slider',
|
||||
label => 'Z',
|
||||
default => $self->{cut_options}{z},
|
||||
min => 0,
|
||||
max => $self->{model_object}->bounding_box->size->z,
|
||||
max => $size_z,
|
||||
full_width => 1,
|
||||
));
|
||||
{
|
||||
@ -133,10 +145,10 @@ sub new {
|
||||
|
||||
# Adjust position / orientation of the split object halves.
|
||||
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}->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}) {
|
||||
$self->{new_model_objects}{upper}->center_around_origin; # align to Z = 0
|
||||
@ -165,7 +177,15 @@ sub new {
|
||||
sub _mesh_slice_z_pos
|
||||
{
|
||||
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.
|
||||
@ -184,8 +204,8 @@ sub _perform_cut
|
||||
return if $self->{mesh_cut_valid};
|
||||
|
||||
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};
|
||||
$self->{new_model} = $new_model;
|
||||
$self->{new_model_objects} = {};
|
||||
@ -210,12 +230,11 @@ sub _update {
|
||||
# Only recalculate the cut, if the live cut preview is active.
|
||||
my $life_preview_active = $self->_life_preview_active();
|
||||
$self->_perform_cut() if $life_preview_active;
|
||||
|
||||
|
||||
{
|
||||
# scale Z down to original size since we're using the transformed mesh for 3D preview
|
||||
# and cut dialog but ModelObject::cut() needs Z without any instance transformation
|
||||
my $z = $self->_mesh_slice_z_pos();
|
||||
|
||||
|
||||
# update canvas
|
||||
if ($self->{canvas}) {
|
||||
@ -226,25 +245,38 @@ sub _update {
|
||||
} else {
|
||||
push @objects, $self->{model_object};
|
||||
}
|
||||
|
||||
|
||||
# get section contour
|
||||
my @expolygons = ();
|
||||
foreach my $volume (@{$self->{model_object}->volumes}) {
|
||||
next if !$volume->mesh;
|
||||
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;
|
||||
}
|
||||
|
||||
my $offset = $self->{model_object}->instances->[0]->offset;
|
||||
foreach my $expolygon (@expolygons) {
|
||||
$self->{model_object}->instances->[0]->transform_polygon($_)
|
||||
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}->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->{cut_options}{z},
|
||||
$self->{cut_options}{axis},
|
||||
$plane_z,
|
||||
[@expolygons],
|
||||
);
|
||||
$self->{canvas}->Render;
|
||||
@ -255,9 +287,16 @@ sub _update {
|
||||
{
|
||||
my $z = $self->{cut_options}{z};
|
||||
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_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});
|
||||
|
||||
# update cut button
|
||||
|
@ -1,8 +1,9 @@
|
||||
#include "Config.hpp"
|
||||
#include "Model.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "IO.hpp"
|
||||
#include "TriangleMesh.hpp"
|
||||
#include "Model.hpp"
|
||||
#include "SLAPrint.hpp"
|
||||
#include "TriangleMesh.hpp"
|
||||
#include "libslic3r.h"
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
@ -69,7 +70,7 @@ main(const int argc, const char **argv)
|
||||
Model model;
|
||||
// TODO: read other file formats with Model::read_from_file()
|
||||
try {
|
||||
Slic3r::IO::STL::read(*it, &model);
|
||||
IO::STL::read(*it, &model);
|
||||
} catch (std::exception &e) {
|
||||
std::cout << *it << ": " << e.what() << std::endl;
|
||||
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(cli_config.scale.value);
|
||||
(*o)->rotate(deg2rad(cli_config.rotate.value), Z);
|
||||
(*o)->rotate(Geometry::deg2rad(cli_config.rotate.value), Z);
|
||||
}
|
||||
|
||||
// TODO: handle --merge
|
||||
@ -105,7 +106,7 @@ main(const int argc, const char **argv)
|
||||
|
||||
TriangleMesh mesh = model->mesh();
|
||||
mesh.repair();
|
||||
Slic3r::IO::OBJ::write(mesh, outfile);
|
||||
IO::OBJ::write(mesh, outfile);
|
||||
printf("File exported to %s\n", outfile.c_str());
|
||||
} else if (cli_config.export_pov) {
|
||||
std::string outfile = cli_config.output.value;
|
||||
@ -113,7 +114,7 @@ main(const int argc, const char **argv)
|
||||
|
||||
TriangleMesh mesh = model->mesh();
|
||||
mesh.repair();
|
||||
Slic3r::IO::POV::write(mesh, outfile);
|
||||
IO::POV::write(mesh, outfile);
|
||||
printf("File exported to %s\n", outfile.c_str());
|
||||
} else if (cli_config.export_svg) {
|
||||
std::string outfile = cli_config.output.value;
|
||||
@ -124,8 +125,35 @@ main(const int argc, const char **argv)
|
||||
print.slice();
|
||||
print.write_svg(outfile);
|
||||
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 {
|
||||
std::cerr << "error: only --export-svg and --export-obj are currently supported" << std::endl;
|
||||
std::cerr << "error: command not supported" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ BEGIN {
|
||||
|
||||
use Getopt::Long qw(:config no_auto_abbrev);
|
||||
use Slic3r;
|
||||
use Slic3r::Geometry qw(Z);
|
||||
use Slic3r::GUI;
|
||||
use Slic3r::GUI::3DScene;
|
||||
$|++;
|
||||
@ -40,7 +41,7 @@ my %opt = ();
|
||||
$app->{canvas}->load_object($model, 0);
|
||||
$app->{canvas}->set_auto_bed_shape;
|
||||
$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;
|
||||
}
|
||||
|
||||
|
@ -61,15 +61,7 @@ typedef struct {
|
||||
static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect");
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} stl_normal;
|
||||
|
||||
#ifdef static_assert
|
||||
static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect");
|
||||
#endif
|
||||
typedef stl_vertex stl_normal;
|
||||
|
||||
typedef char stl_extra[2];
|
||||
|
||||
|
@ -660,6 +660,24 @@ ModelObject::mirror(const Axis &axis)
|
||||
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
|
||||
ModelObject::materials_count() const
|
||||
{
|
||||
@ -692,7 +710,7 @@ ModelObject::needed_repair() const
|
||||
}
|
||||
|
||||
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.
|
||||
ModelObject* upper = model->add_object(*this);
|
||||
@ -707,10 +725,16 @@ ModelObject::cut(coordf_t z, Model* model) const
|
||||
upper->add_volume(*volume);
|
||||
lower->add_volume(*volume);
|
||||
} else {
|
||||
TriangleMeshSlicer tms(&volume->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();
|
||||
lower_mesh.repair();
|
||||
upper_mesh.reset_repair_stats();
|
||||
|
@ -156,10 +156,11 @@ class ModelObject
|
||||
void scale_to_fit(const Sizef3 &size);
|
||||
void rotate(float angle, 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 facets_count() 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 update_bounding_box(); // this is a private method but we expose it until we need to expose it via XS
|
||||
void print_info() const;
|
||||
|
@ -1398,6 +1398,24 @@ CLIConfigDef::CLIConfigDef()
|
||||
{
|
||||
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->label = "Export SVG";
|
||||
def->tooltip = "Export the model as OBJ.";
|
||||
|
@ -589,6 +589,9 @@ class CLIConfig
|
||||
: public virtual ConfigBase, public StaticConfig
|
||||
{
|
||||
public:
|
||||
ConfigOptionFloat cut;
|
||||
ConfigOptionFloat cut_x;
|
||||
ConfigOptionFloat cut_y;
|
||||
ConfigOptionBool export_obj;
|
||||
ConfigOptionBool export_pov;
|
||||
ConfigOptionBool export_svg;
|
||||
@ -606,6 +609,9 @@ class CLIConfig
|
||||
};
|
||||
|
||||
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_pov);
|
||||
OPT_PTR(export_svg);
|
||||
|
@ -49,7 +49,7 @@ SLAPrint::slice()
|
||||
slice_z.push_back(this->layers[i].slice_z);
|
||||
|
||||
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)
|
||||
this->layers[i].slices.expolygons = slices[i];
|
||||
|
@ -477,8 +477,9 @@ TriangleMesh::extrude_tin(float offset)
|
||||
this->repair();
|
||||
}
|
||||
|
||||
template <Axis A>
|
||||
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
|
||||
@ -513,7 +514,7 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* la
|
||||
parallelize<int>(
|
||||
0,
|
||||
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>(
|
||||
0,
|
||||
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
|
||||
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 stl_facet &facet = this->mesh->stl.facet_start[facet_idx];
|
||||
|
||||
// find facet extents
|
||||
const float min_z = fminf(facet.vertex[0].z, fminf(facet.vertex[1].z, facet.vertex[2].z));
|
||||
const float max_z = fmaxf(facet.vertex[0].z, fmaxf(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(_z(facet.vertex[0]), fmaxf(_z(facet.vertex[1]), _z(facet.vertex[2])));
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
printf("\n==> FACET %d (%f,%f,%f - %f,%f,%f - %f,%f,%f):\n", facet_idx,
|
||||
facet.vertex[0].x, facet.vertex[0].y, facet.vertex[0].z,
|
||||
facet.vertex[1].x, facet.vertex[1].y, facet.vertex[1].z,
|
||||
facet.vertex[2].x, facet.vertex[2].y, facet.vertex[2].z);
|
||||
printf("\n==> FACET %zu (%f,%f,%f - %f,%f,%f - %f,%f,%f):\n", facet_idx,
|
||||
_x(facet.vertex[0]), _y(facet.vertex[0]), _z(facet.vertex[0]),
|
||||
_x(facet.vertex[1]), _y(facet.vertex[1]), _z(facet.vertex[1]),
|
||||
_x(facet.vertex[2]), _y(facet.vertex[2]), _z(facet.vertex[2]));
|
||||
printf("z: min = %.2f, max = %.2f\n", min_z, max_z);
|
||||
#endif
|
||||
|
||||
@ -560,8 +562,9 @@ TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLines>*
|
||||
}
|
||||
}
|
||||
|
||||
template <Axis A>
|
||||
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;
|
||||
this->slice(z, &layers_p);
|
||||
@ -577,8 +580,20 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<ExPolygons>*
|
||||
}
|
||||
}
|
||||
|
||||
template <Axis A>
|
||||
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,
|
||||
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
|
||||
(external on the right of the line) */
|
||||
int i = 0;
|
||||
if (facet.vertex[1].z == min_z) {
|
||||
if (_z(facet.vertex[1]) == min_z) {
|
||||
// vertex 1 has lowest Z
|
||||
i = 1;
|
||||
} else if (facet.vertex[2].z == min_z) {
|
||||
} else if (_z(facet.vertex[2]) == min_z) {
|
||||
// vertex 2 has lowest Z
|
||||
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* 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
|
||||
|
||||
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;
|
||||
if (min_z == max_z) {
|
||||
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
|
||||
its point order */
|
||||
std::swap(a, b);
|
||||
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;
|
||||
std::swap(a, b);
|
||||
std::swap(a_id, b_id);
|
||||
} else {
|
||||
line.edge_type = feBottom;
|
||||
}
|
||||
line.a.x = a->x;
|
||||
line.a.y = a->y;
|
||||
line.b.x = b->x;
|
||||
line.b.y = b->y;
|
||||
line.a.x = _x(*a);
|
||||
line.a.y = _y(*a);
|
||||
line.b.x = _x(*b);
|
||||
line.b.y = _y(*b);
|
||||
line.a_id = a_id;
|
||||
line.b_id = b_id;
|
||||
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
|
||||
|
||||
if (line.edge_type != feHorizontal) return;
|
||||
} else if (a->z == slice_z) {
|
||||
} else if (_z(*a) == slice_z) {
|
||||
IntersectionPoint point;
|
||||
point.x = a->x;
|
||||
point.y = a->y;
|
||||
point.x = _x(*a);
|
||||
point.y = _y(*a);
|
||||
point.point_id = a_id;
|
||||
points.push_back(point);
|
||||
points_on_layer.push_back(points.size()-1);
|
||||
} else if (b->z == slice_z) {
|
||||
} else if (_z(*b) == slice_z) {
|
||||
IntersectionPoint point;
|
||||
point.x = b->x;
|
||||
point.y = b->y;
|
||||
point.x = _x(*b);
|
||||
point.y = _y(*b);
|
||||
point.point_id = b_id;
|
||||
points.push_back(point);
|
||||
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
|
||||
|
||||
IntersectionPoint point;
|
||||
point.x = b->x + (a->x - b->x) * (slice_z - b->z) / (a->z - b->z);
|
||||
point.y = b->y + (a->y - b->y) * (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 = _y(*b) + (_y(*a) - _y(*b)) * (slice_z - _z(*b)) / (_z(*a) - _z(*b));
|
||||
point.edge_id = edge_id;
|
||||
points.push_back(point);
|
||||
}
|
||||
@ -700,14 +715,16 @@ TriangleMeshSlicer::slice_facet(float slice_z, const stl_facet &facet, const int
|
||||
}
|
||||
}
|
||||
|
||||
template <Axis A>
|
||||
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]);
|
||||
}
|
||||
|
||||
template <Axis A>
|
||||
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");
|
||||
@ -847,8 +864,9 @@ class _area_comp {
|
||||
std::vector<double>* abs_area;
|
||||
};
|
||||
|
||||
template <Axis A>
|
||||
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;
|
||||
this->make_loops(lines, &loops);
|
||||
@ -881,8 +899,9 @@ TriangleMeshSlicer::make_expolygons_simple(std::vector<IntersectionLine> &lines,
|
||||
}
|
||||
}
|
||||
|
||||
template <Axis A>
|
||||
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
|
||||
@ -944,26 +963,28 @@ TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slices) c
|
||||
slices->insert(slices->end(), ex_slices.begin(), ex_slices.end());
|
||||
}
|
||||
|
||||
template <Axis A>
|
||||
void
|
||||
TriangleMeshSlicer::make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) const
|
||||
TriangleMeshSlicer<A>::make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) const
|
||||
{
|
||||
Polygons pp;
|
||||
this->make_loops(lines, &pp);
|
||||
this->make_expolygons(pp, slices);
|
||||
}
|
||||
|
||||
template <Axis A>
|
||||
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;
|
||||
|
||||
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++) {
|
||||
stl_facet* facet = &this->mesh->stl.facet_start[facet_idx];
|
||||
|
||||
// find facet extents
|
||||
float min_z = fminf(facet->vertex[0].z, fminf(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));
|
||||
float min_z = fminf(_z(facet->vertex[0]), fminf(_z(facet->vertex[1]), _z(facet->vertex[2])));
|
||||
float max_z = fmaxf(_z(facet->vertex[0]), fmaxf(_z(facet->vertex[1]), _z(facet->vertex[2])));
|
||||
|
||||
// intersect facet with cutting plane
|
||||
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
|
||||
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;
|
||||
} 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;
|
||||
} else {
|
||||
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
|
||||
stl_vertex v0v1, v2v0;
|
||||
v0v1.x = v1->x + (v0->x - v1->x) * (z - v1->z) / (v0->z - v1->z);
|
||||
v0v1.y = v1->y + (v0->y - v1->y) * (z - v1->z) / (v0->z - v1->z);
|
||||
v0v1.z = z;
|
||||
v2v0.x = v2->x + (v0->x - v2->x) * (z - v2->z) / (v0->z - v2->z);
|
||||
v2v0.y = v2->y + (v0->y - v2->y) * (z - v2->z) / (v0->z - v2->z);
|
||||
v2v0.z = z;
|
||||
_x(v0v1) = _x(*v1) + (_x(*v0) - _x(*v1)) * (z - _z(*v1)) / (_z(*v0) - _z(*v1));
|
||||
_y(v0v1) = _y(*v1) + (_y(*v0) - _y(*v1)) * (z - _z(*v1)) / (_z(*v0) - _z(*v1));
|
||||
_z(v0v1) = z;
|
||||
_x(v2v0) = _x(*v2) + (_x(*v0) - _x(*v2)) * (z - _z(*v2)) / (_z(*v0) - _z(*v2));
|
||||
_y(v2v0) = _y(*v2) + (_y(*v0) - _y(*v2)) * (z - _z(*v2)) / (_z(*v0) - _z(*v2));
|
||||
_z(v2v0) = z;
|
||||
|
||||
// build the triangular facet
|
||||
stl_facet triangle;
|
||||
@ -1032,7 +1053,7 @@ TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const
|
||||
quadrilateral[1].vertex[1] = v2v0;
|
||||
quadrilateral[1].vertex[2] = v0v1;
|
||||
|
||||
if (v0->z > z) {
|
||||
if (_z(*v0) > z) {
|
||||
if (upper != NULL) stl_add_facet(&upper->stl, &triangle);
|
||||
if (lower != NULL) {
|
||||
stl_add_facet(&lower->stl, &quadrilateral[0]);
|
||||
@ -1064,13 +1085,13 @@ TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const
|
||||
Polygon p = *polygon;
|
||||
p.reverse();
|
||||
stl_facet facet;
|
||||
facet.normal.x = 0;
|
||||
facet.normal.y = 0;
|
||||
facet.normal.z = -1;
|
||||
_x(facet.normal) = 0;
|
||||
_y(facet.normal) = 0;
|
||||
_z(facet.normal) = -1;
|
||||
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;
|
||||
_x(facet.vertex[i]) = unscale(p.points[i].x);
|
||||
_y(facet.vertex[i]) = unscale(p.points[i].y);
|
||||
_z(facet.vertex[i]) = z;
|
||||
}
|
||||
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
|
||||
for (Polygons::const_iterator polygon = triangles.begin(); polygon != triangles.end(); ++polygon) {
|
||||
stl_facet facet;
|
||||
facet.normal.x = 0;
|
||||
facet.normal.y = 0;
|
||||
facet.normal.z = 1;
|
||||
_x(facet.normal) = 0;
|
||||
_y(facet.normal) = 0;
|
||||
_z(facet.normal) = 1;
|
||||
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;
|
||||
_x(facet.vertex[i]) = unscale(polygon->points[i].x);
|
||||
_y(facet.vertex[i]) = unscale(polygon->points[i].y);
|
||||
_z(facet.vertex[i]) = z;
|
||||
}
|
||||
stl_add_facet(&lower->stl, &facet);
|
||||
}
|
||||
@ -1107,7 +1128,8 @@ TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
template class TriangleMeshSlicer<X>;
|
||||
template class TriangleMeshSlicer<Y>;
|
||||
template class TriangleMeshSlicer<Z>;
|
||||
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
namespace Slic3r {
|
||||
|
||||
class TriangleMesh;
|
||||
class TriangleMeshSlicer;
|
||||
template <Axis A> class TriangleMeshSlicer;
|
||||
typedef std::vector<TriangleMesh*> TriangleMeshPtrs;
|
||||
|
||||
class TriangleMesh
|
||||
@ -61,7 +61,9 @@ class TriangleMesh
|
||||
|
||||
private:
|
||||
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 };
|
||||
@ -88,6 +90,7 @@ class IntersectionLine : public Line
|
||||
typedef std::vector<IntersectionLine> IntersectionLines;
|
||||
typedef std::vector<IntersectionLine*> IntersectionLinePtrs;
|
||||
|
||||
template <Axis A>
|
||||
class TriangleMeshSlicer
|
||||
{
|
||||
public:
|
||||
@ -96,11 +99,15 @@ class TriangleMeshSlicer
|
||||
~TriangleMeshSlicer();
|
||||
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(float z, ExPolygons* slices) const;
|
||||
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,
|
||||
boost::mutex* lines_mutex = NULL) const;
|
||||
|
||||
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;
|
||||
@ -111,8 +118,36 @@ class TriangleMeshSlicer
|
||||
void make_expolygons(const Polygons &loops, ExPolygons* slices) const;
|
||||
void make_expolygons_simple(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
|
||||
|
@ -153,6 +153,8 @@ ModelMaterial::attributes()
|
||||
void clear_instances();
|
||||
int instances_count()
|
||||
%code%{ RETVAL = THIS->instances.size(); %};
|
||||
Ref<ModelInstance> get_instance(int idx)
|
||||
%code%{ RETVAL = THIS->instances.at(idx); %};
|
||||
|
||||
std::string name()
|
||||
%code%{ RETVAL = THIS->name; %};
|
||||
@ -187,11 +189,13 @@ ModelMaterial::attributes()
|
||||
%code{% THIS->scale(*versor); %};
|
||||
void rotate(float angle, 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%{
|
||||
RETVAL = new Model();
|
||||
THIS->cut(z, RETVAL);
|
||||
THIS->cut(axis, z, RETVAL);
|
||||
%};
|
||||
|
||||
ModelObjectPtrs* split_object()
|
||||
|
@ -185,7 +185,7 @@ TriangleMesh::slice(z)
|
||||
std::vector<float> z_f(z.begin(), z.end());
|
||||
|
||||
std::vector<ExPolygons> layers;
|
||||
TriangleMeshSlicer mslicer(THIS);
|
||||
TriangleMeshSlicer<Z> mslicer(THIS);
|
||||
mslicer.slice(z_f, &layers);
|
||||
|
||||
AV* layers_av = newAV();
|
||||
@ -205,13 +205,28 @@ TriangleMesh::slice(z)
|
||||
OUTPUT:
|
||||
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
|
||||
TriangleMesh::cut(z, upper, lower)
|
||||
float z;
|
||||
TriangleMesh* upper;
|
||||
TriangleMesh* lower;
|
||||
CODE:
|
||||
TriangleMeshSlicer mslicer(THIS);
|
||||
TriangleMeshSlicer<Z> mslicer(THIS);
|
||||
mslicer.cut(z, upper, lower);
|
||||
|
||||
std::vector<double>
|
||||
|
Loading…
x
Reference in New Issue
Block a user