mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-10 16:27:54 -06:00
WIP: Reconstruction of background processing.
This commit is contained in:
parent
f33713e060
commit
bded28f888
17 changed files with 273 additions and 229 deletions
|
@ -242,6 +242,14 @@ BoundingBoxf3 Model::bounding_box() const
|
||||||
return bb;
|
return bb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int Model::update_print_volume_state(const BoundingBoxf3 &print_volume)
|
||||||
|
{
|
||||||
|
unsigned int num_printable = 0;
|
||||||
|
for (ModelObject *model_object : this->objects)
|
||||||
|
num_printable += model_object->check_instances_print_volume_state(print_volume);
|
||||||
|
return num_printable;
|
||||||
|
}
|
||||||
|
|
||||||
void Model::center_instances_around_point(const Vec2d &point)
|
void Model::center_instances_around_point(const Vec2d &point)
|
||||||
{
|
{
|
||||||
BoundingBoxf3 bb;
|
BoundingBoxf3 bb;
|
||||||
|
@ -875,26 +883,32 @@ void ModelObject::repair()
|
||||||
v->mesh.repair();
|
v->mesh.repair();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by Print::validate() from the UI thread.
|
unsigned int ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume)
|
||||||
void ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume)
|
|
||||||
{
|
{
|
||||||
|
unsigned int num_printable = 0;
|
||||||
|
enum {
|
||||||
|
INSIDE = 1,
|
||||||
|
OUTSIDE = 2
|
||||||
|
};
|
||||||
|
for (ModelInstance *model_instance : this->instances) {
|
||||||
|
unsigned int inside_outside = 0;
|
||||||
for (const ModelVolume *vol : this->volumes)
|
for (const ModelVolume *vol : this->volumes)
|
||||||
{
|
if (vol->is_model_part()) {
|
||||||
if (vol->is_model_part())
|
BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(model_instance->world_matrix());
|
||||||
{
|
|
||||||
for (ModelInstance* inst : this->instances)
|
|
||||||
{
|
|
||||||
BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(inst->world_matrix());
|
|
||||||
|
|
||||||
if (print_volume.contains(bb))
|
if (print_volume.contains(bb))
|
||||||
inst->print_volume_state = ModelInstance::PVS_Inside;
|
inside_outside |= INSIDE;
|
||||||
else if (print_volume.intersects(bb))
|
else if (print_volume.intersects(bb))
|
||||||
inst->print_volume_state = ModelInstance::PVS_Partly_Outside;
|
inside_outside |= INSIDE | OUTSIDE;
|
||||||
else
|
else
|
||||||
inst->print_volume_state = ModelInstance::PVS_Fully_Outside;
|
inside_outside |= OUTSIDE;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
model_instance->print_volume_state =
|
||||||
|
(inside_outside == (INSIDE | OUTSIDE)) ? ModelInstance::PVS_Partly_Outside :
|
||||||
|
(inside_outside == INSIDE) ? ModelInstance::PVS_Inside : ModelInstance::PVS_Fully_Outside;
|
||||||
|
if (inside_outside == INSIDE)
|
||||||
|
++ num_printable;
|
||||||
}
|
}
|
||||||
|
return num_printable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelObject::print_info() const
|
void ModelObject::print_info() const
|
||||||
|
|
|
@ -156,7 +156,7 @@ public:
|
||||||
void repair();
|
void repair();
|
||||||
|
|
||||||
// Called by Print::validate() from the UI thread.
|
// Called by Print::validate() from the UI thread.
|
||||||
void check_instances_print_volume_state(const BoundingBoxf3& print_volume);
|
unsigned int check_instances_print_volume_state(const BoundingBoxf3& print_volume);
|
||||||
|
|
||||||
// Print object statistics to console.
|
// Print object statistics to console.
|
||||||
void print_info() const;
|
void print_info() const;
|
||||||
|
@ -411,6 +411,9 @@ public:
|
||||||
bool add_default_instances();
|
bool add_default_instances();
|
||||||
// Returns approximate axis aligned bounding box of this model
|
// Returns approximate axis aligned bounding box of this model
|
||||||
BoundingBoxf3 bounding_box() const;
|
BoundingBoxf3 bounding_box() const;
|
||||||
|
// Set the print_volume_state of PrintObject::instances,
|
||||||
|
// return total number of printable objects.
|
||||||
|
unsigned int update_print_volume_state(const BoundingBoxf3 &print_volume);
|
||||||
void center_instances_around_point(const Vec2d &point);
|
void center_instances_around_point(const Vec2d &point);
|
||||||
void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); }
|
void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); }
|
||||||
TriangleMesh mesh() const;
|
TriangleMesh mesh() const;
|
||||||
|
|
|
@ -852,7 +852,11 @@ bool Print::apply(const Model &model, const DynamicPrintConfig &config_in)
|
||||||
bool modifiers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::PARAMETER_MODIFIER);
|
bool modifiers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::PARAMETER_MODIFIER);
|
||||||
bool support_blockers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::SUPPORT_BLOCKER);
|
bool support_blockers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::SUPPORT_BLOCKER);
|
||||||
bool support_enforcers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::SUPPORT_ENFORCER);
|
bool support_enforcers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::SUPPORT_ENFORCER);
|
||||||
if (model_parts_differ || modifiers_differ) {
|
if (model_parts_differ || modifiers_differ ||
|
||||||
|
model_object.origin_translation != model_object_new.origin_translation ||
|
||||||
|
model_object.layer_height_ranges != model_object_new.layer_height_ranges ||
|
||||||
|
model_object.layer_height_profile != model_object_new.layer_height_profile ||
|
||||||
|
model_object.layer_height_profile_valid != model_object_new.layer_height_profile_valid) {
|
||||||
// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
|
// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
|
||||||
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
||||||
for (auto it = range.first; it != range.second; ++ it) {
|
for (auto it = range.first; it != range.second; ++ it) {
|
||||||
|
@ -889,6 +893,9 @@ bool Print::apply(const Model &model, const DynamicPrintConfig &config_in)
|
||||||
it->print_object->config_apply_only(new_config, diff, true);
|
it->print_object->config_apply_only(new_config, diff, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
model_object.name = model_object_new.name;
|
||||||
|
model_object.input_file = model_object_new.input_file;
|
||||||
|
model_object.instances = model_object_new.instances;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -936,10 +943,9 @@ bool Print::apply(const Model &model, const DynamicPrintConfig &config_in)
|
||||||
print_objects_new.emplace_back(print_object);
|
print_objects_new.emplace_back(print_object);
|
||||||
print_object_status.emplace(PrintObjectStatus(print_object, PrintObjectStatus::New));
|
print_object_status.emplace(PrintObjectStatus(print_object, PrintObjectStatus::New));
|
||||||
} else if ((*it_old)->print_object->copies() != new_instances.copies) {
|
} else if ((*it_old)->print_object->copies() != new_instances.copies) {
|
||||||
// The PrintObject already exists and the copies differ. The only step currently sensitive to the order is the G-code generator.
|
// The PrintObject already exists and the copies differ.
|
||||||
// Stop it.
|
|
||||||
this->invalidate_step(psGCodeExport);
|
|
||||||
(*it_old)->print_object->set_copies(new_instances.copies);
|
(*it_old)->print_object->set_copies(new_instances.copies);
|
||||||
|
print_objects_new.emplace_back((*it_old)->print_object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -958,7 +964,7 @@ bool Print::apply(const Model &model, const DynamicPrintConfig &config_in)
|
||||||
int idx_region = 0;
|
int idx_region = 0;
|
||||||
for (const auto &volumes : print_object->region_volumes) {
|
for (const auto &volumes : print_object->region_volumes) {
|
||||||
if (! volumes.empty())
|
if (! volumes.empty())
|
||||||
++ m_regions[idx_region];
|
++ m_regions[idx_region]->m_refcnt;
|
||||||
++ idx_region;
|
++ idx_region;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1110,23 +1116,7 @@ bool Print::has_skirt() const
|
||||||
|
|
||||||
std::string Print::validate() const
|
std::string Print::validate() const
|
||||||
{
|
{
|
||||||
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(m_config.bed_shape.values));
|
if (m_objects.empty())
|
||||||
BoundingBoxf3 print_volume(unscale(bed_box_2D.min(0), bed_box_2D.min(1), 0.0), unscale(bed_box_2D.max(0), bed_box_2D.max(1), scale_(m_config.max_print_height)));
|
|
||||||
// Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced.
|
|
||||||
print_volume.min(2) = -1e10;
|
|
||||||
unsigned int printable_count = 0;
|
|
||||||
{
|
|
||||||
// Lock due to the po->reload_model_instances()
|
|
||||||
tbb::mutex::scoped_lock lock(m_mutex);
|
|
||||||
for (PrintObject *po : m_objects) {
|
|
||||||
po->model_object()->check_instances_print_volume_state(print_volume);
|
|
||||||
po->reload_model_instances();
|
|
||||||
if (po->is_printable())
|
|
||||||
++ printable_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (printable_count == 0)
|
|
||||||
return L("All objects are outside of the print volume.");
|
return L("All objects are outside of the print volume.");
|
||||||
|
|
||||||
if (m_config.complete_objects) {
|
if (m_config.complete_objects) {
|
||||||
|
|
|
@ -96,6 +96,7 @@ public:
|
||||||
#endif
|
#endif
|
||||||
mtx.unlock();
|
mtx.unlock();
|
||||||
cancel();
|
cancel();
|
||||||
|
m_state[step] = INVALID;
|
||||||
mtx.lock();
|
mtx.lock();
|
||||||
}
|
}
|
||||||
return invalidated;
|
return invalidated;
|
||||||
|
|
|
@ -87,23 +87,25 @@ bool PrintObject::delete_last_copy()
|
||||||
|
|
||||||
bool PrintObject::set_copies(const Points &points)
|
bool PrintObject::set_copies(const Points &points)
|
||||||
{
|
{
|
||||||
bool copies_num_changed = m_copies.size() != points.size();
|
// Order copies with a nearest-neighbor search.
|
||||||
|
std::vector<Point> copies;
|
||||||
// order copies with a nearest neighbor search and translate them by _copies_shift
|
{
|
||||||
m_copies.clear();
|
|
||||||
m_copies.reserve(points.size());
|
|
||||||
|
|
||||||
// order copies with a nearest-neighbor search
|
|
||||||
std::vector<Points::size_type> ordered_copies;
|
std::vector<Points::size_type> ordered_copies;
|
||||||
Slic3r::Geometry::chained_path(points, ordered_copies);
|
Slic3r::Geometry::chained_path(points, ordered_copies);
|
||||||
|
copies.reserve(ordered_copies.size());
|
||||||
for (size_t point_idx : ordered_copies)
|
for (size_t point_idx : ordered_copies)
|
||||||
m_copies.push_back(points[point_idx] + m_copies_shift);
|
copies.emplace_back(points[point_idx] + m_copies_shift);
|
||||||
|
}
|
||||||
bool invalidated = m_print->invalidate_step(psSkirt);
|
// Invalidate and set copies.
|
||||||
|
bool invalidated = false;
|
||||||
|
if (copies != m_copies) {
|
||||||
|
invalidated = m_print->invalidate_step(psSkirt);
|
||||||
invalidated |= m_print->invalidate_step(psBrim);
|
invalidated |= m_print->invalidate_step(psBrim);
|
||||||
if (copies_num_changed)
|
if (copies.size() != m_copies.size())
|
||||||
invalidated |= m_print->invalidate_step(psWipeTower);
|
invalidated |= m_print->invalidate_step(psWipeTower);
|
||||||
|
invalidated |= m_print->invalidate_step(psGCodeExport);
|
||||||
|
m_copies = copies;
|
||||||
|
}
|
||||||
return invalidated;
|
return invalidated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -858,12 +858,12 @@ void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLin
|
||||||
// find layer extents
|
// find layer extents
|
||||||
std::vector<float>::const_iterator min_layer, max_layer;
|
std::vector<float>::const_iterator min_layer, max_layer;
|
||||||
min_layer = std::lower_bound(z.begin(), z.end(), min_z); // first layer whose slice_z is >= min_z
|
min_layer = std::lower_bound(z.begin(), z.end(), min_z); // first layer whose slice_z is >= min_z
|
||||||
max_layer = std::upper_bound(z.begin() + (min_layer - z.begin()), z.end(), max_z) - 1; // last layer whose slice_z is <= max_z
|
max_layer = std::upper_bound(z.begin() + (min_layer - z.begin()), z.end(), max_z); // first layer, whose slice_z is > max_z
|
||||||
#ifdef SLIC3R_TRIANGLEMESH_DEBUG
|
#ifdef SLIC3R_TRIANGLEMESH_DEBUG
|
||||||
printf("layers: min = %d, max = %d\n", (int)(min_layer - z.begin()), (int)(max_layer - z.begin()));
|
printf("layers: min = %d, max = %d\n", (int)(min_layer - z.begin()), (int)(max_layer - z.begin()) - 1);
|
||||||
#endif /* SLIC3R_TRIANGLEMESH_DEBUG */
|
#endif /* SLIC3R_TRIANGLEMESH_DEBUG */
|
||||||
|
|
||||||
for (std::vector<float>::const_iterator it = min_layer; it != max_layer + 1; ++it) {
|
for (std::vector<float>::const_iterator it = min_layer; it != max_layer; ++it) {
|
||||||
std::vector<float>::size_type layer_idx = it - z.begin();
|
std::vector<float>::size_type layer_idx = it - z.begin();
|
||||||
IntersectionLine il;
|
IntersectionLine il;
|
||||||
if (this->slice_facet(*it / SCALING_FACTOR, facet, facet_idx, min_z, max_z, &il) == TriangleMeshSlicer::Slicing) {
|
if (this->slice_facet(*it / SCALING_FACTOR, facet, facet_idx, min_z, max_z, &il) == TriangleMeshSlicer::Slicing) {
|
||||||
|
|
|
@ -57,11 +57,19 @@ void BackgroundSlicingProcess::thread_proc()
|
||||||
if (! m_print->canceled()) {
|
if (! m_print->canceled()) {
|
||||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_sliced_id));
|
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_sliced_id));
|
||||||
m_print->export_gcode(m_temp_output_path, m_gcode_preview_data);
|
m_print->export_gcode(m_temp_output_path, m_gcode_preview_data);
|
||||||
if (! m_print->canceled() && ! m_output_path.empty()) {
|
if (! m_print->canceled() && ! this->is_step_done(bspsGCodeFinalize)) {
|
||||||
if (copy_file(m_temp_output_path, m_output_path) != 0)
|
this->set_step_started(bspsGCodeFinalize);
|
||||||
|
if (! m_export_path.empty()) {
|
||||||
|
//FIXME localize the messages
|
||||||
|
if (copy_file(m_temp_output_path, m_export_path) != 0)
|
||||||
throw std::runtime_error("Copying of the temporary G-code to the output G-code failed");
|
throw std::runtime_error("Copying of the temporary G-code to the output G-code failed");
|
||||||
m_print->set_status(95, "Running post-processing scripts");
|
m_print->set_status(95, "Running post-processing scripts");
|
||||||
run_post_process_scripts(m_output_path, m_print->config());
|
run_post_process_scripts(m_export_path, m_print->config());
|
||||||
|
m_print->set_status(100, "G-code file exported to " + m_export_path);
|
||||||
|
} else {
|
||||||
|
m_print->set_status(100, "Slicing complete");
|
||||||
|
}
|
||||||
|
this->set_step_done(bspsGCodeFinalize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (CanceledException &ex) {
|
} catch (CanceledException &ex) {
|
||||||
|
@ -133,7 +141,7 @@ bool BackgroundSlicingProcess::stop()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lck(m_mutex);
|
std::unique_lock<std::mutex> lck(m_mutex);
|
||||||
if (m_state == STATE_INITIAL) {
|
if (m_state == STATE_INITIAL) {
|
||||||
this->m_output_path.clear();
|
// this->m_export_path.clear();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// assert(this->running());
|
// assert(this->running());
|
||||||
|
@ -147,7 +155,7 @@ bool BackgroundSlicingProcess::stop()
|
||||||
// In the "Finished" or "Canceled" state. Reset the state to "Idle".
|
// In the "Finished" or "Canceled" state. Reset the state to "Idle".
|
||||||
m_state = STATE_IDLE;
|
m_state = STATE_IDLE;
|
||||||
}
|
}
|
||||||
this->m_output_path.clear();
|
// this->m_export_path.clear();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,4 +177,53 @@ bool BackgroundSlicingProcess::apply(const Model &model, const DynamicPrintConfi
|
||||||
return invalidated;
|
return invalidated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the output path of the G-code.
|
||||||
|
void BackgroundSlicingProcess::schedule_export(const std::string &path)
|
||||||
|
{
|
||||||
|
assert(m_export_path.empty());
|
||||||
|
if (! m_export_path.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Guard against entering the export step before changing the export path.
|
||||||
|
tbb::mutex::scoped_lock lock(m_step_state_mutex);
|
||||||
|
this->invalidate_step(bspsGCodeFinalize);
|
||||||
|
m_export_path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackgroundSlicingProcess::reset_export()
|
||||||
|
{
|
||||||
|
assert(! this->running());
|
||||||
|
if (! this->running()) {
|
||||||
|
m_export_path.clear();
|
||||||
|
// invalidate_step expects the mutex to be locked.
|
||||||
|
tbb::mutex::scoped_lock lock(m_step_state_mutex);
|
||||||
|
this->invalidate_step(bspsGCodeFinalize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackgroundSlicingProcess::set_step_started(BackgroundSlicingProcessStep step)
|
||||||
|
{
|
||||||
|
m_step_state.set_started(step, m_step_state_mutex);
|
||||||
|
if (m_print->canceled())
|
||||||
|
throw CanceledException();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackgroundSlicingProcess::set_step_done(BackgroundSlicingProcessStep step)
|
||||||
|
{
|
||||||
|
m_step_state.set_done(step, m_step_state_mutex);
|
||||||
|
if (m_print->canceled())
|
||||||
|
throw CanceledException();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BackgroundSlicingProcess::invalidate_step(BackgroundSlicingProcessStep step)
|
||||||
|
{
|
||||||
|
bool invalidated = m_step_state.invalidate(step, m_step_state_mutex, [this](){ this->stop(); });
|
||||||
|
return invalidated;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BackgroundSlicingProcess::invalidate_all_steps()
|
||||||
|
{
|
||||||
|
return m_step_state.invalidate_all(m_step_state_mutex, [this](){ this->stop(); });
|
||||||
|
}
|
||||||
|
|
||||||
}; // namespace Slic3r
|
}; // namespace Slic3r
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#include "Print.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class DynamicPrintConfig;
|
class DynamicPrintConfig;
|
||||||
|
@ -13,6 +15,11 @@ class GCodePreviewData;
|
||||||
class Model;
|
class Model;
|
||||||
class Print;
|
class Print;
|
||||||
|
|
||||||
|
// Print step IDs for keeping track of the print state.
|
||||||
|
enum BackgroundSlicingProcessStep {
|
||||||
|
bspsGCodeFinalize, bspsCount,
|
||||||
|
};
|
||||||
|
|
||||||
// Support for the GUI background processing (Slicing and G-code generation).
|
// Support for the GUI background processing (Slicing and G-code generation).
|
||||||
// As of now this class is not declared in Slic3r::GUI due to the Perl bindings limits.
|
// As of now this class is not declared in Slic3r::GUI due to the Perl bindings limits.
|
||||||
class BackgroundSlicingProcess
|
class BackgroundSlicingProcess
|
||||||
|
@ -32,8 +39,6 @@ public:
|
||||||
// The wxCommandEvent is sent to the UI thread asynchronously without waiting for the event to be processed.
|
// The wxCommandEvent is sent to the UI thread asynchronously without waiting for the event to be processed.
|
||||||
void set_finished_event(int event_id) { m_event_finished_id = event_id; }
|
void set_finished_event(int event_id) { m_event_finished_id = event_id; }
|
||||||
|
|
||||||
// Set the output path of the G-code.
|
|
||||||
void set_output_path(const std::string &path) { m_output_path = path; }
|
|
||||||
// Start the background processing. Returns false if the background processing was already running.
|
// Start the background processing. Returns false if the background processing was already running.
|
||||||
bool start();
|
bool start();
|
||||||
// Cancel the background processing. Returns false if the background processing was not running.
|
// Cancel the background processing. Returns false if the background processing was not running.
|
||||||
|
@ -46,6 +51,13 @@ public:
|
||||||
// Apply config over the print. Returns false, if the new config values caused any of the already
|
// Apply config over the print. Returns false, if the new config values caused any of the already
|
||||||
// processed steps to be invalidated, therefore the task will need to be restarted.
|
// processed steps to be invalidated, therefore the task will need to be restarted.
|
||||||
bool apply(const Model &model, const DynamicPrintConfig &config);
|
bool apply(const Model &model, const DynamicPrintConfig &config);
|
||||||
|
// Set the export path of the G-code.
|
||||||
|
// Once the path is set, the G-code
|
||||||
|
void schedule_export(const std::string &path);
|
||||||
|
// Clear m_export_path.
|
||||||
|
void reset_export();
|
||||||
|
// Once the G-code export is scheduled, the apply() methods will do nothing.
|
||||||
|
bool is_export_scheduled() const { return ! m_export_path.empty(); }
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
// m_thread is not running yet, or it did not reach the STATE_IDLE yet (it does not wait on the condition yet).
|
// m_thread is not running yet, or it did not reach the STATE_IDLE yet (it does not wait on the condition yet).
|
||||||
|
@ -74,8 +86,11 @@ private:
|
||||||
Print *m_print = nullptr;
|
Print *m_print = nullptr;
|
||||||
// Data structure, to which the G-code export writes its annotations.
|
// Data structure, to which the G-code export writes its annotations.
|
||||||
GCodePreviewData *m_gcode_preview_data = nullptr;
|
GCodePreviewData *m_gcode_preview_data = nullptr;
|
||||||
|
// Temporary G-code, there is one defined for the BackgroundSlicingProcess, differentiated from the other processes by a process ID.
|
||||||
std::string m_temp_output_path;
|
std::string m_temp_output_path;
|
||||||
std::string m_output_path;
|
// Output path provided by the user. The output path may be set even if the slicing is running,
|
||||||
|
// but once set, it cannot be re-set.
|
||||||
|
std::string m_export_path;
|
||||||
// Thread, on which the background processing is executed. The thread will always be present
|
// Thread, on which the background processing is executed. The thread will always be present
|
||||||
// and ready to execute the slicing process.
|
// and ready to execute the slicing process.
|
||||||
std::thread m_thread;
|
std::thread m_thread;
|
||||||
|
@ -84,6 +99,14 @@ private:
|
||||||
std::condition_variable m_condition;
|
std::condition_variable m_condition;
|
||||||
State m_state = STATE_INITIAL;
|
State m_state = STATE_INITIAL;
|
||||||
|
|
||||||
|
PrintState<BackgroundSlicingProcessStep, bspsCount> m_step_state;
|
||||||
|
mutable tbb::mutex m_step_state_mutex;
|
||||||
|
void set_step_started(BackgroundSlicingProcessStep step);
|
||||||
|
void set_step_done(BackgroundSlicingProcessStep step);
|
||||||
|
bool is_step_done(BackgroundSlicingProcessStep step) const { return m_step_state.is_done(step); }
|
||||||
|
bool invalidate_step(BackgroundSlicingProcessStep step);
|
||||||
|
bool invalidate_all_steps();
|
||||||
|
|
||||||
// wxWidgets command ID to be sent to the platter to inform that the slicing is finished, and the G-code export will continue.
|
// wxWidgets command ID to be sent to the platter to inform that the slicing is finished, and the G-code export will continue.
|
||||||
int m_event_sliced_id = 0;
|
int m_event_sliced_id = 0;
|
||||||
// wxWidgets command ID to be sent to the platter to inform that the task finished.
|
// wxWidgets command ID to be sent to the platter to inform that the task finished.
|
||||||
|
|
|
@ -5145,7 +5145,7 @@ void GLCanvas3D::_render_layer_editing_overlay() const
|
||||||
#else
|
#else
|
||||||
int object_idx = int(volume->select_group_id / 1000000);
|
int object_idx = int(volume->select_group_id / 1000000);
|
||||||
#endif // ENABLE_EXTENDED_SELECTION
|
#endif // ENABLE_EXTENDED_SELECTION
|
||||||
if ((int)m_print->objects().size() < object_idx)
|
if ((int)m_print->objects().size() <= object_idx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const PrintObject* print_object = m_print->get_object(object_idx);
|
const PrintObject* print_object = m_print->get_object(object_idx);
|
||||||
|
|
|
@ -261,18 +261,6 @@ void warning_catcher(wxWindow* parent, const wxString& message){
|
||||||
msg.ShowModal();
|
msg.ShowModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign a Lambda to the print object to emit a wxWidgets Command with the provided ID
|
|
||||||
// to deliver a progress status message.
|
|
||||||
void set_print_callback_event(Print *print, int id)
|
|
||||||
{
|
|
||||||
print->set_status_callback([id](int percent, const std::string &message){
|
|
||||||
wxCommandEvent event(id);
|
|
||||||
event.SetInt(percent);
|
|
||||||
event.SetString(message);
|
|
||||||
wxQueueEvent(wxGetApp().mainframe, event.Clone());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string items, bool initial_value)
|
void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string items, bool initial_value)
|
||||||
{
|
{
|
||||||
if (comboCtrl == nullptr)
|
if (comboCtrl == nullptr)
|
||||||
|
|
|
@ -80,10 +80,6 @@ void show_error_id(int id, const std::string& message); // For Perl
|
||||||
void show_info(wxWindow* parent, const wxString& message, const wxString& title);
|
void show_info(wxWindow* parent, const wxString& message, const wxString& title);
|
||||||
void warning_catcher(wxWindow* parent, const wxString& message);
|
void warning_catcher(wxWindow* parent, const wxString& message);
|
||||||
|
|
||||||
// Assign a Lambda to the print object to emit a wxWidgets Command with the provided ID
|
|
||||||
// to deliver a progress status message.
|
|
||||||
void set_print_callback_event(Print *print, int id);
|
|
||||||
|
|
||||||
// Creates a wxCheckListBoxComboPopup inside the given wxComboCtrl, filled with the given text and items.
|
// Creates a wxCheckListBoxComboPopup inside the given wxComboCtrl, filled with the given text and items.
|
||||||
// Items are all initialized to the given value.
|
// Items are all initialized to the given value.
|
||||||
// Items must be separated by '|', for example "Item1|Item2|Item3", and so on.
|
// Items must be separated by '|', for example "Item1|Item2|Item3", and so on.
|
||||||
|
|
|
@ -63,10 +63,10 @@ namespace Slic3r {
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
|
|
||||||
|
wxDEFINE_EVENT(EVT_PROGRESS_BAR, wxCommandEvent);
|
||||||
wxDEFINE_EVENT(EVT_SLICING_COMPLETED, wxCommandEvent);
|
wxDEFINE_EVENT(EVT_SLICING_COMPLETED, wxCommandEvent);
|
||||||
wxDEFINE_EVENT(EVT_PROCESS_COMPLETED, wxCommandEvent);
|
wxDEFINE_EVENT(EVT_PROCESS_COMPLETED, wxCommandEvent);
|
||||||
|
|
||||||
|
|
||||||
// Sidebar widgets
|
// Sidebar widgets
|
||||||
|
|
||||||
// struct InfoBox : public wxStaticBox
|
// struct InfoBox : public wxStaticBox
|
||||||
|
@ -741,9 +741,6 @@ struct Plater::priv
|
||||||
std::vector<PlaterObject> objects;
|
std::vector<PlaterObject> objects;
|
||||||
#endif // !ENABLE_EXTENDED_SELECTION
|
#endif // !ENABLE_EXTENDED_SELECTION
|
||||||
|
|
||||||
fs::path export_gcode_output_file;
|
|
||||||
fs::path send_gcode_file;
|
|
||||||
|
|
||||||
// GUI elements
|
// GUI elements
|
||||||
wxNotebook *notebook;
|
wxNotebook *notebook;
|
||||||
Sidebar *sidebar;
|
Sidebar *sidebar;
|
||||||
|
@ -809,7 +806,7 @@ struct Plater::priv
|
||||||
|
|
||||||
void on_notebook_changed(wxBookCtrlEvent&);
|
void on_notebook_changed(wxBookCtrlEvent&);
|
||||||
void on_select_preset(wxCommandEvent&);
|
void on_select_preset(wxCommandEvent&);
|
||||||
void on_progress_event();
|
void on_progress_event(wxCommandEvent&);
|
||||||
void on_update_print_preview(wxCommandEvent&);
|
void on_update_print_preview(wxCommandEvent&);
|
||||||
void on_process_completed(wxCommandEvent&);
|
void on_process_completed(wxCommandEvent&);
|
||||||
void on_layer_editing_toggled(bool enable);
|
void on_layer_editing_toggled(bool enable);
|
||||||
|
@ -880,6 +877,14 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) :
|
||||||
background_process.set_gcode_preview_data(&gcode_preview_data);
|
background_process.set_gcode_preview_data(&gcode_preview_data);
|
||||||
background_process.set_sliced_event(EVT_SLICING_COMPLETED);
|
background_process.set_sliced_event(EVT_SLICING_COMPLETED);
|
||||||
background_process.set_finished_event(EVT_PROCESS_COMPLETED);
|
background_process.set_finished_event(EVT_PROCESS_COMPLETED);
|
||||||
|
// Register progress callback from the Print class to the Platter.
|
||||||
|
print.set_status_callback([this](int percent, const std::string &message){
|
||||||
|
wxCommandEvent event(EVT_PROGRESS_BAR);
|
||||||
|
event.SetInt(percent);
|
||||||
|
event.SetString(message);
|
||||||
|
wxQueueEvent(this->q, event.Clone());
|
||||||
|
});
|
||||||
|
this->q->Bind(EVT_PROGRESS_BAR, &priv::on_progress_event, this);
|
||||||
|
|
||||||
_3DScene::add_canvas(canvas3D);
|
_3DScene::add_canvas(canvas3D);
|
||||||
_3DScene::allow_multisample(canvas3D, GLCanvas3DManager::can_multisample());
|
_3DScene::allow_multisample(canvas3D, GLCanvas3DManager::can_multisample());
|
||||||
|
@ -902,7 +907,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) :
|
||||||
_3DScene::enable_shader(canvas3D, true);
|
_3DScene::enable_shader(canvas3D, true);
|
||||||
_3DScene::enable_force_zoom_to_bed(canvas3D, true);
|
_3DScene::enable_force_zoom_to_bed(canvas3D, true);
|
||||||
|
|
||||||
background_process_timer.Bind(wxEVT_TIMER, [this](wxTimerEvent &evt){ this->async_apply_config(); }, 0);
|
this->background_process_timer.SetOwner(this->q, 0);
|
||||||
|
this->q->Bind(wxEVT_TIMER, [this](wxTimerEvent &evt){ this->async_apply_config(); });
|
||||||
|
|
||||||
auto *bed_shape = config->opt<ConfigOptionPoints>("bed_shape");
|
auto *bed_shape = config->opt<ConfigOptionPoints>("bed_shape");
|
||||||
_3DScene::set_bed_shape(canvas3D, bed_shape->values);
|
_3DScene::set_bed_shape(canvas3D, bed_shape->values);
|
||||||
|
@ -938,7 +944,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) :
|
||||||
canvas3D->Bind(EVT_GLCANVAS_ARRANGE, [this](SimpleEvent&) { arrange(); });
|
canvas3D->Bind(EVT_GLCANVAS_ARRANGE, [this](SimpleEvent&) { arrange(); });
|
||||||
#if !ENABLE_EXTENDED_SELECTION
|
#if !ENABLE_EXTENDED_SELECTION
|
||||||
canvas3D->Bind(EVT_GLCANVAS_ROTATE_OBJECT, [this](Event<int> &evt) { /*TODO: call rotate */ });
|
canvas3D->Bind(EVT_GLCANVAS_ROTATE_OBJECT, [this](Event<int> &evt) { /*TODO: call rotate */ });
|
||||||
canvas3D->Bind(EVT_GLCANVAS_SCALE_UNIFORMLY, [this](SimpleEvent&) { scale(); });
|
canvas3D->Bind(EVT_GLCANVAS_SCALE_UNIFORMLY, [this](SimpleEvent&) { this->scale(); });
|
||||||
#endif // !ENABLE_EXTENDED_SELECTION
|
#endif // !ENABLE_EXTENDED_SELECTION
|
||||||
canvas3D->Bind(EVT_GLCANVAS_INCREASE_INSTANCES, [q](Event<int> &evt) { evt.data == 1 ? q->increase_instances() : q->decrease_instances(); });
|
canvas3D->Bind(EVT_GLCANVAS_INCREASE_INSTANCES, [q](Event<int> &evt) { evt.data == 1 ? q->increase_instances() : q->decrease_instances(); });
|
||||||
canvas3D->Bind(EVT_GLCANVAS_INSTANCE_MOVED, [this](SimpleEvent&) { update(); });
|
canvas3D->Bind(EVT_GLCANVAS_INSTANCE_MOVED, [this](SimpleEvent&) { update(); });
|
||||||
|
@ -998,7 +1004,7 @@ void Plater::priv::update(bool force_autocenter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop_background_process(); // TODO
|
// stop_background_process(); // TODO
|
||||||
print.reload_model_instances();
|
// print.reload_model_instances();
|
||||||
|
|
||||||
#if !ENABLE_EXTENDED_SELECTION
|
#if !ENABLE_EXTENDED_SELECTION
|
||||||
const auto selections = collect_selections();
|
const auto selections = collect_selections();
|
||||||
|
@ -1008,7 +1014,7 @@ void Plater::priv::update(bool force_autocenter)
|
||||||
preview->reset_gcode_preview_data();
|
preview->reset_gcode_preview_data();
|
||||||
preview->reload_print();
|
preview->reload_print();
|
||||||
|
|
||||||
schedule_background_process();
|
this->schedule_background_process();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::select_view(const std::string& direction)
|
void Plater::priv::select_view(const std::string& direction)
|
||||||
|
@ -1257,7 +1263,7 @@ std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType
|
||||||
case FT_GCODE:
|
case FT_GCODE:
|
||||||
wildcard = file_wildcards[file_type];
|
wildcard = file_wildcards[file_type];
|
||||||
break;
|
break;
|
||||||
|
// FT_GCODE
|
||||||
default:
|
default:
|
||||||
wildcard = file_wildcards[FT_MODEL];
|
wildcard = file_wildcards[FT_MODEL];
|
||||||
break;
|
break;
|
||||||
|
@ -1290,7 +1296,6 @@ std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType
|
||||||
|
|
||||||
fs::path path(dlg->GetPath());
|
fs::path path(dlg->GetPath());
|
||||||
wxGetApp().app_config->update_last_output_dir(path.parent_path().string());
|
wxGetApp().app_config->update_last_output_dir(path.parent_path().string());
|
||||||
export_gcode_output_file = path;
|
|
||||||
|
|
||||||
return dlg;
|
return dlg;
|
||||||
}
|
}
|
||||||
|
@ -1446,7 +1451,7 @@ void Plater::priv::object_list_changed()
|
||||||
_3DScene::enable_toolbar_item(canvas3D, "arrange", have_objects);
|
_3DScene::enable_toolbar_item(canvas3D, "arrange", have_objects);
|
||||||
#endif // ENABLE_EXTENDED_SELECTION
|
#endif // ENABLE_EXTENDED_SELECTION
|
||||||
|
|
||||||
const bool export_in_progress = !(export_gcode_output_file.empty() && send_gcode_file.empty());
|
const bool export_in_progress = this->background_process.is_export_scheduled(); // || ! send_gcode_file.empty());
|
||||||
// XXX: is this right?
|
// XXX: is this right?
|
||||||
const bool model_fits = _3DScene::check_volumes_outside_state(canvas3D, config) == ModelInstance::PVS_Inside;
|
const bool model_fits = _3DScene::check_volumes_outside_state(canvas3D, config) == ModelInstance::PVS_Inside;
|
||||||
|
|
||||||
|
@ -1478,7 +1483,7 @@ void Plater::priv::remove(size_t obj_idx)
|
||||||
objects.erase(objects.begin() + obj_idx);
|
objects.erase(objects.begin() + obj_idx);
|
||||||
#endif // !ENABLE_EXTENDED_SELECTION
|
#endif // !ENABLE_EXTENDED_SELECTION
|
||||||
model.delete_object(obj_idx);
|
model.delete_object(obj_idx);
|
||||||
print.delete_object(obj_idx);
|
// print.delete_object(obj_idx);
|
||||||
// Delete object from Sidebar list
|
// Delete object from Sidebar list
|
||||||
sidebar->obj_list()->delete_object_from_list(obj_idx);
|
sidebar->obj_list()->delete_object_from_list(obj_idx);
|
||||||
|
|
||||||
|
@ -1504,7 +1509,7 @@ void Plater::priv::reset()
|
||||||
objects.clear();
|
objects.clear();
|
||||||
#endif // !ENABLE_EXTENDED_SELECTION
|
#endif // !ENABLE_EXTENDED_SELECTION
|
||||||
model.clear_objects();
|
model.clear_objects();
|
||||||
print.clear_objects();
|
// print.clear_objects();
|
||||||
|
|
||||||
// Delete all objects from list on c++ side
|
// Delete all objects from list on c++ side
|
||||||
sidebar->obj_list()->delete_all_objects_from_list();
|
sidebar->obj_list()->delete_all_objects_from_list();
|
||||||
|
@ -1609,7 +1614,6 @@ void Plater::priv::split_object()
|
||||||
if (new_objects.size() == 1)
|
if (new_objects.size() == 1)
|
||||||
{
|
{
|
||||||
Slic3r::GUI::warning_catcher(q, _(L("The selected object couldn't be split because it contains only one part.")));
|
Slic3r::GUI::warning_catcher(q, _(L("The selected object couldn't be split because it contains only one part.")));
|
||||||
// $self->schedule_background_process;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1635,9 +1639,16 @@ void Plater::priv::schedule_background_process()
|
||||||
|
|
||||||
void Plater::priv::async_apply_config()
|
void Plater::priv::async_apply_config()
|
||||||
{
|
{
|
||||||
|
DynamicPrintConfig config = wxGetApp().preset_bundle->full_config();
|
||||||
|
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(config.opt<ConfigOptionPoints>("bed_shape")->values));
|
||||||
|
BoundingBoxf3 print_volume(unscale(bed_box_2D.min(0), bed_box_2D.min(1), 0.0), unscale(bed_box_2D.max(0), bed_box_2D.max(1), scale_(config.opt_float("max_print_height"))));
|
||||||
|
// Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced.
|
||||||
|
print_volume.min(2) = -1e10;
|
||||||
|
this->q->model().update_print_volume_state(print_volume);
|
||||||
|
|
||||||
// Apply new config to the possibly running background task.
|
// Apply new config to the possibly running background task.
|
||||||
bool was_running = this->background_process.running();
|
bool was_running = this->background_process.running();
|
||||||
bool invalidated = this->background_process.apply(this->q->model(), wxGetApp().preset_bundle->full_config());
|
bool invalidated = this->background_process.apply(this->q->model(), std::move(config));
|
||||||
// Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile.
|
// Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile.
|
||||||
if (Slic3r::_3DScene::is_layers_editing_enabled(this->canvas3D))
|
if (Slic3r::_3DScene::is_layers_editing_enabled(this->canvas3D))
|
||||||
this->canvas3D->Refresh();
|
this->canvas3D->Refresh();
|
||||||
|
@ -1669,20 +1680,20 @@ void Plater::priv::async_apply_config()
|
||||||
|
|
||||||
void Plater::priv::start_background_process()
|
void Plater::priv::start_background_process()
|
||||||
{
|
{
|
||||||
// return if ! @{$self->{objects}} || $self->{background_slicing_process}->running;
|
if (this->background_process.running())
|
||||||
// Don't start process thread if config is not valid.
|
|
||||||
std::string err = wxGetApp().preset_bundle->full_config().validate();
|
|
||||||
if (err.empty())
|
|
||||||
err = this->q->print().validate();
|
|
||||||
if (! err.empty()) {
|
|
||||||
// $self->statusbar->SetStatusText(err);
|
|
||||||
return;
|
return;
|
||||||
}
|
// return if ! @{$self->{objects}} || $self->{background_slicing_process}->running;
|
||||||
|
// Don't start process thread if Print is not valid.
|
||||||
|
std::string err = this->q->print().validate();
|
||||||
|
if (! err.empty()) {
|
||||||
|
this->statusbar()->set_status_text(err);
|
||||||
|
} else {
|
||||||
// Copy the names of active presets into the placeholder parser.
|
// Copy the names of active presets into the placeholder parser.
|
||||||
wxGetApp().preset_bundle->export_selections(this->q->print().placeholder_parser());
|
wxGetApp().preset_bundle->export_selections(this->q->print().placeholder_parser());
|
||||||
// Start the background process.
|
// Start the background process.
|
||||||
this->background_process.start();
|
this->background_process.start();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Plater::priv::stop_background_process()
|
void Plater::priv::stop_background_process()
|
||||||
{
|
{
|
||||||
|
@ -1795,9 +1806,10 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
|
||||||
wxGetApp().plater()->on_config_change(wxGetApp().preset_bundle->full_config());
|
wxGetApp().plater()->on_config_change(wxGetApp().preset_bundle->full_config());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::on_progress_event()
|
void Plater::priv::on_progress_event(wxCommandEvent &evt)
|
||||||
{
|
{
|
||||||
// TODO
|
this->statusbar()->set_progress(evt.GetInt());
|
||||||
|
this->statusbar()->set_status_text(evt.GetString() + wxString::FromUTF8("…"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::on_update_print_preview(wxCommandEvent &)
|
void Plater::priv::on_update_print_preview(wxCommandEvent &)
|
||||||
|
@ -1813,62 +1825,25 @@ void Plater::priv::on_update_print_preview(wxCommandEvent &)
|
||||||
#endif // !ENABLE_EXTENDED_SELECTION
|
#endif // !ENABLE_EXTENDED_SELECTION
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::on_process_completed(wxCommandEvent &)
|
void Plater::priv::on_process_completed(wxCommandEvent &evt)
|
||||||
{
|
{
|
||||||
// Stop the background task, wait until the thread goes into the "Idle" state.
|
// Stop the background task, wait until the thread goes into the "Idle" state.
|
||||||
// At this point of time the thread should be either finished or canceled,
|
// At this point of time the thread should be either finished or canceled,
|
||||||
// so the following call just confirms, that the produced data were consumed.
|
// so the following call just confirms, that the produced data were consumed.
|
||||||
this->background_process.stop();
|
this->background_process.stop();
|
||||||
//$self->statusbar->ResetCancelCallback();
|
this->statusbar()->reset_cancel_callback();
|
||||||
//$self->statusbar->StopBusy;
|
this->statusbar()->stop_busy();
|
||||||
//$self->statusbar->SetStatusText("");
|
|
||||||
|
|
||||||
/*
|
bool success = evt.GetInt();
|
||||||
my $message;
|
// Reset the "export G-code path" name, so that the automatic background processing will be enabled again.
|
||||||
my $send_gcode = 0;
|
this->background_process.reset_export();
|
||||||
my $do_print = 0;
|
if (! success) {
|
||||||
# print "Process completed, message: ", $message, "\n";
|
wxString message = evt.GetString();
|
||||||
if (defined($result)) {
|
if (message.IsEmpty())
|
||||||
$message = L("Export failed");
|
message = _(L("Export failed"));
|
||||||
} else {
|
this->statusbar()->set_status_text(message);
|
||||||
# G-code file exported successfully.
|
|
||||||
if ($self->{print_file}) {
|
|
||||||
$message = L("File added to print queue");
|
|
||||||
$do_print = 1;
|
|
||||||
} elsif ($self->{send_gcode_file}) {
|
|
||||||
$message = L("Sending G-code file to the Printer Host ...");
|
|
||||||
$send_gcode = 1;
|
|
||||||
} elsif (defined $self->{export_gcode_output_file}) {
|
|
||||||
$message = L("G-code file exported to ") . $self->{export_gcode_output_file};
|
|
||||||
} else {
|
|
||||||
$message = L("Slicing complete");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
$self->{export_gcode_output_file} = undef;
|
|
||||||
wxTheApp->notify($message);
|
|
||||||
|
|
||||||
$self->do_print if $do_print;
|
|
||||||
|
|
||||||
# Send $self->{send_gcode_file} to OctoPrint.
|
|
||||||
if ($send_gcode) {
|
|
||||||
my $host = Slic3r::PrintHost::get_print_host($self->{config});
|
|
||||||
if ($host->send_gcode($self->{send_gcode_file})) {
|
|
||||||
$message = L("Upload to host finished.");
|
|
||||||
} else {
|
|
||||||
$message = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// As of now, the BackgroundProcessing thread posts status bar update messages to a queue on the MainFrame.pm,
|
|
||||||
// but the "Processing finished" message is posted to this window.
|
|
||||||
// Delay the following status bar update, so it will be called later than what is received by MainFrame.pm.
|
|
||||||
//wxTheApp->CallAfter(sub {
|
|
||||||
// $self->statusbar->SetStatusText($message);
|
|
||||||
// });
|
|
||||||
|
|
||||||
//$self->{print_file} = undef;
|
|
||||||
//$self->{send_gcode_file} = undef;
|
|
||||||
//$self->print_info_box_show(1);
|
//$self->print_info_box_show(1);
|
||||||
|
|
||||||
// this updates buttons status
|
// this updates buttons status
|
||||||
|
@ -2209,9 +2184,9 @@ void Plater::increase_instances(size_t num)
|
||||||
Vec3d offset_vec = model_instance->get_offset() + Vec3d(offset, offset, 0.0);
|
Vec3d offset_vec = model_instance->get_offset() + Vec3d(offset, offset, 0.0);
|
||||||
model_object->add_instance(offset_vec, model_instance->get_scaling_factor(), model_instance->get_rotation());
|
model_object->add_instance(offset_vec, model_instance->get_scaling_factor(), model_instance->get_rotation());
|
||||||
#if ENABLE_EXTENDED_SELECTION
|
#if ENABLE_EXTENDED_SELECTION
|
||||||
p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec));
|
// p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec));
|
||||||
#else
|
#else
|
||||||
p->print.get_object(*obj_idx)->add_copy(Slic3r::to_2d(offset_vec));
|
// p->print.get_object(*obj_idx)->add_copy(Slic3r::to_2d(offset_vec));
|
||||||
#endif // ENABLE_EXTENDED_SELECTION
|
#endif // ENABLE_EXTENDED_SELECTION
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2254,9 +2229,9 @@ void Plater::decrease_instances(size_t num)
|
||||||
for (size_t i = 0; i < num; i++) {
|
for (size_t i = 0; i < num; i++) {
|
||||||
model_object->delete_last_instance();
|
model_object->delete_last_instance();
|
||||||
#if ENABLE_EXTENDED_SELECTION
|
#if ENABLE_EXTENDED_SELECTION
|
||||||
p->print.get_object(obj_idx)->delete_last_copy();
|
// p->print.get_object(obj_idx)->delete_last_copy();
|
||||||
#else
|
#else
|
||||||
p->print.get_object(*obj_idx)->delete_last_copy();
|
// p->print.get_object(*obj_idx)->delete_last_copy();
|
||||||
#endif // ENABLE_EXTENDED_SELECTION
|
#endif // ENABLE_EXTENDED_SELECTION
|
||||||
}
|
}
|
||||||
#if ENABLE_EXTENDED_SELECTION
|
#if ENABLE_EXTENDED_SELECTION
|
||||||
|
@ -2281,8 +2256,7 @@ void Plater::decrease_instances(size_t num)
|
||||||
#endif // ENABLE_EXTENDED_SELECTION
|
#endif // ENABLE_EXTENDED_SELECTION
|
||||||
|
|
||||||
p->selection_changed();
|
p->selection_changed();
|
||||||
|
this->p->schedule_background_process();
|
||||||
// $self->schedule_background_process;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::set_number_of_copies(size_t num)
|
void Plater::set_number_of_copies(size_t num)
|
||||||
|
@ -2307,38 +2281,35 @@ void Plater::set_number_of_copies(size_t num)
|
||||||
decrease_instances(-diff);
|
decrease_instances(-diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path Plater::export_gcode(const fs::path &output_path)
|
void Plater::export_gcode(fs::path output_path)
|
||||||
{
|
{
|
||||||
#if ENABLE_EXTENDED_SELECTION
|
#if ENABLE_EXTENDED_SELECTION
|
||||||
if (p->model.objects.empty()) { return ""; }
|
if (p->model.objects.empty())
|
||||||
|
return;
|
||||||
#else
|
#else
|
||||||
if (p->objects.empty()) { return ""; }
|
if (p->objects.empty())
|
||||||
|
return;
|
||||||
#endif // ENABLE_EXTENDED_SELECTION
|
#endif // ENABLE_EXTENDED_SELECTION
|
||||||
|
|
||||||
if (! p->export_gcode_output_file.empty()) {
|
if (this->p->background_process.is_export_scheduled()) {
|
||||||
GUI::show_error(this, _(L("Another export job is currently running.")));
|
GUI::show_error(this, _(L("Another export job is currently running.")));
|
||||||
return "";
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string err = wxGetApp().preset_bundle->full_config().validate();
|
std::string err = wxGetApp().preset_bundle->full_config().validate();
|
||||||
if (err.empty()) {
|
if (err.empty())
|
||||||
err = p->print.validate();
|
err = p->print.validate();
|
||||||
}
|
|
||||||
if (! err.empty()) {
|
if (! err.empty()) {
|
||||||
// The config is not valid
|
// The config is not valid
|
||||||
GUI::show_error(this, _(err));
|
GUI::show_error(this, _(err));
|
||||||
return fs::path();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the names of active presets into the placeholder parser.
|
// Copy the names of active presets into the placeholder parser.
|
||||||
wxGetApp().preset_bundle->export_selections(p->print.placeholder_parser());
|
wxGetApp().preset_bundle->export_selections(p->print.placeholder_parser());
|
||||||
|
|
||||||
// select output file
|
// select output file
|
||||||
if (! output_path.empty()) {
|
if (output_path.empty()) {
|
||||||
p->export_gcode_output_file = fs::path(p->print.output_filepath(output_path.string()));
|
|
||||||
// FIXME: ^ errors to handle?
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// XXX: take output path from CLI opts? Ancient Slic3r versions used to do that...
|
// XXX: take output path from CLI opts? Ancient Slic3r versions used to do that...
|
||||||
|
|
||||||
// If possible, remove accents from accented latin characters.
|
// If possible, remove accents from accented latin characters.
|
||||||
|
@ -2355,13 +2326,17 @@ fs::path Plater::export_gcode(const fs::path &output_path)
|
||||||
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
|
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
|
||||||
);
|
);
|
||||||
|
|
||||||
if (dlg.ShowModal() != wxID_OK) { return ""; }
|
if (dlg.ShowModal() == wxID_OK) {
|
||||||
fs::path path(dlg.GetPath());
|
fs::path path(dlg.GetPath());
|
||||||
wxGetApp().app_config->update_last_output_dir(path.parent_path().string());
|
wxGetApp().app_config->update_last_output_dir(path.parent_path().string());
|
||||||
p->export_gcode_output_file = path;
|
output_path = path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return p->export_gcode_output_file;
|
if (! output_path.empty()) {
|
||||||
|
this->p->background_process.schedule_export(p->print.output_filepath(output_path.string()));
|
||||||
|
this->p->background_process.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::export_stl()
|
void Plater::export_stl()
|
||||||
|
@ -2452,7 +2427,7 @@ void Plater::reslice()
|
||||||
|
|
||||||
void Plater::send_gcode()
|
void Plater::send_gcode()
|
||||||
{
|
{
|
||||||
p->send_gcode_file = export_gcode();
|
// p->send_gcode_file = export_gcode();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::on_extruders_change(int num_extruders)
|
void Plater::on_extruders_change(int num_extruders)
|
||||||
|
|
|
@ -118,7 +118,7 @@ public:
|
||||||
void set_number_of_copies(size_t num);
|
void set_number_of_copies(size_t num);
|
||||||
|
|
||||||
// Note: empty path means "use the default"
|
// Note: empty path means "use the default"
|
||||||
boost::filesystem::path export_gcode(const boost::filesystem::path &output_path = boost::filesystem::path());
|
void export_gcode(boost::filesystem::path output_path = boost::filesystem::path());
|
||||||
void export_stl();
|
void export_stl();
|
||||||
void export_amf();
|
void export_amf();
|
||||||
void export_3mf();
|
void export_3mf();
|
||||||
|
|
|
@ -884,7 +884,8 @@ bool PresetCollection::update_dirty_ui(wxBitmapComboBox *ui)
|
||||||
std::string old_label = ui->GetString(ui_id).utf8_str().data();
|
std::string old_label = ui->GetString(ui_id).utf8_str().data();
|
||||||
std::string preset_name = Preset::remove_suffix_modified(old_label);
|
std::string preset_name = Preset::remove_suffix_modified(old_label);
|
||||||
const Preset *preset = this->find_preset(preset_name, false);
|
const Preset *preset = this->find_preset(preset_name, false);
|
||||||
assert(preset != nullptr);
|
// The old_label could be the "----- system presets ------" or the "------- user presets --------" separator.
|
||||||
|
// assert(preset != nullptr);
|
||||||
if (preset != nullptr) {
|
if (preset != nullptr) {
|
||||||
std::string new_label = preset->is_dirty ? preset->name + g_suffix_modified : preset->name;
|
std::string new_label = preset->is_dirty ? preset->name + g_suffix_modified : preset->name;
|
||||||
if (old_label != new_label)
|
if (old_label != new_label)
|
||||||
|
|
|
@ -53,8 +53,8 @@ ProgressStatusBar::ProgressStatusBar(wxWindow *parent, int id):
|
||||||
});
|
});
|
||||||
|
|
||||||
m_cancelbutton->Bind(wxEVT_BUTTON, [this](const wxCommandEvent&) {
|
m_cancelbutton->Bind(wxEVT_BUTTON, [this](const wxCommandEvent&) {
|
||||||
if(m_cancel_cb) m_cancel_cb();
|
if (m_cancel_cb)
|
||||||
m_perl_cancel_callback.call();
|
m_cancel_cb();
|
||||||
m_cancelbutton->Hide();
|
m_cancelbutton->Hide();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,17 @@ void ProgressStatusBar::embed(wxFrame *frame)
|
||||||
|
|
||||||
void ProgressStatusBar::set_status_text(const wxString& txt)
|
void ProgressStatusBar::set_status_text(const wxString& txt)
|
||||||
{
|
{
|
||||||
self->SetStatusText(wxString::FromUTF8(txt.c_str()));
|
self->SetStatusText(txt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgressStatusBar::set_status_text(const std::string& txt)
|
||||||
|
{
|
||||||
|
this->set_status_text(txt.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgressStatusBar::set_status_text(const char *txt)
|
||||||
|
{
|
||||||
|
this->set_status_text(wxString::FromUTF8(txt));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgressStatusBar::show_cancel_button()
|
void ProgressStatusBar::show_cancel_button()
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include "callback.hpp"
|
|
||||||
|
|
||||||
class wxTimer;
|
class wxTimer;
|
||||||
class wxGauge;
|
class wxGauge;
|
||||||
class wxButton;
|
class wxButton;
|
||||||
|
@ -22,7 +20,8 @@ namespace Slic3r {
|
||||||
* of the Slicer main window. It consists of a message area to the left and a
|
* of the Slicer main window. It consists of a message area to the left and a
|
||||||
* progress indication area to the right with an optional cancel button.
|
* progress indication area to the right with an optional cancel button.
|
||||||
*/
|
*/
|
||||||
class ProgressStatusBar {
|
class ProgressStatusBar
|
||||||
|
{
|
||||||
wxStatusBar *self; // we cheat! It should be the base class but: perl!
|
wxStatusBar *self; // we cheat! It should be the base class but: perl!
|
||||||
wxTimer *m_timer;
|
wxTimer *m_timer;
|
||||||
wxGauge *m_prog;
|
wxGauge *m_prog;
|
||||||
|
@ -44,16 +43,17 @@ public:
|
||||||
void stop_busy();
|
void stop_busy();
|
||||||
inline bool is_busy() const { return m_busy; }
|
inline bool is_busy() const { return m_busy; }
|
||||||
void set_cancel_callback(CancelFn = CancelFn());
|
void set_cancel_callback(CancelFn = CancelFn());
|
||||||
inline void remove_cancel_callback() { set_cancel_callback(); }
|
inline void reset_cancel_callback() { set_cancel_callback(); }
|
||||||
void run(int rate);
|
void run(int rate);
|
||||||
void embed(wxFrame *frame = nullptr);
|
void embed(wxFrame *frame = nullptr);
|
||||||
void set_status_text(const wxString& txt);
|
void set_status_text(const wxString& txt);
|
||||||
|
void set_status_text(const std::string& txt);
|
||||||
|
void set_status_text(const char *txt);
|
||||||
|
|
||||||
// Temporary methods to satisfy Perl side
|
// Temporary methods to satisfy Perl side
|
||||||
void show_cancel_button();
|
void show_cancel_button();
|
||||||
void hide_cancel_button();
|
void hide_cancel_button();
|
||||||
|
|
||||||
PerlCallback m_perl_cancel_callback;
|
|
||||||
private:
|
private:
|
||||||
bool m_busy = false;
|
bool m_busy = false;
|
||||||
CancelFn m_cancel_cb;
|
CancelFn m_cancel_cb;
|
||||||
|
|
|
@ -185,22 +185,6 @@ _constant()
|
||||||
}
|
}
|
||||||
%};
|
%};
|
||||||
|
|
||||||
void export_gcode_with_preview_data(char *path_template, GCodePreviewData *preview_data) %code%{
|
|
||||||
try {
|
|
||||||
THIS->export_gcode(path_template, preview_data);
|
|
||||||
} catch (std::exception& e) {
|
|
||||||
croak(e.what());
|
|
||||||
}
|
|
||||||
%};
|
|
||||||
|
|
||||||
void export_gcode(char *path_template) %code%{
|
|
||||||
try {
|
|
||||||
THIS->export_gcode(path_template, nullptr);
|
|
||||||
} catch (std::exception& e) {
|
|
||||||
croak(e.what());
|
|
||||||
}
|
|
||||||
%};
|
|
||||||
|
|
||||||
void export_png(char *path) %code%{
|
void export_png(char *path) %code%{
|
||||||
try {
|
try {
|
||||||
THIS->export_png(path);
|
THIS->export_png(path);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue