mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-27 10:41:15 -06:00
Merge remote-tracking branch 'origin/vb_3dscene_partial_update' into tm_sla_supports_backend
# Conflicts: # src/libslic3r/SLAPrint.cpp
This commit is contained in:
commit
ab94391fd0
19 changed files with 739 additions and 378 deletions
|
|
@ -1467,4 +1467,52 @@ Transform3d ModelInstance::get_matrix(bool dont_translate, bool dont_rotate, boo
|
|||
}
|
||||
#endif // !ENABLE_MODELVOLUME_TRANSFORM
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.
|
||||
void check_model_ids_validity(const Model &model)
|
||||
{
|
||||
std::set<ModelID> ids;
|
||||
auto check = [&ids](ModelID id) {
|
||||
assert(id.id > 0);
|
||||
assert(ids.find(id) == ids.end());
|
||||
ids.insert(id);
|
||||
};
|
||||
for (const ModelObject *model_object : model.objects) {
|
||||
check(model_object->id());
|
||||
for (const ModelVolume *model_volume : model_object->volumes)
|
||||
check(model_volume->id());
|
||||
for (const ModelInstance *model_instance : model_object->instances)
|
||||
check(model_instance->id());
|
||||
}
|
||||
for (const auto mm : model.materials)
|
||||
check(mm.second->id());
|
||||
}
|
||||
|
||||
void check_model_ids_equal(const Model &model1, const Model &model2)
|
||||
{
|
||||
// Verify whether the IDs of model1 and model match.
|
||||
assert(model1.objects.size() == model2.objects.size());
|
||||
for (size_t idx_model = 0; idx_model < model2.objects.size(); ++ idx_model) {
|
||||
const ModelObject &model_object1 = *model1.objects[idx_model];
|
||||
const ModelObject &model_object2 = * model2.objects[idx_model];
|
||||
assert(model_object1.id() == model_object2.id());
|
||||
assert(model_object1.volumes.size() == model_object2.volumes.size());
|
||||
assert(model_object1.instances.size() == model_object2.instances.size());
|
||||
for (size_t i = 0; i < model_object1.volumes.size(); ++ i)
|
||||
assert(model_object1.volumes[i]->id() == model_object2.volumes[i]->id());
|
||||
for (size_t i = 0; i < model_object1.instances.size(); ++ i)
|
||||
assert(model_object1.instances[i]->id() == model_object2.instances[i]->id());
|
||||
}
|
||||
assert(model1.materials.size() == model2.materials.size());
|
||||
{
|
||||
auto it1 = model1.materials.begin();
|
||||
auto it2 = model2.materials.begin();
|
||||
for (; it1 != model1.materials.end(); ++ it1, ++ it2) {
|
||||
assert(it1->first == it2->first); // compare keys
|
||||
assert(it1->second->id() == it2->second->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* _DEBUG */
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -652,6 +652,12 @@ private:
|
|||
#undef MODELBASE_DERIVED_COPY_MOVE_CLONE
|
||||
#undef MODELBASE_DERIVED_PRIVATE_COPY_MOVE
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.
|
||||
void check_model_ids_validity(const Model &model);
|
||||
void check_model_ids_equal(const Model &model1, const Model &model2);
|
||||
#endif /* _DEBUG */
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ template class PrintState<PrintObjectStep, posCount>;
|
|||
|
||||
void Print::clear()
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(this->cancel_mutex());
|
||||
tbb::mutex::scoped_lock lock(this->state_mutex());
|
||||
// The following call should stop background processing if it is running.
|
||||
this->invalidate_all_steps();
|
||||
for (PrintObject *object : m_objects)
|
||||
|
|
@ -43,7 +43,7 @@ void Print::reload_object(size_t /* idx */)
|
|||
{
|
||||
ModelObjectPtrs model_objects;
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(this->cancel_mutex());
|
||||
tbb::mutex::scoped_lock lock(this->state_mutex());
|
||||
// The following call should stop background processing if it is running.
|
||||
this->invalidate_all_steps();
|
||||
/* TODO: this method should check whether the per-object config and per-material configs
|
||||
|
|
@ -271,8 +271,9 @@ bool Print::is_step_done(PrintObjectStep step) const
|
|||
{
|
||||
if (m_objects.empty())
|
||||
return false;
|
||||
tbb::mutex::scoped_lock lock(this->state_mutex());
|
||||
for (const PrintObject *object : m_objects)
|
||||
if (!object->m_state.is_done(step))
|
||||
if (! object->m_state.is_done_unguarded(step))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -374,7 +375,7 @@ static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig
|
|||
// and have explicit instance positions.
|
||||
void Print::add_model_object(ModelObject* model_object, int idx)
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(this->cancel_mutex());
|
||||
tbb::mutex::scoped_lock lock(this->state_mutex());
|
||||
// Initialize a new print object and store it at the given position.
|
||||
PrintObject *object = new PrintObject(this, model_object);
|
||||
if (idx != -1) {
|
||||
|
|
@ -435,7 +436,7 @@ void Print::add_model_object(ModelObject* model_object, int idx)
|
|||
|
||||
bool Print::apply_config(DynamicPrintConfig config)
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(this->cancel_mutex());
|
||||
tbb::mutex::scoped_lock lock(this->state_mutex());
|
||||
|
||||
// we get a copy of the config object so we can modify it safely
|
||||
config.normalize();
|
||||
|
|
@ -734,54 +735,6 @@ static std::vector<PrintInstances> print_objects_from_model_object(const ModelOb
|
|||
return std::vector<PrintInstances>(trafos.begin(), trafos.end());
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.
|
||||
static inline void check_model_ids_validity(const Model &model)
|
||||
{
|
||||
std::set<ModelID> ids;
|
||||
auto check = [&ids](ModelID id) {
|
||||
assert(id.id > 0);
|
||||
assert(ids.find(id) == ids.end());
|
||||
ids.insert(id);
|
||||
};
|
||||
for (const ModelObject *model_object : model.objects) {
|
||||
check(model_object->id());
|
||||
for (const ModelVolume *model_volume : model_object->volumes)
|
||||
check(model_volume->id());
|
||||
for (const ModelInstance *model_instance : model_object->instances)
|
||||
check(model_instance->id());
|
||||
}
|
||||
for (const auto mm : model.materials)
|
||||
check(mm.second->id());
|
||||
}
|
||||
|
||||
static inline void check_model_ids_equal(const Model &model1, const Model &model2)
|
||||
{
|
||||
// Verify whether the IDs of model1 and model match.
|
||||
assert(model1.objects.size() == model2.objects.size());
|
||||
for (size_t idx_model = 0; idx_model < model2.objects.size(); ++ idx_model) {
|
||||
const ModelObject &model_object1 = *model1.objects[idx_model];
|
||||
const ModelObject &model_object2 = * model2.objects[idx_model];
|
||||
assert(model_object1.id() == model_object2.id());
|
||||
assert(model_object1.volumes.size() == model_object2.volumes.size());
|
||||
assert(model_object1.instances.size() == model_object2.instances.size());
|
||||
for (size_t i = 0; i < model_object1.volumes.size(); ++ i)
|
||||
assert(model_object1.volumes[i]->id() == model_object2.volumes[i]->id());
|
||||
for (size_t i = 0; i < model_object1.instances.size(); ++ i)
|
||||
assert(model_object1.instances[i]->id() == model_object2.instances[i]->id());
|
||||
}
|
||||
assert(model1.materials.size() == model2.materials.size());
|
||||
{
|
||||
auto it1 = model1.materials.begin();
|
||||
auto it2 = model2.materials.begin();
|
||||
for (; it1 != model1.materials.end(); ++ it1, ++ it2) {
|
||||
assert(it1->first == it2->first); // compare keys
|
||||
assert(it1->second->id() == it2->second->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* _DEBUG */
|
||||
|
||||
Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &config_in)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
|
|
@ -804,7 +757,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||
update_apply_status(false);
|
||||
|
||||
// Grab the lock for the Print / PrintObject milestones.
|
||||
tbb::mutex::scoped_lock lock(this->cancel_mutex());
|
||||
tbb::mutex::scoped_lock lock(this->state_mutex());
|
||||
|
||||
// The following call may stop the background processing.
|
||||
update_apply_status(this->invalidate_state_by_config_options(print_diff));
|
||||
|
|
@ -1579,16 +1532,12 @@ void Print::process()
|
|||
BOOST_LOG_TRIVIAL(info) << "Staring the slicing process.";
|
||||
for (PrintObject *obj : m_objects)
|
||||
obj->make_perimeters();
|
||||
this->throw_if_canceled();
|
||||
this->set_status(70, "Infilling layers");
|
||||
for (PrintObject *obj : m_objects)
|
||||
obj->infill();
|
||||
this->throw_if_canceled();
|
||||
for (PrintObject *obj : m_objects)
|
||||
obj->generate_support_material();
|
||||
this->throw_if_canceled();
|
||||
if (! this->is_step_done(psSkirt)) {
|
||||
this->set_started(psSkirt);
|
||||
if (this->set_started(psSkirt)) {
|
||||
m_skirt.clear();
|
||||
if (this->has_skirt()) {
|
||||
this->set_status(88, "Generating skirt");
|
||||
|
|
@ -1596,9 +1545,7 @@ void Print::process()
|
|||
}
|
||||
this->set_done(psSkirt);
|
||||
}
|
||||
this->throw_if_canceled();
|
||||
if (! this->is_step_done(psBrim)) {
|
||||
this->set_started(psBrim);
|
||||
if (this->set_started(psBrim)) {
|
||||
m_brim.clear();
|
||||
if (m_config.brim_width > 0) {
|
||||
this->set_status(88, "Generating brim");
|
||||
|
|
@ -1606,9 +1553,7 @@ void Print::process()
|
|||
}
|
||||
this->set_done(psBrim);
|
||||
}
|
||||
this->throw_if_canceled();
|
||||
if (! this->is_step_done(psWipeTower)) {
|
||||
this->set_started(psWipeTower);
|
||||
if (this->set_started(psWipeTower)) {
|
||||
m_wipe_tower_data.clear();
|
||||
if (this->has_wipe_tower()) {
|
||||
//this->set_status(95, "Generating wipe tower");
|
||||
|
|
@ -1625,9 +1570,6 @@ void Print::process()
|
|||
// It is up to the caller to show an error message.
|
||||
void Print::export_gcode(const std::string &path_template, GCodePreviewData *preview_data)
|
||||
{
|
||||
// prerequisites
|
||||
this->process();
|
||||
|
||||
// output everything to a G-code file
|
||||
// The following call may die if the output_filename_format template substitution fails.
|
||||
std::string path = this->output_filepath(path_template);
|
||||
|
|
|
|||
|
|
@ -97,8 +97,6 @@ public:
|
|||
|
||||
Vec3crd size; // XYZ in scaled coordinates
|
||||
|
||||
const ModelObject* model_object() const { return m_model_object; }
|
||||
ModelObject* model_object() { return m_model_object; }
|
||||
const PrintObjectConfig& config() const { return m_config; }
|
||||
const LayerPtrs& layers() const { return m_layers; }
|
||||
const SupportLayerPtrs& support_layers() const { return m_support_layers; }
|
||||
|
|
@ -197,7 +195,6 @@ private:
|
|||
void combine_infill();
|
||||
void _generate_support_material();
|
||||
|
||||
ModelObject *m_model_object;
|
||||
PrintObjectConfig m_config;
|
||||
// Translation in Z + Rotation + Scaling / Mirroring.
|
||||
Transform3d m_trafo = Transform3d::Identity();
|
||||
|
|
@ -381,7 +378,6 @@ private:
|
|||
// Declared here to have access to Model / ModelObject / ModelInstance
|
||||
static void model_volume_list_update_supports(ModelObject &model_object_dst, const ModelObject &model_object_src);
|
||||
|
||||
Model m_model;
|
||||
PrintConfig m_config;
|
||||
PrintObjectConfig m_default_object_config;
|
||||
PrintRegionConfig m_default_region_config;
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@
|
|||
namespace Slic3r
|
||||
{
|
||||
|
||||
tbb::mutex& PrintObjectBase::cancel_mutex(PrintBase *print)
|
||||
size_t PrintStateBase::g_last_timestamp = 0;
|
||||
|
||||
tbb::mutex& PrintObjectBase::state_mutex(PrintBase *print)
|
||||
{
|
||||
return print->cancel_mutex();
|
||||
return print->state_mutex();
|
||||
}
|
||||
|
||||
std::function<void()> PrintObjectBase::cancel_callback(PrintBase *print)
|
||||
|
|
@ -13,4 +15,9 @@ std::function<void()> PrintObjectBase::cancel_callback(PrintBase *print)
|
|||
return print->cancel_callback();
|
||||
}
|
||||
|
||||
void PrintObjectBase::throw_if_canceled(PrintBase *print)
|
||||
{
|
||||
print->throw_if_canceled();
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
|||
|
|
@ -2,13 +2,11 @@
|
|||
#define slic3r_PrintBase_hpp_
|
||||
|
||||
#include "libslic3r.h"
|
||||
#include <atomic>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
#include "tbb/atomic.h"
|
||||
// tbb/mutex.h includes Windows, which in turn defines min/max macros. Convince Windows.h to not define these min/max macros.
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
|
|
@ -25,68 +23,117 @@ public:
|
|||
const char* what() const throw() { return "Background processing has been canceled"; }
|
||||
};
|
||||
|
||||
// To be instantiated over PrintStep or PrintObjectStep enums.
|
||||
template <class StepType, size_t COUNT>
|
||||
class PrintState
|
||||
{
|
||||
class PrintStateBase {
|
||||
public:
|
||||
PrintState() { for (size_t i = 0; i < COUNT; ++ i) m_state[i].store(INVALID, std::memory_order_relaxed); }
|
||||
|
||||
enum State {
|
||||
INVALID,
|
||||
STARTED,
|
||||
DONE,
|
||||
};
|
||||
|
||||
// With full memory barrier.
|
||||
bool is_done(StepType step) const { return m_state[step] == DONE; }
|
||||
|
||||
// A new unique timestamp is being assigned to the step every time the step changes its state.
|
||||
struct StateWithTimeStamp
|
||||
{
|
||||
StateWithTimeStamp() : state(INVALID), timestamp(0) {}
|
||||
State state;
|
||||
size_t timestamp;
|
||||
};
|
||||
|
||||
protected:
|
||||
//FIXME last timestamp is shared between Print & SLAPrint,
|
||||
// and if multiple Print or SLAPrint instances are executed in parallel, modification of g_last_timestamp
|
||||
// is not synchronized!
|
||||
static size_t g_last_timestamp;
|
||||
};
|
||||
|
||||
// To be instantiated over PrintStep or PrintObjectStep enums.
|
||||
template <class StepType, size_t COUNT>
|
||||
class PrintState : public PrintStateBase
|
||||
{
|
||||
public:
|
||||
PrintState() {}
|
||||
|
||||
StateWithTimeStamp state_with_timestamp(StepType step, tbb::mutex &mtx) const {
|
||||
tbb::mutex::scoped_lock lock(mtx);
|
||||
StateWithTimeStamp state = m_state[step];
|
||||
return state;
|
||||
}
|
||||
|
||||
bool is_done(StepType step, tbb::mutex &mtx) const {
|
||||
return this->state_with_timestamp(step, mtx).state == DONE;
|
||||
}
|
||||
|
||||
StateWithTimeStamp state_with_timestamp_unguarded(StepType step) const {
|
||||
return m_state[step];
|
||||
}
|
||||
|
||||
bool is_done_unguarded(StepType step) const {
|
||||
return this->state_with_timestamp_unguarded(step).state == DONE;
|
||||
}
|
||||
|
||||
// Set the step as started. Block on mutex while the Print / PrintObject / PrintRegion objects are being
|
||||
// modified by the UI thread.
|
||||
// This is necessary to block until the Print::apply_config() updates its state, which may
|
||||
// influence the processing step being entered.
|
||||
void set_started(StepType step, tbb::mutex &mtx) {
|
||||
mtx.lock();
|
||||
m_state[step].store(STARTED, std::memory_order_relaxed);
|
||||
mtx.unlock();
|
||||
template<typename ThrowIfCanceled>
|
||||
bool set_started(StepType step, tbb::mutex &mtx, ThrowIfCanceled throw_if_canceled) {
|
||||
tbb::mutex::scoped_lock lock(mtx);
|
||||
// If canceled, throw before changing the step state.
|
||||
throw_if_canceled();
|
||||
if (m_state[step].state == DONE)
|
||||
return false;
|
||||
m_state[step].state = STARTED;
|
||||
m_state[step].timestamp = ++ g_last_timestamp;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set the step as done. Block on mutex while the Print / PrintObject / PrintRegion objects are being
|
||||
// modified by the UI thread.
|
||||
void set_done(StepType step, tbb::mutex &mtx) {
|
||||
mtx.lock();
|
||||
m_state[step].store(DONE, std::memory_order_relaxed);
|
||||
mtx.unlock();
|
||||
template<typename ThrowIfCanceled>
|
||||
void set_done(StepType step, tbb::mutex &mtx, ThrowIfCanceled throw_if_canceled) {
|
||||
tbb::mutex::scoped_lock lock(mtx);
|
||||
// If canceled, throw before changing the step state.
|
||||
throw_if_canceled();
|
||||
assert(m_state[step].state != DONE);
|
||||
m_state[step].state = DONE;
|
||||
m_state[step].timestamp = ++ g_last_timestamp;
|
||||
}
|
||||
|
||||
// Make the step invalid.
|
||||
// The provided mutex should be locked at this point, guarding access to m_state.
|
||||
// PrintBase::m_state_mutex should be locked at this point, guarding access to m_state.
|
||||
// In case the step has already been entered or finished, cancel the background
|
||||
// processing by calling the cancel callback.
|
||||
template<typename CancelationCallback>
|
||||
bool invalidate(StepType step, tbb::mutex &mtx, CancelationCallback cancel) {
|
||||
bool invalidated = m_state[step].load(std::memory_order_relaxed) != INVALID;
|
||||
bool invalidate(StepType step, CancelationCallback cancel) {
|
||||
bool invalidated = m_state[step].state != INVALID;
|
||||
if (invalidated) {
|
||||
#if 0
|
||||
if (mtx.state != mtx.HELD) {
|
||||
printf("Not held!\n");
|
||||
}
|
||||
#endif
|
||||
m_state[step].state = INVALID;
|
||||
m_state[step].timestamp = ++ g_last_timestamp;
|
||||
// Raise the mutex, so that the following cancel() callback could cancel
|
||||
// the background processing.
|
||||
mtx.unlock();
|
||||
// Internally the cancel() callback shall unlock the PrintBase::m_status_mutex to let
|
||||
// the working thread to proceed.
|
||||
cancel();
|
||||
m_state[step] = INVALID;
|
||||
mtx.lock();
|
||||
}
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
template<typename CancelationCallback, typename StepTypeIterator>
|
||||
bool invalidate_multiple(StepTypeIterator step_begin, StepTypeIterator step_end, tbb::mutex &mtx, CancelationCallback cancel) {
|
||||
bool invalidate_multiple(StepTypeIterator step_begin, StepTypeIterator step_end, CancelationCallback cancel) {
|
||||
bool invalidated = false;
|
||||
for (StepTypeIterator it = step_begin; ! invalidated && it != step_end; ++ it)
|
||||
invalidated = m_state[*it].load(std::memory_order_relaxed) != INVALID;
|
||||
for (StepTypeIterator it = step_begin; it != step_end; ++ it) {
|
||||
StateWithTimeStamp &state = m_state[*it];
|
||||
if (state.state != INVALID) {
|
||||
invalidated = true;
|
||||
state.state = INVALID;
|
||||
state.timestamp = ++ g_last_timestamp;
|
||||
}
|
||||
}
|
||||
if (invalidated) {
|
||||
#if 0
|
||||
if (mtx.state != mtx.HELD) {
|
||||
|
|
@ -95,50 +142,56 @@ public:
|
|||
#endif
|
||||
// Raise the mutex, so that the following cancel() callback could cancel
|
||||
// the background processing.
|
||||
mtx.unlock();
|
||||
// Internally the cancel() callback shall unlock the PrintBase::m_status_mutex to let
|
||||
// the working thread to proceed.
|
||||
cancel();
|
||||
for (StepTypeIterator it = step_begin; it != step_end; ++ it)
|
||||
m_state[*it] = INVALID;
|
||||
mtx.lock();
|
||||
}
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
// Make all steps invalid.
|
||||
// The provided mutex should be locked at this point, guarding access to m_state.
|
||||
// PrintBase::m_state_mutex should be locked at this point, guarding access to m_state.
|
||||
// In case any step has already been entered or finished, cancel the background
|
||||
// processing by calling the cancel callback.
|
||||
template<typename CancelationCallback>
|
||||
bool invalidate_all(tbb::mutex &mtx, CancelationCallback cancel) {
|
||||
bool invalidate_all(CancelationCallback cancel) {
|
||||
bool invalidated = false;
|
||||
for (size_t i = 0; i < COUNT; ++ i)
|
||||
if (m_state[i].load(std::memory_order_relaxed) != INVALID) {
|
||||
for (size_t i = 0; i < COUNT; ++ i) {
|
||||
StateWithTimeStamp &state = m_state[i];
|
||||
if (state.state != INVALID) {
|
||||
invalidated = true;
|
||||
break;
|
||||
state.state = INVALID;
|
||||
state.timestamp = ++ g_last_timestamp;
|
||||
}
|
||||
if (invalidated) {
|
||||
mtx.unlock();
|
||||
cancel();
|
||||
for (size_t i = 0; i < COUNT; ++ i)
|
||||
m_state[i].store(INVALID, std::memory_order_relaxed);
|
||||
mtx.lock();
|
||||
}
|
||||
if (invalidated)
|
||||
cancel();
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<State> m_state[COUNT];
|
||||
StateWithTimeStamp m_state[COUNT];
|
||||
};
|
||||
|
||||
class PrintBase;
|
||||
|
||||
class PrintObjectBase
|
||||
{
|
||||
public:
|
||||
const ModelObject* model_object() const { return m_model_object; }
|
||||
ModelObject* model_object() { return m_model_object; }
|
||||
|
||||
protected:
|
||||
PrintObjectBase(ModelObject *model_object) : m_model_object(model_object) {}
|
||||
virtual ~PrintObjectBase() {}
|
||||
// Declared here to allow access from PrintBase through friendship.
|
||||
static tbb::mutex& cancel_mutex(PrintBase *print);
|
||||
static tbb::mutex& state_mutex(PrintBase *print);
|
||||
static std::function<void()> cancel_callback(PrintBase *print);
|
||||
// If the background processing stop was requested, throw CanceledException.
|
||||
// To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly.
|
||||
static void throw_if_canceled(PrintBase *print);
|
||||
|
||||
ModelObject *m_model_object;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -179,6 +232,7 @@ public:
|
|||
APPLY_STATUS_INVALIDATED,
|
||||
};
|
||||
virtual ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) = 0;
|
||||
const Model& model() const { return m_model; }
|
||||
|
||||
virtual void process() = 0;
|
||||
|
||||
|
|
@ -220,8 +274,9 @@ public:
|
|||
|
||||
protected:
|
||||
friend class PrintObjectBase;
|
||||
friend class BackgroundSlicingProcess;
|
||||
|
||||
tbb::mutex& cancel_mutex() { return m_cancel_mutex; }
|
||||
tbb::mutex& state_mutex() const { return m_state_mutex; }
|
||||
std::function<void()> cancel_callback() { return m_cancel_callback; }
|
||||
void call_cancell_callback() { m_cancel_callback(); }
|
||||
|
||||
|
|
@ -229,6 +284,8 @@ protected:
|
|||
// To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly.
|
||||
void throw_if_canceled() const { if (m_cancel_status) throw CanceledException(); }
|
||||
|
||||
Model m_model;
|
||||
|
||||
private:
|
||||
tbb::atomic<CancelStatus> m_cancel_status;
|
||||
// Callback to be evoked regularly to update state of the UI thread.
|
||||
|
|
@ -240,27 +297,28 @@ private:
|
|||
// Mutex used for synchronization of the worker thread with the UI thread:
|
||||
// The mutex will be used to guard the worker thread against entering a stage
|
||||
// while the data influencing the stage is modified.
|
||||
mutable tbb::mutex m_cancel_mutex;
|
||||
mutable tbb::mutex m_state_mutex;
|
||||
};
|
||||
|
||||
template<typename PrintStepEnum, const size_t COUNT>
|
||||
class PrintBaseWithState : public PrintBase
|
||||
{
|
||||
public:
|
||||
bool is_step_done(PrintStepEnum step) const { return m_state.is_done(step); }
|
||||
bool is_step_done(PrintStepEnum step) const { return m_state.is_done(step, this->state_mutex()); }
|
||||
PrintStateBase::StateWithTimeStamp step_state_with_timestamp(PrintStepEnum step) const { return m_state.state_with_timestamp(step, this->state_mutex()); }
|
||||
|
||||
protected:
|
||||
void set_started(PrintStepEnum step) { m_state.set_started(step, this->cancel_mutex()); throw_if_canceled(); }
|
||||
void set_done(PrintStepEnum step) { m_state.set_done(step, this->cancel_mutex()); throw_if_canceled(); }
|
||||
bool set_started(PrintStepEnum step) { return m_state.set_started(step, this->state_mutex(), [this](){ this->throw_if_canceled(); }); }
|
||||
void set_done(PrintStepEnum step) { m_state.set_done(step, this->state_mutex(), [this](){ this->throw_if_canceled(); }); }
|
||||
bool invalidate_step(PrintStepEnum step)
|
||||
{ return m_state.invalidate(step, this->cancel_mutex(), this->cancel_callback()); }
|
||||
{ return m_state.invalidate(step, this->cancel_callback()); }
|
||||
template<typename StepTypeIterator>
|
||||
bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end)
|
||||
{ return m_state.invalidate_multiple(step_begin, step_end, this->cancel_mutex(), this->cancel_callback()); }
|
||||
{ return m_state.invalidate_multiple(step_begin, step_end, this->cancel_callback()); }
|
||||
bool invalidate_steps(std::initializer_list<PrintStepEnum> il)
|
||||
{ return m_state.invalidate_multiple(il.begin(), il.end(), this->cancel_mutex(), this->cancel_callback()); }
|
||||
{ return m_state.invalidate_multiple(il.begin(), il.end(), this->cancel_callback()); }
|
||||
bool invalidate_all_steps()
|
||||
{ return m_state.invalidate_all(this->cancel_mutex(), this->cancel_callback()); }
|
||||
{ return m_state.invalidate_all(this->cancel_callback()); }
|
||||
|
||||
private:
|
||||
PrintState<PrintStepEnum, COUNT> m_state;
|
||||
|
|
@ -273,22 +331,27 @@ public:
|
|||
PrintType* print() { return m_print; }
|
||||
const PrintType* print() const { return m_print; }
|
||||
|
||||
bool is_step_done(PrintObjectStepEnum step) const { return m_state.is_done(step); }
|
||||
typedef PrintState<PrintObjectStepEnum, COUNT> PrintObjectState;
|
||||
bool is_step_done(PrintObjectStepEnum step) const { return m_state.is_done(step, PrintObjectBase::state_mutex(m_print)); }
|
||||
PrintStateBase::StateWithTimeStamp step_state_with_timestamp(PrintObjectStepEnum step) const { return m_state.state_with_timestamp(step, PrintObjectBase::state_mutex(m_print)); }
|
||||
|
||||
protected:
|
||||
PrintObjectBaseWithState(PrintType *print) : m_print(print) {}
|
||||
PrintObjectBaseWithState(PrintType *print, ModelObject *model_object) : PrintObjectBase(model_object), m_print(print) {}
|
||||
|
||||
void set_started(PrintObjectStepEnum step) { m_state.set_started(step, PrintObjectBase::cancel_mutex(m_print)); }
|
||||
void set_done(PrintObjectStepEnum step) { m_state.set_done(step, PrintObjectBase::cancel_mutex(m_print)); }
|
||||
bool set_started(PrintObjectStepEnum step)
|
||||
{ return m_state.set_started(step, PrintObjectBase::state_mutex(m_print), [this](){ PrintObjectBase::throw_if_canceled(this->m_print); }); }
|
||||
void set_done(PrintObjectStepEnum step)
|
||||
{ m_state.set_done(step, PrintObjectBase::state_mutex(m_print), [this](){ PrintObjectBase::throw_if_canceled(this->m_print); }); }
|
||||
|
||||
bool invalidate_step(PrintObjectStepEnum step)
|
||||
{ return m_state.invalidate(step, PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); }
|
||||
{ return m_state.invalidate(step, PrintObjectBase::cancel_callback(m_print)); }
|
||||
template<typename StepTypeIterator>
|
||||
bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end)
|
||||
{ return m_state.invalidate_multiple(step_begin, step_end, PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); }
|
||||
{ return m_state.invalidate_multiple(step_begin, step_end, PrintObjectBase::cancel_callback(m_print)); }
|
||||
bool invalidate_steps(std::initializer_list<PrintObjectStepEnum> il)
|
||||
{ return m_state.invalidate_multiple(il.begin(), il.end(), PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); }
|
||||
bool invalidate_all_steps() { return m_state.invalidate_all(PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); }
|
||||
{ return m_state.invalidate_multiple(il.begin(), il.end(), PrintObjectBase::cancel_callback(m_print)); }
|
||||
bool invalidate_all_steps()
|
||||
{ return m_state.invalidate_all(PrintObjectBase::cancel_callback(m_print)); }
|
||||
|
||||
protected:
|
||||
friend PrintType;
|
||||
|
|
|
|||
|
|
@ -35,9 +35,8 @@
|
|||
namespace Slic3r {
|
||||
|
||||
PrintObject::PrintObject(Print* print, ModelObject* model_object) :
|
||||
PrintObjectBaseWithState(print),
|
||||
PrintObjectBaseWithState(print, model_object),
|
||||
typed_slices(false),
|
||||
m_model_object(model_object),
|
||||
size(Vec3crd::Zero()),
|
||||
layer_height_profile_valid(false)
|
||||
{
|
||||
|
|
@ -103,9 +102,8 @@ bool PrintObject::set_copies(const Points &points)
|
|||
// this should be idempotent
|
||||
void PrintObject::slice()
|
||||
{
|
||||
if (this->is_step_done(posSlice))
|
||||
if (! this->set_started(posSlice))
|
||||
return;
|
||||
this->set_started(posSlice);
|
||||
m_print->set_status(10, "Processing triangulated mesh");
|
||||
this->_slice();
|
||||
m_print->throw_if_canceled();
|
||||
|
|
@ -131,10 +129,9 @@ void PrintObject::make_perimeters()
|
|||
// prerequisites
|
||||
this->slice();
|
||||
|
||||
if (this->is_step_done(posPerimeters))
|
||||
if (! this->set_started(posPerimeters))
|
||||
return;
|
||||
|
||||
this->set_started(posPerimeters);
|
||||
m_print->set_status(20, "Generating perimeters");
|
||||
BOOST_LOG_TRIVIAL(info) << "Generating perimeters...";
|
||||
|
||||
|
|
@ -242,10 +239,9 @@ void PrintObject::make_perimeters()
|
|||
|
||||
void PrintObject::prepare_infill()
|
||||
{
|
||||
if (this->is_step_done(posPrepareInfill))
|
||||
if (! this->set_started(posPrepareInfill))
|
||||
return;
|
||||
|
||||
this->set_started(posPrepareInfill);
|
||||
m_print->set_status(30, "Preparing infill");
|
||||
|
||||
// This will assign a type (top/bottom/internal) to $layerm->slices.
|
||||
|
|
@ -361,8 +357,7 @@ void PrintObject::infill()
|
|||
// prerequisites
|
||||
this->prepare_infill();
|
||||
|
||||
if (! this->is_step_done(posInfill)) {
|
||||
this->set_started(posInfill);
|
||||
if (this->set_started(posInfill)) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start";
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<size_t>(0, m_layers.size()),
|
||||
|
|
@ -384,8 +379,7 @@ void PrintObject::infill()
|
|||
|
||||
void PrintObject::generate_support_material()
|
||||
{
|
||||
if (! this->is_step_done(posSupportMaterial)) {
|
||||
this->set_started(posSupportMaterial);
|
||||
if (this->set_started(posSupportMaterial)) {
|
||||
this->clear_support_layers();
|
||||
if ((m_config.support_material || m_config.raft_layers > 0) && m_layers.size() > 1) {
|
||||
m_print->set_status(85, "Generating support material");
|
||||
|
|
@ -1706,9 +1700,8 @@ void PrintObject::_simplify_slices(double distance)
|
|||
|
||||
void PrintObject::_make_perimeters()
|
||||
{
|
||||
if (this->is_step_done(posPerimeters))
|
||||
if (! this->set_started(posPerimeters))
|
||||
return;
|
||||
this->set_started(posPerimeters);
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Generating perimeters...";
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ const std::array<std::string, slapsCount> PRINT_STEP_LABELS =
|
|||
|
||||
void SLAPrint::clear()
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(this->cancel_mutex());
|
||||
tbb::mutex::scoped_lock lock(this->state_mutex());
|
||||
// The following call should stop background processing if it is running.
|
||||
this->invalidate_all_steps();
|
||||
|
||||
|
|
@ -78,8 +78,8 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model,
|
|||
// return APPLY_STATUS_UNCHANGED;
|
||||
|
||||
// Grab the lock for the Print / PrintObject milestones.
|
||||
tbb::mutex::scoped_lock lock(this->cancel_mutex());
|
||||
if(m_objects.empty() && model.objects.empty())
|
||||
tbb::mutex::scoped_lock lock(this->state_mutex());
|
||||
if (m_objects.empty() && model.objects.empty() && m_model.objects.empty())
|
||||
return APPLY_STATUS_UNCHANGED;
|
||||
|
||||
// Temporary: just to have to correct layer height for the rasterization
|
||||
|
|
@ -430,8 +430,7 @@ void SLAPrint::process()
|
|||
}
|
||||
|
||||
SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object):
|
||||
Inherited(print),
|
||||
m_model_object(model_object),
|
||||
Inherited(print, model_object),
|
||||
m_stepmask(slaposCount, true)
|
||||
{
|
||||
}
|
||||
|
|
@ -456,6 +455,32 @@ const std::vector<ExPolygons> &SLAPrintObject::get_model_slices() const
|
|||
return m_model_slices;
|
||||
}
|
||||
|
||||
bool SLAPrintObject::has_mesh(SLAPrintObjectStep step) const
|
||||
{
|
||||
switch (step) {
|
||||
case slaposSupportTree:
|
||||
// return m_supportdata && m_supportdata->support_tree_ptr && ! m_supportdata->support_tree_ptr->get().merged_mesh().empty();
|
||||
return ! this->support_mesh().empty();
|
||||
case slaposBasePool:
|
||||
// return m_supportdata && m_supportdata->support_tree_ptr && ! m_supportdata->support_tree_ptr->get_pad().empty();
|
||||
return ! this->pad_mesh().empty();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TriangleMesh SLAPrintObject::get_mesh(SLAPrintObjectStep step) const
|
||||
{
|
||||
switch (step) {
|
||||
case slaposSupportTree:
|
||||
return this->support_mesh();
|
||||
case slaposBasePool:
|
||||
return this->pad_mesh();
|
||||
default:
|
||||
return TriangleMesh();
|
||||
}
|
||||
}
|
||||
|
||||
TriangleMesh SLAPrintObject::support_mesh() const
|
||||
{
|
||||
TriangleMesh trm;
|
||||
|
|
|
|||
|
|
@ -35,8 +35,6 @@ private: // Prevents erroneous use by other classes.
|
|||
using Inherited = _SLAPrintObjectBase;
|
||||
|
||||
public:
|
||||
const ModelObject* model_object() const { return m_model_object; }
|
||||
ModelObject* model_object() { return m_model_object; }
|
||||
const Transform3d& trafo() const { return m_trafo; }
|
||||
|
||||
struct Instance {
|
||||
|
|
@ -50,6 +48,9 @@ public:
|
|||
};
|
||||
const std::vector<Instance>& instances() const { return m_instances; }
|
||||
|
||||
bool has_mesh(SLAPrintObjectStep step) const;
|
||||
TriangleMesh get_mesh(SLAPrintObjectStep step) const;
|
||||
|
||||
// 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.
|
||||
TriangleMesh support_mesh() const;
|
||||
|
|
@ -92,8 +93,6 @@ protected:
|
|||
bool invalidate_step(SLAPrintObjectStep step);
|
||||
|
||||
private:
|
||||
// Points to the instance owned by a Model stored at the parent SLAPrint instance.
|
||||
ModelObject *m_model_object;
|
||||
// Object specific configuration, pulled from the configuration layer.
|
||||
SLAPrintObjectConfig m_config;
|
||||
// Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
|
||||
|
|
@ -156,7 +155,6 @@ private:
|
|||
using SLAPrinter = FilePrinter<FilePrinterFormat::SLA_PNGZIP>;
|
||||
using SLAPrinterPtr = std::unique_ptr<SLAPrinter>;
|
||||
|
||||
Model m_model;
|
||||
SLAPrinterConfig m_printer_config;
|
||||
SLAMaterialConfig m_material_config;
|
||||
PrintObjects m_objects;
|
||||
|
|
|
|||
|
|
@ -521,6 +521,7 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d& t) const
|
|||
|
||||
if (stl.stats.shared_vertices > 0)
|
||||
{
|
||||
assert(stl.v_shared != nullptr);
|
||||
stl_vertex* vertex_ptr = stl.v_shared;
|
||||
for (int i = 0; i < stl.stats.shared_vertices; ++i)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ public:
|
|||
void reset_repair_stats();
|
||||
bool needed_repair() const;
|
||||
size_t facets_count() const { return this->stl.stats.number_of_facets; }
|
||||
bool empty() const { return this->facets_count() == 0; }
|
||||
|
||||
// Returns true, if there are two and more connected patches in the mesh.
|
||||
// Returns false, if one or zero connected patch is in the mesh.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue