diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 53b78ba230..e759285468 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -21,7 +21,7 @@ When possible, please include the following information when [reporting an issue
* STL, OBJ or AMF input file (please make sure the input file is not broken, e.g. non-manifold, before reporting a bug)
* a screenshot of the G-code layer with the issue (e.g. using [Pronterface](https://github.com/kliment/Printrun) or preferably the internal preview tab in Slic3r).
* If the issue is a request for a new feature, be ready to explain why you think it's needed.
- * Doing more prepatory work on your end makes it more likely it'll get done. This includes the "how" it can be done in addition to the "what".
+ * Doing more preparatory work on your end makes it more likely it'll get done. This includes the "how" it can be done in addition to the "what".
* Define the "What" as strictly as you can. Consider what might happen with different infills than simple rectilinear.
Please make sure only to include one issue per report. If you encounter multiple, unrelated issues, please report them as such.
diff --git a/.gitignore b/.gitignore
index ec02368213..590b23926f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,8 @@ CMakeCache.txt
src/test/test_options.hpp
src/slic3r
build/*
+serial.txt
+.vscode
slic3r
gui_test
diff --git a/.travis.yml b/.travis.yml
index adc3fd9fec..a437ef3d56 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -33,6 +33,8 @@ addons:
apt:
sources:
- ubuntu-toolchain-r-test
+ - sourceline: 'deb http://download.opensuse.org/repositories/science:/dlr/xUbuntu_14.04/ /'
+ key_url: 'https://download.opensuse.org/repositories/science:dlr/xUbuntu_14.04/Release.key'
packages:
- g++-7
- gcc-7
@@ -85,29 +87,31 @@ matrix:
# - $HOME/Library/Caches/Homebrew
# - local-lib
- - os: osx
- osx_image: xcode9.4 # OS X 10.13
- env:
- - TARGET=main
- cache:
- directories:
- - /usr/local/Homebrew
- - $HOME/Library/Caches/Homebrew
- - local-lib
- after_success:
- - if [[ "${TRAVIS_BRANCH}" != "cppgui" ]]; then ./package/osx/travis-deploy-main.sh || travis_terminate 1; fi
+ # OSX errors out consistently for Perl now too. Back to jenkins.
+ # - os: osx
+ # osx_image: xcode9.4 # OS X 10.13
+ # env:
+ # - TARGET=main
+ # cache:
+ # directories:
+ # - /usr/local/Homebrew
+ # - $HOME/Library/Caches/Homebrew
+ # - local-lib
+ # after_success:
+ # - if [[ "${TRAVIS_BRANCH}" != "cppgui" ]]; then ./package/osx/travis-deploy-main.sh || travis_terminate 1; fi
- - os: osx
- osx_image: xcode9.4
- env:
- - TARGET=cpp
- - CACHE=$HOME/cache
- cache:
- ccache: true
- directories:
- - /usr/local/Homebrew
- - $HOME/cache
- - $HOME/Library/Caches/Homebrew
+ # OSX is erroring out consistently for C++, remove and debug
+ # - os: osx
+ # osx_image: xcode9.4
+ # env:
+ # - TARGET=cpp
+ # - CACHE=$HOME/cache
+ # cache:
+ # ccache: true
+ # directories:
+ # - /usr/local/Homebrew
+ # - $HOME/cache
+ # - $HOME/Library/Caches/Homebrew
env:
global:
diff --git a/Build.PL b/Build.PL
index 2dd18435a5..f928915908 100755
--- a/Build.PL
+++ b/Build.PL
@@ -131,6 +131,10 @@ EOF
push @cmd, '--notest'
if $module =~ /^(?:OpenGL|Math::PlanePath|Test::Harness|IO::Scalar)$/;
+ # do not try to reinstall modules that were already
+ # installed manually
+ push @cmd, '--skip-satisfied';
+
push @cmd, "$module~$version";
my $res = system @cmd;
if ($res != 0) {
diff --git a/README.md b/README.md
index c9958a8d1d..053a3aa366 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@ Slic3r is:
* **Embeddable:** a complete and powerful command line interface allows Slic3r to be used from the shell or integrated with server-side applications.
* **Powerful:** see the list below!
-See the [project homepage](http://slic3r.org/) at slic3r.org for more information.
+See the [project homepage](https://slic3r.org/) at slic3r.org for more information.
### Features
@@ -44,7 +44,7 @@ The core parts of Slic3r are written in C++11, with multithreading. The graphica
### How to install?
-You can download a precompiled package from [slic3r.org](http://slic3r.org/) (releases) or from [dl.slicr3r.org](http://dl.slic3r.org/dev/) (automated builds).
+You can download a precompiled package from [slic3r.org](https://slic3r.org/) (releases) or from [dl.slicr3r.org](https://dl.slic3r.org/dev/) (automated builds).
If you want to compile the source yourself follow the instructions on one of these wiki pages:
* [Linux](https://github.com/slic3r/Slic3r/wiki/Running-Slic3r-from-git-on-GNU-Linux)
diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm
index e1445335c3..e55370c0b0 100644
--- a/lib/Slic3r.pm
+++ b/lib/Slic3r.pm
@@ -248,6 +248,7 @@ sub thread_cleanup {
*Slic3r::Surface::DESTROY = sub {};
*Slic3r::Surface::Collection::DESTROY = sub {};
*Slic3r::TriangleMesh::DESTROY = sub {};
+ *Slic3r::TransformationMatrix::DESTROY = sub {};
return undef; # this prevents a "Scalars leaked" warning
}
diff --git a/lib/Slic3r/GCode/MotionPlanner.pm b/lib/Slic3r/GCode/MotionPlanner.pm
index 823e6641d4..d87b65d175 100644
--- a/lib/Slic3r/GCode/MotionPlanner.pm
+++ b/lib/Slic3r/GCode/MotionPlanner.pm
@@ -14,7 +14,7 @@ use Slic3r::Geometry::Clipper qw(offset offset_ex diff_ex intersection_pl);
has '_inner_margin' => (is => 'ro', default => sub { scale 1 });
has '_outer_margin' => (is => 'ro', default => sub { scale 2 });
-# this factor weigths the crossing of a perimeter
+# this factor weighs the crossing of a perimeter
# vs. the alternative path. a value of 5 means that
# a perimeter will be crossed if the alternative path
# is >= 5x the length of the straight line we could
diff --git a/lib/Slic3r/GCode/PressureRegulator.pm b/lib/Slic3r/GCode/PressureRegulator.pm
index 19c10a62f7..05e4daffca 100644
--- a/lib/Slic3r/GCode/PressureRegulator.pm
+++ b/lib/Slic3r/GCode/PressureRegulator.pm
@@ -39,7 +39,7 @@ sub process {
# This is a print move.
my $F = $args->{F} // $reader->F;
if ($F != $self->_last_print_F || ($F == $self->_last_print_F && $self->_advance == 0)) {
- # We are setting a (potentially) new speed or a discharge event happend since the last speed change, so we calculate the new advance amount.
+ # We are setting a (potentially) new speed or a discharge event happened since the last speed change, so we calculate the new advance amount.
# First calculate relative flow rate (mm of filament over mm of travel)
my $rel_flow_rate = $info->{dist_E} / $info->{dist_XY};
diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm
index 4f51dfc1ae..6001c4bb6e 100644
--- a/lib/Slic3r/GUI.pm
+++ b/lib/Slic3r/GUI.pm
@@ -96,7 +96,8 @@ our $Settings = {
nudge_val => 1,
rotation_controls => 'z',
reload_hide_dialog => 0,
- reload_behavior => 0
+ reload_behavior => 0,
+ reload_preserve_trafo => 1
},
};
@@ -227,7 +228,7 @@ sub OnInit {
if ($response =~ /^obsolete ?= ?([a-z0-9.-]+,)*\Q$Slic3r::VERSION\E(?:,|$)/) {
my $res = Wx::MessageDialog->new(undef, "A new version is available. Do you want to open the Slic3r website now?",
'Update', wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_INFORMATION | wxICON_ERROR)->ShowModal;
- Wx::LaunchDefaultBrowser('http://slic3r.org/') if $res == wxID_YES;
+ Wx::LaunchDefaultBrowser('https://slic3r.org/') if $res == wxID_YES;
} else {
Slic3r::GUI::show_info(undef, "You're using the latest version. No updates are available.") if $manual_check;
}
@@ -385,7 +386,7 @@ sub check_version {
threads->create(sub {
my $ua = LWP::UserAgent->new;
$ua->timeout(10);
- my $response = $ua->get('http://slic3r.org/updatecheck');
+ my $response = $ua->get('https://slic3r.org/updatecheck');
Wx::PostEvent($self, Wx::PlThreadEvent->new(-1, $VERSION_CHECK_EVENT,
threads::shared::shared_clone([ $response->is_success, $response->decoded_content, $manual_check ])));
diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm
index d59e8da5ec..71df1a8343 100644
--- a/lib/Slic3r/GUI/3DScene.pm
+++ b/lib/Slic3r/GUI/3DScene.pm
@@ -96,14 +96,14 @@ sub new {
# wxWidgets expect the attrib list to be ended by zero.
push(@$attrib, 0);
- # we request a depth buffer explicitely because it looks like it's not created by
+ # we request a depth buffer explicitly because it looks like it's not created by
# default on Linux, causing transparency issues
my $self = $class->SUPER::new($parent, -1, Wx::wxDefaultPosition, Wx::wxDefaultSize, 0, "", $attrib);
if (Wx::wxVERSION >= 3.000003) {
# Wx 3.0.3 contains an ugly hack to support some advanced OpenGL attributes through the attribute list.
# The attribute list is transferred between the wxGLCanvas and wxGLContext constructors using a single static array s_wglContextAttribs.
- # Immediatelly force creation of the OpenGL context to consume the static variable s_wglContextAttribs.
+ # Immediately force creation of the OpenGL context to consume the static variable s_wglContextAttribs.
$self->GetContext();
}
@@ -1331,8 +1331,7 @@ sub load_object {
my $volume = $model_object->volumes->[$volume_idx];
foreach my $instance_idx (@$instance_idxs) {
my $instance = $model_object->instances->[$instance_idx];
- my $mesh = $volume->mesh->clone;
- $instance->transform_mesh($mesh);
+ my $mesh = $volume->get_transformed_mesh($instance);
my $color_idx;
if ($self->color_by eq 'volume') {
diff --git a/lib/Slic3r/GUI/AboutDialog.pm b/lib/Slic3r/GUI/AboutDialog.pm
index 928682a4e9..75f73a0ae6 100644
--- a/lib/Slic3r/GUI/AboutDialog.pm
+++ b/lib/Slic3r/GUI/AboutDialog.pm
@@ -50,8 +50,8 @@ sub new {
' ' .
'' .
'Copyright © 2011-2017 Alessandro Ranellucci. ' .
- 'Slic3r is licensed under the ' .
- 'GNU Affero General Public License, version 3 .' .
+ 'Slic3r is licensed under the ' .
+ 'GNU Affero General Public License, version 3 .' .
' ' .
'Contributions by Henrik Brix Andersen, Vojtech Bubnik, Nicolas Dandrimont, Mark Hindess, Petr Ledvina, Joseph Lenox, Y. Sapir, Mike Sheldrake, Kliment Yanev and numerous others. ' .
'Manual by Gary Hodgson. Inspired by the RepRap community. ' .
diff --git a/lib/Slic3r/GUI/BedShapeDialog.pm b/lib/Slic3r/GUI/BedShapeDialog.pm
index d333b4b28a..e6eca63019 100644
--- a/lib/Slic3r/GUI/BedShapeDialog.pm
+++ b/lib/Slic3r/GUI/BedShapeDialog.pm
@@ -1,5 +1,5 @@
# The bed shape dialog.
-# The dialog opens from Print Settins tab -> Bed Shape: Set...
+# The dialog opens from Print Settings tab -> Bed Shape: Set...
package Slic3r::GUI::BedShapeDialog;
use strict;
diff --git a/lib/Slic3r/GUI/ColorScheme.pm b/lib/Slic3r/GUI/ColorScheme.pm
index dd0ba126e2..009a244d04 100644
--- a/lib/Slic3r/GUI/ColorScheme.pm
+++ b/lib/Slic3r/GUI/ColorScheme.pm
@@ -13,8 +13,8 @@ our $DEFAULT_COLORSCHEME = 1;
our $SOLID_BACKGROUNDCOLOR = 0;
our @SELECTED_COLOR = (0, 1, 0);
our @HOVER_COLOR = (0.4, 0.9, 0); # Hover over Model
-our @TOP_COLOR = (10/255,98/255,144/255); # TOP Backgroud color
-our @BOTTOM_COLOR = (0,0,0); # BOTTOM Backgroud color
+our @TOP_COLOR = (10/255,98/255,144/255); # TOP Background color
+our @BOTTOM_COLOR = (0,0,0); # BOTTOM Background color
our @BACKGROUND_COLOR = @TOP_COLOR; # SOLID background color
our @GRID_COLOR = (0.2, 0.2, 0.2, 0.4); # Grid color
our @GROUND_COLOR = (0.8, 0.6, 0.5, 0.4); # Ground or Plate color
@@ -130,7 +130,7 @@ sub getSolarized { # add this name to Preferences.pm
@BED_SKIRT = map { ceil($_ * 255) } @COLOR_BASE01; # Brim/Skirt
@BED_CLEARANCE = map { ceil($_ * 255) } @COLOR_BLUE; # not sure what that does
@BED_DARK = map { ceil($_ * 255) } @COLOR_BASE01; # not sure what that does
- @BACKGROUND255 = map { ceil($_ * 255) } @BACKGROUND_COLOR; # Backgroud color, this time RGB
+ @BACKGROUND255 = map { ceil($_ * 255) } @BACKGROUND_COLOR; # Background color, this time RGB
# 2DToolpaths.pm colors : LAYERS Tab
@TOOL_DARK = @COLOR_BASE01; # Brim/Skirt
diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm
index b214eef890..995b821827 100644
--- a/lib/Slic3r/GUI/MainFrame.pm
+++ b/lib/Slic3r/GUI/MainFrame.pm
@@ -41,7 +41,7 @@ sub new {
# initialize status bar
$self->{statusbar} = Slic3r::GUI::ProgressStatusBar->new($self, -1);
- $self->{statusbar}->SetStatusText("Version $Slic3r::VERSION - Remember to check for updates at http://slic3r.org/");
+ $self->{statusbar}->SetStatusText("Version $Slic3r::VERSION - Remember to check for updates at https://slic3r.org/");
$self->SetStatusBar($self->{statusbar});
$self->{loaded} = 1;
@@ -308,7 +308,7 @@ sub _init_menubar {
});
$helpMenu->AppendSeparator();
wxTheApp->append_menu_item($helpMenu, "Slic3r &Website", 'Open the Slic3r website in your browser', sub {
- Wx::LaunchDefaultBrowser('http://slic3r.org/');
+ Wx::LaunchDefaultBrowser('https://slic3r.org/');
});
my $versioncheck = wxTheApp->append_menu_item($helpMenu, "Check for &Updates...", 'Check for new Slic3r versions', sub {
wxTheApp->check_version(1);
diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm
index 75c716b0ae..65bea986fd 100644
--- a/lib/Slic3r/GUI/Plater.pm
+++ b/lib/Slic3r/GUI/Plater.pm
@@ -91,6 +91,9 @@ sub new {
# Stack of redo operations.
$self->{redo_stack} = [];
+ # Preset dialogs
+ $self->{'preset_dialogs'} = {};
+
$self->{print}->set_status_cb(sub {
my ($percent, $message) = @_;
@@ -877,6 +880,23 @@ sub selected_presets {
return $group ? @{$presets{$group}} : %presets;
}
+sub show_unique_preset_dialog {
+ my($self, $group) = @_;
+ my $dlg;
+ my $preset_editor;
+ if( $self->{'preset_dialogs'}->{$group} ) {
+ $dlg = $self->{'preset_dialogs'}->{$group};
+ }
+ else {
+ my $class = "Slic3r::GUI::PresetEditorDialog::" . ucfirst($group);
+ $dlg = $class->new($self);
+ $self->{'preset_dialogs'}->{$group} = $dlg;
+ }
+ $dlg->Show;
+ $preset_editor = $dlg->preset_editor;
+ return $preset_editor;
+}
+
sub show_preset_editor {
my ($self, $group, $i, $panel) = @_;
@@ -884,7 +904,6 @@ sub show_preset_editor {
my @presets = $self->selected_presets($group);
my $preset_editor;
- my $dlg;
my $mainframe = $self->GetFrame;
my $tabpanel = $mainframe->{tabpanel};
if (exists $mainframe->{preset_editor_tabs}{$group}) {
@@ -901,9 +920,7 @@ sub show_preset_editor {
$mainframe->{preset_editor_tabs}{$group} = $preset_editor = $class->new($tabpanel);
$tabpanel->AddPage($preset_editor, ucfirst($group) . " Settings");
} else {
- my $class = "Slic3r::GUI::PresetEditorDialog::" . ucfirst($group);
- $dlg = $class->new($self);
- $preset_editor = $dlg->preset_editor;
+ $preset_editor = $self->show_unique_preset_dialog($group);
}
$preset_editor->select_preset_by_name($presets[$i // 0]->name);
@@ -928,10 +945,6 @@ sub show_preset_editor {
};
$preset_editor->on_select_preset($cb);
$preset_editor->on_save_preset($cb);
-
- if ($dlg) {
- $dlg->Show;
- }
});
}
@@ -1029,38 +1042,45 @@ sub undo {
my $type = $operation->{type};
- if ($type eq "ROTATE") {
+ if ($type eq "TRANSFORM") {
+ my $object_id = $operation->{object_identifier};
+ my $obj_idx = $self->get_object_index($object_id);
+ $self->select_object($obj_idx);
+
+ my $trafo = $operation->{attributes}->[0];
+ $self->transform($trafo->inverse(), 'true'); # Apply inverse transformation.
+
+ } elsif ($type eq "ROTATE_Z") {
my $object_id = $operation->{object_identifier};
my $obj_idx = $self->get_object_index($object_id);
$self->select_object($obj_idx);
my $angle = $operation->{attributes}->[0];
- my $axis = $operation->{attributes}->[1];
- $self->rotate(-1 * $angle, $axis, 'true'); # Apply inverse transformation.
+ $self->rotate(-1 * $angle, Z, 'true'); # Apply inverse transformation.
- } elsif ($type eq "INCREASE") {
+ } elsif ($type eq "SCALE_UNIFORM") {
my $object_id = $operation->{object_identifier};
my $obj_idx = $self->get_object_index($object_id);
$self->select_object($obj_idx);
- my $copies = $operation->{attributes}->[0];
- $self->decrease($copies, 'true');
+ my $new_scale = $operation->{attributes}->[0];
+ $self->changescale(undef, undef, $new_scale, 'true');
- } elsif ($type eq "DECREASE") {
+ } elsif ($type eq "INCREASE") {
my $object_id = $operation->{object_identifier};
my $obj_idx = $self->get_object_index($object_id);
$self->select_object($obj_idx);
my $copies = $operation->{attributes}->[0];
- $self->increase($copies, 'true');
+ $self->decrease($copies, 'true');
- } elsif ($type eq "MIRROR") {
+ } elsif ($type eq "DECREASE") {
my $object_id = $operation->{object_identifier};
my $obj_idx = $self->get_object_index($object_id);
$self->select_object($obj_idx);
- my $axis = $operation->{attributes}->[0];
- $self->mirror($axis, 'true');
+ my $copies = $operation->{attributes}->[0];
+ $self->increase($copies, 'true');
} elsif ($type eq "REMOVE") {
my $_model = $operation->{attributes}->[0];
@@ -1079,16 +1099,6 @@ sub undo {
$self->{object_identifier}--;
$self->{objects}->[-1]->identifier($operation->{object_identifier}); # Add the original assigned identifier.
- } elsif ($type eq "CHANGE_SCALE") {
- my $object_id = $operation->{object_identifier};
- my $obj_idx = $self->get_object_index($object_id);
- $self->select_object($obj_idx);
-
- my $axis = $operation->{attributes}->[0];
- my $tosize = $operation->{attributes}->[1];
- my $saved_scale = $operation->{attributes}->[3];
- $self->changescale($axis, $tosize, $saved_scale, 'true');
-
} elsif ($type eq "RESET") {
# Revert changes to the plater object identifier. It's modified when adding new objects only not when undo/redo is executed.
my $current_objects_identifier = $self->{object_identifier};
@@ -1132,38 +1142,45 @@ sub redo {
my $type = $operation->{type};
- if ($type eq "ROTATE") {
+ if ($type eq "TRANSFORM") {
+ my $object_id = $operation->{object_identifier};
+ my $obj_idx = $self->get_object_index($object_id);
+ $self->select_object($obj_idx);
+
+ my $trafo = $operation->{attributes}->[0];
+ $self->transform($trafo, 'true'); # Reapply transformation.
+
+ } elsif ($type eq "ROTATE_Z") {
my $object_id = $operation->{object_identifier};
my $obj_idx = $self->get_object_index($object_id);
$self->select_object($obj_idx);
my $angle = $operation->{attributes}->[0];
- my $axis = $operation->{attributes}->[1];
- $self->rotate($angle, $axis, 'true');
+ $self->rotate($angle, Z, 'true'); # Reapply transformation.
- } elsif ($type eq "INCREASE") {
+ } elsif ($type eq "SCALE_UNIFORM") {
my $object_id = $operation->{object_identifier};
my $obj_idx = $self->get_object_index($object_id);
$self->select_object($obj_idx);
- my $copies = $operation->{attributes}->[0];
- $self->increase($copies, 'true');
+ my $new_scale = $operation->{attributes}->[1];
+ $self->changescale(undef, undef, $new_scale, 'true');
- } elsif ($type eq "DECREASE") {
+ } elsif ($type eq "INCREASE") {
my $object_id = $operation->{object_identifier};
my $obj_idx = $self->get_object_index($object_id);
$self->select_object($obj_idx);
my $copies = $operation->{attributes}->[0];
- $self->decrease($copies, 'true');
+ $self->increase($copies, 'true');
- } elsif ($type eq "MIRROR") {
+ } elsif ($type eq "DECREASE") {
my $object_id = $operation->{object_identifier};
my $obj_idx = $self->get_object_index($object_id);
$self->select_object($obj_idx);
- my $axis = $operation->{attributes}->[0];
- $self->mirror($axis, 'true');
+ my $copies = $operation->{attributes}->[0];
+ $self->decrease($copies, 'true');
} elsif ($type eq "REMOVE") {
my $object_id = $operation->{object_identifier};
@@ -1186,16 +1203,6 @@ sub redo {
$self->{objects}->[-$obj_count]->identifier($obj_identifiers_start++);
$obj_count--;
}
- } elsif ($type eq "CHANGE_SCALE") {
- my $object_id = $operation->{object_identifier};
- my $obj_idx = $self->get_object_index($object_id);
- $self->select_object($obj_idx);
-
- my $axis = $operation->{attributes}->[0];
- my $tosize = $operation->{attributes}->[1];
- my $old_scale = $operation->{attributes}->[2];
- $self->changescale($axis, $tosize, $old_scale, 'true');
-
} elsif ($type eq "RESET") {
$self->reset('true');
} elsif ($type eq "ADD") {
@@ -1493,7 +1500,7 @@ sub reset {
my $current_model = $self->{model}->clone;
if (!defined $dont_push) {
- # Get the identifiers of the curent model objects.
+ # Get the identifiers of the current model objects.
my $objects_identifiers = [];
for (my $i = 0; $i <= $#{$self->{objects}}; $i++){
push @{$objects_identifiers}, $self->{objects}->[$i]->identifier;
@@ -1520,12 +1527,8 @@ sub increase {
for my $i (1..$copies) {
$instance = $model_object->add_instance(
offset => Slic3r::Pointf->new(map 10+$_, @{$instance->offset}),
- z_translation => $instance->z_translation,
scaling_factor => $instance->scaling_factor,
- scaling_vector => $instance->scaling_vector,
rotation => $instance->rotation,
- x_rotation => $instance->x_rotation,
- y_rotation => $instance->y_rotation,
);
$self->{print}->objects->[$obj_idx]->add_copy($instance->offset);
}
@@ -1625,23 +1628,38 @@ sub rotate_face {
return if !defined $normal;
my $axis = $dlg->SelectedAxis;
return if !defined $axis;
-
- # Actual math to rotate
- my $angleToXZ = atan2($normal->y(),$normal->x());
- my $angleToZ = acos(-$normal->z());
- $self->rotate(-rad2deg($angleToXZ),Z);
- $self->rotate(rad2deg($angleToZ),Y);
-
+
+ my $axis_vec = Slic3r::Pointf3->new(0,0,0);
if($axis == Z){
- $self->add_undo_operation("GROUP", $object->identifier, splice(@{$self->{undo_stack}},-2));
+ $axis_vec->set_z(-1);
} else {
if($axis == X){
- $self->rotate(90,Y);
+ $axis_vec->set_x(-1);
} else {
- $self->rotate(90,X);
+ $axis_vec->set_y(-1);
}
- $self->add_undo_operation("GROUP", $object->identifier, splice(@{$self->{undo_stack}},-3));
}
+
+ my $model_object = $self->{model}->objects->[$obj_idx];
+ my $model_instance = $model_object->instances->[0];
+
+ $model_object->transform_by_instance($model_instance, 1);
+
+ $model_object->reset_undo_trafo();
+ $model_object->rotate_vec_to_vec($normal,$axis_vec);
+
+ # realign object to Z = 0
+ $model_object->align_to_ground;
+ $self->make_thumbnail($obj_idx);
+
+ $model_object->update_bounding_box;
+ # update print and start background processing
+ $self->{print}->add_model_object($model_object, $obj_idx);
+
+ $self->selection_changed; # refresh info (size etc.)
+ $self->on_model_change;
+
+ $self->add_undo_operation("TRANSFORM", $object->identifier, $model_object->get_undo_trafo());
}
sub rotate {
@@ -1667,6 +1685,8 @@ sub rotate {
$angle = Wx::GetTextFromUser("Enter the rotation angle:", "Rotate around $axis_name axis",
$default, $self);
return if !$angle || $angle !~ /^-?\d*(?:\.\d*)?$/ || $angle == -1;
+
+ $angle = $angle - $default;
}
$self->stop_background_process;
@@ -1675,25 +1695,31 @@ sub rotate {
my $new_angle = deg2rad($angle);
$_->set_rotation($_->rotation + $new_angle) for @{ $model_object->instances };
$object->transform_thumbnail($self->{model}, $obj_idx);
+
+ if (!defined $dont_push) {
+ $self->add_undo_operation("ROTATE_Z", $object->identifier, $angle);
+ }
} else {
# rotation around X and Y needs to be performed on mesh
# so we first apply any Z rotation
$model_object->transform_by_instance($model_instance, 1);
+
+ $model_object->reset_undo_trafo();
$model_object->rotate(deg2rad($angle), $axis);
# realign object to Z = 0
- $model_object->center_around_origin;
+ $model_object->align_to_ground;
$self->make_thumbnail($obj_idx);
+
+ if (!defined $dont_push) {
+ $self->add_undo_operation("TRANSFORM", $object->identifier, $model_object->get_undo_trafo());
+ }
}
$model_object->update_bounding_box;
# update print and start background processing
$self->{print}->add_model_object($model_object, $obj_idx);
- if (!defined $dont_push) {
- $self->add_undo_operation("ROTATE", $object->identifier, $angle, $axis);
- }
-
$self->selection_changed; # refresh info (size etc.)
$self->on_model_change;
}
@@ -1710,11 +1736,42 @@ sub mirror {
# apply Z rotation before mirroring
$model_object->transform_by_instance($model_instance, 1);
+ $model_object->reset_undo_trafo();
$model_object->mirror($axis);
+
+ # realign object to Z = 0
+ $model_object->align_to_ground;
+ $self->make_thumbnail($obj_idx);
+
+ # update print and start background processing
+ $self->stop_background_process;
+ $self->{print}->add_model_object($model_object, $obj_idx);
+
+ if (!defined $dont_push) {
+ $self->add_undo_operation("TRANSFORM", $object->identifier, $model_object->get_undo_trafo());
+ }
+
+ $self->selection_changed; # refresh info (size etc.)
+ $self->on_model_change;
+}
+
+sub transform {
+ my ($self, $trafo, $dont_push) = @_;
+
+ my ($obj_idx, $object) = $self->selected_object;
+ return if !defined $obj_idx;
+
+ my $model_object = $self->{model}->objects->[$obj_idx];
+ my $model_instance = $model_object->instances->[0];
+
+ # apply Z rotation before mirroring
+ $model_object->transform_by_instance($model_instance, 1);
+
+ $model_object->apply_transformation($trafo);
$model_object->update_bounding_box;
# realign object to Z = 0
- $model_object->center_around_origin;
+ $model_object->align_to_ground;
$self->make_thumbnail($obj_idx);
# update print and start background processing
@@ -1722,7 +1779,7 @@ sub mirror {
$self->{print}->add_model_object($model_object, $obj_idx);
if (!defined $dont_push) {
- $self->add_undo_operation("MIRROR", $object->identifier, $axis);
+ $self->add_undo_operation("TRANSFORM", $object->identifier, $trafo);
}
$self->selection_changed; # refresh info (size etc.)
@@ -1778,9 +1835,17 @@ sub changescale {
my $versor = [1,1,1];
$versor->[$axis] = $scale/100;
+
+ $model_object->reset_undo_trafo();
$model_object->scale_xyz(Slic3r::Pointf3->new(@$versor));
+
# object was already aligned to Z = 0, so no need to realign it
$self->make_thumbnail($obj_idx);
+
+ # Add the new undo operation.
+ if (!defined $dont_push) {
+ $self->add_undo_operation("TRANSFORM", $object->identifier, $model_object->get_undo_trafo());
+ }
} else {
if (!defined $saved_scale) {
if ($tosize) {
@@ -1815,13 +1880,14 @@ sub changescale {
$object->transform_thumbnail($self->{model}, $obj_idx);
$scale *= 100;
- }
- # Add the new undo operation.
- if (!defined $dont_push) {
- $self->add_undo_operation("CHANGE_SCALE", $object->identifier, $axis, $tosize, $scale, $old_scale);
+ # Add the new undo operation.
+ if (!defined $dont_push) {
+ $self->add_undo_operation("SCALE_UNIFORM", $object->identifier, $old_scale, $scale);
+ }
}
+
$model_object->update_bounding_box;
# update print and start background processing
@@ -1863,7 +1929,7 @@ sub split_object {
$self->pause_background_process;
- # Save the curent model object for undo/redo operataions.
+ # Save the current model object for undo/redo operataions.
my $org_object_model = Slic3r::Model->new;
$org_object_model->add_object($current_model_object);
@@ -1889,7 +1955,7 @@ sub split_object {
# remove the original object before spawning the object_loaded event, otherwise
# we'll pass the wrong $obj_idx to it (which won't be recognized after the
# thumbnail thread returns)
- $self->remove($obj_idx, 'true'); # Don't push to the undo stack it's considered a split opeation not a remove one.
+ $self->remove($obj_idx, 'true'); # Don't push to the undo stack it's considered a split operation not a remove one.
$current_object = $obj_idx = undef;
# Save the object identifiers used in undo/redo operations.
@@ -2289,8 +2355,9 @@ sub on_export_completed {
$estimator->parse_file($self->{export_gcode_output_file});
my $time = $estimator->time;
$self->{print_info_tim}->SetLabel(sprintf(
- "%d minutes and %d seconds",
- int($time / 60),
+ "%d hours, %d minutes and %d seconds",
+ int($time / 3600),
+ int(($time % 3600) / 60),
int($time % 60),
));
}
@@ -2468,53 +2535,40 @@ sub export_stl {
sub reload_from_disk {
my ($self) = @_;
- my ($obj_idx, $object) = $self->selected_object;
+ my ($obj_idx, $org_obj_plater) = $self->selected_object;
return if !defined $obj_idx;
- if (!$object->input_file) {
+ if (!$org_obj_plater->input_file) {
Slic3r::GUI::warning_catcher($self)->("The selected object couldn't be reloaded because it isn't referenced to its input file any more. This is the case after performing operations like cut or split.");
return;
}
- if (!-e $object->input_file) {
+ if (!-e $org_obj_plater->input_file) {
Slic3r::GUI::warning_catcher($self)->("The selected object couldn't be reloaded because the file doesn't exist anymore on the disk.");
return;
}
-
- # Only reload the selected object and not all objects from the input file.
- my @new_obj_idx = $self->load_file($object->input_file, $object->input_file_obj_idx);
- if (!@new_obj_idx) {
- Slic3r::GUI::warning_catcher($self)->("The selected object couldn't be reloaded because the new file doesn't contain the object.");
- return;
- }
-
- my $org_obj = $self->{model}->objects->[$obj_idx];
-
- # check if the object is dependant of more than one file
- my $org_obj_has_modifiers=0;
- for my $i (0..($org_obj->volumes_count-1)) {
- if ($org_obj->input_file ne $org_obj->get_volume($i)->input_file) {
- $org_obj_has_modifiers=1;
- last;
- }
- }
my $reload_behavior = $Slic3r::GUI::Settings->{_}{reload_behavior};
+ my $reload_preserve_trafo = $Slic3r::GUI::Settings->{_}{reload_preserve_trafo};
# ask the user how to proceed, if option is selected in preferences
- if ($org_obj_has_modifiers && !$Slic3r::GUI::Settings->{_}{reload_hide_dialog}) {
- my $dlg = Slic3r::GUI::ReloadDialog->new(undef,$reload_behavior);
+ if (!$Slic3r::GUI::Settings->{_}{reload_hide_dialog}) {
+ my $dlg = Slic3r::GUI::ReloadDialog->new(undef,$reload_behavior,$reload_preserve_trafo);
my $res = $dlg->ShowModal;
if ($res==wxID_CANCEL) {
- $self->remove($_) for @new_obj_idx;
$dlg->Destroy;
return;
}
- $reload_behavior = $dlg->GetSelection;
+ $reload_behavior = $dlg->GetAdditionalOption;
+ $reload_preserve_trafo = $dlg->GetPreserveTrafo;
my $save = 0;
if ($reload_behavior != $Slic3r::GUI::Settings->{_}{reload_behavior}) {
$Slic3r::GUI::Settings->{_}{reload_behavior} = $reload_behavior;
$save = 1;
}
+ if ($reload_preserve_trafo != $Slic3r::GUI::Settings->{_}{reload_preserve_trafo}) {
+ $Slic3r::GUI::Settings->{_}{reload_preserve_trafo} = $reload_preserve_trafo;
+ $save = 1;
+ }
if ($dlg->GetHideOnNext) {
$Slic3r::GUI::Settings->{_}{reload_hide_dialog} = 1;
$save = 1;
@@ -2522,6 +2576,15 @@ sub reload_from_disk {
Slic3r::GUI->save_settings if $save;
$dlg->Destroy;
}
+
+ # Only reload the selected object and not all objects from the input file.
+ my @new_obj_idx = $self->load_file($org_obj_plater->input_file, $org_obj_plater->input_file_obj_idx);
+ if (!@new_obj_idx) {
+ Slic3r::GUI::warning_catcher($self)->("The selected object couldn't be reloaded because the new file doesn't contain the object.");
+ return;
+ }
+
+ my $org_obj = my $new_obj = $self->{model}->objects->[$obj_idx];
my $volume_unmatched=0;
@@ -2530,6 +2593,7 @@ sub reload_from_disk {
$new_obj->clear_instances;
$new_obj->add_instance($_) for @{$org_obj->instances};
$new_obj->config->apply($org_obj->config);
+ $new_obj->set_trafo_obj($org_obj->get_trafo_obj()) if $reload_preserve_trafo;
my $new_vol_idx = 0;
my $org_vol_idx = 0;
@@ -2538,10 +2602,12 @@ sub reload_from_disk {
while ($new_vol_idx<=$new_vol_count-1) {
if (($org_vol_idx<=$org_vol_count-1) && ($org_obj->get_volume($org_vol_idx)->input_file eq $new_obj->input_file)) {
- # apply config from the matching volumes
+ # apply config and trafo from the matching volumes
+ $new_obj->get_volume($new_vol_idx)->apply_transformation($org_obj->get_volume($org_vol_idx)->get_transformation) if $reload_preserve_trafo;
$new_obj->get_volume($new_vol_idx++)->config->apply($org_obj->get_volume($org_vol_idx++)->config);
} else {
- # reload has more volumes than original (first file), apply config from the first volume
+ # reload has more volumes than original (first file), apply config and trafo from the parent object
+ $new_obj->get_volume($new_vol_idx)->apply_transformation($org_obj->get_trafo_obj()) if $reload_preserve_trafo;
$new_obj->get_volume($new_vol_idx++)->config->apply($org_obj->get_volume(0)->config);
$volume_unmatched=1;
}
@@ -2553,10 +2619,11 @@ sub reload_from_disk {
$volume_unmatched=1;
}
while ($org_vol_idx<=$org_vol_count-1) {
+ my $org_volume = $org_obj->get_volume($org_vol_idx);
+
if ($reload_behavior==1) { # Reload behavior: copy
- my $new_volume = $new_obj->add_volume($org_obj->get_volume($org_vol_idx));
- $new_volume->mesh->translate(@{$org_obj->origin_translation->negative});
- $new_volume->mesh->translate(@{$new_obj->origin_translation});
+
+ my $new_volume = $new_obj->add_volume($org_volume);
if ($new_volume->name =~ m/link to path\z/) {
my $new_name = $new_volume->name;
$new_name =~ s/ - no link to path$/ - copied/;
@@ -2564,35 +2631,37 @@ sub reload_from_disk {
}elsif(!($new_volume->name =~ m/copied\z/)) {
$new_volume->set_name($new_volume->name . " - copied");
}
+
}else{ # Reload behavior: Reload all, also fallback solution if ini was manually edited to a wrong value
- if ($org_obj->get_volume($org_vol_idx)->input_file) {
- my $model = eval { Slic3r::Model->read_from_file($org_obj->get_volume($org_vol_idx)->input_file) };
+
+ if ($org_volume->input_file) {
+ my $model = eval { Slic3r::Model->read_from_file($org_volume->input_file) };
if ($@) {
- $org_obj->get_volume($org_vol_idx)->set_input_file("");
- }elsif ($org_obj->get_volume($org_vol_idx)->input_file_obj_idx > ($model->objects_count-1)) {
+ $org_volume->set_input_file("");
+ }elsif ($org_volume->input_file_obj_idx > ($model->objects_count-1)) {
# Object Index for that part / modifier not found in current version of the file
- $org_obj->get_volume($org_vol_idx)->set_input_file("");
+ $org_volume->set_input_file("");
}else{
- my $prt_mod_obj = $model->objects->[$org_obj->get_volume($org_vol_idx)->input_file_obj_idx];
- if ($org_obj->get_volume($org_vol_idx)->input_file_vol_idx > ($prt_mod_obj->volumes_count-1)) {
+ my $prt_mod_obj = $model->objects->[$org_volume->input_file_obj_idx];
+ if ($org_volume->input_file_vol_idx > ($prt_mod_obj->volumes_count-1)) {
# Volume Index for that part / modifier not found in current version of the file
- $org_obj->get_volume($org_vol_idx)->set_input_file("");
+ $org_volume->set_input_file("");
}else{
# all checks passed, load new mesh and copy metadata
- my $new_volume = $new_obj->add_volume($prt_mod_obj->get_volume($org_obj->get_volume($org_vol_idx)->input_file_vol_idx));
- $new_volume->set_input_file($org_obj->get_volume($org_vol_idx)->input_file);
- $new_volume->set_input_file_obj_idx($org_obj->get_volume($org_vol_idx)->input_file_obj_idx);
- $new_volume->set_input_file_vol_idx($org_obj->get_volume($org_vol_idx)->input_file_vol_idx);
- $new_volume->config->apply($org_obj->get_volume($org_vol_idx)->config);
- $new_volume->set_modifier($org_obj->get_volume($org_vol_idx)->modifier);
- $new_volume->mesh->translate(@{$new_obj->origin_translation});
+ my $new_volume = $new_obj->add_volume($prt_mod_obj->get_volume($org_volume->input_file_vol_idx));
+
+ $new_volume->apply_transformation($org_volume->get_transformation()) if $reload_preserve_trafo;
+
+ $new_volume->set_input_file($org_volume->input_file);
+ $new_volume->set_input_file_obj_idx($org_volume->input_file_obj_idx);
+ $new_volume->set_input_file_vol_idx($org_volume->input_file_vol_idx);
+ $new_volume->config->apply($org_volume->config);
+ $new_volume->set_modifier($org_volume->modifier);
}
}
}
- if (!$org_obj->get_volume($org_vol_idx)->input_file) {
- my $new_volume = $new_obj->add_volume($org_obj->get_volume($org_vol_idx)); # error -> copy old mesh
- $new_volume->mesh->translate(@{$org_obj->origin_translation->negative});
- $new_volume->mesh->translate(@{$new_obj->origin_translation});
+ if (!$org_volume->input_file) {
+ my $new_volume = $new_obj->add_volume($org_volume); # error -> copy old mesh
if ($new_volume->name =~ m/copied\z/) {
my $new_name = $new_volume->name;
$new_name =~ s/ - copied$/ - no link to path/;
@@ -2605,6 +2674,7 @@ sub reload_from_disk {
}
$org_vol_idx++;
}
+ $new_obj->center_around_origin();
}
$self->remove($obj_idx);
@@ -3374,9 +3444,7 @@ sub make_thumbnail {
my $mesh = $model->objects->[$obj_idx]->raw_mesh;
# Apply x, y rotations and scaling vector in case of reading a 3MF model object.
my $model_instance = $model->objects->[$obj_idx]->instances->[0];
- $mesh->rotate_x($model_instance->x_rotation);
- $mesh->rotate_y($model_instance->y_rotation);
- $mesh->scale_xyz($model_instance->scaling_vector);
+ $mesh->transform($model_instance->additional_trafo);
if ($mesh->facets_count <= 5000) {
# remove polygons with area <= 1mm
diff --git a/lib/Slic3r/GUI/Plater/2DToolpaths.pm b/lib/Slic3r/GUI/Plater/2DToolpaths.pm
index 87d819c748..96aec163b2 100644
--- a/lib/Slic3r/GUI/Plater/2DToolpaths.pm
+++ b/lib/Slic3r/GUI/Plater/2DToolpaths.pm
@@ -172,7 +172,7 @@ sub new {
$class->SUPER::new($parent, -1, Wx::wxDefaultPosition, Wx::wxDefaultSize, 0, "",
[WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 24, 0]) :
$class->SUPER::new($parent);
- # Immediatelly force creation of the OpenGL context to consume the static variable s_wglContextAttribs.
+ # Immediately force creation of the OpenGL context to consume the static variable s_wglContextAttribs.
$self->GetContext();
$self->print($print);
$self->_zoom(1);
@@ -356,7 +356,7 @@ sub Render {
my $tess;
if (!(&Wx::wxMSW && $OpenGL::VERSION < 0.6704)) {
- # We can't use the GLU tesselator on MSW with older OpenGL versions
+ # We can't use the GLU tessellator on MSW with older OpenGL versions
# because of an upstream bug:
# http://sourceforge.net/p/pogl/bugs/16/
$tess = gluNewTess();
diff --git a/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm b/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm
index 35c1af28be..031b03d1e5 100644
--- a/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm
+++ b/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm
@@ -366,7 +366,7 @@ sub on_btn_load {
$new_volume->set_input_file_vol_idx($vol_idx);
# apply the same translation we applied to the object
- $new_volume->mesh->translate(@{$self->{model_object}->origin_translation});
+ $new_volume->apply_transformation($self->{model_object}->get_trafo_obj);
# set a default extruder value, since user can't add it manually
$new_volume->config->set_ifndef('extruder', 0);
@@ -405,27 +405,26 @@ sub on_btn_lambda {
$params->{"slab_h"},
);
# box sets the base coordinate at 0,0, move to center of plate
- $mesh->translate(
- -$size->x*1.5/2.0,
- -$size->y*1.5/2.0, #**
- 0,
- );
+ my $trafo = Slic3r::TransformationMatrix->new;
+ $trafo->set_translation_xyz(-$size->x*1.5/2.0,-$size->y*1.5/2.0,0);
+ $mesh->transform($trafo);
} else {
return;
}
my $center = $self->{model_object}->bounding_box->center;
- if (!$Slic3r::GUI::Settings->{_}{autocenter}) {
- #TODO what we really want to do here is just align the
- # center of the modifier to the center of the part.
- $mesh->translate($center->x, $center->y, 0);
- }
$mesh->repair;
my $new_volume = $self->{model_object}->add_volume(mesh => $mesh);
$new_volume->set_modifier($is_modifier);
$new_volume->set_name($name);
+ if (!$Slic3r::GUI::Settings->{_}{autocenter}) {
+ #TODO what we really want to do here is just align the
+ # center of the modifier to the center of the part.
+ $new_volume->translate($center->x, $center->y,0);
+ }
+
# set a default extruder value, since user can't add it manually
$new_volume->config->set_ifndef('extruder', 0);
@@ -497,7 +496,7 @@ sub _update {
my $itemData = $self->get_selection;
if ($itemData && $itemData->{type} eq 'volume') {
my $volume = $self->{model_object}->volumes->[$itemData->{volume_id}];
- $volume->mesh->translate(@{ $volume->mesh->bounding_box->min_point->vector_to($self->{move_target}) });
+ $volume->translate(@{ $volume->mesh->bounding_box->min_point->vector_to($self->{move_target}) });
}
$self->{parts_changed} = 1;
@@ -517,7 +516,7 @@ sub changescale {
if (defined $axis) {
my $axis_name = $axis == X ? 'X' : $axis == Y ? 'Y' : 'Z';
my $scale;
- if (defined $tosize) {
+ if ($tosize) {
my $cursize = $object_size->[$axis];
# Wx::GetNumberFromUser() does not support decimal numbers
my $newsize = Wx::GetTextFromUser(
@@ -535,7 +534,7 @@ sub changescale {
}
my $versor = [1,1,1];
$versor->[$axis] = $scale/100;
- $volume->mesh->scale_xyz(Slic3r::Pointf3->new(@$versor));
+ $volume->scale_xyz(Slic3r::Pointf3->new(@$versor));
} else {
my $scale;
if ($tosize) {
@@ -553,7 +552,7 @@ sub changescale {
return if !$scale || $scale !~ /^\d*(?:\.\d*)?$/ || $scale < 0;
}
return if !$scale || $scale < 0;
- $volume->mesh->scale($scale);
+ $volume->scale_xyz(Slic3r::Pointf3->new($scale/100, $scale/100, $scale/100));
}
$self->_parts_changed;
}
@@ -574,10 +573,9 @@ sub rotate {
$default, $self);
return if !$angle || $angle !~ /^-?\d*(?:\.\d*)?$/ || $angle == -1;
}
- if ($axis == X) { $volume->mesh->rotate_x(deg2rad($angle)); }
-
- if ($axis == Y) { $volume->mesh->rotate_y(deg2rad($angle)); }
- if ($axis == Z) { $volume->mesh->rotate_z(deg2rad($angle)); }
+ if ($axis == X) { $volume->rotate(deg2rad($angle), X); }
+ if ($axis == Y) { $volume->rotate(deg2rad($angle), Y); }
+ if ($axis == Z) { $volume->rotate(deg2rad($angle), Z); }
$self->_parts_changed;
}
diff --git a/lib/Slic3r/GUI/Preferences.pm b/lib/Slic3r/GUI/Preferences.pm
index 3dcf43e39b..d9788b23d2 100644
--- a/lib/Slic3r/GUI/Preferences.pm
+++ b/lib/Slic3r/GUI/Preferences.pm
@@ -97,9 +97,16 @@ sub new {
opt_id => 'reload_hide_dialog',
type => 'bool',
label => 'Hide Dialog on Reload',
- tooltip => 'When checked, the dialog on reloading files with added parts & modifiers is suppressed. The reload is performed according to the option given in \'Default Reload Behavior\'',
+ tooltip => 'When checked, the dialog on reloading files with added parts & modifiers is suppressed. The reload is performed according to the option given in \'Default Reload Behavior\' and \'Keep Transformation on Reload\'',
default => $Slic3r::GUI::Settings->{_}{reload_hide_dialog},
));
+ $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( # reload preserve transformation
+ opt_id => 'reload_preserve_trafo',
+ type => 'bool',
+ label => 'Keep Transformations on Reload',
+ tooltip => 'When checked, the \'Reload from disk\' function tries to preserve the current orientation of the object on the bed by applying the same transformation to the reloaded object.',
+ default => $Slic3r::GUI::Settings->{_}{reload_preserve_trafo},
+ ));
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( # default reload behavior
opt_id => 'reload_behavior',
type => 'select',
diff --git a/lib/Slic3r/GUI/PresetEditor.pm b/lib/Slic3r/GUI/PresetEditor.pm
index ef41aa863a..447be9228b 100644
--- a/lib/Slic3r/GUI/PresetEditor.pm
+++ b/lib/Slic3r/GUI/PresetEditor.pm
@@ -1251,6 +1251,7 @@ sub title { 'Printer Settings' }
sub options {
return qw(
bed_shape z_offset z_steps_per_mm has_heatbed
+ fan_percentage
gcode_flavor use_relative_e_distances
serial_port serial_speed
host_type print_host octoprint_apikey
@@ -1417,6 +1418,7 @@ sub build {
$optgroup->append_single_option_line('z_steps_per_mm');
$optgroup->append_single_option_line('use_set_and_wait_extruder');
$optgroup->append_single_option_line('use_set_and_wait_bed');
+ $optgroup->append_single_option_line('fan_percentage');
}
}
{
diff --git a/lib/Slic3r/GUI/ReloadDialog.pm b/lib/Slic3r/GUI/ReloadDialog.pm
index bb11bf0898..1430aa45cb 100644
--- a/lib/Slic3r/GUI/ReloadDialog.pm
+++ b/lib/Slic3r/GUI/ReloadDialog.pm
@@ -11,11 +11,11 @@ use base 'Wx::Dialog';
sub new {
my $class = shift;
- my ($parent,$default_selection) = @_;
- my $self = $class->SUPER::new($parent, -1, "Additional parts and modifiers detected", wxDefaultPosition, [350,100], wxDEFAULT_DIALOG_STYLE);
+ my ($parent,$default_selection,$default_preserve) = @_;
+ my $self = $class->SUPER::new($parent, -1, "Reload options", wxDefaultPosition, [350,100], wxDEFAULT_DIALOG_STYLE);
# label
- my $text = Wx::StaticText->new($self, -1, "Additional parts and modifiers are loaded in the current model. \n\nHow do you want to proceed?", wxDefaultPosition, wxDefaultSize);
+ my $text_additional = Wx::StaticText->new($self, -1, "Handling of additional parts and modifiers:", wxDefaultPosition, wxDefaultSize);
# selector
$self->{choice} = my $choice = Wx::Choice->new($self, -1, wxDefaultPosition, wxDefaultSize, []);
@@ -24,14 +24,23 @@ sub new {
$choice->Append("Reload main file, discard added parts & modifiers");
$choice->SetSelection($default_selection);
- # checkbox
- $self->{checkbox} = my $checkbox = Wx::CheckBox->new($self, -1, "Don't ask again");
+ # label
+ my $text_trafo = Wx::StaticText->new($self, -1, "Handling of transformations made inside Slic3r:", wxDefaultPosition, wxDefaultSize);
+
+ # cb_Transformation
+ $self->{cb_Transformation} = my $cb_Transformation = Wx::CheckBox->new($self, -1, "Preserve transformations");
+ $cb_Transformation->SetValue($default_preserve);
+
+ # cb_HideDialog
+ $self->{cb_HideDialog} = my $cb_HideDialog = Wx::CheckBox->new($self, -1, "Don't ask again");
my $vsizer = Wx::BoxSizer->new(wxVERTICAL);
my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL);
- $vsizer->Add($text, 0, wxEXPAND | wxALL, 10);
- $vsizer->Add($choice, 0, wxEXPAND | wxALL, 10);
- $hsizer->Add($checkbox, 1, wxEXPAND | wxALL, 10);
+ $vsizer->Add($text_additional, 0, wxEXPAND | wxALL, 10);
+ $vsizer->Add($choice, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxRIGHT, 10);
+ $vsizer->Add($text_trafo, 0, wxEXPAND | wxALL, 10);
+ $vsizer->Add($cb_Transformation, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxRIGHT, 10);
+ $hsizer->Add($cb_HideDialog, 1, wxEXPAND | wxALL, 10);
$hsizer->Add($self->CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxALL, 10);
$vsizer->Add($hsizer, 0, wxEXPAND | wxALL, 0);
@@ -48,13 +57,17 @@ sub new {
return $self;
}
-sub GetSelection {
+sub GetAdditionalOption {
my ($self) = @_;
return $self->{choice}->GetSelection;
}
+sub GetPreserveTrafo {
+ my ($self) = @_;
+ return $self->{cb_Transformation}->GetValue;
+}
sub GetHideOnNext {
my ($self) = @_;
- return $self->{checkbox}->GetValue;
+ return $self->{cb_HideDialog}->GetValue;
}
1;
diff --git a/lib/Slic3r/Model.pm b/lib/Slic3r/Model.pm
index 8f75e91ab0..b703bc4b5a 100644
--- a/lib/Slic3r/Model.pm
+++ b/lib/Slic3r/Model.pm
@@ -36,8 +36,8 @@ sub add_object {
if defined $args{config};
$new_object->set_layer_height_ranges($args{layer_height_ranges})
if defined $args{layer_height_ranges};
- $new_object->set_origin_translation($args{origin_translation})
- if defined $args{origin_translation};
+ $new_object->apply_transformation($args{trafo_obj})
+ if defined $args{trafo_obj};
return $new_object;
}
@@ -128,18 +128,10 @@ sub add_instance {
$new_instance->set_rotation($args{rotation})
if defined $args{rotation};
- $new_instance->set_x_rotation($args{x_rotation})
- if defined $args{x_rotation};
- $new_instance->set_y_rotation($args{y_rotation})
- if defined $args{y_rotation};
$new_instance->set_scaling_factor($args{scaling_factor})
if defined $args{scaling_factor};
- $new_instance->set_scaling_vector($args{scaling_vector})
- if defined $args{scaling_vector};
$new_instance->set_offset($args{offset})
if defined $args{offset};
- $new_instance->set_z_translation($args{z_translation})
- if defined $args{z_translation};
return $new_instance;
}
diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm
index 7af7cb93ff..e7fbf749a8 100644
--- a/lib/Slic3r/Print.pm
+++ b/lib/Slic3r/Print.pm
@@ -203,7 +203,7 @@ sub export_svg {
EOF
diff --git a/lib/Slic3r/Print/GCode.pm b/lib/Slic3r/Print/GCode.pm
index 250029647d..c0f037569f 100644
--- a/lib/Slic3r/Print/GCode.pm
+++ b/lib/Slic3r/Print/GCode.pm
@@ -145,6 +145,9 @@ sub export {
# disable fan
print $fh $gcodegen->writer->set_fan(0, 1)
if $self->config->cooling && $self->config->disable_fan_first_layers;
+
+ # set initial extruder so it can be used in start G-code
+ print $fh $gcodegen->set_extruder($self->print->extruders->[0]);
# set bed temperature
if ($self->config->has_heatbed && (my $temp = $self->config->first_layer_bed_temperature) && $self->config->start_gcode !~ /M(?:190|140)/i) {
@@ -226,9 +229,6 @@ sub export {
}
}
- # set initial extruder only after custom start G-code
- print $fh $gcodegen->set_extruder($self->print->extruders->[0]);
-
# do all objects for each layer
if ($self->config->complete_objects) {
# print objects from the smallest to the tallest to avoid collisions
@@ -328,6 +328,7 @@ sub export {
print $fh $gcodegen->writer->update_progress($gcodegen->layer_count, $gcodegen->layer_count, 1); # 100%
print $fh $gcodegen->writer->postamble;
+ print $fh $gcodegen->cog_stats;
# get filament stats
$self->print->clear_filament_stats;
@@ -341,26 +342,26 @@ sub export {
my $filament_weight = $extruded_volume * $extruder->filament_density / 1000;
my $filament_cost = $filament_weight * ($extruder->filament_cost / 1000);
$self->print->set_filament_stats($extruder->id, $used_filament);
-
- printf $fh "; filament used = %.1fmm (%.1fcm3)\n",
- $used_filament, $extruded_volume/1000;
+
+ printf $fh "; filament_length_m = %.4f \n", $used_filament/1000;
+ printf $fh "; filament_volume_cm3 = %.4f\n", $extruded_volume/1000;
if ($filament_weight > 0) {
$self->print->total_weight($self->print->total_weight + $filament_weight);
- printf $fh "; filament used = %.1fg\n",
+ printf $fh "; filament mass_g = %.2f\n",
$filament_weight;
if ($filament_cost > 0) {
$self->print->total_cost($self->print->total_cost + $filament_cost);
- printf $fh "; filament cost = %.1f\n",
+ printf $fh "; filament_cost = %.2f\n",
$filament_cost;
}
}
-
+
$self->print->total_used_filament($self->print->total_used_filament + $used_filament);
$self->print->total_extruded_volume($self->print->total_extruded_volume + $extruded_volume);
}
- printf $fh "; total filament cost = %.1f\n",
+ printf $fh "; total_filament_cost = %.1f\n",
$self->print->total_cost;
-
+
# append full config
print $fh "\n";
foreach my $config ($self->print->config, $self->print->default_object_config, $self->print->default_region_config) {
diff --git a/lib/Slic3r/Print/Simple.pm b/lib/Slic3r/Print/Simple.pm
index 3c847d51db..7bc913008c 100644
--- a/lib/Slic3r/Print/Simple.pm
+++ b/lib/Slic3r/Print/Simple.pm
@@ -34,6 +34,16 @@ has 'rotate' => (
default => sub { 0 },
);
+has 'rotate_x' => (
+ is => 'rw',
+ default => sub { 0 },
+);
+
+has 'rotate_y' => (
+ is => 'rw',
+ default => sub { 0 },
+);
+
has 'duplicate_grid' => (
is => 'rw',
default => sub { [1,1] },
@@ -83,9 +93,24 @@ sub set_model {
my $need_arrange = $model->add_default_instances && ! $self->dont_arrange;
# apply scaling and rotation supplied from command line if any
- foreach my $instance (map @{$_->instances}, @{$model->objects}) {
+ foreach my $model_object (@{$model->objects}) {
+ foreach my $instance (@{$model_object->instances}) {
$instance->set_scaling_factor($instance->scaling_factor * $self->scale);
$instance->set_rotation($instance->rotation + $self->rotate);
+ #$instance->set_x_rotation($instance->x_rotation + $self->rotate_x);
+ #$instance->set_y_rotation($instance->y_rotation + $self->rotate_y);
+ if ($self->rotate_x != 0 || $self->rotate_y != 0) {
+ $model_object->transform_by_instance($instance, 1);
+ if ($self->rotate_x != 0) {
+ $model_object->rotate($self->rotate_x, X);
+ }
+ if ($self->rotate_y != 0) {
+ $model_object->rotate($self->rotate_y, Y);
+ }
+ # realign object to Z = 0
+ $model_object->center_around_origin;
+ }
+ }
}
my $bed_shape = $self->_print->config->bed_shape;
diff --git a/lib/Slic3r/Test.pm b/lib/Slic3r/Test.pm
index f167e30aa3..e71b38ce9c 100644
--- a/lib/Slic3r/Test.pm
+++ b/lib/Slic3r/Test.pm
@@ -164,8 +164,16 @@ sub mesh {
my $mesh = Slic3r::TriangleMesh->new;
$mesh->ReadFromPerl($vertices, $facets);
$mesh->repair;
- $mesh->scale_xyz(Slic3r::Pointf3->new(@{$params{scale_xyz}})) if $params{scale_xyz};
- $mesh->translate(@{$params{translate}}) if $params{translate};
+
+ my $trafo = Slic3r::TransformationMatrix->new;
+ $trafo->set_scale_xyz(@{$params{scale_xyz}}) if $params{scale_xyz};
+ if ($params{translate}) {
+ my $trafo2 = Slic3r::TransformationMatrix->new;
+ $trafo2->set_translation_xyz(@{$params{translate}});
+ $trafo->applyLeft($trafo2);
+ }
+
+ $mesh->transform($trafo);
return $mesh;
}
diff --git a/package/common/util.sh b/package/common/util.sh
index d7e7dfb20e..dc09122b0d 100755
--- a/package/common/util.sh
+++ b/package/common/util.sh
@@ -46,7 +46,7 @@ fi
function set_branch ()
{
echo "Setting current_branch"
- if [ -z ${TRAVIS_BRANCH} ] && [ -z ${GIT_BRANCH+x} ] && [ -z ${APPVEYOR_REPO_BRANCH+x} ]; then
+ if [ -z ${TRAVIS_BRANCH+x} ] && [ -z ${GIT_BRANCH+x} ] && [ -z ${APPVEYOR_REPO_BRANCH+x} ]; then
current_branch=$(git symbolic-ref HEAD | sed 's!refs\/heads\/!!')
else
current_branch="unknown"
diff --git a/package/deploy/sftp.sh b/package/deploy/sftp.sh
index 7404d71b77..3cec99357d 100755
--- a/package/deploy/sftp.sh
+++ b/package/deploy/sftp.sh
@@ -29,7 +29,8 @@ if [ -s $KEY ]; then
for i in $FILES; do
filepath=$i # this is expected to be an absolute path
tmpfile=$(mktemp)
- echo put $filepath > $tmpfile
+ echo progress > $tmpfile
+ echo put $filepath >> $tmpfile
sftp -b $tmpfile -i$KEY "${UPLOAD_USER}@dl.slic3r.org:$DIR/"
result=$?
@@ -37,6 +38,7 @@ if [ -s $KEY ]; then
echo "Error with SFTP"
exit $result;
fi
+ rm $tmpfile
done
else
echo "$KEY is not available, not deploying."
diff --git a/package/linux/make_archive.sh b/package/linux/make_archive.sh
index 83e0f307a8..c2b59d77e6 100755
--- a/package/linux/make_archive.sh
+++ b/package/linux/make_archive.sh
@@ -43,7 +43,7 @@ fi
rm -rf $WD/_tmp
mkdir -p $WD/_tmp
-# Set the application folder infomation.
+# Set the application folder information.
appfolder="$WD/${appname}"
archivefolder=$appfolder
resourcefolder=$appfolder
diff --git a/package/linux/travis-build-cpp.sh b/package/linux/travis-build-cpp.sh
index 7c45c81fe0..afa96ec6d4 100755
--- a/package/linux/travis-build-cpp.sh
+++ b/package/linux/travis-build-cpp.sh
@@ -6,6 +6,12 @@ export CC=gcc-7
export CXX=g++-7
export DISPLAY=:99.0
+if [ -f "$(which cmake3)" ]; then
+ export CMAKE=$(which cmake3)
+else
+ export CMAKE=$(which cmake)
+fi
+
mkdir -p $CACHE
if [[ "$WXVERSION" != "pkg" ]]; then
@@ -25,6 +31,6 @@ fi
tar -C$HOME -xjf $CACHE/boost-compiled.tar.bz2
mkdir build && cd build
-cmake -DBOOST_ROOT=$HOME/boost_1_63_0 -DSLIC3R_STATIC=ON -DCMAKE_BUILD_TYPE=Release ../src
-cmake --build .
+${CMAKE} -DBOOST_ROOT=$HOME/boost_1_63_0 -DSLIC3R_STATIC=ON -DCMAKE_BUILD_TYPE=Release ../src
+${CMAKE} --build .
./slic3r_test -s
diff --git a/package/osx/make_dmg.sh b/package/osx/make_dmg.sh
index 3e6104bf45..01a62d0303 100755
--- a/package/osx/make_dmg.sh
+++ b/package/osx/make_dmg.sh
@@ -183,6 +183,12 @@ find -d $macosfolder/local-lib -name libwx_osx_cocoau_webview-3.* -delete
rm -rf $macosfolder/local-lib/lib/perl5/darwin-thread-multi-2level/Alien/wxWidgets/osx_cocoa_3_0_2_uni/include
find -d $macosfolder/local-lib -type d -empty -delete
+# remove wx build tools
+rm -rf $macosfolder/local-lib/lib/perl5/darwin-thread-multi-2level/Alien/wxWidgets/osx_cocoa_3_0_2_uni/bin
+
+# Remove all broken symlinks
+find -L $macosfolder/local-lib/lib/perl5/darwin-thread-multi-2level/Alien/wxWidgets/osx_cocoa_3_0_2_uni -type l -exec rm {} \;
+
make_plist
echo $PkgInfoContents >$appfolder/Contents/PkgInfo
@@ -212,7 +218,7 @@ if [ ! -z $KEYCHAIN_FILE_ ]; then
security list-keychains -s "${KEYCHAIN_FILE_}"
security default-keychain -s "${KEYCHAIN_FILE_}"
security unlock-keychain -p "${KEYCHAIN_PASSWORD_}" "${KEYCHAIN_FILE_}"
- codesign --sign "${KEYCHAIN_IDENTITY_}" --deep "$appfolder"
+ codesign --sign "${KEYCHAIN_IDENTITY_}" --options=runtime --strict --deep "$appfolder"
else
echo "No KEYCHAIN_FILE or KEYCHAIN_BASE64 env variable; skipping codesign"
fi
@@ -229,7 +235,7 @@ if [ ! -z $KEYCHAIN_FILE_ ]; then
security list-keychains -s "${KEYCHAIN_FILE_}"
security default-keychain -s "${KEYCHAIN_FILE_}"
security unlock-keychain -p "${KEYCHAIN_PASSWORD_}" "${KEYCHAIN_FILE_}"
- codesign --sign "${KEYCHAIN_IDENTITY_}" "$dmgfile"
+ codesign --sign "${KEYCHAIN_IDENTITY_}" --options=runtime --strict "$dmgfile"
fi
rm -rf $WD/_tmp
diff --git a/slic3r.pl b/slic3r.pl
index f68968dd80..ba802960c8 100755
--- a/slic3r.pl
+++ b/slic3r.pl
@@ -50,6 +50,8 @@ BEGIN
'scale=f' => \$opt{scale},
'rotate=f' => \$opt{rotate},
+ 'rotate-x=f' => \$opt{rotate_x},
+ 'rotate-y=f' => \$opt{rotate_y},
'sc=f@' => \$opt{sc},
'sx=f@' => \$opt{sx},
'sy=f@' => \$opt{sy},
@@ -190,7 +192,7 @@ BEGIN
my $model = Slic3r::Model->read_from_file($file);
$model->add_default_instances;
my $mesh = $model->mesh;
- $mesh->translate(0, 0, -$mesh->bounding_box->z_min);
+ $mesh->align_to_bed();
my $upper = Slic3r::TriangleMesh->new;
my $lower = Slic3r::TriangleMesh->new;
$mesh->cut(Z, $opt{cut}, $upper, $lower);
@@ -211,8 +213,8 @@ BEGIN
my $model = Slic3r::Model->read_from_file($file);
$model->add_default_instances;
my $mesh = $model->mesh;
+ $mesh->align_to_bed();
my $bb = $mesh->bounding_box;
- $mesh->translate(0, 0, -$bb->z_min);
my $x_parts = ceil(($bb->size->x - epsilon)/$grid_x);
my $y_parts = ceil(($bb->size->y - epsilon)/$grid_y); #--
@@ -307,6 +309,8 @@ BEGIN
my $sprint = Slic3r::Print::Simple->new(
scale => $opt{scale} // 1,
rotate => deg2rad($opt{rotate} // 0),
+ rotate_x => deg2rad($opt{rotate_x} // 0),
+ rotate_y => deg2rad($opt{rotate_y} // 0),
duplicate => $opt{duplicate} // 1,
duplicate_grid => $opt{duplicate_grid} // [1,1],
print_center => $opt{print_center},
@@ -358,7 +362,7 @@ sub usage {
print <<"EOF";
Slic3r $Slic3r::VERSION is a STL-to-GCODE translator for RepRap 3D printers
-written by Alessandro Ranellucci - http://slic3r.org/
+written by Alessandro Ranellucci - https://slic3r.org/
Usage: slic3r.pl [ OPTIONS ] [ file.stl ] [ file2.stl ] ...
@@ -612,7 +616,9 @@ sub usage {
Transform options:
--scale Factor for scaling input object (default: 1)
- --rotate Rotation angle in degrees (0-360, default: 0)
+ --rotate Rotation angle in degrees around Z (default: 0)
+ --rotate-x Rotation angle in degrees around X (default: 0)
+ --rotate-y Rotation angle in degrees around Y (default: 0)
--duplicate Number of items with auto-arrange (1+, default: 1)
--duplicate-grid Number of items with grid arrangement (default: 1,1)
--duplicate-distance Distance in mm between copies (default: $config->{duplicate_distance})
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e73b7c073c..5b3ad7ed8a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,16 +1,21 @@
-cmake_minimum_required (VERSION 3.9)
+cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
project (slic3r)
option(Enable_GUI "Use the wxWidgets code in slic3r.cpp" OFF)
-option(GUI_BUILD_TESTS "Build tests for Slic3r GUI." ON)
+option(GUI_BUILD_TESTS "Build tests for Slic3r GUI." OFF)
option(SLIC3R_BUILD_TESTS "Build tests for libslic3r." ON)
option(SLIC3R_STATIC "Build and link Slic3r statically." ON)
option(BUILD_EXTRUDE_TIN "Build and link the extrude-tin application." OFF)
option(PROFILE "Build with gprof profiling output." OFF)
option(COVERAGE "Build with gcov code coverage profiling." OFF)
+option(SLIC3R_DEBUG "Build with Slic3r's debug output" OFF)
# only on newer GCCs: -ftemplate-backtrace-limit=0
-add_compile_options(-DNO_PERL -DM_PI=3.14159265358979323846 -D_GLIBCXX_USE_C99 -DHAS_BOOL -DNOGDI -DBOOST_ASIO_DISABLE_KQUEUE)
+add_compile_options(-ftemplate-backtrace-limit=0)
+add_compile_options(-DNO_PERL -DM_PI=3.14159265358979323846 -DHAS_BOOL -DNOGDI -DBOOST_ASIO_DISABLE_KQUEUE)
+if(SLIC3R_DEBUG)
+ add_compile_options(-DSLIC3R_DEBUG)
+endif()
if (MSVC)
add_compile_options(-W3)
@@ -114,8 +119,14 @@ endif(NOT GIT_VERSION STREQUAL "")
find_package(Threads REQUIRED)
+set(Boost_NO_BOOST_CMAKE ON)
find_package(Boost REQUIRED COMPONENTS system thread filesystem)
+if (NOT (${Boost_VERSION_STRING} VERSION_LESS "1.74.0"))
+ MESSAGE("Adding in boost::nowide")
+ find_package(Boost REQUIRED COMPONENTS system thread filesystem OPTIONAL_COMPONENTS nowide)
+endif()
+
set(LIBDIR ${CMAKE_CURRENT_SOURCE_DIR}/../xs/src/)
set(GUI_LIBDIR ${CMAKE_CURRENT_SOURCE_DIR}/GUI/)
@@ -161,6 +172,10 @@ set(LIBSLIC3R_INCLUDES
add_library(ZipArchive STATIC
${LIBDIR}/Zip/ZipArchive.cpp
)
+
+add_library(miniz STATIC
+ ${LIBDIR}/miniz/miniz.c
+)
target_compile_features(ZipArchive PUBLIC cxx_std_11)
target_include_directories(ZipArchive PUBLIC ${COMMON_INCLUDES})
target_compile_options(ZipArchive PUBLIC -w)
@@ -223,12 +238,17 @@ add_library(libslic3r STATIC
${LIBDIR}/libslic3r/SurfaceCollection.cpp
${LIBDIR}/libslic3r/SVG.cpp
${LIBDIR}/libslic3r/TriangleMesh.cpp
+ ${LIBDIR}/libslic3r/TransformationMatrix.cpp
${LIBDIR}/libslic3r/SupportMaterial.cpp
${LIBDIR}/libslic3r/utils.cpp
+ ${LIBDIR}/libslic3r/miniz_extension.cpp
)
target_compile_features(libslic3r PUBLIC cxx_std_11)
target_include_directories(libslic3r SYSTEM PUBLIC ${SLIC3R_INCLUDES})
target_include_directories(libslic3r PUBLIC ${LIBSLIC3R_INCLUDES})
+if (BOOST_NOWIDE_FOUND)
+ target_compile_options(libslic3r -DBOOST_INCLUDE_NOWIDE)
+endif()
add_library(BSpline STATIC
${LIBDIR}/BSpline/BSpline.cpp
@@ -314,9 +334,11 @@ set(SLIC3R_TEST_SOURCES
${TESTDIR}/libslic3r/test_printobject.cpp
${TESTDIR}/libslic3r/test_skirt_brim.cpp
${TESTDIR}/libslic3r/test_test_data.cpp
+ ${TESTDIR}/libslic3r/test_transformationmatrix.cpp
${TESTDIR}/libslic3r/test_trianglemesh.cpp
${TESTDIR}/libslic3r/test_extrusion_entity.cpp
${TESTDIR}/libslic3r/test_3mf.cpp
+ ${TESTDIR}/libslic3r/test_amf.cpp
)
@@ -330,7 +352,6 @@ cmake_policy(SET CMP0072 NEW)
endif (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_GREATER 3.10)
-find_package(OpenGL)
if(SLIC3R_STATIC)
set(Boost_USE_STATIC_LIBS ON)
@@ -356,15 +377,19 @@ endif(SLIC3R_STATIC)
set_target_properties(bthread PROPERTIES IMPORTED_LOCATION ${bthread_l})
include_directories(${Boost_INCLUDE_DIRS})
+if (Enable_GUI)
if(SLIC3R_STATIC)
set(wxWidgets_USE_STATIC ON)
else(SLIC3R_STATIC)
set(wxWidgets_USE_STATIC OFF)
endif(SLIC3R_STATIC)
+endif()
+if (Enable_GUI)
+find_package(OpenGL)
set(wxWidgets_USE_UNICODE ON)
-
find_package(wxWidgets COMPONENTS net gl html aui adv core base)
+endif()
IF(CMAKE_HOST_UNIX)
#set(Boost_LIBRARIES bsystem bthread bfilesystem)
@@ -379,6 +404,7 @@ set(LIBSLIC3R_DEPENDS
polypartition
poly2tri
ZipArchive
+ miniz
${Boost_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
)
@@ -496,15 +522,17 @@ endif()
# Windows needs a compiled component for Boost.nowide
IF (WIN32)
- add_library(boost-nowide STATIC
- ${LIBDIR}/boost/nowide/iostream.cpp
- )
- if(MSVC)
- # Tell boost pragmas to not rename nowide as we are building it
- add_definitions(-DBOOST_NOWIDE_NO_LIB)
- endif()
- target_link_libraries(slic3r boost-nowide)
- target_include_directories(boost-nowide PUBLIC ${COMMON_INCLUDES})
+ if (NOT BOOST_NOWIDE_FOUND)
+ add_library(boost-nowide STATIC
+ ${LIBDIR}/boost/nowide/iostream.cpp
+ )
+ if(MSVC)
+ # Tell boost pragmas to not rename nowide as we are building it
+ add_definitions(-DBOOST_NOWIDE_NO_LIB)
+ endif()
+ target_link_libraries(slic3r boost-nowide)
+ target_include_directories(boost-nowide PUBLIC ${COMMON_INCLUDES})
+ endif()
# MinGW apparently has some multiple definitions of UUID-related items
# deal with it.
diff --git a/src/GUI/ColorScheme/Default.hpp b/src/GUI/ColorScheme/Default.hpp
index 2adb8cc613..2b676c760b 100644
--- a/src/GUI/ColorScheme/Default.hpp
+++ b/src/GUI/ColorScheme/Default.hpp
@@ -9,8 +9,8 @@ class DefaultColor : public ColorScheme {
const bool SOLID_BACKGROUNDCOLOR() const { return false; };
const wxColour SELECTED_COLOR() const { return wxColour(0, 255, 0); };
const wxColour HOVER_COLOR() const { return wxColour(255*0.4, 255*0.9, 0); }; //"
<< ""
<< "Copyright © 2011-2017 Alessandro Ranellucci. "
- << "Slic3r is licensed under the "
- << "GNU Affero General Public License, version 3 ."
+ << "Slic3r is licensed under the "
+ << "GNU Affero General Public License, version 3 ."
<< " "
<< "Contributions by Henrik Brix Andersen, Vojtech Bubnik, Nicolas Dandrimont, Mark Hindess, "
<< "Petr Ledvina, Joseph Lenox, Y. Sapir, Mike Sheldrake, Kliment Yanev and numerous others. "
diff --git a/src/GUI/GUI.cpp b/src/GUI/GUI.cpp
index ac8b11aca1..7cb5b922f6 100644
--- a/src/GUI/GUI.cpp
+++ b/src/GUI/GUI.cpp
@@ -124,7 +124,7 @@ bool App::OnInit()
if ($response =~ /^obsolete ?= ?([a-z0-9.-]+,)*\Q$Slic3r::VERSION\E(?:,|$)/) {
my $res = Wx::MessageDialog->new(undef, "A new version is available. Do you want to open the Slic3r website now?",
'Update', wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_INFORMATION | wxICON_ERROR)->ShowModal;
- Wx::LaunchDefaultBrowser('http://slic3r.org/') if $res == wxID_YES;
+ Wx::LaunchDefaultBrowser('https://slic3r.org/') if $res == wxID_YES;
} else {
Slic3r::GUI::show_info(undef, "You're using the latest version. No updates are available.") if $manual_check;
}
diff --git a/src/GUI/MainFrame.cpp b/src/GUI/MainFrame.cpp
index 541a8dc14c..0f2c20bd12 100644
--- a/src/GUI/MainFrame.cpp
+++ b/src/GUI/MainFrame.cpp
@@ -25,7 +25,7 @@ MainFrame::MainFrame(const wxString& title, const wxPoint& pos, const wxSize& si
// initialize status bar
this->statusbar = new ProgressStatusBar(this, -1);
- wxString welcome_text {_("Version SLIC3R_VERSION_REPLACE - Remember to check for updates at http://slic3r.org/")};
+ wxString welcome_text {_("Version SLIC3R_VERSION_REPLACE - Remember to check for updates at https://slic3r.org/")};
welcome_text.Replace("SLIC3R_VERSION_REPLACE", wxString(SLIC3R_VERSION));
this->statusbar->SetStatusText(welcome_text);
this->SetStatusBar(this->statusbar);
diff --git a/src/GUI/MainFrame.hpp b/src/GUI/MainFrame.hpp
index d062c9c14f..75a3dd9633 100644
--- a/src/GUI/MainFrame.hpp
+++ b/src/GUI/MainFrame.hpp
@@ -39,7 +39,7 @@ class MainFrame: public wxFrame
private:
wxDECLARE_EVENT_TABLE();
- void init_menubar(); //< Routine to intialize all top-level menu items.
+ void init_menubar(); //< Routine to initialize all top-level menu items.
void init_tabpanel(); //< Routine to initialize all of the tabs.
bool loaded; //< Main frame itself has finished loading.
diff --git a/src/GUI/OptionsGroup.hpp b/src/GUI/OptionsGroup.hpp
index 56bc3dadf1..4568226b15 100644
--- a/src/GUI/OptionsGroup.hpp
+++ b/src/GUI/OptionsGroup.hpp
@@ -32,7 +32,7 @@ class Option {
/// Destructor to take care of the owned default value.
~Option() {
- if (_default != nullptr) delete _default;
+ delete _default;
_default = nullptr;
}
diff --git a/src/GUI/Plater/Plate2D.cpp b/src/GUI/Plater/Plate2D.cpp
index 2aa46d200c..df6fa9080a 100644
--- a/src/GUI/Plater/Plate2D.cpp
+++ b/src/GUI/Plater/Plate2D.cpp
@@ -262,7 +262,7 @@ void Plate2D::mouse_up(wxMouseEvent& e) {
try {
if (this->drag_object.obj != -1 && this->drag_object.inst != -1) this->on_instances_moved();
} catch (std::bad_function_call &ex) {
- Slic3r::Log::error(LogChannel, L"On_instances_moved was not intialized to a function.");
+ Slic3r::Log::error(LogChannel, L"On_instances_moved was not initialized to a function.");
}
this->drag_start_pos = wxPoint(-1, -1);
this->drag_object = {-1, -1};
diff --git a/src/GUI/Plater/Plate3D.hpp b/src/GUI/Plater/Plate3D.hpp
index 605ce9d65d..d1c7784105 100644
--- a/src/GUI/Plater/Plate3D.hpp
+++ b/src/GUI/Plater/Plate3D.hpp
@@ -28,7 +28,7 @@ class Plate3D : public Scene3D {
void selection_changed(){Refresh();}
protected:
// Render each volume as a different color and check what color is beneath
- // the mouse to detemine the hovered volume
+ // the mouse to determine the hovered volume
void before_render();
// Mouse events are needed to handle selecting and moving objects
diff --git a/src/GUI/Plater/PlaterObject.cpp b/src/GUI/Plater/PlaterObject.cpp
index e0d9f598ab..8718c3b456 100644
--- a/src/GUI/Plater/PlaterObject.cpp
+++ b/src/GUI/Plater/PlaterObject.cpp
@@ -17,9 +17,7 @@ Slic3r::ExPolygonCollection& PlaterObject::make_thumbnail(std::shared_ptrobjects[obj_idx]->instances[0]};
// Apply any x/y rotations and scaling vector if this came from a 3MF object.
- mesh.rotate_x(model_instance->x_rotation);
- mesh.rotate_y(model_instance->y_rotation);
- mesh.scale(model_instance->scaling_vector);
+ mesh.transform(model_instance->additional_trafo);
if (mesh.facets_count() <= 5000) {
auto area_threshold {scale_(1.0)};
diff --git a/src/GUI/Plater/Preview3D.cpp b/src/GUI/Plater/Preview3D.cpp
index 2d794089c3..b4c15142f9 100644
--- a/src/GUI/Plater/Preview3D.cpp
+++ b/src/GUI/Plater/Preview3D.cpp
@@ -96,7 +96,7 @@ void Preview3D::load_print() {
std::sort(layers_z.begin(),layers_z.end());
slider->SetRange(0, layers_z.size()-1);
z_idx = slider->GetValue();
- // If invalide z_idx, move the slider to the top
+ // If invalid z_idx, move the slider to the top
if (z_idx >= layers_z.size() || slider->GetValue() == 0) {
slider->SetValue(layers_z.size()-1);
//$z_idx = @{$self->{layer_z}} ? -1 : undef;
diff --git a/src/GUI/Preset.hpp b/src/GUI/Preset.hpp
index 086fc58b89..cf10095fe5 100644
--- a/src/GUI/Preset.hpp
+++ b/src/GUI/Preset.hpp
@@ -106,7 +106,7 @@ class Preset {
private:
/// store to keep config options for this preset
- /// This is intented to be a "pristine" copy from the underlying
+ /// This is intended to be a "pristine" copy from the underlying
/// file store.
config_ptr _config { nullptr };
diff --git a/src/slic3r.cpp b/src/slic3r.cpp
index 8b30c2f098..8ed723f367 100644
--- a/src/slic3r.cpp
+++ b/src/slic3r.cpp
@@ -1,4 +1,5 @@
#include "slic3r.hpp"
+#include "GCodeSender.hpp"
#include "Geometry.hpp"
#include "IO.hpp"
#include "Log.hpp"
@@ -19,6 +20,8 @@
#include
#include
#include
+#include
+#include
#ifdef USE_WX
#include "GUI/GUI.hpp"
@@ -34,6 +37,9 @@ main(int argc, char **argv) {
#endif // BUILD_TEST
int CLI::run(int argc, char **argv) {
+ #ifdef SLIC3R_DEBUG
+ slic3r_log->set_level(log_t::DEBUG);
+ #endif
// Convert arguments to UTF-8 (needed on Windows).
// argv then points to memory owned by a.
boost::nowide::args a(argc, argv);
@@ -334,6 +340,7 @@ int CLI::run(int argc, char **argv) {
exit(EXIT_FAILURE);
}
Slic3r::Log::info("CLI") << "G-code exported to " << outfile << std::endl;
+ this->last_outfile = outfile;
// output some statistics
double duration { std::chrono::duration_cast(clock_::now() - t0).count() };
@@ -345,6 +352,49 @@ int CLI::run(int argc, char **argv) {
<< "Filament required: " << print.total_used_filament() << "mm"
<< " (" << print.total_extruded_volume()/1000 << "cm3)" << std::endl;
}
+ } else if (opt_key == "print") {
+ if (this->models.size() > 1) {
+ Slic3r::Log::error("CLI") << "error: --print is not supported for multiple jobs" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+
+ // Get last sliced G-code or the manually supplied one
+ std::string gcode_file{ this->config.getString("gcode_file", "") };
+ if (gcode_file.empty())
+ gcode_file = this->last_outfile;
+
+ if (gcode_file.empty()) {
+ Slic3r::Log::error("CLI") << "error: no G-code file to send; supply a model to slice or --gcode-file" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+
+ // Check serial port options
+ if (!this->print_config.has("serial_port") || !this->print_config.has("serial_speed")) {
+ Slic3r::Log::error("CLI") << "error: missing required --serial-port and --serial-speed" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+
+ // Connect to printer
+ Slic3r::GCodeSender sender;
+ sender.connect(
+ this->print_config.getString("serial_port"),
+ this->print_config.getInt("serial_speed")
+ );
+ while (!sender.is_connected()) {}
+ boost::nowide::cout << "Connected to printer" << std::endl;
+
+ // Send file line-by-line
+ std::ifstream infile(gcode_file);
+ std::string line;
+ while (std::getline(infile, line)) {
+ sender.send(line);
+ }
+
+ // Print queue size
+ while (sender.queue_size() > 0) {
+ boost::nowide::cout << "Queue size: " << sender.queue_size() << std::endl;
+ }
+ boost::nowide::cout << "Print completed!" << std::endl;
} else {
Slic3r::Log::error("CLI") << "error: option not supported yet: " << opt_key << std::endl;
exit(EXIT_FAILURE);
diff --git a/src/slic3r.hpp b/src/slic3r.hpp
index e4ba4a4983..68707ecb30 100644
--- a/src/slic3r.hpp
+++ b/src/slic3r.hpp
@@ -20,7 +20,8 @@ class CLI {
FullPrintConfig full_print_config;
t_config_option_keys input_files, actions, transforms;
std::vector models;
-
+ std::string last_outfile;
+
/// Prints usage of the CLI.
void print_help(bool include_print_options = false) const;
diff --git a/src/test/inputs/test_amf/20mmbox.amf b/src/test/inputs/test_amf/20mmbox.amf
new file mode 100644
index 0000000000..c945a45cdd
--- /dev/null
+++ b/src/test/inputs/test_amf/20mmbox.amf
@@ -0,0 +1,138 @@
+
+
+ Slic3r 1.3.1-dev
+
+ 20mmbox.stl
+
+
+
+
+ 10
+ 10
+ 0
+
+
+
+
+ -10
+ -10
+ 0
+
+
+
+
+ -10
+ 10
+ 0
+
+
+
+
+ 10
+ -10
+ 0
+
+
+
+
+ 10
+ -10
+ 10
+
+
+
+
+ -10
+ 10
+ 10
+
+
+
+
+ -10
+ -10
+ 10
+
+
+
+
+ 10
+ 10
+ 10
+
+
+
+
+ 20mmbox.stl
+
+ 0
+ 1
+ 2
+
+
+ 1
+ 0
+ 3
+
+
+ 4
+ 5
+ 6
+
+
+ 5
+ 4
+ 7
+
+
+ 0
+ 4
+ 3
+
+
+ 4
+ 0
+ 7
+
+
+ 4
+ 1
+ 3
+
+
+ 1
+ 4
+ 6
+
+
+ 5
+ 1
+ 6
+
+
+ 1
+ 5
+ 2
+
+
+ 5
+ 0
+ 2
+
+
+ 0
+ 5
+ 7
+
+
+
+
+
+
+ 67.5
+ 35
+ 0
+ 1
+
+
+
diff --git a/src/test/inputs/test_amf/20mmbox_deflated-in_directories.amf b/src/test/inputs/test_amf/20mmbox_deflated-in_directories.amf
new file mode 100644
index 0000000000..4f8a63607c
Binary files /dev/null and b/src/test/inputs/test_amf/20mmbox_deflated-in_directories.amf differ
diff --git a/src/test/inputs/test_amf/20mmbox_deflated-mult_files.amf b/src/test/inputs/test_amf/20mmbox_deflated-mult_files.amf
new file mode 100644
index 0000000000..f334baf9de
Binary files /dev/null and b/src/test/inputs/test_amf/20mmbox_deflated-mult_files.amf differ
diff --git a/src/test/inputs/test_amf/20mmbox_deflated.amf b/src/test/inputs/test_amf/20mmbox_deflated.amf
new file mode 100644
index 0000000000..f0293fcd1f
Binary files /dev/null and b/src/test/inputs/test_amf/20mmbox_deflated.amf differ
diff --git a/src/test/inputs/test_amf/5061-malicious.amf b/src/test/inputs/test_amf/5061-malicious.amf
new file mode 100644
index 0000000000..ce814e321b
--- /dev/null
+++ b/src/test/inputs/test_amf/5061-malicious.amf
@@ -0,0 +1,20 @@
+
+
+ Split Pyramid
+ John Smith
+
+
+
+ 2 0 0
+ 2.5 0.5 0
+
+
+ Hard side
+ 9999992 1 2
+ 0 0 2
+
+
+
+
+
+
diff --git a/src/test/inputs/test_amf/read-amf.amf b/src/test/inputs/test_amf/read-amf.amf
new file mode 100644
index 0000000000..f366b2be47
--- /dev/null
+++ b/src/test/inputs/test_amf/read-amf.amf
@@ -0,0 +1,19 @@
+
+
+ Split Pyramid
+ John Smith
+
+
+
+ 2 0 0
+ 2.5 0.5 0
+ 3.5 2.5 0
+
+
+ Hard side
+ 2 1 2
+ 0 0 2
+
+
+
+
diff --git a/src/test/libslic3r/test_amf.cpp b/src/test/libslic3r/test_amf.cpp
new file mode 100644
index 0000000000..6d137db4f3
--- /dev/null
+++ b/src/test/libslic3r/test_amf.cpp
@@ -0,0 +1,85 @@
+#include
+#include
+#include "Model.hpp"
+#include "IO.hpp"
+
+
+using namespace Slic3r;
+using namespace std::literals::string_literals;
+
+SCENARIO("Reading deflated AMF files", "[AMF]") {
+ GIVEN("Compressed AMF file of a 20mm cube") {
+ auto model {new Slic3r::Model()};
+ WHEN("file is read") {
+ bool result_code = Slic3r::IO::AMF::read(testfile("test_amf/20mmbox_deflated.amf"), model);;
+ THEN("Does not return false.") {
+ REQUIRE(result_code == true);
+ }
+ THEN("Model object contains a single ModelObject.") {
+ REQUIRE(model->objects.size() == 1);
+ }
+ }
+ WHEN("single file is read with some subdirectories") {
+ bool result_code = Slic3r::IO::AMF::read(testfile("test_amf/20mmbox_deflated-in_directories.amf"), model);;
+ THEN("Read returns false.") {
+ REQUIRE(result_code == true);
+ }
+ THEN("Model object contains no ModelObjects.") {
+ REQUIRE(model->objects.size() == 1);
+ }
+ }
+ WHEN("file is read with multiple files in the archive") {
+ bool result_code = Slic3r::IO::AMF::read(testfile("test_amf/20mmbox_deflated-mult_files.amf"), model);;
+ THEN("Read returns true.") {
+ REQUIRE(result_code == true);
+ }
+ THEN("Model object contains one ModelObject.") {
+ REQUIRE(model->objects.size() == 1);
+ }
+ }
+ delete model;
+ }
+ GIVEN("Uncompressed AMF file of a 20mm cube") {
+ auto model {new Slic3r::Model()};
+ WHEN("file is read") {
+ bool result_code = Slic3r::IO::AMF::read(testfile("test_amf/20mmbox.amf"), model);;
+ THEN("Does not return false.") {
+ REQUIRE(result_code == true);
+ }
+ THEN("Model object contains a single ModelObject.") {
+ REQUIRE(model->objects.size() == 1);
+ }
+ }
+ WHEN("nonexistant file is read") {
+ bool result_code = Slic3r::IO::AMF::read(testfile("test_amf/20mmbox-doesnotexist.amf"), model);;
+ THEN("Read returns false.") {
+ REQUIRE(result_code == false);
+ }
+ THEN("Model object contains no ModelObject.") {
+ REQUIRE(model->objects.size() == 0);
+ }
+ }
+ delete model;
+ }
+}
+
+SCENARIO("Reading AMF file", "[AMF]") {
+ GIVEN("badly formed AMF file (missing vertices)") {
+ auto model {new Slic3r::Model()};
+ WHEN("AMF model is read") {
+ auto ret = Slic3r::IO::AMF::read(testfile("test_amf/5061-malicious.amf"),model);
+ THEN("read should return True") {
+ REQUIRE(ret);
+ }
+ }
+ }
+ GIVEN("Ok formed AMF file") {
+ auto model {new Slic3r::Model()};
+ WHEN("AMF model is read") {
+ auto ret = Slic3r::IO::AMF::read(testfile("test_amf/read-amf.amf"),model);
+ THEN("read should return True") {
+ REQUIRE(ret);
+ }
+ }
+ }
+}
diff --git a/src/test/libslic3r/test_config.cpp b/src/test/libslic3r/test_config.cpp
index bc00714996..e6a71669e9 100644
--- a/src/test/libslic3r/test_config.cpp
+++ b/src/test/libslic3r/test_config.cpp
@@ -104,7 +104,7 @@ SCENARIO("Config accessor functions perform as expected.") {
}
}
WHEN("A numeric option is set to a non-numeric value.") {
- THEN("A BadOptionTypeException exception is thown.") {
+ THEN("A BadOptionTypeException exception is thrown.") {
REQUIRE_THROWS_AS(config->set("perimeter_speed", "zzzz"), BadOptionTypeException);
}
THEN("The value does not change.") {
diff --git a/src/test/libslic3r/test_gcode.cpp b/src/test/libslic3r/test_gcode.cpp
index f045f72a27..a72c45f952 100644
--- a/src/test/libslic3r/test_gcode.cpp
+++ b/src/test/libslic3r/test_gcode.cpp
@@ -1,4 +1,11 @@
#include
+#include
+#include "test_data.hpp"
+#include "GCodeReader.hpp"
+#include "GCode.hpp"
+
+using namespace Slic3r::Test;
+using namespace Slic3r;
#include "GCode/CoolingBuffer.hpp"
@@ -13,3 +20,50 @@ SCENARIO("Cooling buffer speed factor rewrite enforces precision") {
}
}
}
+
+SCENARIO( "Test of COG calculation") {
+ GIVEN("A default configuration and a print test object") {
+ auto config {Slic3r::Config::new_from_defaults()};
+ auto gcode {std::stringstream("")};
+
+ WHEN("the output is executed with no support material") {
+ Slic3r::Model model;
+ auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
+ print->process();
+ Slic3r::Test::gcode(gcode, print);
+ auto exported {gcode.str()};
+
+ THEN("Some text output is generated.") {
+ REQUIRE(exported.size() > 0);
+ }
+
+ THEN("COG values are contained in output") {
+ REQUIRE(exported.find("; cog_x") != std::string::npos);
+ REQUIRE(exported.find("; cog_y") != std::string::npos);
+ REQUIRE(exported.find("; cog_z") != std::string::npos);
+ }
+
+ THEN("Check if COG values are correct") {
+
+ int cog_x_start = exported.find("; cog_x = ");
+ int cog_x_len = exported.substr(cog_x_start).find('\n');
+ int cog_y_start = exported.find("; cog_y = ");
+ int cog_y_len = exported.substr(cog_y_start).find('\n');
+ int cog_z_start = exported.find("; cog_z = ");
+ int cog_z_len = exported.substr(cog_z_start).find('\n');
+
+ float val_x, val_y, val_z;
+ // crop cog_x text
+ val_x = std::stof(exported.substr(cog_x_start + 10, cog_x_len - 10));
+ val_y = std::stof(exported.substr(cog_y_start + 10, cog_y_len - 10));
+ val_z = std::stof(exported.substr(cog_z_start + 10, cog_z_len - 10));
+
+ REQUIRE(abs(val_x-100.0) <= 0.5);
+ REQUIRE(abs(val_y-100.0) <= 0.5);
+ REQUIRE(abs(val_z-10.0) <= 0.5);
+ }
+ }
+
+ gcode.clear();
+ }
+}
diff --git a/src/test/libslic3r/test_geometry.cpp b/src/test/libslic3r/test_geometry.cpp
index a65e853135..41c0bfc797 100644
--- a/src/test/libslic3r/test_geometry.cpp
+++ b/src/test/libslic3r/test_geometry.cpp
@@ -154,7 +154,7 @@ TEST_CASE("Bounding boxes are scaled appropriately"){
}
-TEST_CASE("Offseting a line generates a polygon correctly"){
+TEST_CASE("Offsetting a line generates a polygon correctly"){
auto line = Line(Point(10,10), Point(20,10));
Polyline tmp(line);
Polygon area = offset(tmp,5).at(0);
diff --git a/src/test/libslic3r/test_printgcode.cpp b/src/test/libslic3r/test_printgcode.cpp
index 67577875be..a6863580a7 100644
--- a/src/test/libslic3r/test_printgcode.cpp
+++ b/src/test/libslic3r/test_printgcode.cpp
@@ -207,8 +207,6 @@ SCENARIO( "PrintGCode basic functionality") {
REQUIRE(exported.find("M107") != std::string::npos);
}
}
-
-
WHEN("end_gcode exists with layer_num and layer_z") {
config->set("end_gcode", "; Layer_num [layer_num]\n; Layer_z [layer_z]");
config->set("layer_height", 0.1);
@@ -224,6 +222,50 @@ SCENARIO( "PrintGCode basic functionality") {
REQUIRE(exported.find("; Layer_z 20") != std::string::npos);
}
}
+ WHEN("current_extruder exists in start_gcode") {
+ config->set("start_gcode", "; Extruder [current_extruder]");
+ {
+ Slic3r::Model model;
+ auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
+ Slic3r::Test::gcode(gcode, print);
+ auto exported {gcode.str()};
+ THEN("current_extruder is processed in the start gcode and set for first extruder") {
+ REQUIRE(exported.find("; Extruder 0") != std::string::npos);
+ }
+ }
+ config->set("solid_infill_extruder", 2);
+ config->set("support_material_extruder", 2);
+ config->set("infill_extruder", 2);
+ config->set("perimeter_extruder", 2);
+ {
+ Slic3r::Model model;
+ auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
+ Slic3r::Test::gcode(gcode, print);
+ auto exported {gcode.str()};
+ THEN("current_extruder is processed in the start gcode and set for second extruder") {
+ REQUIRE(exported.find("; Extruder 1") != std::string::npos);
+ }
+ }
+ }
+
+ WHEN("layer_num represents the layer's index from z=0") {
+ config->set("layer_gcode", ";Layer:[layer_num] ([layer_z] mm)");
+ config->set("layer_height", 1.0);
+ config->set("first_layer_height", 1.0);
+
+ Slic3r::Model model;
+ auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20,TestMesh::cube_20x20x20}, model, config)};
+ Slic3r::Test::gcode(gcode, print);
+
+ auto exported {gcode.str()};
+ int count = 2;
+ for(int pos = 0; pos != std::string::npos; count--)
+ pos = exported.find(";Layer:38 (20 mm)", pos+1);
+
+ THEN("layer_num and layer_z are processed in the end gcode") {\
+ REQUIRE(count == -1);
+ }
+ }
gcode.clear();
}
diff --git a/src/test/libslic3r/test_printobject.cpp b/src/test/libslic3r/test_printobject.cpp
index 52046f81e9..96557332fe 100644
--- a/src/test/libslic3r/test_printobject.cpp
+++ b/src/test/libslic3r/test_printobject.cpp
@@ -1,6 +1,7 @@
#include
#include
#include "test_data.hpp"
+#include "Log.hpp"
#include "libslic3r.h"
using namespace Slic3r::Test;
@@ -77,3 +78,101 @@ SCENARIO("PrintObject: object layer heights") {
}
}
+
+SCENARIO("PrintObject: minimum horizontal shells") {
+ GIVEN("20mm cube and default initial config, initial layer height of 0.1mm") {
+ auto config {Slic3r::Config::new_from_defaults()};
+ TestMesh m { TestMesh::cube_20x20x20 };
+ Slic3r::Model model;
+
+ config->set("nozzle_diameter", "3");
+ config->set("bottom_solid_layers", 1);
+ config->set("perimeters", 1);
+ config->set("first_layer_height", 0.1);
+ config->set("layer_height", 0.1);
+ config->set("fill_density", "0%");
+ config->set("min_top_bottom_shell_thickness", 1.0);
+
+ WHEN("min shell thickness is 1.0 with layer height of 0.1") {
+ config->set("min_top_bottom_shell_thickness", 1.0);
+ auto print {Slic3r::Test::init_print({m}, model, config)};
+ slic3r_log->set_level(log_t::DEBUG);
+ print->objects[0]->prepare_infill();
+ for (int i = 0; i < 12; i++)
+ print->objects[0]->layers[i]->make_fills();
+ THEN("Layers 0-9 are solid (Z < 1.0) (all fill_surfaces are solid)") {
+ for (int i = 0; i < 10; i++) {
+ CHECK(print->objects[0]->layers[i]->print_z <= (i+1 * 0.1));
+ for (auto* r : print->objects[0]->layers[i]->regions) {
+ for (auto s : r->fill_surfaces) {
+ REQUIRE(s.is_solid());
+ }
+ }
+ }
+ }
+ AND_THEN("Layer 10 (Z > 1.0) is not solid.") {
+ for (auto* r : print->objects[0]->layers[10]->regions) {
+ bool all_solid = true;
+ for (auto s : r->fill_surfaces) {
+ REQUIRE(!s.is_solid());
+ }
+ }
+ }
+ }
+ WHEN("min shell thickness is 1.22 with layer height of 0.1") {
+ config->set("min_top_bottom_shell_thickness", 1.22);
+ config->set("layer_height", 0.1);
+ auto print {Slic3r::Test::init_print({m}, model, config)};
+ slic3r_log->set_level(log_t::DEBUG);
+ print->objects[0]->prepare_infill();
+ for (int i = 0; i < 20; i++)
+ print->objects[0]->layers[i]->make_fills();
+ AND_THEN("Layers 0-12 are solid (bottom of layer >= 1.22) (all fill_surfaces are solid)") {
+ for (int i = 0; i < 13; i++) {
+ CHECK(print->objects[0]->layers[i]->print_z <= (i+1 * 0.1));
+ for (auto* r : print->objects[0]->layers[i]->regions) {
+ for (auto s : r->fill_surfaces) {
+ REQUIRE(s.is_solid());
+ }
+ }
+ }
+ }
+ AND_THEN("Layer 13 (Z > 1.0) is not solid.") {
+ for (auto* r : print->objects[0]->layers[13]->regions) {
+ bool all_solid = true;
+ for (auto s : r->fill_surfaces) {
+ REQUIRE(!s.is_solid());
+ }
+ }
+ }
+ }
+ WHEN("min shell thickness is 1.22 14 bottom layers") {
+ config->set("min_top_bottom_shell_thickness", 1.22);
+ config->set("bottom_solid_layers", 14);
+ config->set("layer_height", 0.1);
+ auto print {Slic3r::Test::init_print({m}, model, config)};
+ slic3r_log->set_level(log_t::DEBUG);
+ print->objects[0]->prepare_infill();
+ for (int i = 0; i < 20; i++)
+ print->objects[0]->layers[i]->make_fills();
+ AND_THEN("Layers 0-13 are solid (bottom of layer >= 1.22) (all fill_surfaces are solid)") {
+ for (int i = 0; i < 14; i++) {
+ CHECK(print->objects[0]->layers[i]->print_z <= (i+1 * 0.1));
+ for (auto* r : print->objects[0]->layers[i]->regions) {
+ for (auto s : r->fill_surfaces) {
+ REQUIRE(s.is_solid());
+ }
+ }
+ }
+ }
+ AND_THEN("Layer 14 is not solid.") {
+ for (auto* r : print->objects[0]->layers[14]->regions) {
+ bool all_solid = true;
+ for (auto s : r->fill_surfaces) {
+ REQUIRE(!s.is_solid());
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/libslic3r/test_transformationmatrix.cpp b/src/test/libslic3r/test_transformationmatrix.cpp
new file mode 100644
index 0000000000..953a66dba5
--- /dev/null
+++ b/src/test/libslic3r/test_transformationmatrix.cpp
@@ -0,0 +1,217 @@
+#include
+
+#include
+
+#include "libslic3r.h"
+#include "TransformationMatrix.hpp"
+
+using namespace Slic3r;
+
+constexpr auto THRESHOLD_EQUALITY = 1.0e-3;
+
+bool check_elements(TransformationMatrix const & matrix,
+ double m00, double m01, double m02, double m03,
+ double m10, double m11, double m12, double m13,
+ double m20, double m21, double m22, double m23);
+bool check_point(const Pointf3 & point, coordf_t x, coordf_t y, coordf_t z);
+double degtorad(double value){ return PI / 180.0 * value; }
+
+SCENARIO("TransformationMatrix: constructors, copytor, comparing, basic operations"){
+ GIVEN("a default constructed Matrix") {
+ auto trafo_default = TransformationMatrix();
+ THEN("comparing to the eye matrix") {
+ REQUIRE(check_elements(trafo_default,
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0));
+ }
+
+ WHEN("copied") {
+ auto trafo_eq_assigned = trafo_default;
+ THEN("comparing the second to the eye matrix") {
+ REQUIRE(check_elements(trafo_eq_assigned,
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0));
+ }
+ THEN("comparing them to each other")
+ {
+ REQUIRE(trafo_default == trafo_eq_assigned);
+ REQUIRE(!(trafo_default != trafo_eq_assigned));
+ }
+ trafo_eq_assigned.m00 = 2.0;
+ THEN("testing uniqueness") {
+ REQUIRE(trafo_default != trafo_eq_assigned);
+ }
+ }
+ }
+ GIVEN("a directly set matrix") {
+ THEN("set via constructor") {
+ auto trafo_set = TransformationMatrix(1,2,3,4,5,6,7,8,9,10,11,12);
+ REQUIRE(check_elements(trafo_set,
+ 1,2,3,4,
+ 5,6,7,8,
+ 9,10,11,12));
+ }
+ THEN("set via vector") {
+ std::vector elements;
+ elements.reserve(12);
+ elements.push_back(1);
+ elements.push_back(2);
+ elements.push_back(3);
+ elements.push_back(4);
+ elements.push_back(5);
+ elements.push_back(6);
+ elements.push_back(7);
+ elements.push_back(8);
+ elements.push_back(9);
+ elements.push_back(10);
+ elements.push_back(11);
+ elements.push_back(12);
+ auto trafo_vec = TransformationMatrix(elements);
+ REQUIRE(check_elements(trafo_vec,
+ 1,2,3,4,
+ 5,6,7,8,
+ 9,10,11,12));
+ }
+ }
+ GIVEN("two separate matrices") {
+ auto mat1 = TransformationMatrix(1,2,3,4,5,6,7,8,9,10,11,12);
+ auto mat2 = TransformationMatrix(1,4,7,10,2,5,8,11,3,6,9,12);
+ THEN("static multiplication") {
+ auto mat3 = TransformationMatrix::multiply(mat1, mat2);
+ REQUIRE(check_elements(mat3,14,32,50,72,38,92,146,208,62,152,242,344));
+ mat3 = TransformationMatrix::multiply(mat2, mat1);
+ REQUIRE(check_elements(mat3,84,96,108,130,99,114,129,155,114,132,150,180));
+ }
+ THEN("direct multiplication") {
+ REQUIRE(check_elements(mat1.multiplyRight(mat2),14,32,50,72,38,92,146,208,62,152,242,344));
+ REQUIRE(check_elements(mat2.multiplyLeft(mat1),14,32,50,72,38,92,146,208,62,152,242,344));
+ }
+ }
+ GIVEN("a random transformation-ish matrix") {
+ auto mat = TransformationMatrix(
+ 0.9004,-0.2369,-0.4847,12.9383,
+ -0.9311,0.531,-0.5026,7.7931,
+ -0.1225,0.5904,0.2576,-7.316);
+ THEN("computing the determinante") {
+ REQUIRE(std::abs(mat.determinante() - 0.5539) < THRESHOLD_EQUALITY);
+ }
+ THEN("computing the inverse") {
+ REQUIRE(check_elements(mat.inverse(),
+ 0.78273016,-0.40649736,0.67967289,-1.98683622,
+ 0.54421957,0.31157368,1.63191055,2.46965668,
+ -0.87508846,-0.90741083,0.46498424,21.79552507));
+ }
+ }
+}
+
+SCENARIO("TransformationMatrix: application") {
+ GIVEN("two vectors to validate geometric transformations") {
+ auto vec1 = Pointf3(1,2,3);
+ auto vec2 = Pointf3(-4,3,-2);
+ THEN("testing general point transformation") {
+ auto mat = TransformationMatrix(1,2,3,4,5,6,7,8,9,10,11,12);
+ REQUIRE(check_point(mat.transform(vec1),18,46,74)); // default arg should be like a point
+ REQUIRE(check_point(mat.transform(vec1,1),18,46,74));
+ REQUIRE(check_point(mat.transform(vec1,0),14,38,62));
+ }
+ WHEN("testing scaling") {
+ THEN("testing universal scaling") {
+ auto mat = TransformationMatrix::mat_scale(3);
+ REQUIRE(check_point(mat.transform(vec1),3,6,9));
+ }
+ THEN("testing vector like scaling") {
+ auto mat = TransformationMatrix::mat_scale(2,3,4);
+ REQUIRE(check_point(mat.transform(vec1),2,6,12));
+ }
+ }
+ WHEN("testing mirroring") {
+ THEN("testing axis aligned mirroring") {
+ auto mat = TransformationMatrix::mat_mirror(Axis::X);
+ REQUIRE(check_point(mat.transform(vec1),-1,2,3));
+ mat = TransformationMatrix::mat_mirror(Axis::Y);
+ REQUIRE(check_point(mat.transform(vec1),1,-2,3));
+ mat = TransformationMatrix::mat_mirror(Axis::Z);
+ REQUIRE(check_point(mat.transform(vec1),1,2,-3));
+ }
+ THEN("testing arbituary axis mirroring") {
+ auto mat = TransformationMatrix::mat_mirror(vec2);
+ REQUIRE(check_point(mat.transform(vec1),-0.1034,2.8276,2.4483));
+ REQUIRE(std::abs(mat.determinante() + 1.0) < THRESHOLD_EQUALITY);
+ }
+ }
+ WHEN("testing translation") {
+ THEN("testing xyz translation") {
+ auto mat = TransformationMatrix::mat_translation(4,2,5);
+ REQUIRE(check_point(mat.transform(vec1),5,4,8));
+ }
+ THEN("testing vector-defined translation") {
+ auto mat = TransformationMatrix::mat_translation(vec2);
+ REQUIRE(check_point(mat.transform(vec1),-3,5,1));
+ }
+ }
+ WHEN("testing rotation") {
+ THEN("testing axis aligned rotation") {
+ auto mat = TransformationMatrix::mat_rotation(degtorad(90), Axis::X);
+ REQUIRE(check_point(mat.transform(vec1),1,-3,2));
+ mat = TransformationMatrix::mat_rotation(degtorad(90), Axis::Y);
+ REQUIRE(check_point(mat.transform(vec1),3,2,-1));
+ mat = TransformationMatrix::mat_rotation(degtorad(90), Axis::Z);
+ REQUIRE(check_point(mat.transform(vec1),-2,1,3));
+ }
+ THEN("testing arbituary axis rotation") {
+ auto mat = TransformationMatrix::mat_rotation(degtorad(80), vec2);
+ REQUIRE(check_point(mat.transform(vec1),3.0069,1.8341,-1.2627));
+ REQUIRE(std::abs(mat.determinante() - 1.0) < THRESHOLD_EQUALITY);
+ }
+ THEN("testing quaternion rotation") {
+ auto mat = TransformationMatrix::mat_rotation(-0.4775,0.3581,-0.2387,0.7660);
+ REQUIRE(check_point(mat.transform(vec1),3.0069,1.8341,-1.2627));
+ REQUIRE(std::abs(mat.determinante() - 1.0) < THRESHOLD_EQUALITY);
+ }
+ THEN("testing vector to vector") {
+ auto mat = TransformationMatrix::mat_rotation(vec1,vec2);
+ REQUIRE(check_point(mat.transform(vec1),-2.7792,2.0844,-1.3896));
+ REQUIRE(std::abs(mat.determinante() - 1.0) < THRESHOLD_EQUALITY);
+ mat = TransformationMatrix::mat_rotation(vec1,vec1.negative());
+ REQUIRE(check_point(mat.transform(vec1),-1,-2,-3)); // colinear, opposite direction
+ mat = TransformationMatrix::mat_rotation(vec1,vec1);
+ REQUIRE(check_elements(mat,
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0)); // colinear, same direction
+ }
+ }
+ }
+}
+
+bool check_elements(const TransformationMatrix & matrix,
+ double m00, double m01, double m02, double m03,
+ double m10, double m11, double m12, double m13,
+ double m20, double m21, double m22, double m23)
+{
+ bool equal = true;
+ equal &= std::abs(matrix.m00 - m00) < THRESHOLD_EQUALITY;
+ equal &= std::abs(matrix.m01 - m01) < THRESHOLD_EQUALITY;
+ equal &= std::abs(matrix.m02 - m02) < THRESHOLD_EQUALITY;
+ equal &= std::abs(matrix.m03 - m03) < THRESHOLD_EQUALITY;
+ equal &= std::abs(matrix.m10 - m10) < THRESHOLD_EQUALITY;
+ equal &= std::abs(matrix.m11 - m11) < THRESHOLD_EQUALITY;
+ equal &= std::abs(matrix.m12 - m12) < THRESHOLD_EQUALITY;
+ equal &= std::abs(matrix.m13 - m13) < THRESHOLD_EQUALITY;
+ equal &= std::abs(matrix.m20 - m20) < THRESHOLD_EQUALITY;
+ equal &= std::abs(matrix.m21 - m21) < THRESHOLD_EQUALITY;
+ equal &= std::abs(matrix.m22 - m22) < THRESHOLD_EQUALITY;
+ equal &= std::abs(matrix.m23 - m23) < THRESHOLD_EQUALITY;
+ return equal;
+}
+
+bool check_point(const Pointf3 & point, coordf_t x, coordf_t y, coordf_t z)
+{
+ bool equal = true;
+ equal &= std::abs(point.x - x) < THRESHOLD_EQUALITY;
+ equal &= std::abs(point.y - y) < THRESHOLD_EQUALITY;
+ equal &= std::abs(point.z - z) < THRESHOLD_EQUALITY;
+ return equal;
+}
diff --git a/src/test/test_data.hpp b/src/test/test_data.hpp
index 8de0b7e5cf..0ac92c2e24 100644
--- a/src/test/test_data.hpp
+++ b/src/test/test_data.hpp
@@ -36,7 +36,7 @@ enum class TestMesh {
two_hollow_squares
};
-// Neccessary for (tm);
diff --git a/utils/wireframe.pl b/utils/wireframe.pl
index f49b66e56b..6bd66433ca 100644
--- a/utils/wireframe.pl
+++ b/utils/wireframe.pl
@@ -42,7 +42,7 @@ BEGIN
$model->add_default_instances;
$model->center_instances_around_point(Slic3r::Pointf->new(100,100));
my $mesh = $model->mesh;
- $mesh->translate(0, 0, -$mesh->bounding_box->z_min);
+ $mesh->align_to_bed();
# get slices
my @z = ();
diff --git a/utils/zsh/functions/_slic3r b/utils/zsh/functions/_slic3r
index a78da948ad..80049fab40 100644
--- a/utils/zsh/functions/_slic3r
+++ b/utils/zsh/functions/_slic3r
@@ -72,7 +72,7 @@ _arguments -S \
\
'--retract-length[specify filament retraction length when pausing extrusion]:filament retraction length in mm' \
'--retract-speed[specify filament retraction speed]:filament retraction speed in mm/s' \
- '--retract-restart-extra[specify filament length to extrude for compensating retraction]: filament lenght in mm' \
+ '--retract-restart-extra[specify filament length to extrude for compensating retraction]: filament length in mm' \
'--retract-before-travel[specify minimum travel length for activating retraction]:minimum travel length for activating retraction in mm' \
'--retract-lift[specify Z-axis lift for use when retracting]:Z-axis lift in mm' \
\
diff --git a/xs/Build.PL b/xs/Build.PL
index 6ca31e3277..a4857c8cc8 100644
--- a/xs/Build.PL
+++ b/xs/Build.PL
@@ -15,21 +15,20 @@ my $linux = $^O eq 'linux';
# prevent an annoying concatenation warning by Devel::CheckLib
$ENV{LD_RUN_PATH} //= "";
-# _GLIBCXX_USE_C99 : to get the long long type for g++
# 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 -Dexprtk_disable_rtl_io_file -Dexprtk_disable_return_statement -Dexprtk_disable_rtl_vecops -Dexprtk_disable_string_capabilities -Dexprtk_disable_enhanced_features);
+my @cflags = qw(-DHAS_BOOL -DNOGDI -DSLIC3RXS -DBOOST_ASIO_DISABLE_KQUEUE -Dexprtk_disable_rtl_io_file -Dexprtk_disable_return_statement -Dexprtk_disable_rtl_vecops -Dexprtk_disable_string_capabilities -Dexprtk_disable_enhanced_features);
push @cflags, "-DSLIC3R_BUILD_COMMIT=$ENV{SLIC3R_GIT_VERSION}" if defined $ENV{SLIC3R_GIT_VERSION};
+# std=c++11 Enforce usage of C++11 (required now). Minimum compiler supported: gcc 4.9, clang 3.3, MSVC 14.0
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__);
+ # GCC is pedantic with c++11 std, so use -std=gnu++11 to be able to use M_PI
+ push @cflags, qw(-std=gnu++11);
+} else {
+ push @cflags, qw(-std=c++11);
}
-# std=c++11 Enforce usage of C++11 (required now). Minimum compiler supported: gcc 4.9, clang 3.3, MSVC 14.0
-push @cflags, qw(-std=c++11);
-
my @ldflags = ();
if ($linux && (defined $ENV{SLIC3R_STATIC} && $ENV{SLIC3R_STATIC})) {
@@ -152,18 +151,27 @@ if (defined $ENV{BOOST_LIBRARYPATH}) {
}
# In order to generate the -l switches we need to know how Boost libraries are named
my $have_boost = 0;
+my $have_boost_optional = 0;
my @boost_libraries = qw(system thread filesystem); # we need these
+my @boost_optional_libraries = qw(nowide); # we need these, but if they aren't present we can deal
# check without explicit lib path (works on Linux)
if (! $mswin) {
$have_boost = 1
if check_lib(
lib => [ map "boost_${_}", @boost_libraries ],
);
+ $have_boost_optional = 1
+ if check_lib(
+ lib => [ map "boost_${_}", @boost_optional_libraries ],
+ );
}
if (!$ENV{SLIC3R_STATIC} && $have_boost) {
# The boost library was detected by check_lib on Linux.
push @LIBS, map "-lboost_${_}", @boost_libraries;
+ if (!$ENV{SLIC3R_STATIC} && $have_boost_optional) {
+ push @LIBS, map "-lboost_${_}", @boost_optional_libraries;
+ }
} else {
# Either static linking, or check_lib could not be used to find the boost libraries.
my $lib_prefix = 'libboost_';
@@ -200,15 +208,14 @@ if (!$ENV{SLIC3R_STATIC} && $have_boost) {
}
}
}
-push @cflags, '-DBOOST_LIBS' if $have_boost;
die <<'EOF' if !$have_boost;
Slic3r requires the Boost libraries. Please make sure they are installed.
If they are installed, this script should be able to locate them in several
standard locations. If this is not the case, you might want to supply their
-path through the BOOST_INCLUDEPATH and BOOST_LIBRARYPATH environment variables:
+path through the BOOST_INCLUDEDIR and BOOST_LIBRARYPATH environment variables:
- BOOST_INCLUDEPATH=/usr/local/include BOOST_LIBRARYPATH=/usr/lib perl Build.PL
+ BOOST_INCLUDEDIR=/usr/local/include BOOST_LIBRARYPATH=/usr/lib perl Build.PL
If you just compiled Boost in its source directory without installing it in the
system you can just provide the BOOST_DIR variable pointing to that directory.
diff --git a/xs/MANIFEST b/xs/MANIFEST
index 4d20158719..a2b1940ab5 100644
--- a/xs/MANIFEST
+++ b/xs/MANIFEST
@@ -161,6 +161,8 @@ src/libslic3r/SurfaceCollection.cpp
src/libslic3r/SurfaceCollection.hpp
src/libslic3r/SVG.cpp
src/libslic3r/SVG.hpp
+src/libslic3r/TransformationMatrix.cpp
+src/libslic3r/TransformationMatrix.hpp
src/libslic3r/TriangleMesh.cpp
src/libslic3r/TriangleMesh.hpp
src/libslic3r/utils.cpp
@@ -258,6 +260,7 @@ xsp/SlicingAdaptive.xsp
xsp/SupportMaterial.xsp
xsp/Surface.xsp
xsp/SurfaceCollection.xsp
+xsp/TransformationMatrix.xsp
xsp/TriangleMesh.xsp
xsp/typemap.xspt
xsp/XS.xsp
diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm
index 7f269c1a80..ce54fa6792 100644
--- a/xs/lib/Slic3r/XS.pm
+++ b/xs/lib/Slic3r/XS.pm
@@ -263,6 +263,7 @@ for my $class (qw(
Slic3r::Surface
Slic3r::Surface::Collection
Slic3r::TriangleMesh
+ Slic3r::TransformationMatrix
))
{
no strict 'refs';
diff --git a/xs/src/BSpline/BSpline.h b/xs/src/BSpline/BSpline.h
index 9114385c13..88aba4dadd 100644
--- a/xs/src/BSpline/BSpline.h
+++ b/xs/src/BSpline/BSpline.h
@@ -138,7 +138,7 @@ template struct BSplineBaseP;
* own instantiation.
*
* The algorithm is based on the cubic spline described by Katsuyuki Ooyama
- * in Montly Weather Review, Vol 115, October 1987. This implementation
+ * in Monthly Weather Review, Vol 115, October 1987. This implementation
* has benefited from comparisons with a previous FORTRAN implementation by
* James L. Franklin, NOAA/Hurricane Research Division. In particular, the
* algorithm in the Setup() method is based mostly on his implementation
diff --git a/xs/src/Zip/ZipArchive.cpp b/xs/src/Zip/ZipArchive.cpp
index 532b2de611..bd2c9c98d0 100644
--- a/xs/src/Zip/ZipArchive.cpp
+++ b/xs/src/Zip/ZipArchive.cpp
@@ -1,4 +1,3 @@
-#include "miniz/miniz.h"
#include "Zip/ZipArchive.hpp"
namespace Slic3r {
diff --git a/xs/src/admesh/normals.c b/xs/src/admesh/normals.c
index 2832899fa9..843a25d16a 100644
--- a/xs/src/admesh/normals.c
+++ b/xs/src/admesh/normals.c
@@ -157,7 +157,7 @@ stl_fix_normal_directions(stl_file *stl) {
/* Get next facet to fix from top of list. */
if(head->next != tail) {
facet_num = head->next->facet_num;
- if(norm_sw[facet_num] != 1) { /* If facet is in list mutiple times */
+ if(norm_sw[facet_num] != 1) { /* If facet is in list multiple times */
norm_sw[facet_num] = 1; /* Record this one as being fixed. */
checked++;
}
diff --git a/xs/src/admesh/shared.c b/xs/src/admesh/shared.c
index 667aefc1eb..092d641006 100644
--- a/xs/src/admesh/shared.c
+++ b/xs/src/admesh/shared.c
@@ -29,14 +29,11 @@ void
stl_invalidate_shared_vertices(stl_file *stl) {
if (stl->error) return;
- if (stl->v_indices != NULL) {
- free(stl->v_indices);
- stl->v_indices = NULL;
- }
- if (stl->v_shared != NULL) {
- free(stl->v_shared);
- stl->v_shared = NULL;
- }
+ free(stl->v_indices);
+ stl->v_indices = NULL;
+
+ free(stl->v_shared);
+ stl->v_shared = NULL;
}
void
diff --git a/xs/src/admesh/stl.h b/xs/src/admesh/stl.h
index b31fdd4f9b..517930d496 100644
--- a/xs/src/admesh/stl.h
+++ b/xs/src/admesh/stl.h
@@ -201,7 +201,8 @@ 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_transform(stl_file *stl, double const *trafo3x4);
+extern void stl_get_transform(stl_file const *stl_src, stl_file *stl_dst, double const *trafo3x4);
extern void stl_open_merge(stl_file *stl, ADMESH_CHAR *file);
extern void stl_invalidate_shared_vertices(stl_file *stl);
extern void stl_generate_shared_vertices(stl_file *stl);
diff --git a/xs/src/admesh/stlinit.c b/xs/src/admesh/stlinit.c
index c15ee073ef..10f7cda2b5 100644
--- a/xs/src/admesh/stlinit.c
+++ b/xs/src/admesh/stlinit.c
@@ -211,7 +211,7 @@ stl_open_merge(stl_file *stl, ADMESH_CHAR *file_to_merge) {
/* Record the file pointer too: */
origFp=stl->fp;
- /* Initialize the sturucture with zero stats, header info and sizes: */
+ /* Initialize the structure with zero stats, header info and sizes: */
stl_initialize(&stl_to_merge);
stl_count_facets(&stl_to_merge, file_to_merge);
@@ -437,13 +437,9 @@ void
stl_close(stl_file *stl) {
if (stl->error) return;
- if(stl->neighbors_start != NULL)
- free(stl->neighbors_start);
- if(stl->facet_start != NULL)
- free(stl->facet_start);
- if(stl->v_indices != NULL)
- free(stl->v_indices);
- if(stl->v_shared != NULL)
- free(stl->v_shared);
+ free(stl->neighbors_start);
+ free(stl->facet_start);
+ free(stl->v_indices);
+ free(stl->v_shared);
}
diff --git a/xs/src/admesh/util.c b/xs/src/admesh/util.c
index a2e32c2f51..3f8f43ec58 100644
--- a/xs/src/admesh/util.c
+++ b/xs/src/admesh/util.c
@@ -185,7 +185,7 @@ void calculate_normals(stl_file *stl) {
}
}
-void stl_transform(stl_file *stl, float *trafo3x4) {
+void stl_transform(stl_file *stl, double const *trafo3x4) {
int i_face, i_vertex, i, j;
if (stl->error)
return;
@@ -193,16 +193,66 @@ void stl_transform(stl_file *stl, float *trafo3x4) {
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];
+ double v_src_x = (double)(v_dst->x);
+ double v_src_y = (double)(v_dst->y);
+ double v_src_z = (double)(v_dst->z);
+ v_dst->x = (float)(trafo3x4[0] * v_src_x + trafo3x4[1] * v_src_y + trafo3x4[2] * v_src_z + trafo3x4[3]);
+ v_dst->y = (float)(trafo3x4[4] * v_src_x + trafo3x4[5] * v_src_y + trafo3x4[6] * v_src_z + trafo3x4[7]);
+ v_dst->z = (float)(trafo3x4[8] * v_src_x + trafo3x4[9] * v_src_y + trafo3x4[10] * v_src_z + trafo3x4[11]);
}
}
+ double det = trafo3x4[0]*trafo3x4[5]*trafo3x4[10] + trafo3x4[4]*trafo3x4[9]*trafo3x4[2] + trafo3x4[8]*trafo3x4[1]*trafo3x4[6]
+ - trafo3x4[0]*trafo3x4[9]*trafo3x4[6] - trafo3x4[4]*trafo3x4[1]*trafo3x4[10] - trafo3x4[8]*trafo3x4[5]*trafo3x4[2];
+ if(det < 0)
+ stl_reverse_all_facets(stl);
stl_get_size(stl);
+ if(det - 1.0 > 1e-04)
+ stl_calculate_volume(stl);
calculate_normals(stl);
}
+void stl_get_transform(stl_file const *stl_src, stl_file *stl_dst, double const *trafo3x4) {
+ int i_face, i_vertex, i, j;
+ if (stl_src->error || stl_dst->error)
+ return;
+
+ if (stl_dst->stats.facets_malloced != stl_src->stats.number_of_facets)
+ {
+ stl_dst->stats.number_of_facets = stl_src->stats.number_of_facets;
+ if (stl_dst->stats.facets_malloced > 0)
+ {
+ stl_reallocate(stl_dst);
+ }
+ else
+ {
+ stl_allocate(stl_dst);
+ }
+ }
+
+ for (i_face = 0; i_face < stl_src->stats.number_of_facets; ++ i_face) {
+ stl_vertex const *vertices_src = stl_src->facet_start[i_face].vertex;
+ stl_vertex *vertices_dst = stl_dst->facet_start[i_face].vertex;
+ for (i_vertex = 0; i_vertex < 3; ++ i_vertex) {
+ stl_vertex* v_dst = &vertices_dst[i_vertex];
+ stl_vertex const * v_src = &vertices_src[i_vertex];
+ double v_src_x = (double)(v_src->x);
+ double v_src_y = (double)(v_src->y);
+ double v_src_z = (double)(v_src->z);
+ v_dst->x = (float)(trafo3x4[0] * v_src_x + trafo3x4[1] * v_src_y + trafo3x4[2] * v_src_z + trafo3x4[3]);
+ v_dst->y = (float)(trafo3x4[4] * v_src_x + trafo3x4[5] * v_src_y + trafo3x4[6] * v_src_z + trafo3x4[7]);
+ v_dst->z = (float)(trafo3x4[8] * v_src_x + trafo3x4[9] * v_src_y + trafo3x4[10] * v_src_z + trafo3x4[11]);
+ }
+ }
+ double det = trafo3x4[0]*trafo3x4[5]*trafo3x4[10] + trafo3x4[4]*trafo3x4[9]*trafo3x4[2] + trafo3x4[8]*trafo3x4[1]*trafo3x4[6]
+ - trafo3x4[0]*trafo3x4[9]*trafo3x4[6] - trafo3x4[4]*trafo3x4[1]*trafo3x4[10] - trafo3x4[8]*trafo3x4[5]*trafo3x4[2];
+ if(det < 0)
+ stl_reverse_all_facets(stl_dst);
+ stl_get_size(stl_dst);
+ if(det - 1.0 > 1e-04)
+ stl_calculate_volume(stl_dst);
+ calculate_normals(stl_dst);
+}
+
void
stl_rotate_x(stl_file *stl, float angle) {
int i;
diff --git a/xs/src/boost/nowide/args.hpp b/xs/src/boost/nowide/args.hpp
index bb806d02e8..eb483c245b 100755
--- a/xs/src/boost/nowide/args.hpp
+++ b/xs/src/boost/nowide/args.hpp
@@ -43,7 +43,7 @@ namespace nowide {
public:
///
- /// Fix command line agruments
+ /// Fix command line arguments
///
args(int &argc,char **&argv) :
old_argc_(argc),
@@ -56,7 +56,7 @@ namespace nowide {
fix_args(argc,argv);
}
///
- /// Fix command line agruments and environment
+ /// Fix command line arguments and environment
///
args(int &argc,char **&argv,char **&en) :
old_argc_(argc),
diff --git a/xs/src/boost/nowide/cenv.hpp b/xs/src/boost/nowide/cenv.hpp
index 5b41b8e8df..90ce7b86fa 100755
--- a/xs/src/boost/nowide/cenv.hpp
+++ b/xs/src/boost/nowide/cenv.hpp
@@ -62,7 +62,7 @@ namespace nowide {
///
/// \brief UTF-8 aware setenv, \a key - the variable name, \a value is a new UTF-8 value,
///
- /// if override is not 0, that the old value is always overridded, otherwise,
+ /// if override is not 0, that the old value is always overridden, otherwise,
/// if the variable exists it remains unchanged
///
inline int setenv(char const *key,char const *value,int override)
@@ -83,7 +83,7 @@ namespace nowide {
return -1;
}
///
- /// \brief Remove enviroment variable \a key
+ /// \brief Remove environment variable \a key
///
inline int unsetenv(char const *key)
{
diff --git a/xs/src/boost/nowide/filebuf.hpp b/xs/src/boost/nowide/filebuf.hpp
index 2d6f4a443f..2649782fd6 100755
--- a/xs/src/boost/nowide/filebuf.hpp
+++ b/xs/src/boost/nowide/filebuf.hpp
@@ -396,7 +396,7 @@ namespace nowide {
};
///
- /// \brief Convinience typedef
+ /// \brief Convenience typedef
///
typedef basic_filebuf filebuf;
diff --git a/xs/src/boost/nowide/fstream.hpp b/xs/src/boost/nowide/fstream.hpp
index b0824a51b5..35604d277b 100755
--- a/xs/src/boost/nowide/fstream.hpp
+++ b/xs/src/boost/nowide/fstream.hpp
@@ -18,7 +18,7 @@
namespace boost {
///
-/// \brief This namespace includes implementation of the standard library functios
+/// \brief This namespace includes implementation of the standard library functions
/// such that they accept UTF-8 strings on Windows. On other platforms it is just an alias
/// of std namespace (i.e. not on Windows)
///
diff --git a/xs/src/boost/nowide/integration/filesystem.hpp b/xs/src/boost/nowide/integration/filesystem.hpp
index c2a44b4ee5..91e17c7fb1 100755
--- a/xs/src/boost/nowide/integration/filesystem.hpp
+++ b/xs/src/boost/nowide/integration/filesystem.hpp
@@ -13,7 +13,7 @@
namespace boost {
namespace nowide {
///
- /// Instal utf8_codecvt facet into boost::filesystem::path such all char strings are interpreted as utf-8 strings
+ /// Install utf8_codecvt facet into boost::filesystem::path such all char strings are interpreted as utf-8 strings
///
inline void nowide_filesystem()
{
diff --git a/xs/src/boost/nowide/stackstring.hpp b/xs/src/boost/nowide/stackstring.hpp
index 948a22f7f6..f1445eac3b 100755
--- a/xs/src/boost/nowide/stackstring.hpp
+++ b/xs/src/boost/nowide/stackstring.hpp
@@ -129,19 +129,19 @@ class basic_stackstring {
}; //basic_stackstring
///
-/// Convinience typedef
+/// Convenience typedef
///
typedef basic_stackstring wstackstring;
///
-/// Convinience typedef
+/// Convenience typedef
///
typedef basic_stackstring stackstring;
///
-/// Convinience typedef
+/// Convenience typedef
///
typedef basic_stackstring wshort_stackstring;
///
-/// Convinience typedef
+/// Convenience typedef
///
typedef basic_stackstring short_stackstring;
diff --git a/xs/src/boost/nowide/utf8_codecvt.hpp b/xs/src/boost/nowide/utf8_codecvt.hpp
index 2d8d393ad8..15ec0be8fe 100755
--- a/xs/src/boost/nowide/utf8_codecvt.hpp
+++ b/xs/src/boost/nowide/utf8_codecvt.hpp
@@ -145,14 +145,14 @@ class utf8_codecvt : public std::codecvt
+#include
#include
#include
#include
@@ -67,7 +68,7 @@ namespace exprtk
#define exprtk_error_location \
"exprtk.hpp:" + details::to_str(__LINE__) \
- #if __GNUC__ >= 7
+ #if defined(__GNUC__) && (__GNUC__ >= 7)
#define exprtk_disable_fallthrough_begin \
_Pragma ("GCC diagnostic push") \
@@ -83,8 +84,14 @@ namespace exprtk
namespace details
{
- typedef unsigned char uchar_t;
- typedef char char_t;
+ typedef unsigned char uchar_t;
+ typedef char char_t;
+ typedef uchar_t* uchar_ptr;
+ typedef char_t* char_ptr;
+ typedef uchar_t const* uchar_cptr;
+ typedef char_t const* char_cptr;
+ typedef unsigned long long int _uint64_t;
+ typedef long long int _int64_t;
inline bool is_whitespace(const char_t c)
{
@@ -158,6 +165,12 @@ namespace exprtk
('\'' != c);
}
+ inline bool is_valid_string_char(const char_t c)
+ {
+ return std::isprint(static_cast(c)) ||
+ is_whitespace(c);
+ }
+
#ifndef exprtk_disable_caseinsensitivity
inline void case_normalise(std::string& s)
{
@@ -283,6 +296,11 @@ namespace exprtk
return result;
}
+ inline std::string to_str(std::size_t i)
+ {
+ return to_str(static_cast(i));
+ }
+
inline bool is_hex_digit(const std::string::value_type digit)
{
return (('0' <= digit) && (digit <= '9')) ||
@@ -299,31 +317,30 @@ namespace exprtk
}
template
- inline void parse_hex(Iterator& itr, Iterator end, std::string::value_type& result)
+ inline bool parse_hex(Iterator& itr, Iterator end,
+ std::string::value_type& result)
{
if (
- (end != (itr )) &&
- (end != (itr + 1)) &&
- (end != (itr + 2)) &&
- (end != (itr + 3)) &&
- ('0' == *(itr )) &&
- (
- ('x' == *(itr + 1)) ||
- ('X' == *(itr + 1))
- ) &&
- (is_hex_digit(*(itr + 2))) &&
- (is_hex_digit(*(itr + 3)))
+ (end == (itr )) ||
+ (end == (itr + 1)) ||
+ (end == (itr + 2)) ||
+ (end == (itr + 3)) ||
+ ('0' != *(itr )) ||
+ ('X' != std::toupper(*(itr + 1))) ||
+ (!is_hex_digit(*(itr + 2))) ||
+ (!is_hex_digit(*(itr + 3)))
)
{
- result = hex_to_bin(static_cast(*(itr + 2))) << 4 |
- hex_to_bin(static_cast(*(itr + 3))) ;
- itr += 3;
+ return false;
}
- else
- result = '\0';
+
+ result = hex_to_bin(static_cast(*(itr + 2))) << 4 |
+ hex_to_bin(static_cast(*(itr + 3))) ;
+
+ return true;
}
- inline void cleanup_escapes(std::string& s)
+ inline bool cleanup_escapes(std::string& s)
{
typedef std::string::iterator str_itr_t;
@@ -337,36 +354,41 @@ namespace exprtk
{
if ('\\' == (*itr1))
{
- ++removal_count;
-
if (end == ++itr1)
- break;
- else if ('\\' != (*itr1))
{
- switch (*itr1)
- {
- case 'n' : (*itr1) = '\n'; break;
- case 'r' : (*itr1) = '\r'; break;
- case 't' : (*itr1) = '\t'; break;
- case '0' : parse_hex(itr1, end, (*itr1));
- removal_count += 3;
- break;
- }
-
- continue;
+ return false;
}
+ else if (parse_hex(itr1, end, *itr2))
+ {
+ itr1+= 4;
+ itr2+= 1;
+ removal_count +=4;
+ }
+ else if ('a' == (*itr1)) { (*itr2++) = '\a'; ++itr1; ++removal_count; }
+ else if ('b' == (*itr1)) { (*itr2++) = '\b'; ++itr1; ++removal_count; }
+ else if ('f' == (*itr1)) { (*itr2++) = '\f'; ++itr1; ++removal_count; }
+ else if ('n' == (*itr1)) { (*itr2++) = '\n'; ++itr1; ++removal_count; }
+ else if ('r' == (*itr1)) { (*itr2++) = '\r'; ++itr1; ++removal_count; }
+ else if ('t' == (*itr1)) { (*itr2++) = '\t'; ++itr1; ++removal_count; }
+ else if ('v' == (*itr1)) { (*itr2++) = '\v'; ++itr1; ++removal_count; }
+ else if ('0' == (*itr1)) { (*itr2++) = '\0'; ++itr1; ++removal_count; }
+ else
+ {
+ (*itr2++) = (*itr1++);
+ ++removal_count;
+ }
+ continue;
}
-
- if (itr1 != itr2)
- {
- (*itr2) = (*itr1);
- }
-
- ++itr1;
- ++itr2;
+ else
+ (*itr2++) = (*itr1++);
}
+ if ((removal_count > s.size()) || (0 == removal_count))
+ return false;
+
s.resize(s.size() - removal_count);
+
+ return true;
}
class build_string
@@ -384,7 +406,7 @@ namespace exprtk
return (*this);
}
- inline build_string& operator << (const char_t* s)
+ inline build_string& operator << (char_cptr s)
{
data_ += std::string(s);
return (*this);
@@ -571,83 +593,82 @@ namespace exprtk
template
inline bool match_impl(const Iterator pattern_begin,
- const Iterator pattern_end,
- const Iterator data_begin,
- const Iterator data_end,
+ const Iterator pattern_end ,
+ const Iterator data_begin ,
+ const Iterator data_end ,
const typename std::iterator_traits::value_type& zero_or_more,
- const typename std::iterator_traits::value_type& zero_or_one)
+ const typename std::iterator_traits::value_type& zero_or_one )
{
- if (0 == std::distance(data_begin,data_end))
- {
- return false;
- }
+ const Iterator null_itr(0);
- Iterator d_itr = data_begin;
- Iterator p_itr = pattern_begin;
- Iterator c_itr = data_begin;
- Iterator m_itr = data_begin;
+ Iterator d_itr = data_begin;
+ Iterator p_itr = pattern_begin;
+ Iterator tb_p_itr = null_itr;
+ Iterator tb_d_itr = null_itr;
- while ((data_end != d_itr) && (zero_or_more != (*p_itr)))
+ while (d_itr != data_end)
{
- if ((!Compare::cmp((*p_itr),(*d_itr))) && (zero_or_one != (*p_itr)))
+ if (zero_or_more == *p_itr)
{
- return false;
- }
+ while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr)))
+ {
+ ++p_itr;
+ }
- ++p_itr;
- ++d_itr;
- }
+ if (pattern_end == p_itr)
+ return true;
- while (data_end != d_itr)
- {
- if (zero_or_more == (*p_itr))
- {
- if (pattern_end == (++p_itr))
+ const typename std::iterator_traits::value_type c = *(p_itr);
+
+ while ((data_end != d_itr) && !Compare::cmp(c,*d_itr))
{
- return true;
+ ++d_itr;
}
- m_itr = p_itr;
- c_itr = d_itr;
- ++c_itr;
- }
- else if ((Compare::cmp((*p_itr),(*d_itr))) || (zero_or_one == (*p_itr)))
- {
- ++p_itr;
- ++d_itr;
+ tb_p_itr = p_itr;
+ tb_d_itr = d_itr;
+
+ continue;
}
- else
+ else if (!Compare::cmp(*p_itr, *d_itr) && (zero_or_one != *p_itr))
{
- p_itr = m_itr;
- d_itr = c_itr++;
+ if (null_itr == tb_d_itr)
+ return false;
+
+ d_itr = tb_d_itr++;
+ p_itr = tb_p_itr;
+
+ continue;
}
+
+ ++p_itr;
+ ++d_itr;
}
- while ((p_itr != pattern_end) && (zero_or_more == (*p_itr))) { ++p_itr; }
+ while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr)))
+ {
+ ++p_itr;
+ }
- return (p_itr == pattern_end);
+ return (pattern_end == p_itr);
}
inline bool wc_match(const std::string& wild_card,
const std::string& str)
{
- return match_impl(wild_card.data(),
- wild_card.data() + wild_card.size(),
- str.data(),
- str.data() + str.size(),
- '*',
- '?');
+ return match_impl(
+ wild_card.data(), wild_card.data() + wild_card.size(),
+ str.data(), str.data() + str.size(),
+ '*', '?');
}
inline bool wc_imatch(const std::string& wild_card,
const std::string& str)
{
- return match_impl(wild_card.data(),
- wild_card.data() + wild_card.size(),
- str.data(),
- str.data() + str.size(),
- '*',
- '?');
+ return match_impl(
+ wild_card.data(), wild_card.data() + wild_card.size(),
+ str.data(), str.data() + str.size(),
+ '*', '?');
}
inline bool sequence_match(const std::string& pattern,
@@ -728,7 +749,7 @@ namespace exprtk
1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016
};
- static const std::size_t pow10_size = sizeof(pow10) / sizeof(double);
+ static const std::size_t pow10_size = sizeof(pow10) / sizeof(double);
namespace numeric
{
@@ -748,23 +769,29 @@ namespace exprtk
namespace details
{
- struct unknown_type_tag {unknown_type_tag(){} };
- struct real_type_tag {real_type_tag(){} };
- struct complex_type_tag {complex_type_tag(){} };
- struct int_type_tag {int_type_tag(){}};
+ struct unknown_type_tag { unknown_type_tag() {} };
+ struct real_type_tag { real_type_tag () {} };
+ struct complex_type_tag { complex_type_tag() {} };
+ struct int_type_tag { int_type_tag () {} };
template
- struct number_type { typedef unknown_type_tag type; };
+ struct number_type
+ {
+ typedef unknown_type_tag type;
+ number_type() {}
+ };
- #define exprtk_register_real_type_tag(T) \
- template<> struct number_type { typedef real_type_tag type; }; \
+ #define exprtk_register_real_type_tag(T) \
+ template <> struct number_type \
+ { typedef real_type_tag type; number_type() {} }; \
- #define exprtk_register_complex_type_tag(T) \
- template<> struct number_type > \
- { typedef complex_type_tag type; }; \
+ #define exprtk_register_complex_type_tag(T) \
+ template <> struct number_type > \
+ { typedef complex_type_tag type; number_type() {} }; \
- #define exprtk_register_int_type_tag(T) \
- template<> struct number_type { typedef int_type_tag type; }; \
+ #define exprtk_register_int_type_tag(T) \
+ template <> struct number_type \
+ { typedef int_type_tag type; number_type() {} }; \
exprtk_register_real_type_tag(double )
exprtk_register_real_type_tag(long double)
@@ -774,45 +801,34 @@ namespace exprtk
exprtk_register_complex_type_tag(long double)
exprtk_register_complex_type_tag(float )
- exprtk_register_int_type_tag(short )
- exprtk_register_int_type_tag(int )
- exprtk_register_int_type_tag(long long int )
- exprtk_register_int_type_tag(unsigned short )
- exprtk_register_int_type_tag(unsigned int )
- exprtk_register_int_type_tag(unsigned long long int)
+ exprtk_register_int_type_tag(short )
+ exprtk_register_int_type_tag(int )
+ exprtk_register_int_type_tag(_int64_t )
+ exprtk_register_int_type_tag(unsigned short)
+ exprtk_register_int_type_tag(unsigned int )
+ exprtk_register_int_type_tag(_uint64_t )
#undef exprtk_register_real_type_tag
#undef exprtk_register_int_type_tag
template
- struct epsilon_type
- {
- static inline T value()
- {
- const T epsilon = T(0.0000000001);
- return epsilon;
- }
- };
+ struct epsilon_type {};
- template <>
- struct epsilon_type
- {
- static inline float value()
- {
- const float epsilon = float(0.000001f);
- return epsilon;
- }
- };
+ #define exprtk_define_epsilon_type(Type, Epsilon) \
+ template <> struct epsilon_type \
+ { \
+ static inline Type value() \
+ { \
+ const Type epsilon = static_cast(Epsilon); \
+ return epsilon; \
+ } \
+ }; \
- template <>
- struct epsilon_type
- {
- static inline long double value()
- {
- const long double epsilon = (long double)(0.000000000001);
- return epsilon;
- }
- };
+ exprtk_define_epsilon_type(float , 0.000001f)
+ exprtk_define_epsilon_type(double , 0.0000000001)
+ exprtk_define_epsilon_type(long double, 0.000000000001)
+
+ #undef exprtk_define_epsilon_type
template
inline bool is_nan_impl(const T v, real_type_tag)
@@ -827,9 +843,9 @@ namespace exprtk
}
template
- inline long long int to_int64_impl(const T v, real_type_tag)
+ inline _int64_t to_int64_impl(const T v, real_type_tag)
{
- return static_cast(v);
+ return static_cast<_int64_t>(v);
}
template
@@ -984,7 +1000,15 @@ namespace exprtk
template
inline T root_impl(const T v0, const T v1, real_type_tag)
{
- return std::pow(v0,T(1) / v1);
+ if (v1 < T(0))
+ return std::numeric_limits::quiet_NaN();
+
+ const std::size_t n = static_cast(v1);
+
+ if ((v0 < T(0)) && (0 == (n % 2)))
+ return std::numeric_limits::quiet_NaN();
+
+ return std::pow(v0, T(1) / n);
}
template
@@ -1002,7 +1026,7 @@ namespace exprtk
template
inline T roundn_impl(const T v0, const T v1, real_type_tag)
{
- const int index = std::max(0, std::min(pow10_size - 1, (int)std::floor(v1)));
+ const int index = std::max(0, std::min(pow10_size - 1, static_cast(std::floor(v1))));
const T p10 = T(pow10[index]);
if (v0 < T(0))
@@ -1297,6 +1321,9 @@ namespace exprtk
template inline T frac_impl(const T v, real_type_tag) { return (v - static_cast(v)); }
template inline T trunc_impl(const T v, real_type_tag) { return T(static_cast(v)); }
+ template inline T const_pi_impl(real_type_tag) { return T(numeric::constant::pi); }
+ template inline T const_e_impl (real_type_tag) { return T(numeric::constant::e); }
+
template inline T abs_impl(const T v, int_type_tag) { return ((v >= T(0)) ? v : -v); }
template inline T exp_impl(const T v, int_type_tag) { return std::exp (v); }
template inline T log_impl(const T v, int_type_tag) { return std::log (v); }
@@ -1343,169 +1370,169 @@ namespace exprtk
template
struct numeric_info { enum { length = 0, size = 32, bound_length = 0, min_exp = 0, max_exp = 0 }; };
- template<> struct numeric_info { enum { length = 10, size = 16, bound_length = 9}; };
- template<> struct numeric_info { enum { min_exp = -38, max_exp = +38}; };
- template<> struct numeric_info { enum { min_exp = -308, max_exp = +308}; };
- template<> struct numeric_info { enum { min_exp = -308, max_exp = +308}; };
+ template <> struct numeric_info { enum { length = 10, size = 16, bound_length = 9}; };
+ template <> struct numeric_info { enum { min_exp = -38, max_exp = +38}; };
+ template <> struct numeric_info { enum { min_exp = -308, max_exp = +308}; };
+ template <> struct numeric_info { enum { min_exp = -308, max_exp = +308}; };
template
inline int to_int32(const T v)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return to_int32_impl(v, num_type);
}
template
- inline long long int to_int64(const T v)
+ inline _int64_t to_int64(const T v)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return to_int64_impl(v, num_type);
}
template
inline bool is_nan(const T v)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return is_nan_impl(v, num_type);
}
template
inline T min(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return min_impl(v0, v1, num_type);
}
template
inline T max(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return max_impl(v0, v1, num_type);
}
template
inline T equal(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return equal_impl(v0, v1, num_type);
}
template
inline T nequal(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return nequal_impl(v0, v1, num_type);
}
template
inline T modulus(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return modulus_impl(v0, v1, num_type);
}
template
inline T pow(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return pow_impl(v0, v1, num_type);
}
template
inline T logn(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return logn_impl(v0, v1, num_type);
}
template
inline T root(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return root_impl(v0, v1, num_type);
}
template
inline T roundn(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return roundn_impl(v0, v1, num_type);
}
template
inline T hypot(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return hypot_impl(v0, v1, num_type);
}
template
inline T atan2(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return atan2_impl(v0, v1, num_type);
}
template
inline T shr(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return shr_impl(v0, v1, num_type);
}
template
inline T shl(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return shl_impl(v0, v1, num_type);
}
template
inline T and_opr(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return and_impl(v0, v1, num_type);
}
template
inline T nand_opr(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return nand_impl(v0, v1, num_type);
}
template
inline T or_opr(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return or_impl(v0, v1, num_type);
}
template
inline T nor_opr(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return nor_impl(v0, v1, num_type);
}
template
inline T xor_opr(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return xor_impl(v0, v1, num_type);
}
template
inline T xnor_opr(const T v0, const T v1)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return xnor_impl(v0, v1, num_type);
}
template
inline bool is_integer(const T v)
{
- typename details::number_type::type num_type;
+ const typename details::number_type::type num_type;
return is_integer_impl(v, num_type);
}
@@ -1545,13 +1572,13 @@ namespace exprtk
template struct fast_exp { static inline T result(T v) { return v; } };
template struct fast_exp { static inline T result(T ) { return T(1); } };
- #define exprtk_define_unary_function(FunctionName) \
- template \
- inline T FunctionName (const T v) \
- { \
- typename details::number_type::type num_type; \
- return FunctionName##_impl(v,num_type); \
- } \
+ #define exprtk_define_unary_function(FunctionName) \
+ template \
+ inline T FunctionName (const T v) \
+ { \
+ const typename details::number_type::type num_type; \
+ return FunctionName##_impl(v,num_type); \
+ } \
exprtk_define_unary_function(abs )
exprtk_define_unary_function(acos )
@@ -1776,7 +1803,7 @@ namespace exprtk
if ((3 != length) && (inf_length != length))
return false;
- const char_t* inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc;
+ char_cptr inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc;
while (end != itr)
{
@@ -1798,6 +1825,13 @@ namespace exprtk
return true;
}
+ template
+ inline bool valid_exponent(const int exponent, numeric::details::real_type_tag)
+ {
+ using namespace details::numeric;
+ return (numeric_info::min_exp <= exponent) && (exponent <= numeric_info::max_exp);
+ }
+
template
inline bool string_to_real(Iterator& itr_external, const Iterator end, T& t, numeric::details::real_type_tag)
{
@@ -1817,7 +1851,7 @@ namespace exprtk
bool instate = false;
- static const char zero = static_cast('0');
+ static const char_t zero = static_cast('0');
#define parse_digit_1(d) \
if ((digit = (*itr - zero)) < 10) \
@@ -1838,16 +1872,9 @@ namespace exprtk
while ((end != itr) && (zero == (*itr))) ++itr;
- unsigned int digit;
-
while (end != itr)
{
- // Note: For 'physical' superscalar architectures it
- // is advised that the following loop be: 4xPD1 and 1xPD2
- #ifdef exprtk_enable_superscalar
- parse_digit_1(d)
- parse_digit_1(d)
- #endif
+ unsigned int digit;
parse_digit_1(d)
parse_digit_1(d)
parse_digit_2(d)
@@ -1863,16 +1890,11 @@ namespace exprtk
if ('.' == (*itr))
{
const Iterator curr = ++itr;
- unsigned int digit;
T tmp_d = T(0);
while (end != itr)
{
- #ifdef exprtk_enable_superscalar
- parse_digit_1(tmp_d)
- parse_digit_1(tmp_d)
- parse_digit_1(tmp_d)
- #endif
+ unsigned int digit;
parse_digit_1(tmp_d)
parse_digit_1(tmp_d)
parse_digit_2(tmp_d)
@@ -1881,7 +1903,13 @@ namespace exprtk
if (curr != itr)
{
instate = true;
- d += compute_pow10(tmp_d,static_cast(-std::distance(curr,itr)));
+
+ const int frac_exponent = static_cast(-std::distance(curr, itr));
+
+ if (!valid_exponent(frac_exponent, numeric::details::real_type_tag()))
+ return false;
+
+ d += compute_pow10(tmp_d, frac_exponent);
}
#undef parse_digit_1
@@ -1952,6 +1980,8 @@ namespace exprtk
if ((end != itr) || (!instate))
return false;
+ else if (!valid_exponent(exponent, numeric::details::real_type_tag()))
+ return false;
else if (exponent)
d = compute_pow10(d,exponent);
@@ -1964,8 +1994,8 @@ namespace exprtk
{
const typename numeric::details::number_type::type num_type;
- const char_t* begin = s.data();
- const char_t* end = s.data() + s.size();
+ char_cptr begin = s.data();
+ char_cptr end = s.data() + s.size();
return string_to_real(begin, end, t, num_type);
}
@@ -1990,6 +2020,50 @@ namespace exprtk
} // namespace details
+ struct loop_runtime_check
+ {
+ enum loop_types
+ {
+ e_invalid = 0,
+ e_for_loop = 1,
+ e_while_loop = 2,
+ e_repeat_until_loop = 4,
+ e_all_loops = 7
+ };
+
+ enum violation_type
+ {
+ e_unknown = 0,
+ e_iteration_count = 1,
+ e_timeout = 2
+ };
+
+ loop_types loop_set;
+
+ loop_runtime_check()
+ : loop_set(e_invalid),
+ max_loop_iterations(0)
+ {}
+
+ details::_uint64_t max_loop_iterations;
+
+ struct violation_context
+ {
+ loop_types loop;
+ violation_type violation;
+ details::_uint64_t iteration_count;
+ };
+
+ virtual void handle_runtime_violation(const violation_context&)
+ {
+ throw std::runtime_error("ExprTk Loop run-time violation.");
+ }
+
+ virtual ~loop_runtime_check() {}
+ };
+
+ typedef loop_runtime_check* loop_runtime_check_ptr;
+
namespace lexer
{
struct token
@@ -2170,7 +2244,7 @@ namespace exprtk
typedef token token_t;
typedef std::vector token_list_t;
- typedef std::vector::iterator token_list_itr_t;
+ typedef token_list_t::iterator token_list_itr_t;
typedef details::char_t char_t;
generator()
@@ -2204,9 +2278,7 @@ namespace exprtk
{
scan_token();
- if (token_list_.empty())
- return true;
- else if (token_list_.back().is_error())
+ if (!token_list_.empty() && token_list_.back().is_error())
return false;
}
@@ -2296,8 +2368,8 @@ namespace exprtk
inline std::string substr(const std::size_t& begin, const std::size_t& end)
{
- const char_t* begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_;
- const char_t* end_itr = ((base_itr_ + end) < s_end_) ? (base_itr_ + end) : s_end_;
+ const details::char_cptr begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_;
+ const details::char_cptr end_itr = ((base_itr_ + end) < s_end_) ? (base_itr_ + end) : s_end_;
return std::string(begin_itr,end_itr);
}
@@ -2307,18 +2379,40 @@ namespace exprtk
if (finished())
return "";
else if (token_list_.begin() != token_itr_)
- return std::string(base_itr_ + (token_itr_ - 1)->position,s_end_);
+ return std::string(base_itr_ + (token_itr_ - 1)->position, s_end_);
else
- return std::string(base_itr_ + token_itr_->position,s_end_);
+ return std::string(base_itr_ + token_itr_->position, s_end_);
}
private:
- inline bool is_end(const char_t* itr)
+ inline bool is_end(details::char_cptr itr)
{
return (s_end_ == itr);
}
+ #ifndef exprtk_disable_comments
+ inline bool is_comment_start(details::char_cptr itr)
+ {
+ const char_t c0 = *(itr + 0);
+ const char_t c1 = *(itr + 1);
+
+ if ('#' == c0)
+ return true;
+ else if (!is_end(itr + 1))
+ {
+ if (('/' == c0) && ('/' == c1)) return true;
+ if (('/' == c0) && ('*' == c1)) return true;
+ }
+ return false;
+ }
+ #else
+ inline bool is_comment_start(details::char_cptr)
+ {
+ return false;
+ }
+ #endif
+
inline void skip_whitespace()
{
while (!is_end(s_itr_) && details::is_whitespace(*s_itr_))
@@ -2348,47 +2442,72 @@ namespace exprtk
return (0 != mode);
}
- static inline bool comment_end(const char_t c0, const char_t c1, const int mode)
+ static inline bool comment_end(const char_t c0, const char_t c1, int& mode)
{
- return (
- ((1 == mode) && ('\n' == c0)) ||
- ((2 == mode) && ( '*' == c0) && ('/' == c1))
- );
+ if (
+ ((1 == mode) && ('\n' == c0)) ||
+ ((2 == mode) && ( '*' == c0) && ('/' == c1))
+ )
+ {
+ mode = 0;
+ return true;
+ }
+ else
+ return false;
}
};
int mode = 0;
int increment = 0;
- if (is_end(s_itr_) || is_end((s_itr_ + 1)))
+ if (is_end(s_itr_))
return;
else if (!test::comment_start(*s_itr_, *(s_itr_ + 1), mode, increment))
return;
+ details::char_cptr cmt_start = s_itr_;
+
s_itr_ += increment;
- while (!is_end(s_itr_) && !test::comment_end(*s_itr_, *(s_itr_ + 1), mode))
+ while (!is_end(s_itr_))
{
- ++s_itr_;
+ if ((1 == mode) && test::comment_end(*s_itr_, 0, mode))
+ {
+ ++s_itr_;
+ return;
+ }
+
+ if ((2 == mode))
+ {
+ if (!is_end((s_itr_ + 1)) && test::comment_end(*s_itr_, *(s_itr_ + 1), mode))
+ {
+ s_itr_ += 2;
+ return;
+ }
+ }
+
+ ++s_itr_;
}
- if (!is_end(s_itr_))
+ if (2 == mode)
{
- s_itr_ += mode;
-
- skip_whitespace();
- skip_comments ();
+ token_t t;
+ t.set_error(token::e_error, cmt_start, cmt_start + mode, base_itr_);
+ token_list_.push_back(t);
}
#endif
}
inline void scan_token()
{
- skip_whitespace();
- skip_comments ();
-
- if (is_end(s_itr_))
+ if (details::is_whitespace(*s_itr_))
{
+ skip_whitespace();
+ return;
+ }
+ else if (is_comment_start(s_itr_))
+ {
+ skip_comments();
return;
}
else if (details::is_operator_char(*s_itr_))
@@ -2502,7 +2621,7 @@ namespace exprtk
inline void scan_symbol()
{
- const char_t* initial_itr = s_itr_;
+ details::char_cptr initial_itr = s_itr_;
while (!is_end(s_itr_))
{
@@ -2553,11 +2672,11 @@ namespace exprtk
(15) .1234e-3
*/
- const char_t* initial_itr = s_itr_;
- bool dot_found = false;
- bool e_found = false;
- bool post_e_sign_found = false;
- bool post_e_digit_found = false;
+ details::char_cptr initial_itr = s_itr_;
+ bool dot_found = false;
+ bool e_found = false;
+ bool post_e_sign_found = false;
+ bool post_e_digit_found = false;
token_t t;
while (!is_end(s_itr_))
@@ -2568,6 +2687,7 @@ namespace exprtk
{
t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_);
token_list_.push_back(t);
+
return;
}
@@ -2640,13 +2760,16 @@ namespace exprtk
inline void scan_special_function()
{
- const char_t* initial_itr = s_itr_;
+ details::char_cptr initial_itr = s_itr_;
token_t t;
// $fdd(x,x,x) = at least 11 chars
if (std::distance(s_itr_,s_end_) < 11)
{
- t.set_error(token::e_err_sfunc, initial_itr, s_itr_, base_itr_);
+ t.set_error(
+ token::e_err_sfunc,
+ initial_itr, std::min(initial_itr + 11, s_end_),
+ base_itr_);
token_list_.push_back(t);
return;
@@ -2659,7 +2782,10 @@ namespace exprtk
(details::is_digit(*(s_itr_ + 3))))
)
{
- t.set_error(token::e_err_sfunc, initial_itr, s_itr_, base_itr_);
+ t.set_error(
+ token::e_err_sfunc,
+ initial_itr, std::min(initial_itr + 4, s_end_),
+ base_itr_);
token_list_.push_back(t);
return;
@@ -2676,13 +2802,14 @@ namespace exprtk
#ifndef exprtk_disable_string_capabilities
inline void scan_string()
{
- const char_t* initial_itr = s_itr_ + 1;
+ details::char_cptr initial_itr = s_itr_ + 1;
token_t t;
if (std::distance(s_itr_,s_end_) < 2)
{
t.set_error(token::e_err_string, s_itr_, s_end_, base_itr_);
token_list_.push_back(t);
+
return;
}
@@ -2693,7 +2820,14 @@ namespace exprtk
while (!is_end(s_itr_))
{
- if (!escaped && ('\\' == *s_itr_))
+ if (!details::is_valid_string_char(*s_itr_))
+ {
+ t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_);
+ token_list_.push_back(t);
+
+ return;
+ }
+ else if (!escaped && ('\\' == *s_itr_))
{
escaped_found = true;
escaped = true;
@@ -2708,28 +2842,17 @@ namespace exprtk
}
else if (escaped)
{
- if (!is_end(s_itr_) && ('0' == *(s_itr_)))
+ if (
+ !is_end(s_itr_) && ('0' == *(s_itr_)) &&
+ ((s_itr_ + 4) <= s_end_)
+ )
{
- /*
- Note: The following 'awkward' conditional is
- due to various broken msvc compilers.
- */
- #if _MSC_VER == 1600
- const bool within_range = !is_end(s_itr_ + 2) &&
- !is_end(s_itr_ + 3) ;
- #else
- const bool within_range = !is_end(s_itr_ + 1) &&
- !is_end(s_itr_ + 2) &&
- !is_end(s_itr_ + 3) ;
- #endif
-
- const bool x_seperator = ('x' == *(s_itr_ + 1)) ||
- ('X' == *(s_itr_ + 1)) ;
+ const bool x_seperator = ('X' == std::toupper(*(s_itr_ + 1)));
- const bool both_digits = details::is_hex_digit(*(s_itr_ + 2)) &&
- details::is_hex_digit(*(s_itr_ + 3)) ;
+ const bool both_digits = details::is_hex_digit(*(s_itr_ + 2)) &&
+ details::is_hex_digit(*(s_itr_ + 3)) ;
- if (!within_range || !x_seperator || !both_digits)
+ if (!(x_seperator && both_digits))
{
t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_);
token_list_.push_back(t);
@@ -2760,7 +2883,13 @@ namespace exprtk
{
std::string parsed_string(initial_itr,s_itr_);
- details::cleanup_escapes(parsed_string);
+ if (!details::cleanup_escapes(parsed_string))
+ {
+ t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_);
+ token_list_.push_back(t);
+
+ return;
+ }
t.set_string(
parsed_string,
@@ -2776,13 +2905,13 @@ namespace exprtk
private:
- token_list_t token_list_;
- token_list_itr_t token_itr_;
- token_list_itr_t store_token_itr_;
- token_t eof_token_;
- const char_t* base_itr_;
- const char_t* s_itr_;
- const char_t* s_end_;
+ token_list_t token_list_;
+ token_list_itr_t token_itr_;
+ token_list_itr_t store_token_itr_;
+ token_t eof_token_;
+ details::char_cptr base_itr_;
+ details::char_cptr s_itr_;
+ details::char_cptr s_end_;
friend class token_scanner;
friend class token_modifier;
@@ -2949,6 +3078,10 @@ namespace exprtk
std::size_t changes = 0;
+ typedef std::pair insert_t;
+ std::vector insert_list;
+ insert_list.reserve(10000);
+
for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i)
{
int insert_index = -1;
@@ -2972,17 +3105,36 @@ namespace exprtk
break;
}
- typedef std::iterator_traits::difference_type diff_t;
-
if ((insert_index >= 0) && (insert_index <= (static_cast(stride_) + 1)))
{
- g.token_list_.insert(
- g.token_list_.begin() + static_cast(i + static_cast(insert_index)), t);
-
+ insert_list.push_back(insert_t(i, t));
changes++;
}
}
+ if (!insert_list.empty())
+ {
+ generator::token_list_t token_list;
+
+ std::size_t insert_index = 0;
+
+ for (std::size_t i = 0; i < g.token_list_.size(); ++i)
+ {
+ token_list.push_back(g.token_list_[i]);
+
+ if (
+ (insert_index < insert_list.size()) &&
+ (insert_list[insert_index].first == i)
+ )
+ {
+ token_list.push_back(insert_list[insert_index].second);
+ insert_index++;
+ }
+ }
+
+ std::swap(g.token_list_,token_list);
+ }
+
return changes;
}
@@ -3017,7 +3169,7 @@ namespace exprtk
{
public:
- token_joiner(const std::size_t& stride)
+ explicit token_joiner(const std::size_t& stride)
: stride_(stride)
{}
@@ -3041,53 +3193,82 @@ namespace exprtk
inline std::size_t process_stride_2(generator& g)
{
- typedef std::iterator_traits::difference_type diff_t;
-
if (g.token_list_.size() < 2)
return 0;
std::size_t changes = 0;
- for (std::size_t i = 0; i < (g.token_list_.size() - 1); ++i)
+ generator::token_list_t token_list;
+ token_list.reserve(10000);
+
+ for (int i = 0; i < static_cast(g.token_list_.size() - 1); ++i)
{
token t;
- while (join(g[i], g[i + 1], t))
+ for ( ; ; )
{
- g.token_list_[i] = t;
+ if (!join(g[i], g[i + 1], t))
+ {
+ token_list.push_back(g[i]);
+ break;
+ }
- g.token_list_.erase(g.token_list_.begin() + static_cast(i + 1));
+ token_list.push_back(t);
++changes;
+
+ i+=2;
+
+ if (static_cast(i) >= g.token_list_.size())
+ break;
}
}
+ token_list.push_back(g.token_list_.back());
+
+ std::swap(token_list, g.token_list_);
+
return changes;
}
inline std::size_t process_stride_3(generator& g)
{
- typedef std::iterator_traits::difference_type diff_t;
-
if (g.token_list_.size() < 3)
return 0;
std::size_t changes = 0;
- for (std::size_t i = 0; i < (g.token_list_.size() - 2); ++i)
+ generator::token_list_t token_list;
+ token_list.reserve(10000);
+
+ for (int i = 0; i < static_cast(g.token_list_.size() - 2); ++i)
{
token t;
- while (join(g[i], g[i + 1], g[i + 2], t))
+ for ( ; ; )
{
- g.token_list_[i] = t;
+ if (!join(g[i], g[i + 1], g[i + 2], t))
+ {
+ token_list.push_back(g[i]);
+ break;
+ }
+
+ token_list.push_back(t);
- g.token_list_.erase(g.token_list_.begin() + static_cast(i + 1),
- g.token_list_.begin() + static_cast(i + 3));
++changes;
+
+ i+=3;
+
+ if (static_cast(i) >= g.token_list_.size())
+ break;
}
}
+ token_list.push_back(*(g.token_list_.begin() + g.token_list_.size() - 2));
+ token_list.push_back(*(g.token_list_.begin() + g.token_list_.size() - 1));
+
+ std::swap(token_list, g.token_list_);
+
return changes;
}
@@ -3097,11 +3278,11 @@ namespace exprtk
namespace helper
{
- inline void dump(lexer::generator& generator)
+ inline void dump(const lexer::generator& generator)
{
for (std::size_t i = 0; i < generator.size(); ++i)
{
- lexer::token t = generator[i];
+ const lexer::token& t = generator[i];
printf("Token[%02d] @ %03d %6s --> '%s'\n",
static_cast(i),
static_cast(t.position),
@@ -3162,6 +3343,7 @@ namespace exprtk
else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_symbol )) match = true;
else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_symbol )) match = true;
else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_symbol )) match = true;
+ else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_symbol )) match = true;
return (match) ? 1 : -1;
}
@@ -3175,7 +3357,7 @@ namespace exprtk
{
public:
- operator_joiner(const std::size_t& stride)
+ explicit operator_joiner(const std::size_t& stride)
: token_joiner(stride)
{}
@@ -3307,7 +3489,7 @@ namespace exprtk
return true;
}
- // '- -' --> '-'
+ // '- -' --> '+'
else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_sub))
{
/*
@@ -3573,11 +3755,11 @@ namespace exprtk
sequence_validator()
: lexer::token_scanner(2)
{
- add_invalid(lexer::token::e_number ,lexer::token::e_number );
- add_invalid(lexer::token::e_string ,lexer::token::e_string );
- add_invalid(lexer::token::e_number ,lexer::token::e_string );
- add_invalid(lexer::token::e_string ,lexer::token::e_number );
- add_invalid(lexer::token::e_string ,lexer::token::e_ternary);
+ add_invalid(lexer::token::e_number, lexer::token::e_number);
+ add_invalid(lexer::token::e_string, lexer::token::e_string);
+ add_invalid(lexer::token::e_number, lexer::token::e_string);
+ add_invalid(lexer::token::e_string, lexer::token::e_number);
+
add_invalid_set1(lexer::token::e_assign );
add_invalid_set1(lexer::token::e_shr );
add_invalid_set1(lexer::token::e_shl );
@@ -3605,7 +3787,7 @@ namespace exprtk
bool operator() (const lexer::token& t0, const lexer::token& t1)
{
- set_t::value_type p = std::make_pair(t0.type,t1.type);
+ const set_t::value_type p = std::make_pair(t0.type,t1.type);
if (invalid_bracket_check(t0.type,t1.type))
{
@@ -3619,7 +3801,7 @@ namespace exprtk
return true;
}
- std::size_t error_count()
+ std::size_t error_count() const
{
return error_list_.size();
}
@@ -3651,21 +3833,21 @@ namespace exprtk
void add_invalid_set1(lexer::token::token_type t)
{
- add_invalid(t,lexer::token::e_assign);
- add_invalid(t,lexer::token::e_shr );
- add_invalid(t,lexer::token::e_shl );
- add_invalid(t,lexer::token::e_lte );
- add_invalid(t,lexer::token::e_ne );
- add_invalid(t,lexer::token::e_gte );
- add_invalid(t,lexer::token::e_lt );
- add_invalid(t,lexer::token::e_gt );
- add_invalid(t,lexer::token::e_eq );
- add_invalid(t,lexer::token::e_comma );
- add_invalid(t,lexer::token::e_div );
- add_invalid(t,lexer::token::e_mul );
- add_invalid(t,lexer::token::e_mod );
- add_invalid(t,lexer::token::e_pow );
- add_invalid(t,lexer::token::e_colon );
+ add_invalid(t, lexer::token::e_assign);
+ add_invalid(t, lexer::token::e_shr );
+ add_invalid(t, lexer::token::e_shl );
+ add_invalid(t, lexer::token::e_lte );
+ add_invalid(t, lexer::token::e_ne );
+ add_invalid(t, lexer::token::e_gte );
+ add_invalid(t, lexer::token::e_lt );
+ add_invalid(t, lexer::token::e_gt );
+ add_invalid(t, lexer::token::e_eq );
+ add_invalid(t, lexer::token::e_comma );
+ add_invalid(t, lexer::token::e_div );
+ add_invalid(t, lexer::token::e_mul );
+ add_invalid(t, lexer::token::e_mod );
+ add_invalid(t, lexer::token::e_pow );
+ add_invalid(t, lexer::token::e_colon );
}
bool invalid_bracket_check(lexer::token::token_type base, lexer::token::token_type t)
@@ -3675,7 +3857,7 @@ namespace exprtk
switch (t)
{
case lexer::token::e_assign : return (']' != base);
- case lexer::token::e_string : return true;
+ case lexer::token::e_string : return (')' != base);
default : return false;
}
}
@@ -3696,7 +3878,7 @@ namespace exprtk
case lexer::token::e_sub : return false;
case lexer::token::e_colon : return false;
case lexer::token::e_ternary : return false;
- default : return true;
+ default : return true ;
}
}
}
@@ -3710,7 +3892,7 @@ namespace exprtk
case lexer::token::e_eof : return false;
case lexer::token::e_colon : return false;
case lexer::token::e_ternary : return false;
- default : return true;
+ default : return true ;
}
}
else if (details::is_left_bracket(static_cast(t)))
@@ -3731,6 +3913,91 @@ namespace exprtk
std::vector > error_list_;
};
+ class sequence_validator_3tokens : public lexer::token_scanner
+ {
+ private:
+
+ typedef lexer::token::token_type token_t;
+ typedef std::pair > token_triplet_t;
+ typedef std::set set_t;
+
+ public:
+
+ using lexer::token_scanner::operator();
+
+ sequence_validator_3tokens()
+ : lexer::token_scanner(3)
+ {
+ add_invalid(lexer::token::e_number, lexer::token::e_number, lexer::token::e_number);
+ add_invalid(lexer::token::e_string, lexer::token::e_string, lexer::token::e_string);
+ add_invalid(lexer::token::e_comma , lexer::token::e_comma , lexer::token::e_comma );
+
+ add_invalid(lexer::token::e_add , lexer::token::e_add , lexer::token::e_add );
+ add_invalid(lexer::token::e_sub , lexer::token::e_sub , lexer::token::e_sub );
+ add_invalid(lexer::token::e_div , lexer::token::e_div , lexer::token::e_div );
+ add_invalid(lexer::token::e_mul , lexer::token::e_mul , lexer::token::e_mul );
+ add_invalid(lexer::token::e_mod , lexer::token::e_mod , lexer::token::e_mod );
+ add_invalid(lexer::token::e_pow , lexer::token::e_pow , lexer::token::e_pow );
+
+ add_invalid(lexer::token::e_add , lexer::token::e_sub , lexer::token::e_add );
+ add_invalid(lexer::token::e_sub , lexer::token::e_add , lexer::token::e_sub );
+ add_invalid(lexer::token::e_div , lexer::token::e_mul , lexer::token::e_div );
+ add_invalid(lexer::token::e_mul , lexer::token::e_div , lexer::token::e_mul );
+ add_invalid(lexer::token::e_mod , lexer::token::e_pow , lexer::token::e_mod );
+ add_invalid(lexer::token::e_pow , lexer::token::e_mod , lexer::token::e_pow );
+ }
+
+ bool result()
+ {
+ return error_list_.empty();
+ }
+
+ bool operator() (const lexer::token& t0, const lexer::token& t1, const lexer::token& t2)
+ {
+ const set_t::value_type p = std::make_pair(t0.type,std::make_pair(t1.type,t2.type));
+
+ if (invalid_comb_.find(p) != invalid_comb_.end())
+ {
+ error_list_.push_back(std::make_pair(t0,t1));
+ }
+
+ return true;
+ }
+
+ std::size_t error_count() const
+ {
+ return error_list_.size();
+ }
+
+ std::pair error(const std::size_t index)
+ {
+ if (index < error_list_.size())
+ {
+ return error_list_[index];
+ }
+ else
+ {
+ static const lexer::token error_token;
+ return std::make_pair(error_token,error_token);
+ }
+ }
+
+ void clear_errors()
+ {
+ error_list_.clear();
+ }
+
+ private:
+
+ void add_invalid(token_t t0, token_t t1, token_t t2)
+ {
+ invalid_comb_.insert(std::make_pair(t0,std::make_pair(t1,t2)));
+ }
+
+ set_t invalid_comb_;
+ std::vector > error_list_;
+ };
+
struct helper_assembly
{
inline bool register_scanner(lexer::token_scanner* scanner)
@@ -3985,40 +4252,6 @@ namespace exprtk
return true;
}
- inline bool token_is_then_assign(const token_t::token_type& ttype,
- std::string& token,
- const token_advance_mode mode = e_advance)
- {
- if (current_token_.type != ttype)
- {
- return false;
- }
-
- token = current_token_.value;
-
- advance_token(mode);
-
- return true;
- }
-
- template class Container>
- inline bool token_is_then_assign(const token_t::token_type& ttype,
- Container& token_list,
- const token_advance_mode mode = e_advance)
- {
- if (current_token_.type != ttype)
- {
- return false;
- }
-
- token_list.push_back(current_token_.value);
-
- advance_token(mode);
-
- return true;
- }
-
inline bool peek_token_is(const token_t::token_type& ttype)
{
return (lexer_.peek_next_token().type == ttype);
@@ -4105,14 +4338,14 @@ namespace exprtk
inline vector_view make_vector_view(T* data,
const std::size_t size, const std::size_t offset = 0)
{
- return vector_view(data + offset,size);
+ return vector_view(data + offset, size);
}
template
inline vector_view make_vector_view(std::vector& v,
const std::size_t size, const std::size_t offset = 0)
{
- return vector_view(v.data() + offset,size);
+ return vector_view(v.data() + offset, size);
}
template class results_context;
@@ -4129,20 +4362,25 @@ namespace exprtk
};
type_store()
- : size(0),
- data(0),
+ : data(0),
+ size(0),
type(e_unknown)
{}
+ union
+ {
+ void* data;
+ T* vec_data;
+ };
+
std::size_t size;
- void* data;
store_type type;
class parameter_list
{
public:
- parameter_list(std::vector& pl)
+ explicit parameter_list(std::vector& pl)
: parameter_list_(pl)
{}
@@ -4199,11 +4437,16 @@ namespace exprtk
typedef type_store type_store_t;
typedef ViewType value_t;
- type_view(type_store_t& ts)
+ explicit type_view(type_store_t& ts)
: ts_(ts),
data_(reinterpret_cast(ts_.data))
{}
+ explicit type_view(const type_store_t& ts)
+ : ts_(const_cast(ts)),
+ data_(reinterpret_cast(ts_.data))
+ {}
+
inline std::size_t size() const
{
return ts_.size;
@@ -4244,11 +4487,11 @@ namespace exprtk
typedef type_store type_store_t;
typedef T value_t;
- scalar_view(type_store_t& ts)
+ explicit scalar_view(type_store_t& ts)
: v_(*reinterpret_cast(ts.data))
{}
- scalar_view(const type_store_t& ts)
+ explicit scalar_view(const type_store_t& ts)
: v_(*reinterpret_cast(const_cast(ts).data))
{}
@@ -4436,27 +4679,33 @@ namespace exprtk
{
switch (opr)
{
- case e_add : return "+";
- case e_sub : return "-";
- case e_mul : return "*";
- case e_div : return "/";
- case e_mod : return "%";
- case e_pow : return "^";
- case e_assign : return ":=";
- case e_addass : return "+=";
- case e_subass : return "-=";
- case e_mulass : return "*=";
- case e_divass : return "/=";
- case e_modass : return "%=";
- case e_lt : return "<";
- case e_lte : return "<=";
- case e_eq : return "==";
- case e_equal : return "=";
- case e_ne : return "!=";
- case e_nequal : return "<>";
- case e_gte : return ">=";
- case e_gt : return ">";
- default : return"N/A";
+ case e_add : return "+" ;
+ case e_sub : return "-" ;
+ case e_mul : return "*" ;
+ case e_div : return "/" ;
+ case e_mod : return "%" ;
+ case e_pow : return "^" ;
+ case e_assign : return ":=" ;
+ case e_addass : return "+=" ;
+ case e_subass : return "-=" ;
+ case e_mulass : return "*=" ;
+ case e_divass : return "/=" ;
+ case e_modass : return "%=" ;
+ case e_lt : return "<" ;
+ case e_lte : return "<=" ;
+ case e_eq : return "==" ;
+ case e_equal : return "=" ;
+ case e_ne : return "!=" ;
+ case e_nequal : return "<>" ;
+ case e_gte : return ">=" ;
+ case e_gt : return ">" ;
+ case e_and : return "and" ;
+ case e_or : return "or" ;
+ case e_xor : return "xor" ;
+ case e_nand : return "nand";
+ case e_nor : return "nor" ;
+ case e_xnor : return "xnor";
+ default : return "N/A" ;
}
}
@@ -4481,8 +4730,8 @@ namespace exprtk
struct details
{
- details(const std::size_t& vsize,
- const unsigned int loop_batch_size = global_loop_batch_size)
+ explicit details(const std::size_t& vsize,
+ const unsigned int loop_batch_size = global_loop_batch_size)
: batch_size(loop_batch_size ),
remainder (vsize % batch_size),
upper_bound(static_cast(vsize - (remainder ? loop_batch_size : 0)))
@@ -4529,17 +4778,17 @@ namespace exprtk
destruct (true)
{}
- control_block(const std::size_t& dsize)
- : ref_count(1),
+ explicit control_block(const std::size_t& dsize)
+ : ref_count(1 ),
size (dsize),
- data (0),
- destruct (true)
+ data (0 ),
+ destruct (true )
{ create_data(); }
control_block(const std::size_t& dsize, data_t dptr, bool dstrct = false)
- : ref_count(1),
- size (dsize),
- data (dptr ),
+ : ref_count(1 ),
+ size (dsize ),
+ data (dptr ),
destruct (dstrct)
{}
@@ -4596,7 +4845,7 @@ namespace exprtk
{
destruct = true;
data = new T[size];
- std::fill_n(data,size,T(0));
+ std::fill_n(data, size, T(0));
dump_ptr("control_block::create_data() - data",data,size);
}
};
@@ -4607,8 +4856,8 @@ namespace exprtk
: control_block_(control_block::create(0))
{}
- vec_data_store(const std::size_t& size)
- : control_block_(control_block::create(size,(data_t)(0),true))
+ explicit vec_data_store(const std::size_t& size)
+ : control_block_(control_block::create(size,reinterpret_cast(0),true))
{}
vec_data_store(const std::size_t& size, data_t data, bool dstrct = false)
@@ -4693,7 +4942,7 @@ namespace exprtk
static inline void match_sizes(type& vds0, type& vds1)
{
- std::size_t size = min_size(vds0.control_block_,vds1.control_block_);
+ const std::size_t size = min_size(vds0.control_block_,vds1.control_block_);
vds0.control_block_->size = size;
vds1.control_block_->size = size;
}
@@ -4702,8 +4951,8 @@ namespace exprtk
static inline std::size_t min_size(control_block* cb0, control_block* cb1)
{
- std::size_t size0 = cb0->size;
- std::size_t size1 = cb1->size;
+ const std::size_t size0 = cb0->size;
+ const std::size_t size1 = cb1->size;
if (size0 && size1)
return std::min(size0,size1);
@@ -4790,19 +5039,19 @@ namespace exprtk
case e_ne : return std::not_equal_to()(arg0,arg1) ? T(1) : T(0);
case e_gte : return (arg0 >= arg1) ? T(1) : T(0);
case e_gt : return (arg0 > arg1) ? T(1) : T(0);
- case e_and : return and_opr (arg0,arg1);
+ case e_and : return and_opr (arg0,arg1);
case e_nand : return nand_opr(arg0,arg1);
- case e_or : return or_opr (arg0,arg1);
- case e_nor : return nor_opr (arg0,arg1);
- case e_xor : return xor_opr (arg0,arg1);
+ case e_or : return or_opr (arg0,arg1);
+ case e_nor : return nor_opr (arg0,arg1);
+ case e_xor : return xor_opr (arg0,arg1);
case e_xnor : return xnor_opr(arg0,arg1);
- case e_root : return root (arg0,arg1);
- case e_roundn : return roundn (arg0,arg1);
+ case e_root : return root (arg0,arg1);
+ case e_roundn : return roundn (arg0,arg1);
case e_equal : return equal (arg0,arg1);
case e_nequal : return nequal (arg0,arg1);
- case e_hypot : return hypot (arg0,arg1);
- case e_shr : return shr (arg0,arg1);
- case e_shl : return shl (arg0,arg1);
+ case e_hypot : return hypot (arg0,arg1);
+ case e_shr : return shr (arg0,arg1);
+ case e_shl : return shl (arg0,arg1);
default : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n"));
return std::numeric_limits