mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-15 18:58:00 -06:00
Merge branch 'sapir-modelcpp'
This commit is contained in:
commit
6e207d3830
17 changed files with 911 additions and 222 deletions
|
@ -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->{$_};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) = @_;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue