Merge branch 'master' into adaptive-slicing-spline

This commit is contained in:
Florens Wasserfall 2017-03-07 13:19:13 +01:00
commit 3a53a17efb
94 changed files with 17536 additions and 731 deletions

View File

@ -17,6 +17,8 @@ _What OS are you using, and state any version #s_
* _Screenshots from __*Slic3r*__ preview are preferred_
_Is this a new feature request?_
Related guides for writing feature requests: http://meta.stackexchange.com/a/259196 http://nickohrn.com/2013/09/write-great-feature-request-bug-report/
#### STL/Config (.ZIP) where problem occurs
_Upload a zipped copy of an STL and your config (`File -> Export Config`)_

2
.gitignore vendored
View File

@ -12,3 +12,5 @@ xs/MANIFEST.bak
xs/assertlib*
.init_bundle.ini
local-lib
package/osx/Slic3r*.app
*.dmg

View File

@ -11,13 +11,18 @@ branches:
- stable
sudo: false
cache:
- apt
apt: true
directories:
- local-lib
addons:
apt:
sources:
- boost-latest
- ubuntu-toolchain-r-test
packages:
- libboost-thread1.55-dev
- libboost-system1.55-dev
- libboost-filesystem1.55-dev
- liblocal-lib-perl
- g++-4.9
env: CC=g++-4.9

View File

