Merge branch 'sapir-modelcpp'

This commit is contained in:
Alessandro Ranellucci 2014-05-08 11:13:21 +02:00
commit 6e207d3830
17 changed files with 911 additions and 222 deletions

View file

@ -35,8 +35,8 @@ sub write_file {
printf $fh qq{<?xml version="1.0" encoding="UTF-8"?>\n};
printf $fh qq{<amf unit="millimeter">\n};
printf $fh qq{ <metadata type="cad">Slic3r %s</metadata>\n}, $Slic3r::VERSION;
for my $material_id (sort keys %{ $model->materials }) {
my $material = $model->materials->{$material_id};
for my $material_id (sort @{ $model->material_names }) {
my $material = $model->get_material($material_id);
printf $fh qq{ <material id="%s">\n}, $material_id;
for (keys %{$material->attributes}) {
printf $fh qq{ <metadata type=\"%s\">%s</metadata>\n}, $_, $material->attributes->{$_};

View file

@ -471,8 +471,8 @@ sub reset {
my $self = shift;
@{$self->{objects}} = ();
$self->{model}->delete_all_objects;
$self->{print}->delete_all_objects;
$self->{model}->clear_objects;
$self->{print}->clear_objects;
$self->{list}->DeleteAllItems;
$self->object_list_changed;
@ -542,7 +542,7 @@ sub rotate {
{
my $new_angle = $model_instance->rotation + $angle;
$_->rotation($new_angle) for @{ $model_object->instances };
$_->set_rotation($new_angle) for @{ $model_object->instances };
$model_object->update_bounding_box;
# update print
@ -578,7 +578,7 @@ sub changescale {
$range->[0] *= $variation;
$range->[1] *= $variation;
}
$_->scaling_factor($scale) for @{ $model_object->instances };
$_->set_scaling_factor($scale) for @{ $model_object->instances };
$model_object->update_bounding_box;
# update print
@ -1108,10 +1108,11 @@ sub mouse_event {
return if !$self->{drag_start_pos}; # concurrency problems
my ($obj_idx, $instance_idx) = @{ $self->{drag_object} };
my $model_object = $parent->{model}->objects->[$obj_idx];
$model_object->instances->[$instance_idx]->offset([
unscale($pos->[X] - $self->{drag_start_pos}[X]),
unscale($pos->[Y] - $self->{drag_start_pos}[Y]),
]);
$model_object->instances->[$instance_idx]->set_offset(
Slic3r::Pointf->new(
unscale($pos->[X] - $self->{drag_start_pos}[X]),
unscale($pos->[Y] - $self->{drag_start_pos}[Y]),
));
$model_object->update_bounding_box;
$parent->Refresh;
} elsif ($event->Moving) {

View file

@ -158,7 +158,7 @@ sub selection_changed {
# attach volume material config to settings panel
my $volume = $self->{model_object}->volumes->[ $itemData->{volume_id} ];
my $material = $self->{model_object}->model->materials->{ $volume->material_id // '_' };
my $material = $self->{model_object}->model->get_material($volume->material_id // '_');
$material //= $volume->assign_unique_material;
$self->{staticbox}->SetLabel('Part Settings');
$self->{settings_panel}->enable;
@ -211,7 +211,7 @@ sub on_btn_load {
$new_volume->mesh->translate(@{$self->{model_object}->origin_translation}, 0);
# set a default extruder value, since user can't add it manually
my $material = $self->{model_object}->model->materials->{$new_volume->material_id};
my $material = $self->{model_object}->model->get_material($new_volume->material_id);
$material->config->set_ifndef('extruder', 1);
$self->{parts_changed} = 1;

View file

@ -1,12 +1,8 @@
package Slic3r::Model;
use Moo;
use List::Util qw(first max);
use Slic3r::Geometry qw(X Y Z move_points);
has 'materials' => (is => 'ro', default => sub { {} });
has 'objects' => (is => 'ro', default => sub { [] });
sub read_from_file {
my $class = shift;
my ($input_file) = @_;
@ -16,7 +12,7 @@ sub read_from_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";
$_->input_file($input_file) for @{$model->objects};
$_->set_input_file($input_file) for @{$model->objects};
return $model;
}
@ -39,11 +35,12 @@ sub add_object {
if (@_ == 1) {
# we have a Model::Object
my ($object) = @_;
$new_object = $self->add_object(
input_file => $object->input_file,
config => $object->config,
layer_height_ranges => $object->layer_height_ranges, # TODO: clone!
origin_translation => $object->origin_translation,
);
foreach my $volume (@{$object->volumes}) {
@ -51,51 +48,43 @@ sub add_object {
}
$new_object->add_instance(
offset => $_->offset,
offset => [ @{$_->offset} ],
rotation => $_->rotation,
scaling_factor => $_->scaling_factor,
) for @{ $object->instances // [] };
} else {
push @{$self->objects}, $new_object = Slic3r::Model::Object->new(model => $self, @_);
my (%args) = @_;
$new_object = $self->_add_object(
$args{input_file},
$args{config} // Slic3r::Config->new,
$args{layer_height_ranges} // [],
$args{origin_translation} // Slic3r::Pointf->new,
);
}
return $new_object;
}
sub delete_object {
my ($self, $obj_idx) = @_;
splice @{$self->objects}, $obj_idx, 1;
}
sub delete_all_objects {
my ($self) = @_;
@{$self->objects} = ();
}
sub set_material {
my $self = shift;
my ($material_id, $attributes) = @_;
return $self->materials->{$material_id} = Slic3r::Model::Material->new(
model => $self,
attributes => $attributes || {},
);
}
sub get_material {
my ($self, $material_id) = @_;
return $self->materials->{$material_id};
$attributes //= {};
my $material = $self->_set_material($material_id);
$material->set_attribute($_, $attributes->{$_}) for keys %$attributes;
return $material;
}
sub duplicate_objects_grid {
my ($self, $grid, $distance) = @_;
die "Grid duplication is not supported with multiple objects\n"
if @{$self->objects} > 1;
my $object = $self->objects->[0];
@{$object->instances} = ();
$object->clear_instances;
my $size = $object->bounding_box->size;
for my $x_copy (1..$grid->[X]) {
for my $y_copy (1..$grid->[Y]) {
@ -144,7 +133,7 @@ sub arrange_objects {
my @positions = $self->_arrange(\@instance_sizes, $distance, $bb);
foreach my $object (@{$self->objects}) {
$_->offset([ @{shift @positions} ]) for @{$object->instances};
$_->set_offset(Slic3r::Pointf->new(@{shift @positions})) for @{$object->instances};
$object->update_bounding_box;
}
}
@ -231,8 +220,10 @@ sub center_instances_around_point {
foreach my $object (@{$self->objects}) {
foreach my $instance (@{$object->instances}) {
$instance->offset->[X] += $shift[X];
$instance->offset->[Y] += $shift[Y];
$instance->set_offset(Slic3r::Pointf->new(
$instance->offset->x + $shift[X],
$instance->offset->y + $shift[Y], #++
));
}
$object->update_bounding_box;
}
@ -276,7 +267,7 @@ sub split_meshes {
if (@{$object->volumes} > 1) {
# We can't split meshes if there's more than one material, because
# we can't group the resulting meshes by object afterwards
push @{$self->objects}, $object;
$self->_add_object($object);
next;
}
@ -286,6 +277,7 @@ sub split_meshes {
input_file => $object->input_file,
config => $object->config->clone,
layer_height_ranges => $object->layer_height_ranges, # TODO: this needs to be cloned
origin_translation => $object->origin_translation,
);
$new_object->add_volume(
mesh => $mesh,
@ -312,57 +304,40 @@ sub get_material_name {
my ($material_id) = @_;
my $name;
if (exists $self->materials->{$material_id}) {
$name //= $self->materials->{$material_id}->attributes->{$_} for qw(Name name);
if ($self->has_material($material_id)) {
$name //= $self->get_material($material_id)
->attributes->{$_} for qw(Name name);
}
$name //= $material_id;
return $name;
}
package Slic3r::Model::Material;
use Moo;
has 'model' => (is => 'ro', weak_ref => 1, required => 1);
has 'attributes' => (is => 'rw', default => sub { {} });
has 'config' => (is => 'rw', default => sub { Slic3r::Config->new });
package Slic3r::Model::Object;
use Moo;
use File::Basename qw(basename);
use List::Util qw(first sum);
use Slic3r::Geometry qw(X Y Z rad2deg);
has 'input_file' => (is => 'rw');
has 'model' => (is => 'ro', weak_ref => 1, required => 1);
has 'volumes' => (is => 'ro', default => sub { [] });
has 'instances' => (is => 'rw');
has 'config' => (is => 'rw', default => sub { Slic3r::Config->new });
has 'layer_height_ranges' => (is => 'rw', default => sub { [] }); # [ z_min, z_max, layer_height ]
has '_bounding_box' => (is => 'rw');
has 'origin_translation' => (is => 'ro', default => sub { Slic3r::Point->new }); # translation vector applied by center_around_origin()
sub add_volume {
my $self = shift;
my $new_volume;
if (@_ == 1) {
# we have a Model::Volume
my ($volume) = @_;
$new_volume = Slic3r::Model::Volume->new(
object => $self,
material_id => $volume->material_id,
mesh => $volume->mesh->clone,
modifier => $volume->modifier,
);
$new_volume = $self->_add_volume(
$volume->material_id, $volume->mesh->clone, $volume->modifier);
# TODO: material_id can't be undef.
if (defined $volume->material_id) {
# merge material attributes and config (should we rename materials in case of duplicates?)
if (my $material = $volume->object->model->materials->{$volume->material_id}) {
if (my $material = $volume->object->model->get_material($volume->material_id)) {
my %attributes = %{ $material->attributes };
if (exists $self->model->materials->{$volume->material_id}) {
%attributes = (%attributes, %{ $self->model->materials->{$volume->material_id}->attributes })
if ($self->model->has_material($volume->material_id)) {
%attributes = (%attributes, %{ $self->model->get_material($volume->material_id)->attributes })
}
my $new_material = $self->model->set_material($volume->material_id, {%attributes});
$new_material->config->apply($material->config);
@ -370,10 +345,10 @@ sub add_volume {
}
} else {
my %args = @_;
$new_volume = Slic3r::Model::Volume->new(
object => $self,
%args,
);
$new_volume = $self->_add_volume(
$args{material_id},
$args{mesh},
$args{modifier} // 0);
}
if (defined $new_volume->material_id && !defined $self->model->get_material($new_volume->material_id)) {
@ -381,33 +356,19 @@ sub add_volume {
$self->model->set_material($new_volume->material_id);
}
push @{$self->volumes}, $new_volume;
# invalidate cached bounding box
$self->_bounding_box(undef);
$self->invalidate_bounding_box();
return $new_volume;
}
sub delete_volume {
my ($self, $i) = @_;
splice @{$self->volumes}, $i, 1;
}
sub add_instance {
my $self = shift;
my %params = @_;
$self->instances([]) if !defined $self->instances;
push @{$self->instances}, my $i = Slic3r::Model::Instance->new(object => $self, %params);
$self->_bounding_box(undef);
return $i;
}
sub delete_last_instance {
my ($self) = @_;
pop @{$self->instances};
$self->_bounding_box(undef);
return $self->_add_instance(
$params{rotation} // 0,
$params{scaling_factor} // 1,
$params{offset} // []);
}
sub instances_count {
@ -487,8 +448,9 @@ sub center_around_origin {
if (defined $self->instances) {
foreach my $instance (@{ $self->instances }) {
$instance->offset->[X] -= $shift[X];
$instance->offset->[Y] -= $shift[Y];
$instance->set_offset(Slic3r::Pointf->new(
$instance->offset->x - $shift[X],
$instance->offset->y - $shift[Y]));
}
$self->update_bounding_box;
}
@ -511,7 +473,7 @@ sub rotate_x {
$angle = rad2deg($angle);
$_->mesh->rotate_x($angle) for @{$self->volumes};
$self->_bounding_box(undef);
$self->invalidate_bounding_box;
}
sub materials_count {
@ -577,22 +539,22 @@ sub cut {
# clone this one
my $upper = Slic3r::Model::Object->new(
input_file => $self->input_file,
model => $self->model,
config => $self->config->clone,
layer_height_ranges => $self->layer_height_ranges,
origin_translation => $self->origin_translation->clone,
$self->model,
$self->input_file,
$self->config, # config is cloned by new()
$self->layer_height_ranges,
$self->origin_translation,
);
my $lower = Slic3r::Model::Object->new(
input_file => $self->input_file,
model => $self->model,
config => $self->config->clone,
layer_height_ranges => $self->layer_height_ranges,
origin_translation => $self->origin_translation->clone,
$self->model,
$self->input_file,
$self->config, # config is cloned by new()
$self->layer_height_ranges,
$self->origin_translation,
);
foreach my $instance (@{$self->instances}) {
$upper->add_instance(offset => $instance->offset);
$lower->add_instance(offset => $instance->offset);
$upper->add_instance(offset => [ @{$instance->offset} ]);
$lower->add_instance(offset => [ @{$instance->offset} ]);
}
foreach my $volume (@{$self->volumes}) {
@ -632,29 +594,17 @@ sub cut {
}
package Slic3r::Model::Volume;
use Moo;
has 'object' => (is => 'ro', weak_ref => 1, required => 1);
has 'material_id' => (is => 'rw');
has 'mesh' => (is => 'rw', required => 1);
has 'modifier' => (is => 'rw', defualt => sub { 0 });
sub assign_unique_material {
my ($self) = @_;
my $model = $self->object->model;
my $material_id = 1 + scalar keys %{$model->materials};
my $material_id = 1 + $model->material_count;
$self->material_id($material_id);
return $model->set_material($material_id);
}
package Slic3r::Model::Instance;
use Moo;
has 'object' => (is => 'ro', weak_ref => 1, required => 1);
has 'rotation' => (is => 'rw', default => sub { 0 }); # around mesh center point
has 'scaling_factor' => (is => 'rw', default => sub { 1 });
has 'offset' => (is => 'rw'); # must be arrayref in *unscaled* coordinates
sub transform_mesh {
my ($self, $mesh, $dont_translate) = @_;

View file

@ -86,7 +86,7 @@ sub apply_config {
$new->apply_dynamic($model_object_config);
}
if (defined $volume->material_id) {
my $material_config = $object->model_object->model->materials->{$volume->material_id}->config->clone;
my $material_config = $object->model_object->model->get_material($volume->material_id)->config->clone;
$material_config->normalize;
$new->apply_dynamic($material_config);
}
@ -104,9 +104,8 @@ sub apply_config {
if ($rearrange_regions) {
# the current subdivision of regions does not make sense anymore.
# we need to remove all objects and re-add them
my @model_objects = map $_->model_object, @{$self->objects};
$self->delete_all_objects;
$self->add_model_object($_) for @model_objects;
$self->clear_objects;
$self->add_model_object($_->model_object) for @{$self->objects};
}
}
@ -138,7 +137,7 @@ sub add_model_object {
$config->apply_dynamic($object_config);
if (defined $volume->material_id) {
my $material_config = $object->model->materials->{ $volume->material_id }->config->clone;
my $material_config = $object->model->get_material($volume->material_id)->config->clone;
$material_config->normalize;
$config->apply_dynamic($material_config);
}
@ -201,7 +200,7 @@ sub delete_object {
$self->_state->invalidate(STEP_BRIM);
}
sub delete_all_objects {
sub clear_objects {
my ($self) = @_;
@{$self->objects} = ();
@ -220,9 +219,9 @@ sub reload_object {
# For now we just re-add all objects since we haven't implemented this incremental logic yet.
# This should also check whether object volumes (parts) have changed.
my @model_objects = map $_->model_object, @{$self->objects};
$self->delete_all_objects;
$self->add_model_object($_) for @model_objects;
my @models_objects = map $_->model_object, @{$self->objects};
$self->clear_objects;
$self->add_model_object($_) for @models_objects;
}
sub validate {
@ -1116,7 +1115,7 @@ sub auto_assign_extruders {
foreach my $i (0..$#{$model_object->volumes}) {
my $volume = $model_object->volumes->[$i];
if (defined $volume->material_id) {
my $material = $model_object->model->materials->{ $volume->material_id };
my $material = $model_object->model->get_material($volume->material_id);
my $config = $material->config;
my $extruder_id = $i + 1;
$config->set_ifndef('extruder', $extruder_id);

View file

@ -10,7 +10,7 @@ use Slic3r::Print::State ':steps';
use Slic3r::Surface ':types';
has 'print' => (is => 'ro', weak_ref => 1, required => 1);
has 'model_object' => (is => 'ro', required => 1);
has 'model_object' => (is => 'ro', required => 1); # caller is responsible for holding the Model object
has 'region_volumes' => (is => 'rw', default => sub { [] }); # by region_id
has 'copies' => (is => 'ro'); # Slic3r::Point objects in scaled G-code coordinates
has 'config' => (is => 'ro', default => sub { Slic3r::Config::PrintObject->new });

View file

@ -44,15 +44,15 @@ sub set_model {
my ($self, $model) = @_;
# make method idempotent so that the object is reusable
$self->_print->delete_all_objects;
$self->_print->clear_objects;
# make sure all objects have at least one defined instance
my $need_arrange = $model->add_default_instances;
# apply scaling and rotation supplied from command line if any
foreach my $instance (map @{$_->instances}, @{$model->objects}) {
$instance->scaling_factor($instance->scaling_factor * $self->scale);
$instance->rotation($instance->rotation + $self->rotate);
$instance->set_scaling_factor($instance->scaling_factor * $self->scale);
$instance->set_rotation($instance->rotation + $self->rotate);
}
if ($self->duplicate_grid->[X] > 1 || $self->duplicate_grid->[Y] > 1) {