2018-11-08 19:18:40 +00:00
|
|
|
#ifndef slic3r_SLAPrint_hpp_
|
|
|
|
#define slic3r_SLAPrint_hpp_
|
|
|
|
|
2018-11-21 14:21:57 +00:00
|
|
|
#include <mutex>
|
2018-11-08 19:18:40 +00:00
|
|
|
#include "PrintBase.hpp"
|
2018-11-13 16:33:03 +00:00
|
|
|
#include "PrintExport.hpp"
|
2018-11-08 19:18:40 +00:00
|
|
|
#include "Point.hpp"
|
2018-11-21 14:21:57 +00:00
|
|
|
#include "MTUtils.hpp"
|
2019-03-27 17:37:50 +00:00
|
|
|
#include <libnest2d/backends/clipper/clipper_polygon.hpp>
|
2019-03-14 18:07:16 +00:00
|
|
|
#include "Zipper.hpp"
|
2018-11-08 19:18:40 +00:00
|
|
|
|
|
|
|
namespace Slic3r {
|
|
|
|
|
2018-11-13 17:44:30 +00:00
|
|
|
enum SLAPrintStep : unsigned int {
|
2019-03-27 09:59:29 +00:00
|
|
|
slapsMergeSlicesAndEval,
|
|
|
|
slapsRasterize,
|
2018-11-08 19:18:40 +00:00
|
|
|
slapsCount
|
|
|
|
};
|
|
|
|
|
2018-11-13 17:44:30 +00:00
|
|
|
enum SLAPrintObjectStep : unsigned int {
|
2018-11-09 11:02:42 +00:00
|
|
|
slaposObjectSlice,
|
2018-11-08 19:18:40 +00:00
|
|
|
slaposSupportPoints,
|
|
|
|
slaposSupportTree,
|
|
|
|
slaposBasePool,
|
2019-03-27 09:59:29 +00:00
|
|
|
slaposSliceSupports,
|
2018-11-08 19:18:40 +00:00
|
|
|
slaposCount
|
|
|
|
};
|
|
|
|
|
|
|
|
class SLAPrint;
|
2018-11-12 16:35:57 +00:00
|
|
|
class GLCanvas;
|
2018-11-08 19:18:40 +00:00
|
|
|
|
2018-11-09 17:32:35 +00:00
|
|
|
using _SLAPrintObjectBase =
|
|
|
|
PrintObjectBaseWithState<SLAPrint, SLAPrintObjectStep, slaposCount>;
|
|
|
|
|
2018-11-29 17:12:40 +00:00
|
|
|
// Layers according to quantized height levels. This will be consumed by
|
|
|
|
// the printer (rasterizer) in the SLAPrint class.
|
2019-03-25 18:02:05 +00:00
|
|
|
// using coord_t = long long;
|
2018-11-29 17:12:40 +00:00
|
|
|
|
2019-03-21 11:25:33 +00:00
|
|
|
enum SliceOrigin { soSupport, soModel };
|
2019-03-20 17:03:11 +00:00
|
|
|
|
2018-11-09 17:32:35 +00:00
|
|
|
class SLAPrintObject : public _SLAPrintObjectBase
|
2018-11-08 19:18:40 +00:00
|
|
|
{
|
|
|
|
private: // Prevents erroneous use by other classes.
|
2018-11-09 17:32:35 +00:00
|
|
|
using Inherited = _SLAPrintObjectBase;
|
2018-11-08 19:18:40 +00:00
|
|
|
|
|
|
|
public:
|
2019-03-20 17:03:11 +00:00
|
|
|
|
|
|
|
// I refuse to grantee copying (Tamas)
|
|
|
|
SLAPrintObject(const SLAPrintObject&) = delete;
|
|
|
|
SLAPrintObject& operator=(const SLAPrintObject&) = delete;
|
|
|
|
|
2018-11-21 16:35:35 +00:00
|
|
|
const SLAPrintObjectConfig& config() const { return m_config; }
|
|
|
|
const Transform3d& trafo() const { return m_trafo; }
|
2019-04-02 11:47:49 +00:00
|
|
|
bool is_left_handed() const { return m_left_handed; }
|
2018-11-13 16:45:44 +00:00
|
|
|
|
|
|
|
struct Instance {
|
2018-11-13 18:22:05 +00:00
|
|
|
Instance(ModelID instance_id, const Point &shift, float rotation) : instance_id(instance_id), shift(shift), rotation(rotation) {}
|
2018-11-21 16:35:35 +00:00
|
|
|
bool operator==(const Instance &rhs) const { return this->instance_id == rhs.instance_id && this->shift == rhs.shift && this->rotation == rhs.rotation; }
|
2018-11-13 18:22:05 +00:00
|
|
|
// ID of the corresponding ModelInstance.
|
|
|
|
ModelID instance_id;
|
|
|
|
// Slic3r::Point objects in scaled G-code coordinates
|
2018-11-13 16:45:44 +00:00
|
|
|
Point shift;
|
|
|
|
// Rotation along the Z axis, in radians.
|
2018-11-21 16:35:35 +00:00
|
|
|
float rotation;
|
2018-11-13 18:22:05 +00:00
|
|
|
};
|
2018-11-13 16:45:44 +00:00
|
|
|
const std::vector<Instance>& instances() const { return m_instances; }
|
|
|
|
|
2018-11-17 16:23:56 +00:00
|
|
|
bool has_mesh(SLAPrintObjectStep step) const;
|
|
|
|
TriangleMesh get_mesh(SLAPrintObjectStep step) const;
|
|
|
|
|
2018-11-13 16:45:44 +00:00
|
|
|
// Get a support mesh centered around origin in XY, and with zero rotation around Z applied.
|
|
|
|
// Support mesh is only valid if this->is_step_done(slaposSupportTree) is true.
|
2018-11-21 14:21:57 +00:00
|
|
|
const TriangleMesh& support_mesh() const;
|
2018-11-13 16:45:44 +00:00
|
|
|
// Get a pad mesh centered around origin in XY, and with zero rotation around Z applied.
|
2018-11-26 13:43:28 +00:00
|
|
|
// Support mesh is only valid if this->is_step_done(slaposBasePool) is true.
|
2018-11-21 14:21:57 +00:00
|
|
|
const TriangleMesh& pad_mesh() const;
|
2018-11-09 11:02:42 +00:00
|
|
|
|
2018-11-15 17:05:47 +00:00
|
|
|
// This will return the transformed mesh which is cached
|
|
|
|
const TriangleMesh& transformed_mesh() const;
|
|
|
|
|
2019-01-30 07:26:23 +00:00
|
|
|
std::vector<sla::SupportPoint> transformed_support_points() const;
|
2018-11-16 10:34:19 +00:00
|
|
|
|
2018-11-16 16:25:23 +00:00
|
|
|
// Get the needed Z elevation for the model geometry if supports should be
|
|
|
|
// displayed. This Z offset should also be applied to the support
|
|
|
|
// geometries. Note that this is not the same as the value stored in config
|
|
|
|
// as the pad height also needs to be considered.
|
|
|
|
double get_elevation() const;
|
|
|
|
|
2018-11-22 12:57:13 +00:00
|
|
|
// This method returns the needed elevation according to the processing
|
|
|
|
// status. If the supports are not ready, it is zero, if they are and the
|
|
|
|
// pad is not, then without the pad, otherwise the full value is returned.
|
|
|
|
double get_current_elevation() const;
|
2018-11-16 16:25:23 +00:00
|
|
|
|
2018-12-21 11:35:20 +00:00
|
|
|
// This method returns the support points of this SLAPrintObject.
|
2019-02-17 12:05:22 +00:00
|
|
|
const std::vector<sla::SupportPoint>& get_support_points() const;
|
2018-12-21 11:35:20 +00:00
|
|
|
|
2019-03-26 10:22:35 +00:00
|
|
|
// The public Slice record structure. It corresponds to one printable layer.
|
|
|
|
class SliceRecord {
|
|
|
|
public:
|
|
|
|
// this will be the max limit of size_t
|
|
|
|
static const size_t NONE = size_t(-1);
|
|
|
|
|
|
|
|
static const SliceRecord EMPTY;
|
|
|
|
|
|
|
|
private:
|
|
|
|
coord_t m_print_z = 0; // Top of the layer
|
|
|
|
float m_slice_z = 0.f; // Exact level of the slice
|
|
|
|
float m_height = 0.f; // Height of the sliced layer
|
|
|
|
|
|
|
|
size_t m_model_slices_idx = NONE;
|
|
|
|
size_t m_support_slices_idx = NONE;
|
|
|
|
const SLAPrintObject *m_po = nullptr;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
SliceRecord(coord_t key, float slicez, float height):
|
|
|
|
m_print_z(key), m_slice_z(slicez), m_height(height) {}
|
|
|
|
|
|
|
|
// The key will be the integer height level of the top of the layer.
|
|
|
|
coord_t print_level() const { return m_print_z; }
|
|
|
|
|
|
|
|
// Returns the exact floating point Z coordinate of the slice
|
|
|
|
float slice_level() const { return m_slice_z; }
|
|
|
|
|
|
|
|
// Returns the current layer height
|
|
|
|
float layer_height() const { return m_height; }
|
|
|
|
|
2019-03-26 15:45:04 +00:00
|
|
|
bool is_valid() const { return ! std::isnan(m_slice_z); }
|
2019-03-26 10:22:35 +00:00
|
|
|
|
2019-03-26 17:51:27 +00:00
|
|
|
const SLAPrintObject* print_obj() const { assert(m_po); return m_po; }
|
2019-03-26 10:22:35 +00:00
|
|
|
|
|
|
|
// Methods for setting the indices into the slice vectors.
|
|
|
|
void set_model_slice_idx(const SLAPrintObject &po, size_t id) {
|
|
|
|
m_po = &po; m_model_slices_idx = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_support_slice_idx(const SLAPrintObject& po, size_t id) {
|
|
|
|
m_po = &po; m_support_slices_idx = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ExPolygons& get_slice(SliceOrigin o) const;
|
|
|
|
};
|
|
|
|
|
2019-03-21 17:01:41 +00:00
|
|
|
private:
|
|
|
|
|
2019-03-26 09:57:45 +00:00
|
|
|
template <class T> inline static T level(const SliceRecord& sr) {
|
|
|
|
static_assert(std::is_arithmetic<T>::value, "Arithmetic only!");
|
|
|
|
return std::is_integral<T>::value ? T(sr.print_level()) : T(sr.slice_level());
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T> inline static SliceRecord create_slice_record(T val) {
|
|
|
|
static_assert(std::is_arithmetic<T>::value, "Arithmetic only!");
|
|
|
|
return std::is_integral<T>::value ? SliceRecord{ coord_t(val), 0.f, 0.f } : SliceRecord{ 0, float(val), 0.f };
|
|
|
|
}
|
|
|
|
|
2019-03-25 18:02:05 +00:00
|
|
|
// This is a template method for searching the slice index either by
|
|
|
|
// an integer key: print_level or a floating point key: slice_level.
|
|
|
|
// The eps parameter gives the max deviation in + or - direction.
|
|
|
|
//
|
|
|
|
// This method can be used in const or non-const contexts as well.
|
|
|
|
template<class Container, class T>
|
2019-03-26 15:45:04 +00:00
|
|
|
static auto closest_slice_record(
|
|
|
|
Container& cont,
|
|
|
|
T lvl,
|
|
|
|
T eps = std::numeric_limits<T>::max()) -> decltype (cont.begin())
|
2019-03-25 18:02:05 +00:00
|
|
|
{
|
|
|
|
if(cont.empty()) return cont.end();
|
2019-03-26 09:57:45 +00:00
|
|
|
if(cont.size() == 1 && std::abs(level<T>(cont.front()) - lvl) > eps)
|
2019-03-25 18:02:05 +00:00
|
|
|
return cont.end();
|
2018-11-26 13:43:28 +00:00
|
|
|
|
2019-03-26 09:57:45 +00:00
|
|
|
SliceRecord query = create_slice_record(lvl);
|
2018-11-26 13:43:28 +00:00
|
|
|
|
2019-03-25 18:02:05 +00:00
|
|
|
auto it = std::lower_bound(cont.begin(), cont.end(), query,
|
|
|
|
[](const SliceRecord& r1,
|
|
|
|
const SliceRecord& r2)
|
|
|
|
{
|
2019-03-26 09:57:45 +00:00
|
|
|
return level<T>(r1) < level<T>(r2);
|
2019-03-25 18:02:05 +00:00
|
|
|
});
|
2018-11-16 16:25:23 +00:00
|
|
|
|
2019-03-26 09:57:45 +00:00
|
|
|
T diff = std::abs(level<T>(*it) - lvl);
|
2019-03-21 15:14:26 +00:00
|
|
|
|
2019-03-25 18:02:05 +00:00
|
|
|
if(it != cont.begin()) {
|
|
|
|
auto it_prev = std::prev(it);
|
2019-03-26 09:57:45 +00:00
|
|
|
T diff_prev = std::abs(level<T>(*it_prev) - lvl);
|
2019-03-25 18:02:05 +00:00
|
|
|
if(diff_prev < diff) { diff = diff_prev; it = it_prev; }
|
|
|
|
}
|
2019-03-20 17:03:11 +00:00
|
|
|
|
2019-03-25 18:02:05 +00:00
|
|
|
if(diff > eps) it = cont.end();
|
2019-03-20 17:03:11 +00:00
|
|
|
|
2019-03-25 18:02:05 +00:00
|
|
|
return it;
|
|
|
|
}
|
2019-03-21 15:14:26 +00:00
|
|
|
|
2019-03-27 09:59:29 +00:00
|
|
|
const std::vector<ExPolygons>& get_model_slices() const { return m_model_slices; }
|
2019-03-26 10:22:35 +00:00
|
|
|
const std::vector<ExPolygons>& get_support_slices() const;
|
|
|
|
|
2019-03-25 18:02:05 +00:00
|
|
|
public:
|
2019-03-20 17:03:11 +00:00
|
|
|
|
2019-03-22 14:31:38 +00:00
|
|
|
// /////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
2019-03-25 18:02:05 +00:00
|
|
|
// These methods should be callable on the client side (e.g. UI thread)
|
2019-03-20 17:03:11 +00:00
|
|
|
// when the appropriate steps slaposObjectSlice and slaposSliceSupports
|
|
|
|
// are ready. All the print objects are processed before slapsRasterize so
|
|
|
|
// it is safe to call them during and/or after slapsRasterize.
|
2019-03-22 14:31:38 +00:00
|
|
|
//
|
|
|
|
// /////////////////////////////////////////////////////////////////////////
|
2018-11-09 17:32:35 +00:00
|
|
|
|
2019-03-25 18:02:05 +00:00
|
|
|
// Retrieve the slice index.
|
2019-03-27 09:59:29 +00:00
|
|
|
const std::vector<SliceRecord>& get_slice_index() const {
|
|
|
|
return m_slice_index;
|
|
|
|
}
|
2019-03-22 14:31:38 +00:00
|
|
|
|
2019-03-25 18:02:05 +00:00
|
|
|
// Search slice index for the closest slice to given print_level.
|
|
|
|
// max_epsilon gives the allowable deviation of the returned slice record's
|
|
|
|
// level.
|
|
|
|
const SliceRecord& closest_slice_to_print_level(
|
2019-03-26 15:45:04 +00:00
|
|
|
coord_t print_level,
|
|
|
|
coord_t max_epsilon = std::numeric_limits<coord_t>::max()) const
|
2019-03-25 18:02:05 +00:00
|
|
|
{
|
|
|
|
auto it = closest_slice_record(m_slice_index, print_level, max_epsilon);
|
2019-03-26 15:45:04 +00:00
|
|
|
return it == m_slice_index.end() ? SliceRecord::EMPTY : *it;
|
2019-03-22 14:31:38 +00:00
|
|
|
}
|
2019-03-21 15:14:26 +00:00
|
|
|
|
2019-03-25 18:02:05 +00:00
|
|
|
// Search slice index for the closest slice to given slice_level.
|
|
|
|
// max_epsilon gives the allowable deviation of the returned slice record's
|
2019-03-26 15:45:04 +00:00
|
|
|
// level. Use SliceRecord::is_valid() to check the result.
|
2019-03-25 18:02:05 +00:00
|
|
|
const SliceRecord& closest_slice_to_slice_level(
|
2019-03-26 15:45:04 +00:00
|
|
|
float slice_level,
|
|
|
|
float max_epsilon = std::numeric_limits<float>::max()) const
|
2019-03-25 18:02:05 +00:00
|
|
|
{
|
|
|
|
auto it = closest_slice_record(m_slice_index, slice_level, max_epsilon);
|
2019-03-26 15:45:04 +00:00
|
|
|
return it == m_slice_index.end() ? SliceRecord::EMPTY : *it;
|
2019-03-21 11:25:33 +00:00
|
|
|
}
|
|
|
|
|
2018-11-09 11:02:42 +00:00
|
|
|
protected:
|
|
|
|
// to be called from SLAPrint only.
|
|
|
|
friend class SLAPrint;
|
|
|
|
|
|
|
|
SLAPrintObject(SLAPrint* print, ModelObject* model_object);
|
2018-11-09 17:32:35 +00:00
|
|
|
~SLAPrintObject();
|
2018-11-09 11:02:42 +00:00
|
|
|
|
|
|
|
void config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->m_config.apply(other, ignore_nonexistent); }
|
|
|
|
void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false)
|
|
|
|
{ this->m_config.apply_only(other, keys, ignore_nonexistent); }
|
2018-11-21 14:21:57 +00:00
|
|
|
|
2019-04-02 11:47:49 +00:00
|
|
|
void set_trafo(const Transform3d& trafo, bool left_handed) {
|
|
|
|
m_transformed_rmesh.invalidate([this, &trafo, left_handed](){ m_trafo = trafo; m_left_handed = left_handed; });
|
2018-11-21 14:21:57 +00:00
|
|
|
}
|
2018-11-09 11:02:42 +00:00
|
|
|
|
2019-04-02 15:48:50 +00:00
|
|
|
template<class InstVec> inline void set_instances(InstVec&& instances) { m_instances = std::forward<InstVec>(instances); }
|
|
|
|
|
2018-11-09 11:02:42 +00:00
|
|
|
// Invalidates the step, and its depending steps in SLAPrintObject and SLAPrint.
|
|
|
|
bool invalidate_step(SLAPrintObjectStep step);
|
2018-11-21 16:35:35 +00:00
|
|
|
bool invalidate_all_steps();
|
|
|
|
// Invalidate steps based on a set of parameters changed.
|
|
|
|
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
2018-11-08 19:18:40 +00:00
|
|
|
|
2019-02-21 07:44:07 +00:00
|
|
|
// Which steps have to be performed. Implicitly: all
|
|
|
|
// to be accessible from SLAPrint
|
|
|
|
std::vector<bool> m_stepmask;
|
|
|
|
|
2018-11-08 19:18:40 +00:00
|
|
|
private:
|
2018-11-09 11:02:42 +00:00
|
|
|
// Object specific configuration, pulled from the configuration layer.
|
|
|
|
SLAPrintObjectConfig m_config;
|
2019-03-21 14:16:33 +00:00
|
|
|
|
2018-11-09 11:02:42 +00:00
|
|
|
// Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
|
|
|
|
Transform3d m_trafo = Transform3d::Identity();
|
2019-04-02 11:47:49 +00:00
|
|
|
// m_trafo is left handed -> 3x3 affine transformation has negative determinant.
|
|
|
|
bool m_left_handed = false;
|
2019-03-21 14:16:33 +00:00
|
|
|
|
2018-11-09 11:02:42 +00:00
|
|
|
std::vector<Instance> m_instances;
|
|
|
|
|
2019-01-15 13:25:28 +00:00
|
|
|
// Individual 2d slice polygons from lower z to higher z levels
|
2018-11-13 16:33:03 +00:00
|
|
|
std::vector<ExPolygons> m_model_slices;
|
2019-01-15 13:25:28 +00:00
|
|
|
|
|
|
|
// Exact (float) height levels mapped to the slices. Each record contains
|
|
|
|
// the index to the model and the support slice vectors.
|
2019-03-25 18:02:05 +00:00
|
|
|
std::vector<SliceRecord> m_slice_index;
|
2019-01-15 13:25:28 +00:00
|
|
|
|
2019-03-21 14:16:33 +00:00
|
|
|
std::vector<float> m_model_height_levels;
|
2018-11-08 19:18:40 +00:00
|
|
|
|
2018-11-15 17:05:47 +00:00
|
|
|
// Caching the transformed (m_trafo) raw mesh of the object
|
2018-11-21 14:21:57 +00:00
|
|
|
mutable CachedObject<TriangleMesh> m_transformed_rmesh;
|
2018-11-15 17:05:47 +00:00
|
|
|
|
2018-11-09 17:32:35 +00:00
|
|
|
class SupportData;
|
|
|
|
std::unique_ptr<SupportData> m_supportdata;
|
2018-11-08 19:18:40 +00:00
|
|
|
};
|
|
|
|
|
2018-11-12 16:35:57 +00:00
|
|
|
using PrintObjects = std::vector<SLAPrintObject*>;
|
|
|
|
|
2019-03-26 10:22:35 +00:00
|
|
|
using SliceRecord = SLAPrintObject::SliceRecord;
|
|
|
|
|
2018-11-12 16:35:57 +00:00
|
|
|
class TriangleMesh;
|
|
|
|
|
2019-02-12 15:34:42 +00:00
|
|
|
struct SLAPrintStatistics
|
|
|
|
{
|
|
|
|
SLAPrintStatistics() { clear(); }
|
|
|
|
std::string estimated_print_time;
|
2019-02-13 14:35:41 +00:00
|
|
|
double objects_used_material;
|
|
|
|
double support_used_material;
|
2019-02-18 11:28:58 +00:00
|
|
|
size_t slow_layers_count;
|
|
|
|
size_t fast_layers_count;
|
2019-02-12 15:34:42 +00:00
|
|
|
double total_cost;
|
|
|
|
double total_weight;
|
|
|
|
|
|
|
|
// Config with the filled in print statistics.
|
|
|
|
DynamicConfig config() const;
|
|
|
|
// Config with the statistics keys populated with placeholder strings.
|
|
|
|
static DynamicConfig placeholders();
|
|
|
|
// Replace the print statistics placeholders in the path.
|
|
|
|
std::string finalize_output_path(const std::string &path_in) const;
|
|
|
|
|
|
|
|
void clear() {
|
|
|
|
estimated_print_time.clear();
|
2019-02-13 14:35:41 +00:00
|
|
|
objects_used_material = 0.;
|
|
|
|
support_used_material = 0.;
|
2019-02-18 11:28:58 +00:00
|
|
|
slow_layers_count = 0;
|
|
|
|
fast_layers_count = 0;
|
2019-02-12 15:34:42 +00:00
|
|
|
total_cost = 0.;
|
|
|
|
total_weight = 0.;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-03-15 11:16:05 +00:00
|
|
|
struct SLAminzZipper {};
|
2019-03-14 18:07:16 +00:00
|
|
|
|
|
|
|
// The implementation of creating zipped archives with wxWidgets
|
2019-03-15 11:16:05 +00:00
|
|
|
template<> class LayerWriter<SLAminzZipper> {
|
2019-03-14 18:07:16 +00:00
|
|
|
Zipper m_zip;
|
|
|
|
public:
|
|
|
|
|
2019-03-28 15:19:30 +00:00
|
|
|
LayerWriter(const std::string& zipfile_path): m_zip(zipfile_path) {}
|
2019-03-14 18:07:16 +00:00
|
|
|
|
2019-03-28 15:19:30 +00:00
|
|
|
void next_entry(const std::string& fname) { m_zip.add_entry(fname); }
|
2019-03-14 18:07:16 +00:00
|
|
|
|
2019-03-28 15:19:30 +00:00
|
|
|
void binary_entry(const std::string& fname,
|
2019-03-18 17:02:50 +00:00
|
|
|
const std::uint8_t* buf,
|
|
|
|
size_t l)
|
|
|
|
{
|
|
|
|
m_zip.add_entry(fname, buf, l);
|
|
|
|
}
|
|
|
|
|
2019-03-28 15:19:30 +00:00
|
|
|
std::string get_name() const {
|
2019-03-14 18:07:16 +00:00
|
|
|
return m_zip.get_name();
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T> inline LayerWriter& operator<<(T&& arg) {
|
|
|
|
m_zip << std::forward<T>(arg); return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_ok() const {
|
|
|
|
return true; // m_zip blows up if something goes wrong...
|
|
|
|
}
|
|
|
|
|
2019-03-28 15:19:30 +00:00
|
|
|
// After finalize, no writing to the archive will have an effect. The only
|
|
|
|
// valid operation is to dispose the object calling the destructor which
|
|
|
|
// should close the file. This method can throw and signal potential errors
|
|
|
|
// when flushing the archive. This is why its present.
|
|
|
|
void finalize() { m_zip.finalize(); }
|
2019-03-14 18:07:16 +00:00
|
|
|
};
|
|
|
|
|
2018-11-08 19:18:40 +00:00
|
|
|
/**
|
|
|
|
* @brief This class is the high level FSM for the SLA printing process.
|
|
|
|
*
|
|
|
|
* It should support the background processing framework and contain the
|
|
|
|
* metadata for the support geometries and their slicing. It should also
|
|
|
|
* dispatch the SLA printing configuration values to the appropriate calculation
|
|
|
|
* steps.
|
|
|
|
*/
|
|
|
|
class SLAPrint : public PrintBaseWithState<SLAPrintStep, slapsCount>
|
|
|
|
{
|
|
|
|
private: // Prevents erroneous use by other classes.
|
|
|
|
typedef PrintBaseWithState<SLAPrintStep, slapsCount> Inherited;
|
|
|
|
|
|
|
|
public:
|
2019-03-26 09:57:45 +00:00
|
|
|
|
2019-03-27 17:37:50 +00:00
|
|
|
SLAPrint(): m_stepmask(slapsCount, true) {}
|
|
|
|
|
|
|
|
virtual ~SLAPrint() override { this->clear(); }
|
|
|
|
|
|
|
|
PrinterTechnology technology() const noexcept override { return ptSLA; }
|
|
|
|
|
|
|
|
void clear() override;
|
|
|
|
bool empty() const override { return m_objects.empty(); }
|
|
|
|
ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override;
|
|
|
|
void set_task(const TaskParams ¶ms) override;
|
|
|
|
void process() override;
|
|
|
|
void finalize() override;
|
|
|
|
// Returns true if an object step is done on all objects and there's at least one object.
|
|
|
|
bool is_step_done(SLAPrintObjectStep step) const;
|
|
|
|
// Returns true if the last step was finished with success.
|
|
|
|
bool finished() const override { return this->is_step_done(slaposSliceSupports) && this->Inherited::is_step_done(slapsRasterize); }
|
|
|
|
|
2019-03-15 11:16:05 +00:00
|
|
|
template<class Fmt = SLAminzZipper>
|
2019-03-14 18:07:16 +00:00
|
|
|
void export_raster(const std::string& fname) {
|
2019-03-27 17:37:50 +00:00
|
|
|
if(m_printer) m_printer->save<Fmt>(fname);
|
|
|
|
}
|
2019-03-14 18:07:16 +00:00
|
|
|
|
2019-03-27 17:37:50 +00:00
|
|
|
const PrintObjects& objects() const { return m_objects; }
|
|
|
|
|
|
|
|
const SLAPrintConfig& print_config() const { return m_print_config; }
|
|
|
|
const SLAPrinterConfig& printer_config() const { return m_printer_config; }
|
|
|
|
const SLAMaterialConfig& material_config() const { return m_material_config; }
|
|
|
|
const SLAPrintObjectConfig& default_object_config() const { return m_default_object_config; }
|
|
|
|
|
|
|
|
std::string output_filename() const override;
|
|
|
|
|
|
|
|
const SLAPrintStatistics& print_statistics() const { return m_print_statistics; }
|
|
|
|
|
|
|
|
std::string validate() const override;
|
|
|
|
|
2019-03-26 09:57:45 +00:00
|
|
|
// 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
|
2019-03-26 13:06:40 +00:00
|
|
|
class PrintLayer {
|
|
|
|
coord_t m_level;
|
2019-03-26 09:57:45 +00:00
|
|
|
|
|
|
|
// The collection of slice records for the current level.
|
2019-03-26 13:06:40 +00:00
|
|
|
std::vector<std::reference_wrapper<const SliceRecord>> m_slices;
|
2019-03-26 09:57:45 +00:00
|
|
|
|
2019-03-27 17:37:50 +00:00
|
|
|
std::vector<ClipperLib::Polygon> m_transformed_slices;
|
2019-03-26 17:51:27 +00:00
|
|
|
|
|
|
|
template<class Container> void transformed_slices(Container&& c) {
|
|
|
|
m_transformed_slices = std::forward<Container>(c);
|
|
|
|
}
|
|
|
|
|
2019-03-27 17:37:50 +00:00
|
|
|
friend void SLAPrint::process();
|
2019-03-26 17:51:27 +00:00
|
|
|
|
2019-03-26 13:06:40 +00:00
|
|
|
public:
|
|
|
|
|
|
|
|
explicit PrintLayer(coord_t lvl) : m_level(lvl) {}
|
2019-03-26 09:57:45 +00:00
|
|
|
|
|
|
|
// for being sorted in their container (see m_printer_input)
|
|
|
|
bool operator<(const PrintLayer& other) const {
|
2019-03-26 13:06:40 +00:00
|
|
|
return m_level < other.m_level;
|
2019-03-26 09:57:45 +00:00
|
|
|
}
|
2019-03-26 13:06:40 +00:00
|
|
|
|
2019-03-26 15:02:39 +00:00
|
|
|
void add(const SliceRecord& sr) { m_slices.emplace_back(sr); }
|
2019-03-26 13:06:40 +00:00
|
|
|
|
|
|
|
coord_t level() const { return m_level; }
|
|
|
|
|
2019-03-26 15:02:39 +00:00
|
|
|
auto slices() const -> const decltype (m_slices)& { return m_slices; }
|
2019-03-26 17:51:27 +00:00
|
|
|
|
2019-03-27 17:37:50 +00:00
|
|
|
const std::vector<ClipperLib::Polygon> & transformed_slices() const {
|
2019-03-26 17:51:27 +00:00
|
|
|
return m_transformed_slices;
|
|
|
|
}
|
2019-03-26 09:57:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// The aggregated and leveled print records from various objects.
|
|
|
|
// TODO: use this structure for the preview in the future.
|
|
|
|
const std::vector<PrintLayer>& print_layers() const { return m_printer_input; }
|
|
|
|
|
2018-11-08 19:18:40 +00:00
|
|
|
private:
|
2018-11-13 16:33:03 +00:00
|
|
|
using SLAPrinter = FilePrinter<FilePrinterFormat::SLA_PNGZIP>;
|
|
|
|
using SLAPrinterPtr = std::unique_ptr<SLAPrinter>;
|
|
|
|
|
2019-03-27 09:59:29 +00:00
|
|
|
// Implement same logic as in SLAPrintObject
|
|
|
|
bool invalidate_step(SLAPrintStep st);
|
|
|
|
|
2018-11-21 16:35:35 +00:00
|
|
|
// Invalidate steps based on a set of parameters changed.
|
|
|
|
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
|
|
|
|
2018-12-03 12:14:28 +00:00
|
|
|
SLAPrintConfig m_print_config;
|
2018-11-08 19:18:40 +00:00
|
|
|
SLAPrinterConfig m_printer_config;
|
|
|
|
SLAMaterialConfig m_material_config;
|
2018-11-21 16:35:35 +00:00
|
|
|
SLAPrintObjectConfig m_default_object_config;
|
|
|
|
|
2018-11-12 16:35:57 +00:00
|
|
|
PrintObjects m_objects;
|
2018-11-13 10:53:54 +00:00
|
|
|
std::vector<bool> m_stepmask;
|
2018-11-29 11:53:56 +00:00
|
|
|
|
2019-03-26 09:57:45 +00:00
|
|
|
// Ready-made data for rasterization.
|
|
|
|
std::vector<PrintLayer> m_printer_input;
|
2018-11-29 11:53:56 +00:00
|
|
|
|
|
|
|
// The printer itself
|
|
|
|
SLAPrinterPtr m_printer;
|
2018-11-08 19:18:40 +00:00
|
|
|
|
2019-02-12 15:34:42 +00:00
|
|
|
// Estimated print time, material consumed.
|
|
|
|
SLAPrintStatistics m_print_statistics;
|
|
|
|
|
2019-04-02 08:54:14 +00:00
|
|
|
class StatusReporter {
|
|
|
|
double m_st = 0;
|
|
|
|
public:
|
|
|
|
void operator() (SLAPrint& p, double st, const std::string& msg,
|
|
|
|
unsigned flags = SlicingStatus::DEFAULT);
|
|
|
|
double status() const { return m_st; }
|
|
|
|
} m_report_status;
|
|
|
|
|
|
|
|
|
2018-11-08 19:18:40 +00:00
|
|
|
friend SLAPrintObject;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace Slic3r
|
|
|
|
|
|
|
|
#endif /* slic3r_SLAPrint_hpp_ */
|