Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortamasmeszaros <meszaros.q@gmail.com>2019-06-20 11:03:47 +0300
committertamasmeszaros <meszaros.q@gmail.com>2019-06-20 11:04:17 +0300
commitc82fd692c3a67c439eec860a77155cee1b041aa8 (patch)
tree68d7507a7330a3c9acd01c084095693b175b472f /src/libslic3r/SLA
parentd7684188f90c8eb2ae1f7bc881aa918d3177ecd6 (diff)
parent09f4831f4eba9fd5190d974904945f8c5c79b99f (diff)
Merge branch 'master' into tm_builtin_pad
Diffstat (limited to 'src/libslic3r/SLA')
-rw-r--r--src/libslic3r/SLA/SLARaster.cpp329
-rw-r--r--src/libslic3r/SLA/SLARaster.hpp150
-rw-r--r--src/libslic3r/SLA/SLARasterWriter.cpp136
-rw-r--r--src/libslic3r/SLA/SLARasterWriter.hpp167
-rw-r--r--src/libslic3r/SLA/SLARotfinder.cpp4
-rw-r--r--src/libslic3r/SLA/SLASupportTreeIGL.cpp17
-rw-r--r--src/libslic3r/SLA/bicubic.h186
7 files changed, 974 insertions, 15 deletions
diff --git a/src/libslic3r/SLA/SLARaster.cpp b/src/libslic3r/SLA/SLARaster.cpp
new file mode 100644
index 000000000..32a88b1b5
--- /dev/null
+++ b/src/libslic3r/SLA/SLARaster.cpp
@@ -0,0 +1,329 @@
+#ifndef SLARASTER_CPP
+#define SLARASTER_CPP
+
+#include <functional>
+
+#include "SLARaster.hpp"
+#include "libslic3r/ExPolygon.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 {
+
+class Raster::Impl {
+public:
+ 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>;
+
+ static const TPixel ColorWhite;
+ static const TPixel ColorBlack;
+
+ using Format = Raster::Format;
+
+private:
+ Raster::Resolution m_resolution;
+// Raster::PixelDim m_pxdim;
+ 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;
+ std::array<bool, 2> m_mirror;
+ Format m_fmt = Format::PNG;
+
+ inline void flipy(agg::path_storage& path) const {
+ path.flip_y(0, m_resolution.height_px);
+ }
+
+ inline void flipx(agg::path_storage& path) const {
+ path.flip_x(0, m_resolution.width_px);
+ }
+
+public:
+
+ inline Impl(const Raster::Resolution& res, const Raster::PixelDim &pd,
+ const std::array<bool, 2>& mirror, double gamma = 1.0):
+ m_resolution(res),
+// m_pxdim(pd),
+ 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()),
+ res.width_px, 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_mirror(mirror)
+ {
+ m_renderer.color(ColorWhite);
+
+ if(gamma > 0) m_gammafn = agg::gamma_power(gamma);
+ else m_gammafn = agg::gamma_threshold(0.5);
+
+ clear();
+ }
+
+ inline Impl(const Raster::Resolution& res,
+ const Raster::PixelDim &pd,
+ Format fmt,
+ double gamma = 1.0):
+ Impl(res, pd, {false, false}, gamma)
+ {
+ switch (fmt) {
+ case Format::PNG: m_mirror = {false, true}; break;
+ case Format::RAW: m_mirror = {false, false}; break;
+ }
+ m_fmt = fmt;
+ }
+
+ template<class P> void draw(const P &poly) {
+ agg::rasterizer_scanline_aa<> ras;
+ agg::scanline_p8 scanlines;
+
+ ras.gamma(m_gammafn);
+
+ auto&& path = to_path(contour(poly));
+
+ if(m_mirror[X]) flipx(path);
+ if(m_mirror[Y]) flipy(path);
+
+ ras.add_path(path);
+
+ for(auto& h : holes(poly)) {
+ auto&& holepath = to_path(h);
+ if(m_mirror[X]) flipx(holepath);
+ if(m_mirror[Y]) flipy(holepath);
+ ras.add_path(holepath);
+ }
+
+ agg::render_scanlines(ras, scanlines, m_renderer);
+ }
+
+ inline void clear() {
+ m_raw_renderer.clear(ColorBlack);
+ }
+
+ inline TBuffer& buffer() { return m_buf; }
+
+ inline Format format() const { return m_fmt; }
+
+ inline const Raster::Resolution resolution() { return m_resolution; }
+
+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& poly)
+ {
+ agg::path_storage path;
+
+ auto it = poly.begin();
+ path.move_to(getPx(*it), getPy(*it));
+
+ while(++it != poly.end())
+ path.line_to(getPx(*it), getPy(*it));
+
+ path.line_to(getPx(poly.front()), getPy(poly.front()));
+ return path;
+ }
+
+};
+
+const Raster::Impl::TPixel Raster::Impl::ColorWhite = Raster::Impl::TPixel(255);
+const Raster::Impl::TPixel Raster::Impl::ColorBlack = Raster::Impl::TPixel(0);
+
+template<> Raster::Raster() { reset(); };
+Raster::~Raster() = default;
+
+// Raster::Raster(Raster &&m) = default;
+// Raster& Raster::operator=(Raster&&) = default;
+
+// FIXME: remove after migrating to higher version of windows compiler
+Raster::Raster(Raster &&m): m_impl(std::move(m.m_impl)) {}
+Raster& Raster::operator=(Raster &&m) {
+ m_impl = std::move(m.m_impl); return *this;
+}
+
+void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd,
+ Format fmt, double gamma)
+{
+ m_impl.reset();
+ m_impl.reset(new Impl(r, pd, fmt, gamma));
+}
+
+void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd,
+ const std::array<bool, 2>& mirror, double gamma)
+{
+ m_impl.reset();
+ m_impl.reset(new Impl(r, pd, mirror, gamma));
+}
+
+void Raster::reset()
+{
+ m_impl.reset();
+}
+
+Raster::Resolution Raster::resolution() const
+{
+ if(m_impl) return m_impl->resolution();
+
+ return Resolution(0, 0);
+}
+
+void Raster::clear()
+{
+ assert(m_impl);
+ m_impl->clear();
+}
+
+void Raster::draw(const ExPolygon &expoly)
+{
+ m_impl->draw(expoly);
+}
+
+void Raster::draw(const ClipperLib::Polygon &poly)
+{
+ m_impl->draw(poly);
+}
+
+void Raster::save(std::ostream& stream, Format fmt)
+{
+ assert(m_impl);
+ if(!stream.good()) return;
+
+ switch(fmt) {
+ case Format::PNG: {
+ auto& b = m_impl->buffer();
+ size_t out_len = 0;
+ void * rawdata = tdefl_write_image_to_png_file_in_memory(
+ b.data(),
+ int(resolution().width_px),
+ int(resolution().height_px), 1, &out_len);
+
+ if(rawdata == nullptr) break;
+
+ stream.write(static_cast<const char*>(rawdata),
+ std::streamsize(out_len));
+
+ MZ_FREE(rawdata);
+
+ break;
+ }
+ case Format::RAW: {
+ stream << "P5 "
+ << m_impl->resolution().width_px << " "
+ << m_impl->resolution().height_px << " "
+ << "255 ";
+
+ auto sz = m_impl->buffer().size()*sizeof(Impl::TBuffer::value_type);
+ stream.write(reinterpret_cast<const char*>(m_impl->buffer().data()),
+ std::streamsize(sz));
+ }
+ }
+}
+
+void Raster::save(std::ostream &stream)
+{
+ save(stream, m_impl->format());
+}
+
+RawBytes Raster::save(Format fmt)
+{
+ assert(m_impl);
+
+ std::vector<std::uint8_t> data; size_t s = 0;
+
+ switch(fmt) {
+ case Format::PNG: {
+ void *rawdata = tdefl_write_image_to_png_file_in_memory(
+ m_impl->buffer().data(),
+ int(resolution().width_px),
+ int(resolution().height_px), 1, &s);
+
+ if(rawdata == nullptr) break;
+ auto ptr = static_cast<std::uint8_t*>(rawdata);
+
+ data.reserve(s); std::copy(ptr, ptr + s, std::back_inserter(data));
+
+ MZ_FREE(rawdata);
+ break;
+ }
+ case Format::RAW: {
+ auto header = std::string("P5 ") +
+ std::to_string(m_impl->resolution().width_px) + " " +
+ std::to_string(m_impl->resolution().height_px) + " " + "255 ";
+
+ auto sz = m_impl->buffer().size()*sizeof(Impl::TBuffer::value_type);
+ s = sz + header.size();
+
+ data.reserve(s);
+
+ auto buff = reinterpret_cast<std::uint8_t*>(m_impl->buffer().data());
+ std::copy(header.begin(), header.end(), std::back_inserter(data));
+ std::copy(buff, buff+sz, std::back_inserter(data));
+
+ break;
+ }
+ }
+
+ return {std::move(data)};
+}
+
+RawBytes Raster::save()
+{
+ return save(m_impl->format());
+}
+
+}
+}
+
+#endif // SLARASTER_CPP
diff --git a/src/libslic3r/SLA/SLARaster.hpp b/src/libslic3r/SLA/SLARaster.hpp
new file mode 100644
index 000000000..d3bd52d92
--- /dev/null
+++ b/src/libslic3r/SLA/SLARaster.hpp
@@ -0,0 +1,150 @@
+#ifndef SLARASTER_HPP
+#define SLARASTER_HPP
+
+#include <ostream>
+#include <memory>
+#include <vector>
+#include <array>
+#include <utility>
+#include <cstdint>
+
+namespace ClipperLib { struct Polygon; }
+
+namespace Slic3r {
+
+class ExPolygon;
+
+namespace sla {
+
+// Raw byte buffer paired with its size. Suitable for compressed PNG data.
+class RawBytes {
+
+ std::vector<std::uint8_t> m_buffer;
+public:
+
+ RawBytes() = default;
+ RawBytes(std::vector<std::uint8_t>&& data): m_buffer(std::move(data)) {}
+
+ size_t size() const { return m_buffer.size(); }
+ const uint8_t * data() { return m_buffer.data(); }
+
+ RawBytes(const RawBytes&) = delete;
+ RawBytes& operator=(const RawBytes&) = delete;
+
+ // /////////////////////////////////////////////////////////////////////////
+ // FIXME: the following is needed for MSVC2013 compatibility
+ // /////////////////////////////////////////////////////////////////////////
+
+ // RawBytes(RawBytes&&) = default;
+ // RawBytes& operator=(RawBytes&&) = default;
+
+ RawBytes(RawBytes&& mv) : m_buffer(std::move(mv.m_buffer)) {}
+ RawBytes& operator=(RawBytes&& mv) {
+ m_buffer = std::move(mv.m_buffer);
+ return *this;
+ }
+
+ // /////////////////////////////////////////////////////////////////////////
+};
+
+/**
+ * @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:
+
+ /// Supported compression types
+ enum class Format {
+ RAW, //!> Uncompressed pixel data
+ PNG //!> PNG compression
+ };
+
+ /// Type that represents a resolution in pixels.
+ struct Resolution {
+ unsigned width_px;
+ unsigned height_px;
+
+ inline Resolution(unsigned w = 0, unsigned h = 0):
+ width_px(w), height_px(h) {}
+
+ inline unsigned pixels() const /*noexcept*/ {
+ 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) {}
+ };
+
+ /// Constructor taking the resolution and the pixel dimension.
+ template <class...Args> Raster(Args...args) {
+ reset(std::forward<Args>(args)...);
+ }
+
+ 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.
+ /// The third parameter is either the X, Y mirroring or a supported format
+ /// for which the correct mirroring will be configured.
+ void reset(const Resolution&,
+ const PixelDim&,
+ const std::array<bool, 2>& mirror,
+ double gamma = 1.0);
+
+ void reset(const Resolution& r,
+ const PixelDim& pd,
+ Format o,
+ double gamma = 1.0);
+
+ /**
+ * Release the allocated resources. Drawing in this state ends in
+ * unspecified behavior.
+ */
+ 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);
+ void draw(const ClipperLib::Polygon& poly);
+
+ // Saving the raster:
+ // It is possible to override the format given in the constructor but
+ // be aware that the mirroring will not be modified.
+
+ /// Save the raster on the specified stream.
+ void save(std::ostream& stream, Format);
+ void save(std::ostream& stream);
+
+ /// Save into a continuous byte stream which is returned.
+ RawBytes save(Format fmt);
+ RawBytes save();
+};
+
+// This prevents the duplicate default constructor warning on MSVC2013
+template<> Raster::Raster();
+
+
+} // sla
+} // Slic3r
+
+#endif // SLARASTER_HPP
diff --git a/src/libslic3r/SLA/SLARasterWriter.cpp b/src/libslic3r/SLA/SLARasterWriter.cpp
new file mode 100644
index 000000000..f7c3925ac
--- /dev/null
+++ b/src/libslic3r/SLA/SLARasterWriter.cpp
@@ -0,0 +1,136 @@
+#include "SLARasterWriter.hpp"
+#include "libslic3r/Zipper.hpp"
+#include "ExPolygon.hpp"
+#include <libnest2d/backends/clipper/clipper_polygon.hpp>
+
+#include <boost/log/trivial.hpp>
+#include <boost/filesystem/path.hpp>
+
+namespace Slic3r { namespace sla {
+
+std::string SLARasterWriter::createIniContent(const std::string& projectname) const
+{
+ auto expt_str = std::to_string(m_exp_time_s);
+ auto expt_first_str = std::to_string(m_exp_time_first_s);
+ auto layerh_str = std::to_string(m_layer_height);
+
+ const std::string cnt_fade_layers = std::to_string(m_cnt_fade_layers);
+ const std::string cnt_slow_layers = std::to_string(m_cnt_slow_layers);
+ const std::string cnt_fast_layers = std::to_string(m_cnt_fast_layers);
+ const std::string used_material = std::to_string(m_used_material);
+
+ return std::string(
+ "action = print\n"
+ "jobDir = ") + projectname + "\n" +
+ "expTime = " + expt_str + "\n"
+ "expTimeFirst = " + expt_first_str + "\n"
+ "numFade = " + cnt_fade_layers + "\n"
+ "layerHeight = " + layerh_str + "\n"
+ "usedMaterial = " + used_material + "\n"
+ "numSlow = " + cnt_slow_layers + "\n"
+ "numFast = " + cnt_fast_layers + "\n";
+}
+
+void SLARasterWriter::flpXY(ClipperLib::Polygon &poly)
+{
+ for(auto& p : poly.Contour) std::swap(p.X, p.Y);
+ std::reverse(poly.Contour.begin(), poly.Contour.end());
+
+ for(auto& h : poly.Holes) {
+ for(auto& p : h) std::swap(p.X, p.Y);
+ std::reverse(h.begin(), h.end());
+ }
+}
+
+void SLARasterWriter::flpXY(ExPolygon &poly)
+{
+ for(auto& p : poly.contour.points) p = Point(p.y(), p.x());
+ std::reverse(poly.contour.points.begin(), poly.contour.points.end());
+
+ for(auto& h : poly.holes) {
+ for(auto& p : h.points) p = Point(p.y(), p.x());
+ std::reverse(h.points.begin(), h.points.end());
+ }
+}
+
+SLARasterWriter::SLARasterWriter(const SLAPrinterConfig &cfg,
+ const SLAMaterialConfig &mcfg,
+ double layer_height)
+{
+ double w = cfg.display_width.getFloat();
+ double h = cfg.display_height.getFloat();
+ auto pw = unsigned(cfg.display_pixels_x.getInt());
+ auto ph = unsigned(cfg.display_pixels_y.getInt());
+
+ m_mirror[X] = cfg.display_mirror_x.getBool();
+
+ // PNG raster will implicitly do an Y mirror
+ m_mirror[Y] = ! cfg.display_mirror_y.getBool();
+
+ auto ro = cfg.display_orientation.getInt();
+
+ if(ro == roPortrait) {
+ std::swap(w, h);
+ std::swap(pw, ph);
+ m_o = roPortrait;
+
+ // XY flipping implicitly does an X mirror
+ m_mirror[X] = ! m_mirror[X];
+ } else m_o = roLandscape;
+
+ m_res = Raster::Resolution(pw, ph);
+ m_pxdim = Raster::PixelDim(w/pw, h/ph);
+ m_exp_time_s = mcfg.exposure_time.getFloat();
+ m_exp_time_first_s = mcfg.initial_exposure_time.getFloat();
+ m_layer_height = layer_height;
+
+ m_gamma = cfg.gamma_correction.getFloat();
+}
+
+void SLARasterWriter::save(const std::string &fpath, const std::string &prjname)
+{
+ try {
+ Zipper zipper(fpath); // zipper with no compression
+
+ std::string project = prjname.empty()?
+ boost::filesystem::path(fpath).stem().string() : prjname;
+
+ zipper.add_entry("config.ini");
+
+ zipper << createIniContent(project);
+
+ for(unsigned i = 0; i < m_layers_rst.size(); i++)
+ {
+ if(m_layers_rst[i].rawbytes.size() > 0) {
+ char lyrnum[6];
+ std::sprintf(lyrnum, "%.5d", i);
+ auto zfilename = project + lyrnum + ".png";
+
+ // Add binary entry to the zipper
+ zipper.add_entry(zfilename,
+ m_layers_rst[i].rawbytes.data(),
+ m_layers_rst[i].rawbytes.size());
+ }
+ }
+
+ zipper.finalize();
+ } catch(std::exception& e) {
+ BOOST_LOG_TRIVIAL(error) << e.what();
+ // Rethrow the exception
+ throw;
+ }
+}
+
+void SLARasterWriter::set_statistics(const std::vector<double> statistics)
+{
+ if (statistics.size() != psCnt)
+ return;
+
+ m_used_material = statistics[psUsedMaterial];
+ m_cnt_fade_layers = int(statistics[psNumFade]);
+ m_cnt_slow_layers = int(statistics[psNumSlow]);
+ m_cnt_fast_layers = int(statistics[psNumFast]);
+}
+
+} // namespace sla
+} // namespace Slic3r
diff --git a/src/libslic3r/SLA/SLARasterWriter.hpp b/src/libslic3r/SLA/SLARasterWriter.hpp
new file mode 100644
index 000000000..7133d2dde
--- /dev/null
+++ b/src/libslic3r/SLA/SLARasterWriter.hpp
@@ -0,0 +1,167 @@
+#ifndef SLARASTERWRITER_HPP
+#define SLARASTERWRITER_HPP
+
+// For png export of the sliced model
+#include <fstream>
+#include <sstream>
+#include <vector>
+#include <array>
+
+#include "libslic3r/PrintConfig.hpp"
+
+#include "SLARaster.hpp"
+
+namespace Slic3r { namespace sla {
+
+// Implementation for PNG raster output
+// Be aware that if a large number of layers are allocated, it can very well
+// exhaust the available memory especially on 32 bit platform.
+// This class is designed to be used in parallel mode. Layers have an ID and
+// each layer can be written and compressed independently (in parallel).
+// At the end when all layers where written, the save method can be used to
+// write out the result into a zipped archive.
+class SLARasterWriter
+{
+public:
+ enum RasterOrientation {
+ roLandscape,
+ roPortrait
+ };
+
+ // Used for addressing parameters of set_statistics()
+ enum ePrintStatistics
+ {
+ psUsedMaterial = 0,
+ psNumFade,
+ psNumSlow,
+ psNumFast,
+
+ psCnt
+ };
+
+private:
+
+ // A struct to bind the raster image data and its compressed bytes together.
+ struct Layer {
+ Raster raster;
+ RawBytes rawbytes;
+
+ Layer() = default;
+ Layer(const Layer&) = delete; // The image is big, do not copy by accident
+ Layer& operator=(const Layer&) = delete;
+
+ // /////////////////////////////////////////////////////////////////////
+ // FIXME: the following is needed for MSVC2013 compatibility
+ // /////////////////////////////////////////////////////////////////////
+
+ // Layer(Layer&& m) = default;
+ // Layer& operator=(Layer&&) = default;
+ Layer(Layer &&m):
+ raster(std::move(m.raster)), rawbytes(std::move(m.rawbytes)) {}
+ Layer& operator=(Layer &&m) {
+ raster = std::move(m.raster); rawbytes = std::move(m.rawbytes);
+ return *this;
+ }
+ };
+
+ // We will save the compressed PNG data into RawBytes type buffers in
+ // parallel. Later we can write every layer to the disk sequentially.
+ std::vector<Layer> m_layers_rst;
+ Raster::Resolution m_res;
+ Raster::PixelDim m_pxdim;
+ double m_exp_time_s = .0, m_exp_time_first_s = .0;
+ double m_layer_height = .0;
+ RasterOrientation m_o = roPortrait;
+ std::array<bool, 2> m_mirror;
+
+ double m_gamma;
+
+ double m_used_material = 0.0;
+ int m_cnt_fade_layers = 0;
+ int m_cnt_slow_layers = 0;
+ int m_cnt_fast_layers = 0;
+
+ std::string createIniContent(const std::string& projectname) const;
+
+ static void flpXY(ClipperLib::Polygon& poly);
+ static void flpXY(ExPolygon& poly);
+
+public:
+
+ SLARasterWriter(const SLAPrinterConfig& cfg,
+ const SLAMaterialConfig& mcfg,
+ double layer_height);
+
+ SLARasterWriter(const SLARasterWriter& ) = delete;
+ SLARasterWriter& operator=(const SLARasterWriter&) = delete;
+
+ // /////////////////////////////////////////////////////////////////////////
+ // FIXME: the following is needed for MSVC2013 compatibility
+ // /////////////////////////////////////////////////////////////////////////
+
+ // SLARasterWriter(SLARasterWriter&& m) = default;
+ // SLARasterWriter& operator=(SLARasterWriter&&) = default;
+ SLARasterWriter(SLARasterWriter&& m):
+ m_layers_rst(std::move(m.m_layers_rst)),
+ m_res(m.m_res),
+ m_pxdim(m.m_pxdim),
+ m_exp_time_s(m.m_exp_time_s),
+ m_exp_time_first_s(m.m_exp_time_first_s),
+ m_layer_height(m.m_layer_height),
+ m_o(m.m_o),
+ m_mirror(std::move(m.m_mirror)),
+ m_gamma(m.m_gamma),
+ m_used_material(m.m_used_material),
+ m_cnt_fade_layers(m.m_cnt_fade_layers),
+ m_cnt_slow_layers(m.m_cnt_slow_layers),
+ m_cnt_fast_layers(m.m_cnt_fast_layers)
+ {}
+
+ // /////////////////////////////////////////////////////////////////////////
+
+ inline void layers(unsigned cnt) { if(cnt > 0) m_layers_rst.resize(cnt); }
+ inline unsigned layers() const { return unsigned(m_layers_rst.size()); }
+
+ template<class Poly> void draw_polygon(const Poly& p, unsigned lyr) {
+ assert(lyr < m_layers_rst.size());
+ if(m_o == roPortrait) {
+ Poly poly(p); flpXY(poly);
+ m_layers_rst[lyr].raster.draw(poly);
+ }
+ else m_layers_rst[lyr].raster.draw(p);
+ }
+
+ inline void begin_layer(unsigned lyr) {
+ if(m_layers_rst.size() <= lyr) m_layers_rst.resize(lyr+1);
+ m_layers_rst[lyr].raster.reset(m_res, m_pxdim, m_mirror, m_gamma);
+ }
+
+ inline void begin_layer() {
+ m_layers_rst.emplace_back();
+ m_layers_rst.front().raster.reset(m_res, m_pxdim, m_mirror, m_gamma);
+ }
+
+ inline void finish_layer(unsigned lyr_id) {
+ assert(lyr_id < m_layers_rst.size());
+ m_layers_rst[lyr_id].rawbytes =
+ m_layers_rst[lyr_id].raster.save(Raster::Format::PNG);
+ m_layers_rst[lyr_id].raster.reset();
+ }
+
+ inline void finish_layer() {
+ if(!m_layers_rst.empty()) {
+ m_layers_rst.back().rawbytes =
+ m_layers_rst.back().raster.save(Raster::Format::PNG);
+ m_layers_rst.back().raster.reset();
+ }
+ }
+
+ void save(const std::string& fpath, const std::string& prjname = "");
+
+ void set_statistics(const std::vector<double> statistics);
+};
+
+} // namespace sla
+} // namespace Slic3r
+
+#endif // SLARASTERWRITER_HPP
diff --git a/src/libslic3r/SLA/SLARotfinder.cpp b/src/libslic3r/SLA/SLARotfinder.cpp
index 1a91041b7..2e64059d6 100644
--- a/src/libslic3r/SLA/SLARotfinder.cpp
+++ b/src/libslic3r/SLA/SLARotfinder.cpp
@@ -44,7 +44,7 @@ std::array<double, 3> find_best_rotation(const ModelObject& modelobj,
// call the status callback in each iteration but the actual value may be
// the same for subsequent iterations (status goes from 0 to 100 but
// iterations can be many more)
- auto objfunc = [&emesh, &status, &statuscb, max_tries]
+ auto objfunc = [&emesh, &status, &statuscb, &stopcond, max_tries]
(double rx, double ry, double rz)
{
EigenMesh3D& m = emesh;
@@ -91,7 +91,7 @@ std::array<double, 3> find_best_rotation(const ModelObject& modelobj,
}
// report status
- statuscb( unsigned(++status * 100.0/max_tries) );
+ if(!stopcond()) statuscb( unsigned(++status * 100.0/max_tries) );
return score;
};
diff --git a/src/libslic3r/SLA/SLASupportTreeIGL.cpp b/src/libslic3r/SLA/SLASupportTreeIGL.cpp
index 04e6f79c7..4b6498a20 100644
--- a/src/libslic3r/SLA/SLASupportTreeIGL.cpp
+++ b/src/libslic3r/SLA/SLASupportTreeIGL.cpp
@@ -189,19 +189,10 @@ EigenMesh3D::EigenMesh3D(const TriangleMesh& tmesh): m_aabb(new AABBImpl()) {
V.resize(3*stl.stats.number_of_facets, 3);
F.resize(stl.stats.number_of_facets, 3);
for (unsigned int i = 0; i < stl.stats.number_of_facets; ++i) {
- const stl_facet* facet = stl.facet_start+i;
- V(3*i+0, 0) = double(facet->vertex[0](0));
- V(3*i+0, 1) = double(facet->vertex[0](1));
- V(3*i+0, 2) = double(facet->vertex[0](2));
-
- V(3*i+1, 0) = double(facet->vertex[1](0));
- V(3*i+1, 1) = double(facet->vertex[1](1));
- V(3*i+1, 2) = double(facet->vertex[1](2));
-
- V(3*i+2, 0) = double(facet->vertex[2](0));
- V(3*i+2, 1) = double(facet->vertex[2](1));
- V(3*i+2, 2) = double(facet->vertex[2](2));
-
+ const stl_facet &facet = stl.facet_start[i];
+ V.block<1, 3>(3 * i + 0, 0) = facet.vertex[0].cast<double>();
+ V.block<1, 3>(3 * i + 1, 0) = facet.vertex[1].cast<double>();
+ V.block<1, 3>(3 * i + 2, 0) = facet.vertex[2].cast<double>();
F(i, 0) = int(3*i+0);
F(i, 1) = int(3*i+1);
F(i, 2) = int(3*i+2);
diff --git a/src/libslic3r/SLA/bicubic.h b/src/libslic3r/SLA/bicubic.h
new file mode 100644
index 000000000..870d00dbd
--- /dev/null
+++ b/src/libslic3r/SLA/bicubic.h
@@ -0,0 +1,186 @@
+#ifndef BICUBIC_HPP
+#define BICUBIC_HPP
+
+#include <algorithm>
+#include <vector>
+#include <cmath>
+
+#include <Eigen/Dense>
+
+namespace Slic3r {
+
+namespace BicubicInternal {
+ // Linear kernel, to be able to test cubic methods with hat kernels.
+ template<typename T>
+ struct LinearKernel
+ {
+ typedef T FloatType;
+
+ static T a00() { return T(0.); }
+ static T a01() { return T(0.); }
+ static T a02() { return T(0.); }
+ static T a03() { return T(0.); }
+ static T a10() { return T(1.); }
+ static T a11() { return T(-1.); }
+ static T a12() { return T(0.); }
+ static T a13() { return T(0.); }
+ static T a20() { return T(0.); }
+ static T a21() { return T(1.); }
+ static T a22() { return T(0.); }
+ static T a23() { return T(0.); }
+ static T a30() { return T(0.); }
+ static T a31() { return T(0.); }
+ static T a32() { return T(0.); }
+ static T a33() { return T(0.); }
+ };
+
+ // Interpolation kernel aka Catmul-Rom aka Keyes kernel.
+ template<typename T>
+ struct CubicCatmulRomKernel
+ {
+ typedef T FloatType;
+
+ static T a00() { return 0; }
+ static T a01() { return (T)-0.5; }
+ static T a02() { return (T) 1.; }
+ static T a03() { return (T)-0.5; }
+ static T a10() { return (T) 1.; }
+ static T a11() { return 0; }
+ static T a12() { return (T)-5./2.; }
+ static T a13() { return (T) 3./2.; }
+ static T a20() { return 0; }
+ static T a21() { return (T) 0.5; }
+ static T a22() { return (T) 2.; }
+ static T a23() { return (T)-3./2.; }
+ static T a30() { return 0; }
+ static T a31() { return 0; }
+ static T a32() { return (T)-0.5; }
+ static T a33() { return (T) 0.5; }
+ };
+
+ // B-spline kernel
+ template<typename T>
+ struct CubicBSplineKernel
+ {
+ typedef T FloatType;
+
+ static T a00() { return (T) 1./6.; }
+ static T a01() { return (T) -3./6.; }
+ static T a02() { return (T) 3./6.; }
+ static T a03() { return (T) -1./6.; }
+ static T a10() { return (T) 4./6.; }
+ static T a11() { return 0; }
+ static T a12() { return (T) -6./6.; }
+ static T a13() { return (T) 3./6.; }
+ static T a20() { return (T) 1./6.; }
+ static T a21() { return (T) 3./6.; }
+ static T a22() { return (T) 3./6.; }
+ static T a23() { return (T)- 3./6.; }
+ static T a30() { return 0; }
+ static T a31() { return 0; }
+ static T a32() { return 0; }
+ static T a33() { return (T) 1./6.; }
+ };
+
+ template<class T>
+ inline T clamp(T a, T lower, T upper)
+ {
+ return (a < lower) ? lower :
+ (a > upper) ? upper : a;
+ }
+}
+
+template<typename KERNEL>
+struct CubicKernel
+{
+ typedef typename KERNEL KernelInternal;
+ typedef typename KERNEL::FloatType FloatType;
+
+ static FloatType kernel(FloatType x)
+ {
+ x = fabs(x);
+ if (x >= (FloatType)2.)
+ return 0.0f;
+ if (x <= (FloatType)1.) {
+ FloatType x2 = x * x;
+ FloatType x3 = x2 * x;
+ return KERNEL::a10() + KERNEL::a11() * x + KERNEL::a12() * x2 + KERNEL::a13() * x3;
+ }
+ assert(x > (FloatType)1. && x < (FloatType)2.);
+ x -= (FloatType)1.;
+ FloatType x2 = x * x;
+ FloatType x3 = x2 * x;
+ return KERNEL::a00() + KERNEL::a01() * x + KERNEL::a02() * x2 + KERNEL::a03() * x3;
+ }
+
+ static FloatType interpolate(FloatType f0, FloatType f1, FloatType f2, FloatType f3, FloatType x)
+ {
+ const FloatType x2 = x*x;
+ const FloatType x3 = x*x*x;
+ return f0*(KERNEL::a00() + KERNEL::a01() * x + KERNEL::a02() * x2 + KERNEL::a03() * x3) +
+ f1*(KERNEL::a10() + KERNEL::a11() * x + KERNEL::a12() * x2 + KERNEL::a13() * x3) +
+ f2*(KERNEL::a20() + KERNEL::a21() * x + KERNEL::a22() * x2 + KERNEL::a23() * x3) +
+ f3*(KERNEL::a30() + KERNEL::a31() * x + KERNEL::a32() * x2 + KERNEL::a33() * x3);
+ }
+};
+
+// Linear splines
+typedef CubicKernel<BicubicInternal::LinearKernel<float>> LinearKernelf;
+typedef CubicKernel<BicubicInternal::LinearKernel<double>> LinearKerneld;
+// Catmul-Rom splines
+typedef CubicKernel<BicubicInternal::CubicCatmulRomKernel<float>> CubicCatmulRomKernelf;
+typedef CubicKernel<BicubicInternal::CubicCatmulRomKernel<double>> CubicCatmulRomKerneld;
+typedef CubicKernel<BicubicInternal::CubicCatmulRomKernel<float>> CubicInterpolationKernelf;
+typedef CubicKernel<BicubicInternal::CubicCatmulRomKernel<double>> CubicInterpolationKerneld;
+// Cubic B-splines
+typedef CubicKernel<BicubicInternal::CubicBSplineKernel<float>> CubicBSplineKernelf;
+typedef CubicKernel<BicubicInternal::CubicBSplineKernel<double>> CubicBSplineKerneld;
+
+template<typename KERNEL, typename Derived>
+static float cubic_interpolate(const Eigen::ArrayBase<Derived> &F, const typename KERNEL::FloatType pt, const typename KERNEL::FloatType dx)
+{
+ typedef typename KERNEL::FloatType T;
+ const int w = int(F.size());
+ const int ix = (int)floor(pt);
+ const T s = pt - (T)ix;
+
+ if (ix > 1 && ix + 2 < w) {
+ // Inside the fully interpolated region.
+ return KERNEL::interpolate(F[ix - 1], F[ix], F[ix + 1], F[ix + 2], s);
+ }
+ // Transition region. Extend with a constant function.
+ auto f = [&F, w](x) { return F[BicubicInternal::clamp(x, 0, w - 1)]; }
+ return KERNEL::interpolate(f(ix - 1), f(ix), f(ix + 1), f(ix + 2), s);
+}
+
+template<typename KERNEL, typename Derived>
+static float bicubic_interpolate(const Eigen::MatrixBase<Derived> &F, const Eigen::Matrix<typename KERNEL::FloatType, 2, 1, Eigen::DontAlign> &pt, const typename KERNEL::FloatType dx)
+{
+ typedef typename KERNEL::FloatType T;
+ const int w = F.cols();
+ const int h = F.rows();
+ const int ix = (int)floor(pt[0]);
+ const int iy = (int)floor(pt[1]);
+ const T s = pt[0] - (T)ix;
+ const T t = pt[1] - (T)iy;
+
+ if (ix > 1 && ix + 2 < w && iy > 1 && iy + 2 < h) {
+ // Inside the fully interpolated region.
+ return KERNEL::interpolate(
+ KERNEL::interpolate(F(ix-1,iy-1),F(ix ,iy-1),F(ix+1,iy-1),F(ix+2,iy-1),s),
+ KERNEL::interpolate(F(ix-1,iy ),F(ix ,iy ),F(ix+1,iy ),F(ix+2,iy ),s),
+ KERNEL::interpolate(F(ix-1,iy+1),F(ix ,iy+1),F(ix+1,iy+1),F(ix+2,iy+1),s),
+ KERNEL::interpolate(F(ix-1,iy+2),F(ix ,iy+2),F(ix+1,iy+2),F(ix+2,iy+2),s),t);
+ }
+ // Transition region. Extend with a constant function.
+ auto f = [&f, w, h](int x, int y) { return F(BicubicInternal::clamp(x,0,w-1),BicubicInternal::clamp(y,0,h-1)); }
+ return KERNEL::interpolate(
+ KERNEL::interpolate(f(ix-1,iy-1),f(ix ,iy-1),f(ix+1,iy-1),f(ix+2,iy-1),s),
+ KERNEL::interpolate(f(ix-1,iy ),f(ix ,iy ),f(ix+1,iy ),f(ix+2,iy ),s),
+ KERNEL::interpolate(f(ix-1,iy+1),f(ix ,iy+1),f(ix+1,iy+1),f(ix+2,iy+1),s),
+ KERNEL::interpolate(f(ix-1,iy+2),f(ix ,iy+2),f(ix+1,iy+2),f(ix+2,iy+2),s),t);
+}
+
+} // namespace Slic3r
+
+#endif /* BICUBIC_HPP */