From 8e0d458d1d7e646e75d34d7fcb8c19d2215143e8 Mon Sep 17 00:00:00 2001 From: Vicious-one Date: Wed, 30 Sep 2015 16:22:49 +0300 Subject: [PATCH 01/13] Fix for #3069 --- xs/src/libslic3r/GCode.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 51093667af..f1fe42817a 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -2,6 +2,7 @@ #include "ExtrusionEntity.hpp" #include #include +#include namespace Slic3r { @@ -400,7 +401,7 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed) Polygon polygon = loop.polygon(); Point centroid = polygon.centroid(); last_pos = Point(polygon.bounding_box().max.x, centroid.y); - last_pos.rotate(rand() % 2*PI, centroid); + last_pos.rotate(fmod((float)rand()/16.0, 2.0*PI), centroid); } loop.split_at(last_pos); } From 5f8eea9adf6744bd3c4d7e59cc665f65602df857 Mon Sep 17 00:00:00 2001 From: Chow Loong Jin Date: Sun, 6 Mar 2016 17:44:39 +0800 Subject: [PATCH 02/13] Don't use equality comparisons for floats This fixes an issue where F0 moves arise from 0-width (or 0 layer height?) support material segments when using autospeed. Fixes: #3261 --- lib/Slic3r/Print/GCode.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Slic3r/Print/GCode.pm b/lib/Slic3r/Print/GCode.pm index e3022fef05..b7a48870a4 100644 --- a/lib/Slic3r/Print/GCode.pm +++ b/lib/Slic3r/Print/GCode.pm @@ -75,7 +75,8 @@ sub BUILD { } } } - @mm3_per_mm = grep $_ != 0, @mm3_per_mm; + # filter out 0-width segments + @mm3_per_mm = grep $_ > 0.000001, @mm3_per_mm; if (@mm3_per_mm) { my $min_mm3_per_mm = min(@mm3_per_mm); # In order to honor max_print_speed we need to find a target volumetric From 209b919fe6e90cd6ad06f09096cdf030de09b73c Mon Sep 17 00:00:00 2001 From: Chow Loong Jin Date: Thu, 12 May 2016 23:31:26 +0800 Subject: [PATCH 03/13] Fix cooling not working if !gcode_comments The cooling markers were being passed into GCodeWriter::set_speed() as a comment which were being ignored if gcode_comments was false. Fixes: #3325 --- xs/src/libslic3r/GCode.cpp | 4 ++-- xs/src/libslic3r/GCodeWriter.cpp | 4 +++- xs/src/libslic3r/GCodeWriter.hpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 88020246b3..066d94f2d2 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -177,7 +177,7 @@ Wipe::wipe(GCode &gcodegen, bool toolchange) /* Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one due to rounding (TODO: test and/or better math for this) */ double dE = length * (segment_length / wipe_dist) * 0.95; - gcode += gcodegen.writer.set_speed(wipe_speed*60, gcodegen.enable_cooling_markers ? ";_WIPE" : ""); + gcode += gcodegen.writer.set_speed(wipe_speed*60, "", gcodegen.enable_cooling_markers ? ";_WIPE" : ""); gcode += gcodegen.writer.extrude_to_xy( gcodegen.point_to_gcode(line->b), -dE, @@ -562,7 +562,7 @@ GCode::_extrude(ExtrusionPath path, std::string description, double speed) // extrude arc or line if (path.is_bridge() && this->enable_cooling_markers) gcode += ";_BRIDGE_FAN_START\n"; - gcode += this->writer.set_speed(F, this->enable_cooling_markers ? ";_EXTRUDE_SET_SPEED" : ""); + gcode += this->writer.set_speed(F, "", this->enable_cooling_markers ? ";_EXTRUDE_SET_SPEED" : ""); double path_length = 0; { std::string comment = this->config.gcode_comments ? description : ""; diff --git a/xs/src/libslic3r/GCodeWriter.cpp b/xs/src/libslic3r/GCodeWriter.cpp index d932fd83f6..bb52218776 100644 --- a/xs/src/libslic3r/GCodeWriter.cpp +++ b/xs/src/libslic3r/GCodeWriter.cpp @@ -273,11 +273,13 @@ GCodeWriter::toolchange(unsigned int extruder_id) } std::string -GCodeWriter::set_speed(double F, const std::string &comment) const +GCodeWriter::set_speed(double F, const std::string &comment, + const std::string &cooling_marker) const { std::ostringstream gcode; gcode << "G1 F" << F; COMMENT(comment); + gcode << cooling_marker; gcode << "\n"; return gcode.str(); } diff --git a/xs/src/libslic3r/GCodeWriter.hpp b/xs/src/libslic3r/GCodeWriter.hpp index 21ed8d2411..72d54215b3 100644 --- a/xs/src/libslic3r/GCodeWriter.hpp +++ b/xs/src/libslic3r/GCodeWriter.hpp @@ -34,7 +34,7 @@ class GCodeWriter { bool need_toolchange(unsigned int extruder_id) const; std::string set_extruder(unsigned int extruder_id); std::string toolchange(unsigned int extruder_id); - std::string set_speed(double F, const std::string &comment = std::string()) const; + std::string set_speed(double F, const std::string &comment = std::string(), const std::string &cooling_marker = std::string()) const; std::string travel_to_xy(const Pointf &point, const std::string &comment = std::string()); std::string travel_to_xyz(const Pointf3 &point, const std::string &comment = std::string()); std::string travel_to_z(double z, const std::string &comment = std::string()); From d8be976356820996f6249228c21c9ace0075a9e1 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 16 May 2016 23:40:24 +0200 Subject: [PATCH 04/13] The "controller" tab and the settings of the USB/serial connection was made configurable. Now one may hide the "controller" tab and the USB/serial connection configuration from the preferences. This is useful for someone, who never connects his printer to the computer by a cable. --- lib/Slic3r/GUI.pm | 13 +++++++++++-- lib/Slic3r/GUI/MainFrame.pm | 22 ++++++++++++++++------ lib/Slic3r/GUI/Preferences.pm | 9 ++++++++- lib/Slic3r/GUI/Tab.pm | 19 ++++++++++++------- slic3r.pl | 10 ++++++---- 5 files changed, 53 insertions(+), 20 deletions(-) diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index 077b5625b8..7f4a028a5f 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -53,6 +53,8 @@ use constant FILE_WILDCARDS => { use constant MODEL_WILDCARD => join '|', @{&FILE_WILDCARDS}{qw(known stl obj amf)}; our $datadir; +# If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden. +our $no_controller; our $no_plater; our $mode; our $autosave; @@ -64,6 +66,9 @@ our $Settings = { version_check => 1, autocenter => 1, background_processing => 1, + # If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden. + # By default, Prusa has the controller hidden. + no_controller => 1, }, }; @@ -115,6 +120,8 @@ sub OnInit { $Settings->{_}{mode} ||= 'expert'; $Settings->{_}{autocenter} //= 1; $Settings->{_}{background_processing} //= 1; + # If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden. + $Settings->{_}{no_controller} //= 1; } $Settings->{_}{version} = $Slic3r::VERSION; $self->save_settings; @@ -122,8 +129,10 @@ sub OnInit { # application frame Wx::Image::AddHandler(Wx::PNGHandler->new); $self->{mainframe} = my $frame = Slic3r::GUI::MainFrame->new( - mode => $mode // $Settings->{_}{mode}, - no_plater => $no_plater, + mode => $mode // $Settings->{_}{mode}, + # If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden. + no_controller => $no_controller // $Settings->{_}{no_controller}, + no_plater => $no_plater, ); $self->SetTopWindow($frame); diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index d2661765cc..d97ad22efc 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -24,6 +24,8 @@ sub new { # store input params $self->{mode} = $params{mode}; $self->{mode} = 'expert' if $self->{mode} !~ /^(?:simple|expert)$/; + # If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden. + $self->{no_controller} = $params{no_controller}; $self->{no_plater} = $params{no_plater}; $self->{loaded} = 0; @@ -96,7 +98,9 @@ sub _init_tabpanel { if (!$self->{no_plater}) { $panel->AddPage($self->{plater} = Slic3r::GUI::Plater->new($panel), "Plater"); - $panel->AddPage($self->{controller} = Slic3r::GUI::Controller->new($panel), "Controller"); + if (!$self->{no_controller}) { + $panel->AddPage($self->{controller} = Slic3r::GUI::Controller->new($panel), "Controller"); + } } $self->{options_tabs} = {}; @@ -109,7 +113,9 @@ sub _init_tabpanel { my $class_prefix = $self->{mode} eq 'simple' ? "Slic3r::GUI::SimpleTab::" : "Slic3r::GUI::Tab::"; for my $tab_name (qw(print filament printer)) { my $tab; - $tab = $self->{options_tabs}{$tab_name} = ($class_prefix . ucfirst $tab_name)->new($panel); + $tab = $self->{options_tabs}{$tab_name} = ($class_prefix . ucfirst $tab_name)->new( + $panel, + no_controller => $self->{no_controller}); $tab->on_value_change(sub { my ($opt_key, $value) = @_; @@ -136,7 +142,9 @@ sub _init_tabpanel { if ($self->{plater}) { $self->{plater}->update_presets($tab_name, @_); $self->{plater}->on_config_change($tab->config); - $self->{controller}->update_presets($tab_name, @_); + if ($self->{controller}) { + $self->{controller}->update_presets($tab_name, @_); + } } }); $tab->load_presets; @@ -246,9 +254,11 @@ sub _init_menubar { $self->_append_menu_item($windowMenu, "Select &Plater Tab\tCtrl+1", 'Show the plater', sub { $self->select_tab(0); }, undef, 'application_view_tile.png'); - $self->_append_menu_item($windowMenu, "Select &Controller Tab\tCtrl+T", 'Show the printer controller', sub { - $self->select_tab(1); - }, undef, 'printer_empty.png'); + if (!$self->{no_controller}) { + $self->_append_menu_item($windowMenu, "Select &Controller Tab\tCtrl+T", 'Show the printer controller', sub { + $self->select_tab(1); + }, undef, 'printer_empty.png'); + } $windowMenu->AppendSeparator(); $tab_offset += 2; } diff --git a/lib/Slic3r/GUI/Preferences.pm b/lib/Slic3r/GUI/Preferences.pm index 74846cfc96..ed210d2293 100644 --- a/lib/Slic3r/GUI/Preferences.pm +++ b/lib/Slic3r/GUI/Preferences.pm @@ -58,6 +58,13 @@ sub new { default => $Slic3r::GUI::Settings->{_}{background_processing}, readonly => !$Slic3r::have_threads, )); + $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( + opt_id => 'no_controller', + type => 'bool', + label => 'Disable USB/serial connection', + tooltip => 'Disable communication with the printer over a serial / USB cable. This simplifies the user interface in case the printer is never attached to the computer.', + default => $Slic3r::GUI::Settings->{_}{no_controller}, + )); my $sizer = Wx::BoxSizer->new(wxVERTICAL); $sizer->Add($optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); @@ -75,7 +82,7 @@ sub new { sub _accept { my $self = shift; - if ($self->{values}{mode}) { + if ($self->{values}{mode} || defined($self->{values}{no_controller})) { Slic3r::GUI::warning_catcher($self)->("You need to restart Slic3r to make the changes effective."); } diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 3736d1b023..9c0ee57885 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -107,7 +107,7 @@ sub new { }); $self->{config} = Slic3r::Config->new; - $self->build; + $self->build(%params); $self->update_tree; $self->_update; if ($self->hidden_options) { @@ -985,6 +985,7 @@ sub title { 'Printer Settings' } sub build { my $self = shift; + my (%params) = @_; $self->init_config_options(qw( bed_shape z_offset @@ -1064,6 +1065,7 @@ sub build { } }); } + if (!$params{no_controller}) { my $optgroup = $page->new_optgroup('USB/Serial connection'); my $line = Slic3r::GUI::OptionsGroup::Line->new( @@ -1239,7 +1241,7 @@ sub build { $self->{extruder_pages} = []; $self->_build_extruder_pages; - $self->_update_serial_ports; + $self->_update_serial_ports if (!$params{no_controller}); } sub _update_serial_ports { @@ -1341,11 +1343,14 @@ sub _update { my $config = $self->{config}; - $self->get_field('serial_speed')->toggle($config->get('serial_port')); - if ($config->get('serial_speed') && $config->get('serial_port')) { - $self->{serial_test_btn}->Enable; - } else { - $self->{serial_test_btn}->Disable; + my $serial_speed = $self->get_field('serial_speed'); + if ($serial_speed) { + $self->get_field('serial_speed')->toggle($config->get('serial_port')); + if ($config->get('serial_speed') && $config->get('serial_port')) { + $self->{serial_test_btn}->Enable; + } else { + $self->{serial_test_btn}->Disable; + } } if ($config->get('octoprint_host') && eval "use LWP::UserAgent; 1") { $self->{octoprint_host_test_btn}->Enable; diff --git a/slic3r.pl b/slic3r.pl index db3fca5fe8..cc6192641c 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -32,6 +32,7 @@ my %cli_options = (); 'load=s@' => \$opt{load}, 'autosave=s' => \$opt{autosave}, 'ignore-nonexistent-config' => \$opt{ignore_nonexistent_config}, + 'no-controller' => \$opt{no_controller}, 'no-plater' => \$opt{no_plater}, 'gui-mode=s' => \$opt{gui_mode}, 'datadir=s' => \$opt{datadir}, @@ -99,10 +100,11 @@ my $gui; if ((!@ARGV || $opt{gui}) && !$opt{save} && eval "require Slic3r::GUI; 1") { { no warnings 'once'; - $Slic3r::GUI::datadir = Slic3r::decode_path($opt{datadir} // ''); - $Slic3r::GUI::no_plater = $opt{no_plater}; - $Slic3r::GUI::mode = $opt{gui_mode}; - $Slic3r::GUI::autosave = $opt{autosave}; + $Slic3r::GUI::datadir = Slic3r::decode_path($opt{datadir} // ''); + $Slic3r::GUI::no_controller = $opt{no_controller}; + $Slic3r::GUI::no_plater = $opt{no_plater}; + $Slic3r::GUI::mode = $opt{gui_mode}; + $Slic3r::GUI::autosave = $opt{autosave}; } $gui = Slic3r::GUI->new; setlocale(LC_NUMERIC, 'C'); From 9e8022f6f62b6f4c07b5846a765128b3609e53ef Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Fri, 20 May 2016 06:24:05 +0200 Subject: [PATCH 05/13] More refactoring to medial axis and gap fill, more robust --- t/thin.t | 19 +++++- xs/src/libslic3r/ExPolygon.cpp | 37 ++++++----- xs/src/libslic3r/ExPolygon.hpp | 1 + xs/src/libslic3r/Geometry.cpp | 87 +++++++++++++++---------- xs/src/libslic3r/Geometry.hpp | 4 +- xs/src/libslic3r/Line.cpp | 6 ++ xs/src/libslic3r/Line.hpp | 1 + xs/src/libslic3r/MultiPoint.cpp | 13 ++++ xs/src/libslic3r/MultiPoint.hpp | 1 + xs/src/libslic3r/PerimeterGenerator.cpp | 2 +- xs/src/libslic3r/Point.cpp | 16 +++++ xs/src/libslic3r/Point.hpp | 2 + xs/xsp/Line.xsp | 2 + 13 files changed, 133 insertions(+), 58 deletions(-) diff --git a/t/thin.t b/t/thin.t index 276a29e2b8..5146148025 100644 --- a/t/thin.t +++ b/t/thin.t @@ -1,4 +1,4 @@ -use Test::More tests => 21; +use Test::More tests => 23; use strict; use warnings; @@ -8,7 +8,7 @@ BEGIN { } use Slic3r; -use List::Util qw(first sum); +use List::Util qw(first sum none); use Slic3r::Geometry qw(epsilon scale unscale scaled_epsilon Y); use Slic3r::Test; @@ -91,7 +91,20 @@ if (0) { is scalar(@$res), 1, 'medial axis of a narrow rectangle with an extra vertex is still a single line'; ok unscale($res->[0]->length) >= (200-100 - (120-100)) - epsilon, 'medial axis has still a reasonable length'; ok !(grep { abs($_ - scale 150) < scaled_epsilon } map $_->[Y], map @$_, @$res2), "extra vertices don't influence medial axis"; +} + +{ + my $expolygon = Slic3r::ExPolygon->new( + Slic3r::Polygon->new([1185881,829367],[1421988,1578184],[1722442,2303558],[2084981,2999998],[2506843,3662186],[2984809,4285086],[3515250,4863959],[4094122,5394400],[4717018,5872368],[5379210,6294226],[6075653,6656769],[6801033,6957229],[7549842,7193328],[8316383,7363266],[9094809,7465751],[9879211,7500000],[10663611,7465750],[11442038,7363265],[12208580,7193327],[12957389,6957228],[13682769,6656768],[14379209,6294227],[15041405,5872366],[15664297,5394401],[16243171,4863960],[16758641,4301424],[17251579,3662185],[17673439,3000000],[18035980,2303556],[18336441,1578177],[18572539,829368],[18750748,0],[19758422,0],[19727293,236479],[19538467,1088188],[19276136,1920196],[18942292,2726179],[18539460,3499999],[18070731,4235755],[17539650,4927877],[16950279,5571067],[16307090,6160437],[15614974,6691519],[14879209,7160248],[14105392,7563079],[13299407,7896927],[12467399,8159255],[11615691,8348082],[10750769,8461952],[9879211,8500000],[9007652,8461952],[8142729,8348082],[7291022,8159255],[6459015,7896927],[5653029,7563079],[4879210,7160247],[4143447,6691519],[3451331,6160437],[2808141,5571066],[2218773,4927878],[1687689,4235755],[1218962,3499999],[827499,2748020],[482284,1920196],[219954,1088186],[31126,236479],[0,0],[1005754,0]), + ); + my $res = $expolygon->medial_axis(scale 1.324888, scale 0.25); + is scalar(@$res), 1, 'medial axis of a semicircumference is a single line'; + # check whether turns are all CCW or all CW + my @lines = @{$res->[0]->lines}; + my @angles = map { $lines[$_-1]->ccw($lines[$_]->b) } 1..$#lines; + ok !!(none { $_ < 0 } @angles) || (none { $_ > 0 } @angles), + 'all medial axis segments of a semicircumference have the same orientation'; } { @@ -136,7 +149,7 @@ if (0) { { my $expolygon = Slic3r::ExPolygon->new(Slic3r::Polygon->new_scale( [50, 100], - [300, 102], + [1000, 102], [50, 104], )); my $res = $expolygon->medial_axis(scale 4, scale 0.5); diff --git a/xs/src/libslic3r/ExPolygon.cpp b/xs/src/libslic3r/ExPolygon.cpp index c84812fdfd..3640d39188 100644 --- a/xs/src/libslic3r/ExPolygon.cpp +++ b/xs/src/libslic3r/ExPolygon.cpp @@ -174,17 +174,10 @@ void ExPolygon::medial_axis(double max_width, double min_width, ThickPolylines* polylines) const { // init helper object - Slic3r::Geometry::MedialAxis ma(max_width, min_width); - ma.expolygon = this; + Slic3r::Geometry::MedialAxis ma(max_width, min_width, this); + ma.lines = this->lines(); - // populate list of segments for the Voronoi diagram - ma.lines = this->contour.lines(); - for (Polygons::const_iterator hole = this->holes.begin(); hole != this->holes.end(); ++hole) { - Lines lines = hole->lines(); - ma.lines.insert(ma.lines.end(), lines.begin(), lines.end()); - } - - // compute the Voronoi diagram + // compute the Voronoi diagram and extract medial axis polylines ThickPolylines pp; ma.build(&pp); @@ -195,15 +188,14 @@ ExPolygon::medial_axis(double max_width, double min_width, ThickPolylines* polyl svg.Close(); */ - // find the maximum width returned + /* Find the maximum width returned; we're going to use this for validating and + filtering the output segments. */ double max_w = 0; - if (!pp.empty()) { - std::vector widths; - for (ThickPolylines::const_iterator it = pp.begin(); it != pp.end(); ++it) - widths.insert(widths.end(), it->width.begin(), it->width.end()); - max_w = *std::max_element(widths.begin(), widths.end()); - } + for (ThickPolylines::const_iterator it = pp.begin(); it != pp.end(); ++it) + max_w = fmaxf(max_w, *std::max_element(it->width.begin(), it->width.end())); + /* Loop through all returned polylines in order to extend their endpoints to the + expolygon boundaries */ bool removed = false; for (size_t i = 0; i < pp.size(); ++i) { ThickPolyline& polyline = pp[i]; @@ -502,4 +494,15 @@ ExPolygon::lines() const return lines; } +std::string +ExPolygon::dump_perl() const +{ + std::ostringstream ret; + ret << "[" << this->contour.dump_perl(); + for (Polygons::const_iterator h = this->holes.begin(); h != this->holes.end(); ++h) + ret << "," << h->dump_perl(); + ret << "]"; + return ret.str(); +} + } diff --git a/xs/src/libslic3r/ExPolygon.hpp b/xs/src/libslic3r/ExPolygon.hpp index f23178cc08..69fe9fb0ee 100644 --- a/xs/src/libslic3r/ExPolygon.hpp +++ b/xs/src/libslic3r/ExPolygon.hpp @@ -42,6 +42,7 @@ class ExPolygon void triangulate_pp(Polygons* polygons) const; void triangulate_p2t(Polygons* polygons) const; Lines lines() const; + std::string dump_perl() const; }; } diff --git a/xs/src/libslic3r/Geometry.cpp b/xs/src/libslic3r/Geometry.cpp index d4528e8645..6d864f6313 100644 --- a/xs/src/libslic3r/Geometry.cpp +++ b/xs/src/libslic3r/Geometry.cpp @@ -324,7 +324,7 @@ MedialAxis::build(ThickPolylines* polylines) if (edge->is_secondary() || edge->is_infinite()) continue; // don't re-validate twins - if (seen_edges.find(&*edge) != seen_edges.end()) continue; + if (seen_edges.find(&*edge) != seen_edges.end()) continue; // TODO: is this needed? seen_edges.insert(&*edge); seen_edges.insert(edge->twin()); @@ -445,49 +445,66 @@ MedialAxis::validate_edge(const VD::edge_type* edge) } // retrieve the original line segments which generated the edge we're checking - const VD::cell_type* cell1 = edge->cell(); - const VD::cell_type* cell2 = edge->twin()->cell(); - const Line &segment1 = this->retrieve_segment(cell1); - const Line &segment2 = this->retrieve_segment(cell2); + const VD::cell_type* cell_l = edge->cell(); + const VD::cell_type* cell_r = edge->twin()->cell(); + const Line &segment_l = this->retrieve_segment(cell_l); + const Line &segment_r = this->retrieve_segment(cell_r); - /* Calculate thickness of the section at both the endpoints of this edge. - Our Voronoi edge is part of a CCW sequence going around its Voronoi cell - (segment1). This edge's twin goes around segment2. Thus, segment2 is - oriented in the same direction as our main edge, and segment1 is oriented + /* + SVG svg("edge.svg"); + svg.draw(*this->expolygon); + svg.draw(line); + svg.draw(segment_l, "red"); + svg.draw(segment_r, "blue"); + svg.Close(); + */ + + /* Calculate thickness of the cross-section at both the endpoints of this edge. + Our Voronoi edge is part of a CCW sequence going around its Voronoi cell + located on the left side. (segment_l). + This edge's twin goes around segment_r. Thus, segment_r is + oriented in the same direction as our main edge, and segment_l is oriented in the same direction as our twin edge. - We used to only consider the (half-)distances to segment2, and that works - whenever segment1 and segment2 are almost specular and facing. However, + We used to only consider the (half-)distances to segment_r, and that works + whenever segment_l and segment_r are almost specular and facing. However, at curves they are staggered and they only face for a very little length - (such visibility actually coincides with our very short edge). This is why - we calculate w0 and w1 this way. - When cell1 or cell2 don't refer to the segment but only to an endpoint, we + (our very short edge represents such visibility). + Both w0 and w1 can be calculated either towards cell_l or cell_r with equal + results by Voronoi definition. + When cell_l or cell_r don't refer to the segment but only to an endpoint, we calculate the distance to that endpoint instead. */ - coordf_t w0 = cell2->contains_segment() - ? line.a.perp_distance_to(segment2)*2 - : line.a.distance_to(this->retrieve_endpoint(cell2))*2; + coordf_t w0 = cell_r->contains_segment() + ? line.a.distance_to(segment_r)*2 + : line.a.distance_to(this->retrieve_endpoint(cell_r))*2; - coordf_t w1 = cell1->contains_segment() - ? line.b.perp_distance_to(segment1)*2 - : line.b.distance_to(this->retrieve_endpoint(cell1))*2; + coordf_t w1 = cell_l->contains_segment() + ? line.b.distance_to(segment_l)*2 + : line.b.distance_to(this->retrieve_endpoint(cell_l))*2; - // if this edge is the centerline for a very thin area, we might want to skip it - // in case the area is too thin - if (w0 < SCALED_EPSILON || w1 < SCALED_EPSILON) { - if (cell1->contains_segment() && cell2->contains_segment()) { - // calculate the relative angle between the two boundary segments - double angle = fabs(segment2.orientation() - segment1.orientation()); + if (cell_l->contains_segment() && cell_r->contains_segment()) { + // calculate the relative angle between the two boundary segments + double angle = fabs(segment_r.orientation() - segment_l.orientation()); + if (angle > PI) angle = 2*PI - angle; + assert(angle >= 0 && angle <= PI); + + // fabs(angle) ranges from 0 (collinear, same direction) to PI (collinear, opposite direction) + // we're interested only in segments close to the second case (facing segments) + // so we allow some tolerance. + // this filter ensures that we're dealing with a narrow/oriented area (longer than thick) + // we don't run it on edges not generated by two segments (thus generated by one segment + // and the endpoint of another segment), since their orientation would not be meaningful + if (PI - angle > PI/8) { + // angle is not narrow enough - // fabs(angle) ranges from 0 (collinear, same direction) to PI (collinear, opposite direction) - // we're interested only in segments close to the second case (facing segments) - // so we allow some tolerance. - // this filter ensures that we're dealing with a narrow/oriented area (longer than thick) - // we don't run it on edges not generated by two segments (thus generated by one segment - // and the endpoint of another segment), since their orientation would not be meaningful - if (fabs(angle - PI) > PI/5) return false; - } else { - return false; + // only apply this filter to segments that are not too short otherwise their + // angle could possibly be not meaningful + if (w0 < SCALED_EPSILON || w1 < SCALED_EPSILON || line.length() >= this->min_width) + return false; } + } else { + if (w0 < SCALED_EPSILON || w1 < SCALED_EPSILON) + return false; } if (w0 < this->min_width && w1 < this->min_width) diff --git a/xs/src/libslic3r/Geometry.hpp b/xs/src/libslic3r/Geometry.hpp index af4667d42c..14bc3f0ca8 100644 --- a/xs/src/libslic3r/Geometry.hpp +++ b/xs/src/libslic3r/Geometry.hpp @@ -46,8 +46,8 @@ class MedialAxis { const ExPolygon* expolygon; double max_width; double min_width; - MedialAxis(double _max_width, double _min_width) - : max_width(_max_width), min_width(_min_width), expolygon(NULL) {}; + MedialAxis(double _max_width, double _min_width, const ExPolygon* _expolygon = NULL) + : max_width(_max_width), min_width(_min_width), expolygon(_expolygon) {}; void build(ThickPolylines* polylines); void build(Polylines* polylines); diff --git a/xs/src/libslic3r/Line.cpp b/xs/src/libslic3r/Line.cpp index c98750e846..c7afc80c74 100644 --- a/xs/src/libslic3r/Line.cpp +++ b/xs/src/libslic3r/Line.cpp @@ -212,6 +212,12 @@ Line::intersection(const Line& line, Point* intersection) const return false; // not intersecting } +double +Line::ccw(const Point& point) const +{ + return point.ccw(*this); +} + Pointf3 Linef3::intersect_plane(double z) const { diff --git a/xs/src/libslic3r/Line.hpp b/xs/src/libslic3r/Line.hpp index ae1f4cb7d0..42e811449c 100644 --- a/xs/src/libslic3r/Line.hpp +++ b/xs/src/libslic3r/Line.hpp @@ -44,6 +44,7 @@ class Line void extend_end(double distance); void extend_start(double distance); bool intersection(const Line& line, Point* intersection) const; + double ccw(const Point& point) const; }; class ThickLine : public Line diff --git a/xs/src/libslic3r/MultiPoint.cpp b/xs/src/libslic3r/MultiPoint.cpp index ff2771cff5..6857d6393e 100644 --- a/xs/src/libslic3r/MultiPoint.cpp +++ b/xs/src/libslic3r/MultiPoint.cpp @@ -128,6 +128,19 @@ MultiPoint::intersection(const Line& line, Point* intersection) const return false; } +std::string +MultiPoint::dump_perl() const +{ + std::ostringstream ret; + ret << "["; + for (Points::const_iterator p = this->points.begin(); p != this->points.end(); ++p) { + ret << p->dump_perl(); + if (p != this->points.end()-1) ret << ","; + } + ret << "]"; + return ret.str(); +} + Points MultiPoint::_douglas_peucker(const Points &points, const double tolerance) { diff --git a/xs/src/libslic3r/MultiPoint.hpp b/xs/src/libslic3r/MultiPoint.hpp index 18d67a9e4c..d057b14f12 100644 --- a/xs/src/libslic3r/MultiPoint.hpp +++ b/xs/src/libslic3r/MultiPoint.hpp @@ -37,6 +37,7 @@ class MultiPoint void append(const Points &points); void append(const Points::const_iterator &begin, const Points::const_iterator &end); bool intersection(const Line& line, Point* intersection) const; + std::string dump_perl() const; static Points _douglas_peucker(const Points &points, const double tolerance); }; diff --git a/xs/src/libslic3r/PerimeterGenerator.cpp b/xs/src/libslic3r/PerimeterGenerator.cpp index d7fdcbfae2..7bb207e000 100644 --- a/xs/src/libslic3r/PerimeterGenerator.cpp +++ b/xs/src/libslic3r/PerimeterGenerator.cpp @@ -92,7 +92,7 @@ PerimeterGenerator::process() // the following offset2 ensures almost nothing in @thin_walls is narrower than $min_width // (actually, something larger than that still may exist due to mitering or other causes) - coord_t min_width = scale_(this->ext_perimeter_flow.nozzle_diameter / 2); + coord_t min_width = scale_(this->ext_perimeter_flow.nozzle_diameter / 3); ExPolygons expp = offset2_ex(diffpp, -min_width/2, +min_width/2); // the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop diff --git a/xs/src/libslic3r/Point.cpp b/xs/src/libslic3r/Point.cpp index dc9d510c69..29ce0b1532 100644 --- a/xs/src/libslic3r/Point.cpp +++ b/xs/src/libslic3r/Point.cpp @@ -26,6 +26,14 @@ Point::wkt() const return ss.str(); } +std::string +Point::dump_perl() const +{ + std::ostringstream ss; + ss << "[" << this->x << "," << this->y << "]"; + return ss.str(); +} + void Point::scale(double factor) { @@ -313,6 +321,14 @@ Pointf::wkt() const return ss.str(); } +std::string +Pointf::dump_perl() const +{ + std::ostringstream ss; + ss << "[" << this->x << "," << this->y << "]"; + return ss.str(); +} + void Pointf::scale(double factor) { diff --git a/xs/src/libslic3r/Point.hpp b/xs/src/libslic3r/Point.hpp index dbd1219b9e..6638e0eb3f 100644 --- a/xs/src/libslic3r/Point.hpp +++ b/xs/src/libslic3r/Point.hpp @@ -38,6 +38,7 @@ class Point }; bool operator==(const Point& rhs) const; std::string wkt() const; + std::string dump_perl() const; void scale(double factor); void translate(double x, double y); void translate(const Vector &vector); @@ -87,6 +88,7 @@ class Pointf return Pointf(unscale(p.x), unscale(p.y)); }; std::string wkt() const; + std::string dump_perl() const; void scale(double factor); void translate(double x, double y); void translate(const Vectorf &vector); diff --git a/xs/xsp/Line.xsp b/xs/xsp/Line.xsp index 461856a1a6..92429e57a8 100644 --- a/xs/xsp/Line.xsp +++ b/xs/xsp/Line.xsp @@ -41,6 +41,8 @@ %code{% RETVAL = Polyline(*THIS); %}; Clone normal(); Clone vector(); + double ccw(Point* point) + %code{% RETVAL = THIS->ccw(*point); %}; %{ Line* From ea9b10c7640e5a293024dc19f0f2babbdb347701 Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Sun, 29 May 2016 10:56:21 -0500 Subject: [PATCH 06/13] Added a short OpenSCAD description to aid in the creation of simple modifier meshes that describe a change every N layers --- utils/modifier_helpers/solid_layers.scad | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 utils/modifier_helpers/solid_layers.scad diff --git a/utils/modifier_helpers/solid_layers.scad b/utils/modifier_helpers/solid_layers.scad new file mode 100644 index 0000000000..80a92fee03 --- /dev/null +++ b/utils/modifier_helpers/solid_layers.scad @@ -0,0 +1,24 @@ +// Used to generate a modifier mesh to do something every few layers. +// Load into OpenSCAD, tweak the variables below, export as STL and load as +// a modifier mesh. Then change settings for the modifier mesh. + +// Written by Joseph Lenox; in public domain. + +layer_height = 0.3; // set to layer height in slic3r for "best" results. +number_of_solid_layers = 2; +N = 4; // N > number_of_solid_layers or else the whole thing will be solid +model_height = 300.0; +model_width = 300.0; // these two should be at least as big as the model +model_depth = 300.0; // but bigger isn't a problem +initial_offset=0; // don't generate below this + +position_on_bed=[0,0,0]; // in case you need to move it around + +// don't touch below unless you know what you are doing. +simple_layers = round(model_height/0.3); +translate(position_on_bed) + for (i = [initial_offset:N:simple_layers]) { + translate([0,0,i*layer_height]) + translate([0,0,(layer_height*number_of_solid_layers)/2]) + cube([model_width,model_depth,layer_height*number_of_solid_layers], center=true); + } From 30f6e4b16f94b167b28521d71786aeea7cc4585b Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 24 May 2016 03:47:21 +0200 Subject: [PATCH 07/13] Bugfix: homing was not correctly saved --- lib/Slic3r/GUI/Controller/ManualControlDialog.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Slic3r/GUI/Controller/ManualControlDialog.pm b/lib/Slic3r/GUI/Controller/ManualControlDialog.pm index 399c397cb6..a8209f9888 100644 --- a/lib/Slic3r/GUI/Controller/ManualControlDialog.pm +++ b/lib/Slic3r/GUI/Controller/ManualControlDialog.pm @@ -182,8 +182,8 @@ sub home { $self->sender->send(sprintf("G28 %s", $axis), 1); $self->{canvas}->set_pos(undef); - $self->x_homed if $axis eq 'X'; - $self->y_homed if $axis eq 'Y'; + $self->x_homed(1) if $axis eq 'X'; + $self->y_homed(1) if $axis eq 'Y'; } 1; From 2a8c139ca42c759a590bb72a23257140789399a9 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 24 May 2016 03:54:52 +0200 Subject: [PATCH 08/13] Add XYZ homing button to printer manual control --- lib/Slic3r/GUI/Controller/ManualControlDialog.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Slic3r/GUI/Controller/ManualControlDialog.pm b/lib/Slic3r/GUI/Controller/ManualControlDialog.pm index a8209f9888..ebd0031a9c 100644 --- a/lib/Slic3r/GUI/Controller/ManualControlDialog.pm +++ b/lib/Slic3r/GUI/Controller/ManualControlDialog.pm @@ -87,7 +87,8 @@ sub new { $bed_sizer->Add($sizer, 1, wxEXPAND, 0); } - $bed_sizer->AddSpacer(0); + # XYZ home button + $move_button->($bed_sizer, 'XYZ', 'house', 1, wxTOP, sub { $self->home(undef) }); # X buttons { @@ -180,6 +181,7 @@ sub rel_move { sub home { my ($self, $axis) = @_; + $axis //= ''; $self->sender->send(sprintf("G28 %s", $axis), 1); $self->{canvas}->set_pos(undef); $self->x_homed(1) if $axis eq 'X'; From 08a2775dbdc54179c755095f3d9c81c4303f5fee Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Tue, 31 May 2016 19:14:20 -0500 Subject: [PATCH 09/13] Update solid_layers.scad Oops, left a hardcoded 0.3 in. Fixed. --- utils/modifier_helpers/solid_layers.scad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/modifier_helpers/solid_layers.scad b/utils/modifier_helpers/solid_layers.scad index 80a92fee03..3782949495 100644 --- a/utils/modifier_helpers/solid_layers.scad +++ b/utils/modifier_helpers/solid_layers.scad @@ -15,7 +15,7 @@ initial_offset=0; // don't generate below this position_on_bed=[0,0,0]; // in case you need to move it around // don't touch below unless you know what you are doing. -simple_layers = round(model_height/0.3); +simple_layers = round(model_height/layer_height); translate(position_on_bed) for (i = [initial_offset:N:simple_layers]) { translate([0,0,i*layer_height]) From 39dfee79c71507ec67edb872e3eef88ded670282 Mon Sep 17 00:00:00 2001 From: Vanessa Ezekowitz Date: Wed, 1 Jun 2016 17:47:54 -0400 Subject: [PATCH 10/13] Mention anti-ooze sacrificial skirt feature. --- xs/src/libslic3r/PrintConfig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 6fcb0864e2..47609aaff8 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -1015,7 +1015,7 @@ PrintConfigDef::PrintConfigDef() def = this->add("standby_temperature_delta", coInt); def->label = "Temperature variation"; - def->tooltip = "Temperature difference to be applied when an extruder is not active."; + def->tooltip = "Temperature difference to be applied when an extruder is not active. Enables a full-height \"sacrificial\" skirt on which the nozzles are periodically wiped."; def->sidetext = "∆°C"; def->cli = "standby-temperature-delta=i"; def->min = -500; From 5e1774642796ae04dc048e92b13bfe7a96ed1598 Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Thu, 2 Jun 2016 11:43:34 -0500 Subject: [PATCH 11/13] Post process script for fan kickstart Addresses #3308 --- utils/post-processing/fan_kickstart.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 utils/post-processing/fan_kickstart.py diff --git a/utils/post-processing/fan_kickstart.py b/utils/post-processing/fan_kickstart.py new file mode 100644 index 0000000000..9ee1bc0a4a --- /dev/null +++ b/utils/post-processing/fan_kickstart.py @@ -0,0 +1,13 @@ +#!/usr/bin/python +import sys +import re + +sea = re.compile("M106 S[1-9]+[0-9]*") +rep = re.compile("M106 S255\n\g<0>") +out = open(sys.argv[1]+"_fixed", 'w') + with open(sys.argv[1]) as f: + for r in f: + if re.search(sea, r) is not None: + out.write(re.sub(sea,"M106 S255\n\g<0>",r)) + else: + out.write(r) From 223065221888e202a762bfeaff125f960896b009 Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Thu, 2 Jun 2016 19:18:29 -0500 Subject: [PATCH 12/13] Added simple JSCAD modifier helper Simple cube oriented around the center with a parametric interface. Just copy/paste into openjscad.org and hit shift+enter. --- utils/modifier_helpers/layer_generator.jscad | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 utils/modifier_helpers/layer_generator.jscad diff --git a/utils/modifier_helpers/layer_generator.jscad b/utils/modifier_helpers/layer_generator.jscad new file mode 100644 index 0000000000..fc193a53f9 --- /dev/null +++ b/utils/modifier_helpers/layer_generator.jscad @@ -0,0 +1,19 @@ +// title: Layer_generator +// written by: Joseph Lenox +// Used for generating cubes oriented about the center +// for making simple modifier meshes. + +var width = 100; +var layer_height = 0.3; +var z = 30; +function main() { + + return cube(size=[width,width,layer_height], center=true).translate([0,0,z]); +} +function getParameterDefinitions() { + return [ + { name: 'width', type: 'float', initial: 100, caption: "Width of the cube:" }, + { name: 'layer_height', type: 'float', initial: 0.3, caption: "Layer height used:" }, + { name: 'z', type: 'float', initial: 0, caption: "Z:" } + ]; +} From 36231347f9bd683c5196d3ee6e1e2447ac5ced95 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 20 Jun 2016 21:02:15 +0200 Subject: [PATCH 13/13] Partially ported Format::STL and Format::OBJ to XS --- xs/MANIFEST | 2 ++ xs/src/admesh/shared.c | 2 +- xs/src/admesh/stl.h | 6 ++-- xs/src/admesh/stlinit.c | 4 +-- xs/src/libslic3r/IO.cpp | 47 +++++++++++++++++++++++++++++++ xs/src/libslic3r/IO.hpp | 26 +++++++++++++++++ xs/src/libslic3r/TriangleMesh.cpp | 16 +++++------ xs/src/libslic3r/TriangleMesh.hpp | 8 +++--- xs/xsp/TriangleMesh.xsp | 8 +++--- 9 files changed, 97 insertions(+), 22 deletions(-) create mode 100644 xs/src/libslic3r/IO.cpp create mode 100644 xs/src/libslic3r/IO.hpp diff --git a/xs/MANIFEST b/xs/MANIFEST index 0f541515da..4e544d472c 100644 --- a/xs/MANIFEST +++ b/xs/MANIFEST @@ -38,6 +38,8 @@ src/libslic3r/GCodeWriter.cpp src/libslic3r/GCodeWriter.hpp src/libslic3r/Geometry.cpp src/libslic3r/Geometry.hpp +src/libslic3r/IO.cpp +src/libslic3r/IO.hpp src/libslic3r/Layer.cpp src/libslic3r/Layer.hpp src/libslic3r/LayerRegion.cpp diff --git a/xs/src/admesh/shared.c b/xs/src/admesh/shared.c index 56164e25fc..19c7da70ec 100644 --- a/xs/src/admesh/shared.c +++ b/xs/src/admesh/shared.c @@ -234,7 +234,7 @@ stl_write_vrml(stl_file *stl, char *file) { fclose(fp); } -void stl_write_obj (stl_file *stl, char *file) { +void stl_write_obj (stl_file *stl, const char *file) { int i; FILE* fp; diff --git a/xs/src/admesh/stl.h b/xs/src/admesh/stl.h index 25fe770aa8..3013a887c9 100644 --- a/xs/src/admesh/stl.h +++ b/xs/src/admesh/stl.h @@ -135,7 +135,7 @@ typedef struct { } stl_file; -extern void stl_open(stl_file *stl, char *file); +extern void stl_open(stl_file *stl, const char *file); extern void stl_close(stl_file *stl); extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file); extern void stl_print_edges(stl_file *stl, FILE *file); @@ -171,7 +171,7 @@ extern void stl_mirror_xz(stl_file *stl); extern void stl_open_merge(stl_file *stl, char *file); extern void stl_invalidate_shared_vertices(stl_file *stl); extern void stl_generate_shared_vertices(stl_file *stl); -extern void stl_write_obj(stl_file *stl, char *file); +extern void stl_write_obj(stl_file *stl, const char *file); extern void stl_write_off(stl_file *stl, char *file); extern void stl_write_dxf(stl_file *stl, char *file, char *label); extern void stl_write_vrml(stl_file *stl, char *file); @@ -182,7 +182,7 @@ extern void stl_calculate_volume(stl_file *stl); extern void stl_repair(stl_file *stl, int fixall_flag, int exact_flag, int tolerance_flag, float tolerance, int increment_flag, float increment, int nearby_flag, int iterations, int remove_unconnected_flag, int fill_holes_flag, int normal_directions_flag, int normal_values_flag, int reverse_all_flag, int verbose_flag); extern void stl_initialize(stl_file *stl); -extern void stl_count_facets(stl_file *stl, char *file); +extern void stl_count_facets(stl_file *stl, const char *file); extern void stl_allocate(stl_file *stl); extern void stl_read(stl_file *stl, int first_facet, int first); extern void stl_facet_stats(stl_file *stl, stl_facet facet, int first); diff --git a/xs/src/admesh/stlinit.c b/xs/src/admesh/stlinit.c index 3a5de90525..58f6947c73 100644 --- a/xs/src/admesh/stlinit.c +++ b/xs/src/admesh/stlinit.c @@ -34,7 +34,7 @@ #endif void -stl_open(stl_file *stl, char *file) { +stl_open(stl_file *stl, const char *file) { stl_initialize(stl); stl_count_facets(stl, file); stl_allocate(stl); @@ -65,7 +65,7 @@ stl_initialize(stl_file *stl) { } void -stl_count_facets(stl_file *stl, char *file) { +stl_count_facets(stl_file *stl, const char *file) { long file_size; int header_num_facets; int num_facets; diff --git a/xs/src/libslic3r/IO.cpp b/xs/src/libslic3r/IO.cpp new file mode 100644 index 0000000000..81ac8a127e --- /dev/null +++ b/xs/src/libslic3r/IO.cpp @@ -0,0 +1,47 @@ +#include "IO.hpp" +#include + +namespace Slic3r { namespace IO { + +bool +STL::read_file(std::string input_file, Model* model) +{ + // TODO: encode file name + // TODO: check that file exists + + TriangleMesh mesh; + mesh.ReadSTLFile(input_file); + mesh.repair(); + + if (mesh.facets_count() == 0) + throw std::runtime_error("This STL file couldn't be read because it's empty."); + + ModelObject* object = model->add_object(); + object->name = input_file; // TODO: use basename() + object->input_file = input_file; + + ModelVolume* volume = object->add_volume(mesh); + volume->name = input_file; // TODO: use basename() + + return true; +} + +bool +STL::write(TriangleMesh& mesh, std::string output_file, bool binary) +{ + if (binary) { + mesh.write_binary(output_file); + } else { + mesh.write_ascii(output_file); + } + return true; +} + +bool +OBJ::write(TriangleMesh& mesh, std::string output_file) +{ + mesh.WriteOBJFile(output_file); + return true; +} + +} } diff --git a/xs/src/libslic3r/IO.hpp b/xs/src/libslic3r/IO.hpp new file mode 100644 index 0000000000..248f3be540 --- /dev/null +++ b/xs/src/libslic3r/IO.hpp @@ -0,0 +1,26 @@ +#ifndef slic3r_IO_hpp_ +#define slic3r_IO_hpp_ + +#include "libslic3r.h" +#include "Model.hpp" +#include "TriangleMesh.hpp" +#include + +namespace Slic3r { namespace IO { + +class STL +{ + public: + bool read_file(std::string input_file, Model* model); + bool write(TriangleMesh& mesh, std::string output_file, bool binary = true); +}; + +class OBJ +{ + public: + bool write(TriangleMesh& mesh, std::string output_file); +}; + +} } + +#endif diff --git a/xs/src/libslic3r/TriangleMesh.cpp b/xs/src/libslic3r/TriangleMesh.cpp index 484fee9fc1..40d0e480b1 100644 --- a/xs/src/libslic3r/TriangleMesh.cpp +++ b/xs/src/libslic3r/TriangleMesh.cpp @@ -70,20 +70,20 @@ TriangleMesh::~TriangleMesh() { } void -TriangleMesh::ReadSTLFile(char* input_file) { - stl_open(&stl, input_file); +TriangleMesh::ReadSTLFile(const std::string &input_file) { + stl_open(&stl, input_file.c_str()); } void -TriangleMesh::write_ascii(char* output_file) +TriangleMesh::write_ascii(const std::string &output_file) { - stl_write_ascii(&this->stl, output_file, ""); + stl_write_ascii(&this->stl, output_file.c_str(), ""); } void -TriangleMesh::write_binary(char* output_file) +TriangleMesh::write_binary(const std::string &output_file) { - stl_write_binary(&this->stl, output_file, ""); + stl_write_binary(&this->stl, output_file.c_str(), ""); } void @@ -173,9 +173,9 @@ TriangleMesh::facets_count() const } void -TriangleMesh::WriteOBJFile(char* output_file) { +TriangleMesh::WriteOBJFile(const std::string &output_file) { stl_generate_shared_vertices(&stl); - stl_write_obj(&stl, output_file); + stl_write_obj(&stl, output_file.c_str()); } void TriangleMesh::scale(float factor) diff --git a/xs/src/libslic3r/TriangleMesh.hpp b/xs/src/libslic3r/TriangleMesh.hpp index cf129809a2..0eb62d65e0 100644 --- a/xs/src/libslic3r/TriangleMesh.hpp +++ b/xs/src/libslic3r/TriangleMesh.hpp @@ -24,11 +24,11 @@ class TriangleMesh TriangleMesh& operator= (TriangleMesh other); void swap(TriangleMesh &other); ~TriangleMesh(); - void ReadSTLFile(char* input_file); - void write_ascii(char* output_file); - void write_binary(char* output_file); + void ReadSTLFile(const std::string &input_file); + void write_ascii(const std::string &output_file); + void write_binary(const std::string &output_file); void repair(); - void WriteOBJFile(char* output_file); + void WriteOBJFile(const std::string &output_file); void scale(float factor); void scale(const Pointf3 &versor); void translate(float x, float y, float z); diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp index c7324f98d1..7c13cb7f4a 100644 --- a/xs/xsp/TriangleMesh.xsp +++ b/xs/xsp/TriangleMesh.xsp @@ -10,11 +10,11 @@ ~TriangleMesh(); Clone clone() %code{% RETVAL = THIS; %}; - void ReadSTLFile(char* input_file); - void write_ascii(char* output_file); - void write_binary(char* output_file); + void ReadSTLFile(std::string input_file); + void write_ascii(std::string output_file); + void write_binary(std::string output_file); void repair(); - void WriteOBJFile(char* output_file); + void WriteOBJFile(std::string output_file); void scale(float factor); void scale_xyz(Pointf3* versor) %code{% THIS->scale(*versor); %};