From d9ff63c0222623a8c8a449f7f10351e3dc346223 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 15 May 2018 18:01:47 +0200 Subject: [PATCH] Basic svg export ported from perl to the point where actual svg is assembled. Empty PNG files are genereted for each sliced layer. --- lib/Slic3r/GUI/MainFrame.pm | 19 ++++- lib/Slic3r/Print.pm | 10 +++ lib/Slic3r/Print/Simple.pm | 10 +++ xs/src/libslic3r/Print.cpp | 164 +++++++++++++++++++++++++++++++++++- xs/src/libslic3r/Print.hpp | 14 ++- xs/xsp/Print.xsp | 3 + 6 files changed, 216 insertions(+), 4 deletions(-) diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index fbcd34a3f..b9572ad62 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -9,7 +9,7 @@ use File::Basename qw(basename dirname); use FindBin; use List::Util qw(min first); use Slic3r::Geometry qw(X Y); -use Wx qw(:frame :bitmap :id :misc :notebook :panel :sizer :menu :dialog :filedialog +use Wx qw(:frame :bitmap :id :misc :notebook :panel :sizer :menu :dialog :filedialog :dirdialog :font :icon wxTheApp); use Wx::Event qw(EVT_CLOSE EVT_COMMAND EVT_MENU EVT_NOTEBOOK_PAGE_CHANGED); use base 'Wx::Frame'; @@ -230,6 +230,9 @@ sub _init_menubar { $self->_append_menu_item($fileMenu, L("Slice to SV&G…\tCtrl+G"), L('Slice file to a multi-layer SVG'), sub { $self->quick_slice(save_as => 1, export_svg => 1); }, undef, 'shape_handles.png'); + $self->_append_menu_item($fileMenu, L("Slice to PNG…"), L('Slice file to a set of PNG files'), sub { + $self->quick_slice(save_as => 0, export_png => 1); + }, undef, 'shape_handles.png'); $self->{menu_item_reslice_now} = $self->_append_menu_item( $fileMenu, L("(&Re)Slice Now\tCtrl+S"), L('Start new slicing process'), sub { $self->reslice_now; }, undef, 'shape_handles.png'); @@ -453,6 +456,14 @@ sub quick_slice { $qs_last_output_file = $output_file unless $params{export_svg}; wxTheApp->{app_config}->update_last_output_dir(dirname($output_file)); $dlg->Destroy; + } elsif($params{export_png}) { + my $dlg = Wx::DirDialog->new($self, L('Choose output directory')); + if ($dlg->ShowModal != wxID_OK) { + $dlg->Destroy; + return; + } + $output_file = $dlg->GetPath; + $dlg->Destroy; } # show processbar dialog @@ -467,7 +478,11 @@ sub quick_slice { $sprint->output_file($output_file); if ($params{export_svg}) { $sprint->export_svg; - } else { + } + elsif($params{export_png}) { + $sprint->export_png; + } + else { $sprint->export_gcode; } $sprint->status_cb(undef); diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 8300fdbed..fc28a192e 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -109,6 +109,16 @@ sub export_gcode { } } +sub export_png { + my $self = shift; + my %params = @_; + + $_->slice for @{$self->objects}; + + my $fh = $params{output_file}; + $self->print_to_png($fh); +} + # Export SVG slices for the offline SLA printing. # The export_svg is expected to be executed inside an eval block. sub export_svg { diff --git a/lib/Slic3r/Print/Simple.pm b/lib/Slic3r/Print/Simple.pm index 4fe3eb820..b171e6536 100644 --- a/lib/Slic3r/Print/Simple.pm +++ b/lib/Slic3r/Print/Simple.pm @@ -121,4 +121,14 @@ sub export_svg { $self->_after_export; } +sub export_png { + my ($self) = @_; + + $self->_before_export; + + $self->_print->export_png(output_file => $self->output_file); + + $self->_after_export; +} + 1; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 80f68c51b..8a9665448 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -11,6 +11,11 @@ #include #include +// For png export of the sliced model +#include +#include +#include + namespace Slic3r { template class PrintState; @@ -444,7 +449,7 @@ bool Print::apply_config(DynamicPrintConfig config) const ModelVolume &volume = *object->model_object()->volumes[volume_id]; if (this_region_config_set) { // If the new config for this volume differs from the other - // volume configs currently associated to this region, it means + // volume configs currently associated to this region, it means // the region subdivision does not make sense anymore. if (! this_region_config.equals(this->_region_config_from_model_volume(volume))) { rearrange_regions = true; @@ -1242,4 +1247,161 @@ void Print::set_status(int percent, const std::string &message) printf("Print::status %d => %s\n", percent, message.c_str()); } +template +class FilePrinter { +public: + void drawPolygon(const ExPolygon& p); + void save(const std::string& path); +}; + +template<> +class FilePrinter { + wxBitmap bitmap_; + wxMemoryDC dc_; + std::unique_ptr gc_; +public: + inline FilePrinter(unsigned width, unsigned height): + bitmap_(width, height), + dc_(bitmap_), + gc_(wxGraphicsContext::Create(dc_)) { + gc_->SetAntialiasMode(wxANTIALIAS_DEFAULT); + } + + void drawPolygon(const ExPolygon& p) { + gc_->SetPen( *wxRED_PEN ); + std::vector points; + points.reserve(p.contour.points.size()); + for(auto pp : p.contour.points) points.emplace_back(pp.x, pp.y); + gc_->DrawLines(points.size(), points.data()); + } + + void save(const std::string& path) { + if(!bitmap_.SaveFile(path, wxBITMAP_TYPE_PNG)) { + std::cout << "fail for " << path << std::endl; + } + } +}; + +template +void Print::print_to(std::string dirpath, Args...args) +{ + + std::string dir = dirpath; + +#ifdef WIN32 + if(dir.back() != '\\') dir.push_back('\\'); +#else + if(dir.back() != '/') dir.push_back('/'); +#endif + + FilePrinter printer(std::forward(args)...); + + LayerPtrs layers; + + std::for_each(objects.begin(), objects.end(), [&layers](PrintObject *o){ + layers.insert(layers.end(), o->layers.begin(), o->layers.end()); + layers.insert(layers.end(), o->support_layers.begin(), + o->support_layers.end()); + }); + + std::sort(layers.begin(), layers.end(), [](Layer *l1, Layer *l2){ + return l1->print_z < l2->print_z; + }); + +// auto printSlice = [&printer](ExPolygon path) { + +// }; + + int layer_id = -1; + ExPolygons previous_layer_slices; + auto print_bb = bounding_box(); + + for(auto lp : layers) { + Layer& l = *lp; + ++layer_id; + + auto slices = l.slices; + using Sl = ExPolygons::value_type; + std::sort(slices.expolygons.begin(), + slices.expolygons.end(), + [](Sl a, Sl b){ + return a.contains(b.contour.first_point()) ? false : true; + }); + + ExPolygons current_layer_slices; + + // please enable C++14 ... + std::for_each(l.object()->_shifted_copies.begin(), + l.object()->_shifted_copies.end(), + [&] (Point d) + { + std::for_each(slices.expolygons.begin(), + slices.expolygons.end(), + [&] (ExPolygon slice) + { + slice.translate(d.x, d.y); + slice.translate(-print_bb.min.x, -print_bb.min.y); + printer.drawPolygon(slice); + // $print_polygon->($expolygon->contour, 'contour'); + // $print_polygon->($_, 'hole') for @{$expolygon->holes}; + current_layer_slices.push_back(slice); + }); + }); + + printer.save(dir + "layer" + std::to_string(layer_id) + ".png"); + +// layer_id++; +// if ($layer->slice_z == -1) { +// printf $fh qq{ \n}, $layer_id; +// } else { +// printf $fh qq{ \n}, $layer_id, unscale($layer->slice_z); +// } + +// my @current_layer_slices = (); +// # sort slices so that the outermost ones come first +// my @slices = sort { $a->contour->contains_point($b->contour->first_point) ? 0 : 1 } @{$layer->slices}; +// foreach my $copy (@{$layer->object->_shifted_copies}) { +// foreach my $slice (@slices) { +// my $expolygon = $slice->clone; +// $expolygon->translate(@$copy); +// $expolygon->translate(-$print_bb->x_min, -$print_bb->y_min); +// $print_polygon->($expolygon->contour, 'contour'); +// $print_polygon->($_, 'hole') for @{$expolygon->holes}; +// push @current_layer_slices, $expolygon; +// } +// } +// # generate support material +// if ($self->has_support_material && $layer->id > 0) { +// my (@supported_slices, @unsupported_slices) = (); +// foreach my $expolygon (@current_layer_slices) { +// my $intersection = intersection_ex( +// [ map @$_, @previous_layer_slices ], +// [ @$expolygon ], +// ); +// @$intersection +// ? push @supported_slices, $expolygon +// : push @unsupported_slices, $expolygon; +// } +// my @supported_points = map @$_, @$_, @supported_slices; +// foreach my $expolygon (@unsupported_slices) { +// # look for the nearest point to this island among all +// # supported points +// my $contour = $expolygon->contour; +// my $support_point = $contour->first_point->nearest_point(\@supported_points) +// or next; +// my $anchor_point = $support_point->nearest_point([ @$contour ]); +// printf $fh qq{ \n}, +// map @$_, $support_point, $anchor_point; +// } +// } +// print $fh qq{ \n}; +// @previous_layer_slices = @current_layer_slices; + previous_layer_slices = current_layer_slices; + } +} + +void Print::print_to_png(std::string dirpath) { + print_to(dirpath, 800, 600); +} + } diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index c56e64c6c..01561dad3 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -309,7 +309,19 @@ public: void restart() { m_canceled = false; } // Has the calculation been canceled? bool canceled() { return m_canceled; } - + + enum class FilePrinterFormat { + PNG, + SVG + }; + + void print_to_png(std::string dirpath); + +private: + + template + void print_to(std::string dirpath, Args...args); + private: bool invalidate_state_by_config_options(const std::vector &opt_keys); PrintRegionConfig _region_config_from_model_volume(const ModelVolume &volume); diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index ef9c5345f..0e3c9b7a1 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -215,6 +215,9 @@ _constant() croak("%s\n", e.what()); } %}; + + + void print_to_png(std::string dirpath); void add_model_object(ModelObject* model_object, int idx = -1); bool apply_config(DynamicPrintConfig* config)