diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 5d596f9e6..1da3d9ce2 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -15,10 +15,6 @@ // For png export of the sliced model #include #include -//#include -//#include -//#include -//#include #include "Rasterizer/Rasterizer.hpp" #include "tbb/parallel_for.h" @@ -1254,22 +1250,57 @@ void Print::set_status(int percent, const std::string &message) printf("Print::status %d => %s\n", percent, message.c_str()); } +/* + * Interface for a file printer of the slices. Implementation can be an SVG + * or PNG printer or any other format. + * + * The format argument spefies the output format of the printer and it enables + * different implementations of this class template for each supported format. + * + */ template class FilePrinter { public: + + // Draw an ExPolygon which is a polygon inside a slice on the specified layer. void drawPolygon(const ExPolygon& p, unsigned lyr); + + // Tell the printer how many layers should it consider. void layers(unsigned layernum); + + // Get the number of layers in the print. unsigned layers() const; + + /* Switch the a particular layer. If there where less layers then the + * specified layer number than an appripriate number of layers will be + * allocated in the printer. + */ void beginLayer(unsigned layer); + + // Allocate a new layer on top of the last and switch to it. void beginLayer(); + + /* + * Finish the selected layer. It means that no drawing is allowed on that + * layer anymore. This fact can be used to prepare the file system output + * data like png conmprimation and so on. + */ void finishLayer(unsigned layer); + + // Finish the top layer. void finishLayer(); + + // Save all the layers into the file (or dir) specified in the path argument void save(const std::string& path); + + // Save only the selected layer to the file specified in path argument. void saveLayer(unsigned lyr, const std::string& path); }; -template<> +template<> // Implementation for PNG raster output class FilePrinter { + // We will save the compressed PNG data into stringstreams which can be done + // in parallel. Later we can write every layer to the disk sequentially. std::vector> layers_rst_; Raster::Resolution res_; Raster::PixelDim pxdim_; @@ -1341,70 +1372,24 @@ public: std::fstream out(loc, std::fstream::out | std::fstream::binary); if(out.good()) { layers_rst_[i].first.save(out, Raster::Compression::PNG); - } + } /*else { + some logging should be done here... + }*/ out.close(); layers_rst_[i].first.reset(); } }; -//template<> -//class FilePrinter { -// wxBitmap bitmap_; -// std::unique_ptr dc_; -// std::unique_ptr gc_; -// double pxw_; -// double pxh_; -//public: -// inline FilePrinter(unsigned width_px, unsigned height_px, -// double width_mm, double height_mm): -// bitmap_(width_px, height_px), -// dc_(new wxMemoryDC(bitmap_)), -// gc_(wxGraphicsContext::Create(*dc_)), -// pxw_(width_mm/width_px), -// pxh_(height_mm/width_px) -// { -// gc_->SetAntialiasMode(wxANTIALIAS_DEFAULT); -// } - -// FilePrinter(const FilePrinter& ) = delete; -// FilePrinter(FilePrinter&& m): -// bitmap_(std::move(m.bitmap_)), dc_(std::move(m.dc_)), -// gc_(std::move(m.gc_)), pxw_(m.pxw_), pxh_(m.pxh_) {} - -// void drawPolygon(const Polygon& p) { - -// gc_->SetPen(*wxWHITE_PEN); -// std::vector points; -// points.reserve(p.points.size()); - -// for(auto pp : p.points) { -// points.emplace_back( -// std::round(pp.x * SCALING_FACTOR/pxw_), -// std::round(pp.y * SCALING_FACTOR/pxh_) -// ); -// } - -// gc_->DrawLines(points.size(), points.data()); -// } - -// void finish() { - -// } - -// 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) +void Print::print_to(std::string dirpath, + double width_mm, + double height_mm, + Args...args) { std::string dir = dirpath; -#ifdef WIN32 +#ifdef WIN32 // Making dirpath end with a directory separator on all platforms if(dir.back() != '\\') dir.push_back('\\'); #else if(dir.back() != '/') dir.push_back('/'); @@ -1412,34 +1397,50 @@ void Print::print_to(std::string dirpath, Args...args) LayerPtrs layers; + // Merge the sliced layers wit hthe support 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()); }); + // Sort layers by z coord std::sort(layers.begin(), layers.end(), [](Layer *l1, Layer *l2){ return l1->print_z < l2->print_z; }); auto print_bb = bounding_box(); - FilePrinter printer(std::forward(args)...); - printer.layers(layers.size()); + // If the print does not fit into the print area we should cry about it. + assert(unscale(print_bb.size().x) <= width_mm || + unscale(print_bb.size().y) <= height_mm); - auto process_layer = [&layers, &printer, print_bb, dir] (unsigned layer_id) { + // Offset for centering the print onto the print area + auto cx = scale_(width_mm)/2 - (print_bb.center().x - print_bb.min.x); + auto cy = scale_(height_mm)/2 - (print_bb.center().y - print_bb.min.y); + + // Create the actual printer, forward any additional arguments to it. + FilePrinter printer(std::forward(args)...); + printer.layers(layers.size()); // Allocate space for all the layers + + // Method that prints one layer + auto process_layer = [this, &layers, &printer, print_bb, dir, cx, cy] + (unsigned layer_id) + { Layer& l = *(layers[layer_id]); - ExPolygonCollection slices = l.slices; - using Sl = ExPolygons::value_type; + ExPolygonCollection slices = l.slices; // Copy the layer slices + + // Sort the polygons in the layer std::sort(slices.expolygons.begin(), slices.expolygons.end(), - [](Sl a, Sl b){ + [](const ExPolygon& a, const ExPolygon& b){ return a.contains(b.contour.first_point()) ? false : true; }); - printer.beginLayer(layer_id); + printer.beginLayer(layer_id); // Switch to the appropriate layer + // Draw all the polygons in the slice to the actual layer. std::for_each(l.object()->_shifted_copies.begin(), l.object()->_shifted_copies.end(), [&] (Point d) @@ -1449,25 +1450,34 @@ void Print::print_to(std::string dirpath, Args...args) [&] (ExPolygon slice) { slice.translate(d.x, d.y); - slice.translate(-print_bb.min.x, -print_bb.min.y); + slice.translate(-print_bb.min.x + cx, -print_bb.min.y + cy); printer.drawPolygon(slice, layer_id); }); }); - printer.finishLayer(layer_id); -// printer.saveLayer(layer_id, dir); + if(has_support_material() && layer_id > 0) { + std::cout << "support layer " << layer_id << "\n"; + } + + printer.finishLayer(layer_id); // Finish the layer for later saving it. + // printer.saveLayer(layer_id, dir); We could save the layer immediately }; - tbb::parallel_for(0, layers.size(), process_layer); + // Print all the layers in parallel + tbb::parallel_for(0, + layers.size(), + process_layer); + // Save the print into the file system. printer.save(dir); } void Print::print_to_png(std::string dirpath, long width_px, long height_px, double width_mm, double height_mm) { - print_to(dirpath, width_px, height_px, + print_to(dirpath, width_mm, height_mm, + width_px, height_px, width_mm, height_mm); } diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 2409b6f4f..8fd8f832d 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -316,14 +316,17 @@ public: }; template - void print_to(std::string dirpath, Args...args); + void print_to(std::string dirpath, + double width_mm, + double height_mm, + Args...args); void print_to_png(std::string dirpath, long width_px, long height_px, double width_mm, double height_mm); void print_to_png(std::string dirpath) { - // Where should this be specified? - print_to_png(dirpath, 1440, 2560, 40.0, 72.0); + // Will need some GUI dialogue perhaps for these to be specified. + print_to_png(dirpath, 1440, 2560, 68.0, 120.0); } private: diff --git a/xs/src/libslic3r/Rasterizer/Rasterizer.cpp b/xs/src/libslic3r/Rasterizer/Rasterizer.cpp index 5b0719ecf..adf4fa2c8 100644 --- a/xs/src/libslic3r/Rasterizer/Rasterizer.cpp +++ b/xs/src/libslic3r/Rasterizer/Rasterizer.cpp @@ -1,4 +1,6 @@ #include "Rasterizer.hpp" +#include + #include // For rasterizing @@ -14,7 +16,7 @@ #include #include -// For compression +// For png compression #ifdef WIN32 inline char *strerror_r(int errnum, char *buf, size_t buflen) { strerror_s(buf, buflen, errnum); @@ -70,9 +72,12 @@ public: agg::rasterizer_scanline_aa<> ras; agg::scanline_p8 scanlines; - ras.add_path(to_path(poly.contour)); + auto&& path = to_path(poly.contour); + ras.add_path(path); + for(auto h : poly.holes) { - ras.add_path(to_path(h)); + auto&& holepath = to_path(h); + ras.add_path(holepath); } agg::render_scanlines(ras, scanlines, renderer_); diff --git a/xs/src/libslic3r/Rasterizer/Rasterizer.hpp b/xs/src/libslic3r/Rasterizer/Rasterizer.hpp index 31a1244ec..5fc927d51 100644 --- a/xs/src/libslic3r/Rasterizer/Rasterizer.hpp +++ b/xs/src/libslic3r/Rasterizer/Rasterizer.hpp @@ -2,20 +2,32 @@ #define RASTERIZER_HPP #include -#include +#include namespace Slic3r { +class ExPolygon; + +/** + * @brief Raster captures an antialiased monochrome canvas where vectorial + * polygons can be rasterized. Fill color is always white and the background is + * black. Countours are antialiased. + * + * It also supports saving the raster data into a standard output stream in raw + * or PNG format. + */ class Raster { class Impl; std::unique_ptr impl_; public: + /// Supported compression types enum class Compression { - RAW, - PNG + RAW, //!> Uncompressed pixel data + PNG //!> PNG compression }; + /// Type that represents a resolution in pixels. struct Resolution { unsigned width_px; unsigned height_px; @@ -25,6 +37,7 @@ public: } }; + /// Types that represents the dimension of a pixel in millimeters. struct PixelDim { double w_mm; double h_mm; @@ -32,22 +45,32 @@ public: w_mm(px_width_mm), h_mm(px_height_mm) {} }; + /// Constructor taking the resolution and the pixel dimension. explicit Raster(const Resolution& r, const PixelDim& pd ); Raster(); - ~Raster(); Raster(const Raster& cpy); Raster(Raster&& m); + ~Raster(); + /// Reallocated everything for the given resolution and pixel dimension. void reset(const Resolution& r, const PixelDim& pd); + /** + * Release the allocated resources. Drawing in this state ends in + * unspecified behaviour. + */ void reset(); + /// Get the resolution of the raster. Resolution resolution() const; + /// Clear the raster with black color. void clear(); + /// Draw a polygon with holes. void draw(const ExPolygon& poly); + /// Save the raster on the specified stream. void save(std::ostream& stream, Compression comp = Compression::RAW); };