Output raster seem ok, stats broken.
This commit is contained in:
parent
8fdff97eb7
commit
440e54181b
10 changed files with 436 additions and 347 deletions
|
@ -64,6 +64,7 @@ endif()
|
||||||
target_include_directories(ClipperBackend INTERFACE ${Boost_INCLUDE_DIRS} )
|
target_include_directories(ClipperBackend INTERFACE ${Boost_INCLUDE_DIRS} )
|
||||||
target_sources(ClipperBackend INTERFACE
|
target_sources(ClipperBackend INTERFACE
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/geometries.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/geometries.hpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/clipper_polygon.hpp
|
||||||
${SRC_DIR}/libnest2d/utils/boost_alg.hpp )
|
${SRC_DIR}/libnest2d/utils/boost_alg.hpp )
|
||||||
|
|
||||||
target_compile_definitions(ClipperBackend INTERFACE LIBNEST2D_BACKEND_CLIPPER)
|
target_compile_definitions(ClipperBackend INTERFACE LIBNEST2D_BACKEND_CLIPPER)
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
#ifndef CLIPPER_POLYGON_HPP
|
||||||
|
#define CLIPPER_POLYGON_HPP
|
||||||
|
|
||||||
|
#include <clipper.hpp>
|
||||||
|
|
||||||
|
namespace ClipperLib {
|
||||||
|
|
||||||
|
struct Polygon {
|
||||||
|
Path Contour;
|
||||||
|
Paths Holes;
|
||||||
|
|
||||||
|
inline Polygon() = default;
|
||||||
|
|
||||||
|
inline explicit Polygon(const Path& cont): Contour(cont) {}
|
||||||
|
inline explicit Polygon(const Paths& holes):
|
||||||
|
Holes(holes) {}
|
||||||
|
inline Polygon(const Path& cont, const Paths& holes):
|
||||||
|
Contour(cont), Holes(holes) {}
|
||||||
|
|
||||||
|
inline explicit Polygon(Path&& cont): Contour(std::move(cont)) {}
|
||||||
|
inline explicit Polygon(Paths&& holes): Holes(std::move(holes)) {}
|
||||||
|
inline Polygon(Path&& cont, Paths&& holes):
|
||||||
|
Contour(std::move(cont)), Holes(std::move(holes)) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline IntPoint& operator +=(IntPoint& p, const IntPoint& pa ) {
|
||||||
|
// This could be done with SIMD
|
||||||
|
p.X += pa.X;
|
||||||
|
p.Y += pa.Y;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IntPoint operator+(const IntPoint& p1, const IntPoint& p2) {
|
||||||
|
IntPoint ret = p1;
|
||||||
|
ret += p2;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IntPoint& operator -=(IntPoint& p, const IntPoint& pa ) {
|
||||||
|
p.X -= pa.X;
|
||||||
|
p.Y -= pa.Y;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IntPoint operator -(IntPoint& p ) {
|
||||||
|
IntPoint ret = p;
|
||||||
|
ret.X = -ret.X;
|
||||||
|
ret.Y = -ret.Y;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IntPoint operator-(const IntPoint& p1, const IntPoint& p2) {
|
||||||
|
IntPoint ret = p1;
|
||||||
|
ret -= p2;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IntPoint& operator *=(IntPoint& p, const IntPoint& pa ) {
|
||||||
|
p.X *= pa.X;
|
||||||
|
p.Y *= pa.Y;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IntPoint operator*(const IntPoint& p1, const IntPoint& p2) {
|
||||||
|
IntPoint ret = p1;
|
||||||
|
ret *= p2;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CLIPPER_POLYGON_HPP
|
|
@ -10,84 +10,15 @@
|
||||||
#include <libnest2d/geometry_traits.hpp>
|
#include <libnest2d/geometry_traits.hpp>
|
||||||
#include <libnest2d/geometry_traits_nfp.hpp>
|
#include <libnest2d/geometry_traits_nfp.hpp>
|
||||||
|
|
||||||
#include <clipper.hpp>
|
#include "clipper_polygon.hpp"
|
||||||
|
|
||||||
namespace ClipperLib {
|
|
||||||
using PointImpl = IntPoint;
|
|
||||||
using PathImpl = Path;
|
|
||||||
using HoleStore = std::vector<PathImpl>;
|
|
||||||
|
|
||||||
struct PolygonImpl {
|
|
||||||
PathImpl Contour;
|
|
||||||
HoleStore Holes;
|
|
||||||
|
|
||||||
inline PolygonImpl() = default;
|
|
||||||
|
|
||||||
inline explicit PolygonImpl(const PathImpl& cont): Contour(cont) {}
|
|
||||||
inline explicit PolygonImpl(const HoleStore& holes):
|
|
||||||
Holes(holes) {}
|
|
||||||
inline PolygonImpl(const Path& cont, const HoleStore& holes):
|
|
||||||
Contour(cont), Holes(holes) {}
|
|
||||||
|
|
||||||
inline explicit PolygonImpl(PathImpl&& cont): Contour(std::move(cont)) {}
|
|
||||||
inline explicit PolygonImpl(HoleStore&& holes): Holes(std::move(holes)) {}
|
|
||||||
inline PolygonImpl(Path&& cont, HoleStore&& holes):
|
|
||||||
Contour(std::move(cont)), Holes(std::move(holes)) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline PointImpl& operator +=(PointImpl& p, const PointImpl& pa ) {
|
|
||||||
// This could be done with SIMD
|
|
||||||
p.X += pa.X;
|
|
||||||
p.Y += pa.Y;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PointImpl operator+(const PointImpl& p1, const PointImpl& p2) {
|
|
||||||
PointImpl ret = p1;
|
|
||||||
ret += p2;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PointImpl& operator -=(PointImpl& p, const PointImpl& pa ) {
|
|
||||||
p.X -= pa.X;
|
|
||||||
p.Y -= pa.Y;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PointImpl operator -(PointImpl& p ) {
|
|
||||||
PointImpl ret = p;
|
|
||||||
ret.X = -ret.X;
|
|
||||||
ret.Y = -ret.Y;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PointImpl operator-(const PointImpl& p1, const PointImpl& p2) {
|
|
||||||
PointImpl ret = p1;
|
|
||||||
ret -= p2;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PointImpl& operator *=(PointImpl& p, const PointImpl& pa ) {
|
|
||||||
p.X *= pa.X;
|
|
||||||
p.Y *= pa.Y;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PointImpl operator*(const PointImpl& p1, const PointImpl& p2) {
|
|
||||||
PointImpl ret = p1;
|
|
||||||
ret *= p2;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace libnest2d {
|
namespace libnest2d {
|
||||||
|
|
||||||
// Aliases for convinience
|
// Aliases for convinience
|
||||||
using ClipperLib::PointImpl;
|
using PointImpl = ClipperLib::IntPoint;
|
||||||
using ClipperLib::PathImpl;
|
using PathImpl = ClipperLib::Path;
|
||||||
using ClipperLib::PolygonImpl;
|
using HoleStore = ClipperLib::Paths;
|
||||||
using ClipperLib::HoleStore;
|
using PolygonImpl = ClipperLib::Polygon;
|
||||||
|
|
||||||
// Type of coordinate units used by Clipper
|
// Type of coordinate units used by Clipper
|
||||||
template<> struct CoordType<PointImpl> {
|
template<> struct CoordType<PointImpl> {
|
||||||
|
@ -158,33 +89,24 @@ template<> inline TCoord<PointImpl>& y(PointImpl& p)
|
||||||
#define DISABLE_BOOST_AREA
|
#define DISABLE_BOOST_AREA
|
||||||
|
|
||||||
namespace _smartarea {
|
namespace _smartarea {
|
||||||
|
|
||||||
template<Orientation o>
|
template<Orientation o>
|
||||||
inline double area(const PolygonImpl& /*sh*/) {
|
inline double area(const PolygonImpl& /*sh*/) {
|
||||||
return std::nan("");
|
return std::nan("");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline double area<Orientation::CLOCKWISE>(const PolygonImpl& sh) {
|
inline double area<Orientation::COUNTER_CLOCKWISE>(const PolygonImpl& sh) {
|
||||||
double a = 0;
|
return std::accumulate(sh.Holes.begin(), sh.Holes.end(),
|
||||||
|
ClipperLib::Area(sh.Contour),
|
||||||
std::for_each(sh.Holes.begin(), sh.Holes.end(), [&a](const PathImpl& h)
|
[](double a, const ClipperLib::Path& pt){
|
||||||
{
|
return a + ClipperLib::Area(pt);
|
||||||
a -= ClipperLib::Area(h);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return -ClipperLib::Area(sh.Contour) + a;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline double area<Orientation::COUNTER_CLOCKWISE>(const PolygonImpl& sh) {
|
inline double area<Orientation::CLOCKWISE>(const PolygonImpl& sh) {
|
||||||
double a = 0;
|
return -area<Orientation::COUNTER_CLOCKWISE>(sh);
|
||||||
|
|
||||||
std::for_each(sh.Holes.begin(), sh.Holes.end(), [&a](const PathImpl& h)
|
|
||||||
{
|
|
||||||
a += ClipperLib::Area(h);
|
|
||||||
});
|
|
||||||
|
|
||||||
return ClipperLib::Area(sh.Contour) + a;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -390,11 +312,17 @@ inline void rotate(PolygonImpl& sh, const Radians& rads)
|
||||||
} // namespace shapelike
|
} // namespace shapelike
|
||||||
|
|
||||||
#define DISABLE_BOOST_NFP_MERGE
|
#define DISABLE_BOOST_NFP_MERGE
|
||||||
inline std::vector<PolygonImpl> _merge(ClipperLib::Clipper& clipper) {
|
inline std::vector<PolygonImpl> clipper_execute(
|
||||||
|
ClipperLib::Clipper& clipper,
|
||||||
|
ClipperLib::ClipType clipType,
|
||||||
|
ClipperLib::PolyFillType subjFillType = ClipperLib::pftEvenOdd,
|
||||||
|
ClipperLib::PolyFillType clipFillType = ClipperLib::pftEvenOdd)
|
||||||
|
{
|
||||||
shapelike::Shapes<PolygonImpl> retv;
|
shapelike::Shapes<PolygonImpl> retv;
|
||||||
|
|
||||||
ClipperLib::PolyTree result;
|
ClipperLib::PolyTree result;
|
||||||
clipper.Execute(ClipperLib::ctUnion, result, ClipperLib::pftNegative);
|
clipper.Execute(clipType, result, subjFillType, clipFillType);
|
||||||
|
|
||||||
retv.reserve(static_cast<size_t>(result.Total()));
|
retv.reserve(static_cast<size_t>(result.Total()));
|
||||||
|
|
||||||
std::function<void(ClipperLib::PolyNode*, PolygonImpl&)> processHole;
|
std::function<void(ClipperLib::PolyNode*, PolygonImpl&)> processHole;
|
||||||
|
@ -437,15 +365,12 @@ merge(const std::vector<PolygonImpl>& shapes)
|
||||||
|
|
||||||
for(auto& path : shapes) {
|
for(auto& path : shapes) {
|
||||||
valid &= clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed);
|
valid &= clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed);
|
||||||
|
valid &= clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed);
|
||||||
for(auto& hole : path.Holes) {
|
|
||||||
valid &= clipper.AddPath(hole, ClipperLib::ptSubject, closed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!valid) throw GeometryException(GeomErr::MERGE);
|
if(!valid) throw GeometryException(GeomErr::MERGE);
|
||||||
|
|
||||||
return _merge(clipper);
|
return clipper_execute(clipper, ClipperLib::ctUnion, ClipperLib::pftNegative);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,36 +2,10 @@
|
||||||
#define PRINTER_PARTS_H
|
#define PRINTER_PARTS_H
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <clipper.hpp>
|
#include <libnest2d/backends/clipper/clipper_polygon.hpp>
|
||||||
|
|
||||||
#ifndef CLIPPER_BACKEND_HPP
|
|
||||||
namespace ClipperLib {
|
|
||||||
using PointImpl = IntPoint;
|
|
||||||
using PathImpl = Path;
|
|
||||||
using HoleStore = std::vector<PathImpl>;
|
|
||||||
|
|
||||||
struct PolygonImpl {
|
|
||||||
PathImpl Contour;
|
|
||||||
HoleStore Holes;
|
|
||||||
|
|
||||||
inline PolygonImpl() {}
|
|
||||||
|
|
||||||
inline explicit PolygonImpl(const PathImpl& cont): Contour(cont) {}
|
|
||||||
inline explicit PolygonImpl(const HoleStore& holes):
|
|
||||||
Holes(holes) {}
|
|
||||||
inline PolygonImpl(const Path& cont, const HoleStore& holes):
|
|
||||||
Contour(cont), Holes(holes) {}
|
|
||||||
|
|
||||||
inline explicit PolygonImpl(PathImpl&& cont): Contour(std::move(cont)) {}
|
|
||||||
inline explicit PolygonImpl(HoleStore&& holes): Holes(std::move(holes)) {}
|
|
||||||
inline PolygonImpl(Path&& cont, HoleStore&& holes):
|
|
||||||
Contour(std::move(cont)), Holes(std::move(holes)) {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using TestData = std::vector<ClipperLib::Path>;
|
using TestData = std::vector<ClipperLib::Path>;
|
||||||
using TestDataEx = std::vector<ClipperLib::PolygonImpl>;
|
using TestDataEx = std::vector<ClipperLib::Polygon>;
|
||||||
|
|
||||||
extern const TestData PRINTER_PART_POLYGONS;
|
extern const TestData PRINTER_PART_POLYGONS;
|
||||||
extern const TestData STEGOSAUR_POLYGONS;
|
extern const TestData STEGOSAUR_POLYGONS;
|
||||||
|
|
|
@ -574,7 +574,7 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
|
||||||
|
|
||||||
for(ModelInstance* objinst : objptr->instances) {
|
for(ModelInstance* objinst : objptr->instances) {
|
||||||
if(objinst) {
|
if(objinst) {
|
||||||
ClipperLib::PolygonImpl pn;
|
ClipperLib::Polygon pn;
|
||||||
pn.Contour = clpath;
|
pn.Contour = clpath;
|
||||||
|
|
||||||
// Efficient conversion to item.
|
// Efficient conversion to item.
|
||||||
|
|
|
@ -42,8 +42,9 @@ template<FilePrinterFormat format>
|
||||||
class FilePrinter {
|
class FilePrinter {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Draw an ExPolygon which is a polygon inside a slice on the specified layer.
|
// Draw a polygon which is a polygon inside a slice on the specified layer.
|
||||||
void draw_polygon(const Polygon& p, unsigned lyr);
|
void draw_polygon(const ExPolygon& p, unsigned lyr);
|
||||||
|
void draw_polygon(const ClipperLib::Polygon& p, unsigned lyr);
|
||||||
|
|
||||||
// Tell the printer how many layers should it consider.
|
// Tell the printer how many layers should it consider.
|
||||||
void layers(unsigned layernum);
|
void layers(unsigned layernum);
|
||||||
|
@ -209,7 +210,12 @@ public:
|
||||||
inline void layers(unsigned cnt) { if(cnt > 0) m_layers_rst.resize(cnt); }
|
inline void layers(unsigned cnt) { if(cnt > 0) m_layers_rst.resize(cnt); }
|
||||||
inline unsigned layers() const { return unsigned(m_layers_rst.size()); }
|
inline unsigned layers() const { return unsigned(m_layers_rst.size()); }
|
||||||
|
|
||||||
inline void draw_polygon(const Polygon& p, unsigned lyr) {
|
inline void draw_polygon(const ExPolygon& p, unsigned lyr) {
|
||||||
|
assert(lyr < m_layers_rst.size());
|
||||||
|
m_layers_rst[lyr].first.draw(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void draw_polygon(const ClipperLib::Polygon& p, unsigned lyr) {
|
||||||
assert(lyr < m_layers_rst.size());
|
assert(lyr < m_layers_rst.size());
|
||||||
m_layers_rst[lyr].first.draw(p);
|
m_layers_rst[lyr].first.draw(p);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "Rasterizer.hpp"
|
#include "Rasterizer.hpp"
|
||||||
#include <Polygon.hpp>
|
#include <ExPolygon.hpp>
|
||||||
|
#include <libnest2d/backends/clipper/clipper_polygon.hpp>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
@ -72,7 +73,7 @@ public:
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(const Polygon &poly) {
|
template<class Geometry> inline void draw(const Geometry &poly) {
|
||||||
agg::rasterizer_scanline_aa<> ras;
|
agg::rasterizer_scanline_aa<> ras;
|
||||||
agg::scanline_p8 scanlines;
|
agg::scanline_p8 scanlines;
|
||||||
|
|
||||||
|
@ -104,14 +105,36 @@ private:
|
||||||
return p(1) * SCALING_FACTOR/m_pxdim.h_mm;
|
return p(1) * SCALING_FACTOR/m_pxdim.h_mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
agg::path_storage to_path(const Polygon& poly) {
|
agg::path_storage to_path(const Polygon& poly)
|
||||||
|
{
|
||||||
agg::path_storage path;
|
agg::path_storage path;
|
||||||
|
|
||||||
auto it = poly.points.begin();
|
auto it = poly.points.begin();
|
||||||
path.move_to(getPx(*it), getPy(*it));
|
path.move_to(getPx(*it), getPy(*it));
|
||||||
while(++it != poly.points.end())
|
while(++it != poly.points.end()) path.line_to(getPx(*it), getPy(*it));
|
||||||
|
path.line_to(getPx(poly.points.front()), getPy(poly.points.front()));
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double getPx(const ClipperLib::IntPoint& p) {
|
||||||
|
return p.X * SCALING_FACTOR/m_pxdim.w_mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
double getPy(const ClipperLib::IntPoint& p) {
|
||||||
|
return p.Y * SCALING_FACTOR/m_pxdim.h_mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
agg::path_storage to_path(const ClipperLib::Path& 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(*it), getPy(*it));
|
||||||
|
|
||||||
path.line_to(getPx(poly.points.front()), getPy(poly.points.front()));
|
path.line_to(getPx(poly.front()), getPy(poly.front()));
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,10 +186,16 @@ void Raster::clear()
|
||||||
m_impl->clear();
|
m_impl->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Raster::draw(const Polygon &poly)
|
void Raster::draw(const ExPolygon &expoly)
|
||||||
{
|
{
|
||||||
assert(m_impl);
|
m_impl->draw(expoly.contour);
|
||||||
m_impl->draw(poly);
|
for(auto& h : expoly.holes) m_impl->draw(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Raster::draw(const ClipperLib::Polygon &poly)
|
||||||
|
{
|
||||||
|
m_impl->draw(poly.Contour);
|
||||||
|
for(auto& h : poly.Holes) m_impl->draw(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Raster::save(std::ostream& stream, Compression comp)
|
void Raster::save(std::ostream& stream, Compression comp)
|
||||||
|
|
|
@ -4,9 +4,11 @@
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
namespace ClipperLib { class Polygon; }
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class Polygon;
|
class ExPolygon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Raster captures an anti-aliased monochrome canvas where vectorial
|
* @brief Raster captures an anti-aliased monochrome canvas where vectorial
|
||||||
|
@ -83,7 +85,8 @@ public:
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
/// Draw a polygon with holes.
|
/// Draw a polygon with holes.
|
||||||
void draw(const Polygon& poly);
|
void draw(const ExPolygon& poly);
|
||||||
|
void draw(const ClipperLib::Polygon& poly);
|
||||||
|
|
||||||
/// Save the raster on the specified stream.
|
/// Save the raster on the specified stream.
|
||||||
void save(std::ostream& stream, Compression comp = Compression::RAW);
|
void save(std::ostream& stream, Compression comp = Compression::RAW);
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
|
// For geometry algorithms with native Clipper types (no copies and conversions)
|
||||||
|
#include <libnest2d/backends/clipper/geometries.hpp>
|
||||||
|
|
||||||
//#include <tbb/spin_mutex.h>//#include "tbb/mutex.h"
|
//#include <tbb/spin_mutex.h>//#include "tbb/mutex.h"
|
||||||
|
|
||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
|
@ -958,8 +961,249 @@ void SLAPrint::process()
|
||||||
|
|
||||||
m_print_statistics.clear();
|
m_print_statistics.clear();
|
||||||
|
|
||||||
// Fill statistics
|
using ClipperPolygon = libnest2d::PolygonImpl;
|
||||||
fill_statistics();
|
using ClipperPath = ClipperLib::Path;
|
||||||
|
using ClipperPoint = ClipperLib::IntPoint;
|
||||||
|
using ClipperPolygons = std::vector<ClipperPolygon>;
|
||||||
|
using libnest2d::Radians;
|
||||||
|
namespace sl = libnest2d::shapelike;
|
||||||
|
|
||||||
|
// If the raster has vertical orientation, we will flip the coordinates
|
||||||
|
bool flpXY = m_printer_config.display_orientation.getInt() == SLADisplayOrientation::sladoPortrait;
|
||||||
|
|
||||||
|
auto polyunion = [] (const ClipperPolygons& subjects)
|
||||||
|
{
|
||||||
|
ClipperLib::Clipper clipper;
|
||||||
|
|
||||||
|
bool closed = true;
|
||||||
|
|
||||||
|
for(auto& path : subjects) {
|
||||||
|
clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed);
|
||||||
|
clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mode = ClipperLib::pftPositive;
|
||||||
|
|
||||||
|
return libnest2d::clipper_execute(clipper, ClipperLib::ctUnion, mode, mode);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto polydiff = [](const ClipperPolygons& subjects, const ClipperPolygons& clips)
|
||||||
|
{
|
||||||
|
ClipperLib::Clipper clipper;
|
||||||
|
|
||||||
|
bool closed = true;
|
||||||
|
|
||||||
|
for(auto& path : subjects) {
|
||||||
|
clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed);
|
||||||
|
clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& path : clips) {
|
||||||
|
clipper.AddPath(path.Contour, ClipperLib::ptClip, closed);
|
||||||
|
clipper.AddPaths(path.Holes, ClipperLib::ptClip, closed);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mode = ClipperLib::pftPositive;
|
||||||
|
|
||||||
|
return libnest2d::clipper_execute(clipper, ClipperLib::ctDifference, mode, mode);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto area = [](const ClipperPolygon& poly)
|
||||||
|
{
|
||||||
|
using ClipperLib::Area;
|
||||||
|
return std::accumulate( poly.Holes.begin(), poly.Holes.end(),
|
||||||
|
Area(poly.Contour),
|
||||||
|
[](double a, const ClipperPath& p) { return a + Area(p); });
|
||||||
|
};
|
||||||
|
|
||||||
|
const double area_fill = m_printer_config.area_fill.getFloat()*0.01;// 0.5 (50%);
|
||||||
|
const double fast_tilt = m_printer_config.fast_tilt_time.getFloat();// 5.0;
|
||||||
|
const double slow_tilt = m_printer_config.slow_tilt_time.getFloat();// 8.0;
|
||||||
|
|
||||||
|
const double init_exp_time = m_material_config.initial_exposure_time.getFloat();
|
||||||
|
const double exp_time = m_material_config.exposure_time.getFloat();
|
||||||
|
|
||||||
|
const int fade_layers_cnt = m_default_object_config.faded_layers.getInt();// 10 // [3;20]
|
||||||
|
|
||||||
|
const double width = m_printer_config.display_width.getFloat() / SCALING_FACTOR;
|
||||||
|
const double height = m_printer_config.display_height.getFloat() / SCALING_FACTOR;
|
||||||
|
const double display_area = width*height;
|
||||||
|
|
||||||
|
// get polygons for all instances in the object
|
||||||
|
auto get_all_polygons =
|
||||||
|
[flpXY](const ExPolygons& input_polygons,
|
||||||
|
const std::vector<SLAPrintObject::Instance>& instances)
|
||||||
|
{
|
||||||
|
ClipperPolygons polygons;
|
||||||
|
polygons.reserve(input_polygons.size() * instances.size());
|
||||||
|
|
||||||
|
for (const ExPolygon& polygon : input_polygons) {
|
||||||
|
if(polygon.contour.empty()) continue;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < instances.size(); ++i)
|
||||||
|
{
|
||||||
|
ClipperPolygon poly;
|
||||||
|
|
||||||
|
// should be a move
|
||||||
|
poly.Contour.reserve(polygon.contour.size() + 1);
|
||||||
|
|
||||||
|
for(auto& p : polygon.contour.points)
|
||||||
|
poly.Contour.emplace_back(p.x(), p.y());
|
||||||
|
|
||||||
|
auto pfirst = poly.Contour.front();
|
||||||
|
poly.Contour.emplace_back(pfirst);
|
||||||
|
|
||||||
|
for(auto& h : polygon.holes) {
|
||||||
|
poly.Holes.emplace_back();
|
||||||
|
auto& hole = poly.Holes.back();
|
||||||
|
hole.reserve(h.points.size() + 1);
|
||||||
|
|
||||||
|
for(auto& p : h.points) hole.emplace_back(p.x(), p.y());
|
||||||
|
auto pfirst = hole.front(); hole.emplace_back(pfirst);
|
||||||
|
}
|
||||||
|
|
||||||
|
sl::rotate(poly, Radians(double(instances[i].rotation)));
|
||||||
|
sl::translate(poly, ClipperPoint{instances[i].shift(X),
|
||||||
|
instances[i].shift(Y)});
|
||||||
|
if (flpXY) {
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
polygons.emplace_back(std::move(poly));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return polygons;
|
||||||
|
};
|
||||||
|
|
||||||
|
double supports_volume = 0.0;
|
||||||
|
double models_volume = 0.0;
|
||||||
|
|
||||||
|
double estim_time = 0.0;
|
||||||
|
|
||||||
|
size_t slow_layers = 0;
|
||||||
|
size_t fast_layers = 0;
|
||||||
|
|
||||||
|
const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1);
|
||||||
|
double fade_layer_time = init_exp_time;
|
||||||
|
|
||||||
|
int sliced_layer_cnt = 0;
|
||||||
|
for (PrintLayer& layer : m_printer_input)
|
||||||
|
{
|
||||||
|
// vector of slice record references
|
||||||
|
auto& lyrslices = layer.slices();
|
||||||
|
|
||||||
|
if(lyrslices.empty()) continue;
|
||||||
|
|
||||||
|
// Layer height should match for all object slices for a given level.
|
||||||
|
const auto l_height = double(lyrslices.front().get().layer_height());
|
||||||
|
|
||||||
|
// Calculation of the consumed material
|
||||||
|
|
||||||
|
ClipperPolygons model_polygons;
|
||||||
|
ClipperPolygons supports_polygons;
|
||||||
|
|
||||||
|
size_t c = std::accumulate(layer.slices().begin(), layer.slices().end(), 0u, [](size_t a, const SliceRecord& sr) {
|
||||||
|
return a + sr.get_slice(soModel).size();
|
||||||
|
});
|
||||||
|
|
||||||
|
model_polygons.reserve(c);
|
||||||
|
|
||||||
|
c = std::accumulate(layer.slices().begin(), layer.slices().end(), 0u, [](size_t a, const SliceRecord& sr) {
|
||||||
|
return a + sr.get_slice(soModel).size();
|
||||||
|
});
|
||||||
|
|
||||||
|
supports_polygons.reserve(c);
|
||||||
|
|
||||||
|
for(const SliceRecord& record : layer.slices()) {
|
||||||
|
const SLAPrintObject *po = record.print_obj();
|
||||||
|
|
||||||
|
const ExPolygons &modelslices = record.get_slice(soModel);
|
||||||
|
if (!modelslices.empty()) {
|
||||||
|
ClipperPolygons v = get_all_polygons(modelslices, po->instances());
|
||||||
|
for(ClipperPolygon& p_tmp : v) model_polygons.emplace_back(std::move(p_tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
const ExPolygons &supportslices = record.get_slice(soSupport);
|
||||||
|
if (!supportslices.empty()) {
|
||||||
|
ClipperPolygons v = get_all_polygons(supportslices, po->instances());
|
||||||
|
for(ClipperPolygon& p_tmp : v) supports_polygons.emplace_back(std::move(p_tmp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model_polygons = polyunion(model_polygons);
|
||||||
|
double layer_model_area = 0;
|
||||||
|
for (const ClipperPolygon& polygon : model_polygons)
|
||||||
|
layer_model_area += area(polygon);
|
||||||
|
|
||||||
|
if (layer_model_area < 0 || layer_model_area > 0)
|
||||||
|
models_volume += layer_model_area * l_height;
|
||||||
|
|
||||||
|
if(!supports_polygons.empty()) {
|
||||||
|
if(model_polygons.empty()) supports_polygons = polyunion(supports_polygons);
|
||||||
|
else supports_polygons = polydiff(supports_polygons, model_polygons);
|
||||||
|
// allegedly, union of subject is done withing the diff
|
||||||
|
}
|
||||||
|
|
||||||
|
double layer_support_area = 0;
|
||||||
|
for (const ClipperPolygon& polygon : supports_polygons)
|
||||||
|
layer_support_area += area(polygon);
|
||||||
|
|
||||||
|
if (layer_support_area < 0 || layer_model_area > 0)
|
||||||
|
supports_volume += layer_support_area * l_height;
|
||||||
|
|
||||||
|
// Here we can save the expensively calculated polygons for printing
|
||||||
|
ClipperPolygons trslices;
|
||||||
|
trslices.reserve(model_polygons.size() + supports_polygons.size());
|
||||||
|
for(ClipperPolygon& poly : model_polygons) trslices.emplace_back(std::move(poly));
|
||||||
|
for(ClipperPolygon& poly : supports_polygons) trslices.emplace_back(std::move(poly));
|
||||||
|
|
||||||
|
layer.transformed_slices(polyunion(trslices));
|
||||||
|
|
||||||
|
// Calculation of the slow and fast layers to the future controlling those values on FW
|
||||||
|
|
||||||
|
const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*area_fill;
|
||||||
|
const double tilt_time = is_fast_layer ? fast_tilt : slow_tilt;
|
||||||
|
if (is_fast_layer)
|
||||||
|
fast_layers++;
|
||||||
|
else
|
||||||
|
slow_layers++;
|
||||||
|
|
||||||
|
|
||||||
|
// Calculation of the printing time
|
||||||
|
|
||||||
|
if (sliced_layer_cnt < 3)
|
||||||
|
estim_time += init_exp_time;
|
||||||
|
else if (fade_layer_time > exp_time)
|
||||||
|
{
|
||||||
|
fade_layer_time -= delta_fade_time;
|
||||||
|
estim_time += fade_layer_time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
estim_time += exp_time;
|
||||||
|
|
||||||
|
estim_time += tilt_time;
|
||||||
|
|
||||||
|
sliced_layer_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_print_statistics.support_used_material = supports_volume * SCALING_FACTOR * SCALING_FACTOR;
|
||||||
|
m_print_statistics.objects_used_material = models_volume * SCALING_FACTOR * SCALING_FACTOR;
|
||||||
|
|
||||||
|
// Estimated printing time
|
||||||
|
// A layers count o the highest object
|
||||||
|
if (m_printer_input.size() == 0)
|
||||||
|
m_print_statistics.estimated_print_time = "N/A";
|
||||||
|
else
|
||||||
|
m_print_statistics.estimated_print_time = get_time_dhms(float(estim_time));
|
||||||
|
|
||||||
|
m_print_statistics.fast_layers_count = fast_layers;
|
||||||
|
m_print_statistics.slow_layers_count = slow_layers;
|
||||||
|
|
||||||
report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
|
report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
|
||||||
};
|
};
|
||||||
|
@ -1011,7 +1255,7 @@ void SLAPrint::process()
|
||||||
|
|
||||||
// procedure to process one height level. This will run in parallel
|
// procedure to process one height level. This will run in parallel
|
||||||
auto lvlfn =
|
auto lvlfn =
|
||||||
[this, &slck, &printer, slot, sd, ist, &pst, flpXY]
|
[this, &slck, &printer, slot, sd, ist, &pst]
|
||||||
(unsigned level_id)
|
(unsigned level_id)
|
||||||
{
|
{
|
||||||
if(canceled()) return;
|
if(canceled()) return;
|
||||||
|
@ -1021,31 +1265,9 @@ void SLAPrint::process()
|
||||||
// Switch to the appropriate layer in the printer
|
// Switch to the appropriate layer in the printer
|
||||||
printer.begin_layer(level_id);
|
printer.begin_layer(level_id);
|
||||||
|
|
||||||
for(const Polygon& poly : printlayer.transformed_slices())
|
for(const ClipperLib::Polygon& poly : printlayer.transformed_slices())
|
||||||
printer.draw_polygon(poly, level_id);
|
printer.draw_polygon(poly, level_id);
|
||||||
|
|
||||||
|
|
||||||
// auto draw =
|
|
||||||
// [&printer, flpXY, level_id](Polygon& poly, const Instance& tr)
|
|
||||||
// {
|
|
||||||
// poly.rotate(double(tr.rotation));
|
|
||||||
// poly.translate(tr.shift(X), tr.shift(Y));
|
|
||||||
// if(flpXY) for(auto& p : poly.points) std::swap(p(X), p(Y));
|
|
||||||
// printer.draw_polygon(poly, level_id);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// for(const SliceRecord& sr : printlayer.slices()) {
|
|
||||||
// if(! sr.print_obj()) continue;
|
|
||||||
|
|
||||||
// for(const Instance& inst : sr.print_obj()->instances()) {
|
|
||||||
// ExPolygons objsl = sr.get_slice(soModel);
|
|
||||||
// for(ExPolygon& poly : objsl) draw(poly, inst);
|
|
||||||
|
|
||||||
// ExPolygons supsl = sr.get_slice(soSupport);
|
|
||||||
// for(ExPolygon& poly : supsl) draw(poly, inst);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Finish the layer for later saving it.
|
// Finish the layer for later saving it.
|
||||||
printer.finish_layer(level_id);
|
printer.finish_layer(level_id);
|
||||||
|
|
||||||
|
@ -1221,149 +1443,6 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt
|
||||||
return invalidated;
|
return invalidated;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SLAPrint::fill_statistics()
|
|
||||||
{
|
|
||||||
const double area_fill = m_printer_config.area_fill.getFloat()*0.01;// 0.5 (50%);
|
|
||||||
const double fast_tilt = m_printer_config.fast_tilt_time.getFloat();// 5.0;
|
|
||||||
const double slow_tilt = m_printer_config.slow_tilt_time.getFloat();// 8.0;
|
|
||||||
|
|
||||||
const double init_exp_time = m_material_config.initial_exposure_time.getFloat();
|
|
||||||
const double exp_time = m_material_config.exposure_time.getFloat();
|
|
||||||
|
|
||||||
const int fade_layers_cnt = m_default_object_config.faded_layers.getInt();// 10 // [3;20]
|
|
||||||
|
|
||||||
const double width = m_printer_config.display_width.getFloat() / SCALING_FACTOR;
|
|
||||||
const double height = m_printer_config.display_height.getFloat() / SCALING_FACTOR;
|
|
||||||
const double display_area = width*height;
|
|
||||||
|
|
||||||
// If the raster has vertical orientation, we will flip the coordinates
|
|
||||||
bool flpXY = m_printer_config.display_orientation.getInt() ==
|
|
||||||
SLADisplayOrientation::sladoPortrait;
|
|
||||||
|
|
||||||
// get polygons for all instances in the object
|
|
||||||
auto get_all_polygons =
|
|
||||||
[flpXY](const ExPolygons& input_polygons,
|
|
||||||
const std::vector<SLAPrintObject::Instance>& instances)
|
|
||||||
{
|
|
||||||
const size_t inst_cnt = instances.size();
|
|
||||||
|
|
||||||
size_t polygon_cnt = 0;
|
|
||||||
for (const ExPolygon& polygon : input_polygons)
|
|
||||||
polygon_cnt += polygon.holes.size() + 1;
|
|
||||||
|
|
||||||
Polygons polygons;
|
|
||||||
polygons.reserve(polygon_cnt * inst_cnt);
|
|
||||||
for (const ExPolygon& polygon : input_polygons) {
|
|
||||||
for (size_t i = 0; i < inst_cnt; ++i)
|
|
||||||
{
|
|
||||||
ExPolygon tmp = polygon;
|
|
||||||
tmp.rotate(double(instances[i].rotation));
|
|
||||||
tmp.translate(instances[i].shift.x(), instances[i].shift.y());
|
|
||||||
if(flpXY) swapXY(tmp);
|
|
||||||
polygons_append(polygons, to_polygons(std::move(tmp)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return polygons;
|
|
||||||
};
|
|
||||||
|
|
||||||
double supports_volume = 0.0;
|
|
||||||
double models_volume = 0.0;
|
|
||||||
|
|
||||||
double estim_time = 0.0;
|
|
||||||
|
|
||||||
size_t slow_layers = 0;
|
|
||||||
size_t fast_layers = 0;
|
|
||||||
|
|
||||||
const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1);
|
|
||||||
double fade_layer_time = init_exp_time;
|
|
||||||
|
|
||||||
int sliced_layer_cnt = 0;
|
|
||||||
for (PrintLayer& layer : m_printer_input)
|
|
||||||
{
|
|
||||||
if(layer.slices().empty()) continue;
|
|
||||||
|
|
||||||
// Layer height should match for all object slices for a given level.
|
|
||||||
const auto l_height = double(layer.slices().front().get().layer_height());
|
|
||||||
|
|
||||||
// Calculation of the consumed material
|
|
||||||
|
|
||||||
Polygons model_polygons;
|
|
||||||
Polygons supports_polygons;
|
|
||||||
|
|
||||||
for(const SliceRecord& record : layer.slices()) {
|
|
||||||
const SLAPrintObject *po = record.print_obj();
|
|
||||||
|
|
||||||
const ExPolygons &modelslices = record.get_slice(soModel);
|
|
||||||
if (!modelslices.empty())
|
|
||||||
append(model_polygons, get_all_polygons(modelslices, po->instances()));
|
|
||||||
|
|
||||||
const ExPolygons &supportslices = record.get_slice(soSupport);
|
|
||||||
if (!supportslices.empty())
|
|
||||||
append(supports_polygons, get_all_polygons(supportslices, po->instances()));
|
|
||||||
}
|
|
||||||
|
|
||||||
model_polygons = union_(model_polygons);
|
|
||||||
double layer_model_area = 0;
|
|
||||||
for (const Polygon& polygon : model_polygons)
|
|
||||||
layer_model_area += polygon.area();
|
|
||||||
|
|
||||||
if (layer_model_area < 0 || layer_model_area > 0)
|
|
||||||
models_volume += layer_model_area * l_height;
|
|
||||||
|
|
||||||
if (!supports_polygons.empty() && !model_polygons.empty())
|
|
||||||
supports_polygons = diff(supports_polygons, model_polygons);
|
|
||||||
double layer_support_area = 0;
|
|
||||||
for (const Polygon& polygon : supports_polygons)
|
|
||||||
layer_support_area += polygon.area();
|
|
||||||
|
|
||||||
if (layer_support_area < 0 || layer_model_area > 0)
|
|
||||||
supports_volume += layer_support_area * l_height;
|
|
||||||
|
|
||||||
// Here we can save the expensively calculated polygons for printing
|
|
||||||
append(model_polygons, supports_polygons);
|
|
||||||
layer.transformed_slices(union_(model_polygons));
|
|
||||||
|
|
||||||
// Calculation of the slow and fast layers to the future controlling those values on FW
|
|
||||||
|
|
||||||
const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*area_fill;
|
|
||||||
const double tilt_time = is_fast_layer ? fast_tilt : slow_tilt;
|
|
||||||
if (is_fast_layer)
|
|
||||||
fast_layers++;
|
|
||||||
else
|
|
||||||
slow_layers++;
|
|
||||||
|
|
||||||
|
|
||||||
// Calculation of the printing time
|
|
||||||
|
|
||||||
if (sliced_layer_cnt < 3)
|
|
||||||
estim_time += init_exp_time;
|
|
||||||
else if (fade_layer_time > exp_time)
|
|
||||||
{
|
|
||||||
fade_layer_time -= delta_fade_time;
|
|
||||||
estim_time += fade_layer_time;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
estim_time += exp_time;
|
|
||||||
|
|
||||||
estim_time += tilt_time;
|
|
||||||
|
|
||||||
sliced_layer_cnt++;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_print_statistics.support_used_material = supports_volume * SCALING_FACTOR * SCALING_FACTOR;
|
|
||||||
m_print_statistics.objects_used_material = models_volume * SCALING_FACTOR * SCALING_FACTOR;
|
|
||||||
|
|
||||||
// Estimated printing time
|
|
||||||
// A layers count o the highest object
|
|
||||||
if (m_printer_input.size() == 0)
|
|
||||||
m_print_statistics.estimated_print_time = "N/A";
|
|
||||||
else
|
|
||||||
m_print_statistics.estimated_print_time = get_time_dhms(float(estim_time));
|
|
||||||
|
|
||||||
m_print_statistics.fast_layers_count = fast_layers;
|
|
||||||
m_print_statistics.slow_layers_count = slow_layers;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if an object step is done on all objects and there's at least one object.
|
// Returns true if an object step is done on all objects and there's at least one object.
|
||||||
bool SLAPrint::is_step_done(SLAPrintObjectStep step) const
|
bool SLAPrint::is_step_done(SLAPrintObjectStep step) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "PrintExport.hpp"
|
#include "PrintExport.hpp"
|
||||||
#include "Point.hpp"
|
#include "Point.hpp"
|
||||||
#include "MTUtils.hpp"
|
#include "MTUtils.hpp"
|
||||||
|
#include <libnest2d/backends/clipper/clipper_polygon.hpp>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
@ -328,46 +329,8 @@ class SLAPrint : public PrintBaseWithState<SLAPrintStep, slapsCount>
|
||||||
private: // Prevents erroneous use by other classes.
|
private: // Prevents erroneous use by other classes.
|
||||||
typedef PrintBaseWithState<SLAPrintStep, slapsCount> Inherited;
|
typedef PrintBaseWithState<SLAPrintStep, slapsCount> Inherited;
|
||||||
|
|
||||||
void fill_statistics();
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// An aggregation of SliceRecord-s from all the print objects for each
|
|
||||||
// occupied layer. Slice record levels dont have to match exactly.
|
|
||||||
// They are unified if the level difference is within +/- SCALED_EPSILON
|
|
||||||
class PrintLayer {
|
|
||||||
coord_t m_level;
|
|
||||||
|
|
||||||
// The collection of slice records for the current level.
|
|
||||||
std::vector<std::reference_wrapper<const SliceRecord>> m_slices;
|
|
||||||
|
|
||||||
Polygons m_transformed_slices;
|
|
||||||
|
|
||||||
template<class Container> void transformed_slices(Container&& c) {
|
|
||||||
m_transformed_slices = std::forward<Container>(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend void SLAPrint::fill_statistics();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
explicit PrintLayer(coord_t lvl) : m_level(lvl) {}
|
|
||||||
|
|
||||||
// for being sorted in their container (see m_printer_input)
|
|
||||||
bool operator<(const PrintLayer& other) const {
|
|
||||||
return m_level < other.m_level;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add(const SliceRecord& sr) { m_slices.emplace_back(sr); }
|
|
||||||
|
|
||||||
coord_t level() const { return m_level; }
|
|
||||||
|
|
||||||
auto slices() const -> const decltype (m_slices)& { return m_slices; }
|
|
||||||
|
|
||||||
const Polygons& transformed_slices() const {
|
|
||||||
return m_transformed_slices;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
SLAPrint(): m_stepmask(slapsCount, true) {}
|
SLAPrint(): m_stepmask(slapsCount, true) {}
|
||||||
|
|
||||||
virtual ~SLAPrint() override { this->clear(); }
|
virtual ~SLAPrint() override { this->clear(); }
|
||||||
|
@ -401,6 +364,43 @@ public:
|
||||||
|
|
||||||
std::string validate() const override;
|
std::string validate() const override;
|
||||||
|
|
||||||
|
// An aggregation of SliceRecord-s from all the print objects for each
|
||||||
|
// occupied layer. Slice record levels dont have to match exactly.
|
||||||
|
// They are unified if the level difference is within +/- SCALED_EPSILON
|
||||||
|
class PrintLayer {
|
||||||
|
coord_t m_level;
|
||||||
|
|
||||||
|
// The collection of slice records for the current level.
|
||||||
|
std::vector<std::reference_wrapper<const SliceRecord>> m_slices;
|
||||||
|
|
||||||
|
std::vector<ClipperLib::Polygon> m_transformed_slices;
|
||||||
|
|
||||||
|
template<class Container> void transformed_slices(Container&& c) {
|
||||||
|
m_transformed_slices = std::forward<Container>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend void SLAPrint::process();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit PrintLayer(coord_t lvl) : m_level(lvl) {}
|
||||||
|
|
||||||
|
// for being sorted in their container (see m_printer_input)
|
||||||
|
bool operator<(const PrintLayer& other) const {
|
||||||
|
return m_level < other.m_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(const SliceRecord& sr) { m_slices.emplace_back(sr); }
|
||||||
|
|
||||||
|
coord_t level() const { return m_level; }
|
||||||
|
|
||||||
|
auto slices() const -> const decltype (m_slices)& { return m_slices; }
|
||||||
|
|
||||||
|
const std::vector<ClipperLib::Polygon> & transformed_slices() const {
|
||||||
|
return m_transformed_slices;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// The aggregated and leveled print records from various objects.
|
// The aggregated and leveled print records from various objects.
|
||||||
// TODO: use this structure for the preview in the future.
|
// TODO: use this structure for the preview in the future.
|
||||||
const std::vector<PrintLayer>& print_layers() const { return m_printer_input; }
|
const std::vector<PrintLayer>& print_layers() const { return m_printer_input; }
|
||||||
|
|
Loading…
Add table
Reference in a new issue