Refactoring to Model API for making it stricter and safer

This commit is contained in:
Alessandro Ranellucci 2014-05-09 14:24:35 +02:00
parent bc023c2d51
commit 7ba08c90cf
17 changed files with 316 additions and 317 deletions

View File

@ -126,7 +126,7 @@ sub end_document {
foreach my $instance (@{ $self->{_instances}{$object_id} }) { foreach my $instance (@{ $self->{_instances}{$object_id} }) {
$self->{_model}->objects->[$new_object_id]->add_instance( $self->{_model}->objects->[$new_object_id]->add_instance(
rotation => $instance->{rz} || 0, rotation => $instance->{rz} || 0,
offset => [ $instance->{deltax} || 0, $instance->{deltay} || 0 ], offset => Slic3r::Pointf->new($instance->{deltax} || 0, $instance->{deltay} || 0),
); );
} }
} }

View File

@ -409,7 +409,7 @@ sub load_model_objects {
# add a default instance and center object around origin # add a default instance and center object around origin
$o->center_around_origin; $o->center_around_origin;
$o->add_instance(offset => [ @{$self->{config}->print_center} ]); $o->add_instance(offset => Slic3r::Pointf->new(@{$self->{config}->print_center}));
} }
$self->{print}->auto_assign_extruders($o); $self->{print}->auto_assign_extruders($o);
@ -487,7 +487,7 @@ sub increase {
my $model_object = $self->{model}->objects->[$obj_idx]; my $model_object = $self->{model}->objects->[$obj_idx];
my $last_instance = $model_object->instances->[-1]; my $last_instance = $model_object->instances->[-1];
my $i = $model_object->add_instance( my $i = $model_object->add_instance(
offset => [ map 10+$_, @{$last_instance->offset} ], offset => Slic3r::Pointf->new(map 10+$_, @{$last_instance->offset}),
scaling_factor => $last_instance->scaling_factor, scaling_factor => $last_instance->scaling_factor,
rotation => $last_instance->rotation, rotation => $last_instance->rotation,
); );
@ -654,10 +654,10 @@ sub split_object {
for my $instance_idx (0..$#{ $current_model_object->instances }) { for my $instance_idx (0..$#{ $current_model_object->instances }) {
my $current_instance = $current_model_object->instances->[$instance_idx]; my $current_instance = $current_model_object->instances->[$instance_idx];
$model_object->add_instance( $model_object->add_instance(
offset => [ offset => Slic3r::Pointf->new(
$current_instance->offset->[X] + ($instance_idx * 10), $current_instance->offset->[X] + ($instance_idx * 10),
$current_instance->offset->[Y] + ($instance_idx * 10), $current_instance->offset->[Y] + ($instance_idx * 10),
], ),
rotation => $current_instance->rotation, rotation => $current_instance->rotation,
scaling_factor => $current_instance->scaling_factor, scaling_factor => $current_instance->scaling_factor,
); );

View File

@ -31,48 +31,34 @@ sub merge {
sub add_object { sub add_object {
my $self = shift; my $self = shift;
my $new_object;
if (@_ == 1) { if (@_ == 1) {
# we have a Model::Object # we have a Model::Object
my ($object) = @_; my ($object) = @_;
return $self->_add_object_clone($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}) {
$new_object->add_volume($volume);
}
$new_object->add_instance(
offset => [ @{$_->offset} ],
rotation => $_->rotation,
scaling_factor => $_->scaling_factor,
) for @{ $object->instances // [] };
} else { } else {
my (%args) = @_; 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; my $new_object = $self->_add_object;
$new_object->set_input_file($args{input_file})
if defined $args{input_file};
$new_object->config->apply($args{config})
if defined $args{config};
$new_object->set_layer_height_ranges($args{layer_height_ranges})
if defined $args{layer_height_ranges};
$new_object->set_origin_translation($args{origin_translation})
if defined $args{origin_translation};
return $new_object;
}
} }
sub set_material { sub set_material {
my $self = shift; my $self = shift;
my ($material_id, $attributes) = @_; my ($material_id, $attributes) = @_;
$attributes //= {}; my $material = $self->add_material($material_id);
$material->apply($attributes // {});
my $material = $self->_set_material($material_id);
$material->set_attribute($_, $attributes->{$_}) for keys %$attributes;
return $material; return $material;
} }
@ -89,10 +75,10 @@ sub duplicate_objects_grid {
for my $x_copy (1..$grid->[X]) { for my $x_copy (1..$grid->[X]) {
for my $y_copy (1..$grid->[Y]) { for my $y_copy (1..$grid->[Y]) {
$object->add_instance( $object->add_instance(
offset => [ offset => Slic3r::Pointf->new(
($size->[X] + $distance) * ($x_copy-1), ($size->[X] + $distance) * ($x_copy-1),
($size->[Y] + $distance) * ($y_copy-1), ($size->[Y] + $distance) * ($y_copy-1),
], ),
); );
} }
} }
@ -106,12 +92,7 @@ sub duplicate_objects {
foreach my $object (@{$self->objects}) { foreach my $object (@{$self->objects}) {
my @instances = @{$object->instances}; my @instances = @{$object->instances};
foreach my $instance (@instances) { foreach my $instance (@instances) {
### $object->add_instance($instance->clone); if we had clone() $object->add_instance($instance) for 2..$copies_num;
$object->add_instance(
offset => [ @{$instance->offset} ],
rotation => $instance->rotation,
scaling_factor => $instance->scaling_factor,
) for 2..$copies_num;
} }
} }
@ -151,9 +132,8 @@ sub duplicate {
my @instances = @{$object->instances}; # store separately to avoid recursion from add_instance() below my @instances = @{$object->instances}; # store separately to avoid recursion from add_instance() below
foreach my $instance (@instances) { foreach my $instance (@instances) {
foreach my $pos (@positions) { foreach my $pos (@positions) {
### $object->add_instance($instance->clone); if we had clone()
$object->add_instance( $object->add_instance(
offset => [ $instance->offset->[X] + $pos->[X], $instance->offset->[Y] + $pos->[Y] ], offset => Slic3r::Pointf->new($instance->offset->[X] + $pos->[X], $instance->offset->[Y] + $pos->[Y]),
rotation => $instance->rotation, rotation => $instance->rotation,
scaling_factor => $instance->scaling_factor, scaling_factor => $instance->scaling_factor,
); );
@ -187,8 +167,8 @@ sub add_default_instances {
# apply a default position to all objects not having one # apply a default position to all objects not having one
my $added = 0; my $added = 0;
foreach my $object (@{$self->objects}) { foreach my $object (@{$self->objects}) {
if (!defined $object->instances) { if ($object->instances_count == 0) {
$object->add_instance(offset => [0,0]); $object->add_instance(offset => Slic3r::Pointf->new(0,0));
$added = 1; $added = 1;
} }
} }
@ -286,7 +266,7 @@ sub split_meshes {
# add one instance per original instance # add one instance per original instance
$new_object->add_instance( $new_object->add_instance(
offset => [ @{$_->offset} ], offset => Slic3r::Pointf->new(@{$_->offset}),
rotation => $_->rotation, rotation => $_->rotation,
scaling_factor => $_->scaling_factor, scaling_factor => $_->scaling_factor,
) for @{ $object->instances // [] }; ) for @{ $object->instances // [] };
@ -314,6 +294,11 @@ sub get_material_name {
package Slic3r::Model::Material; package Slic3r::Model::Material;
sub apply {
my ($self, $attributes) = @_;
$self->set_attribute($_, $attributes{$_}) for keys %$attributes;
}
package Slic3r::Model::Object; package Slic3r::Model::Object;
use File::Basename qw(basename); use File::Basename qw(basename);
@ -328,8 +313,7 @@ sub add_volume {
# we have a Model::Volume # we have a Model::Volume
my ($volume) = @_; my ($volume) = @_;
$new_volume = $self->_add_volume( $new_volume = $self->_add_volume_clone($volume);
$volume->material_id, $volume->mesh->clone, $volume->modifier);
# TODO: material_id can't be undef. # TODO: material_id can't be undef.
if (defined $volume->material_id) { if (defined $volume->material_id) {
@ -345,10 +329,13 @@ sub add_volume {
} }
} else { } else {
my %args = @_; my %args = @_;
$new_volume = $self->_add_volume(
$args{material_id}, $new_volume = $self->_add_volume($args{mesh});
$args{mesh},
$args{modifier} // 0); $new_volume->set_material_id($args{material_id})
if defined $args{material_id};
$new_volume->set_modifier($args{modifier})
if defined $args{modifier};
} }
if (defined $new_volume->material_id && !defined $self->model->get_material($new_volume->material_id)) { if (defined $new_volume->material_id && !defined $self->model->get_material($new_volume->material_id)) {
@ -356,7 +343,7 @@ sub add_volume {
$self->model->set_material($new_volume->material_id); $self->model->set_material($new_volume->material_id);
} }
$self->invalidate_bounding_box(); $self->invalidate_bounding_box;
return $new_volume; return $new_volume;
} }
@ -365,15 +352,24 @@ sub add_instance {
my $self = shift; my $self = shift;
my %params = @_; my %params = @_;
return $self->_add_instance( if (@_ == 1) {
$params{rotation} // 0, # we have a Model::Instance
$params{scaling_factor} // 1, my ($instance) = @_;
$params{offset} // []); return $self->_add_instance_clone($instance);
} } else {
my (%args) = @_;
sub instances_count { my $new_instance = $self->_add_instance;
my $self = shift;
return scalar(@{ $self->instances // [] }); $new_instance->set_rotation($args{rotation})
if defined $args{rotation};
$new_instance->set_scaling_factor($args{scaling_factor})
if defined $args{scaling_factor};
$new_instance->set_offset($args{offset})
if defined $args{offset};
return $new_instance;
}
} }
sub raw_mesh { sub raw_mesh {
@ -446,11 +442,12 @@ sub center_around_origin {
$self->translate(@shift); $self->translate(@shift);
$self->origin_translation->translate(@shift[X,Y]); $self->origin_translation->translate(@shift[X,Y]);
if (defined $self->instances) { if ($self->instances_count > 0) {
foreach my $instance (@{ $self->instances }) { foreach my $instance (@{ $self->instances }) {
$instance->set_offset(Slic3r::Pointf->new( $instance->set_offset(Slic3r::Pointf->new(
$instance->offset->x - $shift[X], $instance->offset->x - $shift[X],
$instance->offset->y - $shift[Y])); $instance->offset->y - $shift[Y], #--
));
} }
$self->update_bounding_box; $self->update_bounding_box;
} }
@ -538,23 +535,12 @@ sub cut {
my ($self, $z) = @_; my ($self, $z) = @_;
# clone this one # clone this one
my $upper = Slic3r::Model::Object->new( my $upper = $self->model->add_object($self);
$self->model, my $lower = $self->model->add_object($self);
$self->input_file,
$self->config, # config is cloned by new()
$self->layer_height_ranges,
$self->origin_translation,
);
my $lower = Slic3r::Model::Object->new(
$self->model,
$self->input_file,
$self->config, # config is cloned by new()
$self->layer_height_ranges,
$self->origin_translation,
);
foreach my $instance (@{$self->instances}) { foreach my $instance (@{$self->instances}) {
$upper->add_instance(offset => [ @{$instance->offset} ]); $upper->add_instance(offset => Slic3r::Pointf->new(@{$instance->offset}));
$lower->add_instance(offset => [ @{$instance->offset} ]); $lower->add_instance(offset => Slic3r::Pointf->new(@{$instance->offset}));
} }
foreach my $volume (@{$self->volumes}) { foreach my $volume (@{$self->volumes}) {

View File

@ -124,9 +124,9 @@ sub model {
$model->set_material($model_name); $model->set_material($model_name);
$object->add_volume(mesh => mesh($model_name, %params), material_id => $model_name); $object->add_volume(mesh => mesh($model_name, %params), material_id => $model_name);
$object->add_instance( $object->add_instance(
offset => [0,0], offset => Slic3r::Pointf->new(0,0),
rotation => $params{rotation} // 0, rotation => $params{rotation} // 0,
scaling_factor => $params{scale} // 1, scaling_factor => $params{scale} // 1,
); );
return $model; return $model;
} }
@ -142,7 +142,8 @@ sub init_print {
$print->apply_config($config); $print->apply_config($config);
$models = [$models] if ref($models) ne 'ARRAY'; $models = [$models] if ref($models) ne 'ARRAY';
for my $model (map { ref($_) ? $_ : model($_, %params) } @$models) { $models = [ map { ref($_) ? $_ : model($_, %params) } @$models ];
for my $model (@$models) {
die "Unknown model in test" if !defined $model; die "Unknown model in test" if !defined $model;
if (defined $params{duplicate} && $params{duplicate} > 1) { if (defined $params{duplicate} && $params{duplicate} > 1) {
$model->duplicate($params{duplicate} // 1, $print->config->min_object_distance); $model->duplicate($params{duplicate} // 1, $print->config->min_object_distance);
@ -156,12 +157,18 @@ sub init_print {
} }
$print->validate; $print->validate;
return $print; # We return a proxy object in order to keep $models alive as required by the Print API.
return Slic3r::Test::Print->new(
print => $print,
models => $models,
);
} }
sub gcode { sub gcode {
my ($print) = @_; my ($print) = @_;
$print = $print->print if $print->isa('Slic3r::Test::Print');
my $fh = IO::Scalar->new(\my $gcode); my $fh = IO::Scalar->new(\my $gcode);
$print->process; $print->process;
$print->export_gcode(output_fh => $fh, quiet => 1); $print->export_gcode(output_fh => $fh, quiet => 1);
@ -189,4 +196,10 @@ sub add_facet {
} }
} }
package Slic3r::Test::Print;
use Moo;
has 'print' => (is => 'ro', required => 1);
has 'models' => (is => 'ro', required => 1);
1; 1;

View File

@ -57,7 +57,7 @@ use Slic3r::Test;
$config->set('start_gcode', "TRAVEL:[travel_speed] HEIGHT:[layer_height]\n"); $config->set('start_gcode', "TRAVEL:[travel_speed] HEIGHT:[layer_height]\n");
my $print = Slic3r::Test::init_print('20mm_cube', config => $config); my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
my $output_file = $print->expanded_output_filepath; my $output_file = $print->print->expanded_output_filepath;
ok $output_file !~ /\[travel_speed\]/, 'print config options are replaced in output filename'; ok $output_file !~ /\[travel_speed\]/, 'print config options are replaced in output filename';
ok $output_file !~ /\[layer_height\]/, 'region config options are replaced in output filename'; ok $output_file !~ /\[layer_height\]/, 'region config options are replaced in output filename';

View File

@ -78,7 +78,7 @@ use Slic3r::Test;
}); });
ok $print->total_used_filament > 0, 'final retraction is not considered in total used filament'; ok $print->print->total_used_filament > 0, 'final retraction is not considered in total used filament';
} }
{ {

View File

@ -173,7 +173,7 @@ sub stacked_cubes {
my $object = $model->add_object; my $object = $model->add_object;
$object->add_volume(mesh => Slic3r::Test::mesh('20mm_cube'), material_id => 'lower'); $object->add_volume(mesh => Slic3r::Test::mesh('20mm_cube'), material_id => 'lower');
$object->add_volume(mesh => Slic3r::Test::mesh('20mm_cube', translate => [0,0,20]), material_id => 'upper'); $object->add_volume(mesh => Slic3r::Test::mesh('20mm_cube', translate => [0,0,20]), material_id => 'upper');
$object->add_instance(offset => [0,0]); $object->add_instance(offset => Slic3r::Pointf->new(0,0));
return $model; return $model;
} }

File diff suppressed because one or more lines are too long

View File

@ -38,21 +38,21 @@ use Slic3r::Test;
my $print = Slic3r::Test::init_print(my $model = Slic3r::Test::model('20mm_cube'), config => $config); my $print = Slic3r::Test::init_print(my $model = Slic3r::Test::model('20mm_cube'), config => $config);
# user sets a per-region option # user sets a per-region option
$print->objects->[0]->model_object->config->set('fill_density', 100); $print->print->objects->[0]->model_object->config->set('fill_density', 100);
$print->reload_object(0); $print->print->reload_object(0);
# user exports G-code, thus the default config is reapplied # user exports G-code, thus the default config is reapplied
$print->apply_config($config); $print->print->apply_config($config);
is $print->regions->[0]->config->fill_density, 100, 'apply_config() does not override per-object settings'; is $print->print->regions->[0]->config->fill_density, 100, 'apply_config() does not override per-object settings';
# user assigns object extruders # user assigns object extruders
$print->objects->[0]->model_object->config->set('extruder', 3); $print->print->objects->[0]->model_object->config->set('extruder', 3);
$print->objects->[0]->model_object->config->set('perimeter_extruder', 2); $print->print->objects->[0]->model_object->config->set('perimeter_extruder', 2);
$print->reload_object(0); $print->print->reload_object(0);
is $print->regions->[0]->config->infill_extruder, 3, 'extruder setting is correctly expanded'; is $print->print->regions->[0]->config->infill_extruder, 3, 'extruder setting is correctly expanded';
is $print->regions->[0]->config->perimeter_extruder, 2, 'extruder setting does not override explicitely specified extruders'; is $print->print->regions->[0]->config->perimeter_extruder, 2, 'extruder setting does not override explicitely specified extruders';
} }
__END__ __END__

View File

@ -42,8 +42,8 @@ use Slic3r::Test qw(_eq);
if ($info->{dist_Z}) { if ($info->{dist_Z}) {
# lift move or lift + change layer # lift move or lift + change layer
if (_eq($info->{dist_Z}, $print->config->get_at('retract_lift', $tool)) if (_eq($info->{dist_Z}, $print->print->config->get_at('retract_lift', $tool))
|| (_eq($info->{dist_Z}, $conf->layer_height + $print->config->get_at('retract_lift', $tool)) && $print->config->get_at('retract_lift', $tool) > 0)) { || (_eq($info->{dist_Z}, $conf->layer_height + $print->print->config->get_at('retract_lift', $tool)) && $print->print->config->get_at('retract_lift', $tool) > 0)) {
fail 'only lifting while retracted' if !$retracted[$tool] && !($conf->g0 && $info->{retracting}); fail 'only lifting while retracted' if !$retracted[$tool] && !($conf->g0 && $info->{retracting});
fail 'double lift' if $lifted; fail 'double lift' if $lifted;
$lifted = 1; $lifted = 1;
@ -51,8 +51,8 @@ use Slic3r::Test qw(_eq);
if ($info->{dist_Z} < 0) { if ($info->{dist_Z} < 0) {
fail 'going down only after lifting' if !$lifted; fail 'going down only after lifting' if !$lifted;
fail 'going down by the same amount of the lift or by the amount needed to get to next layer' fail 'going down by the same amount of the lift or by the amount needed to get to next layer'
if !_eq($info->{dist_Z}, -$print->config->get_at('retract_lift', $tool)) if !_eq($info->{dist_Z}, -$print->print->config->get_at('retract_lift', $tool))
&& !_eq($info->{dist_Z}, -$print->config->get_at('retract_lift', $tool) + $conf->layer_height); && !_eq($info->{dist_Z}, -$print->print->config->get_at('retract_lift', $tool) + $conf->layer_height);
$lifted = 0; $lifted = 0;
} }
fail 'move Z at travel speed' if ($args->{F} // $self->F) != $conf->travel_speed * 60; fail 'move Z at travel speed' if ($args->{F} // $self->F) != $conf->travel_speed * 60;
@ -60,9 +60,9 @@ use Slic3r::Test qw(_eq);
if ($info->{retracting}) { if ($info->{retracting}) {
$retracted[$tool] = 1; $retracted[$tool] = 1;
$retracted_length[$tool] += -$info->{dist_E}; $retracted_length[$tool] += -$info->{dist_E};
if (_eq($retracted_length[$tool], $print->config->get_at('retract_length', $tool))) { if (_eq($retracted_length[$tool], $print->print->config->get_at('retract_length', $tool))) {
# okay # okay
} elsif (_eq($retracted_length[$tool], $print->config->get_at('retract_length_toolchange', $tool))) { } elsif (_eq($retracted_length[$tool], $print->print->config->get_at('retract_length_toolchange', $tool))) {
$wait_for_toolchange = 1; $wait_for_toolchange = 1;
} else { } else {
fail 'retracted by the correct amount'; fail 'retracted by the correct amount';
@ -73,9 +73,9 @@ use Slic3r::Test qw(_eq);
if ($info->{extruding}) { if ($info->{extruding}) {
fail 'only extruding while not lifted' if $lifted; fail 'only extruding while not lifted' if $lifted;
if ($retracted[$tool]) { if ($retracted[$tool]) {
my $expected_amount = $retracted_length[$tool] + $print->config->get_at('retract_restart_extra', $tool); my $expected_amount = $retracted_length[$tool] + $print->print->config->get_at('retract_restart_extra', $tool);
if ($changed_tool && $toolchange_count[$tool] > 1) { if ($changed_tool && $toolchange_count[$tool] > 1) {
$expected_amount = $print->config->get_at('retract_length_toolchange', $tool) + $print->config->get_at('retract_restart_extra_toolchange', $tool); $expected_amount = $print->print->config->get_at('retract_length_toolchange', $tool) + $print->print->config->get_at('retract_restart_extra_toolchange', $tool);
$changed_tool = 0; $changed_tool = 0;
} }
fail 'unretracted by the correct amount' fail 'unretracted by the correct amount'
@ -84,7 +84,7 @@ use Slic3r::Test qw(_eq);
$retracted_length[$tool] = 0; $retracted_length[$tool] = 0;
} }
} }
if ($info->{travel} && $info->{dist_XY} >= $print->config->get_at('retract_before_travel', $tool)) { if ($info->{travel} && $info->{dist_XY} >= $print->print->config->get_at('retract_before_travel', $tool)) {
fail 'retracted before long travel move' if !$retracted[$tool]; fail 'retracted before long travel move' if !$retracted[$tool];
} }
}); });

View File

@ -20,12 +20,12 @@ use Slic3r::Test;
my $test = sub { my $test = sub {
my $print = Slic3r::Test::init_print('20mm_cube', config => $config); my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
$print->init_extruders; $print->print->init_extruders;
my $flow = $print->objects->[0]->support_material_flow; my $flow = $print->print->objects->[0]->support_material_flow;
my $support_z = Slic3r::Print::SupportMaterial my $support_z = Slic3r::Print::SupportMaterial
->new( ->new(
object_config => $print->objects->[0]->config, object_config => $print->print->objects->[0]->config,
print_config => $print->config, print_config => $print->print->config,
flow => $flow, flow => $flow,
interface_flow => $flow, interface_flow => $flow,
first_layer_flow => $flow, first_layer_flow => $flow,

View File

@ -14,7 +14,7 @@ use Slic3r::Test;
my $print = Slic3r::Test::init_print('20mm_cube'); my $print = Slic3r::Test::init_print('20mm_cube');
eval { eval {
my $fh = IO::Scalar->new(\my $gcode); my $fh = IO::Scalar->new(\my $gcode);
$print->export_svg(output_fh => $fh, quiet => 1); $print->print->export_svg(output_fh => $fh, quiet => 1);
$fh->close; $fh->close;
}; };
ok !$@, 'successful SVG export'; ok !$@, 'successful SVG export';

View File

@ -18,7 +18,7 @@ $ARGV[0] or usage(1);
if (-e $ARGV[0]) { if (-e $ARGV[0]) {
my $model = Slic3r::Format::STL->read_file($ARGV[0]); my $model = Slic3r::Format::STL->read_file($ARGV[0]);
$model->objects->[0]->add_instance(offset => [0,0]); $model->objects->[0]->add_instance(offset => Slic3r::Pointf->new(0,0));
my $mesh = $model->mesh; my $mesh = $model->mesh;
$mesh->repair; $mesh->repair;
printf "VERTICES = %s\n", join ',', map "[$_->[0],$_->[1],$_->[2]]", @{$mesh->vertices}; printf "VERTICES = %s\n", join ',', map "[$_->[0],$_->[1],$_->[2]]", @{$mesh->vertices};

View File

@ -11,7 +11,8 @@ use Module::Build::WithXSpp;
# NOGDI : prevents inclusion of wingdi.h which defines functions Polygon() and Polyline() in global namespace # NOGDI : prevents inclusion of wingdi.h which defines functions Polygon() and Polyline() in global namespace
my @cflags = qw(-D_GLIBCXX_USE_C99 -DHAS_BOOL -DNOGDI -DSLIC3RXS); my @cflags = qw(-D_GLIBCXX_USE_C99 -DHAS_BOOL -DNOGDI -DSLIC3RXS);
if ($ENV{SLIC3R_DEBUG}) { if ($ENV{SLIC3R_DEBUG}) {
push @cflags, qw(-DSLIC3R_DEBUG -g -ftemplate-backtrace-limit=0); # only on newer GCCs: -ftemplate-backtrace-limit=0
push @cflags, qw(-DSLIC3R_DEBUG -g);
} }
if (ExtUtils::CppGuess->new->is_gcc) { if (ExtUtils::CppGuess->new->is_gcc) {
# check whether we're dealing with a buggy GCC version # check whether we're dealing with a buggy GCC version

View File

@ -6,24 +6,14 @@ Model::Model() {}
Model::Model(const Model &other) Model::Model(const Model &other)
{ {
objects.reserve(other.objects.size()); // copy materials
for (ModelMaterialMap::const_iterator i = other.materials.begin(); i != other.materials.end(); ++i)
this->add_material(i->first, *i->second);
for (ModelMaterialMap::const_iterator i = other.materials.begin(); // copy objects
i != other.materials.end(); ++i) this->objects.reserve(other.objects.size());
{ for (ModelObjectPtrs::const_iterator i = other.objects.begin(); i != other.objects.end(); ++i)
ModelMaterial *copy = new ModelMaterial(*i->second); this->add_object(**i);
copy->model = this;
materials[i->first] = copy;
}
for (ModelObjectPtrs::const_iterator i = other.objects.begin();
i != other.objects.end(); ++i)
{
ModelObject *copy = new ModelObject(**i);
copy->model = this;
objects.push_back(copy);
}
} }
Model& Model::operator= (Model other) Model& Model::operator= (Model other)
@ -46,13 +36,19 @@ Model::~Model()
} }
ModelObject* ModelObject*
Model::add_object(const std::string &input_file, const DynamicPrintConfig &config, Model::add_object()
const t_layer_height_ranges &layer_height_ranges, const Pointf &origin_translation)
{ {
ModelObject* object = new ModelObject(this, input_file, config, ModelObject* new_object = new ModelObject(this);
layer_height_ranges, origin_translation); this->objects.push_back(new_object);
this->objects.push_back(object); return new_object;
return object; }
ModelObject*
Model::add_object(const ModelObject &other)
{
ModelObject* new_object = new ModelObject(this, other);
this->objects.push_back(new_object);
return new_object;
} }
void void
@ -88,19 +84,40 @@ Model::clear_materials()
this->delete_material( this->materials.begin()->first ); this->delete_material( this->materials.begin()->first );
} }
ModelMaterial * ModelMaterial*
Model::set_material(t_model_material_id material_id) Model::add_material(t_model_material_id material_id)
{ {
ModelMaterialMap::iterator i = this->materials.find(material_id); ModelMaterial* material = this->get_material(material_id);
if (material == NULL) {
material = this->materials[material_id] = new ModelMaterial(this);
}
return material;
}
ModelMaterial *mat; ModelMaterial*
if (i == this->materials.end()) { Model::add_material(t_model_material_id material_id, const ModelMaterial &other)
mat = this->materials[material_id] = new ModelMaterial(this); {
} else { // delete existing material if any
mat = i->second; ModelMaterial* material = this->get_material(material_id);
if (material != NULL) {
delete material;
} }
return mat; // set new material
material = new ModelMaterial(this, other);
this->materials[material_id] = material;
return material;
}
ModelMaterial*
Model::get_material(t_model_material_id material_id)
{
ModelMaterialMap::iterator i = this->materials.find(material_id);
if (i == this->materials.end()) {
return NULL;
} else {
return i->second;
}
} }
/* /*
@ -147,6 +164,9 @@ REGISTER_CLASS(Model, "Model");
ModelMaterial::ModelMaterial(Model *model) : model(model) {} ModelMaterial::ModelMaterial(Model *model) : model(model) {}
ModelMaterial::ModelMaterial(Model *model, const ModelMaterial &other)
: model(model), config(other.config), attributes(other.attributes)
{}
void void
ModelMaterial::apply(const t_model_material_attributes &attributes) ModelMaterial::apply(const t_model_material_attributes &attributes)
@ -160,20 +180,12 @@ REGISTER_CLASS(ModelMaterial, "Model::Material");
#endif #endif
ModelObject::ModelObject(Model *model, const std::string &input_file, ModelObject::ModelObject(Model *model)
const DynamicPrintConfig &config, const t_layer_height_ranges &layer_height_ranges, : model(model)
const Pointf &origin_translation) {}
: model(model),
input_file(input_file),
config(config),
layer_height_ranges(layer_height_ranges),
origin_translation(origin_translation),
_bounding_box_valid(false)
{
}
ModelObject::ModelObject(const ModelObject &other) ModelObject::ModelObject(Model *model, const ModelObject &other)
: model(other.model), : model(model),
input_file(other.input_file), input_file(other.input_file),
instances(), instances(),
volumes(), volumes(),
@ -183,25 +195,14 @@ ModelObject::ModelObject(const ModelObject &other)
_bounding_box(other._bounding_box), _bounding_box(other._bounding_box),
_bounding_box_valid(other._bounding_box_valid) _bounding_box_valid(other._bounding_box_valid)
{ {
volumes.reserve(other.volumes.size());
instances.reserve(other.instances.size());
for (ModelVolumePtrs::const_iterator i = other.volumes.begin(); this->volumes.reserve(other.volumes.size());
i != other.volumes.end(); ++i) for (ModelVolumePtrs::const_iterator i = other.volumes.begin(); i != other.volumes.end(); ++i)
{ this->add_volume(**i);
ModelVolume *v = new ModelVolume(**i);
v->object = this;
volumes.push_back(v);
} this->instances.reserve(other.instances.size());
for (ModelInstancePtrs::const_iterator i = other.instances.begin(); i != other.instances.end(); ++i)
for (ModelInstancePtrs::const_iterator i = other.instances.begin(); this->add_instance(**i);
i != other.instances.end(); ++i)
{
ModelInstance *in = new ModelInstance(**i);
in->object = this;
instances.push_back(in);
}
} }
ModelObject& ModelObject::operator= (ModelObject other) ModelObject& ModelObject::operator= (ModelObject other)
@ -229,11 +230,19 @@ ModelObject::~ModelObject()
this->clear_instances(); this->clear_instances();
} }
ModelVolume * ModelVolume*
ModelObject::add_volume(const t_model_material_id &material_id, ModelObject::add_volume(const TriangleMesh &mesh)
const TriangleMesh &mesh, bool modifier)
{ {
ModelVolume *v = new ModelVolume(this, material_id, mesh, modifier); ModelVolume* v = new ModelVolume(this, mesh);
this->volumes.push_back(v);
this->invalidate_bounding_box();
return v;
}
ModelVolume*
ModelObject::add_volume(const ModelVolume &other)
{
ModelVolume* v = new ModelVolume(this, other);
this->volumes.push_back(v); this->volumes.push_back(v);
this->invalidate_bounding_box(); this->invalidate_bounding_box();
return v; return v;
@ -256,12 +265,19 @@ ModelObject::clear_volumes()
this->delete_volume(i); this->delete_volume(i);
} }
ModelInstance * ModelInstance*
ModelObject::add_instance(double rotation, double scaling_factor, ModelObject::add_instance()
Pointf offset)
{ {
ModelInstance *i = new ModelInstance( ModelInstance* i = new ModelInstance(this);
this, rotation, scaling_factor, offset); this->instances.push_back(i);
this->invalidate_bounding_box();
return i;
}
ModelInstance*
ModelObject::add_instance(const ModelInstance &other)
{
ModelInstance* i = new ModelInstance(this, other);
this->instances.push_back(i); this->instances.push_back(i);
this->invalidate_bounding_box(); this->invalidate_bounding_box();
return i; return i;
@ -300,28 +316,26 @@ REGISTER_CLASS(ModelObject, "Model::Object");
#endif #endif
ModelVolume::ModelVolume(ModelObject* object, const t_model_material_id &material_id, ModelVolume::ModelVolume(ModelObject* object, const TriangleMesh &mesh)
const TriangleMesh &mesh, bool modifier) : object(object), mesh(mesh), modifier(false)
: object(object), {}
material_id(material_id),
mesh(mesh), ModelVolume::ModelVolume(ModelObject* object, const ModelVolume &other)
modifier(modifier) : object(object), material_id(other.material_id), mesh(other.mesh), modifier(other.modifier)
{ {}
}
#ifdef SLIC3RXS #ifdef SLIC3RXS
REGISTER_CLASS(ModelVolume, "Model::Volume"); REGISTER_CLASS(ModelVolume, "Model::Volume");
#endif #endif
ModelInstance::ModelInstance(ModelObject *object, double rotation, ModelInstance::ModelInstance(ModelObject *object)
double scaling_factor, const Pointf &offset) : object(object), rotation(0), scaling_factor(1)
: object(object), {}
rotation(rotation),
scaling_factor(scaling_factor), ModelInstance::ModelInstance(ModelObject *object, const ModelInstance &other)
offset(offset) : object(object), rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset)
{ {}
}
#ifdef SLIC3RXS #ifdef SLIC3RXS
REGISTER_CLASS(ModelInstance, "Model::Instance"); REGISTER_CLASS(ModelInstance, "Model::Instance");

View File

@ -38,13 +38,16 @@ class Model
Model& operator= (Model other); Model& operator= (Model other);
void swap(Model &other); void swap(Model &other);
~Model(); ~Model();
ModelObject* add_object(const std::string &input_file, const DynamicPrintConfig &config, ModelObject* add_object();
const t_layer_height_ranges &layer_height_ranges, const Pointf &origin_translation); ModelObject* add_object(const ModelObject &other);
void delete_object(size_t idx); void delete_object(size_t idx);
void clear_objects(); void clear_objects();
ModelMaterial* add_material(t_model_material_id material_id);
ModelMaterial* add_material(t_model_material_id material_id, const ModelMaterial &other);
ModelMaterial* get_material(t_model_material_id material_id);
void delete_material(t_model_material_id material_id); void delete_material(t_model_material_id material_id);
void clear_materials(); void clear_materials();
ModelMaterial *set_material(t_model_material_id material_id);
// void duplicate_objects_grid(unsigned int x, unsigned int y, coordf_t distance); // void duplicate_objects_grid(unsigned int x, unsigned int y, coordf_t distance);
// void duplicate_objects(size_t copies_num, coordf_t distance, const BoundingBox &bb); // void duplicate_objects(size_t copies_num, coordf_t distance, const BoundingBox &bb);
// void arrange_objects(coordf_t distance, const BoundingBox &bb); // void arrange_objects(coordf_t distance, const BoundingBox &bb);
@ -65,19 +68,25 @@ class Model
class ModelMaterial class ModelMaterial
{ {
friend class Model;
public: public:
Model* model;
t_model_material_attributes attributes; t_model_material_attributes attributes;
DynamicPrintConfig config; DynamicPrintConfig config;
ModelMaterial(Model *model); Model* get_model() const { return this->model; };
void apply(const t_model_material_attributes &attributes); void apply(const t_model_material_attributes &attributes);
private:
Model* model;
ModelMaterial(Model *model);
ModelMaterial(Model *model, const ModelMaterial &other);
}; };
class ModelObject class ModelObject
{ {
friend class Model;
public: public:
Model* model;
std::string input_file; std::string input_file;
ModelInstancePtrs instances; ModelInstancePtrs instances;
ModelVolumePtrs volumes; ModelVolumePtrs volumes;
@ -89,65 +98,76 @@ class ModelObject
BoundingBoxf3 _bounding_box; BoundingBoxf3 _bounding_box;
bool _bounding_box_valid; bool _bounding_box_valid;
ModelObject(Model *model, const std::string &input_file, const DynamicPrintConfig &config, Model* get_model() const { return this->model; };
const t_layer_height_ranges &layer_height_ranges, const Pointf &origin_translation);
ModelObject(const ModelObject &other);
ModelObject& operator= (ModelObject other);
void swap(ModelObject &other);
~ModelObject();
ModelVolume* add_volume(const t_model_material_id &material_id, ModelVolume* add_volume(const TriangleMesh &mesh);
const TriangleMesh &mesh, bool modifier); ModelVolume* add_volume(const ModelVolume &volume);
void delete_volume(size_t idx); void delete_volume(size_t idx);
void clear_volumes(); void clear_volumes();
ModelInstance *add_instance(double rotation=0, double scaling_factor = 1, ModelInstance* add_instance();
Pointf offset = Pointf(0, 0)); ModelInstance* add_instance(const ModelInstance &instance);
void delete_instance(size_t idx); void delete_instance(size_t idx);
void delete_last_instance(); void delete_last_instance();
void clear_instances(); void clear_instances();
void invalidate_bounding_box(); void invalidate_bounding_box();
void raw_mesh(TriangleMesh* mesh) const; //void raw_mesh(TriangleMesh* mesh) const;
void mesh(TriangleMesh* mesh) const; //void mesh(TriangleMesh* mesh) const;
void instance_bounding_box(size_t instance_idx, BoundingBox* bb) const; //void instance_bounding_box(size_t instance_idx, BoundingBox* bb) const;
void center_around_origin(); //void center_around_origin();
void translate(coordf_t x, coordf_t y, coordf_t z); //void translate(coordf_t x, coordf_t y, coordf_t z);
size_t materials_count() const; //size_t materials_count() const;
void unique_materials(std::vector<t_model_material_id>* materials) const; //void unique_materials(std::vector<t_model_material_id>* materials) const;
size_t facets_count() const; //size_t facets_count() const;
bool needed_repair() const; //bool needed_repair() const;
private: private:
Model* model;
ModelObject(Model *model);
ModelObject(Model *model, const ModelObject &other);
ModelObject& operator= (ModelObject other);
void swap(ModelObject &other);
~ModelObject();
void update_bounding_box(); void update_bounding_box();
}; };
class ModelVolume class ModelVolume
{ {
friend class ModelObject;
public: public:
ModelObject* object;
t_model_material_id material_id; t_model_material_id material_id;
TriangleMesh mesh; TriangleMesh mesh;
bool modifier; bool modifier;
ModelVolume(ModelObject *object, const t_model_material_id &material_id, ModelObject* get_object() const { return this->object; };
const TriangleMesh &mesh, bool modifier);
private:
ModelObject* object;
ModelVolume(ModelObject *object, const TriangleMesh &mesh);
ModelVolume(ModelObject *object, const ModelVolume &other);
}; };
class ModelInstance class ModelInstance
{ {
friend class ModelObject;
public: public:
ModelObject* object;
double rotation; // around mesh center point double rotation; // around mesh center point
double scaling_factor; double scaling_factor;
Pointf offset; // in unscaled coordinates Pointf offset; // in unscaled coordinates
ModelInstance(ModelObject *object, double rotation, double scaling_factor, ModelObject* get_object() const { return this->object; };
const Pointf &offset);
void transform_mesh(TriangleMesh* mesh, bool dont_translate) const; void transform_mesh(TriangleMesh* mesh, bool dont_translate) const;
void transform_polygon(Polygon* polygon) const; void transform_polygon(Polygon* polygon) const;
private:
ModelObject* object;
ModelInstance(ModelObject *object);
ModelInstance(ModelObject *object, const ModelInstance &other);
}; };
} }

View File

@ -13,37 +13,29 @@
Clone<Model> clone() Clone<Model> clone()
%code%{ RETVAL = THIS; %}; %code%{ RETVAL = THIS; %};
Ref<ModelObject> _add_object(std::string input_file, %name{_add_object} Ref<ModelObject> add_object();
DynamicPrintConfig* config, Ref<ModelObject> _add_object_clone(ModelObject* other)
t_layer_height_ranges layer_height_ranges, %code%{ RETVAL = THIS->add_object(*other); %};
Pointf* origin_translation)
%code%{
RETVAL = THIS->add_object(input_file, *config, layer_height_ranges,
*origin_translation);
%};
void delete_object(size_t idx); void delete_object(size_t idx);
void clear_objects(); void clear_objects();
void delete_material(t_model_material_id material_id);
void clear_materials();
%name{_set_material} Ref<ModelMaterial> set_material(t_model_material_id material_id)
%code%{ RETVAL = THIS->set_material(material_id); %};
Ref<ModelMaterial> get_material(t_model_material_id material_id) Ref<ModelMaterial> get_material(t_model_material_id material_id)
%code%{ %code%{
ModelMaterialMap::iterator i = THIS->materials.find(material_id); RETVAL = THIS->get_material(material_id);
if (i == THIS->materials.end()) { if (RETVAL == NULL) {
XSRETURN_UNDEF; XSRETURN_UNDEF;
} }
RETVAL = i->second;
%}; %};
%name{add_material} Ref<ModelMaterial> add_material(t_model_material_id material_id);
Ref<ModelMaterial> add_material_clone(t_model_material_id material_id, ModelMaterial* other)
%code%{ RETVAL = THIS->add_material(material_id, *other); %};
bool has_material(t_model_material_id material_id) const bool has_material(t_model_material_id material_id) const
%code%{ %code%{
RETVAL = (THIS->materials.find(material_id) != THIS->materials.end()); RETVAL = (THIS->get_material(material_id) != NULL);
%}; %};
void delete_material(t_model_material_id material_id);
void clear_materials();
std::vector<std::string> material_names() const std::vector<std::string> material_names() const
%code%{ %code%{
@ -70,22 +62,14 @@
// void split_meshes(); // void split_meshes();
// std::string get_material_name(t_model_material_id material_id); // std::string get_material_name(t_model_material_id material_id);
ModelObjectPtrs *objects() ModelObjectPtrs* objects()
%code%{ %code%{ RETVAL = &THIS->objects; %};
if (THIS->objects.empty()) {
XSRETURN_UNDEF;
}
RETVAL = &THIS->objects;
%};
}; };
%name{Slic3r::Model::Material} class ModelMaterial { %name{Slic3r::Model::Material} class ModelMaterial {
~ModelMaterial();
Ref<Model> model() Ref<Model> model()
%code%{ RETVAL = THIS->model; %}; %code%{ RETVAL = THIS->get_model(); %};
Ref<DynamicPrintConfig> config() Ref<DynamicPrintConfig> config()
%code%{ RETVAL = &THIS->config; %}; %code%{ RETVAL = &THIS->config; %};
@ -114,38 +98,15 @@ ModelMaterial::attributes()
%name{Slic3r::Model::Object} class ModelObject { %name{Slic3r::Model::Object} class ModelObject {
ModelObject(Model* model, std::string input_file, ModelVolumePtrs* volumes()
DynamicPrintConfig* config, t_layer_height_ranges layer_height_ranges, %code%{ RETVAL = &THIS->volumes; %};
Pointf* origin_translation)
%code%{
RETVAL = new ModelObject(model, input_file, *config,
layer_height_ranges, *origin_translation);
%};
~ModelObject();
ModelVolumePtrs *volumes()
%code%{
if (THIS->volumes.empty()) {
XSRETURN_UNDEF;
}
RETVAL = &THIS->volumes;
%};
ModelInstancePtrs *instances()
%code%{
if (THIS->instances.empty()) {
XSRETURN_UNDEF;
}
RETVAL = &THIS->instances;
%};
ModelInstancePtrs* instances()
%code%{ RETVAL = &THIS->instances; %};
void invalidate_bounding_box(); void invalidate_bounding_box();
Ref<BoundingBoxf3> _bounding_box(BoundingBoxf3 *new_bbox = NULL) Ref<BoundingBoxf3> _bounding_box(BoundingBoxf3* new_bbox = NULL)
%code{% %code{%
if (NULL != new_bbox) { if (NULL != new_bbox) {
THIS->_bounding_box = *new_bbox; THIS->_bounding_box = *new_bbox;
@ -159,21 +120,21 @@ ModelMaterial::attributes()
RETVAL = &THIS->_bounding_box; RETVAL = &THIS->_bounding_box;
%}; %};
%name{_add_volume} Ref<ModelVolume> add_volume( %name{_add_volume} Ref<ModelVolume> add_volume(TriangleMesh* mesh)
t_model_material_id material_id, TriangleMesh* mesh, bool modifier) %code%{ RETVAL = THIS->add_volume(*mesh); %};
%code%{ RETVAL = THIS->add_volume(material_id, *mesh, modifier); %}; Ref<ModelVolume> _add_volume_clone(ModelVolume* other)
%code%{ RETVAL = THIS->add_volume(*other); %};
void delete_volume(size_t idx); void delete_volume(size_t idx);
void clear_volumes(); void clear_volumes();
%name{_add_instance} Ref<ModelInstance> add_instance( %name{_add_instance} Ref<ModelInstance> add_instance();
double rotation, double scaling_factor, std::vector<double> offset) Ref<ModelInstance> _add_instance_clone(ModelInstance* other)
%code%{ %code%{ RETVAL = THIS->add_instance(*other); %};
RETVAL = THIS->add_instance(rotation, scaling_factor,
Pointf(offset[0], offset[1]));
%};
void delete_last_instance(); void delete_last_instance();
void clear_instances(); void clear_instances();
int instances_count()
%code%{ RETVAL = THIS->instances.size(); %};
std::string input_file() std::string input_file()
%code%{ RETVAL = THIS->input_file; %}; %code%{ RETVAL = THIS->input_file; %};
@ -183,38 +144,42 @@ ModelMaterial::attributes()
%code%{ RETVAL = &THIS->config; %}; %code%{ RETVAL = &THIS->config; %};
Ref<Model> model() Ref<Model> model()
%code%{ RETVAL = THIS->model; %}; %code%{ RETVAL = THIS->get_model(); %};
t_layer_height_ranges layer_height_ranges() t_layer_height_ranges layer_height_ranges()
%code%{ RETVAL = THIS->layer_height_ranges; %}; %code%{ RETVAL = THIS->layer_height_ranges; %};
void set_layer_height_ranges(t_layer_height_ranges ranges)
%code%{ THIS->layer_height_ranges = ranges; %};
Clone<Pointf> origin_translation() Clone<Pointf> origin_translation()
%code%{ RETVAL = THIS->origin_translation; %}; %code%{ RETVAL = THIS->origin_translation; %};
void set_origin_translation(Pointf* point)
%code%{ THIS->origin_translation = *point; %};
}; };
%name{Slic3r::Model::Volume} class ModelVolume { %name{Slic3r::Model::Volume} class ModelVolume {
~ModelVolume();
Ref<ModelObject> object() Ref<ModelObject> object()
%code%{ RETVAL = THIS->object; %}; %code%{ RETVAL = THIS->get_object(); %};
t_model_material_id material_id() t_model_material_id material_id()
%code%{ RETVAL = THIS->material_id; %}; %code%{ RETVAL = THIS->material_id; %};
void set_material_id(t_model_material_id material_id)
%code%{ THIS->material_id = material_id; %};
Ref<TriangleMesh> mesh() Ref<TriangleMesh> mesh()
%code%{ RETVAL = &THIS->mesh; %}; %code%{ RETVAL = &THIS->mesh; %};
bool modifier() bool modifier()
%code%{ RETVAL = THIS->modifier; %}; %code%{ RETVAL = THIS->modifier; %};
void set_modifier(bool modifier)
%code%{ THIS->modifier = modifier; %};
}; };
%name{Slic3r::Model::Instance} class ModelInstance { %name{Slic3r::Model::Instance} class ModelInstance {
~ModelInstance();
Ref<ModelObject> object() Ref<ModelObject> object()
%code%{ RETVAL = THIS->object; %}; %code%{ RETVAL = THIS->get_object(); %};
double rotation() double rotation()
%code%{ RETVAL = THIS->rotation; %}; %code%{ RETVAL = THIS->rotation; %};