Browse Source

Initial version of sl1 import with sla::Raster refactor.

tamasmeszaros 4 years ago
parent
commit
247fca6d55

+ 4 - 2
src/PrusaSlicer.cpp

@@ -42,6 +42,7 @@
 #include "libslic3r/Format/3mf.hpp"
 #include "libslic3r/Format/STL.hpp"
 #include "libslic3r/Format/OBJ.hpp"
+#include "libslic3r/Format/SL1.hpp"
 #include "libslic3r/Utils.hpp"
 
 #include "PrusaSlicer.hpp"
@@ -422,7 +423,8 @@ int CLI::run(int argc, char **argv)
                 std::string outfile = m_config.opt_string("output");
                 Print       fff_print;
                 SLAPrint    sla_print;
-
+                SL1Archive  sla_archive(sla_print.printer_config());
+                sla_print.set_printer(&sla_archive);
                 sla_print.set_status_callback(
                             [](const PrintBase::SlicingStatus& s)
                 {
@@ -462,7 +464,7 @@ int CLI::run(int argc, char **argv)
                             outfile = sla_print.output_filepath(outfile);
                             // We need to finalize the filename beforehand because the export function sets the filename inside the zip metadata
                             outfile_final = sla_print.print_statistics().finalize_output_path(outfile);
-                            sla_print.export_raster(outfile_final);
+                            sla_archive.export_print(outfile_final, sla_print);
                         }
                         if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final)) {
                             boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl;

+ 12 - 4
src/libslic3r/CMakeLists.txt

@@ -77,6 +77,8 @@ add_library(libslic3r STATIC
     Format/PRUS.hpp
     Format/STL.cpp
     Format/STL.hpp
+    Format/SL1.hpp
+    Format/SL1.cpp
     GCode/Analyzer.cpp
     GCode/Analyzer.hpp
     GCode/ThumbnailData.cpp
@@ -162,6 +164,8 @@ add_library(libslic3r STATIC
     SLAPrint.hpp
     Slicing.cpp
     Slicing.hpp
+    SlicesToTriangleMesh.hpp
+    SlicesToTriangleMesh.cpp
     SlicingAdaptive.cpp
     SlicingAdaptive.hpp
     SupportMaterial.cpp
@@ -177,6 +181,8 @@ add_library(libslic3r STATIC
     Tesselate.hpp
     TriangleMesh.cpp
     TriangleMesh.hpp
+    TriangulateWall.hpp
+    TriangulateWall.cpp
     utils.cpp
     Utils.hpp
     Time.cpp
@@ -191,6 +197,7 @@ add_library(libslic3r STATIC
     SimplifyMesh.hpp
     SimplifyMeshImpl.hpp
     SimplifyMesh.cpp
+    MarchingSquares.hpp
     ${OpenVDBUtils_SOURCES}
     SLA/Common.hpp
     SLA/Common.cpp
@@ -208,10 +215,11 @@ add_library(libslic3r STATIC
     SLA/Rotfinder.cpp
     SLA/BoostAdapter.hpp
     SLA/SpatIndex.hpp
-    SLA/Raster.hpp
-    SLA/Raster.cpp
-    SLA/RasterWriter.hpp
-    SLA/RasterWriter.cpp
+    SLA/RasterBase.hpp
+    SLA/RasterBase.cpp
+    SLA/AGGRaster.hpp
+    SLA/RasterToPolygons.hpp
+    SLA/RasterToPolygons.cpp
     SLA/ConcaveHull.hpp
     SLA/ConcaveHull.cpp
     SLA/Hollowing.hpp

+ 171 - 0
src/libslic3r/Format/SL1.cpp

@@ -0,0 +1,171 @@
+#include "SL1.hpp"
+#include "GCode/ThumbnailData.hpp"
+#include "libslic3r/Time.hpp"
+
+#include <boost/log/trivial.hpp>
+#include <boost/filesystem.hpp>
+
+#include "libslic3r/Zipper.hpp"
+#include "libslic3r/SLAPrint.hpp"
+
+namespace Slic3r {
+
+using ConfMap = std::map<std::string, std::string>;
+
+namespace {
+
+std::string to_ini(const ConfMap &m)
+{
+    std::string ret;
+    for (auto &param : m) ret += param.first + " = " + param.second + "\n";
+    
+    return ret;
+}
+
+std::string get_cfg_value(const DynamicPrintConfig &cfg, const std::string &key)
+{
+    std::string ret;
+    
+    if (cfg.has(key)) {
+        auto opt = cfg.option(key);
+        if (opt) ret = opt->serialize();
+    }
+    
+    return ret;    
+}
+
+void fill_iniconf(ConfMap &m, const SLAPrint &print)
+{
+    auto &cfg = print.full_print_config();
+    m["layerHeight"]    = get_cfg_value(cfg, "layer_height");
+    m["expTime"]        = get_cfg_value(cfg, "exposure_time");
+    m["expTimeFirst"]   = get_cfg_value(cfg, "initial_exposure_time");
+    m["materialName"]   = get_cfg_value(cfg, "sla_material_settings_id");
+    m["printerModel"]   = get_cfg_value(cfg, "printer_model");
+    m["printerVariant"] = get_cfg_value(cfg, "printer_variant");
+    m["printerProfile"] = get_cfg_value(cfg, "printer_settings_id");
+    m["printProfile"]   = get_cfg_value(cfg, "sla_print_settings_id");
+    m["fileCreationTimestamp"] = Utils::utc_timestamp();
+    m["prusaSlicerVersion"]    = SLIC3R_BUILD_ID;
+    
+    SLAPrintStatistics stats = print.print_statistics();
+    // Set statistics values to the printer
+    
+    double used_material = (stats.objects_used_material +
+                            stats.support_used_material) / 1000;
+    
+    int num_fade = print.default_object_config().faded_layers.getInt();
+    num_fade = num_fade >= 0 ? num_fade : 0;
+    
+    m["usedMaterial"] = std::to_string(used_material);
+    m["numFade"]      = std::to_string(num_fade);
+    m["numSlow"]      = std::to_string(stats.slow_layers_count);
+    m["numFast"]      = std::to_string(stats.fast_layers_count);
+    m["printTime"]    = std::to_string(stats.estimated_print_time);
+    
+    m["action"] = "print";
+}
+
+void fill_slicerconf(ConfMap &m, const SLAPrint &print)
+{
+    using namespace std::literals::string_view_literals;
+    
+    // Sorted list of config keys, which shall not be stored into the ini.
+    static constexpr auto banned_keys = { 
+		"compatible_printers"sv,
+        "compatible_prints"sv,
+        "print_host"sv,
+        "printhost_apikey"sv,
+        "printhost_cafile"sv
+    };
+    
+    assert(std::is_sorted(banned_keys.begin(), banned_keys.end()));
+    auto is_banned = [](const std::string &key) {
+        return std::binary_search(banned_keys.begin(), banned_keys.end(), key);
+    };
+    
+    auto &cfg = print.full_print_config();
+    for (const std::string &key : cfg.keys())
+        if (! is_banned(key) && ! cfg.option(key)->is_nil())
+            m[key] = cfg.opt_serialize(key);
+    
+}
+
+} // namespace
+
+uqptr<sla::RasterBase> SL1Archive::create_raster() const
+{
+    sla::RasterBase::Resolution res;
+    sla::RasterBase::PixelDim   pxdim;
+    std::array<bool, 2>         mirror;
+
+    double w  = m_cfg.display_width.getFloat();
+    double h  = m_cfg.display_height.getFloat();
+    auto   pw = size_t(m_cfg.display_pixels_x.getInt());
+    auto   ph = size_t(m_cfg.display_pixels_y.getInt());
+
+    mirror[X] = m_cfg.display_mirror_x.getBool();
+    mirror[Y] = m_cfg.display_mirror_y.getBool();
+    
+    auto ro = m_cfg.display_orientation.getInt();
+    sla::RasterBase::Orientation orientation =
+        ro == sla::RasterBase::roPortrait ? sla::RasterBase::roPortrait :
+                                            sla::RasterBase::roLandscape;
+    
+    if (orientation == sla::RasterBase::roPortrait) {
+        std::swap(w, h);
+        std::swap(pw, ph);
+    }
+
+    res   = sla::RasterBase::Resolution{pw, ph};
+    pxdim = sla::RasterBase::PixelDim{w / pw, h / ph};
+    sla::RasterBase::Trafo tr{orientation, mirror};
+
+    double gamma = m_cfg.gamma_correction.getFloat();
+
+    return sla::create_raster_grayscale_aa(res, pxdim, gamma, tr);
+}
+
+sla::EncodedRaster SL1Archive::encode_raster(const sla::RasterBase &rst) const
+{
+    return rst.encode(sla::PNGRasterEncoder());    
+}
+
+void SL1Archive::export_print(Zipper& zipper,
+                              const SLAPrint &print,
+                              const std::string &prjname)
+{
+    std::string project =
+        prjname.empty() ?
+            boost::filesystem::path(zipper.get_filename()).stem().string() :
+            prjname;
+    
+    ConfMap iniconf, slicerconf;
+    fill_iniconf(iniconf, print);
+    
+    iniconf["jobDir"] = project;
+
+    fill_slicerconf(slicerconf, print);
+
+    try {
+        zipper.add_entry("config.ini");
+        zipper << to_ini(iniconf);
+        zipper.add_entry("prusaslicer.ini");
+        zipper << to_ini(slicerconf);
+        
+        size_t i = 0;
+        for (const sla::EncodedRaster &rst : m_layers) {
+
+            std::string imgname = project + string_printf("%.5d", i++) + "." +
+                                  rst.extension();
+            
+            zipper.add_entry(imgname.c_str(), rst.data(), rst.size());
+        }
+    } catch(std::exception& e) {
+        BOOST_LOG_TRIVIAL(error) << e.what();
+        // Rethrow the exception
+        throw;
+    }
+}
+
+} // namespace Slic3r

+ 44 - 0
src/libslic3r/Format/SL1.hpp

@@ -0,0 +1,44 @@
+#ifndef ARCHIVETRAITS_HPP
+#define ARCHIVETRAITS_HPP
+
+#include <string>
+
+#include "libslic3r/Zipper.hpp"
+#include "libslic3r/SLAPrint.hpp"
+
+namespace Slic3r {
+
+class SL1Archive: public SLAPrinter {
+    SLAPrinterConfig m_cfg;
+    
+protected:
+    uqptr<sla::RasterBase> create_raster() const override;
+    sla::EncodedRaster encode_raster(const sla::RasterBase &rst) const override;
+    
+public:
+    
+    SL1Archive() = default;
+    explicit SL1Archive(const SLAPrinterConfig &cfg): m_cfg(cfg) {}
+    explicit SL1Archive(SLAPrinterConfig &&cfg): m_cfg(std::move(cfg)) {}
+    
+    void export_print(Zipper &zipper, const SLAPrint &print, const std::string &projectname = "");
+    void export_print(const std::string &fname, const SLAPrint &print, const std::string &projectname = "")
+    {
+        Zipper zipper(fname);
+        export_print(zipper, print, projectname);
+    }
+    
+    void apply(const SLAPrinterConfig &cfg) override
+    {
+        auto diff = m_cfg.diff(cfg);
+        if (!diff.empty()) {
+            m_cfg.apply_only(cfg, diff);
+            m_layers = {};
+        }
+    }
+};
+    
+
+} // namespace Slic3r::sla
+
+#endif // ARCHIVETRAITS_HPP

+ 2 - 2
src/libslic3r/MTUtils.hpp

@@ -126,10 +126,10 @@ inline IntegerOnly<I, std::vector<T, Args...>> reserve_vector(I capacity)
 }
 
 /// Exactly like Matlab https://www.mathworks.com/help/matlab/ref/linspace.html
-template<class T, class I>
+template<class T, class I, class = IntegerOnly<I>>
 inline std::vector<T> linspace_vector(const ArithmeticOnly<T> &start, 
                                       const T &stop, 
-                                      const IntegerOnly<I> &n)
+                                      const I &n)
 {
     std::vector<T> vals(n, T());
 

+ 432 - 0
src/libslic3r/MarchingSquares.hpp

@@ -0,0 +1,432 @@
+#ifndef MARCHINGSQUARES_HPP
+#define MARCHINGSQUARES_HPP
+
+#include <type_traits>
+#include <cstdint>
+#include <vector>
+#include <algorithm>
+#include <cassert>
+
+namespace marchsq {
+
+// Marks a square in the grid
+struct Coord {
+    size_t r = 0, c = 0;
+    
+    Coord() = default;
+    explicit Coord(size_t s) : r(s), c(s) {}
+    Coord(size_t _r, size_t _c): r(_r), c(_c) {}
+    
+    size_t seq(const Coord &res) const { return r * res.c + c; }
+    Coord& operator+=(const Coord& b) { r += b.r; c += b.c; return *this; }
+    Coord operator+(const Coord& b) const { Coord a = *this; a += b; return a; }
+};
+
+// Closed ring of cell coordinates
+using Ring = std::vector<Coord>;
+
+// Specialize this struct to register a raster type for the Marching squares alg
+template<class T, class Enable = void> struct _RasterTraits {
+    
+    // The type of pixel cell in the raster
+    using ValueType = typename T::ValueType;
+    
+    // Value at a given position
+    static ValueType get(const T &raster, size_t row, size_t col);
+    
+    // Number of rows and cols of the raster
+    static size_t rows(const T &raster);
+    static size_t cols(const T &raster);
+};
+
+// Specialize this to use parellel loops within the algorithm
+template<class ExecutionPolicy, class Enable = void> struct _Loop {
+    template<class It, class Fn> static void for_each(It from, It to, Fn &&fn)
+    {
+        for (auto it = from; it < to; ++it) fn(*it, size_t(it - from));
+    }
+};
+
+namespace __impl {
+
+template<class T> using RasterTraits = _RasterTraits<std::decay_t<T>>;
+template<class T> using TRasterValue = typename RasterTraits<T>::ValueType;
+
+template<class T> TRasterValue<T> isoval(const T &raster, const Coord &crd)
+{
+    return RasterTraits<T>::get(raster, crd.r, crd.c);
+}
+
+template<class T> size_t rows(const T &raster)
+{
+    return RasterTraits<T>::rows(raster);
+}
+
+template<class T> size_t cols(const T &raster)
+{
+    return RasterTraits<T>::cols(raster);
+}
+
+template<class ExecutionPolicy, class It, class Fn>
+void for_each(ExecutionPolicy&& policy, It from, It to, Fn &&fn)
+{
+    _Loop<ExecutionPolicy>::for_each(from, to, fn);
+}
+
+// Type of squares (tiles) depending on which vertices are inside an ROI
+// The vertices would be marked a, b, c, d in counter clockwise order from the 
+// bottom left vertex of a square.
+// d --- c
+// |     |
+// |     |
+// a --- b
+enum class SquareTag : uint8_t {
+//     0, 1, 2,  3, 4,  5,  6,   7, 8,  9, 10,  11, 12,  13,  14,  15
+    none, a, b, ab, c, ac, bc, abc, d, ad, bd, abd, cd, acd, bcd, full
+};
+
+template<class E> constexpr std::underlying_type_t<E> _t(E e) noexcept
+{
+    return static_cast<std::underlying_type_t<E>>(e);
+}
+
+enum class Dir: uint8_t { left, down, right, up, none};
+
+static const constexpr Dir NEXT_CCW[] = {
+    /* 00 */ Dir::none,      // SquareTag::none (empty square, nowhere to go)
+    /* 01 */ Dir::left,      // SquareTag::a
+    /* 02 */ Dir::down,      // SquareTag::b
+    /* 03 */ Dir::left,      // SquareTag::ab
+    /* 04 */ Dir::right,     // SquareTag::c
+    /* 05 */ Dir::none,      // SquareTag::ac   (ambiguous case)
+    /* 06 */ Dir::down,      // SquareTag::bc
+    /* 07 */ Dir::left,      // SquareTag::abc
+    /* 08 */ Dir::up,        // SquareTag::d
+    /* 09 */ Dir::up,        // SquareTag::ad
+    /* 10 */ Dir::none,      // SquareTag::bd   (ambiguous case)
+    /* 11 */ Dir::up,        // SquareTag::abd
+    /* 12 */ Dir::right,     // SquareTag::cd
+    /* 13 */ Dir::right,     // SquareTag::acd
+    /* 14 */ Dir::down,      // SquareTag::bcd
+    /* 15 */ Dir::none       // SquareTag::full (full covered, nowhere to go)
+};
+
+static const constexpr uint8_t PREV_CCW[] = {
+    /* 00 */ 1 << _t(Dir::none),
+    /* 01 */ 1 << _t(Dir::up),      
+    /* 02 */ 1 << _t(Dir::left),
+    /* 03 */ 1 << _t(Dir::left),     
+    /* 04 */ 1 << _t(Dir::down),     
+    /* 05 */ 1 << _t(Dir::up) | 1 << _t(Dir::down),      
+    /* 06 */ 1 << _t(Dir::down),
+    /* 07 */ 1 << _t(Dir::down),
+    /* 08 */ 1 << _t(Dir::right),
+    /* 09 */ 1 << _t(Dir::up),
+    /* 10 */ 1 << _t(Dir::left) | 1 << _t(Dir::right), 
+    /* 11 */ 1 << _t(Dir::left),   
+    /* 12 */ 1 << _t(Dir::right),
+    /* 13 */ 1 << _t(Dir::up),
+    /* 14 */ 1 << _t(Dir::right), 
+    /* 15 */ 1 << _t(Dir::none)  
+};
+
+const constexpr uint8_t DIRMASKS[] = {
+    /*left: */ 0x01, /*down*/ 0x12, /*right */0x21, /*up*/ 0x10, /*none*/ 0x00
+};
+
+inline Coord step(const Coord &crd, Dir d)
+{
+    uint8_t dd = DIRMASKS[uint8_t(d)];
+    return {crd.r - 1 + (dd & 0x0f), crd.c - 1 + (dd >> 4)};
+}
+
+template<class Rst> class Grid {
+    const Rst *            m_rst = nullptr;
+    Coord                  m_cellsize, m_res_1, m_window, m_gridsize;
+    std::vector<uint8_t>   m_tags;     // Assign tags to each square
+
+    Coord rastercoord(const Coord &crd) const
+    {
+        return {crd.r * m_window.r, crd.c * m_window.c};
+    }
+
+    Coord bl(const Coord &crd) const { return tl(crd) + Coord{m_res_1.r, 0}; }
+    Coord br(const Coord &crd) const { return tl(crd) + Coord{m_res_1.r, m_res_1.c}; }
+    Coord tr(const Coord &crd) const { return tl(crd) + Coord{0, m_res_1.c}; }
+    Coord tl(const Coord &crd) const { return rastercoord(crd); }
+
+    TRasterValue<Rst> bottomleft(const Coord &cell) const
+    {
+        return isoval(*m_rst, bl(cell));
+    }
+    
+    TRasterValue<Rst> bottomright(const Coord &cell) const
+    {
+        return isoval(*m_rst, br(cell));
+    }
+    
+    TRasterValue<Rst> topright(const Coord &cell) const
+    {
+        return isoval(*m_rst, tr(cell));
+    }
+    
+    TRasterValue<Rst> topleft(const Coord &cell) const
+    {
+        return isoval(*m_rst, tl(cell));
+    }
+
+    // Calculate the tag for a cell (or square). The cell coordinates mark the
+    // top left vertex of a square in the raster. v is the isovalue
+    uint8_t get_tag_for_cell(const Coord &cell, TRasterValue<Rst> v)
+    {   
+        uint8_t t = (bottomleft(cell) >= v) +
+                    ((bottomright(cell) >= v) << 1) +
+                    ((topright(cell) >= v) << 2) +
+                    ((topleft(cell) >= v) << 3);
+        
+        assert(t < 16);
+        return t;
+    }
+    
+    // Get a cell coordinate from a sequential index
+    Coord coord(size_t i) const { return {i / m_gridsize.c, i % m_gridsize.c}; }
+    
+    size_t seq(const Coord &crd) const { return crd.seq(m_gridsize); }
+    
+    bool is_visited(size_t idx, Dir d = Dir::none) const
+    {
+        SquareTag t = get_tag(idx);
+        uint8_t ref = d == Dir::none ? PREV_CCW[_t(t)] : uint8_t(1 << _t(d));
+        return t == SquareTag::full || t == SquareTag::none ||
+               ((m_tags[idx] & 0xf0) >> 4) == ref;
+    }
+    
+    void set_visited(size_t idx, Dir d = Dir::none)
+    {
+        m_tags[idx] |= (1 << (_t(d)) << 4);
+    }
+    
+    bool is_ambiguous(size_t idx) const
+    {
+        SquareTag t = get_tag(idx);
+        return t == SquareTag::ac || t == SquareTag::bd;
+    }
+
+    // Search for a new starting square
+    size_t search_start_cell(size_t i = 0) const
+    {
+        // Skip ambiguous tags as starting tags due to unknown previous
+        // direction.
+        while ((i < m_tags.size() && is_visited(i)) || is_ambiguous(i)) ++i;
+        
+        return i;
+    }
+    
+    SquareTag get_tag(size_t idx) const { return SquareTag(m_tags[idx] & 0x0f); }
+        
+    Dir next_dir(Dir prev, SquareTag tag) const
+    {
+        // Treat ambiguous cases as two separate regions in one square.
+        switch (tag) {
+        case SquareTag::ac:
+            switch (prev) {
+            case Dir::down: return Dir::right;
+            case Dir::up:   return Dir::left;
+            default:        assert(false); return Dir::none;
+            }
+        case SquareTag::bd:
+            switch (prev) {
+            case Dir::right: return Dir::up;
+            case Dir::left:  return Dir::down;
+            default:         assert(false); return Dir::none;
+            }
+        default:
+            return NEXT_CCW[uint8_t(tag)];
+        }
+        
+        return Dir::none;
+    }
+    
+    struct CellIt {
+        Coord crd; Dir dir= Dir::none; const Rst *rst = nullptr;
+        TRasterValue<Rst> operator*() const { return isoval(*rst, crd); }
+        CellIt& operator++() { crd = step(crd, dir); return *this; }
+        CellIt operator++(int) { CellIt it = *this; ++(*this); return it; }
+        bool operator!=(const CellIt &it) { return crd.r != it.crd.r || crd.c != it.crd.c; }
+        
+        using value_type        = TRasterValue<Rst>;
+        using pointer           = TRasterValue<Rst> *;
+        using reference         = TRasterValue<Rst> &;
+        using difference_type   = long;
+        using iterator_category = std::forward_iterator_tag;
+    };
+    
+    // Two cell iterators representing an edge of a square. This is then
+    // used for binary search for the first active pixel on the edge.
+    struct Edge { CellIt from, to; };
+    
+    Edge edge(const Coord &ringvertex)
+    {
+        size_t idx = ringvertex.r;
+        Coord cell = coord(idx);
+        uint8_t tg = m_tags[ringvertex.r];
+        SquareTag t = SquareTag(tg & 0x0f);
+        
+        switch (t) {
+        case SquareTag::a:
+        case SquareTag::ab:
+        case SquareTag::abc:
+            return {{tl(cell), Dir::down,  m_rst}, {bl(cell)}};
+        case SquareTag::b:
+        case SquareTag::bc:
+        case SquareTag::bcd:
+            return {{bl(cell), Dir::right, m_rst}, {br(cell)}};
+        case SquareTag::c:
+            return {{br(cell), Dir::up,    m_rst}, {tr(cell)}};
+        case SquareTag::ac:
+            switch (Dir(ringvertex.c)) {
+            case Dir::left:  return {{tl(cell), Dir::down, m_rst}, {bl(cell)}};
+            case Dir::right: return {{br(cell), Dir::up,   m_rst}, {tr(cell)}};
+            default: assert(false);
+            }
+        case SquareTag::d:
+        case SquareTag::ad:
+        case SquareTag::abd:
+            return {{tr(cell), Dir::left, m_rst}, {tl(cell)}};
+        case SquareTag::bd:
+            switch (Dir(ringvertex.c)) {
+            case Dir::down: return {{bl(cell), Dir::right, m_rst}, {br(cell)}};
+            case Dir::up:   return {{tr(cell), Dir::left,  m_rst}, {tl(cell)}};
+            default: assert(false);
+            }
+        case SquareTag::cd:
+        case SquareTag::acd:
+            return {{br(cell), Dir::up, m_rst}, {tr(cell)}};
+        case SquareTag::full:
+        case SquareTag::none: {
+            Coord crd{tl(cell) + Coord{m_cellsize.r / 2, m_cellsize.c / 2}};
+            return {{crd, Dir::none, m_rst}, crd};
+        }
+        }
+        
+        return {}; 
+    }
+    
+public:
+    explicit Grid(const Rst &rst, const Coord &cellsz, const Coord &overlap)
+        : m_rst{&rst}
+        , m_cellsize{cellsz}
+        , m_res_1{m_cellsize.r - 1, m_cellsize.c - 1}
+        , m_window{overlap.r < cellsz.r ? cellsz.r - overlap.r : cellsz.r,
+                   overlap.c < cellsz.c ? cellsz.c - overlap.c : cellsz.c}
+        , m_gridsize{(rows(rst) - overlap.r) / m_window.r,
+                     (cols(rst) - overlap.c) / m_window.c}
+        , m_tags(m_gridsize.r * m_gridsize.c, 0)
+    {}
+    
+    // Go through the cells and mark them with the appropriate tag.
+    template<class ExecutionPolicy>
+    void tag_grid(ExecutionPolicy &&policy, TRasterValue<Rst> isoval)
+    {        
+        // parallel for r
+        for_each (std::forward<ExecutionPolicy>(policy),
+                 m_tags.begin(), m_tags.end(),
+                 [this, isoval](uint8_t& tag, size_t idx) {
+            tag = get_tag_for_cell(coord(idx), isoval);
+        });
+    }
+    
+    // Scan for the rings on the tagged grid. Each ring vertex stores the
+    // sequential index of the cell and the next direction (Dir).
+    // This info can be used later to calculate the exact raster coordinate.
+    std::vector<Ring> scan_rings()
+    {
+        std::vector<Ring> rings;
+        size_t startidx = 0;
+        while ((startidx = search_start_cell(startidx)) < m_tags.size()) {
+            Ring ring;
+            
+            size_t idx = startidx;
+            Dir prev = Dir::none, next = next_dir(prev, get_tag(idx));
+            
+            while (next != Dir::none && !is_visited(idx, prev)) {
+                Coord ringvertex{idx, size_t(next)};
+                ring.emplace_back(ringvertex);
+                set_visited(idx, prev);
+                
+                idx  = seq(step(coord(idx), next));
+                prev = next;
+                next = next_dir(next, get_tag(idx));
+            }
+            
+            // To prevent infinite loops in case of degenerate input
+            if (next == Dir::none) m_tags[startidx] = _t(SquareTag::none);
+            
+            if (ring.size() > 1) {
+                ring.pop_back();
+                rings.emplace_back(ring);
+            }
+        }
+        
+        return rings;
+    }
+    
+    // Calculate the exact raster position from the cells which store the
+    // sequantial index of the square and the next direction
+    template<class ExecutionPolicy>
+    void interpolate_rings(ExecutionPolicy && policy,
+                           std::vector<Ring> &rings,
+                           TRasterValue<Rst>  isov)
+    {
+        for_each(std::forward<ExecutionPolicy>(policy),
+                 rings.begin(), rings.end(), [this, isov] (Ring &ring, size_t) {
+            for (Coord &ringvertex : ring) {
+                Edge e = edge(ringvertex);
+                CellIt found = std::lower_bound(e.from, e.to, isov);
+                ringvertex = found.crd;
+            }
+        });
+    }
+};
+
+template<class Raster, class ExecutionPolicy>
+std::vector<marchsq::Ring> execute_with_policy(ExecutionPolicy &&   policy,
+                                               const Raster &       raster,
+                                               TRasterValue<Raster> isoval,
+                                               Coord windowsize = {})
+{
+    if (!rows(raster) || !cols(raster)) return {};
+    
+    size_t ratio = cols(raster) / rows(raster);
+    
+    if (!windowsize.r) windowsize.r = 2;
+    if (!windowsize.c)
+        windowsize.c = std::max(size_t(2), windowsize.r * ratio);
+    
+    Coord overlap{1};
+    
+    Grid<Raster> grid{raster, windowsize, overlap};
+    
+    grid.tag_grid(std::forward<ExecutionPolicy>(policy), isoval);
+    std::vector<marchsq::Ring> rings = grid.scan_rings();
+    grid.interpolate_rings(std::forward<ExecutionPolicy>(policy), rings, isoval);
+    
+    return rings;
+}
+
+template<class Raster>
+std::vector<marchsq::Ring> execute(const Raster &raster,
+                                   TRasterValue<Raster> isoval,
+                                   Coord                windowsize = {})
+{
+    return execute_with_policy(nullptr, raster, isoval, windowsize);
+}
+
+} // namespace __impl
+
+using __impl::execute_with_policy;
+using __impl::execute;
+
+} // namespace marchsq
+
+#endif // MARCHINGSQUARES_HPP

+ 222 - 0
src/libslic3r/SLA/AGGRaster.hpp

@@ -0,0 +1,222 @@
+#ifndef AGGRASTER_HPP
+#define AGGRASTER_HPP
+
+#include <libslic3r/SLA/RasterBase.hpp>
+#include "libslic3r/ExPolygon.hpp"
+#include "libslic3r/MTUtils.hpp"
+#include <libnest2d/backends/clipper/clipper_polygon.hpp>
+
+// For rasterizing
+#include <agg/agg_basics.h>
+#include <agg/agg_rendering_buffer.h>
+#include <agg/agg_pixfmt_gray.h>
+#include <agg/agg_pixfmt_rgb.h>
+#include <agg/agg_renderer_base.h>
+#include <agg/agg_renderer_scanline.h>
+
+#include <agg/agg_scanline_p.h>
+#include <agg/agg_rasterizer_scanline_aa.h>
+#include <agg/agg_path_storage.h>
+
+namespace Slic3r {
+
+inline const Polygon& contour(const ExPolygon& p) { return p.contour; }
+inline const ClipperLib::Path& contour(const ClipperLib::Polygon& p) { return p.Contour; }
+
+inline const Polygons& holes(const ExPolygon& p) { return p.holes; }
+inline const ClipperLib::Paths& holes(const ClipperLib::Polygon& p) { return p.Holes; }
+
+namespace sla {
+
+template<class Color> struct Colors {
+    static const Color White;
+    static const Color Black;
+};
+
+template<class Color> const Color Colors<Color>::White = Color{255};
+template<class Color> const Color Colors<Color>::Black = Color{0};
+
+template<class PixelRenderer,
+         template<class /*agg::renderer_base<PixelRenderer>*/> class Renderer,
+         class Rasterizer = agg::rasterizer_scanline_aa<>,
+         class Scanline   = agg::scanline_p8>
+class AGGRaster: public RasterBase {
+public:
+    using TColor = typename PixelRenderer::color_type;
+    using TValue = typename TColor::value_type;
+    using TPixel = typename PixelRenderer::pixel_type;
+    using TRawBuffer = agg::rendering_buffer;
+    
+protected:
+    
+    Resolution m_resolution;
+    PixelDim m_pxdim_scaled;    // used for scaled coordinate polygons
+    
+    std::vector<TPixel> m_buf;
+    agg::rendering_buffer m_rbuf;
+    
+    PixelRenderer m_pixrenderer;
+    
+    agg::renderer_base<PixelRenderer> m_raw_renderer;
+    Renderer<agg::renderer_base<PixelRenderer>> m_renderer;
+    
+    Trafo m_trafo;
+    Scanline m_scanlines;
+    Rasterizer m_rasterizer;
+    
+    void flipy(agg::path_storage &path) const
+    {
+        path.flip_y(0, double(m_resolution.height_px));
+    }
+    
+    void flipx(agg::path_storage &path) const
+    {
+        path.flip_x(0, double(m_resolution.width_px));
+    }
+    
+    double getPx(const Point &p) { return p(0) * m_pxdim_scaled.w_mm; }
+    double getPy(const Point &p) { return p(1) * m_pxdim_scaled.h_mm; }
+    agg::path_storage to_path(const Polygon &poly) { return to_path(poly.points); }
+    double getPx(const ClipperLib::IntPoint &p) { return p.X * m_pxdim_scaled.w_mm; }
+    double getPy(const ClipperLib::IntPoint& p) { return p.Y * m_pxdim_scaled.h_mm; }
+    
+    template<class PointVec> agg::path_storage _to_path(const PointVec& v)
+    {
+        agg::path_storage path;
+        
+        auto it = v.begin();
+        path.move_to(getPx(*it), getPy(*it));
+        while(++it != v.end()) path.line_to(getPx(*it), getPy(*it));
+        path.line_to(getPx(v.front()), getPy(v.front()));
+        
+        return path;
+    }
+    
+    template<class PointVec> agg::path_storage _to_path_flpxy(const PointVec& v)
+    {
+        agg::path_storage path;
+        
+        auto it = v.begin();
+        path.move_to(getPy(*it), getPx(*it));
+        while(++it != v.end()) path.line_to(getPy(*it), getPx(*it));
+        path.line_to(getPy(v.front()), getPx(v.front()));
+        
+        return path;
+    }
+    
+    template<class PointVec> agg::path_storage to_path(const PointVec &v)
+    {
+        auto path = m_trafo.flipXY ? _to_path_flpxy(v) : _to_path(v);
+        
+        path.translate_all_paths(m_trafo.center_x * m_pxdim_scaled.w_mm,
+                                 m_trafo.center_y * m_pxdim_scaled.h_mm);
+        
+        if(m_trafo.mirror_x) flipx(path);
+        if(m_trafo.mirror_y) flipy(path);
+        
+        return path;
+    }
+    
+    template<class P> void _draw(const P &poly)
+    {
+        m_rasterizer.reset();
+        
+        m_rasterizer.add_path(to_path(contour(poly)));
+        for(auto& h : holes(poly)) m_rasterizer.add_path(to_path(h));
+        
+        agg::render_scanlines(m_rasterizer, m_scanlines, m_renderer);
+    }
+    
+public:
+    template<class GammaFn> AGGRaster(const Resolution &res,
+              const PixelDim &  pd,
+              const Trafo &     trafo,
+              const TColor &            foreground,
+              const TColor &            background,
+              GammaFn &&                gammafn)
+        : m_resolution(res)
+        , m_pxdim_scaled(SCALING_FACTOR / pd.w_mm, SCALING_FACTOR / pd.h_mm)
+        , m_buf(res.pixels())
+        , m_rbuf(reinterpret_cast<TValue *>(m_buf.data()),
+                 unsigned(res.width_px),
+                 unsigned(res.height_px),
+                 int(res.width_px *PixelRenderer::num_components))
+        , m_pixrenderer(m_rbuf)
+        , m_raw_renderer(m_pixrenderer)
+        , m_renderer(m_raw_renderer)
+        , m_trafo(trafo)
+    {
+        m_renderer.color(foreground);
+        clear(background);
+        
+        m_rasterizer.gamma(gammafn);
+    }
+    
+    Trafo trafo() const override { return m_trafo; }
+    Resolution resolution() const override { return m_resolution; }
+    PixelDim   pixel_dimensions() const override
+    {
+        return {SCALING_FACTOR / m_pxdim_scaled.w_mm,
+                SCALING_FACTOR / m_pxdim_scaled.h_mm};
+    }
+    
+    void draw(const ExPolygon &poly) override { _draw(poly); }
+    void draw(const ClipperLib::Polygon &poly) override { _draw(poly); }
+    
+    EncodedRaster encode(RasterEncoder encoder) const override
+    {
+        return encoder(m_buf.data(), m_resolution.width_px, m_resolution.height_px, 1);    
+    }
+    
+    void clear(const TColor color) { m_raw_renderer.clear(color); }
+};
+
+/*
+ * Captures an anti-aliased monochrome canvas where vectorial
+ * polygons can be rasterized. Fill color is always white and the background is
+ * black. Contours are anti-aliased.
+ * 
+ * A gamma function can be specified at compile time to make it more flexible.
+ */
+using _RasterGrayscaleAA =
+    AGGRaster<agg::pixfmt_gray8, agg::renderer_scanline_aa_solid>;
+
+class RasterGrayscaleAA : public _RasterGrayscaleAA {
+    using Base = _RasterGrayscaleAA;
+    using typename Base::TColor;
+    using typename Base::TValue;
+public:
+    template<class GammaFn>
+    RasterGrayscaleAA(const RasterBase::Resolution &res,
+                      const RasterBase::PixelDim &  pd,
+                      const RasterBase::Trafo &     trafo,
+                      GammaFn &&                    fn)
+        : Base(res, pd, trafo, Colors<TColor>::White, Colors<TColor>::Black,
+               std::forward<GammaFn>(fn))
+    {}
+    
+    uint8_t read_pixel(size_t col, size_t row) const
+    {
+        static_assert(std::is_same<TValue, uint8_t>::value, "Not grayscale pix");
+        
+        uint8_t px;
+        Base::m_buf[row * Base::resolution().width_px + col].get(px);
+        return px;
+    }
+    
+    void clear() { Base::clear(Colors<TColor>::Black); }
+};
+
+class RasterGrayscaleAAGammaPower: public RasterGrayscaleAA {
+public:
+    RasterGrayscaleAAGammaPower(const RasterBase::Resolution &res,
+                                const RasterBase::PixelDim &  pd,
+                                const RasterBase::Trafo &     trafo,
+                                double                        gamma = 1.)
+        : RasterGrayscaleAA(res, pd, trafo, agg::gamma_power(gamma))
+    {}
+};
+
+}} // namespace Slic3r::sla
+
+#endif // AGGRASTER_HPP

+ 21 - 179
src/libslic3r/SLA/Pad.cpp

@@ -11,6 +11,8 @@
 #include "Tesselate.hpp"
 #include "MTUtils.hpp"
 
+#include "TriangulateWall.hpp"
+
 // For debugging:
 // #include <fstream>
 // #include <libnest2d/tools/benchmark.h>
@@ -27,186 +29,27 @@ namespace Slic3r { namespace sla {
 
 namespace {
 
-/// This function will return a triangulation of a sheet connecting an upper
-/// and a lower plate given as input polygons. It will not triangulate the
-/// plates themselves only the sheet. The caller has to specify the lower and
-/// upper z levels in world coordinates as well as the offset difference
-/// between the sheets. If the lower_z_mm is higher than upper_z_mm or the
-/// offset difference is negative, the resulting triangle orientation will be
-/// reversed.
-///
-/// IMPORTANT: This is not a universal triangulation algorithm. It assumes
-/// that the lower and upper polygons are offsetted versions of the same
-/// original polygon. In general, it assumes that one of the polygons is
-/// completely inside the other. The offset difference is the reference
-/// distance from the inner polygon's perimeter to the outer polygon's
-/// perimeter. The real distance will be variable as the clipper offset has
-/// different strategies (rounding, etc...). This algorithm should have
-/// O(2n + 3m) complexity where n is the number of upper vertices and m is the
-/// number of lower vertices.
 Contour3D walls(
     const Polygon &lower,
     const Polygon &upper,
     double         lower_z_mm,
-    double         upper_z_mm,
-    double         offset_difference_mm,
-    ThrowOnCancel  thr = [] {})
+    double         upper_z_mm)
 {
-    Contour3D ret;
-
-    if(upper.points.size() < 3 || lower.size() < 3) return ret;
-
-    // The concept of the algorithm is relatively simple. It will try to find
-    // the closest vertices from the upper and the lower polygon and use those
-    // as starting points. Then it will create the triangles sequentially using
-    // an edge from the upper polygon and a vertex from the lower or vice versa,
-    // depending on the resulting triangle's quality.
-    // The quality is measured by a scalar value. So far it looks like it is
-    // enough to derive it from the slope of the triangle's two edges connecting
-    // the upper and the lower part. A reference slope is calculated from the
-    // height and the offset difference.
-
-    // Offset in the index array for the ceiling
-    const auto offs = upper.points.size();
-
-    // Shorthand for the vertex arrays
-    auto& upts = upper.points, &lpts = lower.points;
-    auto& rpts = ret.points; auto& ind = ret.faces3;
-
-    // If the Z levels are flipped, or the offset difference is negative, we
-    // will interpret that as the triangles normals should be inverted.
-    bool inverted = upper_z_mm < lower_z_mm || offset_difference_mm < 0;
-
-    // Copy the points into the mesh, convert them from 2D to 3D
-    rpts.reserve(upts.size() + lpts.size());
-    ind.reserve(2 * upts.size() + 2 * lpts.size());
-    for (auto &p : upts)
-        rpts.emplace_back(unscaled(p.x()), unscaled(p.y()), upper_z_mm);
-    for (auto &p : lpts)
-        rpts.emplace_back(unscaled(p.x()), unscaled(p.y()), lower_z_mm);
-
-    // Create pointing indices into vertex arrays. u-upper, l-lower
-    size_t uidx = 0, lidx = offs, unextidx = 1, lnextidx = offs + 1;
-
-    // Simple squared distance calculation.
-    auto distfn = [](const Vec3d& p1, const Vec3d& p2) {
-        auto p = p1 - p2; return p.transpose() * p;
-    };
-
-    // We need to find the closest point on lower polygon to the first point on
-    // the upper polygon. These will be our starting points.
-    double distmin = std::numeric_limits<double>::max();
-    for(size_t l = lidx; l < rpts.size(); ++l) {
-        thr();
-        double d = distfn(rpts[l], rpts[uidx]);
-        if(d < distmin) { lidx = l; distmin = d; }
-    }
-
-    // Set up lnextidx to be ahead of lidx in cyclic mode
-    lnextidx = lidx + 1;
-    if(lnextidx == rpts.size()) lnextidx = offs;
-
-    // This will be the flip switch to toggle between upper and lower triangle
-    // creation mode
-    enum class Proceed {
-        UPPER, // A segment from the upper polygon and one vertex from the lower
-        LOWER  // A segment from the lower polygon and one vertex from the upper
-    } proceed = Proceed::UPPER;
-
-    // Flags to help evaluating loop termination.
-    bool ustarted = false, lstarted = false;
-
-    // The variables for the fitness values, one for the actual and one for the
-    // previous.
-    double current_fit = 0, prev_fit = 0;
-
-    // Every triangle of the wall has two edges connecting the upper plate with
-    // the lower plate. From the length of these two edges and the zdiff we
-    // can calculate the momentary squared offset distance at a particular
-    // position on the wall. The average of the differences from the reference
-    // (squared) offset distance will give us the driving fitness value.
-    const double offsdiff2 = std::pow(offset_difference_mm, 2);
-    const double zdiff2 = std::pow(upper_z_mm - lower_z_mm, 2);
-
-    // Mark the current vertex iterator positions. If the iterators return to
-    // the same position, the loop can be terminated.
-    size_t uendidx = uidx, lendidx = lidx;
-
-    do { thr();  // check throw if canceled
-
-        prev_fit = current_fit;
-
-        switch(proceed) {   // proceed depending on the current state
-        case Proceed::UPPER:
-            if(!ustarted || uidx != uendidx) { // there are vertices remaining
-                // Get the 3D vertices in order
-                const Vec3d& p_up1 = rpts[uidx];
-                const Vec3d& p_low = rpts[lidx];
-                const Vec3d& p_up2 = rpts[unextidx];
-
-                // Calculate fitness: the average of the two connecting edges
-                double a = offsdiff2 - (distfn(p_up1, p_low) - zdiff2);
-                double b = offsdiff2 - (distfn(p_up2, p_low) - zdiff2);
-                current_fit = (std::abs(a) + std::abs(b)) / 2;
-
-                if(current_fit > prev_fit) { // fit is worse than previously
-                    proceed = Proceed::LOWER;
-                } else {    // good to go, create the triangle
-                    inverted
-                        ? ind.emplace_back(int(unextidx), int(lidx), int(uidx))
-                        : ind.emplace_back(int(uidx), int(lidx), int(unextidx));
-
-                    // Increment the iterators, rotate if necessary
-                    ++uidx; ++unextidx;
-                    if(unextidx == offs) unextidx = 0;
-                    if(uidx == offs) uidx = 0;
-
-                    ustarted = true;    // mark the movement of the iterators
-                    // so that the comparison to uendidx can be made correctly
-                }
-            } else proceed = Proceed::LOWER;
-
-            break;
-        case Proceed::LOWER:
-            // Mode with lower segment, upper vertex. Same structure:
-            if(!lstarted || lidx != lendidx) {
-                const Vec3d& p_low1 = rpts[lidx];
-                const Vec3d& p_low2 = rpts[lnextidx];
-                const Vec3d& p_up   = rpts[uidx];
-
-                double a = offsdiff2 - (distfn(p_up, p_low1) - zdiff2);
-                double b = offsdiff2 - (distfn(p_up, p_low2) - zdiff2);
-                current_fit = (std::abs(a) + std::abs(b)) / 2;
-
-                if(current_fit > prev_fit) {
-                    proceed = Proceed::UPPER;
-                } else {
-                    inverted
-                        ? ind.emplace_back(int(uidx), int(lnextidx), int(lidx))
-                        : ind.emplace_back(int(lidx), int(lnextidx), int(uidx));
-
-                    ++lidx; ++lnextidx;
-                    if(lnextidx == rpts.size()) lnextidx = offs;
-                    if(lidx == rpts.size()) lidx = offs;
-
-                    lstarted = true;
-                }
-            } else proceed = Proceed::UPPER;
-
-            break;
-        } // end of switch
-    } while(!ustarted || !lstarted || uidx != uendidx || lidx != lendidx);
+    Wall w = triangulate_wall(lower, upper, lower_z_mm, upper_z_mm);
 
+    Contour3D ret;
+    ret.points = std::move(w.first);
+    ret.faces3 = std::move(w.second);
+    
     return ret;
 }
 
 // Same as walls() but with identical higher and lower polygons.
 Contour3D inline straight_walls(const Polygon &plate,
                                 double         lo_z,
-                                double         hi_z,
-                                ThrowOnCancel  thr)
+                                double         hi_z)
 {
-    return walls(plate, plate, lo_z, hi_z, .0 /*offset_diff*/, thr);
+    return walls(plate, plate, lo_z, hi_z);
 }
 
 // Function to cut tiny connector cavities for a given polygon. The input poly
@@ -534,10 +377,8 @@ bool add_cavity(Contour3D &pad, ExPolygon &top_poly, const PadConfig3D &cfg,
     top_poly = pdiff.front();
 
     double z_min = -cfg.wing_height, z_max = 0;
-    double offset_difference = -wing_distance;
-    pad.merge(walls(inner_base.contour, middle_base.contour, z_min, z_max,
-                    offset_difference, thr));
-
+    pad.merge(walls(inner_base.contour, middle_base.contour, z_min, z_max));
+    thr();
     pad.merge(triangulate_expolygon_3d(inner_base, z_min, NORMALS_UP));
 
     return true;
@@ -555,17 +396,17 @@ Contour3D create_outer_pad_geometry(const ExPolygons & skeleton,
             offset_contour_only(pad_part, -scaled(cfg.bottom_offset()));
 
         if (bottom_poly.empty()) continue;
-
+        thr();
+        
         double z_min = -cfg.height, z_max = 0;
-        ret.merge(walls(top_poly.contour, bottom_poly.contour, z_max, z_min,
-                        cfg.bottom_offset(), thr));
+        ret.merge(walls(top_poly.contour, bottom_poly.contour, z_max, z_min));
 
         if (cfg.wing_height > 0. && add_cavity(ret, top_poly, cfg, thr))
             z_max = -cfg.wing_height;
 
         for (auto &h : bottom_poly.holes)
-            ret.merge(straight_walls(h, z_max, z_min, thr));
-
+            ret.merge(straight_walls(h, z_max, z_min));
+        
         ret.merge(triangulate_expolygon_3d(bottom_poly, z_min, NORMALS_DOWN));
         ret.merge(triangulate_expolygon_3d(top_poly, NORMALS_UP));
     }
@@ -581,11 +422,12 @@ Contour3D create_inner_pad_geometry(const ExPolygons & skeleton,
 
     double z_max = 0., z_min = -cfg.height;
     for (const ExPolygon &pad_part : skeleton) {
-        ret.merge(straight_walls(pad_part.contour, z_max, z_min,thr));
+        thr();
+        ret.merge(straight_walls(pad_part.contour, z_max, z_min));
 
         for (auto &h : pad_part.holes)
-            ret.merge(straight_walls(h, z_max, z_min, thr));
-
+            ret.merge(straight_walls(h, z_max, z_min));
+    
         ret.merge(triangulate_expolygon_3d(pad_part, z_min, NORMALS_DOWN));
         ret.merge(triangulate_expolygon_3d(pad_part, z_max, NORMALS_UP));
     }

+ 0 - 320
src/libslic3r/SLA/Raster.cpp

@@ -1,320 +0,0 @@
-#ifndef SLARASTER_CPP
-#define SLARASTER_CPP
-
-#include <functional>
-
-#include <libslic3r/SLA/Raster.hpp>
-#include "libslic3r/ExPolygon.hpp"
-#include "libslic3r/MTUtils.hpp"
-#include <libnest2d/backends/clipper/clipper_polygon.hpp>
-
-// For rasterizing
-#include <agg/agg_basics.h>
-#include <agg/agg_rendering_buffer.h>
-#include <agg/agg_pixfmt_gray.h>
-#include <agg/agg_pixfmt_rgb.h>
-#include <agg/agg_renderer_base.h>
-#include <agg/agg_renderer_scanline.h>
-
-#include <agg/agg_scanline_p.h>
-#include <agg/agg_rasterizer_scanline_aa.h>
-#include <agg/agg_path_storage.h>
-
-// Experimental minz image write:
-#include <miniz.h>
-
-namespace Slic3r {
-
-inline const Polygon& contour(const ExPolygon& p) { return p.contour; }
-inline const ClipperLib::Path& contour(const ClipperLib::Polygon& p) { return p.Contour; }
-
-inline const Polygons& holes(const ExPolygon& p) { return p.holes; }
-inline const ClipperLib::Paths& holes(const ClipperLib::Polygon& p) { return p.Holes; }
-
-namespace sla {
-
-const Raster::TMirroring Raster::NoMirror = {false, false};
-const Raster::TMirroring Raster::MirrorX  = {true, false};
-const Raster::TMirroring Raster::MirrorY  = {false, true};
-const Raster::TMirroring Raster::MirrorXY = {true, true};
-
-
-using TPixelRenderer = agg::pixfmt_gray8; // agg::pixfmt_rgb24;
-using TRawRenderer = agg::renderer_base<TPixelRenderer>;
-using TPixel = TPixelRenderer::color_type;
-using TRawBuffer = agg::rendering_buffer;
-using TBuffer = std::vector<TPixelRenderer::pixel_type>;
-
-using TRendererAA = agg::renderer_scanline_aa_solid<TRawRenderer>;
-
-class Raster::Impl {
-public:
-
-    static const TPixel ColorWhite;
-    static const TPixel ColorBlack;
-
-    using Format = Raster::RawData;
-
-private:
-    Raster::Resolution m_resolution;
-    Raster::PixelDim m_pxdim_scaled;    // used for scaled coordinate polygons
-    TBuffer m_buf;
-    TRawBuffer m_rbuf;
-    TPixelRenderer m_pixfmt;
-    TRawRenderer m_raw_renderer;
-    TRendererAA m_renderer;
-    
-    std::function<double(double)> m_gammafn;
-    Trafo m_trafo;
-    
-    inline void flipy(agg::path_storage& path) const {
-        path.flip_y(0, double(m_resolution.height_px));
-    }
-    
-    inline void flipx(agg::path_storage& path) const {
-        path.flip_x(0, double(m_resolution.width_px));
-    }
-
-public:
-    inline Impl(const Raster::Resolution & res,
-                const Raster::PixelDim &   pd,
-                const Trafo &trafo)
-        : m_resolution(res)
-        , m_pxdim_scaled(SCALING_FACTOR / pd.w_mm, SCALING_FACTOR / pd.h_mm)
-        , m_buf(res.pixels())
-        , m_rbuf(reinterpret_cast<TPixelRenderer::value_type *>(m_buf.data()),
-                 unsigned(res.width_px),
-                 unsigned(res.height_px),
-                 int(res.width_px * TPixelRenderer::num_components))
-        , m_pixfmt(m_rbuf)
-        , m_raw_renderer(m_pixfmt)
-        , m_renderer(m_raw_renderer)
-        , m_trafo(trafo)
-    {
-        m_renderer.color(ColorWhite);
-        
-        if (trafo.gamma > 0) m_gammafn = agg::gamma_power(trafo.gamma);
-        else m_gammafn = agg::gamma_threshold(0.5);
-        
-        clear();
-    }
-
-    template<class P> void draw(const P &poly) {
-        agg::rasterizer_scanline_aa<> ras;
-        agg::scanline_p8 scanlines;
-        
-        ras.gamma(m_gammafn);
-        
-        ras.add_path(to_path(contour(poly)));
-        for(auto& h : holes(poly)) ras.add_path(to_path(h));
-        
-        agg::render_scanlines(ras, scanlines, m_renderer);
-    }
-
-    inline void clear() {
-        m_raw_renderer.clear(ColorBlack);
-    }
-
-    inline TBuffer& buffer()  { return m_buf; }
-    inline const TBuffer& buffer() const { return m_buf; }
-    
-
-    inline const Raster::Resolution resolution() { return m_resolution; }
-    inline const Raster::PixelDim   pixdim()
-    {
-        return {SCALING_FACTOR / m_pxdim_scaled.w_mm,
-                SCALING_FACTOR / m_pxdim_scaled.h_mm};
-    }
-
-private:
-    inline double getPx(const Point& p) {
-        return p(0) * m_pxdim_scaled.w_mm;
-    }
-
-    inline double getPy(const Point& p) {
-        return p(1) * m_pxdim_scaled.h_mm;
-    }
-
-    inline agg::path_storage to_path(const Polygon& poly)
-    {
-        return to_path(poly.points);
-    }
-
-    inline double getPx(const ClipperLib::IntPoint& p) {
-        return p.X * m_pxdim_scaled.w_mm;
-    }
-
-    inline double getPy(const ClipperLib::IntPoint& p) {
-        return p.Y * m_pxdim_scaled.h_mm;
-    }
-
-    template<class PointVec> agg::path_storage _to_path(const PointVec& v)
-    {
-        agg::path_storage path;
-        
-        auto it = v.begin();
-        path.move_to(getPx(*it), getPy(*it));
-        while(++it != v.end()) path.line_to(getPx(*it), getPy(*it));
-        path.line_to(getPx(v.front()), getPy(v.front()));
-        
-        return path;
-    }
-   
-    template<class PointVec> agg::path_storage _to_path_flpxy(const PointVec& v)
-    {
-        agg::path_storage path;
-        
-        auto it = v.begin();
-        path.move_to(getPy(*it), getPx(*it));
-        while(++it != v.end()) path.line_to(getPy(*it), getPx(*it));
-        path.line_to(getPy(v.front()), getPx(v.front()));
-        
-        return path;
-    }
-    
-    template<class PointVec> agg::path_storage to_path(const PointVec &v)
-    {
-        auto path = m_trafo.flipXY ? _to_path_flpxy(v) : _to_path(v);
-        
-        path.translate_all_paths(m_trafo.origin_x * m_pxdim_scaled.w_mm,
-                                 m_trafo.origin_y * m_pxdim_scaled.h_mm);
-        
-        if(m_trafo.mirror_x) flipx(path);
-        if(m_trafo.mirror_y) flipy(path);
-        
-        return path;
-    }
-
-};
-
-const TPixel Raster::Impl::ColorWhite = TPixel(255);
-const TPixel Raster::Impl::ColorBlack = TPixel(0);
-
-Raster::Raster() { reset(); }
-
-Raster::Raster(const Raster::Resolution &r,
-               const Raster::PixelDim &  pd,
-               const Raster::Trafo &     tr)
-{
-    reset(r, pd, tr);
-}
-
-Raster::~Raster() = default;
-
-Raster::Raster(Raster &&m) = default;
-Raster &Raster::operator=(Raster &&) = default;
-
-void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd,
-                   const Trafo &trafo)
-{
-    m_impl.reset();
-    m_impl.reset(new Impl(r, pd, trafo));
-}
-
-void Raster::reset()
-{
-    m_impl.reset();
-}
-
-Raster::Resolution Raster::resolution() const
-{
-    if (m_impl) return m_impl->resolution();
-    
-    return Resolution{0, 0};
-}
-
-Raster::PixelDim Raster::pixel_dimensions() const
-{
-    if (m_impl) return m_impl->pixdim();
-    
-    return PixelDim{0., 0.};
-}
-
-void Raster::clear()
-{
-    assert(m_impl);
-    m_impl->clear();
-}
-
-void Raster::draw(const ExPolygon &expoly)
-{
-    assert(m_impl);
-    m_impl->draw(expoly);
-}
-
-void Raster::draw(const ClipperLib::Polygon &poly)
-{
-    assert(m_impl);
-    m_impl->draw(poly);
-}
-
-uint8_t Raster::read_pixel(size_t x, size_t y) const
-{
-    assert (m_impl);
-    TPixel::value_type px;
-    m_impl->buffer()[y * resolution().width_px + x].get(px);
-    return px;
-}
-
-PNGImage & PNGImage::serialize(const Raster &raster)
-{
-    size_t s = 0;
-    m_buffer.clear();
-    
-    void *rawdata = tdefl_write_image_to_png_file_in_memory(
-        get_internals(raster).buffer().data(),
-        int(raster.resolution().width_px),
-        int(raster.resolution().height_px), 1, &s);
-    
-    // On error, data() will return an empty vector. No other info can be
-    // retrieved from miniz anyway...
-    if (rawdata == nullptr) return *this;
-    
-    auto ptr = static_cast<std::uint8_t*>(rawdata);
-    
-    m_buffer.reserve(s);
-    std::copy(ptr, ptr + s, std::back_inserter(m_buffer));
-    
-    MZ_FREE(rawdata);
-    return *this;
-}
-
-std::ostream &operator<<(std::ostream &stream, const Raster::RawData &bytes)
-{
-    stream.write(reinterpret_cast<const char *>(bytes.data()),
-                 std::streamsize(bytes.size()));
-    
-    return stream;
-}
-
-Raster::RawData::~RawData() = default;
-
-PPMImage & PPMImage::serialize(const Raster &raster)
-{
-    auto header = std::string("P5 ") +
-            std::to_string(raster.resolution().width_px) + " " +
-            std::to_string(raster.resolution().height_px) + " " + "255 ";
-    
-    const auto &impl = get_internals(raster);
-    auto sz = impl.buffer().size() * sizeof(TBuffer::value_type);
-    size_t s = sz + header.size();
-    
-    m_buffer.clear();
-    m_buffer.reserve(s);
-
-    auto buff = reinterpret_cast<const std::uint8_t*>(impl.buffer().data());
-    std::copy(header.begin(), header.end(), std::back_inserter(m_buffer));
-    std::copy(buff, buff+sz, std::back_inserter(m_buffer));
-    
-    return *this;
-}
-
-const Raster::Impl &Raster::RawData::get_internals(const Raster &raster)
-{
-    return *raster.m_impl;
-}
-
-} // namespace sla
-} // namespace Slic3r
-
-#endif // SLARASTER_CPP

+ 0 - 157
src/libslic3r/SLA/Raster.hpp

@@ -1,157 +0,0 @@
-#ifndef SLA_RASTER_HPP
-#define SLA_RASTER_HPP
-
-#include <ostream>
-#include <memory>
-#include <vector>
-#include <array>
-#include <utility>
-#include <cstdint>
-
-#include <libslic3r/ExPolygon.hpp>
-
-namespace ClipperLib { struct Polygon; }
-
-namespace Slic3r {
-namespace sla {
-
-/**
- * @brief Raster captures an anti-aliased monochrome canvas where vectorial
- * polygons can be rasterized. Fill color is always white and the background is
- * black. Contours are anti-aliased.
- *
- * 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> m_impl;
-public:
-
-    // Raw byte buffer paired with its size. Suitable for compressed image data.
-    class RawData
-    {
-    protected:
-        std::vector<std::uint8_t> m_buffer;
-        const Impl& get_internals(const Raster& raster);
-    public:
-        RawData() = default;
-        RawData(std::vector<std::uint8_t>&& data): m_buffer(std::move(data)) {}
-        virtual ~RawData();
-
-        RawData(const RawData &) = delete;
-        RawData &operator=(const RawData &) = delete;
-
-        RawData(RawData &&) = default;
-        RawData &operator=(RawData &&) = default;
-
-        size_t size() const { return m_buffer.size(); }
-        const uint8_t * data() const { return m_buffer.data(); }
-
-        virtual RawData& serialize(const Raster &/*raster*/)  { return *this; }
-        virtual std::string get_file_extension() const = 0;
-    };
-
-    /// Type that represents a resolution in pixels.
-    struct Resolution {
-        size_t width_px;
-        size_t height_px;
-
-        inline Resolution(size_t w = 0, size_t h = 0)
-            : width_px(w), height_px(h)
-        {}
-
-        inline size_t pixels() const { return width_px * height_px; }
-    };
-
-    /// Types that represents the dimension of a pixel in millimeters.
-    struct PixelDim {
-        double w_mm;
-        double h_mm;
-        inline PixelDim(double px_width_mm = 0.0, double px_height_mm = 0.0):
-            w_mm(px_width_mm), h_mm(px_height_mm) {}
-    };
-
-    enum Orientation { roLandscape, roPortrait };
-
-    using TMirroring = std::array<bool, 2>;
-    static const TMirroring NoMirror;
-    static const TMirroring MirrorX;
-    static const TMirroring MirrorY;
-    static const TMirroring MirrorXY;
-
-    struct Trafo {
-        bool mirror_x = false, mirror_y = false, flipXY = false;
-        coord_t origin_x = 0, origin_y = 0;
-
-        // If gamma is zero, thresholding will be performed which disables AA.
-        double gamma = 1.;
-
-        // Portrait orientation will make sure the drawed polygons are rotated
-        // by 90 degrees.
-        Trafo(Orientation o = roLandscape, const TMirroring &mirror = NoMirror)
-            // XY flipping implicitly does an X mirror
-            : mirror_x(o == roPortrait ? !mirror[0] : mirror[0])
-            , mirror_y(!mirror[1]) // Makes raster origin to be top left corner
-            , flipXY(o == roPortrait)
-        {}
-    };
-
-    Raster();
-    Raster(const Resolution &r,
-           const PixelDim &  pd,
-           const Trafo &     tr = {});
-
-    Raster(const Raster& cpy) = delete;
-    Raster& operator=(const Raster& cpy) = delete;
-    Raster(Raster&& m);
-    Raster& operator=(Raster&&);
-    ~Raster();
-
-    /// Reallocated everything for the given resolution and pixel dimension.
-    void reset(const Resolution& r,
-               const PixelDim& pd,
-               const Trafo &tr = {});
-
-    /**
-     * Release the allocated resources. Drawing in this state ends in
-     * unspecified behavior.
-     */
-    void reset();
-
-    /// Get the resolution of the raster.
-    Resolution resolution() const;
-    PixelDim   pixel_dimensions() const;
-
-    /// Clear the raster with black color.
-    void clear();
-
-    /// Draw a polygon with holes.
-    void draw(const ExPolygon& poly);
-    void draw(const ClipperLib::Polygon& poly);
-
-    uint8_t read_pixel(size_t w, size_t h) const;
-
-    inline bool empty() const { return ! bool(m_impl); }
-
-};
-
-class PNGImage: public Raster::RawData {
-public:
-    PNGImage& serialize(const Raster &raster) override;
-    std::string get_file_extension() const override { return "png"; }
-};
-
-class PPMImage: public Raster::RawData {
-public:
-    PPMImage& serialize(const Raster &raster) override;
-    std::string get_file_extension() const override { return "ppm"; }
-};
-
-std::ostream& operator<<(std::ostream &stream, const Raster::RawData &bytes);
-
-} // sla
-} // Slic3r
-
-
-#endif // SLARASTER_HPP

Some files were not shown because too many files changed in this diff