@ -28,8 +28,9 @@ my %prereqs = qw(
);
my %recommends = qw(
Class::XSAccessor 0
XML::SAX::ExpatXS 0
Test::Harness 0
Thread::Queue 0
threads::shared 0
);
my $sudo = grep { $_ eq '--sudo' } @ARGV;
@ -130,15 +131,6 @@ EOF
if $module =~ /^(?:OpenGL|Math::PlanePath|Test::Harness)$/;
push @cmd, "$module~$version";
if ($module eq 'XML::SAX::ExpatXS' && $^O eq 'MSWin32') {
my $mingw = 'C:\dev\CitrusPerl\mingw64';
$mingw = 'C:\dev\CitrusPerl\mingw32' if !-d $mingw;
if (!-d $mingw) {
print "Could not find the MinGW directory at $mingw; skipping XML::SAX::ExpatXS (only needed for faster parsing of AMF files)\n";
} else {
push @cmd, sprintf('--configure-args="EXPATLIBPATH=%s\lib EXPATINCPATH=%s\include"', $mingw, $mingw);
}
}
my $res = system @cmd;
if ($res != 0) {
if (exists $prereqs{$module}) {

View File

@ -2,11 +2,12 @@ _Q: Oh cool, a new RepRap slicer?_
A: Yes.
Slic3r [![Build Status](https://travis-ci.org/alexrj/Slic3r.svg?branch=master)](https://travis-ci.org/alexrj/Slic3r) [![Build status](https://ci.appveyor.com/api/projects/status/8iqmeat6cj158vo6?svg=true)](https://ci.appveyor.com/project/lordofhyphens/slic3r)
Slic3r [![Build Status](https://travis-ci.org/alexrj/Slic3r.svg?branch=master)](https://travis-ci.org/alexrj/Slic3r) [![Build status](https://ci.appveyor.com/api/projects/status/8iqmeat6cj158vo6?svg=true)](https://ci.appveyor.com/project/lordofhyphens/slic3r) [![Build Status](http://osx-build.slic3r.org:8080/buildStatus/icon?job=Slic3r)](http://osx-build.slic3r.org:8080/job/Slic3r)
======
Prebuilt Win32 builds:
Prebuilt Windows (64-bit) and OSX (>10.7) builds:
* https://bintray.com/lordofhyphens/Slic3r/slic3r_dev/view (from build server)
* https://bintray.com/lordofhyphens/Slic3r/slic3r_dev/1.3.0-dev (manually packaged)
<img width=256 src=https://cloud.githubusercontent.com/assets/31754/22719818/09998c92-ed6d-11e6-9fa0-09de638f3a36.png />
Slic3r takes 3D models (STL, OBJ, AMF) and converts them into G-code instructions for
3D printers. It's compatible with any modern printer based on the RepRap toolchain,

View File

@ -53,9 +53,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;

View File

@ -1,130 +0,0 @@
package Slic3r::Format::AMF;
use Moo;
use Slic3r::Geometry qw(X Y Z);
sub read_file {
my $self = shift;
my ($file) = @_;
eval qq{
require Slic3r::Format::AMF::Parser;
use XML::SAX::ParserFactory;
1;
} or die "AMF parsing requires XML::SAX\n";
Slic3r::open(\my $fh, '<', $file) or die "Failed to open $file\n";
my $model = Slic3r::Model->new;
XML::SAX::ParserFactory
->parser(Handler => Slic3r::Format::AMF::Parser->new(_model => $model))
->parse_file($fh);
close $fh;
return $model;
}
sub write_file {
my $self = shift;
my ($file, $model, %params) = @_;
my %vertices_offset = ();
Slic3r::open(\my $fh, '>', $file);
binmode $fh, ':utf8';
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 @{ $model->material_names }) {
next if $material_id eq '';
my $material = $model->get_material($material_id);
# note that material-id must never be 0 since it's reserved by the AMF spec
printf $fh qq{ <material id="%s">\n}, $material_id;
for (keys %{$material->attributes}) {
printf $fh qq{ <metadata type=\"%s\">%s</metadata>\n}, $_, $material->attributes->{$_};
}
my $config = $material->config;
foreach my $opt_key (@{$config->get_keys}) {
printf $fh qq{ <metadata type=\"slic3r.%s\">%s</metadata>\n}, $opt_key, $config->serialize($opt_key);
}
printf $fh qq{ </material>\n};
}
my $instances = '';
for my $object_id (0 .. $#{ $model->objects }) {
my $object = $model->objects->[$object_id];
printf $fh qq{ <object id="%d">\n}, $object_id;
my $config = $object->config;
foreach my $opt_key (@{$config->get_keys}) {
printf $fh qq{ <metadata type=\"slic3r.%s\">%s</metadata>\n}, $opt_key, $config->serialize($opt_key);
}
if ($object->name) {
printf $fh qq{ <metadata type=\"name\">%s</metadata>\n}, $object->name;
}
printf $fh qq{ <mesh>\n};
printf $fh qq{ <vertices>\n};
my @vertices_offset = ();
{
my $vertices_offset = 0;
foreach my $volume (@{ $object->volumes }) {
push @vertices_offset, $vertices_offset;
my $vertices = $volume->mesh->vertices;
foreach my $vertex (@$vertices) {
printf $fh qq{ <vertex>\n};
printf $fh qq{ <coordinates>\n};
printf $fh qq{ <x>%s</x>\n}, $vertex->[X];
printf $fh qq{ <y>%s</y>\n}, $vertex->[Y];
printf $fh qq{ <z>%s</z>\n}, $vertex->[Z];
printf $fh qq{ </coordinates>\n};
printf $fh qq{ </vertex>\n};
}
$vertices_offset += scalar(@$vertices);
}
}
printf $fh qq{ </vertices>\n};
foreach my $volume (@{ $object->volumes }) {
my $vertices_offset = shift @vertices_offset;
printf $fh qq{ <volume%s>\n},
($volume->material_id eq '') ? '' : (sprintf ' materialid="%s"', $volume->material_id);
my $config = $volume->config;
foreach my $opt_key (@{$config->get_keys}) {
printf $fh qq{ <metadata type=\"slic3r.%s\">%s</metadata>\n}, $opt_key, $config->serialize($opt_key);
}
if ($volume->name) {
printf $fh qq{ <metadata type=\"name\">%s</metadata>\n}, $volume->name;
}
if ($volume->modifier) {
printf $fh qq{ <metadata type=\"slic3r.modifier\">1</metadata>\n};
}
foreach my $facet (@{$volume->mesh->facets}) {
printf $fh qq{ <triangle>\n};
printf $fh qq{ <v%d>%d</v%d>\n}, $_, $facet->[$_-1] + $vertices_offset, $_ for 1..3;
printf $fh qq{ </triangle>\n};
}
printf $fh qq{ </volume>\n};
}
printf $fh qq{ </mesh>\n};
printf $fh qq{ </object>\n};
if ($object->instances) {
foreach my $instance (@{$object->instances}) {
$instances .= sprintf qq{ <instance objectid="%d">\n}, $object_id;
$instances .= sprintf qq{ <deltax>%s</deltax>\n}, $instance->offset->[X];
$instances .= sprintf qq{ <deltay>%s</deltay>\n}, $instance->offset->[Y];
$instances .= sprintf qq{ <rz>%s</rz>\n}, $instance->rotation;
$instances .= sprintf qq{ </instance>\n};
}
}
}
if ($instances) {
printf $fh qq{ <constellation id="1">\n};
printf $fh $instances;
printf $fh qq{ </constellation>\n};
}
printf $fh qq{</amf>\n};
close $fh;
}
1;

View File

@ -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;

View File

@ -1,34 +0,0 @@
package Slic3r::Format::OBJ;
use Moo;
use File::Basename qw(basename);
sub read_file {
my $self = shift;
my ($file) = @_;
Slic3r::open(\my $fh, '<', $file) or die "Failed to open $file\n";
my $vertices = [];
my $facets = [];
while (<$fh>) {
if (/^v ([^ ]+)\s+([^ ]+)\s+([^ ]+)/) {
push @$vertices, [$1, $2, $3];
} elsif (/^f (\d+).*? (\d+).*? (\d+).*?/) {
push @$facets, [ $1-1, $2-1, $3-1 ];
}
}
close $fh;
my $mesh = Slic3r::TriangleMesh->new;
$mesh->ReadFromPerl($vertices, $facets);
$mesh->check_topology;
my $model = Slic3r::Model->new;
my $basename = basename($file);
my $object = $model->add_object(input_file => $file, name => $basename);
my $volume = $object->add_volume(mesh => $mesh, name => $basename);
return $model;
}
1;

View File

@ -1,41 +0,0 @@
package Slic3r::Format::STL;
use Moo;
use File::Basename qw(basename);
sub read_file {
my $self = shift;
my ($file) = @_;
my $path = Slic3r::encode_path($file);
die "Failed to open $file\n" if !-e $path;
my $mesh = Slic3r::TriangleMesh->new;
$mesh->ReadSTLFile($path);
$mesh->check_topology;
die "This STL file couldn't be read because it's empty.\n"
if $mesh->facets_count == 0;
my $model = Slic3r::Model->new;
my $basename = basename($file);
my $object = $model->add_object(input_file => $file, name => $basename);
my $volume = $object->add_volume(mesh => $mesh, name => $basename);
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;

View File

@ -85,7 +85,8 @@ sub _discharge {
$self->_extrusion_axis, $new_E, $F // $self->_unretract_speed;
$gcode .= sprintf "G92 %s%.5f ; restore E\n", $self->_extrusion_axis, $self->reader->E
if !$self->config->use_relative_e_distances;
$gcode .= sprintf "G1 F%.3f ; restore F\n", $oldSpeed;
$gcode .= sprintf "G1 F%.3f ; restore F\n", $oldSpeed
if $oldSpeed;
$self->_advance(0);
return $gcode;

View File

@ -50,7 +50,6 @@ use constant PI => 3.1415927;
# Constant to determine if Vertex Buffer objects are used to draw
# bed grid and the cut plane for object separation.
# Old Perl (5.10.x) should set to 0.
use constant HAS_VBO => 1;
@ -854,8 +853,8 @@ sub Render {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnableClientState(GL_VERTEX_ARRAY);
my $triangle_vertex;
if (HAS_VBO) {
my ($triangle_vertex);
($triangle_vertex) =
glGenBuffersARB_p(1);
$self->bed_triangles->bind($triangle_vertex);
@ -863,7 +862,7 @@ sub Render {
glVertexPointer_c(3, GL_FLOAT, 0, 0);
} else {
# fall back on old behavior
glVertexPointer_p(3, $self->bed_triangles);
glVertexPointer_c(3, GL_FLOAT, 0, $self->bed_triangles->ptr());
}
glColor4f(0.8, 0.6, 0.5, 0.4);
glNormal3d(0,0,1);
@ -877,8 +876,8 @@ sub Render {
# draw grid
glLineWidth(3);
glEnableClientState(GL_VERTEX_ARRAY);
my $grid_vertex;
if (HAS_VBO) {
my ($grid_vertex);
($grid_vertex) =
glGenBuffersARB_p(1);
$self->bed_grid_lines->bind($grid_vertex);
@ -886,7 +885,7 @@ sub Render {
glVertexPointer_c(3, GL_FLOAT, 0, 0);
} else {
# fall back on old behavior
glVertexPointer_p(3, $self->bed_grid_lines);
glVertexPointer_c(3, GL_FLOAT, 0, $self->bed_grid_lines->ptr());
}
glColor4f(0.2, 0.2, 0.2, 0.4);
glNormal3d(0,0,1);
@ -898,6 +897,8 @@ sub Render {
# Turn off buffer objects to let the rest of the draw code work.
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
glDeleteBuffersARB_p($grid_vertex);
glDeleteBuffersARB_p($triangle_vertex);
}
}
@ -1086,17 +1087,18 @@ sub draw_volumes {
}
glDisableClientState(GL_NORMAL_ARRAY);
glDisable(GL_BLEND);
my $cut_vertex;
if (defined $self->cutting_plane_z) {
if (HAS_VBO) {
# Use Vertex Buffer Object for cutting plane (previous method crashes on modern POGL).
my ($cut_vertex) = glGenBuffersARB_p(1);
($cut_vertex) = glGenBuffersARB_p(1);
$self->cut_lines_vertices->bind($cut_vertex);
glBufferDataARB_p(GL_ARRAY_BUFFER_ARB, $self->cut_lines_vertices, GL_STATIC_DRAW_ARB);
glVertexPointer_c(3, GL_FLOAT, 0, 0);
} else {
# Use legacy method.
glVertexPointer_p(3, $self->cut_lines_vertices);
glVertexPointer_c(3, GL_FLOAT, 0, $self->cut_lines_vertices->ptr());
}
glLineWidth(2);
glColor3f(0, 0, 0);
@ -1106,6 +1108,7 @@ sub draw_volumes {
# Turn off buffer objects to let the rest of the draw code work.
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
glDeleteBuffersARB_p($cut_vertex);
}
}

View File

@ -212,9 +212,9 @@ sub _update_shape {
my $rect_origin = $self->{optgroups}[SHAPE_RECTANGULAR]->get_value('rect_origin');
my ($x, $y) = @$rect_size;
return if !looks_like_number($x) || !looks_like_number($y); # empty strings or '-' or other things
return if !$x || !$y;
return if !$x || !$y or $x == 0 or $y == 0;
my ($x0, $y0) = (0,0);
my ($x1, $y1) = ($x,$y);
my ($x1, $y1) = ($x ,$y);
{
my ($dx, $dy) = @$rect_origin;
return if !looks_like_number($dx) || !looks_like_number($dy); # empty strings or '-' or other things
@ -231,7 +231,7 @@ sub _update_shape {
]);
} elsif ($page_idx == SHAPE_CIRCULAR) {
my $diameter = $self->{optgroups}[SHAPE_CIRCULAR]->get_value('diameter');
return if !$diameter;
return if !$diameter or $diameter == 0;
my $r = $diameter/2;
my $twopi = 2*PI;
my $edges = 60;

View File

@ -506,17 +506,6 @@ sub repair_stl {
Slic3r::GUI::show_info($self, "Your file was repaired.", "Repair");
}
sub extra_variables {
my $self = shift;
my %extra_variables = ();
if ($self->{mode} eq 'expert') {
$extra_variables{"${_}_preset"} = $self->{options_tabs}{$_}->get_current_preset->name
for qw(print filament printer);
}
return { %extra_variables };
}
sub export_config {
my $self = shift;

View File

@ -350,7 +350,7 @@ sub get_option {
$self->_opt_map->{$opt_id} = [ $opt_key, $opt_index ];
my $optdef = $Slic3r::Config::Options->{$opt_key}; # we should access this from $self->config
my $default_value = $self->_get_config_value($opt_key, $opt_index, $optdef->{gui_flags} =~ /\bserialized\b/);
my $default_value = $self->_get_config_value($opt_key, $opt_index, $optdef->{type} eq 's@');
return Slic3r::GUI::OptionsGroup::Option->new(
opt_id => $opt_id,
@ -395,7 +395,7 @@ sub reload_config {
foreach my $opt_id (keys %{ $self->_opt_map }) {
my ($opt_key, $opt_index) = @{ $self->_opt_map->{$opt_id} };
my $option = $self->_options->{$opt_id};
$self->set_value($opt_id, $self->_get_config_value($opt_key, $opt_index, $option->gui_flags =~ /\bserialized\b/));
$self->set_value($opt_id, $self->_get_config_value($opt_key, $opt_index, $option->type eq 's@'));
}
}
@ -409,15 +409,16 @@ sub get_fieldc {
}
sub _get_config_value {
my ($self, $opt_key, $opt_index, $deserialize) = @_;
my ($self, $opt_key, $opt_index, $as_string) = @_;
if ($deserialize) {
die "Can't deserialize option indexed value" if $opt_index != -1;
return $self->config->serialize($opt_key);
if ($opt_index == -1) {
my $value = $self->config->get($opt_key);
if ($as_string && ref($value) eq 'ARRAY') {
return join "\n", @$value;
}
return $value;
} else {
return $opt_index == -1
? $self->config->get($opt_key)
: $self->config->get_at($opt_key, $opt_index);
return $self->config->get_at($opt_key, $opt_index);
}
}
@ -430,17 +431,15 @@ sub _on_change {
# get value
my $field_value = $self->get_value($opt_id);
if ($option->gui_flags =~ /\bserialized\b/) {
die "Can't set serialized option indexed value" if $opt_index != -1;
$self->config->set_deserialize($opt_key, $field_value);
} else {
if ($opt_index == -1) {
$self->config->set($opt_key, $field_value);
} else {
my $value = $self->config->get($opt_key);
$value->[$opt_index] = $field_value;
$self->config->set($opt_key, $value);
if ($opt_index == -1) {
if ($option->type eq 's@' && ref($field_value) ne 'ARRAY') {
$field_value = [ split /(?<!\\)[;\n]/, $field_value ];
}
$self->config->set($opt_key, $field_value);
} else {
my $value = $self->config->get($opt_key);
$value->[$opt_index] = $field_value;
$self->config->set($opt_key, $value);
}
}

View File

@ -257,7 +257,7 @@ sub new {
$self->{print_file} = $self->export_gcode(Wx::StandardPaths::Get->GetTempDir());
});
EVT_BUTTON($self, $self->{btn_send_gcode}, sub {
my $filename = basename($self->{print}->output_filepath($main::opt{output}));
my $filename = basename($self->{print}->output_filepath($main::opt{output} // ''));
$filename = Wx::GetTextFromUser("Save to printer with the following name:",
"OctoPrint", $filename, $self);
@ -536,12 +536,15 @@ sub update_presets {
}
if ($selected <= $#$presets) {
my $preset_name = $choice->GetString($selected);
if ($is_dirty) {
$choice->SetString($selected, $choice->GetString($selected) . " (modified)");
$choice->SetString($selected, "$preset_name (modified)");
}
# call SetSelection() only after SetString() otherwise the new string
# won't be picked up as the visible string
$choice->SetSelection($selected);
$self->{print}->placeholder_parser->set("${group}_preset", $preset_name);
}
}
}
@ -1124,12 +1127,6 @@ sub start_background_process {
return;
}
# apply extra variables
{
my $extra = $self->GetFrame->extra_variables;
$self->{print}->placeholder_parser->set($_, $extra->{$_}) for keys %$extra;
}
# start thread
@_ = ();
$self->{process_thread} = Slic3r::spawn_thread(sub {
@ -1233,7 +1230,7 @@ sub export_gcode {
if ($output_file) {
$self->{export_gcode_output_file} = $self->{print}->output_filepath($output_file);
} else {
my $default_output_file = $self->{print}->output_filepath($main::opt{output});
my $default_output_file = $self->{print}->output_filepath($main::opt{output} // '');
my $dlg = Wx::FileDialog->new($self, 'Save G-code file as:', wxTheApp->output_path(dirname($default_output_file)),
basename($default_output_file), &Slic3r::GUI::FILE_WILDCARDS->{gcode}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if ($dlg->ShowModal != wxID_OK) {
@ -1435,7 +1432,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");
}
@ -1482,7 +1479,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");
}
@ -1492,7 +1489,7 @@ sub export_amf {
return if !@{$self->{objects}};
my $output_file = $self->_get_export_file('AMF') or return;
Slic3r::Format::AMF->write_file($output_file, $self->{model});
$self->{model}->write_amf($output_file);
$self->statusbar->SetStatusText("AMF file exported to $output_file");
}
@ -1504,7 +1501,7 @@ sub _get_export_file {
my $output_file = $main::opt{output};
{
$output_file = $self->{print}->output_filepath($output_file);
$output_file = $self->{print}->output_filepath($output_file // '');
$output_file =~ s/\.gcode$/$suffix/i;
my $dlg = Wx::FileDialog->new($self, "Save $format file as:", dirname($output_file),
basename($output_file), &Slic3r::GUI::MODEL_WILDCARD, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);

View File

@ -451,7 +451,7 @@ sub set_value {
package Slic3r::GUI::Tab::Print;
use base 'Slic3r::GUI::Tab';
use List::Util qw(first);
use List::Util qw(first any);
use Wx qw(:icon :dialog :id);
sub name { 'print' }
@ -467,7 +467,7 @@ sub build {
top_solid_layers bottom_solid_layers
extra_perimeters avoid_crossing_perimeters thin_walls overhangs
seam_position external_perimeters_first
fill_density fill_pattern external_fill_pattern
fill_density fill_pattern external_fill_pattern fill_gaps
infill_every_layers infill_only_where_needed
solid_infill_every_layers fill_angle solid_infill_below_area
only_retract_when_crossing_perimeters infill_first
@ -556,6 +556,7 @@ sub build {
}
{
my $optgroup = $page->new_optgroup('Advanced');
$optgroup->append_single_option_line('fill_gaps');
$optgroup->append_single_option_line('solid_infill_every_layers');
$optgroup->append_single_option_line('fill_angle');
$optgroup->append_single_option_line('solid_infill_below_area');
@ -614,10 +615,10 @@ sub build {
$optgroup->append_single_option_line('infill_speed');
$optgroup->append_single_option_line('solid_infill_speed');
$optgroup->append_single_option_line('top_solid_infill_speed');
$optgroup->append_single_option_line('gap_fill_speed');
$optgroup->append_single_option_line('support_material_speed');
$optgroup->append_single_option_line('support_material_interface_speed');
$optgroup->append_single_option_line('bridge_speed');
$optgroup->append_single_option_line('gap_fill_speed');
}
{
my $optgroup = $page->new_optgroup('Speed for non-print moves');
@ -846,12 +847,19 @@ sub _update {
$self->get_field($_)->toggle($have_infill || $have_solid_infill)
for qw(fill_angle infill_extrusion_width infill_speed bridge_speed);
$self->get_field('gap_fill_speed')->toggle($have_perimeters && $have_infill);
$self->get_field('fill_gaps')->toggle($have_perimeters && $have_infill);
$self->get_field('gap_fill_speed')->toggle($have_perimeters && $have_infill && $config->fill_gaps);
my $have_top_solid_infill = $config->top_solid_layers > 0;
$self->get_field($_)->toggle($have_top_solid_infill)
for qw(top_infill_extrusion_width top_solid_infill_speed);
my $have_autospeed = any { $config->get("${_}_speed") eq '0' }
qw(perimeter external_perimeter small_perimeter
infill solid_infill top_solid_infill gap_fill support_material
support_material_interface);
$self->get_field('max_print_speed')->toggle($have_autospeed);
my $have_default_acceleration = $config->default_acceleration > 0;
$self->get_field($_)->toggle($have_default_acceleration)
for qw(perimeter_acceleration infill_acceleration bridge_acceleration first_layer_acceleration);

View 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 = @_;

View File

@ -101,7 +101,16 @@ sub export_gcode {
# close our gcode file
close $fh;
rename $tempfile, $output_file if $tempfile;
if ($tempfile) {
my $renamed = 0;
for my $i (1..5) {
last if $renamed = rename Slic3r::encode_path($tempfile), Slic3r::encode_path($output_file);
# Wait for 1/4 seconds and try to rename once again.
select(undef, undef, undef, 0.25);
}
Slic3r::debugf "Failed to remove the output G-code file from $tempfile to $output_file. Is $tempfile locked?\n"
if !$renamed;
}
}
# run post-processing scripts

View File

@ -14,6 +14,7 @@ has '_skirt_done' => (is => 'rw', default => sub { {} }); #
has '_brim_done' => (is => 'rw');
has '_second_layer_things_done' => (is => 'rw');
has '_last_obj_copy' => (is => 'rw');
has '_autospeed' => (is => 'rw', default => sub { 0 }); # boolean
use List::Util qw(first sum min max);
use Slic3r::ExtrusionPath ':roles';
@ -43,59 +44,6 @@ sub BUILD {
$gcodegen->set_enable_cooling_markers(1);
$gcodegen->apply_print_config($self->config);
$gcodegen->set_extruders($self->print->extruders);
# initialize autospeed
{
# get the minimum cross-section used in the print
my @mm3_per_mm = ();
foreach my $object (@{$self->print->objects}) {
foreach my $region_id (0..$#{$self->print->regions}) {
my $region = $self->print->get_region($region_id);
foreach my $layer (@{$object->layers}) {
my $layerm = $layer->get_region($region_id);
if ($region->config->get_abs_value('perimeter_speed') == 0
|| $region->config->get_abs_value('small_perimeter_speed') == 0
|| $region->config->get_abs_value('external_perimeter_speed') == 0
|| $region->config->get_abs_value('bridge_speed') == 0) {
push @mm3_per_mm, $layerm->perimeters->min_mm3_per_mm;
}
if ($region->config->get_abs_value('infill_speed') == 0
|| $region->config->get_abs_value('solid_infill_speed') == 0
|| $region->config->get_abs_value('top_solid_infill_speed') == 0
|| $region->config->get_abs_value('bridge_speed') == 0) {
push @mm3_per_mm, $layerm->fills->min_mm3_per_mm;
}
}
}
if ($object->config->get_abs_value('support_material_speed') == 0
|| $object->config->get_abs_value('support_material_interface_speed') == 0) {
foreach my $layer (@{$object->support_layers}) {
push @mm3_per_mm, $layer->support_fills->min_mm3_per_mm;
push @mm3_per_mm, $layer->support_interface_fills->min_mm3_per_mm;
}
}
}
# filter out 0-width segments
@mm3_per_mm = grep $_ > 0.000001, @mm3_per_mm;
if (@mm3_per_mm) {
my $min_mm3_per_mm = min(@mm3_per_mm);
# In order to honor max_print_speed we need to find a target volumetric
# speed that we can use throughout the print. So we define this target
# volumetric speed as the volumetric speed produced by printing the
# smallest cross-section at the maximum speed: any larger cross-section
# will need slower feedrates.
my $volumetric_speed = $min_mm3_per_mm * $self->config->max_print_speed;
# limit such volumetric speed with max_volumetric_speed if set
if ($self->config->max_volumetric_speed > 0) {
$volumetric_speed = min(
$volumetric_speed,
$self->config->max_volumetric_speed,
);
}
$gcodegen->set_volumetric_speed($volumetric_speed);
}
}
}
$self->_cooling_buffer(Slic3r::GCode::CoolingBuffer->new($self->_gcodegen));
@ -365,6 +313,56 @@ sub process_layer {
# if we're going to apply spiralvase to this layer, disable loop clipping
$self->_gcodegen->set_enable_loop_clipping(!defined $self->_spiral_vase || !$self->_spiral_vase->enable);
# initialize autospeed
{
# get the minimum cross-section used in the layer
my @mm3_per_mm = ();
foreach my $region_id (0..$#{$self->print->regions}) {
my $region = $self->print->get_region($region_id);
my $layerm = $layer->region($region_id);
if ($region->config->get_abs_value('perimeter_speed') == 0
|| $region->config->get_abs_value('small_perimeter_speed') == 0
|| $region->config->get_abs_value('external_perimeter_speed') == 0
|| $region->config->get_abs_value('bridge_speed') == 0) {
push @mm3_per_mm, $layerm->perimeters->min_mm3_per_mm;
}
if ($region->config->get_abs_value('infill_speed') == 0
|| $region->config->get_abs_value('solid_infill_speed') == 0
|| $region->config->get_abs_value('top_solid_infill_speed') == 0
|| $region->config->get_abs_value('bridge_speed') == 0
|| $region->config->get_abs_value('gap_fill_speed') == 0) {
push @mm3_per_mm, $layerm->fills->min_mm3_per_mm;
}
}
if ($layer->isa('Slic3r::Layer::Support')) {
if ($object->config->get_abs_value('support_material_speed') == 0
|| $object->config->get_abs_value('support_material_interface_speed') == 0) {
push @mm3_per_mm, $layer->support_fills->min_mm3_per_mm;
push @mm3_per_mm, $layer->support_interface_fills->min_mm3_per_mm;
}
}
# filter out 0-width segments
@mm3_per_mm = grep $_ > 0.000001, @mm3_per_mm;
if (@mm3_per_mm) {
my $min_mm3_per_mm = min(@mm3_per_mm);
# In order to honor max_print_speed we need to find a target volumetric
# speed that we can use throughout the print. So we define this target
# volumetric speed as the volumetric speed produced by printing the
# smallest cross-section at the maximum speed: any larger cross-section
# will need slower feedrates.
my $volumetric_speed = $min_mm3_per_mm * $self->config->max_print_speed;
# limit such volumetric speed with max_volumetric_speed if set
if ($self->config->max_volumetric_speed > 0) {
$volumetric_speed = min(
$volumetric_speed,
$self->config->max_volumetric_speed,
);
}
$self->_gcodegen->set_volumetric_speed($volumetric_speed);
}
}
if (!$self->_second_layer_things_done && $layer->id == 1) {
for my $extruder (@{$self->_gcodegen->writer->extruders}) {
my $temperature = $self->config->get_at('temperature', $extruder->id);

60
package/deploy-bintray.sh Executable file
View File

@ -0,0 +1,60 @@
#!/bin/bash
# Prerequistes
# Environment variables:
# BINTRAY_API_KEY - Working API key
# BINTRAY_API_USER - Bintray username.
# Run this from the repository root (required to get slic3r version)
SLIC3R_VERSION=$(grep "VERSION" xs/src/libslic3r/libslic3r.h | awk -F\" '{print $2}')
if [ $(git describe &>/dev/null) ]; then
SLIC3R_BUILD_ID=$(git describe)
TAGGED=true
else
SLIC3R_BUILD_ID=${SLIC3R_VERSION}-$(git rev-parse --short HEAD)
fi
if [ -z ${GIT_BRANCH+x} ] && [ -z ${APPVEYOR_REPO_BRANCH+x} ]; then
current_branch=$(git symbolic-ref HEAD | sed 's!refs\/heads\/!!')
else
current_branch="unknown"
if [ ! -z ${GIT_BRANCH+x} ]; then
echo "Setting to GIT_BRANCH"
current_branch=$(echo $GIT_BRANCH | cut -d / -f 2)
fi
if [ ! -z ${APPVEYOR_REPO_BRANCH+x} ]; then
echo "Setting to APPVEYOR_REPO_BRANCH"
current_branch=$APPVEYOR_REPO_BRANCH
fi
fi
if [ -z ${current_branch+x} ]; then
current_branch="unknown"
fi
if [ "$current_branch" == "master" ] && [ "$APPVEYOR_PULL_REQUEST_NUMBER" == "" ]; then
# If building master, goes in slic3r_dev or slic3r, depending on whether or not this is a tagged build
if [ -z ${TAGGED+x} ]; then
SLIC3R_PKG=slic3r_dev
else
SLIC3R_PKG=slic3r
fi
version=$SLIC3R_BUILD_ID
else
# If building a branch, put the package somewhere else.
SLIC3R_PKG=Slic3r_Branches
version=$SLIC3R_BUILD_ID-$current_branch
fi
file=$1
echo "Deploying $file to $version on Bintray repo $SLIC3R_PKG..."
API=${BINTRAY_API_KEY}
USER=${BINTRAY_API_USER}
echo "Creating version: $version"
curl -X POST -d "{ \"name\": \"$version\", \"released\": \"ISO8601 $(date +%Y-%m-%d'T'%H:%M:%S)\", \"desc\": \"This version...\", \"github_release_notes_file\": \"RELEASE.txt\", \"github_use_tag_release_notes\": true, \"vcs_tag\": \"$version\" }" -u${USER}:${API} https://api.bintray.com/content/lordofhyphens/Slic3r/${SLIC3R_PKG}/versions
echo "Publishing ${file} to ${version}..."
curl -H "X-Bintray-Package: $SLIC3R_PKG" -H "X-Bintray-Version: $version" -H 'X-Bintray-Publish: 1' -H 'X-Bintray-Override: 1' -T $file -u${USER}:${API} https://api.bintray.com/content/lordofhyphens/Slic3r/$(basename $1)
#curl -X POST -u${USER}:${API} https://api.bintray.com/content/lordofhyphens/Slic3r/${SLIC3R_PKG}/$version/publish
# Wait 5s for the server to catch up
sleep 5
curl -H 'Content-Type: application/json' -X PUT -d "{ \"list_in_downloads\":true }" -u${USER}:${API} https://api.bintray.com/file_metadata/lordofhyphens/Slic3r/$(basename $1)

6
package/linux/package_linux.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash
# Written by Joseph Lenox
# Licensed under the same license as the rest of Slic3r.
# ------------------------
pp -a "../../utils;utils" -a "../../var;var" -a "../../lib;lib" -a "../../local-lib;local-lib" -a "../../slic3r.pl;slic3r.pl" -M AutoLoader -M B -M Carp -M Class::Accessor -M Class::XSAccessor -M Class::XSAccessor::Heavy -M Config -M Cwd -M Devel::GlobalDestruction -M Digest -M Digest::MD5 -M Digest::SHA -M Digest::base -M DynaLoader -M Errno -M Exporter -M Exporter::Heavy -M Fcntl -M File::Basename -M File::Glob -M File::Spec -M File::Spec::Unix -M File::Spec::Win32 -M FindBin -M HTTP::Config -M HTTP::Date -M HTTP::Headers -M HTTP::Headers::Util -M HTTP::Message -M HTTP::Request -M HTTP::Request::Common -M HTTP::Response -M HTTP::Status -M IO -M IO::Handle -M IO::Select -M LWP -M LWP::MediaTypes -M LWP::MemberMixin -M LWP::Protocol -M LWP::Protocol::http -M LWP::UserAgent -M List::Util -M Math::Trig -M Method::Generate::Accessor -M Method::Generate::BuildAll -M Method::Generate::Constructor -M Module::Runtime -M POSIX -M Pod::Escapes -M Pod::Text -M Pod::Usage -M SelectSaver -M Socket -M Socket6 -M Storable -M Sub::Defer -M Sub::Exporter -M Sub::Exporter::Progressive -M Sub::Name -M Symbol -M Term::Cap -M Text::ParseWords -M Thread -M Thread::Queue -M Thread::Semaphore -M Tie::Handle -M Tie::Hash -M Tie::StdHandle -M Time::Local -M URI -M URI::Escape -M URI::http -M Unicode::Normalize -M XSLoader -B -M lib -p ../../slic3r.pl -o ../../slic3r.par

119
package/osx/make_dmg.sh Executable file
View File

@ -0,0 +1,119 @@
#!/bin/bash
# Assembles an installation bundle from a built copy of Slic3r.
# Requires PAR::Packer to be installed for the version of
# perl copied.
# Adapted from script written by bubnikv for Prusa3D.
# Run from slic3r repo root directory.
SLIC3R_VERSION=$(grep "VERSION" xs/src/libslic3r/libslic3r.h | awk -F\" '{print $2}')
if [ "$#" -ne 1 ]; then
echo "Usage: $(basename $0) dmg_name"
exit 1;
fi
WD=$(dirname $0)
# Determine if this is a tagged (release) commit.
# Change the build id accordingly.
if [ $(git describe &>/dev/null) ]; then
TAGGED=true
SLIC3R_BUILD_ID=$(git describe)
else
TAGGED=false
SLIC3R_BUILD_ID=${SLIC3R_VERSION}
fi
if [ -z ${GIT_BRANCH+x} ] && [ -z ${APPVEYOR_REPO_BRANCH+x} ]; then
current_branch=$(git symbolic-ref HEAD | sed 's!refs\/heads\/!!')
else
current_branch="unknown"
if [ ! -z ${GIT_BRANCH+x} ]; then
echo "Setting to GIT_BRANCH"
current_branch=$(echo $GIT_BRANCH | cut -d / -f 2)
fi
if [ ! -z ${APPVEYOR_REPO_BRANCH+x} ]; then
echo "Setting to APPVEYOR_REPO_BRANCH"
current_branch=$APPVEYOR_REPO_BRANCH
fi
fi
# If we're on a branch, add the branch name to the app name.
if [ "$current_branch" == "master" ]; then
appname=Slic3r
dmgfile=slic3r-${SLIC3R_BUILD_ID}-${1}.dmg
else
appname=Slic3r-$(git symbolic-ref HEAD | sed 's!refs\/heads\/!!')
dmgfile=slic3r-${SLIC3R_BUILD_ID}-${1}-$(git symbolic-ref HEAD | sed 's!refs\/heads\/!!').dmg
fi
rm -rf $WD/_tmp
mkdir -p $WD/_tmp
# OSX Application folder shenanigans.
appfolder="$WD/${appname}.app"
macosfolder=$appfolder/Contents/MacOS
resourcefolder=$appfolder/Contents/Resources
plistfile=$appfolder/Contents/Info.plist
PkgInfoContents="APPL????"
source $WD/plist.sh
# Our slic3r dir and location of perl
PERL_BIN=$(which perl)
PP_BIN=$(which pp)
SLIC3R_DIR=$(perl -MCwd=realpath -e "print realpath '${WD}/../../'")
if [[ -d "${appfolder}" ]]; then
echo "Deleting old working folder."
rm -rf ${appfolder}
fi
if [[ -e "${dmgfile}" ]]; then
echo "Deleting old dmg ${dmgfile}."
rm -rf ${dmgfile}
fi
echo "Creating new app folder at $appfolder."
mkdir -p $appfolder
mkdir -p $macosfolder
mkdir -p $resourcefolder
echo "Copying resources..."
cp -r $SLIC3R_DIR/var $macosfolder/
mv $macosfolder/var/Slic3r.icns $resourcefolder
echo "Copying Slic3r..."
cp $SLIC3R_DIR/slic3r.pl $macosfolder/slic3r.pl
cp -RP $SLIC3R_DIR/local-lib $macosfolder/local-lib
cp -RP $SLIC3R_DIR/lib/* $macosfolder/local-lib/lib/perl5/
find $macosfolder/local-lib -name man -type d -delete
find $macosfolder/local-lib -name .packlist -delete
rm -rf $macosfolder/local-lib/lib/perl5/darwin-thread-multi-2level/Alien/wxWidgets/osx_cocoa_3_0_2_uni/include
echo "Relocating dylib paths..."
for bundle in $(find $macosfolder/local-lib/lib/perl5/darwin-thread-multi-2level/auto/Wx -name '*.bundle') $(find $macosfolder/local-lib/lib/perl5/darwin-thread-multi-2level/Alien/wxWidgets -name '*.dylib' -type f); do
chmod +w $bundle
find $SLIC3R_DIR/local-lib -name '*.dylib' -exec bash -c 'install_name_tool -change "{}" "@executable_path/local-lib/lib/perl5/darwin-thread-multi-2level/Alien/wxWidgets/osx_cocoa_3_0_2_uni/lib/$(basename {})" '$bundle \;
done
echo "Copying startup script..."
cp $WD/startup_script.sh $macosfolder/$appname
chmod +x $macosfolder/$appname
echo "Copying perl from $PERL_BIN"
cp $PERL_BIN $macosfolder/perl-local
${PP_BIN} -M attributes -M base -M bytes -M B -M POSIX \
-M FindBin -M Unicode::Normalize -M Tie::Handle \
-M Time::Local -M Math::Trig \
-M lib -M overload \
-M warnings -M local::lib \
-M strict -M utf8 -M parent \
-B -p -e "print 123" -o $WD/_tmp/test.par
unzip $WD/_tmp/test.par -d $WD/_tmp/
cp -r $WD/_tmp/lib/* $macosfolder/local-lib/lib/perl5/
rm -rf $WD/_tmp
make_plist
echo $PkgInfoContents >$appfolder/Contents/PkgInfo
echo "Creating dmg file...."
hdiutil create -fs HFS+ -srcfolder "$appfolder" -volname "$appname" "$dmgfile"

98
package/osx/plist.sh Normal file
View File

@ -0,0 +1,98 @@
#!/bin/bash
function make_plist() {
# Create information property list file (Info.plist).
cat << EOF > $plistfile
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>$appname</string>
<key>CFBundleGetInfoString</key>
<string>Slic3r Copyright (C) 2011-$(date +%Y) Alessandro Ranellucci</string>
<key>CFBundleIconFile</key>
<string>Slic3r.icns</string>
<key>CFBundleName</key>
<string>Slic3r</string>
<key>CFBundleShortVersionString</key>
EOF
if [ $TAGGED ]; then
echo " <string>Slic3r $SLIC3R_BUILD_ID</string>" >>$plistfile
else
echo " <string>Slic3r $SLIC3R_BUILD_ID-$(git rev-parse --short head)</string>" >>$plistfile
fi
cat << EOF >> $plistfile
<key>CFBundleIdentifier</key>
<string>org.slic3r.$appname</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${SLIC3R_BUILD_ID}</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>stl</string>
<string>STL</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>Slic3r.icns</string>
<key>CFBundleTypeName</key>
<string>STL</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LISsAppleDefaultForType</key>
<true/>
<key>LSHandlerRank</key>
<string>Alternate</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>obj</string>
<string>OBJ</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>Slic3r.icns</string>
<key>CFBundleTypeName</key>
<string>STL</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LISsAppleDefaultForType</key>
<true/>
<key>LSHandlerRank</key>
<string>Alternate</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>amf</string>
<string>AMF</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>Slic3r.icns</string>
<key>CFBundleTypeName</key>
<string>STL</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LISsAppleDefaultForType</key>
<true/>
<key>LSHandlerRank</key>
<string>Alternate</string>
</dict>
</array>
<key>LSMinimumSystemVersion</key>
<string>10.7</string>
</dict>
</plist>
EOF
}

View File

@ -0,0 +1,4 @@
#!/bin/bash
DIR=$(dirname "$0")
$DIR/perl-local -I$DIR/local-lib/lib/perl5 $DIR/slic3r.pl $@

View File

@ -0,0 +1,15 @@
# Short Powershell script to build a wrapper exec
if ($args[0])
{
$perlver = $args[0]
} else
{
$perlver = 518
}
$perllib = "-lperl$perlver"
windres slic3r.rc -O coff -o slic3r.res
g++ -c -I'C:\strawberry\perl\lib\CORE\' shell.cpp -o slic3r.o
g++ -v -static-libgcc -static-libstdc++ -L'C:\strawberry\c\lib' -L'C:\strawberry\perl\bin' -L'C:\strawberry\perl\lib\CORE\' $perllib slic3r.o slic3r.res -o slic3r.exe | Write-Host

View File

@ -12,6 +12,14 @@ New-Variable -Name "current_branch" -Value ""
New-Variable -Name "current_date" -Value "$(Get-Date -UFormat '%Y.%m.%d')"
New-Variable -Name "output_file" -Value ""
if ($args[0]) {
$perlversion = $args[0]
} else {
$perlversion = "524"
}
$perldll = "perl$perlversion"
git branch | foreach {
if ($env:APPVEYOR) {
if ($_ -match "` (.*)") {
@ -35,25 +43,22 @@ New-Variable -Name "STRAWBERRY_PATH" -Value "C:\Strawberry"
cpanm "PAR::Packer"
pp `
-a "../utils;utils" `
-a "autorun.bat;slic3r.bat" `
-a "../var;var" `
-a "${STRAWBERRY_PATH}\perl\bin\perl5.24.0.exe;perl5.24.0.exe" `
-a "${STRAWBERRY_PATH}\perl\bin\perl524.dll;perl524.dll" `
-a "${STRAWBERRY_PATH}\perl\bin\libgcc_s_sjlj-1.dll;libgcc_s_sjlj-1.dll" `
-a "slic3r.exe;slic3r.exe" `
-a "../../lib;lib" `
-a "../../local-lib;local-lib" `
-a "../../slic3r.pl;slic3r.pl" `
-a "../../utils;utils" `
-a "../../var;var" `
-a "../../FreeGLUT/freeglut.dll;freeglut.dll" `
-a "${STRAWBERRY_PATH}\perl\bin\perl${perlversion}.dll;perl${perlversion}.dll" `
-a "${STRAWBERRY_PATH}\perl\bin\libstdc++-6.dll;libstdc++-6.dll" `
-a "${STRAWBERRY_PATH}\perl\bin\libwinpthread-1.dll;libwinpthread-1.dll" `
-a "${STRAWBERRY_PATH}\perl\bin\freeglut.dll;freeglut.dll" `
-a "${STRAWBERRY_PATH}\c\bin\libglut-0_.dll;libglut-0_.dll" `
-a "../lib;lib" `
-a "../local-lib;local-lib" `
-a "../slic3r.pl;slic3r.pl" `
-a "${STRAWBERRY_PATH}\perl\bin\libgcc_s_sjlj-1.dll;libgcc_s_sjlj-1.dll" `
-a "${STRAWBERRY_PATH}\c\bin\pthreadGC2-w64.dll;pthreadGC2-w64.dll" `
-a "${STRAWBERRY_PATH}\c\bin\libglut-0__.dll;libglut-0__.dll" `
-M AutoLoader `
-M B `
-M Carp `
-M Class::Accessor `
-M Class::XSAccessor `
-M Class::XSAccessor::Heavy `
-M Config `
-M Crypt::CBC `
-M Cwd `
@ -109,7 +114,6 @@ pp `
-M Sub::Exporter `
-M Sub::Exporter::Progressive `
-M Sub::Name `
-M Sub::Util `
-M Symbol `
-M Term::Cap `
-M Text::ParseWords `
@ -124,6 +128,7 @@ pp `
-M URI::Escape `
-M URI::http `
-M Unicode::Normalize `
-M Win32 `
-M Win32::API `
-M Win32::TieRegistry `
-M Win32::WinError `
@ -131,23 +136,23 @@ pp `
-M XSLoader `
-B `
-M lib `
-p ..\slic3r.pl -o ..\${output_file}
-p ..\..\slic3r.pl -o ..\..\${output_file}
# switch renaming based on whether or not using packaged exe or zip
if ($exe) {
if ($env:APPVEYOR) {
copy ..\slic3r.exe "..\slic3r-${current_branch}.${current_date}.${env:APPVEYOR_BUILD_NUMBER}.$(git rev-parse --short HEAD).exe"
copy ..\..\slic3r.exe "..\..\slic3r-${current_branch}.${current_date}.${env:APPVEYOR_BUILD_NUMBER}.$(git rev-parse --short HEAD).exe"
del ..\slic3r.exe
} else {
copy ..\slic3r.exe "..\slic3r-${current_branch}.${current_date}.$(git rev-parse --short HEAD).exe"
del ..\slic3r.exe
copy ..\..\slic3r.exe "..\..\slic3r-${current_branch}.${current_date}.$(git rev-parse --short HEAD).exe"
del ..\..\slic3r.exe
}
} else {
# make this more useful for not being on the appveyor server
if ($env:APPVEYOR) {
copy ..\slic3r.par "..\slic3r-${current_branch}.${current_date}.${env:APPVEYOR_BUILD_NUMBER}.$(git rev-parse --short HEAD).zip"
copy ..\..\slic3r.par "..\..\slic3r-${current_branch}.${current_date}.${env:APPVEYOR_BUILD_NUMBER}.$(git rev-parse --short HEAD).zip"
} else {
copy ..\slic3r.par "..\slic3r-${current_branch}.${current_date}.$(git rev-parse --short HEAD).zip"
del ../slic3r.par
copy ..\..\slic3r.par "..\..\slic3r-${current_branch}.${current_date}.$(git rev-parse --short HEAD).zip"
del ..\..\slic3r.par
}
}

84
package/win/shell.cpp Normal file
View File

@ -0,0 +1,84 @@
#include <EXTERN.h> // from the Perl distribution
#include <perl.h> // from the Perl distribution
// Perl win32 specific includes, found in perl\\lib\\CORE\\win32.h
// Defines the windows specific convenience RunPerl() function,
// which is not available on other operating systems.
#include <win32.h>
// the standard Windows. include
//#include <Windows.h>
#include <cstdio>
#include <cstdlib>
#include <wchar.h>
int main(int argc, char **argv, char **env)
{
// replaces following Windows batch file: @"%~dp0\perl5.24.0.exe"
// "%~dp0\slic3r.pl" --DataDir "C:\Users\Public\Documents\Prusa3D\Slic3r
// settings MK2"%*
// If the Slic3r is installed in a localized directory (containing non-iso
// characters), spaces or semicolons, use short file names.
char exe_path[MAX_PATH] = {0};
char script_path[MAX_PATH];
char** command_line = (char**)malloc(sizeof(char*) * ((++ argc) + 1));
{
// Unicode path. This will not be used directly, but to test, whether
// there are any non-ISO characters, in which case the path is converted to a
// short path (using 8.3 directory names).
wchar_t exe_path_w[MAX_PATH] = {0};
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
bool needs_short_paths = false;
int len;
int i;
GetModuleFileNameA(NULL, exe_path, MAX_PATH-1);
GetModuleFileNameW(NULL, exe_path_w, MAX_PATH-1);
len = strlen(exe_path);
if (len != wcslen(exe_path_w)) {
needs_short_paths = true;
} else {
for (i = 0; i < len; ++ i)
if ((wchar_t)exe_path[i] != exe_path_w[i] || exe_path[i] == ' ' ||
exe_path[i] == ';') {
needs_short_paths = true;
break;
}
}
if (needs_short_paths) {
wchar_t exe_path_short[MAX_PATH] = {0};
GetShortPathNameW(exe_path_w, exe_path_short, MAX_PATH);
len = wcslen(exe_path_short);
for (i = 0; i <= len; ++ i)
exe_path[i] = (char)exe_path_short[i];
}
_splitpath(exe_path, drive, dir, fname, ext);
_makepath(script_path, drive, dir, NULL, NULL);
if (needs_short_paths)
printf("Slic3r installed in a loclized path. Using an 8.3 path: \"%s\"\n",
script_path);
SetDllDirectoryA(script_path);
_makepath(script_path, drive, dir, "slic3r", "pl");
command_line[0] = exe_path;
command_line[1] = script_path;
memcpy(command_line + 2, argv + 1, sizeof(char*) * (argc - 2));
command_line[argc] = NULL;
// Unset the PERL5LIB and PERLLIB environment variables.
SetEnvironmentVariable("PERL5LIB", NULL);
SetEnvironmentVariable("PERLLIB", NULL);
#if 0
printf("Arguments: \r\n");
for (size_t i = 0; i < argc + 1; ++ i)
printf(" %d: %s\r\n", i, command_line[i]);
#endif
}
RunPerl(argc, command_line, NULL);
free(command_line);
}

25
package/win/slic3r.rc Normal file
View File

@ -0,0 +1,25 @@
id ICON "../../var/Slic3r.ico"
1 VERSIONINFO
FILEVERSION 1,3,0,0
PRODUCTVERSION 1,3,0,0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "Slic3r.org"
VALUE "FileDescription", "3D Printer Slicer application"
VALUE "FileVersion", "1.3.0"
VALUE "InternalName", "slic3r"
VALUE "LegalCopyright", "Alessandro Ranellucci"
VALUE "OriginalFilename", "slic3r.exe"
VALUE "ProductName", "Slic3r"
VALUE "ProductVersion", "1.3.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END

View File

@ -112,12 +112,14 @@ if ((!@ARGV || $opt{gui}) && !$opt{save} && eval "require Slic3r::GUI; 1") {
}
$gui = Slic3r::GUI->new;
setlocale(LC_NUMERIC, 'C');
$gui->{mainframe}->load_config_file($_) for @{$opt{load}};
$gui->{mainframe}->load_config($cli_config);
foreach my $input_file (@ARGV) {
$input_file = Slic3r::decode_path($input_file);
$gui->{mainframe}{plater}->load_file($input_file) unless $opt{no_plater};
}
$gui->CallAfter(sub {
$gui->{mainframe}->load_config_file($_) for @{$opt{load}};
$gui->{mainframe}->load_config($cli_config);
foreach my $input_file (@ARGV) {
$input_file = Slic3r::decode_path($input_file);
$gui->{mainframe}{plater}->load_file($input_file) unless $opt{no_plater};
}
});
$gui->MainLoop;
exit;
}
@ -217,7 +219,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;
@ -428,6 +430,7 @@ $j
--fill-density Infill density (range: 0%-100%, default: $config->{fill_density}%)
--fill-angle Infill angle in degrees (range: 0-90, default: $config->{fill_angle})
--fill-pattern Pattern to use to fill non-solid layers (default: $config->{fill_pattern})
--fill-gaps Fill gaps with single passes (default: yes)
--external-fill-pattern Pattern to use to fill solid layers (default: $config->{external_fill_pattern})
--start-gcode Load initial G-code from the supplied file. This will overwrite
the default command (home all axes [G28]).

View File

@ -30,6 +30,7 @@ include_directories(${LIBDIR}/libslic3r)
include_directories(${LIBDIR}/Slic3r/GUI/)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/standalone/)
include_directories(${LIBDIR}/admesh/)
include_directories(${LIBDIR}/expat/)
include_directories(${LIBDIR}/poly2tri/)
include_directories(${LIBDIR}/poly2tri/sweep)
include_directories(${LIBDIR}/poly2tri/common)
@ -57,6 +58,7 @@ add_library(libslic3r STATIC
${LIBDIR}/libslic3r/GCodeWriter.cpp
${LIBDIR}/libslic3r/Geometry.cpp
${LIBDIR}/libslic3r/IO.cpp
${LIBDIR}/libslic3r/IO/AMF.cpp
${LIBDIR}/libslic3r/Layer.cpp
${LIBDIR}/libslic3r/LayerRegion.cpp
${LIBDIR}/libslic3r/LayerRegionFill.cpp
@ -89,6 +91,11 @@ add_library(admesh STATIC
${LIBDIR}/admesh/util.c
)
add_library(clipper STATIC ${LIBDIR}/clipper.cpp)
add_library(expat STATIC
${LIBDIR}/expat/xmlparse.c
${LIBDIR}/expat/xmlrole.c
${LIBDIR}/expat/xmltok.c
)
add_library(polypartition STATIC ${LIBDIR}/polypartition.cpp)
add_library(poly2tri STATIC
${LIBDIR}/poly2tri/common/shapes.cc
@ -130,12 +137,12 @@ IF(wxWidgets_FOUND)
INCLUDE("${wxWidgets_USE_FILE}")
add_library(slic3r_gui STATIC ${LIBDIR}/slic3r/GUI/3DScene.cpp ${LIBDIR}/slic3r/GUI/GUI.cpp)
#only build GUI lib if building with wx
target_link_libraries (slic3r slic3r_gui libslic3r admesh clipper polypartition poly2tri ${Boost_LIBRARIES} ${wxWidgets_LIBRARIES})
target_link_libraries (slic3r slic3r_gui libslic3r admesh clipper expat polypartition poly2tri ${Boost_LIBRARIES} ${wxWidgets_LIBRARIES})
ELSE(wxWidgets_FOUND)
# For convenience. When we cannot continue, inform the user
MESSAGE("wx not found!")
target_link_libraries (slic3r libslic3r admesh clipper polypartition poly2tri ${Boost_LIBRARIES})
target_link_libraries (slic3r libslic3r admesh clipper expat polypartition poly2tri ${Boost_LIBRARIES})
#skip gui when no wx included
ENDIF(wxWidgets_FOUND)
target_link_libraries (extrude-tin libslic3r admesh clipper polypartition poly2tri ${Boost_LIBRARIES})
target_link_libraries (extrude-tin libslic3r admesh clipper expat polypartition poly2tri ${Boost_LIBRARIES})

View File

@ -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);

View File

@ -2,7 +2,7 @@ use Test::More;
use strict;
use warnings;
plan tests => 12;
plan tests => 13;
BEGIN {
use FindBin;
@ -10,7 +10,7 @@ BEGIN {
use local::lib "$FindBin::Bin/../local-lib";
}
use List::Util qw(first);
use List::Util qw(none all);
use Slic3r;
use Slic3r::Test;
@ -141,21 +141,33 @@ $config->set('disable_fan_first_layers', 0);
$config->set('slowdown_below_layer_time', 10);
$config->set('min_print_speed', 0);
$config->set('start_gcode', '');
$config->set('first_layer_speed', '100%');
$config->set('external_perimeter_speed', 99);
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
my @layer_times = (0); # in seconds
my %layer_external = (); # z => 1
Slic3r::GCode::Reader->new->parse(my $gcode = Slic3r::Test::gcode($print), sub {
my ($self, $cmd, $args, $info) = @_;
if ($cmd eq 'G1') {
if ($info->{dist_Z}) {
push @layer_times, 0;
$layer_external{ $args->{Z} } = 0;
}
$layer_times[-1] += abs($info->{dist_XY} || $info->{dist_E} || $info->{dist_Z} || 0) / ($args->{F} // $self->F) * 60;
if ($args->{F} && $args->{F} == $config->external_perimeter_speed*60) {
$layer_external{ $self->Z }++;
}
}
});
my $all_below = !defined first { $_ > 0 && $_ < $config->slowdown_below_layer_time } @layer_times;
@layer_times = grep $_, @layer_times;
my $all_below = none { $_ < $config->slowdown_below_layer_time } @layer_times;
ok $all_below, 'slowdown_below_layer_time is honored';
# check that all layers have at least one unaltered external perimeter speed
my $external = all { $_ > 0 } values %layer_external;
ok $external, 'slowdown_below_layer_time does not alter external perimeters';
}
__END__

53
t/speed.t Normal file
View File

@ -0,0 +1,53 @@
use Test::More tests => 2;
use strict;
use warnings;
BEGIN {
use FindBin;
use lib "$FindBin::Bin/../lib";
use local::lib "$FindBin::Bin/../local-lib";
}
use List::Util qw(none);
use Slic3r;
use Slic3r::Geometry qw(epsilon);
use Slic3r::Test;
{
my $config = Slic3r::Config->new_from_defaults;
my $test = sub {
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
my %speeds_by_z = (); # z => []
Slic3r::GCode::Reader->new->parse(my $gcode = Slic3r::Test::gcode($print), sub {
my ($self, $cmd, $args, $info) = @_;
if ($cmd eq 'G1' && $info->{dist_E} > 0 && $info->{dist_XY} > 0) {
$speeds_by_z{$self->Z} //= [];
push @{ $speeds_by_z{$self->Z} }, $self->F/60;
}
});
return %speeds_by_z;
};
{
$config->set('perimeter_speed', 0);
$config->set('external_perimeter_speed', 0);
$config->set('infill_speed', 0);
$config->set('support_material_speed', 0);
$config->set('solid_infill_speed', 0);
$config->set('first_layer_speed', '50%');
$config->set('first_layer_height', 0.25);
my %speeds_by_z = $test->();
ok !!(none { $_ > $config->max_print_speed/2+&epsilon } @{ $speeds_by_z{$config->first_layer_height} }),
'percent first_layer_speed is applied over autospeed';
}
{
$config->set('first_layer_speed', 33);
my %speeds_by_z = $test->();
ok !!(none { $_ > $config->first_layer_speed } @{ $speeds_by_z{$config->first_layer_height} }),
'absolute first_layer_speed overrides autospeed';
}
}
__END__

View File

@ -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});
}

View File

@ -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 {

View File

@ -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});
}
}

View File

@ -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);
}

View File

@ -15,10 +15,25 @@ my $mswin = $^O eq 'MSWin32';
# HAS_BOOL : stops Perl/lib/CORE/handy.h from doing "# define bool char" for MSVC
# NOGDI : prevents inclusion of wingdi.h which defines functions Polygon() and Polyline() in global namespace
# BOOST_ASIO_DISABLE_KQUEUE : prevents a Boost ASIO bug on OS X: https://svn.boost.org/trac/boost/ticket/5339
my @cflags = qw(-D_GLIBCXX_USE_C99 -DHAS_BOOL -DNOGDI -DSLIC3RXS -DBOOST_ASIO_DISABLE_KQUEUE);
# std=c++11 Enforce usage of C++11 (required now). Minimum compiler supported: gcc 4.9, clang 3.3, MSVC 14.0
my @cflags = qw(-D_GLIBCXX_USE_C99 -DHAS_BOOL -DNOGDI -DSLIC3RXS -DBOOST_ASIO_DISABLE_KQUEUE
-std=c++11);
if ($cpp_guess->is_gcc) {
# GCC is pedantic with c++11 std, so undefine strict ansi to get M_PI back
push @cflags, qw(-U__STRICT_ANSI__);
}
my @ldflags = ();
if ($^O eq 'darwin') {
push @ldflags, qw(-framework IOKit -framework CoreFoundation);
push @cflags, qw(-stdlib=libc++);
push @ldflags, qw(-framework IOKit -framework CoreFoundation -lc++);
# Due to a bug/misconfiguration/stupidity, boost 1.52 and libc++ don't like each
# other much: a compilation error "Constexpr function never produces a constant
# expression" pops up when trying to compile anything that uses
# boost/chrono/duration.hpp (namely boost/thread for us). This is a workaround
# that prevents this from happening, not needed with newer Boost versions.
# See here for more details: https://svn.boost.org/trac/boost/ticket/7671
push @cflags, qw(-DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_NO_CXX11_RVALUE_REFERENCES -DBOOST_THREAD_USES_MOVE);
}
if ($mswin) {
# In case windows.h is included, we don't want the min / max macros to be active.
@ -83,11 +98,9 @@ if (defined $ENV{BOOST_LIBRARYDIR}) {
qw(/opt/local/lib /usr/local/lib /opt/lib /usr/lib /lib);
}
}
# In order to generate the -l switches we need to know how Boost libraries are named
my $have_boost = 0;
my @boost_libraries = qw(system thread filesystem); # we need these
# check without explicit lib path (works on Linux)
if (! $mswin) {
$have_boost = 1
@ -107,8 +120,8 @@ if (!$ENV{SLIC3R_STATIC} && $have_boost) {
# Try to find the boost system library.
my @files = glob "$path/${lib_prefix}system*$lib_ext";
next if !@files;
if ($files[0] =~ /${lib_prefix}system([^.]+)$lib_ext$/) {
if ($files[0] =~ /${lib_prefix}system([^.]*)$lib_ext$/) {
# Suffix contains the version number, the build type etc.
my $suffix = $1;
# Verify existence of all required boost libraries at $path.

View File

@ -10,6 +10,26 @@ src/admesh/stlinit.c
src/admesh/util.c
src/clipper.cpp
src/clipper.hpp
src/expat/ascii.h
src/expat/asciitab.h
src/expat/COPYING
src/expat/expat.h
src/expat/expat_config.h
src/expat/expat_external.h
src/expat/iasciitab.h
src/expat/internal.h
src/expat/latin1tab.h
src/expat/nametab.h
src/expat/README
src/expat/utf8tab.h
src/expat/xmlparse.c
src/expat/xmlrole.c
src/expat/xmlrole.h
src/expat/xmltok.c
src/expat/xmltok.h
src/expat/xmltok_impl.h
src/expat/xmltok_impl.inc
src/expat/xmltok_ns.inc
src/libslic3r/BoundingBox.cpp
src/libslic3r/BoundingBox.hpp
src/libslic3r/BridgeDetector.cpp
@ -30,12 +50,12 @@ src/libslic3r/ExtrusionEntityCollection.cpp
src/libslic3r/ExtrusionEntityCollection.hpp
src/libslic3r/Fill/Fill.cpp
src/libslic3r/Fill/Fill.hpp
src/libslic3r/Fill/Fill3DHoneycomb.cpp
src/libslic3r/Fill/Fill3DHoneycomb.hpp
src/libslic3r/Fill/FillConcentric.cpp
src/libslic3r/Fill/FillConcentric.hpp
src/libslic3r/Fill/FillHoneycomb.cpp
src/libslic3r/Fill/FillHoneycomb.hpp
src/libslic3r/Fill/Fill3DHoneycomb.cpp
src/libslic3r/Fill/Fill3DHoneycomb.hpp
src/libslic3r/Fill/FillPlanePath.cpp
src/libslic3r/Fill/FillPlanePath.hpp
src/libslic3r/Fill/FillRectilinear.cpp
@ -54,6 +74,7 @@ src/libslic3r/Geometry.cpp
src/libslic3r/Geometry.hpp
src/libslic3r/IO.cpp
src/libslic3r/IO.hpp
src/libslic3r/IO/AMF.cpp
src/libslic3r/Layer.cpp
src/libslic3r/Layer.hpp
src/libslic3r/LayerRegion.cpp
@ -119,6 +140,7 @@ src/slic3r/GUI/3DScene.cpp
src/slic3r/GUI/3DScene.hpp
src/slic3r/GUI/GUI.cpp
src/slic3r/GUI/GUI.hpp
src/tiny_obj_loader.h
src/xsinit.h
t/01_trianglemesh.t
t/03_point.t
@ -141,7 +163,6 @@ t/19_model.t
t/20_print.t
t/21_gcode.t
t/22_exception.t
t/23_config.t
t/inc/22_config_bad_config_options.ini
xsp/BoundingBox.xsp
xsp/BridgeDetector.xsp

View File

@ -82,6 +82,16 @@ stl_check_facets_exact(stl_file *stl) {
for(i = 0; i < stl->stats.number_of_facets; i++) {
facet = stl->facet_start[i];
// Positive and negative zeros are possible in the floats, which are considered equal by the FP unit.
// When using a memcmp on raw floats, those numbers report to be different.
// Unify all +0 and -0 to +0 to make the floats equal under memcmp.
{
uint32_t *f = (uint32_t*)&facet;
for (int j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
if (*f == 0x80000000)
// Negative zero, switch to positive zero.
*f = 0;
}
/* If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet. */
if( !memcmp(&facet.vertex[0], &facet.vertex[1],
@ -278,6 +288,16 @@ stl_check_facets_nearby(stl_file *stl, float tolerance) {
for(i = 0; i < stl->stats.number_of_facets; i++) {
facet = stl->facet_start[i];
// Positive and negative zeros are possible in the floats, which are considered equal by the FP unit.
// When using a memcmp on raw floats, those numbers report to be different.
// Unify all +0 and -0 to +0 to make the floats equal under memcmp.
{
uint32_t *f = (uint32_t*)&facet;
for (int j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
if (*f == 0x80000000)
// Negative zero, switch to positive zero.
*f = 0;
}
for(j = 0; j < 3; j++) {
if(stl->neighbors_start[i].neighbor[j] == -1) {
edge[j].facet_number = i;

View File

@ -197,6 +197,7 @@ extern void stl_rotate_z(stl_file *stl, float angle);
extern void stl_mirror_xy(stl_file *stl);
extern void stl_mirror_yz(stl_file *stl);
extern void stl_mirror_xz(stl_file *stl);
extern void stl_transform(stl_file *stl, float *trafo3x4);
extern void stl_open_merge(stl_file *stl, char *file);
extern void stl_invalidate_shared_vertices(stl_file *stl);
extern void stl_generate_shared_vertices(stl_file *stl);

View File

@ -318,29 +318,6 @@ stl_read(stl_file *stl, int first_facet, int first) {
}
#endif
#if 1
{
// Positive and negative zeros are possible in the floats, which are considered equal by the FP unit.
// When using a memcmp on raw floats, those numbers report to be different.
// Unify all +0 and -0 to +0 to make the floats equal under memcmp.
uint32_t *f = (uint32_t*)&facet;
int j;
for (j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
if (*f == 0x80000000)
// Negative zero, switch to positive zero.
*f = 0;
}
#else
{
// Due to the nature of the floating point numbers, close to zero values may be represented with singificantly higher precision
// than the rest of the vertices. Round them to zero.
float *f = (float*)&facet;
for (int j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
if (*f > -1e-12f && *f < 1e-12f)
// Negative zero, switch to positive zero.
*f = 0;
}
#endif
/* Write the facet into memory. */
memcpy(stl->facet_start+i, &facet, SIZEOF_STL_FACET);
stl_facet_stats(stl, facet, first);

View File

@ -185,6 +185,24 @@ void calculate_normals(stl_file *stl) {
}
}
void stl_transform(stl_file *stl, float *trafo3x4) {
int i_face, i_vertex, i, j;
if (stl->error)
return;
for (i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) {
stl_vertex *vertices = stl->facet_start[i_face].vertex;
for (i_vertex = 0; i_vertex < 3; ++ i_vertex) {
stl_vertex &v_dst = vertices[i_vertex];
stl_vertex v_src = v_dst;
v_dst.x = trafo3x4[0] * v_src.x + trafo3x4[1] * v_src.y + trafo3x4[2] * v_src.z + trafo3x4[3];
v_dst.y = trafo3x4[4] * v_src.x + trafo3x4[5] * v_src.y + trafo3x4[6] * v_src.z + trafo3x4[7];
v_dst.z = trafo3x4[8] * v_src.x + trafo3x4[9] * v_src.y + trafo3x4[10] * v_src.z + trafo3x4[11];
}
}
stl_get_size(stl);
calculate_normals(stl);
}
void
stl_rotate_x(stl_file *stl, float angle) {
int i;

View File

@ -1,10 +1,10 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.1 *
* Date : 5 December 2016 *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2016 *
* Copyright : Angus Johnson 2010-2017 *
* *
* License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. *
@ -1866,7 +1866,7 @@ OutPt* Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt)
prevE = e->PrevInAEL;
}
if (prevE && prevE->OutIdx >= 0)
if (prevE && prevE->OutIdx >= 0 && prevE->Top.Y < Pt.Y && e->Top.Y < Pt.Y)
{
cInt xPrev = TopX(*prevE, Pt.Y);
cInt xE = TopX(*e, Pt.Y);
@ -2713,7 +2713,11 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge)
if (horzEdge->OutIdx >= 0 && !IsOpen) //note: may be done multiple times
{
op1 = AddOutPt(horzEdge, e->Curr);
#ifdef use_xyz
if (dir == dLeftToRight) SetZ(e->Curr, *horzEdge, *e);
else SetZ(e->Curr, *e, *horzEdge);
#endif
op1 = AddOutPt(horzEdge, e->Curr);
TEdge* eNextHorz = m_SortedEdges;
while (eNextHorz)
{
@ -3039,7 +3043,10 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
{
e->Curr.X = TopX( *e, topY );
e->Curr.Y = topY;
}
#ifdef use_xyz
e->Curr.Z = topY == e->Top.Y ? e->Top.Z : (topY == e->Bot.Y ? e->Bot.Z : 0);
#endif
}
//When StrictlySimple and 'e' is being touched by another edge, then
//make sure both edges have a vertex here ...

View File

@ -1,10 +1,10 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.1 *
* Date : 5 December 2016 *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2015 *
* Copyright : Angus Johnson 2010-2017 *
* *
* License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. *
@ -34,7 +34,7 @@
#ifndef clipper_hpp
#define clipper_hpp
#define CLIPPER_VERSION "6.4.1"
#define CLIPPER_VERSION "6.4.2"
//use_int32: When enabled 32bit ints are used instead of 64bit ints. This
//improve performance but coordinate values are limited to the range +/- 46340

21
xs/src/expat/COPYING Normal file
View File

@ -0,0 +1,21 @@
Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper
Copyright (c) 2001-2016 Expat maintainers
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

146
xs/src/expat/README Normal file
View File

@ -0,0 +1,146 @@
Expat, Release 2.2.0, stripped and modified for inclusion into Slic3r.
Only the library sources needed for static linking were left.
The original README follows:
---------------------------------------------------------------------
Expat, Release 2.2.0
This is Expat, a C library for parsing XML, written by James Clark.
Expat is a stream-oriented XML parser. This means that you register
handlers with the parser before starting the parse. These handlers
are called when the parser discovers the associated structures in the
document being parsed. A start tag is an example of the kind of
structures for which you may register handlers.
Windows users should use the expat_win32bin package, which includes
both precompiled libraries and executables, and source code for
developers.
Expat is free software. You may copy, distribute, and modify it under
the terms of the License contained in the file COPYING distributed
with this package. This license is the same as the MIT/X Consortium
license.
Versions of Expat that have an odd minor version (the middle number in
the release above), are development releases and should be considered
as beta software. Releases with even minor version numbers are
intended to be production grade software.
If you are building Expat from a check-out from the CVS repository,
you need to run a script that generates the configure script using the
GNU autoconf and libtool tools. To do this, you need to have
autoconf 2.58 or newer. Run the script like this:
./buildconf.sh
Once this has been done, follow the same instructions as for building
from a source distribution.
To build Expat from a source distribution, you first run the
configuration shell script in the top level distribution directory:
./configure
There are many options which you may provide to configure (which you
can discover by running configure with the --help option). But the
one of most interest is the one that sets the installation directory.
By default, the configure script will set things up to install
libexpat into /usr/local/lib, expat.h into /usr/local/include, and
xmlwf into /usr/local/bin. If, for example, you'd prefer to install
into /home/me/mystuff/lib, /home/me/mystuff/include, and
/home/me/mystuff/bin, you can tell configure about that with:
./configure --prefix=/home/me/mystuff
Another interesting option is to enable 64-bit integer support for
line and column numbers and the over-all byte index:
./configure CPPFLAGS=-DXML_LARGE_SIZE
However, such a modification would be a breaking change to the ABI
and is therefore not recommended for general use - e.g. as part of
a Linux distribution - but rather for builds with special requirements.
After running the configure script, the "make" command will build
things and "make install" will install things into their proper
location. Have a look at the "Makefile" to learn about additional
"make" options. Note that you need to have write permission into
the directories into which things will be installed.
If you are interested in building Expat to provide document
information in UTF-16 encoding rather than the default UTF-8, follow
these instructions (after having run "make distclean"):
1. For UTF-16 output as unsigned short (and version/error
strings as char), run:
./configure CPPFLAGS=-DXML_UNICODE
For UTF-16 output as wchar_t (incl. version/error strings),
run:
./configure CFLAGS="-g -O2 -fshort-wchar" \
CPPFLAGS=-DXML_UNICODE_WCHAR_T
2. Edit the MakeFile, changing:
LIBRARY = libexpat.la
to:
LIBRARY = libexpatw.la
(Note the additional "w" in the library name.)
3. Run "make buildlib" (which builds the library only).
Or, to save step 2, run "make buildlib LIBRARY=libexpatw.la".
4. Run "make installlib" (which installs the library only).
Or, if step 2 was omitted, run "make installlib LIBRARY=libexpatw.la".
Using DESTDIR or INSTALL_ROOT is enabled, with INSTALL_ROOT being the default
value for DESTDIR, and the rest of the make file using only DESTDIR.
It works as follows:
$ make install DESTDIR=/path/to/image
overrides the in-makefile set DESTDIR, while both
$ INSTALL_ROOT=/path/to/image make install
$ make install INSTALL_ROOT=/path/to/image
use DESTDIR=$(INSTALL_ROOT), even if DESTDIR eventually is defined in the
environment, because variable-setting priority is
1) commandline
2) in-makefile
3) environment
Note: This only applies to the Expat library itself, building UTF-16 versions
of xmlwf and the tests is currently not supported.
Note for Solaris users: The "ar" command is usually located in
"/usr/ccs/bin", which is not in the default PATH. You will need to
add this to your path for the "make" command, and probably also switch
to GNU make (the "make" found in /usr/ccs/bin does not seem to work
properly -- apparently it does not understand .PHONY directives). If
you're using ksh or bash, use this command to build:
PATH=/usr/ccs/bin:$PATH make
When using Expat with a project using autoconf for configuration, you
can use the probing macro in conftools/expat.m4 to determine how to
include Expat. See the comments at the top of that file for more
information.
A reference manual is available in the file doc/reference.html in this
distribution.
The homepage for this project is http://www.libexpat.org/. There
are links there to connect you to the bug reports page. If you need
to report a bug when you don't have access to a browser, you may also
send a bug report by email to expat-bugs@mail.libexpat.org.
Discussion related to the direction of future expat development takes
place on expat-discuss@mail.libexpat.org. Archives of this list and
other Expat-related lists may be found at:
http://mail.libexpat.org/mailman/listinfo/

92
xs/src/expat/ascii.h Normal file
View File

@ -0,0 +1,92 @@
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
See the file COPYING for copying permission.
*/
#define ASCII_A 0x41
#define ASCII_B 0x42
#define ASCII_C 0x43
#define ASCII_D 0x44
#define ASCII_E 0x45
#define ASCII_F 0x46
#define ASCII_G 0x47
#define ASCII_H 0x48
#define ASCII_I 0x49
#define ASCII_J 0x4A
#define ASCII_K 0x4B
#define ASCII_L 0x4C
#define ASCII_M 0x4D
#define ASCII_N 0x4E
#define ASCII_O 0x4F
#define ASCII_P 0x50
#define ASCII_Q 0x51
#define ASCII_R 0x52
#define ASCII_S 0x53
#define ASCII_T 0x54
#define ASCII_U 0x55
#define ASCII_V 0x56
#define ASCII_W 0x57
#define ASCII_X 0x58
#define ASCII_Y 0x59
#define ASCII_Z 0x5A
#define ASCII_a 0x61
#define ASCII_b 0x62
#define ASCII_c 0x63
#define ASCII_d 0x64
#define ASCII_e 0x65
#define ASCII_f 0x66
#define ASCII_g 0x67
#define ASCII_h 0x68
#define ASCII_i 0x69
#define ASCII_j 0x6A
#define ASCII_k 0x6B
#define ASCII_l 0x6C
#define ASCII_m 0x6D
#define ASCII_n 0x6E
#define ASCII_o 0x6F
#define ASCII_p 0x70
#define ASCII_q 0x71
#define ASCII_r 0x72
#define ASCII_s 0x73
#define ASCII_t 0x74
#define ASCII_u 0x75
#define ASCII_v 0x76
#define ASCII_w 0x77
#define ASCII_x 0x78
#define ASCII_y 0x79
#define ASCII_z 0x7A
#define ASCII_0 0x30
#define ASCII_1 0x31
#define ASCII_2 0x32
#define ASCII_3 0x33
#define ASCII_4 0x34
#define ASCII_5 0x35
#define ASCII_6 0x36
#define ASCII_7 0x37
#define ASCII_8 0x38
#define ASCII_9 0x39
#define ASCII_TAB 0x09
#define ASCII_SPACE 0x20
#define ASCII_EXCL 0x21
#define ASCII_QUOT 0x22
#define ASCII_AMP 0x26
#define ASCII_APOS 0x27
#define ASCII_MINUS 0x2D
#define ASCII_PERIOD 0x2E
#define ASCII_COLON 0x3A
#define ASCII_SEMI 0x3B
#define ASCII_LT 0x3C
#define ASCII_EQUALS 0x3D
#define ASCII_GT 0x3E
#define ASCII_LSQB 0x5B
#define ASCII_RSQB 0x5D
#define ASCII_UNDERSCORE 0x5F
#define ASCII_LPAREN 0x28
#define ASCII_RPAREN 0x29
#define ASCII_FF 0x0C
#define ASCII_SLASH 0x2F
#define ASCII_HASH 0x23
#define ASCII_PIPE 0x7C
#define ASCII_COMMA 0x2C

36
xs/src/expat/asciitab.h Normal file
View File

@ -0,0 +1,36 @@
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
See the file COPYING for copying permission.
*/
/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML,
/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,

1048
xs/src/expat/expat.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
/*================================================================
** Copyright 2000, Clark Cooper
** All rights reserved.
**
** This is free software. You are permitted to copy, distribute, or modify
** it under the terms of the MIT/X license (contained in the COPYING file
** with this distribution.)
*/
#ifndef EXPATCONFIG_H
#define EXPATCONFIG_H
#include <memory.h>
#include <string.h>
#define XML_NS 1
#define XML_DTD 1
#define XML_CONTEXT_BYTES 1024
/* we will assume all Windows platforms are little endian */
#define BYTEORDER 1234
/* Windows has memmove() available. */
#define HAVE_MEMMOVE
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#else
#endif
#endif /* ifndef EXPATCONFIG_H */

View File

@ -0,0 +1,129 @@
/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
See the file COPYING for copying permission.
*/
#ifndef Expat_External_INCLUDED
#define Expat_External_INCLUDED 1
/* External API definitions */
#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__)
#define XML_USE_MSC_EXTENSIONS 1
#endif
/* Expat tries very hard to make the API boundary very specifically
defined. There are two macros defined to control this boundary;
each of these can be defined before including this header to
achieve some different behavior, but doing so it not recommended or
tested frequently.
XMLCALL - The calling convention to use for all calls across the
"library boundary." This will default to cdecl, and
try really hard to tell the compiler that's what we
want.
XMLIMPORT - Whatever magic is needed to note that a function is
to be imported from a dynamically loaded library
(.dll, .so, or .sl, depending on your platform).
The XMLCALL macro was added in Expat 1.95.7. The only one which is
expected to be directly useful in client code is XMLCALL.
Note that on at least some Unix versions, the Expat library must be
compiled with the cdecl calling convention as the default since
system headers may assume the cdecl convention.
*/
#ifndef XMLCALL
#if defined(_MSC_VER)
#define XMLCALL __cdecl
#elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER)
#define XMLCALL __attribute__((cdecl))
#else
/* For any platform which uses this definition and supports more than
one calling convention, we need to extend this definition to
declare the convention used on that platform, if it's possible to
do so.
If this is the case for your platform, please file a bug report
with information on how to identify your platform via the C
pre-processor and how to specify the same calling convention as the
platform's malloc() implementation.
*/
#define XMLCALL
#endif
#endif /* not defined XMLCALL */
#if !defined(XML_STATIC) && !defined(XMLIMPORT)
#ifndef XML_BUILDING_EXPAT
/* using Expat from an application */
#ifdef XML_USE_MSC_EXTENSIONS
// #define XMLIMPORT __declspec(dllimport)
#endif
#endif
#endif /* not defined XML_STATIC */
#if !defined(XMLIMPORT) && defined(__GNUC__) && (__GNUC__ >= 4)
#define XMLIMPORT __attribute__ ((visibility ("default")))
#endif
/* If we didn't define it above, define it away: */
#ifndef XMLIMPORT
#define XMLIMPORT
#endif
#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
#define XML_ATTR_MALLOC __attribute__((__malloc__))
#else
#define XML_ATTR_MALLOC
#endif
#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
#define XML_ATTR_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
#else
#define XML_ATTR_ALLOC_SIZE(x)
#endif
#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
#ifdef __cplusplus
extern "C" {
#endif
#ifdef XML_UNICODE_WCHAR_T
#define XML_UNICODE
#endif
#ifdef XML_UNICODE /* Information is UTF-16 encoded. */
#ifdef XML_UNICODE_WCHAR_T
typedef wchar_t XML_Char;
typedef wchar_t XML_LChar;
#else
typedef unsigned short XML_Char;
typedef char XML_LChar;
#endif /* XML_UNICODE_WCHAR_T */
#else /* Information is UTF-8 encoded. */
typedef char XML_Char;
typedef char XML_LChar;
#endif /* XML_UNICODE */
#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */
#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
typedef __int64 XML_Index;
typedef unsigned __int64 XML_Size;
#else
typedef long long XML_Index;
typedef unsigned long long XML_Size;
#endif
#else
typedef long XML_Index;
typedef unsigned long XML_Size;
#endif /* XML_LARGE_SIZE */
#ifdef __cplusplus
}
#endif
#endif /* not Expat_External_INCLUDED */

37
xs/src/expat/iasciitab.h Normal file
View File

@ -0,0 +1,37 @@
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
See the file COPYING for copying permission.
*/
/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */
/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML,
/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,

95
xs/src/expat/internal.h Normal file
View File

@ -0,0 +1,95 @@
/* internal.h
Internal definitions used by Expat. This is not needed to compile
client code.
The following calling convention macros are defined for frequently
called functions:
FASTCALL - Used for those internal functions that have a simple
body and a low number of arguments and local variables.
PTRCALL - Used for functions called though function pointers.
PTRFASTCALL - Like PTRCALL, but for low number of arguments.
inline - Used for selected internal functions for which inlining
may improve performance on some platforms.
Note: Use of these macros is based on judgement, not hard rules,
and therefore subject to change.
*/
#if defined(__GNUC__) && defined(__i386__) && !defined(__MINGW32__)
/* We'll use this version by default only where we know it helps.
regparm() generates warnings on Solaris boxes. See SF bug #692878.
Instability reported with egcs on a RedHat Linux 7.3.
Let's comment out:
#define FASTCALL __attribute__((stdcall, regparm(3)))
and let's try this:
*/
#define FASTCALL __attribute__((regparm(3)))
#define PTRFASTCALL __attribute__((regparm(3)))
#endif
/* Using __fastcall seems to have an unexpected negative effect under
MS VC++, especially for function pointers, so we won't use it for
now on that platform. It may be reconsidered for a future release
if it can be made more effective.
Likely reason: __fastcall on Windows is like stdcall, therefore
the compiler cannot perform stack optimizations for call clusters.
*/
/* Make sure all of these are defined if they aren't already. */
#ifndef FASTCALL
#define FASTCALL
#endif
#ifndef PTRCALL
#define PTRCALL
#endif
#ifndef PTRFASTCALL
#define PTRFASTCALL
#endif
#ifndef XML_MIN_SIZE
#if !defined(__cplusplus) && !defined(inline)
#ifdef __GNUC__
#define inline __inline
#endif /* __GNUC__ */
#endif
#endif /* XML_MIN_SIZE */
#ifdef __cplusplus
#define inline inline
#else
#ifndef inline
#define inline
#endif
#endif
#ifndef UNUSED_P
# ifdef __GNUC__
# define UNUSED_P(p) UNUSED_ ## p __attribute__((__unused__))
# else
# define UNUSED_P(p) UNUSED_ ## p
# endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
void
align_limit_to_full_utf8_characters(const char * from, const char ** fromLimRef);
#ifdef __cplusplus
}
#endif

36
xs/src/expat/latin1tab.h Normal file
View File

@ -0,0 +1,36 @@
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
See the file COPYING for copying permission.
*/
/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME,
/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,

150
xs/src/expat/nametab.h Normal file
View File

@ -0,0 +1,150 @@
static const unsigned namingBitmap[] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE,
0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF,
0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF,
0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF,
0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000,
0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060,
0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003,
0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003,
0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000,
0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001,
0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003,
0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000,
0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003,
0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003,
0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000,
0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000,
0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF,
0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB,
0x40000000, 0xF580C900, 0x00000007, 0x02010800,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF,
0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF,
0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF,
0x00000000, 0x00004C40, 0x00000000, 0x00000000,
0x00000007, 0x00000000, 0x00000000, 0x00000000,
0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF,
0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF,
0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000,
0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE,
0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF,
0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000,
0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003,
0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF,
0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF,
0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF,
0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF,
0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF,
0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0,
0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1,
0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3,
0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80,
0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3,
0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3,
0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000,
0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000,
0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF,
0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x1FFF0000, 0x00000002,
0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF,
0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF,
};
static const unsigned char nmstrtPages[] = {
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00,
0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const unsigned char namePages[] = {
0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00,
0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

37
xs/src/expat/utf8tab.h Normal file
View File

@ -0,0 +1,37 @@
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
See the file COPYING for copying permission.
*/
/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4,
/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML,
/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM,

6458
xs/src/expat/xmlparse.c Normal file

File diff suppressed because it is too large Load Diff

1322
xs/src/expat/xmlrole.c Normal file

File diff suppressed because it is too large Load Diff

114
xs/src/expat/xmlrole.h Normal file
View File

@ -0,0 +1,114 @@
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
See the file COPYING for copying permission.
*/
#ifndef XmlRole_INCLUDED
#define XmlRole_INCLUDED 1
#ifdef __VMS
/* 0 1 2 3 0 1 2 3
1234567890123456789012345678901 1234567890123456789012345678901 */
#define XmlPrologStateInitExternalEntity XmlPrologStateInitExternalEnt
#endif
#include "xmltok.h"
#ifdef __cplusplus
extern "C" {
#endif
enum {
XML_ROLE_ERROR = -1,
XML_ROLE_NONE = 0,
XML_ROLE_XML_DECL,
XML_ROLE_INSTANCE_START,
XML_ROLE_DOCTYPE_NONE,
XML_ROLE_DOCTYPE_NAME,
XML_ROLE_DOCTYPE_SYSTEM_ID,
XML_ROLE_DOCTYPE_PUBLIC_ID,
XML_ROLE_DOCTYPE_INTERNAL_SUBSET,
XML_ROLE_DOCTYPE_CLOSE,
XML_ROLE_GENERAL_ENTITY_NAME,
XML_ROLE_PARAM_ENTITY_NAME,
XML_ROLE_ENTITY_NONE,
XML_ROLE_ENTITY_VALUE,
XML_ROLE_ENTITY_SYSTEM_ID,
XML_ROLE_ENTITY_PUBLIC_ID,
XML_ROLE_ENTITY_COMPLETE,
XML_ROLE_ENTITY_NOTATION_NAME,
XML_ROLE_NOTATION_NONE,
XML_ROLE_NOTATION_NAME,
XML_ROLE_NOTATION_SYSTEM_ID,
XML_ROLE_NOTATION_NO_SYSTEM_ID,
XML_ROLE_NOTATION_PUBLIC_ID,
XML_ROLE_ATTRIBUTE_NAME,
XML_ROLE_ATTRIBUTE_TYPE_CDATA,
XML_ROLE_ATTRIBUTE_TYPE_ID,
XML_ROLE_ATTRIBUTE_TYPE_IDREF,
XML_ROLE_ATTRIBUTE_TYPE_IDREFS,
XML_ROLE_ATTRIBUTE_TYPE_ENTITY,
XML_ROLE_ATTRIBUTE_TYPE_ENTITIES,
XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN,
XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS,
XML_ROLE_ATTRIBUTE_ENUM_VALUE,
XML_ROLE_ATTRIBUTE_NOTATION_VALUE,
XML_ROLE_ATTLIST_NONE,
XML_ROLE_ATTLIST_ELEMENT_NAME,
XML_ROLE_IMPLIED_ATTRIBUTE_VALUE,
XML_ROLE_REQUIRED_ATTRIBUTE_VALUE,
XML_ROLE_DEFAULT_ATTRIBUTE_VALUE,
XML_ROLE_FIXED_ATTRIBUTE_VALUE,
XML_ROLE_ELEMENT_NONE,
XML_ROLE_ELEMENT_NAME,
XML_ROLE_CONTENT_ANY,
XML_ROLE_CONTENT_EMPTY,
XML_ROLE_CONTENT_PCDATA,
XML_ROLE_GROUP_OPEN,
XML_ROLE_GROUP_CLOSE,
XML_ROLE_GROUP_CLOSE_REP,
XML_ROLE_GROUP_CLOSE_OPT,
XML_ROLE_GROUP_CLOSE_PLUS,
XML_ROLE_GROUP_CHOICE,
XML_ROLE_GROUP_SEQUENCE,
XML_ROLE_CONTENT_ELEMENT,
XML_ROLE_CONTENT_ELEMENT_REP,
XML_ROLE_CONTENT_ELEMENT_OPT,
XML_ROLE_CONTENT_ELEMENT_PLUS,
XML_ROLE_PI,
XML_ROLE_COMMENT,
#ifdef XML_DTD
XML_ROLE_TEXT_DECL,
XML_ROLE_IGNORE_SECT,
XML_ROLE_INNER_PARAM_ENTITY_REF,
#endif /* XML_DTD */
XML_ROLE_PARAM_ENTITY_REF
};
typedef struct prolog_state {
int (PTRCALL *handler) (struct prolog_state *state,
int tok,
const char *ptr,
const char *end,
const ENCODING *enc);
unsigned level;
int role_none;
#ifdef XML_DTD
unsigned includeLevel;
int documentEntity;
int inEntityValue;
#endif /* XML_DTD */
} PROLOG_STATE;
void XmlPrologStateInit(PROLOG_STATE *);
#ifdef XML_DTD
void XmlPrologStateInitExternalEntity(PROLOG_STATE *);
#endif /* XML_DTD */
#define XmlTokenRole(state, tok, ptr, end, enc) \
(((state)->handler)(state, tok, ptr, end, enc))
#ifdef __cplusplus
}
#endif
#endif /* not XmlRole_INCLUDED */

1737
xs/src/expat/xmltok.c Normal file

File diff suppressed because it is too large Load Diff

322
xs/src/expat/xmltok.h Normal file
View File

@ -0,0 +1,322 @@
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
See the file COPYING for copying permission.
*/
#ifndef XmlTok_INCLUDED
#define XmlTok_INCLUDED 1
#ifdef __cplusplus
extern "C" {
#endif
/* The following token may be returned by XmlContentTok */
#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be
start of illegal ]]> sequence */
/* The following tokens may be returned by both XmlPrologTok and
XmlContentTok.
*/
#define XML_TOK_NONE -4 /* The string to be scanned is empty */
#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan;
might be part of CRLF sequence */
#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */
#define XML_TOK_PARTIAL -1 /* only part of a token */
#define XML_TOK_INVALID 0
/* The following tokens are returned by XmlContentTok; some are also
returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok.
*/
#define XML_TOK_START_TAG_WITH_ATTS 1
#define XML_TOK_START_TAG_NO_ATTS 2
#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag <e/> */
#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4
#define XML_TOK_END_TAG 5
#define XML_TOK_DATA_CHARS 6
#define XML_TOK_DATA_NEWLINE 7
#define XML_TOK_CDATA_SECT_OPEN 8
#define XML_TOK_ENTITY_REF 9
#define XML_TOK_CHAR_REF 10 /* numeric character reference */
/* The following tokens may be returned by both XmlPrologTok and
XmlContentTok.
*/
#define XML_TOK_PI 11 /* processing instruction */
#define XML_TOK_XML_DECL 12 /* XML decl or text decl */
#define XML_TOK_COMMENT 13
#define XML_TOK_BOM 14 /* Byte order mark */
/* The following tokens are returned only by XmlPrologTok */
#define XML_TOK_PROLOG_S 15
#define XML_TOK_DECL_OPEN 16 /* <!foo */
#define XML_TOK_DECL_CLOSE 17 /* > */
#define XML_TOK_NAME 18
#define XML_TOK_NMTOKEN 19
#define XML_TOK_POUND_NAME 20 /* #name */
#define XML_TOK_OR 21 /* | */
#define XML_TOK_PERCENT 22
#define XML_TOK_OPEN_PAREN 23
#define XML_TOK_CLOSE_PAREN 24
#define XML_TOK_OPEN_BRACKET 25
#define XML_TOK_CLOSE_BRACKET 26
#define XML_TOK_LITERAL 27
#define XML_TOK_PARAM_ENTITY_REF 28
#define XML_TOK_INSTANCE_START 29
/* The following occur only in element type declarations */
#define XML_TOK_NAME_QUESTION 30 /* name? */
#define XML_TOK_NAME_ASTERISK 31 /* name* */
#define XML_TOK_NAME_PLUS 32 /* name+ */
#define XML_TOK_COND_SECT_OPEN 33 /* <![ */
#define XML_TOK_COND_SECT_CLOSE 34 /* ]]> */
#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */
#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */
#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */
#define XML_TOK_COMMA 38
/* The following token is returned only by XmlAttributeValueTok */
#define XML_TOK_ATTRIBUTE_VALUE_S 39
/* The following token is returned only by XmlCdataSectionTok */
#define XML_TOK_CDATA_SECT_CLOSE 40
/* With namespace processing this is returned by XmlPrologTok for a
name with a colon.
*/
#define XML_TOK_PREFIXED_NAME 41
#ifdef XML_DTD
#define XML_TOK_IGNORE_SECT 42
#endif /* XML_DTD */
#ifdef XML_DTD
#define XML_N_STATES 4
#else /* not XML_DTD */
#define XML_N_STATES 3
#endif /* not XML_DTD */
#define XML_PROLOG_STATE 0
#define XML_CONTENT_STATE 1
#define XML_CDATA_SECTION_STATE 2
#ifdef XML_DTD
#define XML_IGNORE_SECTION_STATE 3
#endif /* XML_DTD */
#define XML_N_LITERAL_TYPES 2
#define XML_ATTRIBUTE_VALUE_LITERAL 0
#define XML_ENTITY_VALUE_LITERAL 1
/* The size of the buffer passed to XmlUtf8Encode must be at least this. */
#define XML_UTF8_ENCODE_MAX 4
/* The size of the buffer passed to XmlUtf16Encode must be at least this. */
#define XML_UTF16_ENCODE_MAX 2
typedef struct position {
/* first line and first column are 0 not 1 */
XML_Size lineNumber;
XML_Size columnNumber;
} POSITION;
typedef struct {
const char *name;
const char *valuePtr;
const char *valueEnd;
char normalized;
} ATTRIBUTE;
struct encoding;
typedef struct encoding ENCODING;
typedef int (PTRCALL *SCANNER)(const ENCODING *,
const char *,
const char *,
const char **);
enum XML_Convert_Result {
XML_CONVERT_COMPLETED = 0,
XML_CONVERT_INPUT_INCOMPLETE = 1,
XML_CONVERT_OUTPUT_EXHAUSTED = 2 /* and therefore potentially input remaining as well */
};
struct encoding {
SCANNER scanners[XML_N_STATES];
SCANNER literalScanners[XML_N_LITERAL_TYPES];
int (PTRCALL *sameName)(const ENCODING *,
const char *,
const char *);
int (PTRCALL *nameMatchesAscii)(const ENCODING *,
const char *,
const char *,
const char *);
int (PTRFASTCALL *nameLength)(const ENCODING *, const char *);
const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *);
int (PTRCALL *getAtts)(const ENCODING *enc,
const char *ptr,
int attsMax,
ATTRIBUTE *atts);
int (PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr);
int (PTRCALL *predefinedEntityName)(const ENCODING *,
const char *,
const char *);
void (PTRCALL *updatePosition)(const ENCODING *,
const char *ptr,
const char *end,
POSITION *);
int (PTRCALL *isPublicId)(const ENCODING *enc,
const char *ptr,
const char *end,
const char **badPtr);
enum XML_Convert_Result (PTRCALL *utf8Convert)(const ENCODING *enc,
const char **fromP,
const char *fromLim,
char **toP,
const char *toLim);
enum XML_Convert_Result (PTRCALL *utf16Convert)(const ENCODING *enc,
const char **fromP,
const char *fromLim,
unsigned short **toP,
const unsigned short *toLim);
int minBytesPerChar;
char isUtf8;
char isUtf16;
};
/* Scan the string starting at ptr until the end of the next complete
token, but do not scan past eptr. Return an integer giving the
type of token.
Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set.
Return XML_TOK_PARTIAL when the string does not contain a complete
token; nextTokPtr will not be set.
Return XML_TOK_INVALID when the string does not start a valid
token; nextTokPtr will be set to point to the character which made
the token invalid.
Otherwise the string starts with a valid token; nextTokPtr will be
set to point to the character following the end of that token.
Each data character counts as a single token, but adjacent data
characters may be returned together. Similarly for characters in
the prolog outside literals, comments and processing instructions.
*/
#define XmlTok(enc, state, ptr, end, nextTokPtr) \
(((enc)->scanners[state])(enc, ptr, end, nextTokPtr))
#define XmlPrologTok(enc, ptr, end, nextTokPtr) \
XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr)
#define XmlContentTok(enc, ptr, end, nextTokPtr) \
XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr)
#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \
XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr)
#ifdef XML_DTD
#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \
XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr)
#endif /* XML_DTD */
/* This is used for performing a 2nd-level tokenization on the content
of a literal that has already been returned by XmlTok.
*/
#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \
(((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr))
#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \
XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr)
#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \
XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr)
#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2))
#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \
(((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2))
#define XmlNameLength(enc, ptr) \
(((enc)->nameLength)(enc, ptr))
#define XmlSkipS(enc, ptr) \
(((enc)->skipS)(enc, ptr))
#define XmlGetAttributes(enc, ptr, attsMax, atts) \
(((enc)->getAtts)(enc, ptr, attsMax, atts))
#define XmlCharRefNumber(enc, ptr) \
(((enc)->charRefNumber)(enc, ptr))
#define XmlPredefinedEntityName(enc, ptr, end) \
(((enc)->predefinedEntityName)(enc, ptr, end))
#define XmlUpdatePosition(enc, ptr, end, pos) \
(((enc)->updatePosition)(enc, ptr, end, pos))
#define XmlIsPublicId(enc, ptr, end, badPtr) \
(((enc)->isPublicId)(enc, ptr, end, badPtr))
#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \
(((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim))
#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \
(((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim))
typedef struct {
ENCODING initEnc;
const ENCODING **encPtr;
} INIT_ENCODING;
int XmlParseXmlDecl(int isGeneralTextEntity,
const ENCODING *enc,
const char *ptr,
const char *end,
const char **badPtr,
const char **versionPtr,
const char **versionEndPtr,
const char **encodingNamePtr,
const ENCODING **namedEncodingPtr,
int *standalonePtr);
int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name);
const ENCODING *XmlGetUtf8InternalEncoding(void);
const ENCODING *XmlGetUtf16InternalEncoding(void);
int FASTCALL XmlUtf8Encode(int charNumber, char *buf);
int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf);
int XmlSizeOfUnknownEncoding(void);
typedef int (XMLCALL *CONVERTER) (void *userData, const char *p);
ENCODING *
XmlInitUnknownEncoding(void *mem,
int *table,
CONVERTER convert,
void *userData);
int XmlParseXmlDeclNS(int isGeneralTextEntity,
const ENCODING *enc,
const char *ptr,
const char *end,
const char **badPtr,
const char **versionPtr,
const char **versionEndPtr,
const char **encodingNamePtr,
const ENCODING **namedEncodingPtr,
int *standalonePtr);
int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name);
const ENCODING *XmlGetUtf8InternalEncodingNS(void);
const ENCODING *XmlGetUtf16InternalEncodingNS(void);
ENCODING *
XmlInitUnknownEncodingNS(void *mem,
int *table,
CONVERTER convert,
void *userData);
#ifdef __cplusplus
}
#endif
#endif /* not XmlTok_INCLUDED */

View File

@ -0,0 +1,46 @@
/*
Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
See the file COPYING for copying permission.
*/
enum {
BT_NONXML,
BT_MALFORM,
BT_LT,
BT_AMP,
BT_RSQB,
BT_LEAD2,
BT_LEAD3,
BT_LEAD4,
BT_TRAIL,
BT_CR,
BT_LF,
BT_GT,
BT_QUOT,
BT_APOS,
BT_EQUALS,
BT_QUEST,
BT_EXCL,
BT_SOL,
BT_SEMI,
BT_NUM,
BT_LSQB,
BT_S,
BT_NMSTRT,
BT_COLON,
BT_HEX,
BT_DIGIT,
BT_NAME,
BT_MINUS,
BT_OTHER, /* known not to be a name or name start character */
BT_NONASCII, /* might be a name or name start character */
BT_PERCNT,
BT_LPAR,
BT_RPAR,
BT_AST,
BT_PLUS,
BT_COMMA,
BT_VERBAR
};
#include <stddef.h>

1779
xs/src/expat/xmltok_impl.inc Normal file

File diff suppressed because it is too large Load Diff

115
xs/src/expat/xmltok_ns.inc Normal file
View File

@ -0,0 +1,115 @@
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
See the file COPYING for copying permission.
*/
/* This file is included! */
#ifdef XML_TOK_NS_C
const ENCODING *
NS(XmlGetUtf8InternalEncoding)(void)
{
return &ns(internal_utf8_encoding).enc;
}
const ENCODING *
NS(XmlGetUtf16InternalEncoding)(void)
{
#if BYTEORDER == 1234
return &ns(internal_little2_encoding).enc;
#elif BYTEORDER == 4321
return &ns(internal_big2_encoding).enc;
#else
const short n = 1;
return (*(const char *)&n
? &ns(internal_little2_encoding).enc
: &ns(internal_big2_encoding).enc);
#endif
}
static const ENCODING * const NS(encodings)[] = {
&ns(latin1_encoding).enc,
&ns(ascii_encoding).enc,
&ns(utf8_encoding).enc,
&ns(big2_encoding).enc,
&ns(big2_encoding).enc,
&ns(little2_encoding).enc,
&ns(utf8_encoding).enc /* NO_ENC */
};
static int PTRCALL
NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr)
{
return initScan(NS(encodings), (const INIT_ENCODING *)enc,
XML_PROLOG_STATE, ptr, end, nextTokPtr);
}
static int PTRCALL
NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr)
{
return initScan(NS(encodings), (const INIT_ENCODING *)enc,
XML_CONTENT_STATE, ptr, end, nextTokPtr);
}
int
NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr,
const char *name)
{
int i = getEncodingIndex(name);
if (i == UNKNOWN_ENC)
return 0;
SET_INIT_ENC_INDEX(p, i);
p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog);
p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent);
p->initEnc.updatePosition = initUpdatePosition;
p->encPtr = encPtr;
*encPtr = &(p->initEnc);
return 1;
}
static const ENCODING *
NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end)
{
#define ENCODING_MAX 128
char buf[ENCODING_MAX];
char *p = buf;
int i;
XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1);
if (ptr != end)
return 0;
*p = 0;
if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2)
return enc;
i = getEncodingIndex(buf);
if (i == UNKNOWN_ENC)
return 0;
return NS(encodings)[i];
}
int
NS(XmlParseXmlDecl)(int isGeneralTextEntity,
const ENCODING *enc,
const char *ptr,
const char *end,
const char **badPtr,
const char **versionPtr,
const char **versionEndPtr,
const char **encodingName,
const ENCODING **encoding,
int *standalone)
{
return doParseXmlDecl(NS(findEncoding),
isGeneralTextEntity,
enc,
ptr,
end,
badPtr,
versionPtr,
versionEndPtr,
encodingName,
encoding,
standalone);
}
#endif /* XML_TOK_NS_C */

View File

@ -183,6 +183,26 @@ BoundingBox3Base<PointClass>::size() const
}
template Pointf3 BoundingBox3Base<Pointf3>::size() const;
template <class PointClass> double
BoundingBoxBase<PointClass>::radius() const
{
double x = this->max.x - this->min.x;
double y = this->max.y - this->min.y;
return 0.5 * sqrt(x*x+y*y);
}
template double BoundingBoxBase<Point>::radius() const;
template double BoundingBoxBase<Pointf>::radius() const;
template <class PointClass> double
BoundingBox3Base<PointClass>::radius() const
{
double x = this->max.x - this->min.x;
double y = this->max.y - this->min.y;
double z = this->max.z - this->min.z;
return 0.5 * sqrt(x*x+y*y+z*z);
}
template double BoundingBox3Base<Pointf3>::radius() const;
template <class PointClass> void
BoundingBoxBase<PointClass>::translate(coordf_t x, coordf_t y)
{

View File

@ -29,6 +29,7 @@ class BoundingBoxBase
void merge(const BoundingBoxBase<PointClass> &bb);
void scale(double factor);
PointClass size() const;
double radius() const;
void translate(coordf_t x, coordf_t y);
void offset(coordf_t delta);
PointClass center() const;
@ -48,6 +49,7 @@ class BoundingBox3Base : public BoundingBoxBase<PointClass>
void merge(const std::vector<PointClass> &points);
void merge(const BoundingBox3Base<PointClass> &bb);
PointClass size() const;
double radius() const;
void translate(coordf_t x, coordf_t y, coordf_t z);
void offset(coordf_t delta);
PointClass center() const;

View File

@ -39,6 +39,7 @@ ClipperPath_to_Slic3rMultiPoint(const ClipperLib::Path &input)
retval.points.push_back(Point( (*pit).X, (*pit).Y ));
return retval;
}
template Polygon ClipperPath_to_Slic3rMultiPoint<Polygon>(const ClipperLib::Path &input);
template <class T>
T

View File

@ -565,10 +565,9 @@ class ConfigOptionDef
// Special values - "i_enum_open", "f_enum_open" to provide combo box for int or float selection,
// "select_open" - to open a selection dialog (currently only a serial port selection).
std::string gui_type;
// Usually empty. Otherwise "serialized" or "show_value"
// The flags may be combined.
// "serialized" - vector valued option is entered in a single edit field. Values are separated by a semicolon.
// "show_value" - even if enum_values / enum_labels are set, still display the value, not the enum label.
// "align_label_right" - align label to right
std::string gui_flags;
// Label of the GUI input field.
// In case the GUI input fields are grouped in some views, the label defines a short label of a grouped value,

View File

@ -145,22 +145,38 @@ ExtrusionLoop::split_at_vertex(const Point &point)
return false;
}
void
ExtrusionLoop::split_at(const Point &point)
// Splitting an extrusion loop, possibly made of multiple segments, some of the segments may be bridging.
void ExtrusionLoop::split_at(const Point &point, bool prefer_non_overhang)
{
if (this->paths.empty()) return;
if (this->paths.empty())
return;
// find the closest path and closest point belonging to that path
// Find the closest path and closest point belonging to that path. Avoid overhangs, if asked for.
size_t path_idx = 0;
Point p = this->paths.front().first_point();
double min = point.distance_to(p);
for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) {
Point p_tmp = point.projection_onto(path->polyline);
double dist = point.distance_to(p_tmp);
if (dist < min) {
p = p_tmp;
min = dist;
path_idx = path - this->paths.begin();
Point p;
{
double min = std::numeric_limits<double>::max();
Point p_non_overhang;
size_t path_idx_non_overhang = 0;
double min_non_overhang = std::numeric_limits<double>::max();
for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) {
Point p_tmp = point.projection_onto(path->polyline);
double dist = point.distance_to(p_tmp);
if (dist < min) {
p = p_tmp;
min = dist;
path_idx = path - this->paths.begin();
}
if (prefer_non_overhang && ! path->is_bridge() && dist < min_non_overhang) {
p_non_overhang = p_tmp;
min_non_overhang = dist;
path_idx_non_overhang = path - this->paths.begin();
}
}
if (prefer_non_overhang && min_non_overhang != std::numeric_limits<double>::max()) {
// Only apply the non-overhang point if there is one.
path_idx = path_idx_non_overhang;
p = p_non_overhang;
}
}

View File

@ -139,7 +139,7 @@ class ExtrusionLoop : public ExtrusionEntity
Polygon polygon() const;
virtual double length() const;
bool split_at_vertex(const Point &point);
void split_at(const Point &point);
void split_at(const Point &point, bool prefer_non_overhang = false);
void clip_end(double distance, ExtrusionPaths* paths) const;
// Test, whether the point is extruded by a bridging flow.
// This used to be used to avoid placing seams on overhangs, but now the EdgeGrid is used instead.

View File

@ -1,3 +1,4 @@
#undef NDEBUG
#include "../ClipperUtils.hpp"
#include "../ExPolygon.hpp"
#include "../PolylineCollection.hpp"
@ -28,6 +29,9 @@ FillRectilinear::_fill_single_direction(ExPolygon expolygon,
// We ignore this->bounding_box because it doesn't matter; we're doing align_to_grid below.
BoundingBox bounding_box = expolygon.contour.bounding_box();
// Ignore too small expolygons.
if (bounding_box.size().x < min_spacing) return;
// Due to integer rounding, rotated polygons might not preserve verticality
// (i.e. when rotating by PI/2 two points having the same x coordinate
// they might get different y coordinates), thus the first line will be skipped.

View File

@ -201,7 +201,8 @@ Wipe::wipe(GCode &gcodegen, bool toolchange)
GCode::GCode()
: placeholder_parser(NULL), enable_loop_clipping(true), enable_cooling_markers(false), layer_count(0),
layer_index(-1), layer(NULL), first_layer(false), elapsed_time(0.0), volumetric_speed(0),
layer_index(-1), layer(NULL), first_layer(false), elapsed_time(0.0),
elapsed_time_bridges(0.0), elapsed_time_external(0.0), volumetric_speed(0),
_last_pos_defined(false)
{
}
@ -324,7 +325,7 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed)
Point last_pos = this->last_pos();
if (this->config.spiral_vase) {
loop.split_at(last_pos);
} else if (seam_position == spNearest || seam_position == spAligned) {
} else if (seam_position == spNearest || seam_position == spAligned || seam_position == spRear) {
const Polygon polygon = loop.polygon();
// simplify polygon in order to skip false positives in concave/convex detection
@ -354,8 +355,13 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed)
}
// retrieve the last start position for this object
if (this->layer != NULL && this->_seam_position.count(this->layer->object()) > 0) {
last_pos = this->_seam_position[this->layer->object()];
if (this->layer != NULL) {
if (seam_position == spRear) {
last_pos = this->layer->object()->bounding_box().center();
last_pos.y += coord_t(3. * this->layer->object()->bounding_box().radius());
} else if (this->_seam_position.count(this->layer->object()) > 0) {
last_pos = this->_seam_position[this->layer->object()];
}
}
Point point;
@ -392,7 +398,8 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed)
last_pos = Point(polygon.bounding_box().max.x, centroid.y);
last_pos.rotate(fmod((float)rand()/16.0, 2.0*PI), centroid);
}
loop.split_at(last_pos);
// Find the closest point, avoid overhangs.
loop.split_at(last_pos, true);
}
// clip the path to avoid the extruder to get exactly on the first point of the loop;
@ -544,12 +551,12 @@ GCode::_extrude(ExtrusionPath path, std::string description, double speed)
CONFESS("Invalid speed");
}
}
if (this->first_layer) {
speed = this->config.get_abs_value("first_layer_speed", speed);
}
if (this->volumetric_speed != 0 && speed == 0) {
speed = this->volumetric_speed / path.mm3_per_mm;
}
if (this->first_layer) {
speed = this->config.get_abs_value("first_layer_speed", speed);
}
if (this->config.max_volumetric_speed.value > 0) {
// cap speed with max_volumetric_speed anyway (even if user is not using autospeed)
speed = std::min(
@ -569,7 +576,9 @@ GCode::_extrude(ExtrusionPath path, std::string description, double speed)
// extrude arc or line
if (path.is_bridge() && this->enable_cooling_markers)
gcode += ";_BRIDGE_FAN_START\n";
gcode += this->writer.set_speed(F, "", this->enable_cooling_markers ? ";_EXTRUDE_SET_SPEED" : "");
std::string comment = ";_EXTRUDE_SET_SPEED";
if (path.role == erExternalPerimeter) comment += ";_EXTERNAL_PERIMETER";
gcode += this->writer.set_speed(F, "", this->enable_cooling_markers ? comment : "");
double path_length = 0;
{
std::string comment = this->config.gcode_comments ? description : "";
@ -594,8 +603,12 @@ GCode::_extrude(ExtrusionPath path, std::string description, double speed)
this->set_last_pos(path.last_point());
if (this->config.cooling)
this->elapsed_time += path_length / F * 60;
if (this->config.cooling) {
float t = path_length / F * 60;
this->elapsed_time += t;
if (path.is_bridge()) this->elapsed_time_bridges += t;
if (path.role == erExternalPerimeter) this->elapsed_time_external += t;
}
return gcode;
}

View File

@ -89,7 +89,7 @@ class GCode {
// This value is not quite precise. First it only accouts for extrusion moves and travel moves,
// it does not account for wipe, retract / unretract moves.
// second it does not account for the velocity profiles of the printer.
float elapsed_time; // seconds
float elapsed_time, elapsed_time_bridges, elapsed_time_external; // seconds
double volumetric_speed;
GCode();

View File

@ -19,8 +19,12 @@ CoolingBuffer::append(const std::string &gcode, std::string obj_id, size_t layer
this->_gcode += gcode;
// This is a very rough estimate of the print time,
// not taking into account the acceleration curves generated by the printer firmware.
this->_elapsed_time += this->_gcodegen->elapsed_time;
this->_gcodegen->elapsed_time = 0;
this->_elapsed_time += this->_gcodegen->elapsed_time;
this->_elapsed_time_bridges += this->_gcodegen->elapsed_time_bridges;
this->_elapsed_time_external += this->_gcodegen->elapsed_time_external;
this->_gcodegen->elapsed_time = 0;
this->_gcodegen->elapsed_time_bridges = 0;
this->_gcodegen->elapsed_time_external = 0;
return out;
}
@ -55,32 +59,40 @@ std::string
CoolingBuffer::flush()
{
GCode &gg = *this->_gcodegen;
std::string gcode = this->_gcode;
std::string gcode = this->_gcode;
float elapsed = this->_elapsed_time;
this->_gcode = "";
this->_elapsed_time = 0;
this->_last_z.clear(); // reset the whole table otherwise we would compute overlapping times
int fan_speed = gg.config.fan_always_on ? gg.config.min_fan_speed.value : 0;
float speed_factor = 1.0;
int fan_speed = gg.config.fan_always_on ? gg.config.min_fan_speed.value : 0;
float speed_factor = 1.0;
bool slowdown_external = true;
if (gg.config.cooling) {
#ifdef SLIC3R_DEBUG
printf("Layer %zu estimated printing time: %f seconds\n", this->_layer_id, elapsed);
printf("Layer %zu estimated printing time: %f seconds\n", this->_layer_id, this->_elapsed_time);
#endif
if (elapsed < (float)gg.config.slowdown_below_layer_time) {
if (this->_elapsed_time < (float)gg.config.slowdown_below_layer_time) {
// Layer time very short. Enable the fan to a full throttle and slow down the print
// (stretch the layer print time to slowdown_below_layer_time).
fan_speed = gg.config.max_fan_speed;
speed_factor = elapsed / (float)gg.config.slowdown_below_layer_time;
} else if (elapsed < (float)gg.config.fan_below_layer_time) {
// We are not altering speed of bridges.
float time_to_stretch = this->_elapsed_time - this->_elapsed_time_bridges;
float target_time = (float)gg.config.slowdown_below_layer_time - this->_elapsed_time_bridges;
// If we spend most of our time on external perimeters include them in the slowdown,
// otherwise only alter other extrusions.
if (this->_elapsed_time_external < time_to_stretch/2.) {
time_to_stretch -= this->_elapsed_time_external;
target_time -= this->_elapsed_time_external;
slowdown_external = false;
}
speed_factor = time_to_stretch / target_time;
} else if (this->_elapsed_time < (float)gg.config.fan_below_layer_time) {
// Layer time quite short. Enable the fan proportionally according to the current layer time.
fan_speed = gg.config.max_fan_speed
- (gg.config.max_fan_speed - gg.config.min_fan_speed)
* (elapsed - (float)gg.config.slowdown_below_layer_time)
* (this->_elapsed_time - (float)gg.config.slowdown_below_layer_time)
/ (gg.config.fan_below_layer_time - gg.config.slowdown_below_layer_time);
}
@ -100,11 +112,12 @@ CoolingBuffer::flush()
if (boost::starts_with(line, "G1")
&& boost::contains(line, ";_EXTRUDE_SET_SPEED")
&& !boost::contains(line, ";_WIPE")
&& !bridge_fan_start) {
&& !bridge_fan_start
&& (slowdown_external || !boost::contains(line, ";_EXTERNAL_PERIMETER"))) {
apply_speed_factor(line, speed_factor, this->_min_print_speed);
boost::replace_first(line, ";_EXTRUDE_SET_SPEED", "");
}
bridge_fan_start = boost::contains(line, ";_BRIDGE_FAN_START");
bridge_fan_start = boost::starts_with(line, ";_BRIDGE_FAN_START");
new_gcode += line + '\n';
}
gcode = new_gcode;
@ -125,6 +138,14 @@ CoolingBuffer::flush()
}
boost::replace_all(gcode, ";_WIPE", "");
boost::replace_all(gcode, ";_EXTRUDE_SET_SPEED", "");
boost::replace_all(gcode, ";_EXTERNAL_PERIMETER", "");
// Reset the buffer.
this->_elapsed_time = 0;
this->_elapsed_time_bridges = 0;
this->_elapsed_time_external = 0;
this->_gcode = "";
this->_last_z.clear(); // reset the whole table otherwise we would compute overlapping times
return gcode;
}

View File

@ -17,7 +17,8 @@ and the print is modified to stretch over a minimum layer time.
class CoolingBuffer {
public:
CoolingBuffer(GCode &gcodegen)
: _gcodegen(&gcodegen), _elapsed_time(0.), _layer_id(0)
: _gcodegen(&gcodegen), _elapsed_time(0.), _elapsed_time_bridges(0.),
_elapsed_time_external(0.), _layer_id(0)
{
this->_min_print_speed = this->_gcodegen->config.min_print_speed * 60;
};
@ -29,6 +30,8 @@ class CoolingBuffer {
GCode* _gcodegen;
std::string _gcode;
float _elapsed_time;
float _elapsed_time_bridges;
float _elapsed_time_external;
size_t _layer_id;
std::map<std::string,float> _last_z;
float _min_print_speed;

View File

@ -13,18 +13,6 @@
namespace Slic3r {
Extruder*
GCodeWriter::extruder()
{
return this->_extruder;
}
std::string
GCodeWriter::extrusion_axis() const
{
return this->_extrusion_axis;
}
void
GCodeWriter::apply_print_config(const PrintConfig &print_config)
{
@ -35,9 +23,8 @@ GCodeWriter::apply_print_config(const PrintConfig &print_config)
void
GCodeWriter::set_extruders(const std::vector<unsigned int> &extruder_ids)
{
for (std::vector<unsigned int>::const_iterator i = extruder_ids.begin(); i != extruder_ids.end(); ++i) {
for (std::vector<unsigned int>::const_iterator i = extruder_ids.begin(); i != extruder_ids.end(); ++i)
this->extruders.insert( std::pair<unsigned int,Extruder>(*i, Extruder(*i, &this->config)) );
}
/* we enable support for multiple extruder if any extruder greater than 0 is used
(even if prints only uses that one) since we need to output Tx commands
@ -531,10 +518,4 @@ GCodeWriter::unlift()
return gcode;
}
Pointf3
GCodeWriter::get_position() const
{
return this->_pos;
}
}

View File

@ -19,8 +19,8 @@ public:
: multiple_extruders(false), _extrusion_axis("E"), _extruder(NULL),
_last_acceleration(0), _last_fan_speed(0), _lifted(0)
{};
Extruder* extruder();
std::string extrusion_axis() const;
Extruder* extruder() const { return this->_extruder; }
std::string extrusion_axis() const { return this->_extrusion_axis; }
void apply_print_config(const PrintConfig &print_config);
void set_extruders(const std::vector<unsigned int> &extruder_ids);
std::string preamble();
@ -46,8 +46,7 @@ public:
std::string unretract();
std::string lift();
std::string unlift();
Pointf3 get_position() const;
Pointf3 get_position() const { return this->_pos; }
private:
std::string _extrusion_axis;
Extruder* _extruder;

View File

@ -2,12 +2,19 @@
#include <stdexcept>
#include <fstream>
#include <iostream>
#include <boost/filesystem.hpp>
#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"
namespace Slic3r { namespace IO {
bool
STL::read(std::string input_file, TriangleMesh* mesh)
{
// TODO: encode file name
// TODO: check that file exists
try {
mesh->ReadSTLFile(input_file);
mesh->check_topology();
@ -20,9 +27,6 @@ STL::read(std::string input_file, TriangleMesh* mesh)
bool
STL::read(std::string input_file, Model* model)
{
// TODO: encode file name
// TODO: check that file exists
TriangleMesh mesh;
if (!STL::read(input_file, &mesh)) return false;
@ -30,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)
{
@ -50,6 +61,84 @@ STL::write(TriangleMesh& mesh, std::string output_file, bool binary)
return true;
}
bool
OBJ::read(std::string input_file, TriangleMesh* mesh)
{
Model model;
OBJ::read(input_file, &model);
*mesh = model.mesh();
return true;
}
bool
OBJ::read(std::string input_file, Model* model)
{
// TODO: encode file name
// TODO: check that file exists
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, input_file.c_str());
if (!err.empty()) { // `err` may contain warning message.
std::cerr << err << std::endl;
}
if (!ret)
throw std::runtime_error("Error while reading OBJ file");
ModelObject* object = model->add_object();
object->name = boost::filesystem::path(input_file).filename().string();
object->input_file = input_file;
// Loop over shapes and add a volume for each one.
for (std::vector<tinyobj::shape_t>::const_iterator shape = shapes.begin();
shape != shapes.end(); ++shape) {
Pointf3s points;
std::vector<Point3> facets;
// Read vertices.
assert((attrib.vertices.size() % 3) == 0);
for (size_t v = 0; v < attrib.vertices.size(); v += 3) {
points.push_back(Pointf3(
attrib.vertices[v],
attrib.vertices[v+1],
attrib.vertices[v+2]
));
}
// Loop over facets of the current shape.
for (size_t f = 0; f < shape->mesh.num_face_vertices.size(); ++f) {
// tiny_obj_loader should triangulate any facet with more than 3 vertices
assert((shape->mesh.num_face_vertices[f] % 3) == 0);
facets.push_back(Point3(
shape->mesh.indices[f*3+0].vertex_index,
shape->mesh.indices[f*3+1].vertex_index,
shape->mesh.indices[f*3+2].vertex_index
));
}
TriangleMesh mesh(points, facets);
mesh.check_topology();
ModelVolume* volume = object->add_volume(mesh);
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)
{

View File

@ -13,15 +13,26 @@ 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);
};
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);
};
class AMF
{
public:
static bool read(std::string input_file, Model* model);
static bool write(Model& model, std::string output_file);
};
class POV
{
public:

587
xs/src/libslic3r/IO/AMF.cpp Normal file
View File

@ -0,0 +1,587 @@
#include "../IO.hpp"
#include <string.h>
#include <map>
#include <string>
#include <boost/move/move.hpp>
#include <expat/expat.h>
namespace Slic3r { namespace IO {
struct AMFParserContext
{
AMFParserContext(XML_Parser parser, Model *model) :
m_parser(parser),
m_model(*model),
m_object(NULL),
m_volume(NULL),
m_material(NULL),
m_instance(NULL)
{
m_path.reserve(12);
}
void stop()
{
XML_StopParser(m_parser, 0);
}
void startElement(const char *name, const char **atts);
void endElement(const char *name);
void endDocument();
void characters(const XML_Char *s, int len);
static void XMLCALL startElement(void *userData, const char *name, const char **atts)
{
AMFParserContext *ctx = (AMFParserContext*)userData;
ctx->startElement(name, atts);
}
static void XMLCALL endElement(void *userData, const char *name)
{
AMFParserContext *ctx = (AMFParserContext*)userData;
ctx->endElement(name);
}
/* s is not 0 terminated. */
static void XMLCALL characters(void *userData, const XML_Char *s, int len)
{
AMFParserContext *ctx = (AMFParserContext*)userData;
ctx->characters(s, len);
}
static const char* get_attribute(const char **atts, const char *id) {
if (atts == NULL)
return NULL;
while (*atts != NULL) {
if (strcmp(*(atts ++), id) == 0)
return *atts;
++ atts;
}
return NULL;
}
enum AMFNodeType {
NODE_TYPE_INVALID = 0,
NODE_TYPE_UNKNOWN,
NODE_TYPE_AMF, // amf
// amf/metadata
NODE_TYPE_MATERIAL, // amf/material
// amf/material/metadata
NODE_TYPE_OBJECT, // amf/object
// amf/object/metadata
NODE_TYPE_MESH, // amf/object/mesh
NODE_TYPE_VERTICES, // amf/object/mesh/vertices
NODE_TYPE_VERTEX, // amf/object/mesh/vertices/vertex
NODE_TYPE_COORDINATES, // amf/object/mesh/vertices/vertex/coordinates
NODE_TYPE_COORDINATE_X, // amf/object/mesh/vertices/vertex/coordinates/x
NODE_TYPE_COORDINATE_Y, // amf/object/mesh/vertices/vertex/coordinates/y
NODE_TYPE_COORDINATE_Z, // amf/object/mesh/vertices/vertex/coordinates/z
NODE_TYPE_VOLUME, // amf/object/mesh/volume
// amf/object/mesh/volume/metadata
NODE_TYPE_TRIANGLE, // amf/object/mesh/volume/triangle
NODE_TYPE_VERTEX1, // amf/object/mesh/volume/triangle/v1
NODE_TYPE_VERTEX2, // amf/object/mesh/volume/triangle/v2
NODE_TYPE_VERTEX3, // amf/object/mesh/volume/triangle/v3
NODE_TYPE_CONSTELLATION, // amf/constellation
NODE_TYPE_INSTANCE, // amf/constellation/instance
NODE_TYPE_DELTAX, // amf/constellation/instance/deltax
NODE_TYPE_DELTAY, // amf/constellation/instance/deltay
NODE_TYPE_RZ, // amf/constellation/instance/rz
NODE_TYPE_METADATA, // anywhere under amf/*/metadata
};
struct Instance {
Instance() : deltax_set(false), deltay_set(false), rz_set(false) {}
// Shift in the X axis.
float deltax;
bool deltax_set;
// Shift in the Y axis.
float deltay;
bool deltay_set;
// Rotation around the Z axis.
float rz;
bool rz_set;
};
struct Object {
Object() : idx(-1) {}
int idx;
std::vector<Instance> instances;
};
// Current Expat XML parser instance.
XML_Parser m_parser;
// Model to receive objects extracted from an AMF file.
Model &m_model;
// Current parsing path in the XML file.
std::vector<AMFNodeType> m_path;
// Current object allocated for an amf/object XML subtree.
ModelObject *m_object;
// Map from obect name to object idx & instances.
std::map<std::string, Object> m_object_instances_map;
// Vertices parsed for the current m_object.
std::vector<float> m_object_vertices;
// Current volume allocated for an amf/object/mesh/volume subtree.
ModelVolume *m_volume;
// Faces collected for the current m_volume.
std::vector<int> m_volume_facets;
// Current material allocated for an amf/metadata subtree.
ModelMaterial *m_material;
// Current instance allocated for an amf/constellation/instance subtree.
Instance *m_instance;
// Generic string buffer for vertices, face indices, metadata etc.
std::string m_value[3];
};
void AMFParserContext::startElement(const char *name, const char **atts)
{
AMFNodeType node_type_new = NODE_TYPE_UNKNOWN;
switch (m_path.size()) {
case 0:
// An AMF file must start with an <amf> tag.
node_type_new = NODE_TYPE_AMF;
if (strcmp(name, "amf") != 0)
this->stop();
break;
case 1:
if (strcmp(name, "metadata") == 0) {
const char *type = get_attribute(atts, "type");
if (type != NULL) {
m_value[0] = type;
node_type_new = NODE_TYPE_METADATA;
}
} else if (strcmp(name, "material") == 0) {
const char *material_id = get_attribute(atts, "id");
m_material = m_model.add_material((material_id == NULL) ? "_" : material_id);
node_type_new = NODE_TYPE_MATERIAL;
} else if (strcmp(name, "object") == 0) {
const char *object_id = get_attribute(atts, "id");
if (object_id == NULL)
this->stop();
else {
assert(m_object_vertices.empty());
m_object = m_model.add_object();
m_object_instances_map[object_id].idx = int(m_model.objects.size())-1;
node_type_new = NODE_TYPE_OBJECT;
}
} else if (strcmp(name, "constellation") == 0) {
node_type_new = NODE_TYPE_CONSTELLATION;
}
break;
case 2:
if (strcmp(name, "metadata") == 0) {
if (m_path[1] == NODE_TYPE_MATERIAL || m_path[1] == NODE_TYPE_OBJECT) {
m_value[0] = get_attribute(atts, "type");
node_type_new = NODE_TYPE_METADATA;
}
} else if (strcmp(name, "mesh") == 0) {
if (m_path[1] == NODE_TYPE_OBJECT)
node_type_new = NODE_TYPE_MESH;
} else if (strcmp(name, "instance") == 0) {
if (m_path[1] == NODE_TYPE_CONSTELLATION) {
const char *object_id = get_attribute(atts, "objectid");
if (object_id == NULL)
this->stop();
else {
m_object_instances_map[object_id].instances.push_back(AMFParserContext::Instance());
m_instance = &m_object_instances_map[object_id].instances.back();
node_type_new = NODE_TYPE_INSTANCE;
}
}
else
this->stop();
}
break;
case 3:
if (m_path[2] == NODE_TYPE_MESH) {
assert(m_object);
if (strcmp(name, "vertices") == 0)
node_type_new = NODE_TYPE_VERTICES;
else if (strcmp(name, "volume") == 0) {
assert(! m_volume);
m_volume = m_object->add_volume(TriangleMesh());
node_type_new = NODE_TYPE_VOLUME;
}
} else if (m_path[2] == NODE_TYPE_INSTANCE) {
assert(m_instance);
if (strcmp(name, "deltax") == 0)
node_type_new = NODE_TYPE_DELTAX;
else if (strcmp(name, "deltay") == 0)
node_type_new = NODE_TYPE_DELTAY;
else if (strcmp(name, "rz") == 0)
node_type_new = NODE_TYPE_RZ;
}
break;
case 4:
if (m_path[3] == NODE_TYPE_VERTICES) {
if (strcmp(name, "vertex") == 0)
node_type_new = NODE_TYPE_VERTEX;
} else if (m_path[3] == NODE_TYPE_VOLUME) {
if (strcmp(name, "metadata") == 0) {
const char *type = get_attribute(atts, "type");
if (type == NULL)
this->stop();
else {
m_value[0] = type;
node_type_new = NODE_TYPE_METADATA;
}
} else if (strcmp(name, "triangle") == 0)
node_type_new = NODE_TYPE_TRIANGLE;
}
break;
case 5:
if (strcmp(name, "coordinates") == 0) {
if (m_path[4] == NODE_TYPE_VERTEX) {
node_type_new = NODE_TYPE_COORDINATES;
} else
this->stop();
} else if (name[0] == 'v' && name[1] >= '1' && name[1] <= '3' && name[2] == 0) {
if (m_path[4] == NODE_TYPE_TRIANGLE) {
node_type_new = AMFNodeType(NODE_TYPE_VERTEX1 + name[1] - '1');
} else
this->stop();
}
break;
case 6:
if ((name[0] == 'x' || name[0] == 'y' || name[0] == 'z') && name[1] == 0) {
if (m_path[5] == NODE_TYPE_COORDINATES)
node_type_new = AMFNodeType(NODE_TYPE_COORDINATE_X + name[0] - 'x');
else
this->stop();
}
break;
default:
break;
}
m_path.push_back(node_type_new);
}
void AMFParserContext::characters(const XML_Char *s, int len)
{
if (m_path.back() == NODE_TYPE_METADATA) {
m_value[1].append(s, len);
}
else
{
switch (m_path.size()) {
case 4:
if (m_path.back() == NODE_TYPE_DELTAX || m_path.back() == NODE_TYPE_DELTAY || m_path.back() == NODE_TYPE_RZ)
m_value[0].append(s, len);
break;
case 6:
switch (m_path.back()) {
case NODE_TYPE_VERTEX1: m_value[0].append(s, len); break;
case NODE_TYPE_VERTEX2: m_value[1].append(s, len); break;
case NODE_TYPE_VERTEX3: m_value[2].append(s, len); break;
default: break;
}
case 7:
switch (m_path.back()) {
case NODE_TYPE_COORDINATE_X: m_value[0].append(s, len); break;
case NODE_TYPE_COORDINATE_Y: m_value[1].append(s, len); break;
case NODE_TYPE_COORDINATE_Z: m_value[2].append(s, len); break;
default: break;
}
default:
break;
}
}
}
void AMFParserContext::endElement(const char *name)
{
switch (m_path.back()) {
// Constellation transformation:
case NODE_TYPE_DELTAX:
assert(m_instance);
m_instance->deltax = float(atof(m_value[0].c_str()));
m_instance->deltax_set = true;
m_value[0].clear();
break;
case NODE_TYPE_DELTAY:
assert(m_instance);
m_instance->deltay = float(atof(m_value[0].c_str()));
m_instance->deltay_set = true;
m_value[0].clear();
break;
case NODE_TYPE_RZ:
assert(m_instance);
m_instance->rz = float(atof(m_value[0].c_str()));
m_instance->rz_set = true;
m_value[0].clear();
break;
// Object vertices:
case NODE_TYPE_VERTEX:
assert(m_object);
// Parse the vertex data
m_object_vertices.push_back(atof(m_value[0].c_str()));
m_object_vertices.push_back(atof(m_value[1].c_str()));
m_object_vertices.push_back(atof(m_value[2].c_str()));
m_value[0].clear();
m_value[1].clear();
m_value[2].clear();
break;
// Faces of the current volume:
case NODE_TYPE_TRIANGLE:
assert(m_object && m_volume);
m_volume_facets.push_back(atoi(m_value[0].c_str()));
m_volume_facets.push_back(atoi(m_value[1].c_str()));
m_volume_facets.push_back(atoi(m_value[2].c_str()));
m_value[0].clear();
m_value[1].clear();
m_value[2].clear();
break;
// Closing the current volume. Create an STL from m_volume_facets pointing to m_object_vertices.
case NODE_TYPE_VOLUME:
{
assert(m_object && m_volume);
stl_file &stl = m_volume->mesh.stl;
stl.stats.type = inmemory;
stl.stats.number_of_facets = int(m_volume_facets.size() / 3);
stl.stats.original_num_facets = stl.stats.number_of_facets;
stl_allocate(&stl);
for (size_t i = 0; i < m_volume_facets.size();) {
stl_facet &facet = stl.facet_start[i/3];
for (unsigned int v = 0; v < 3; ++ v)
memcpy(&facet.vertex[v].x, &m_object_vertices[m_volume_facets[i ++] * 3], 3 * sizeof(float));
}
stl_get_size(&stl);
m_volume->mesh.repair();
m_volume_facets.clear();
m_volume = NULL;
break;
}
case NODE_TYPE_OBJECT:
assert(m_object);
m_object_vertices.clear();
m_object = NULL;
break;
case NODE_TYPE_MATERIAL:
assert(m_material);
m_material = NULL;
break;
case NODE_TYPE_INSTANCE:
assert(m_instance);
m_instance = NULL;
break;
case NODE_TYPE_METADATA:
if (strncmp(m_value[0].c_str(), "slic3r.", 7) == 0) {
const char *opt_key = m_value[0].c_str() + 7;
if (print_config_def.options.find(opt_key) != print_config_def.options.end()) {
DynamicPrintConfig *config = NULL;
if (m_path.size() == 3) {
if (m_path[1] == NODE_TYPE_MATERIAL && m_material)
config = &m_material->config;
else if (m_path[1] == NODE_TYPE_OBJECT && m_object)
config = &m_object->config;
} else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume)
config = &m_volume->config;
if (config)
config->set_deserialize(opt_key, m_value[1]);
} else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume && strcmp(opt_key, "modifier") == 0) {
// Is this volume a modifier volume?
m_volume->modifier = atoi(m_value[1].c_str()) == 1;
}
} else if (m_path.size() == 3) {
if (m_path[1] == NODE_TYPE_MATERIAL) {
if (m_material)
m_material->attributes[m_value[0]] = m_value[1];
} else if (m_path[1] == NODE_TYPE_OBJECT) {
if (m_object && m_value[0] == "name")
m_object->name = boost::move(m_value[1]);
}
} else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME) {
if (m_volume && m_value[0] == "name")
m_volume->name = boost::move(m_value[1]);
}
m_value[0].clear();
m_value[1].clear();
break;
default:
break;
}
m_path.pop_back();
}
void AMFParserContext::endDocument()
{
for (const auto &object : m_object_instances_map) {
if (object.second.idx == -1) {
printf("Undefined object %s referenced in constellation\n", object.first.c_str());
continue;
}
for (const Instance &instance : object.second.instances)
if (instance.deltax_set && instance.deltay_set) {
ModelInstance *mi = m_model.objects[object.second.idx]->add_instance();
mi->offset.x = instance.deltax;
mi->offset.y = instance.deltay;
mi->rotation = instance.rz_set ? instance.rz : 0.f;
}
}
}
bool
AMF::read(std::string input_file, Model* model)
{
XML_Parser parser = XML_ParserCreate(NULL); // encoding
if (! parser) {
printf("Couldn't allocate memory for parser\n");
return false;
}
FILE *pFile = ::fopen(input_file.c_str(), "rt");
if (pFile == NULL) {
printf("Cannot open file %s\n", input_file.c_str());
return false;
}
AMFParserContext ctx(parser, model);
XML_SetUserData(parser, (void*)&ctx);
XML_SetElementHandler(parser, AMFParserContext::startElement, AMFParserContext::endElement);
XML_SetCharacterDataHandler(parser, AMFParserContext::characters);
char buff[8192];
bool result = false;
for (;;) {
int len = (int)fread(buff, 1, 8192, pFile);
if (ferror(pFile)) {
printf("AMF parser: Read error\n");
break;
}
int done = feof(pFile);
if (XML_Parse(parser, buff, len, done) == XML_STATUS_ERROR) {
printf("AMF parser: Parse error at line %lu:\n%s\n",
XML_GetCurrentLineNumber(parser),
XML_ErrorString(XML_GetErrorCode(parser)));
break;
}
if (done) {
result = true;
break;
}
}
XML_ParserFree(parser);
::fclose(pFile);
if (result)
ctx.endDocument();
return result;
}
bool
AMF::write(Model& model, std::string output_file)
{
FILE *file = ::fopen(output_file.c_str(), "wb");
if (file == NULL)
return false;
fprintf(file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
fprintf(file, "<amf unit=\"millimeter\">\n");
fprintf(file, "<metadata type=\"cad\">Slic3r %s</metadata>\n", SLIC3R_VERSION);
for (const auto &material : model.materials) {
if (material.first.empty())
continue;
// note that material-id must never be 0 since it's reserved by the AMF spec
fprintf(file, " <material id=\"%s\">\n", material.first.c_str());
for (const auto &attr : material.second->attributes)
fprintf(file, " <metadata type=\"%s\">%s</metadata>\n", attr.first.c_str(), attr.second.c_str());
for (const std::string &key : material.second->config.keys())
fprintf(file, " <metadata type=\"slic3r.%s\">%s</metadata>\n", key.c_str(), material.second->config.serialize(key).c_str());
fprintf(file, " </material>\n");
}
std::string instances;
for (size_t object_id = 0; object_id < model.objects.size(); ++ object_id) {
ModelObject *object = model.objects[object_id];
fprintf(file, " <object id=\"%zu\">\n", object_id);
for (const std::string &key : object->config.keys())
fprintf(file, " <metadata type=\"slic3r.%s\">%s</metadata>\n", key.c_str(), object->config.serialize(key).c_str());
if (! object->name.empty())
fprintf(file, " <metadata type=\"name\">%s</metadata>\n", object->name.c_str());
//FIXME Store the layer height ranges (ModelObject::layer_height_ranges)
fprintf(file, " <mesh>\n");
fprintf(file, " <vertices>\n");
std::vector<int> vertices_offsets;
int num_vertices = 0;
for (ModelVolume *volume : object->volumes) {
vertices_offsets.push_back(num_vertices);
if (! volume->mesh.repaired)
CONFESS("store_amf() requires repair()");
auto &stl = volume->mesh.stl;
if (stl.v_shared == NULL)
stl_generate_shared_vertices(&stl);
for (size_t i = 0; i < stl.stats.shared_vertices; ++ i) {
fprintf(file, " <vertex>\n");
fprintf(file, " <coordinates>\n");
fprintf(file, " <x>%f</x>\n", stl.v_shared[i].x);
fprintf(file, " <y>%f</y>\n", stl.v_shared[i].y);
fprintf(file, " <z>%f</z>\n", stl.v_shared[i].z);
fprintf(file, " </coordinates>\n");
fprintf(file, " </vertex>\n");
}
num_vertices += stl.stats.shared_vertices;
}
fprintf(file, " </vertices>\n");
for (size_t i_volume = 0; i_volume < object->volumes.size(); ++ i_volume) {
ModelVolume *volume = object->volumes[i_volume];
int vertices_offset = vertices_offsets[i_volume];
if (volume->material_id().empty())
fprintf(file, " <volume>\n");
else
fprintf(file, " <volume materialid=\"%s\">\n", volume->material_id().c_str());
for (const std::string &key : volume->config.keys())
fprintf(file, " <metadata type=\"slic3r.%s\">%s</metadata>\n", key.c_str(), volume->config.serialize(key).c_str());
if (! volume->name.empty())
fprintf(file, " <metadata type=\"name\">%s</metadata>\n", volume->name.c_str());
if (volume->modifier)
fprintf(file, " <metadata type=\"slic3r.modifier\">1</metadata>\n");
for (int i = 0; i < volume->mesh.stl.stats.number_of_facets; ++ i) {
fprintf(file, " <triangle>\n");
for (int j = 0; j < 3; ++ j)
fprintf(file, " <v%d>%d</v%d>\n", j+1, volume->mesh.stl.v_indices[i].vertex[j] + vertices_offset, j+1);
fprintf(file, " </triangle>\n");
}
fprintf(file, " </volume>\n");
}
fprintf(file, " </mesh>\n");
fprintf(file, " </object>\n");
if (! object->instances.empty()) {
for (ModelInstance *instance : object->instances) {
char buf[512];
sprintf(buf,
" <instance objectid=\"%zu\">\n"
" <deltax>%lf</deltax>\n"
" <deltay>%lf</deltay>\n"
" <rz>%lf</rz>\n"
" </instance>\n",
object_id,
instance->offset.x,
instance->offset.y,
instance->rotation);
//FIXME missing instance->scaling_factor
instances.append(buf);
}
}
}
if (! instances.empty()) {
fprintf(file, " <constellation id=\"1\">\n");
fwrite(instances.data(), instances.size(), 1, file);
fprintf(file, " </constellation>\n");
}
fprintf(file, "</amf>\n");
fclose(file);
return true;
}
} }

View 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()
{

View File

@ -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);

View File

@ -141,7 +141,7 @@ PerimeterGenerator::process()
}
// look for gaps
if (this->config->gap_fill_speed.value > 0 && this->config->fill_density.value > 0) {
if (this->config->fill_gaps && this->config->fill_density.value > 0) {
// not using safety offset here would "detect" very narrow gaps
// (but still long enough to escape the area threshold) that gap fill
// won't be able to fill but we'd still remove from infill area

View File

@ -106,12 +106,15 @@ PrintConfigDef::PrintConfigDef()
def = this->add("bridge_speed", coFloat);
def->label = "Bridges";
def->gui_type = "f_enum_open";
def->category = "Speed";
def->tooltip = "Speed for printing bridges.";
def->sidetext = "mm/s";
def->cli = "bridge-speed=f";
def->aliases.push_back("bridge_feed_rate");
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("auto");
def->default_value = new ConfigOptionFloat(60);
def = this->add("brim_connections_width", coFloat);
@ -206,21 +209,28 @@ PrintConfigDef::PrintConfigDef()
def->default_value = new ConfigOptionEnum<InfillPattern>(ipRectilinear);
def = this->add("external_perimeter_extrusion_width", coFloatOrPercent);
def->label = "External perimeters";
def->label = "↳ external";
def->gui_type = "f_enum_open";
def->category = "Extrusion Width";
def->tooltip = "Set this to a non-zero value to set a manual extrusion width for external perimeters. If left zero, an automatic value will be used that maximizes accuracy of the external visible surfaces. If expressed as percentage (for example 200%) it will be computed over layer height.";
def->sidetext = "mm or % (leave 0 for default)";
def->tooltip = "Set this to a non-zero value to set a manual extrusion width for external perimeters. If auto is chosen, a value will be used that maximizes accuracy of the external visible surfaces. If expressed as percentage (for example 200%) it will be computed over layer height.";
def->sidetext = "mm or %";
def->cli = "external-perimeter-extrusion-width=s";
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("auto");
def->default_value = new ConfigOptionFloatOrPercent(0, false);
def = this->add("external_perimeter_speed", coFloatOrPercent);
def->label = "External perimeters";
def->label = "↳ external";
def->gui_type = "f_enum_open";
def->category = "Speed";
def->tooltip = "This separate setting will affect the speed of external perimeters (the visible ones). If expressed as percentage (for example: 80%) it will be calculated on the perimeters speed setting above. Set to zero for auto.";
def->tooltip = "This separate setting will affect the speed of external perimeters (the visible ones). If expressed as percentage (for example: 80%) it will be calculated on the perimeters speed setting above.";
def->sidetext = "mm/s or %";
def->cli = "external-perimeter-speed=s";
def->ratio_over = "perimeter_speed";
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("auto");
def->default_value = new ConfigOptionFloatOrPercent(50, true);
def = this->add("external_perimeters_first", coBool);
@ -295,10 +305,14 @@ PrintConfigDef::PrintConfigDef()
def = this->add("extrusion_width", coFloatOrPercent);
def->label = "Default extrusion width";
def->gui_type = "f_enum_open";
def->category = "Extrusion Width";
def->tooltip = "Set this to a non-zero value to set a manual extrusion width. If left to zero, Slic3r calculates a width automatically. If expressed as percentage (for example: 230%) it will be computed over layer height.";
def->sidetext = "mm or % (leave 0 for auto)";
def->tooltip = "Set this to a non-zero value to set a manual extrusion width. If expressed as percentage (for example: 230%) it will be computed over layer height.";
def->sidetext = "mm or %";
def->cli = "extrusion-width=s";
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("auto");
def->default_value = new ConfigOptionFloatOrPercent(0, false);
def = this->add("fan_always_on", coBool);
@ -418,6 +432,12 @@ PrintConfigDef::PrintConfigDef()
def->enum_labels.push_back("100%");
def->default_value = new ConfigOptionPercent(20);
def = this->add("fill_gaps", coBool);
def->label = "Fill gaps";
def->tooltip = "If this is enabled, gaps will be filled with single passes. Enable this for better quality, disable it for shorter printing times.";
def->cli = "fill-gaps!";
def->default_value = new ConfigOptionBool(true);
def = this->add("fill_pattern", coEnum);
def->label = "Fill pattern";
def->category = "Infill";
@ -468,11 +488,15 @@ PrintConfigDef::PrintConfigDef()
def = this->add("first_layer_extrusion_width", coFloatOrPercent);
def->label = "First layer";
def->gui_type = "f_enum_open";
def->category = "Extrusion Width";
def->tooltip = "Set this to a non-zero value to set a manual extrusion width for first layer. You can use this to force fatter extrudates for better adhesion. If expressed as percentage (for example 120%) it will be computed over first layer height. If set to zero, it will use the Default Extrusion Width.";
def->sidetext = "mm or % (leave 0 for default)";
def->tooltip = "Set this to a non-zero value to set a manual extrusion width for first layer. You can use this to force fatter extrudates for better adhesion. If expressed as percentage (for example 120%) it will be computed over first layer height.";
def->sidetext = "mm or %";
def->cli = "first-layer-extrusion-width=s";
def->ratio_over = "first_layer_height";
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("default");
def->default_value = new ConfigOptionFloatOrPercent(200, true);
def = this->add("first_layer_height", coFloatOrPercent);
@ -505,12 +529,16 @@ PrintConfigDef::PrintConfigDef()
}
def = this->add("gap_fill_speed", coFloat);
def->label = "Gap fill";
def->label = "↳ gaps";
def->gui_type = "f_enum_open";
def->category = "Speed";
def->tooltip = "Speed for filling small gaps using short zigzag moves. Keep this reasonably low to avoid too much shaking and resonance issues. Set zero to disable gaps filling.";
def->sidetext = "mm/s";
def->cli = "gap-fill-speed=f";
def->tooltip = "Speed for filling gaps. Since these are usually single lines you might want to use a low speed for better sticking. If expressed as percentage (for example: 80%) it will be calculated on the infill speed setting above.";
def->sidetext = "mm/s or %";
def->cli = "gap-fill-speed=s";
def->ratio_over = "infill_speed";
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("auto");
def->default_value = new ConfigOptionFloat(20);
def = this->add("gcode_arcs", coBool);
@ -578,10 +606,14 @@ PrintConfigDef::PrintConfigDef()
def = this->add("infill_extrusion_width", coFloatOrPercent);
def->label = "Infill";
def->gui_type = "f_enum_open";
def->category = "Extrusion Width";
def->tooltip = "Set this to a non-zero value to set a manual extrusion width for infill. You may want to use fatter extrudates to speed up the infill and make your parts stronger. If expressed as percentage (for example 90%) it will be computed over layer height.";
def->sidetext = "mm or % (leave 0 for default)";
def->sidetext = "mm or %";
def->cli = "infill-extrusion-width=s";
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("default");
def->default_value = new ConfigOptionFloatOrPercent(0, false);
def = this->add("infill_first", coBool);
@ -608,13 +640,16 @@ PrintConfigDef::PrintConfigDef()
def = this->add("infill_speed", coFloat);
def->label = "Infill";
def->gui_type = "f_enum_open";
def->category = "Speed";
def->tooltip = "Speed for printing the internal fill. Set to zero for auto.";
def->tooltip = "Speed for printing the internal fill.";
def->sidetext = "mm/s";
def->cli = "infill-speed=f";
def->aliases.push_back("print_feed_rate");
def->aliases.push_back("infill_feed_rate");
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("auto");
def->default_value = new ConfigOptionFloat(80);
def = this->add("interface_shells", coBool);
@ -798,21 +833,28 @@ PrintConfigDef::PrintConfigDef()
def = this->add("perimeter_extrusion_width", coFloatOrPercent);
def->label = "Perimeters";
def->gui_type = "f_enum_open";
def->category = "Extrusion Width";
def->tooltip = "Set this to a non-zero value to set a manual extrusion width for perimeters. You may want to use thinner extrudates to get more accurate surfaces. If expressed as percentage (for example 200%) it will be computed over layer height.";
def->sidetext = "mm or % (leave 0 for default)";
def->sidetext = "mm or %";
def->cli = "perimeter-extrusion-width=s";
def->aliases.push_back("perimeters_extrusion_width");
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("default");
def->default_value = new ConfigOptionFloatOrPercent(0, false);
def = this->add("perimeter_speed", coFloat);
def->label = "Perimeters";
def->gui_type = "f_enum_open";
def->category = "Speed";
def->tooltip = "Speed for perimeters (contours, aka vertical shells). Set to zero for auto.";
def->tooltip = "Speed for perimeters (contours, aka vertical shells).";
def->sidetext = "mm/s";
def->cli = "perimeter-speed=f";
def->aliases.push_back("perimeter_feed_rate");
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("auto");
def->default_value = new ConfigOptionFloat(60);
def = this->add("perimeters", coInt);
@ -827,9 +869,8 @@ PrintConfigDef::PrintConfigDef()
def = this->add("post_process", coStrings);
def->label = "Post-processing scripts";
def->tooltip = "If you want to process the output G-code through custom scripts, just list their absolute paths here. Separate multiple scripts with a semicolon. Scripts will be passed the absolute path to the G-code file as the first argument, and they can access the Slic3r config settings by reading environment variables.";
def->tooltip = "If you want to process the output G-code through custom scripts, just list their absolute paths here. Separate multiple scripts on individual lines. Scripts will be passed the absolute path to the G-code file as the first argument, and they can access the Slic3r config settings by reading environment variables.";
def->cli = "post-process=s@";
def->gui_flags = "serialized";
def->multiline = true;
def->full_width = true;
def->height = 60;
@ -996,9 +1037,11 @@ PrintConfigDef::PrintConfigDef()
def->enum_values.push_back("random");
def->enum_values.push_back("nearest");
def->enum_values.push_back("aligned");
def->enum_values.push_back("rear");
def->enum_labels.push_back("Random");
def->enum_labels.push_back("Nearest");
def->enum_labels.push_back("Aligned");
def->enum_labels.push_back("Rear");
def->default_value = new ConfigOptionEnum<SeamPosition>(spAligned);
def = this->add("serial_port", coString);
@ -1056,13 +1099,16 @@ PrintConfigDef::PrintConfigDef()
def->default_value = new ConfigOptionInt(5);
def = this->add("small_perimeter_speed", coFloatOrPercent);
def->label = "Small perimeters";
def->label = "↳ small";
def->gui_type = "f_enum_open";
def->category = "Speed";
def->tooltip = "This separate setting will affect the speed of perimeters having radius <= 6.5mm (usually holes). If expressed as percentage (for example: 80%) it will be calculated on the perimeters speed setting above. Set to zero for auto.";
def->tooltip = "This separate setting will affect the speed of perimeters having radius <= 6.5mm (usually holes). If expressed as percentage (for example: 80%) it will be calculated on the perimeters speed setting above.";
def->sidetext = "mm/s or %";
def->cli = "small-perimeter-speed=s";
def->ratio_over = "perimeter_speed";
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("auto");
def->default_value = new ConfigOptionFloatOrPercent(15, false);
def = this->add("solid_infill_below_area", coFloat);
@ -1092,22 +1138,29 @@ PrintConfigDef::PrintConfigDef()
def->default_value = new ConfigOptionInt(0);
def = this->add("solid_infill_extrusion_width", coFloatOrPercent);
def->label = "Solid infill";
def->label = "↳ solid";
def->gui_type = "f_enum_open";
def->category = "Extrusion Width";
def->tooltip = "Set this to a non-zero value to set a manual extrusion width for infill for solid surfaces. If expressed as percentage (for example 90%) it will be computed over layer height.";
def->sidetext = "mm or % (leave 0 for default)";
def->sidetext = "mm or %";
def->cli = "solid-infill-extrusion-width=s";
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("default");
def->default_value = new ConfigOptionFloatOrPercent(0, false);
def = this->add("solid_infill_speed", coFloatOrPercent);
def->label = "Solid infill";
def->label = "↳ solid";
def->gui_type = "f_enum_open";
def->category = "Speed";
def->tooltip = "Speed for printing solid regions (top/bottom/internal horizontal shells). This can be expressed as a percentage (for example: 80%) over the default infill speed above. Set to zero for auto.";
def->tooltip = "Speed for printing solid regions (top/bottom/internal horizontal shells). This can be expressed as a percentage (for example: 80%) over the default infill speed above.";
def->sidetext = "mm/s or %";
def->cli = "solid-infill-speed=s";
def->ratio_over = "infill_speed";
def->aliases.push_back("solid_infill_feed_rate");
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("auto");
def->default_value = new ConfigOptionFloatOrPercent(20, false);
def = this->add("solid_layers", coInt);
@ -1193,10 +1246,14 @@ PrintConfigDef::PrintConfigDef()
def = this->add("support_material_extrusion_width", coFloatOrPercent);
def->label = "Support material";
def->gui_type = "f_enum_open";
def->category = "Extrusion Width";
def->tooltip = "Set this to a non-zero value to set a manual extrusion width for support material. If expressed as percentage (for example 90%) it will be computed over layer height.";
def->sidetext = "mm or % (leave 0 for default)";
def->sidetext = "mm or %";
def->cli = "support-material-extrusion-width=s";
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("default");
def->default_value = new ConfigOptionFloatOrPercent(0, false);
def = this->add("support_material_interface_extruder", coInt);
@ -1226,13 +1283,16 @@ PrintConfigDef::PrintConfigDef()
def->default_value = new ConfigOptionFloat(0);
def = this->add("support_material_interface_speed", coFloatOrPercent);
def->label = "Support material interface";
def->label = "↳ interface";
def->gui_type = "f_enum_open";
def->category = "Support material";
def->tooltip = "Speed for printing support material interface layers. If expressed as percentage (for example 50%) it will be calculated over support material speed.";
def->sidetext = "mm/s or %";
def->cli = "support-material-interface-speed=s";
def->ratio_over = "support_material_speed";
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("auto");
def->default_value = new ConfigOptionFloatOrPercent(100, true);
def = this->add("support_material_pattern", coEnum);
@ -1262,11 +1322,14 @@ PrintConfigDef::PrintConfigDef()
def = this->add("support_material_speed", coFloat);
def->label = "Support material";
def->gui_type = "f_enum_open";
def->category = "Support material";
def->tooltip = "Speed for printing support material.";
def->sidetext = "mm/s";
def->cli = "support-material-speed=f";
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("auto");
def->default_value = new ConfigOptionFloat(60);
def = this->add("support_material_threshold", coInt);
@ -1320,21 +1383,28 @@ PrintConfigDef::PrintConfigDef()
def->default_value = new ConfigOptionString("");
def = this->add("top_infill_extrusion_width", coFloatOrPercent);
def->label = "Top solid infill";
def->label = "↳ top solid";
def->gui_type = "f_enum_open";
def->category = "Extrusion Width";
def->tooltip = "Set this to a non-zero value to set a manual extrusion width for infill for top surfaces. You may want to use thinner extrudates to fill all narrow regions and get a smoother finish. If expressed as percentage (for example 90%) it will be computed over layer height.";
def->sidetext = "mm or % (leave 0 for default)";
def->sidetext = "mm or %";
def->cli = "top-infill-extrusion-width=s";
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("default");
def->default_value = new ConfigOptionFloatOrPercent(0, false);
def = this->add("top_solid_infill_speed", coFloatOrPercent);
def->label = "Top solid infill";
def->label = "↳ top solid";
def->gui_type = "f_enum_open";
def->category = "Speed";
def->tooltip = "Speed for printing top solid layers (it only applies to the uppermost external layers and not to their internal solid layers). You may want to slow down this to get a nicer surface finish. This can be expressed as a percentage (for example: 80%) over the solid infill speed above. Set to zero for auto.";
def->tooltip = "Speed for printing top solid layers (it only applies to the uppermost external layers and not to their internal solid layers). You may want to slow down this to get a nicer surface finish. This can be expressed as a percentage (for example: 80%) over the solid infill speed above.";
def->sidetext = "mm/s or %";
def->cli = "top-solid-infill-speed=s";
def->ratio_over = "solid_infill_speed";
def->min = 0;
def->enum_values.push_back("0");
def->enum_labels.push_back("auto");
def->default_value = new ConfigOptionFloatOrPercent(15, false);
def = this->add("top_solid_layers", coInt);

View File

@ -41,7 +41,7 @@ enum SupportMaterialPattern {
};
enum SeamPosition {
spRandom, spNearest, spAligned
spRandom, spNearest, spAligned, spRear
};
template<> inline t_config_enum_values ConfigOptionEnum<GCodeFlavor>::get_enum_values() {
@ -89,6 +89,7 @@ template<> inline t_config_enum_values ConfigOptionEnum<SeamPosition>::get_enum_
keys_map["random"] = spRandom;
keys_map["nearest"] = spNearest;
keys_map["aligned"] = spAligned;
keys_map["rear"] = spRear;
return keys_map;
}
@ -219,6 +220,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
ConfigOptionBool extra_perimeters;
ConfigOptionFloat fill_angle;
ConfigOptionPercent fill_density;
ConfigOptionBool fill_gaps;
ConfigOptionEnum<InfillPattern> fill_pattern;
ConfigOptionFloat gap_fill_speed;
ConfigOptionInt infill_extruder;
@ -258,6 +260,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
OPT_PTR(extra_perimeters);
OPT_PTR(fill_angle);
OPT_PTR(fill_density);
OPT_PTR(fill_gaps);
OPT_PTR(fill_pattern);
OPT_PTR(gap_fill_speed);
OPT_PTR(infill_extruder);

View File

@ -33,7 +33,9 @@
#define UTILS_H
// Otherwise #defines like M_PI are undeclared under Visual Studio
#ifndef _USE_MATH_DEFINES
#define _USE_MATH_DEFINES
#endif
#include <exception>
#include <math.h>
@ -119,4 +121,4 @@ bool InScanArea(const Point& pa, const Point& pb, const Point& pc, const Point&
}
#endif
#endif

2020
xs/src/tiny_obj_loader.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@ use strict;
use warnings;
use Slic3r::XS;
use Test::More tests => 146;
use Test::More tests => 147;
use Data::Dumper;
foreach my $config (Slic3r::Config->new, Slic3r::Config::Static::new_FullPrintConfig) {
@ -242,4 +242,13 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Static::new_FullPrintCo
is_deeply $config->get('retract_layer_change'), [0,0], 'retract_layer_change is disabled with spiral_vase';
}
{
use Cwd qw(abs_path);
use File::Basename qw(dirname);
my $class = Slic3r::Config->new;
my $path = abs_path($0);
my $config = $class->_load(dirname($path)."/inc/22_config_bad_config_options.ini");
ok 1, 'did not crash on reading invalid items in config';
}
__END__

View File

@ -1,17 +0,0 @@
#!/usr/bin/perl
use strict;
use warnings;
use Slic3r::XS;
use Test::More tests => 1;
{
use Cwd qw(abs_path);
use File::Basename qw(dirname);
my $class = Slic3r::Config->new;
my $path = abs_path($0);
my $config = $class->_load(dirname($path)."/inc/22_config_bad_config_options.ini");
ok 1, 'did not crash on reading invalid items in config';
}
__END__

View File

@ -21,8 +21,8 @@
double length();
bool split_at_vertex(Point* point)
%code{% RETVAL = THIS->split_at_vertex(*point); %};
void split_at(Point* point)
%code{% THIS->split_at(*point); %};
void split_at(Point* point, int prefer_non_overhang = 0)
%code{% THIS->split_at(*point, prefer_non_overhang != 0); %};
ExtrusionPaths clip_end(double distance)
%code{% THIS->clip_end(distance, &RETVAL); %};
bool has_overhang_point(Point* point)

View File

@ -2,6 +2,7 @@
%{
#include <xsinit.h>
#include "libslic3r/IO.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/PrintConfig.hpp"
%}
@ -9,10 +10,33 @@
%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; %};
bool read_stl(std::string input_file)
%code%{ RETVAL = Slic3r::IO::STL::read(input_file, THIS); %};
bool read_obj(std::string input_file)
%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); %};
%name{_add_object} Ref<ModelObject> add_object();
Ref<ModelObject> _add_object_clone(ModelObject* other, bool copy_volumes = true)
%code%{ RETVAL = THIS->add_object(*other, copy_volumes); %};