diff --git a/src/libslic3r/Format/SL1.cpp b/src/libslic3r/Format/SL1.cpp index 6ed8c5ebe..6f1e95528 100644 --- a/src/libslic3r/Format/SL1.cpp +++ b/src/libslic3r/Format/SL1.cpp @@ -446,8 +446,8 @@ void fill_slicerconf(ConfMap &m, const SLAPrint &print) std::unique_ptr SL1Archive::create_raster() const { - sla::RasterBase::Resolution res; - sla::RasterBase::PixelDim pxdim; + sla::Resolution res; + sla::PixelDim pxdim; std::array mirror; double w = m_cfg.display_width.getFloat(); @@ -468,8 +468,8 @@ std::unique_ptr SL1Archive::create_raster() const std::swap(pw, ph); } - res = sla::RasterBase::Resolution{pw, ph}; - pxdim = sla::RasterBase::PixelDim{w / pw, h / ph}; + res = sla::Resolution{pw, ph}; + pxdim = sla::PixelDim{w / pw, h / ph}; sla::RasterBase::Trafo tr{orientation, mirror}; double gamma = m_cfg.gamma_correction.getFloat(); diff --git a/src/libslic3r/Format/SL1_SVG.cpp b/src/libslic3r/Format/SL1_SVG.cpp index 70e3a444f..8788577d3 100644 --- a/src/libslic3r/Format/SL1_SVG.cpp +++ b/src/libslic3r/Format/SL1_SVG.cpp @@ -1,6 +1,7 @@ #include "SL1_SVG.hpp" #include "SLA/RasterBase.hpp" #include "libslic3r/LocalesUtils.hpp" +#include "libslic3r/ClipperUtils.hpp" namespace Slic3r { @@ -29,41 +30,79 @@ void transform(ExPolygon &ep, const sla::RasterBase::Trafo &tr, const BoundingBo void append_svg(std::string &buf, const Polygon &poly) { - buf += "(c.x()), precision) + +// " " + float_to_string_decimal_point(unscaled(c.y()), precision) + " m"; + +// for (auto &p : poly) { +// auto d = p - c; +// if (d.squaredNorm() == 0) continue; +// buf += " "; +// buf += float_to_string_decimal_point(unscaled(p.x() - c.x()), precision); +// buf += " "; +// buf += float_to_string_decimal_point(unscaled(p.y() - c.y()), precision); +// c = p; +// } +// buf += " z\""; // mark path as closed +// buf += " />\n"; +//} + } // namespace // A fake raster from SVG class SVGRaster : public sla::RasterBase { // Resolution here will be used for svg boundaries - BoundingBox m_bb; - Trafo m_trafo; + BoundingBox m_bb; + sla::Resolution m_res; + Trafo m_trafo; + Vec2d m_sc; std::string m_svg; public: - SVGRaster(Resolution res = {}, Trafo tr = {}) - : m_bb{BoundingBox{{0, 0}, Vec2crd{res.width_px, res.height_px}}} + SVGRaster(const BoundingBox &svgarea, sla::Resolution res, Trafo tr = {}) + : m_bb{svgarea} + , m_res{res} , m_trafo{tr} + , m_sc{double(m_res.width_px) / m_bb.size().x(), double(m_res.height_px) / m_bb.size().y()} { // Inside the svg header, the boundaries will be defined in mm to // the actual bed size. The viewport is then defined to work with our // scaled coordinates. All the exported polygons will be in these scaled // coordinates but svg rendering software will interpret them correctly // in mm due to the header's definition. - std::string wf = float_to_string_decimal_point(unscaled(res.width_px)); - std::string hf = float_to_string_decimal_point(unscaled(res.height_px)); - std::string w = std::to_string(res.width_px); - std::string h = std::to_string(res.height_px); + std::string wf = float_to_string_decimal_point(unscaled(m_bb.size().x())); + std::string hf = float_to_string_decimal_point(unscaled(m_bb.size().y())); + std::string w = std::to_string(coord_t(m_res.width_px)); + std::string h = std::to_string(coord_t(m_res.height_px)); // Notice the header also defines the fill-rule as nonzero which should // generate correct results for our ExPolygons. @@ -84,21 +123,28 @@ public: { auto cpoly = poly; - transform(cpoly, m_trafo, m_bb); - append_svg(m_svg, cpoly.contour); - for (auto &h : cpoly.holes) - append_svg(m_svg, h); + double tol = std::min(m_bb.size().x() / double(m_res.width_px), + m_bb.size().y() / double(m_res.height_px)); + + ExPolygons cpolys = poly.simplify(tol / 4.); + + for (auto &cpoly : cpolys) { + transform(cpoly, m_trafo, m_bb); + + for (auto &p : cpoly.contour.points) + p = {std::round(p.x() * m_sc.x()), std::round(p.y() * m_sc.y())}; + + for (auto &h : cpoly.holes) + for (auto &p : h) + p = {std::round(p.x() * m_sc.x()), std::round(p.y() * m_sc.y())}; + + append_svg(m_svg, cpoly.contour); + for (auto &h : cpoly.holes) + append_svg(m_svg, h); + } } - Resolution resolution() const override - { - return {size_t(m_bb.size().x()), size_t(m_bb.size().y())}; - } - - // Pixel dimension is undefined in this case. - PixelDim pixel_dimensions() const override { return {0, 0}; } - - Trafo trafo() const override { return m_trafo; } + Trafo trafo() const override { return m_trafo; } sla::EncodedRaster encode(sla::RasterEncoder /*encoder*/) const override { @@ -116,8 +162,11 @@ public: std::unique_ptr SL1_SVGArchive::create_raster() const { - auto w = scaled(cfg().display_width.getFloat()); - auto h = scaled(cfg().display_height.getFloat()); + auto w = cfg().display_width.getFloat(); + auto h = cfg().display_height.getFloat(); + + auto res_x = size_t(cfg().display_pixels_x.getInt()); + auto res_y = size_t(cfg().display_pixels_y.getInt()); std::array mirror; @@ -133,13 +182,14 @@ std::unique_ptr SL1_SVGArchive::create_raster() const std::swap(w, h); } - sla::RasterBase::Resolution res{w, h}; + BoundingBox svgarea{{0, 0}, {scaled(w), scaled(h)}}; + sla::RasterBase::Trafo tr{orientation, mirror}; // Gamma does not really make sense in an svg, right? // double gamma = cfg().gamma_correction.getFloat(); - return std::make_unique(res, tr); + return std::make_unique(svgarea, sla::Resolution{res_x * 4, res_y * 4}, tr); } sla::RasterEncoder SL1_SVGArchive::get_encoder() const diff --git a/src/libslic3r/SLA/AGGRaster.hpp b/src/libslic3r/SLA/AGGRaster.hpp index bc68cd377..7c8e71c2a 100644 --- a/src/libslic3r/SLA/AGGRaster.hpp +++ b/src/libslic3r/SLA/AGGRaster.hpp @@ -41,7 +41,7 @@ public: using TValue = typename TColor::value_type; using TPixel = typename PixelRenderer::pixel_type; using TRawBuffer = agg::rendering_buffer; - + protected: Resolution m_resolution; @@ -153,8 +153,8 @@ public: } Trafo trafo() const override { return m_trafo; } - Resolution resolution() const override { return m_resolution; } - PixelDim pixel_dimensions() const override + Resolution resolution() const { return m_resolution; } + PixelDim pixel_dimensions() const { return {SCALING_FACTOR / m_pxdim_scaled.w_mm, SCALING_FACTOR / m_pxdim_scaled.h_mm}; @@ -186,11 +186,15 @@ class RasterGrayscaleAA : public _RasterGrayscaleAA { using typename Base::TValue; public: template - RasterGrayscaleAA(const RasterBase::Resolution &res, - const RasterBase::PixelDim & pd, - const RasterBase::Trafo & trafo, - GammaFn && fn) - : Base(res, pd, trafo, Colors::White, Colors::Black, + RasterGrayscaleAA(const Resolution &res, + const PixelDim &pd, + const RasterBase::Trafo &trafo, + GammaFn &&fn) + : Base(res, + pd, + trafo, + Colors::White, + Colors::Black, std::forward(fn)) {} @@ -208,10 +212,10 @@ public: class RasterGrayscaleAAGammaPower: public RasterGrayscaleAA { public: - RasterGrayscaleAAGammaPower(const RasterBase::Resolution &res, - const RasterBase::PixelDim & pd, - const RasterBase::Trafo & trafo, - double gamma = 1.) + RasterGrayscaleAAGammaPower(const Resolution &res, + const PixelDim &pd, + const RasterBase::Trafo &trafo, + double gamma = 1.) : RasterGrayscaleAA(res, pd, trafo, agg::gamma_power(gamma)) {} }; diff --git a/src/libslic3r/SLA/RasterBase.cpp b/src/libslic3r/SLA/RasterBase.cpp index cc9aca027..0b6c45eff 100644 --- a/src/libslic3r/SLA/RasterBase.cpp +++ b/src/libslic3r/SLA/RasterBase.cpp @@ -68,10 +68,10 @@ EncodedRaster PPMRasterEncoder::operator()(const void *ptr, size_t w, size_t h, } std::unique_ptr create_raster_grayscale_aa( - const RasterBase::Resolution &res, - const RasterBase::PixelDim & pxdim, - double gamma, - const RasterBase::Trafo & tr) + const Resolution &res, + const PixelDim &pxdim, + double gamma, + const RasterBase::Trafo &tr) { std::unique_ptr rst; diff --git a/src/libslic3r/SLA/RasterBase.hpp b/src/libslic3r/SLA/RasterBase.hpp index 6439830fe..657fc865c 100644 --- a/src/libslic3r/SLA/RasterBase.hpp +++ b/src/libslic3r/SLA/RasterBase.hpp @@ -31,6 +31,27 @@ public: const char * extension() const { return m_ext.c_str(); } }; +/// Type that represents a resolution in pixels. +struct Resolution { + size_t width_px = 0; + size_t height_px = 0; + + Resolution() = default; + Resolution(size_t w, size_t h) : width_px(w), height_px(h) {} + size_t pixels() const { return width_px * height_px; } +}; + +/// Types that represents the dimension of a pixel in millimeters. +struct PixelDim { + double w_mm = 1.; + double h_mm = 1.; + + PixelDim() = default; + PixelDim(double px_width_mm, double px_height_mm) + : w_mm(px_width_mm), h_mm(px_height_mm) + {} +}; + using RasterEncoder = std::function; @@ -63,35 +84,14 @@ public: Point get_center() const { return {center_x, center_y}; } }; - /// Type that represents a resolution in pixels. - struct Resolution { - size_t width_px = 0; - size_t height_px = 0; - - Resolution() = default; - Resolution(size_t w, size_t h) : width_px(w), height_px(h) {} - size_t pixels() const { return width_px * height_px; } - }; - - /// Types that represents the dimension of a pixel in millimeters. - struct PixelDim { - double w_mm = 1.; - double h_mm = 1.; - - PixelDim() = default; - PixelDim(double px_width_mm, double px_height_mm) - : w_mm(px_width_mm), h_mm(px_height_mm) - {} - }; - virtual ~RasterBase() = default; /// Draw a polygon with holes. virtual void draw(const ExPolygon& poly) = 0; /// Get the resolution of the raster. - virtual Resolution resolution() const = 0; - virtual PixelDim pixel_dimensions() const = 0; +// virtual Resolution resolution() const = 0; +// virtual PixelDim pixel_dimensions() const = 0; virtual Trafo trafo() const = 0; virtual EncodedRaster encode(RasterEncoder encoder) const = 0; @@ -109,10 +109,10 @@ std::ostream& operator<<(std::ostream &stream, const EncodedRaster &bytes); // If gamma is zero, thresholding will be performed which disables AA. std::unique_ptr create_raster_grayscale_aa( - const RasterBase::Resolution &res, - const RasterBase::PixelDim & pxdim, - double gamma = 1.0, - const RasterBase::Trafo & tr = {}); + const Resolution &res, + const PixelDim &pxdim, + double gamma = 1.0, + const RasterBase::Trafo &tr = {}); }} // namespace Slic3r::sla diff --git a/tests/libslic3r/test_marchingsquares.cpp b/tests/libslic3r/test_marchingsquares.cpp index 3553697ac..32b137175 100644 --- a/tests/libslic3r/test_marchingsquares.cpp +++ b/tests/libslic3r/test_marchingsquares.cpp @@ -20,17 +20,17 @@ using namespace Slic3r; -static double area(const sla::RasterBase::PixelDim &pxd) +static double area(const sla::PixelDim &pxd) { return pxd.w_mm * pxd.h_mm; } static Slic3r::sla::RasterGrayscaleAA create_raster( - const sla::RasterBase::Resolution &res, + const sla::Resolution &res, double disp_w = 100., double disp_h = 100.) { - sla::RasterBase::PixelDim pixdim{disp_w / res.width_px, disp_h / res.height_px}; + sla::PixelDim pixdim{disp_w / res.width_px, disp_h / res.height_px}; auto bb = BoundingBox({0, 0}, {scaled(disp_w), scaled(disp_h)}); sla::RasterBase::Trafo trafo; @@ -107,7 +107,7 @@ static void test_expolys(Rst && rst, svg.Close(); double max_rel_err = 0.1; - sla::RasterBase::PixelDim pxd = rst.pixel_dimensions(); + sla::PixelDim pxd = rst.pixel_dimensions(); double max_abs_err = area(pxd) * scaled(1.) * scaled(1.); BoundingBox ref_bb; @@ -175,7 +175,7 @@ TEST_CASE("Fully covered raster should result in a rectangle", "[MarchingSquares TEST_CASE("4x4 raster with one ring", "[MarchingSquares]") { - sla::RasterBase::PixelDim pixdim{1, 1}; + sla::PixelDim pixdim{1, 1}; // We need one additional row and column to detect edges sla::RasterGrayscaleAA rst{{4, 4}, pixdim, {}, agg::gamma_threshold(.5)}; @@ -205,7 +205,7 @@ TEST_CASE("4x4 raster with one ring", "[MarchingSquares]") { TEST_CASE("4x4 raster with two rings", "[MarchingSquares]") { - sla::RasterBase::PixelDim pixdim{1, 1}; + sla::PixelDim pixdim{1, 1}; // We need one additional row and column to detect edges sla::RasterGrayscaleAA rst{{5, 5}, pixdim, {}, agg::gamma_threshold(.5)}; @@ -321,7 +321,7 @@ static void recreate_object_from_rasters(const std::string &objname, float lh) { std::vector layers = slice_mesh_ex(mesh.its, grid(float(bb.min.z()) + lh, float(bb.max.z()), lh)); - sla::RasterBase::Resolution res{2560, 1440}; + sla::Resolution res{2560, 1440}; double disp_w = 120.96; double disp_h = 68.04; diff --git a/tests/libslic3r/test_png_io.cpp b/tests/libslic3r/test_png_io.cpp index b4fcd6255..e8229b716 100644 --- a/tests/libslic3r/test_png_io.cpp +++ b/tests/libslic3r/test_png_io.cpp @@ -9,9 +9,9 @@ using namespace Slic3r; -static sla::RasterGrayscaleAA create_raster(const sla::RasterBase::Resolution &res) +static sla::RasterGrayscaleAA create_raster(const sla::Resolution &res) { - sla::RasterBase::PixelDim pixdim{1., 1.}; + sla::PixelDim pixdim{1., 1.}; auto bb = BoundingBox({0, 0}, {scaled(1.), scaled(1.)}); sla::RasterBase::Trafo trafo; diff --git a/tests/sla_print/sla_print_tests.cpp b/tests/sla_print/sla_print_tests.cpp index db8c5e93e..f7b0df339 100644 --- a/tests/sla_print/sla_print_tests.cpp +++ b/tests/sla_print/sla_print_tests.cpp @@ -159,8 +159,8 @@ TEST_CASE("FloorSupportsDoNotPierceModel", "[SLASupportGeneration]") { TEST_CASE("InitializedRasterShouldBeNONEmpty", "[SLARasterOutput]") { // Default Prusa SL1 display parameters - sla::RasterBase::Resolution res{2560, 1440}; - sla::RasterBase::PixelDim pixdim{120. / res.width_px, 68. / res.height_px}; + sla::Resolution res{2560, 1440}; + sla::PixelDim pixdim{120. / res.width_px, 68. / res.height_px}; sla::RasterGrayscaleAAGammaPower raster(res, pixdim, {}, 1.); REQUIRE(raster.resolution().width_px == res.width_px); @@ -186,8 +186,8 @@ TEST_CASE("MirroringShouldBeCorrect", "[SLARasterOutput]") { TEST_CASE("RasterizedPolygonAreaShouldMatch", "[SLARasterOutput]") { double disp_w = 120., disp_h = 68.; - sla::RasterBase::Resolution res{2560, 1440}; - sla::RasterBase::PixelDim pixdim{disp_w / res.width_px, disp_h / res.height_px}; + sla::Resolution res{2560, 1440}; + sla::PixelDim pixdim{disp_w / res.width_px, disp_h / res.height_px}; double gamma = 1.; sla::RasterGrayscaleAAGammaPower raster(res, pixdim, {}, gamma); diff --git a/tests/sla_print/sla_test_utils.cpp b/tests/sla_print/sla_test_utils.cpp index 1082df200..d98a92037 100644 --- a/tests/sla_print/sla_test_utils.cpp +++ b/tests/sla_print/sla_test_utils.cpp @@ -307,8 +307,8 @@ void check_validity(const TriangleMesh &input_mesh, int flags) void check_raster_transformations(sla::RasterBase::Orientation o, sla::RasterBase::TMirroring mirroring) { double disp_w = 120., disp_h = 68.; - sla::RasterBase::Resolution res{2560, 1440}; - sla::RasterBase::PixelDim pixdim{disp_w / res.width_px, disp_h / res.height_px}; + sla::Resolution res{2560, 1440}; + sla::PixelDim pixdim{disp_w / res.width_px, disp_h / res.height_px}; auto bb = BoundingBox({0, 0}, {scaled(disp_w), scaled(disp_h)}); sla::RasterBase::Trafo trafo{o, mirroring}; @@ -400,7 +400,7 @@ double raster_white_area(const sla::RasterGrayscaleAA &raster) return a; } -double predict_error(const ExPolygon &p, const sla::RasterBase::PixelDim &pd) +double predict_error(const ExPolygon &p, const sla::PixelDim &pd) { auto lines = p.lines(); double pix_err = pixel_area(FullWhite, pd) / 2.; diff --git a/tests/sla_print/sla_test_utils.hpp b/tests/sla_print/sla_test_utils.hpp index 2264ad856..7171914d4 100644 --- a/tests/sla_print/sla_test_utils.hpp +++ b/tests/sla_print/sla_test_utils.hpp @@ -175,7 +175,7 @@ void check_raster_transformations(sla::RasterBase::Orientation o, ExPolygon square_with_hole(double v); -inline double pixel_area(TPixel px, const sla::RasterBase::PixelDim &pxdim) +inline double pixel_area(TPixel px, const sla::PixelDim &pxdim) { return (pxdim.h_mm * pxdim.w_mm) * px * 1. / (FullWhite - FullBlack); } @@ -183,7 +183,7 @@ inline double pixel_area(TPixel px, const sla::RasterBase::PixelDim &pxdim) double raster_white_area(const sla::RasterGrayscaleAA &raster); long raster_pxsum(const sla::RasterGrayscaleAA &raster); -double predict_error(const ExPolygon &p, const sla::RasterBase::PixelDim &pd); +double predict_error(const ExPolygon &p, const sla::PixelDim &pd); sla::SupportPoints calc_support_pts( const TriangleMesh & mesh,