Browse Source

New options dialog for SLAPrint

Alessandro Ranellucci 8 years ago
parent
commit
92845300be

+ 1 - 0
lib/Slic3r/Config.pm

@@ -421,5 +421,6 @@ sub Slic3r::Config::Print::new { Slic3r::Config::Static::new_PrintConfig }
 sub Slic3r::Config::PrintObject::new { Slic3r::Config::Static::new_PrintObjectConfig }
 sub Slic3r::Config::PrintRegion::new { Slic3r::Config::Static::new_PrintRegionConfig }
 sub Slic3r::Config::Full::new { Slic3r::Config::Static::new_FullPrintConfig }
+sub Slic3r::Config::SLAPrint::new { Slic3r::Config::Static::new_SLAPrintConfig }
 
 1;

+ 1 - 0
lib/Slic3r/GUI.pm

@@ -31,6 +31,7 @@ use Slic3r::GUI::Projector;
 use Slic3r::GUI::OptionsGroup;
 use Slic3r::GUI::OptionsGroup::Field;
 use Slic3r::GUI::SimpleTab;
+use Slic3r::GUI::SLAPrintOptions;
 use Slic3r::GUI::Tab;
 
 our $have_OpenGL = eval "use Slic3r::GUI::3DScene; 1";

+ 1 - 5
lib/Slic3r/GUI/MainFrame.pm

@@ -253,11 +253,7 @@ sub _init_menubar {
             $plater->export_amf;
         }, undef, 'brick_go.png');
         $self->_append_menu_item($self->{plater_menu}, "Open DLP Projector…\tCtrl+L", 'Open projector window for DLP printing', sub {
-            my $projector = Slic3r::GUI::Projector->new($self);
-            
-            # this double invocation is needed for properly hiding the MainFrame
-            $projector->Show;
-            $projector->ShowModal;
+            Slic3r::GUI::SLAPrintOptions->new($self)->ShowModal;
         }, undef, 'film.png');
         
         $self->{object_menu} = $self->{plater}->object_menu;

+ 40 - 5
lib/Slic3r/GUI/Projector.pm

@@ -3,7 +3,8 @@
 package Slic3r::GUI::Projector;
 use strict;
 use warnings;
-use Wx qw(:dialog :id :misc :sizer :systemsettings :bitmap :button :icon wxTheApp);
+use File::Basename qw(basename dirname);
+use Wx qw(:dialog :id :misc :sizer :systemsettings :bitmap :button :icon :filedialog wxTheApp);
 use Wx::Event qw(EVT_BUTTON EVT_CLOSE EVT_TEXT_ENTER EVT_SPINCTRL EVT_SLIDER);
 use base qw(Wx::Dialog Class::Accessor);
 use utf8;
