2012-08-29 14:49:38 +00:00
|
|
|
|
package Slic3r::Model;
|
|
|
|
|
use Moo;
|
|
|
|
|
|
|
|
|
|
use Slic3r::Geometry qw(X Y Z);
|
|
|
|
|
|
2012-08-29 16:23:34 +00:00
|
|
|
|
has 'materials' => (is => 'ro', default => sub { {} });
|
2012-08-29 14:49:38 +00:00
|
|
|
|
has 'objects' => (is => 'ro', default => sub { [] });
|
|
|
|
|
|
2012-08-29 17:37:27 +00:00
|
|
|
|
sub read_from_file {
|
|
|
|
|
my $class = shift;
|
|
|
|
|
my ($input_file) = @_;
|
|
|
|
|
|
|
|
|
|
my $model = $input_file =~ /\.stl$/i ? Slic3r::Format::STL->read_file($input_file)
|
|
|
|
|
: $input_file =~ /\.obj$/i ? Slic3r::Format::OBJ->read_file($input_file)
|
|
|
|
|
: $input_file =~ /\.amf(\.xml)?$/i ? Slic3r::Format::AMF->read_file($input_file)
|
|
|
|
|
: die "Input file must have .stl, .obj or .amf(.xml) extension\n";
|
|
|
|
|
|
2012-09-22 17:04:36 +00:00
|
|
|
|
$_->input_file($input_file) for @{$model->objects};
|
2012-08-29 17:37:27 +00:00
|
|
|
|
return $model;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-29 14:49:38 +00:00
|
|
|
|
sub add_object {
|
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
|
|
my $object = Slic3r::Model::Object->new(model => $self, @_);
|
|
|
|
|
push @{$self->objects}, $object;
|
|
|
|
|
return $object;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-22 17:04:36 +00:00
|
|
|
|
sub set_material {
|
|
|
|
|
my $self = shift;
|
|
|
|
|
my ($material_id, $attributes) = @_;
|
|
|
|
|
|
2012-09-23 00:52:31 +00:00
|
|
|
|
return $self->materials->{$material_id} = Slic3r::Model::Region->new(
|
2012-09-22 17:04:36 +00:00
|
|
|
|
model => $self,
|
|
|
|
|
attributes => $attributes || {},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-21 18:56:19 +00:00
|
|
|
|
sub scale {
|
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
|
|
$_->scale(@_) for @{$self->objects};
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-29 14:49:38 +00:00
|
|
|
|
# flattens everything to a single mesh
|
|
|
|
|
sub mesh {
|
|
|
|
|
my $self = shift;
|
|
|
|
|
|
2012-09-12 14:30:44 +00:00
|
|
|
|
my @meshes = ();
|
2012-08-29 14:49:38 +00:00
|
|
|
|
foreach my $object (@{$self->objects}) {
|
2012-09-12 14:30:44 +00:00
|
|
|
|
my @instances = $object->instances ? @{$object->instances} : (undef);
|
|
|
|
|
foreach my $instance (@instances) {
|
|
|
|
|
my $mesh = $object->mesh->clone;
|
|
|
|
|
if ($instance) {
|
|
|
|
|
$mesh->rotate($instance->rotation);
|
|
|
|
|
$mesh->align_to_origin;
|
|
|
|
|
$mesh->move(@{$instance->offset});
|
|
|
|
|
}
|
|
|
|
|
push @meshes, $mesh;
|
|
|
|
|
}
|
2012-08-29 14:49:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-09-12 14:30:44 +00:00
|
|
|
|
return Slic3r::TriangleMesh->merge(@meshes);
|
2012-08-29 14:49:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-09-23 00:52:31 +00:00
|
|
|
|
package Slic3r::Model::Region;
|
2012-08-29 14:49:38 +00:00
|
|
|
|
use Moo;
|
|
|
|
|
|
|
|
|
|
has 'model' => (is => 'ro', weak_ref => 1, required => 1);
|
|
|
|
|
has 'attributes' => (is => 'rw', default => sub { {} });
|
|
|
|
|
|
|
|
|
|
package Slic3r::Model::Object;
|
|
|
|
|
use Moo;
|
|
|
|
|
|
2013-02-24 17:17:08 +00:00
|
|
|
|
use List::Util qw(first);
|
2012-09-11 16:11:46 +00:00
|
|
|
|
use Slic3r::Geometry qw(X Y Z);
|
|
|
|
|
|
2012-09-12 14:30:44 +00:00
|
|
|
|
has 'input_file' => (is => 'rw');
|
2012-08-29 14:49:38 +00:00
|
|
|
|
has 'model' => (is => 'ro', weak_ref => 1, required => 1);
|
|
|
|
|
has 'vertices' => (is => 'ro', default => sub { [] });
|
|
|
|
|
has 'volumes' => (is => 'ro', default => sub { [] });
|
|
|
|
|
has 'instances' => (is => 'rw');
|
|
|
|
|
|
|
|
|
|
sub add_volume {
|
|
|
|
|
my $self = shift;
|
2012-09-23 12:48:58 +00:00
|
|
|
|
my %args = @_;
|
2012-08-29 14:49:38 +00:00
|
|
|
|
|
2012-09-23 12:48:58 +00:00
|
|
|
|
if (my $vertices = delete $args{vertices}) {
|
|
|
|
|
my $v_offset = @{$self->vertices};
|
|
|
|
|
push @{$self->vertices}, @$vertices;
|
|
|
|
|
|
|
|
|
|
@{$args{facets}} = map {
|
|
|
|
|
my $f = [@$_];
|
|
|
|
|
$f->[$_] += $v_offset for -3..-1;
|
|
|
|
|
$f;
|
|
|
|
|
} @{$args{facets}};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
my $volume = Slic3r::Model::Volume->new(object => $self, %args);
|
2012-08-29 14:49:38 +00:00
|
|
|
|
push @{$self->volumes}, $volume;
|
|
|
|
|
return $volume;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub add_instance {
|
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
|
|
$self->instances([]) if !defined $self->instances;
|
|
|
|
|
push @{$self->instances}, Slic3r::Model::Instance->new(object => $self, @_);
|
|
|
|
|
return $self->instances->[-1];
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-29 17:37:27 +00:00
|
|
|
|
sub mesh {
|
|
|
|
|
my $self = shift;
|
|
|
|
|
|
2013-02-24 17:17:08 +00:00
|
|
|
|
# this mesh won't be suitable for check_manifoldness as multiple
|
|
|
|
|
# facets from different volumes may use the same vertices
|
2012-08-29 17:37:27 +00:00
|
|
|
|
return Slic3r::TriangleMesh->new(
|
2012-09-12 14:30:44 +00:00
|
|
|
|
vertices => $self->vertices,
|
|
|
|
|
facets => [ map @{$_->facets}, @{$self->volumes} ],
|
2012-08-29 17:37:27 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-21 18:56:19 +00:00
|
|
|
|
sub scale {
|
|
|
|
|
my $self = shift;
|
|
|
|
|
my ($factor) = @_;
|
|
|
|
|
return if $factor == 1;
|
|
|
|
|
|
|
|
|
|
# transform vertex coordinates
|
|
|
|
|
foreach my $vertex (@{$self->vertices}) {
|
|
|
|
|
$vertex->[$_] *= $factor for X,Y,Z;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-24 20:44:08 +00:00
|
|
|
|
sub materials_count {
|
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
|
|
my %materials = map { $_->material_id // '_default' => 1 } @{$self->volumes};
|
|
|
|
|
return scalar keys %materials;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-24 17:17:08 +00:00
|
|
|
|
sub check_manifoldness {
|
|
|
|
|
my $self = shift;
|
|
|
|
|
return (first { !$_->mesh->check_manifoldness } @{$self->volumes}) ? 0 : 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-29 14:49:38 +00:00
|
|
|
|
package Slic3r::Model::Volume;
|
|
|
|
|
use Moo;
|
|
|
|
|
|
|
|
|
|
has 'object' => (is => 'ro', weak_ref => 1, required => 1);
|
|
|
|
|
has 'material_id' => (is => 'rw');
|
|
|
|
|
has 'facets' => (is => 'rw', default => sub { [] });
|
|
|
|
|
|
|
|
|
|
sub mesh {
|
|
|
|
|
my $self = shift;
|
|
|
|
|
return Slic3r::TriangleMesh->new(
|
|
|
|
|
vertices => $self->object->vertices,
|
|
|
|
|
facets => $self->facets,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
package Slic3r::Model::Instance;
|
|
|
|
|
use Moo;
|
|
|
|
|
|
|
|
|
|
has 'object' => (is => 'ro', weak_ref => 1, required => 1);
|
|
|
|
|
has 'rotation' => (is => 'rw', default => sub { 0 });
|
|
|
|
|
has 'offset' => (is => 'rw');
|
|
|
|
|
|
|
|
|
|
1;
|