mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 01:45:54 +08:00
Finished porting importers and read_from_file() to C++
This commit is contained in:
parent
8326f75af8
commit
22ba87c3b3
@ -52,9 +52,6 @@ use Slic3r::ExPolygon;
|
||||
use Slic3r::ExtrusionLoop;
|
||||
use Slic3r::ExtrusionPath;
|
||||
use Slic3r::Flow;
|
||||
use Slic3r::Format::AMF;
|
||||
use Slic3r::Format::OBJ;
|
||||
use Slic3r::Format::STL;
|
||||
use Slic3r::GCode::ArcFitting;
|
||||
use Slic3r::GCode::MotionPlanner;
|
||||
use Slic3r::GCode::PressureRegulator;
|
||||
|
@ -1,13 +0,0 @@
|
||||
package Slic3r::Format::AMF;
|
||||
use Moo;
|
||||
|
||||
sub read_file {
|
||||
my $self = shift;
|
||||
my ($file) = @_;
|
||||
|
||||
my $model = Slic3r::Model->new;
|
||||
$model->read_amf($file);
|
||||
return $model;
|
||||
}
|
||||
|
||||
1;
|
@ -1,162 +0,0 @@
|
||||
package Slic3r::Format::AMF::Parser;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use base 'XML::SAX::Base';
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
sub start_element {
|
||||
my $self = shift;
|
||||
my $data = shift;
|
||||
|
||||
if ($data->{LocalName} eq 'object') {
|
||||
$self->{_object} = $self->{_model}->add_object;
|
||||
$self->{_object_vertices} = [];
|
||||
$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} = $self->{_object}->add_volume(
|
||||
material_id => $self->_get_attribute($data, 'materialid') // undef,
|
||||
mesh => Slic3r::TriangleMesh->new,
|
||||
);
|
||||
$self->{_volume_facets} = [];
|
||||
} 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') {
|
||||
my $material_id = $self->_get_attribute($data, 'id') // '_';
|
||||
$self->{_material} = $self->{_model}->set_material($material_id);
|
||||
} elsif ($data->{LocalName} eq 'metadata') {
|
||||
$self->{_metadata_type} = $self->_get_attribute($data, 'type');
|
||||
$self->{_metadata_value} = '';
|
||||
} 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};
|
||||
}
|
||||
|
||||
sub characters {
|
||||
my $self = shift;
|
||||
my $data = shift;
|
||||
|
||||
if ($self->{_vertex} && $self->{_coordinate}) {
|
||||
$self->{_vertex}[ $xyz_index{$self->{_coordinate}} ] .= $data->{Data};
|
||||
} elsif ($self->{_triangle} && defined $self->{_vertex_idx}) {
|
||||
$self->{_triangle}[ $self->{_vertex_idx} ] .= $data->{Data};
|
||||
} elsif ($self->{_metadata_type}) {
|
||||
$self->{_metadata_value} .= $data->{Data};
|
||||
} elsif ($self->{_instance_property}) {
|
||||
$self->{_instance}{ $self->{_instance_property} } .= $data->{Data};
|
||||
}
|
||||
}
|
||||
|
||||
sub end_element {
|
||||
my $self = shift;
|
||||
my $data = shift;
|
||||
|
||||
pop @{$self->{_tree}};
|
||||
|
||||
if ($data->{LocalName} eq 'object') {
|
||||
$self->{_object} = undef;
|
||||
$self->{_object_vertices} = 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->{_volume}->mesh->ReadFromPerl($self->{_object_vertices}, $self->{_volume_facets});
|
||||
$self->{_volume}->mesh->repair;
|
||||
$self->{_volume} = undef;
|
||||
$self->{_volume_facets} = undef;
|
||||
} elsif ($data->{LocalName} eq '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->{_material} = undef;
|
||||
} elsif ($data->{LocalName} eq 'metadata') {
|
||||
my $value = $self->{_metadata_value};
|
||||
if ($self->{_metadata_type} =~ /^slic3r\.(.+)/) {
|
||||
my $opt_key = $1;
|
||||
if (exists $Slic3r::Config::Options->{$opt_key}) {
|
||||
my $config;
|
||||
if ($self->{_material}) {
|
||||
$config = $self->{_material}->config;
|
||||
} elsif ($self->{_volume}) {
|
||||
$config = $self->{_volume}->config;
|
||||
} elsif ($self->{_object}) {
|
||||
$config = $self->{_object}->config;
|
||||
}
|
||||
|
||||
$config->set_deserialize($opt_key, $value) if defined $config;
|
||||
} elsif ($opt_key eq 'modifier' && $self->{_volume}) {
|
||||
$self->{_volume}->set_modifier($value);
|
||||
}
|
||||
} elsif ($self->{_metadata_type} eq 'name' && $self->{_volume}) {
|
||||
$self->{_volume}->set_name($value);
|
||||
} elsif ($self->{_metadata_type} eq 'name' && $self->{_object}) {
|
||||
$self->{_object}->set_name($value);
|
||||
} elsif ($self->{_material}) {
|
||||
$self->{_material}->set_attribute($self->{_metadata_type}, $value);
|
||||
}
|
||||
$self->{_metadata_type} = undef;
|
||||
$self->{_metadata_value} = 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 (!defined $new_object_id) {
|
||||
warn "Undefined object $object_id referenced in constellation\n";
|
||||
next;
|
||||
}
|
||||
|
||||
foreach my $instance (@{ $self->{_instances}{$object_id} }) {
|
||||
next if !defined($instance->{deltax}) || !defined($instance->{deltay});
|
||||
$self->{_model}->objects->[$new_object_id]->add_instance(
|
||||
rotation => $instance->{rz} || 0,
|
||||
offset => Slic3r::Pointf->new($instance->{deltax} || 0, $instance->{deltay} || 0),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub _get_attribute {
|
||||
my $self = shift;
|
||||
my ($data, $name) = @_;
|
||||
|
||||
return +(map $_->{Value}, grep $_->{Name} eq $name, values %{$data->{Attributes}})[0];
|
||||
}
|
||||
|
||||
1;
|
@ -1,13 +0,0 @@
|
||||
package Slic3r::Format::OBJ;
|
||||
use Moo;
|
||||
|
||||
sub read_file {
|
||||
my $self = shift;
|
||||
my ($file) = @_;
|
||||
|
||||
my $model = Slic3r::Model->new;
|
||||
$model->read_obj($file);
|
||||
return $model;
|
||||
}
|
||||
|
||||
1;
|
@ -1,26 +0,0 @@
|
||||
package Slic3r::Format::STL;
|
||||
use Moo;
|
||||
|
||||
sub read_file {
|
||||
my $self = shift;
|
||||
my ($file) = @_;
|
||||
|
||||
my $model = Slic3r::Model->new;
|
||||
$model->read_stl($file);
|
||||
return $model;
|
||||
}
|
||||
|
||||
sub write_file {
|
||||
my $self = shift;
|
||||
my ($file, $mesh, %params) = @_;
|
||||
|
||||
$mesh = $mesh->mesh if $mesh->isa('Slic3r::Model');
|
||||
|
||||
my $path = Slic3r::encode_path($file);
|
||||
|
||||
$params{binary}
|
||||
? $mesh->write_binary($path)
|
||||
: $mesh->write_ascii($path);
|
||||
}
|
||||
|
||||
1;
|
@ -1420,7 +1420,7 @@ sub export_stl {
|
||||
return if !@{$self->{objects}};
|
||||
|
||||
my $output_file = $self->_get_export_file('STL') or return;
|
||||
Slic3r::Format::STL->write_file($output_file, $self->{model}, binary => 1);
|
||||
$self->{model}->write_stl($output_file, 1);
|
||||
$self->statusbar->SetStatusText("STL file exported to $output_file");
|
||||
}
|
||||
|
||||
@ -1467,7 +1467,7 @@ sub export_object_stl {
|
||||
my $model_object = $self->{model}->objects->[$obj_idx];
|
||||
|
||||
my $output_file = $self->_get_export_file('STL') or return;
|
||||
Slic3r::Format::STL->write_file($output_file, $model_object->mesh, binary => 1);
|
||||
$model_object->mesh->write_binary($output_file);
|
||||
$self->statusbar->SetStatusText("STL file exported to $output_file");
|
||||
}
|
||||
|
||||
|
@ -4,22 +4,6 @@ package Slic3r::Model;
|
||||
use List::Util qw(first max any);
|
||||
use Slic3r::Geometry qw(X Y Z move_points);
|
||||
|
||||
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";
|
||||
|
||||
die "The supplied file couldn't be read because it's empty.\n"
|
||||
if $model->objects_count == 0;
|
||||
|
||||
$_->set_input_file($input_file) for @{$model->objects};
|
||||
return $model;
|
||||
}
|
||||
|
||||
sub merge {
|
||||
my $class = shift;
|
||||
my @models = @_;
|
||||
|
@ -217,7 +217,7 @@ if (@ARGV) { # slicing from command line
|
||||
foreach my $new_mesh (@{$mesh->split}) {
|
||||
my $output_file = sprintf '%s_%02d.stl', $file, ++$part_count;
|
||||
printf "Writing to %s\n", basename($output_file);
|
||||
Slic3r::Format::STL->write_file($output_file, $new_mesh, binary => 1);
|
||||
$new_mesh->write_binary($output_file);
|
||||
}
|
||||
}
|
||||
exit;
|
||||
|
@ -69,9 +69,8 @@ main(const int argc, const char **argv)
|
||||
}
|
||||
|
||||
Model model;
|
||||
// TODO: read other file formats with Model::read_from_file()
|
||||
try {
|
||||
IO::STL::read(*it, &model);
|
||||
model = Model::read_from_file(*it);
|
||||
} catch (std::exception &e) {
|
||||
std::cout << *it << ": " << e.what() << std::endl;
|
||||
exit(1);
|
||||
|
@ -26,12 +26,12 @@ my %opt = ();
|
||||
}
|
||||
|
||||
{
|
||||
my $model = Slic3r::Format::AMF->read_file($ARGV[0]);
|
||||
my $model = Slic3r::Model->read_from_file($ARGV[0]);
|
||||
my $output_file = $ARGV[0];
|
||||
$output_file =~ s/\.amf(?:\.xml)?$/\.stl/i;
|
||||
|
||||
printf "Writing to %s\n", basename($output_file);
|
||||
Slic3r::Format::STL->write_file($output_file, $model, binary => !$opt{ascii});
|
||||
$model->write_stl($output_file, !$opt{ascii});
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ $|++;
|
||||
$ARGV[0] or usage(1);
|
||||
|
||||
if (-e $ARGV[0]) {
|
||||
my $model = Slic3r::Format::STL->read_file($ARGV[0]);
|
||||
my $model = Slic3r::Model->read_from_file($ARGV[0]);
|
||||
$model->objects->[0]->add_instance(offset => Slic3r::Pointf->new(0,0));
|
||||
my $mesh = $model->mesh;
|
||||
$mesh->repair;
|
||||
@ -27,7 +27,7 @@ if (-e $ARGV[0]) {
|
||||
exit 0;
|
||||
} elsif ((my $model = Slic3r::Test::model($ARGV[0]))) {
|
||||
$ARGV[1] or die "Missing writeable destination as second argument\n";
|
||||
Slic3r::Format::STL->write_file($ARGV[1], $model);
|
||||
$model->write_stl($ARGV[1]);
|
||||
printf "Model $ARGV[0] written to $ARGV[1]\n";
|
||||
exit 0;
|
||||
} else {
|
||||
|
@ -26,7 +26,7 @@ my %opt = ();
|
||||
}
|
||||
|
||||
{
|
||||
my $model = Slic3r::Format::STL->read_file($ARGV[0]);
|
||||
my $model = Slic3r::Model->read_from_file($ARGV[0]);
|
||||
my $basename = $ARGV[0];
|
||||
$basename =~ s/\.stl$//i;
|
||||
|
||||
@ -44,7 +44,7 @@ my %opt = ();
|
||||
|
||||
my $output_file = sprintf '%s_%02d.stl', $basename, ++$part_count;
|
||||
printf "Writing to %s\n", basename($output_file);
|
||||
Slic3r::Format::STL->write_file($output_file, $new_model, binary => !$opt{ascii});
|
||||
$new_model->write_stl($output_file, !$opt{ascii});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ my %opt = ();
|
||||
}
|
||||
|
||||
{
|
||||
my @models = map Slic3r::Format::STL->read_file($_), @ARGV;
|
||||
my @models = map Slic3r::Model->read_from_file($_), @ARGV;
|
||||
my $output_file = $ARGV[0];
|
||||
$output_file =~ s/\.stl$/.amf.xml/i;
|
||||
|
||||
@ -54,7 +54,7 @@ my %opt = ();
|
||||
}
|
||||
|
||||
printf "Writing to %s\n", basename($output_file);
|
||||
Slic3r::Format::AMF->write_file($output_file, $new_model);
|
||||
$new_model->write_amf($output_file);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <stdexcept>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#define TINYOBJLOADER_IMPLEMENTATION
|
||||
#include "tiny_obj_loader.h"
|
||||
@ -33,15 +34,22 @@ STL::read(std::string input_file, Model* model)
|
||||
throw std::runtime_error("This STL file couldn't be read because it's empty.");
|
||||
|
||||
ModelObject* object = model->add_object();
|
||||
object->name = input_file; // TODO: use basename()
|
||||
object->name = boost::filesystem::path(input_file).filename().string();
|
||||
object->input_file = input_file;
|
||||
|
||||
ModelVolume* volume = object->add_volume(mesh);
|
||||
volume->name = input_file; // TODO: use basename()
|
||||
volume->name = object->name;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
STL::write(Model& model, std::string output_file, bool binary)
|
||||
{
|
||||
TriangleMesh mesh = model.mesh();
|
||||
return STL::write(mesh, output_file, binary);
|
||||
}
|
||||
|
||||
bool
|
||||
STL::write(TriangleMesh& mesh, std::string output_file, bool binary)
|
||||
{
|
||||
@ -83,7 +91,7 @@ OBJ::read(std::string input_file, Model* model)
|
||||
throw std::runtime_error("Error while reading OBJ file");
|
||||
|
||||
ModelObject* object = model->add_object();
|
||||
object->name = input_file; // TODO: use basename()
|
||||
object->name = boost::filesystem::path(input_file).filename().string();
|
||||
object->input_file = input_file;
|
||||
|
||||
// Loop over shapes and add a volume for each one.
|
||||
@ -118,12 +126,19 @@ OBJ::read(std::string input_file, Model* model)
|
||||
TriangleMesh mesh(points, facets);
|
||||
mesh.check_topology();
|
||||
ModelVolume* volume = object->add_volume(mesh);
|
||||
volume->name = input_file; // TODO: use basename()
|
||||
volume->name = object->name;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
OBJ::write(Model& model, std::string output_file)
|
||||
{
|
||||
TriangleMesh mesh = model.mesh();
|
||||
return OBJ::write(mesh, output_file);
|
||||
}
|
||||
|
||||
bool
|
||||
OBJ::write(TriangleMesh& mesh, std::string output_file)
|
||||
{
|
||||
|
@ -13,6 +13,7 @@ class STL
|
||||
public:
|
||||
static bool read(std::string input_file, TriangleMesh* mesh);
|
||||
static bool read(std::string input_file, Model* model);
|
||||
static bool write(Model& model, std::string output_file, bool binary = true);
|
||||
static bool write(TriangleMesh& mesh, std::string output_file, bool binary = true);
|
||||
};
|
||||
|
||||
@ -21,6 +22,7 @@ class OBJ
|
||||
public:
|
||||
static bool read(std::string input_file, TriangleMesh* mesh);
|
||||
static bool read(std::string input_file, Model* model);
|
||||
static bool write(Model& model, std::string output_file);
|
||||
static bool write(TriangleMesh& mesh, std::string output_file);
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
#include "Model.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "IO.hpp"
|
||||
#include <iostream>
|
||||
#include "boost/filesystem.hpp"
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -38,6 +40,31 @@ Model::~Model()
|
||||
this->clear_materials();
|
||||
}
|
||||
|
||||
Model
|
||||
Model::read_from_file(std::string input_file)
|
||||
{
|
||||
Model model;
|
||||
|
||||
if (boost::algorithm::iends_with(input_file, ".stl")) {
|
||||
IO::STL::read(input_file, &model);
|
||||
} else if (boost::algorithm::iends_with(input_file, ".obj")) {
|
||||
IO::OBJ::read(input_file, &model);
|
||||
} else if (boost::algorithm::iends_with(input_file, ".amf")
|
||||
|| boost::algorithm::iends_with(input_file, ".amf.xml")) {
|
||||
IO::AMF::read(input_file, &model);
|
||||
} else {
|
||||
throw std::runtime_error("Unknown file format");
|
||||
}
|
||||
|
||||
if (model.objects.empty())
|
||||
throw std::runtime_error("The supplied file couldn't be read because it's empty");
|
||||
|
||||
for (ModelObjectPtrs::const_iterator o = model.objects.begin(); o != model.objects.end(); ++o)
|
||||
(*o)->input_file = input_file;
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
ModelObject*
|
||||
Model::add_object()
|
||||
{
|
||||
|
@ -47,6 +47,7 @@ class Model
|
||||
Model& operator= (Model other);
|
||||
void swap(Model &other);
|
||||
~Model();
|
||||
static Model read_from_file(std::string input_file);
|
||||
ModelObject* add_object();
|
||||
ModelObject* add_object(const ModelObject &other, bool copy_volumes = true);
|
||||
void delete_object(size_t idx);
|
||||
|
@ -10,6 +10,15 @@
|
||||
%name{Slic3r::Model} class Model {
|
||||
Model();
|
||||
~Model();
|
||||
|
||||
%name{read_from_file} Model(std::string input_file)
|
||||
%code%{
|
||||
try {
|
||||
RETVAL = new Model(Model::read_from_file(input_file));
|
||||
} catch (std::exception& e) {
|
||||
croak("Error while opening %s: %s\n", input_file.c_str(), e.what());
|
||||
}
|
||||
%};
|
||||
|
||||
Clone<Model> clone()
|
||||
%code%{ RETVAL = THIS; %};
|
||||
@ -20,6 +29,11 @@
|
||||
%code%{ RETVAL = Slic3r::IO::OBJ::read(input_file, THIS); %};
|
||||
bool read_amf(std::string input_file)
|
||||
%code%{ RETVAL = Slic3r::IO::AMF::read(input_file, THIS); %};
|
||||
|
||||
bool write_stl(std::string output_file, bool binary = false)
|
||||
%code%{ RETVAL = Slic3r::IO::STL::write(*THIS, output_file, binary); %};
|
||||
bool write_obj(std::string output_file)
|
||||
%code%{ RETVAL = Slic3r::IO::OBJ::write(*THIS, output_file); %};
|
||||
bool write_amf(std::string output_file)
|
||||
%code%{ RETVAL = Slic3r::IO::AMF::write(*THIS, output_file); %};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user