@@ -378,10 +379,23 @@ sub new {
     
     {
         # should be wxCLOSE but it crashes on Linux, maybe it's a Wx bug
-        my $buttons = $self->CreateStdDialogButtonSizer(wxOK);
-        EVT_BUTTON($self, wxID_OK, sub {
-            $self->_close;
-        });
+        my $buttons = Wx::BoxSizer->new(wxHORIZONTAL);
+        {
+            my $btn = Wx::Button->new($self, -1, "Export SVG…");
+            EVT_BUTTON($self, $btn, sub {
+                $self->_export_svg;
+            });
+            $buttons->Add($btn, 0);
+        }
+        $buttons->AddStretchSpacer(1);
+        {
+            my $btn = Wx::Button->new($self, -1, "Close");
+            $btn->SetDefault;
+            EVT_BUTTON($self, $btn, sub {
+                $self->_close;
+            });
+            $buttons->Add($btn, 0);
+        }
         $sizer->Add($buttons, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
     }
     EVT_CLOSE($self, sub {
@@ -457,6 +471,27 @@ sub _update_buttons {
     $self->Layout;
 }
 
+sub _export_svg {
+    my ($self) = @_;
+    
+    my $output_file = 'print.svg';
+    my $dlg = Wx::FileDialog->new(
+        $self,
+        'Save SVG file as:',
+        wxTheApp->output_path(dirname($output_file)),
+        basename($output_file),
+        &Slic3r::GUI::FILE_WILDCARDS->{svg},
+        wxFD_SAVE | wxFD_OVERWRITE_PROMPT,
+    );
+    if ($dlg->ShowModal != wxID_OK) {
+        $dlg->Destroy;
+        return;
+    }
+    $output_file = Slic3r::decode_path($dlg->GetPath);
+    
+    $self->controller->_print->write_svg($output_file);
+}
+
 sub _set_status {
     my ($self, $status) = @_;
     $self->{status_text}->SetLabel($status // '');

+ 118 - 0
lib/Slic3r/GUI/SLAPrintOptions.pm

@@ -0,0 +1,118 @@
+package Slic3r::GUI::SLAPrintOptions;
+use Wx qw(:dialog :id :misc :sizer :systemsettings wxTheApp);
+use Wx::Event qw(EVT_BUTTON EVT_TEXT_ENTER);
+use base qw(Wx::Dialog Class::Accessor);
+
+__PACKAGE__->mk_accessors(qw(config));
+
+sub new {
+    my ($class, $parent) = @_;
+    my $self = $class->SUPER::new($parent, -1, "SLA/DLP Print", wxDefaultPosition, wxDefaultSize);
+    
+    $self->config(Slic3r::Config::SLAPrint->new);
+    $self->config->apply_dynamic(wxTheApp->{mainframe}->config);
+    
+    my $sizer = Wx::BoxSizer->new(wxVERTICAL);
+    my $new_optgroup = sub {
+        my ($title) = @_;
+        
+        my $optgroup = Slic3r::GUI::ConfigOptionsGroup->new(
+            parent      => $self,
+            title       => $title,
+            config      => $self->config,
+            label_width => 200,
+        );
+        $sizer->Add($optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
+        return $optgroup;
+    };
+    {
+        my $optgroup = $new_optgroup->('Layers');
+        $optgroup->append_single_option_line('layer_height');
+        $optgroup->append_single_option_line('first_layer_height');
+    }
+    {
+        my $optgroup = $new_optgroup->('Infill');
+        $optgroup->append_single_option_line('fill_density');
+        $optgroup->append_single_option_line('fill_pattern');
+        {
+            my $line = $optgroup->create_single_option_line('perimeter_extrusion_width');
+            $line->label('Shell thickness');
+            my $opt = $line->get_options->[0];
+            $opt->sidetext('mm');
+            $opt->tooltip('Thickness of the external shell (both horizontal and vertical).');
+            $optgroup->append_line($line);
+        }
+        {
+            my $line = $optgroup->create_single_option_line('infill_extrusion_width');
+            $line->label('Infill thickness');
+            my $opt = $line->get_options->[0];
+            $opt->sidetext('mm');
+            $opt->tooltip('Thickness of the infill lines.');
+            $optgroup->append_line($line);
+        }
+        $optgroup->append_single_option_line('fill_angle');
+    }
+    {
+        my $optgroup = $new_optgroup->('Raft');
+        $optgroup->append_single_option_line('raft_layers');
+        $optgroup->append_single_option_line('raft_offset');
+    }
+    {
+        my $optgroup = $new_optgroup->('Support Material');
+        $optgroup->append_single_option_line('support_material');
+        {
+            my $line = $optgroup->create_single_option_line('support_material_spacing');
+            $line->label('Pillars spacing');
+            my $opt = $line->get_options->[0];
+            $opt->tooltip('Max spacing between support material pillars.');
+            $optgroup->append_line($line);
+        }
+        {
+            my $line = $optgroup->create_single_option_line('support_material_extrusion_width');
+            $line->label('Pillars diameter');
+            my $opt = $line->get_options->[0];
+            $opt->sidetext('mm');
+            $opt->tooltip('Diameter of the cylindrical support pillars.');
+            $optgroup->append_line($line);
+        }
+    }
+    
+    
+    my $buttons = $self->CreateStdDialogButtonSizer(wxOK | wxCANCEL);
+    EVT_BUTTON($self, wxID_OK, sub { $self->_accept });
+    $sizer->Add($buttons, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
+    
+    $self->SetSizer($sizer);
+    $sizer->SetSizeHints($self);
+    
+    return $self;
+}
+
+sub _accept {
+    my $self = shift;
+    
+    # validate config
+    eval {
+        die "Invalid shell thickness (must be greater than 0).\n"
+            if $self->config->fill_density < 100 && $self->config->perimeter_extrusion_width == 0;
+        die "Invalid infill thickness (must be greater than 0).\n"
+            if $self->config->fill_density < 100 && $self->config->infill_extrusion_width == 0;
+    };
+    if ($@) {
+        Slic3r::GUI::show_error($self, $@);
+        return;
+    }
+    
+    wxTheApp->{mainframe}->load_config($self->config->dynamic);
+    
+    $self->EndModal(wxID_OK);
+    $self->Close;  # needed on Linux
+    
+    my $projector = Slic3r::GUI::Projector->new($self->GetParent);
+            
+    # this double invocation is needed for properly hiding the MainFrame
+    $projector->Show;
+    $projector->ShowModal;
+}
+
+1;

+ 1 - 1
xs/src/libslic3r/Fill/FillRectilinear.cpp

@@ -78,7 +78,7 @@ void FillRectilinear::_fill_surface_single(
     }
 
     size_t n_polylines_out_old = polylines_out->size();
-
+    
     // connect lines
     if (!this->dont_connect && !polylines.empty()) { // prevent calling leftmost_point() on empty collections
         // offset the expolygon by max(min_spacing/2, extra)

+ 1 - 0
xs/src/libslic3r/Point.cpp

@@ -311,6 +311,7 @@ _align_to_grid(const coord_t coord, const coord_t spacing) {
     // Current C++ standard defines the result of integer division to be rounded to zero,
     // for both positive and negative numbers. Here we want to round down for negative
     // numbers as well.
+    assert(spacing > 0);
     coord_t aligned = (coord < 0) ?
             ((coord - spacing + 1) / spacing) * spacing :
             (coord / spacing) * spacing;

+ 3 - 3
xs/src/libslic3r/SLAPrint.cpp

@@ -55,11 +55,12 @@ SLAPrint::slice()
     }
     
     // generate infill
-    if (this->config.fill_density < 100) {
+    const float infill_spacing = this->config.get_abs_value("infill_extrusion_width", this->config.layer_height.value);
+    if (this->config.fill_density < 100 && infill_spacing > 0) {
         std::auto_ptr<Fill> fill(Fill::new_from_type(this->config.fill_pattern.value));
         fill->bounding_box.merge(Point::new_scale(bb.min.x, bb.min.y));
         fill->bounding_box.merge(Point::new_scale(bb.max.x, bb.max.y));
-        fill->spacing       = this->config.get_abs_value("infill_extrusion_width", this->config.layer_height.value);
+        fill->spacing       = infill_spacing;
         fill->angle         = Geometry::deg2rad(this->config.fill_angle.value);
         fill->density       = this->config.fill_density.value/100;
         
@@ -189,7 +190,6 @@ SLAPrint::_infill_layer(size_t i, const Fill* _fill)
         
         ExtrusionPath templ(erInternalInfill);
         templ.width = fill->spacing;
-        
         const ExPolygons internal_ex = intersection_ex(infill, internal);
         for (ExPolygons::const_iterator it = internal_ex.begin(); it != internal_ex.end(); ++it) {
             Polylines polylines = fill->fill_surface(Surface(stInternal, *it));

+ 4 - 0
xs/xsp/Config.xsp

@@ -53,6 +53,8 @@
         %code{% RETVAL = new PrintRegionConfig (); %};
     static StaticPrintConfig* new_FullPrintConfig()
         %code{% RETVAL = new FullPrintConfig (); %};
+    static StaticPrintConfig* new_SLAPrintConfig()
+        %code{% RETVAL = new SLAPrintConfig (); %};
     ~StaticPrintConfig();
     bool has(t_config_option_key opt_key);
     SV* as_hash()
@@ -88,6 +90,8 @@
     double min_object_distance();
     %name{_load} void load(std::string file);
     %name{_save} void save(std::string file);
+    DynamicPrintConfig* dynamic()
+        %code{% RETVAL = new DynamicPrintConfig (); RETVAL->apply(*THIS, true); %};
 };
 
 %package{Slic3r::Config};

+ 1 - 0
xs/xsp/SLAPrint.xsp

@@ -28,6 +28,7 @@
         %code%{ RETVAL = &THIS->layers[i].infill; %};
     bool layer_solid(size_t i)
         %code%{ RETVAL = THIS->layers[i].solid; %};
+    void write_svg(std::string file);
     
 %{