Refactor the AMF parser so that it popolates a Model object directly. Also read constellations
This commit is contained in:
parent
23f6842bd4
commit
f29d455319
4 changed files with 59 additions and 35 deletions
|
@ -12,28 +12,12 @@ sub read_file {
|
|||
|
||||
open my $fh, '<', $file or die "Failed to open $file\n";
|
||||
|
||||
my $vertices = [];
|
||||
my $materials = {};
|
||||
my $meshes_by_material = {};
|
||||
my $model = Slic3r::Model->new;
|
||||
XML::SAX::PurePerl
|
||||
->new(Handler => Slic3r::Format::AMF::Parser->new(
|
||||
_vertices => $vertices,
|
||||
_materials => $materials,
|
||||
_meshes_by_material => $meshes_by_material,
|
||||
))
|
||||
->new(Handler => Slic3r::Format::AMF::Parser->new(_model => $model))
|
||||
->parse_file($fh);
|
||||
|
||||
close $fh;
|
||||
|
||||
my $model = Slic3r::Model->new;
|
||||
my $object = $model->add_object(vertices => $vertices);
|
||||
foreach my $material (keys %$meshes_by_material) {
|
||||
push @{$model->materials}, $material; # TODO: we should not add duplicate materials
|
||||
$object->add_volume(
|
||||
material_id => $#{$model->materials},
|
||||
facets => $meshes_by_material->{$material},
|
||||
);
|
||||
}
|
||||
return $model;
|
||||
}
|
||||
|
||||
|
@ -48,8 +32,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 (0 .. $#{ $model->materials }) {
|
||||
my $material = $model->materials->[$material_id];
|
||||
for my $material_id (sort keys %{ $model->materials }) {
|
||||
my $material = $model->materials->{$material_id};
|
||||
printf $fh qq{ <material id="%d">\n}, $material_id;
|
||||
for (keys %$material) {
|
||||
printf $fh qq{ <metadata type=\"%s\">%s</metadata>\n}, $_, $material->{$_};
|
||||
|
|
|
@ -11,6 +11,8 @@ my %xyz_index = (x => 0, y => 1, z => 2); #=
|
|||
sub new {
|
||||
my $self = shift->SUPER::new(@_);
|
||||
$self->{_tree} = [];
|
||||
$self->{_objects_map} = {}; # this hash maps AMF object IDs to object indexes in $model->objects
|
||||
$self->{_instances} = {}; # apply these lazily to make sure all objects have been parsed
|
||||
$self;
|
||||
}
|
||||
|
||||
|
@ -18,23 +20,35 @@ sub start_element {
|
|||
my $self = shift;
|
||||
my $data = shift;
|
||||
|
||||
if ($data->{LocalName} eq 'vertex') {
|
||||
if ($data->{LocalName} eq 'object') {
|
||||
$self->{_object} = $self->{_model}->add_object;
|
||||
$self->{_objects_map}{ $self->_get_attribute($data, 'id') } = $#{ $self->{_model}->objects };
|
||||
} elsif ($data->{LocalName} eq 'vertex') {
|
||||
$self->{_vertex} = ["", "", ""];
|
||||
} elsif ($self->{_vertex} && $data->{LocalName} =~ /^[xyz]$/ && $self->{_tree}[-1] eq 'coordinates') {
|
||||
$self->{_coordinate} = $data->{LocalName};
|
||||
} elsif ($data->{LocalName} eq 'volume') {
|
||||
$self->{_volume_materialid} = $self->_get_attribute($data, 'materialid') || '_';
|
||||
$self->{_volume} = [];
|
||||
$self->{_volume} = $self->{_object}->add_volume(
|
||||
material_id => $self->_get_attribute($data, 'materialid') || undef,
|
||||
);
|
||||
} elsif ($data->{LocalName} eq 'triangle') {
|
||||
$self->{_triangle} = ["", "", ""];
|
||||
} elsif ($self->{_triangle} && $data->{LocalName} =~ /^v([123])$/ && $self->{_tree}[-1] eq 'triangle') {
|
||||
$self->{_vertex_idx} = $1-1;
|
||||
} elsif ($data->{LocalName} eq 'material') {
|
||||
$self->{_material_id} = $self->_get_attribute($data, 'id') || '_';
|
||||
$self->{_material} = {};
|
||||
my $material_id = $self->_get_attribute($data, 'id') || '_';
|
||||
$self->{_material} = $self->{_model}->materials->{ $material_id } = {};
|
||||
} elsif ($data->{LocalName} eq 'metadata' && $self->{_tree}[-1] eq 'material') {
|
||||
$self->{_material_metadata_type} = $self->_get_attribute($data, 'type');
|
||||
$self->{_material}{ $self->{_material_metadata_type} } = "";
|
||||
} elsif ($data->{LocalName} eq 'constellation') {
|
||||
$self->{_constellation} = 1; # we merge all constellations as we don't support more than one
|
||||
} elsif ($data->{LocalName} eq 'instance' && $self->{_constellation}) {
|
||||
my $object_id = $self->_get_attribute($data, 'objectid');
|
||||
$self->{_instances}{$object_id} ||= [];
|
||||
push @{ $self->{_instances}{$object_id} }, $self->{_instance} = {};
|
||||
} elsif ($data->{LocalName} =~ /^(?:deltax|deltay|rz)$/ && $self->{_instance}) {
|
||||
$self->{_instance_property} = $data->{LocalName};
|
||||
}
|
||||
|
||||
push @{$self->{_tree}}, $data->{LocalName};
|
||||
|
@ -50,6 +64,8 @@ sub characters {
|
|||
$self->{_triangle}[ $self->{_vertex_idx} ] .= $data->{Data};
|
||||
} elsif ($self->{_material_metadata_type}) {
|
||||
$self->{_material}{ $self->{_material_metadata_type} } .= $data->{Data};
|
||||
} elsif ($self->{_instance_property}) {
|
||||
$self->{_instance}{ $self->{_instance_property} } .= $data->{Data};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,26 +75,49 @@ sub end_element {
|
|||
|
||||
pop @{$self->{_tree}};
|
||||
|
||||
if ($data->{LocalName} eq 'vertex') {
|
||||
push @{$self->{_vertices}}, $self->{_vertex};
|
||||
if ($data->{LocalName} eq 'object') {
|
||||
$self->{_object} = undef;
|
||||
} elsif ($data->{LocalName} eq 'vertex') {
|
||||
push @{$self->{_object}->vertices}, $self->{_vertex};
|
||||
$self->{_vertex} = undef;
|
||||
} elsif ($self->{_coordinate} && $data->{LocalName} =~ /^[xyz]$/) {
|
||||
$self->{_coordinate} = undef;
|
||||
} elsif ($data->{LocalName} eq 'volume') {
|
||||
$self->{_meshes_by_material}{ $self->{_volume_materialid} } ||= [];
|
||||
push @{ $self->{_meshes_by_material}{ $self->{_volume_materialid} } }, @{$self->{_volume}};
|
||||
$self->{_volume} = undef;
|
||||
} elsif ($data->{LocalName} eq 'triangle') {
|
||||
push @{$self->{_volume}}, $self->{_triangle};
|
||||
push @{$self->{_volume}->facets}, $self->{_triangle};
|
||||
$self->{_triangle} = undef;
|
||||
} elsif (defined $self->{_vertex_idx} && $data->{LocalName} =~ /^v[123]$/) {
|
||||
$self->{_vertex_idx} = undef;
|
||||
} elsif ($data->{LocalName} eq 'material') {
|
||||
$self->{_materials}{ $self->{_material_id} } = $self->{_material};
|
||||
$self->{_material_id} = undef;
|
||||
$self->{_material} = undef;
|
||||
} elsif ($data->{LocalName} eq 'metadata' && $self->{_material}) {
|
||||
$self->{_material_metadata_type} = undef;
|
||||
} elsif ($data->{LocalName} eq 'constellation') {
|
||||
$self->{_constellation} = undef;
|
||||
} elsif ($data->{LocalName} eq 'instance') {
|
||||
$self->{_instance} = undef;
|
||||
} elsif ($data->{LocalName} =~ /^(?:deltax|deltay|rz)$/ && $self->{_instance}) {
|
||||
$self->{_instance_property} = undef;
|
||||
}
|
||||
}
|
||||
|
||||
sub end_document {
|
||||
my $self = shift;
|
||||
|
||||
foreach my $object_id (keys %{ $self->{_instances} }) {
|
||||
my $new_object_id = $self->{_objects_map}{$object_id};
|
||||
if (!$new_object_id) {
|
||||
warn "Undefined object $object_id referenced in constellation\n";
|
||||
next;
|
||||
}
|
||||
|
||||
foreach my $instance (@{ $self->{_instances}{$object_id} }) {
|
||||
$self->{_model}->objects->[$new_object_id]->add_instance(
|
||||
rotation => $instance->{rz} || 0,
|
||||
offset => [ $instance->{deltax} || 0, $instance->{deltay} ],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use Moo;
|
|||
|
||||
use Slic3r::Geometry qw(X Y Z);
|
||||
|
||||
has 'materials' => (is => 'ro', default => sub { [] });
|
||||
has 'materials' => (is => 'ro', default => sub { {} });
|
||||
has 'objects' => (is => 'ro', default => sub { [] });
|
||||
|
||||
sub add_object {
|
||||
|
|
|
@ -43,9 +43,10 @@ my %opt = ();
|
|||
$f;
|
||||
} @{ $model->objects->[0]->volumes->[0]->facets };
|
||||
|
||||
push @{$new_model->materials}, { Name => basename($ARGV[$m]) };
|
||||
my $material_id = scalar keys %{$new_model->materials};
|
||||
$new_model->materials->{$material_id} = { Name => basename($ARGV[$m]) };
|
||||
$new_object->add_volume(
|
||||
material_id => $#{$new_model->materials},
|
||||
material_id => $material_id,
|
||||
facets => [@new_facets],
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue