WIP: Background processing.
This commit is contained in:
parent
bb70ad6090
commit
9d9e4a0f7b
@ -1417,9 +1417,9 @@ sub start_background_process {
|
||||
# Stop the background processing
|
||||
sub stop_background_process {
|
||||
my ($self) = @_;
|
||||
$self->{background_slicing_process}->stop();
|
||||
$self->{toolpaths2D}->reload_print if $self->{canvas3D};
|
||||
$self->{preview3D}->reload_print if $self->{preview3D};
|
||||
$self->schedule_background_process;
|
||||
}
|
||||
|
||||
# Called by the "Slice now" button, which is visible only if the background processing is disabled.
|
||||
@ -1467,6 +1467,7 @@ sub export_gcode {
|
||||
eval {
|
||||
# this will throw errors if config is not valid
|
||||
$config->validate;
|
||||
#FIXME it shall use the background processing!
|
||||
$self->{print}->apply_config($config);
|
||||
$self->{print}->validate;
|
||||
};
|
||||
@ -1508,6 +1509,8 @@ sub export_gcode {
|
||||
# this updates buttons status
|
||||
$self->object_list_changed;
|
||||
});
|
||||
|
||||
$self->{background_slicing_process}->set_output_path($self->{export_gcode_output_file});
|
||||
|
||||
# start background process, whose completion event handler
|
||||
# will detect $self->{export_gcode_output_file} and proceed with export
|
||||
@ -1557,7 +1560,10 @@ sub on_process_completed {
|
||||
my $message;
|
||||
my $send_gcode = 0;
|
||||
my $do_print = 0;
|
||||
if ($result) {
|
||||
# print "Process completed, message: ", $message, "\n";
|
||||
if (defined($result)) {
|
||||
$message = L("Export failed");
|
||||
} else {
|
||||
# G-code file exported successfully.
|
||||
if ($self->{print_file}) {
|
||||
$message = L("File added to print queue");
|
||||
@ -1565,14 +1571,13 @@ sub on_process_completed {
|
||||
} elsif ($self->{send_gcode_file}) {
|
||||
$message = L("Sending G-code file to the Printer Host ...");
|
||||
$send_gcode = 1;
|
||||
} else {
|
||||
} elsif (defined $self->{export_gcode_output_file}) {
|
||||
$message = L("G-code file exported to ") . $self->{export_gcode_output_file};
|
||||
} else {
|
||||
$message = L("Slicing complete");
|
||||
}
|
||||
} else {
|
||||
$message = L("Export failed");
|
||||
}
|
||||
$self->{export_gcode_output_file} = undef;
|
||||
$self->statusbar->SetStatusText($message);
|
||||
wxTheApp->notify($message);
|
||||
|
||||
$self->do_print if $do_print;
|
||||
@ -1580,14 +1585,20 @@ sub on_process_completed {
|
||||
# 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})) {
|
||||
$self->statusbar->SetStatusText(L("Upload to host finished."));
|
||||
$message = L("Upload to host finished.");
|
||||
} else {
|
||||
$self->statusbar->SetStatusText("");
|
||||
$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);
|
||||
|
@ -602,12 +602,12 @@ if (WIN32 AND ";${PerlEmbed_CCFLAGS};" MATCHES ";[-/]Od;")
|
||||
message("Old CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
message("Old CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
message("Old CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "/MD /Od /Zi /EHsc /DNDEBUG /DWIN32")
|
||||
set(CMAKE_C_FLAGS_RELEASE "/MD /Od /Zi /DNDEBUG /DWIN32")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /EHsc /DNDEBUG /DWIN32")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /DNDEBUG /DWIN32")
|
||||
set(CMAKE_CXX_FLAGS "/MD /Od /Zi /EHsc /DNDEBUG /DWIN32")
|
||||
set(CMAKE_C_FLAGS "/MD /Od /Zi /DNDEBUG /DWIN32")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "/MD /Od /Zi /EHsc /DNDEBUG /DWIN32 /DTBB_USE_ASSERT")
|
||||
set(CMAKE_C_FLAGS_RELEASE "/MD /Od /Zi /DNDEBUG /DWIN32 /DTBB_USE_ASSERT")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /EHsc /DNDEBUG /DWIN32 /DTBB_USE_ASSERT")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /DNDEBUG /DWIN32 /DTBB_USE_ASSERT")
|
||||
set(CMAKE_CXX_FLAGS "/MD /Od /Zi /EHsc /DNDEBUG /DWIN32 /DTBB_USE_ASSERT")
|
||||
set(CMAKE_C_FLAGS "/MD /Od /Zi /DNDEBUG /DWIN32 /DTBB_USE_ASSERT")
|
||||
endif()
|
||||
# The following line will add -fPIC on Linux to make the XS.so rellocable.
|
||||
add_definitions(${PerlEmbed_CCCDLFLAGS})
|
||||
|
@ -418,6 +418,17 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
||||
{
|
||||
PROFILE_CLEAR();
|
||||
|
||||
if (print->is_step_done(psGCodeExport)) {
|
||||
// Does the file exist? If so, we hope that it is still valid.
|
||||
FILE *f = boost::nowide::fopen(path, "r");
|
||||
if (f != nullptr) {
|
||||
::fclose(f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
print->set_started(psGCodeExport);
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Exporting G-code...";
|
||||
|
||||
// Remove the old g-code if it exists.
|
||||
@ -467,12 +478,13 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (boost::nowide::rename(path_tmp.c_str(), path) != 0)
|
||||
if (rename_file(path_tmp, path) != 0)
|
||||
throw std::runtime_error(
|
||||
std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' +
|
||||
"Is " + path_tmp + " locked?" + '\n');
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Exporting G-code finished";
|
||||
print->set_done(psGCodeExport);
|
||||
|
||||
// Write the profiler measurements to file
|
||||
PROFILE_UPDATE();
|
||||
@ -483,8 +495,6 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
|
||||
print.set_started(psGCodeExport);
|
||||
|
||||
// resets time estimators
|
||||
m_normal_time_estimator.reset();
|
||||
m_normal_time_estimator.set_dialect(print.config().gcode_flavor);
|
||||
@ -1029,8 +1039,6 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
// starts analizer calculations
|
||||
if (preview_data != nullptr)
|
||||
m_analyzer.calc_gcode_preview_data(*preview_data);
|
||||
|
||||
print.set_done(psGCodeExport);
|
||||
}
|
||||
|
||||
std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override)
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "GCodeTimeEstimator.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include <boost/bind.hpp>
|
||||
#include <cmath>
|
||||
|
||||
@ -367,8 +368,7 @@ namespace Slic3r {
|
||||
fclose(out);
|
||||
in.close();
|
||||
|
||||
boost::nowide::remove(filename.c_str());
|
||||
if (boost::nowide::rename(path_tmp.c_str(), filename.c_str()) != 0)
|
||||
if (rename_file(path_tmp, filename) != 0)
|
||||
throw std::runtime_error(std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + filename + '\n' +
|
||||
"Is " + path_tmp + " locked?" + '\n');
|
||||
|
||||
|
@ -849,6 +849,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
||||
return;
|
||||
}
|
||||
|
||||
// Called by Print::validate() from the UI thread.
|
||||
void ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume)
|
||||
{
|
||||
for (const ModelVolume* vol : this->volumes)
|
||||
|
@ -129,6 +129,7 @@ public:
|
||||
void cut(coordf_t z, Model* model) const;
|
||||
void split(ModelObjectPtrs* new_objects);
|
||||
|
||||
// Called by Print::validate() from the UI thread.
|
||||
void check_instances_print_volume_state(const BoundingBoxf3& print_volume);
|
||||
|
||||
// Print object statistics to console.
|
||||
|
@ -72,6 +72,7 @@ void Print::reload_object(size_t /* idx */)
|
||||
// Returns true if the brim or skirt have been invalidated.
|
||||
bool Print::reload_model_instances()
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_mutex);
|
||||
bool invalidated = false;
|
||||
for (PrintObject *object : m_objects)
|
||||
invalidated |= object->reload_model_instances();
|
||||
@ -370,6 +371,7 @@ double Print::max_allowed_layer_height() const
|
||||
// and have explicit instance positions.
|
||||
void Print::add_model_object(ModelObject* model_object, int idx)
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_mutex);
|
||||
// Initialize a new print object and store it at the given position.
|
||||
PrintObject *object = new PrintObject(this, model_object, model_object->raw_bounding_box());
|
||||
if (idx != -1) {
|
||||
@ -378,6 +380,7 @@ void Print::add_model_object(ModelObject* model_object, int idx)
|
||||
} else
|
||||
m_objects.emplace_back(object);
|
||||
// Invalidate all print steps.
|
||||
//FIXME lock mutex!
|
||||
this->invalidate_all_steps();
|
||||
|
||||
for (size_t volume_id = 0; volume_id < model_object->volumes.size(); ++ volume_id) {
|
||||
@ -434,6 +437,8 @@ void Print::add_model_object(ModelObject* model_object, int idx)
|
||||
|
||||
bool Print::apply_config(DynamicPrintConfig config)
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_mutex);
|
||||
|
||||
// we get a copy of the config object so we can modify it safely
|
||||
config.normalize();
|
||||
|
||||
@ -564,13 +569,17 @@ std::string Print::validate() const
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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.");
|
||||
|
@ -88,6 +88,11 @@ public:
|
||||
bool invalidate(StepType step, tbb::mutex &mtx, CancelationCallback &cancel) {
|
||||
bool invalidated = m_state[step].load(std::memory_order_relaxed) != INVALID;
|
||||
if (invalidated) {
|
||||
#if 0
|
||||
if (mtx.state != mtx.HELD) {
|
||||
printf("Not held!\n");
|
||||
}
|
||||
#endif
|
||||
mtx.unlock();
|
||||
cancel();
|
||||
mtx.lock();
|
||||
@ -283,18 +288,14 @@ private:
|
||||
SupportLayerPtrs m_support_layers;
|
||||
|
||||
PrintState<PrintObjectStep, posCount> m_state;
|
||||
// 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.
|
||||
tbb::mutex m_mutex;
|
||||
|
||||
// TODO: call model_object->get_bounding_box() instead of accepting
|
||||
// parameter
|
||||
PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox);
|
||||
~PrintObject() {}
|
||||
|
||||
void set_started(PrintObjectStep step) { m_state.set_started(step, m_mutex); }
|
||||
void set_done(PrintObjectStep step) { m_state.set_done(step, m_mutex); }
|
||||
void set_started(PrintObjectStep step);
|
||||
void set_done(PrintObjectStep step);
|
||||
std::vector<ExPolygons> _slice_region(size_t region_id, const std::vector<float> &z, bool modifier);
|
||||
};
|
||||
|
||||
@ -446,8 +447,8 @@ public:
|
||||
const PrintRegion* get_region(size_t idx) const { return m_regions[idx]; }
|
||||
|
||||
protected:
|
||||
void set_started(PrintStep step) { m_state.set_started(step, m_mutex); }
|
||||
void set_done(PrintStep step) { m_state.set_done(step, m_mutex); }
|
||||
void set_started(PrintStep step) { m_state.set_started(step, m_mutex); throw_if_canceled(); }
|
||||
void set_done(PrintStep step) { m_state.set_done(step, m_mutex); throw_if_canceled(); }
|
||||
bool invalidate_step(PrintStep step);
|
||||
bool invalidate_all_steps() { return m_state.invalidate_all(m_mutex, m_cancel_callback); }
|
||||
|
||||
@ -473,7 +474,7 @@ 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.
|
||||
tbb::mutex m_mutex;
|
||||
mutable tbb::mutex m_mutex;
|
||||
|
||||
// Has the calculation been canceled?
|
||||
tbb::atomic<bool> m_canceled;
|
||||
|
@ -59,8 +59,19 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding
|
||||
this->layer_height_profile = model_object->layer_height_profile;
|
||||
}
|
||||
|
||||
void PrintObject::set_started(PrintObjectStep step)
|
||||
{
|
||||
m_state.set_started(step, m_print->m_mutex);
|
||||
}
|
||||
|
||||
void PrintObject::set_done(PrintObjectStep step)
|
||||
{
|
||||
m_state.set_done(step, m_print->m_mutex);
|
||||
}
|
||||
|
||||
bool PrintObject::add_copy(const Vec2d &point)
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_print->m_mutex);
|
||||
Points points = m_copies;
|
||||
points.push_back(Point::new_scale(point(0), point(1)));
|
||||
return this->set_copies(points);
|
||||
@ -68,6 +79,7 @@ bool PrintObject::add_copy(const Vec2d &point)
|
||||
|
||||
bool PrintObject::delete_last_copy()
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_print->m_mutex);
|
||||
Points points = m_copies;
|
||||
points.pop_back();
|
||||
return this->set_copies(points);
|
||||
@ -158,7 +170,6 @@ void PrintObject::make_perimeters()
|
||||
m_print->throw_if_canceled();
|
||||
}
|
||||
this->typed_slices = false;
|
||||
// m_state.invalidate(posPrepareInfill);
|
||||
}
|
||||
|
||||
// compare each layer to the one below, and mark those slices needing
|
||||
|
@ -43,6 +43,14 @@ extern local_encoded_string encode_path(const char *src);
|
||||
extern std::string decode_path(const char *src);
|
||||
extern std::string normalize_utf8_nfc(const char *src);
|
||||
|
||||
// Safely rename a file even if the target exists.
|
||||
// On Windows, the file explorer (or anti-virus or whatever else) often locks the file
|
||||
// for a short while, so the file may not be movable. Retry while we see recoverable errors.
|
||||
extern int rename_file(const std::string &from, const std::string &to);
|
||||
|
||||
// Copy a file, adjust the access attributes, so that the target is writable.
|
||||
extern int copy_file(const std::string &from, const std::string &to);
|
||||
|
||||
// File path / name / extension splitting utilities, working with UTF-8,
|
||||
// to be published to Perl.
|
||||
namespace PerlUtils {
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <boost/nowide/integration/filesystem.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -139,6 +140,87 @@ const std::string& data_dir()
|
||||
return g_data_dir;
|
||||
}
|
||||
|
||||
|
||||
// borrowed from LVVM lib/Support/Windows/Path.inc
|
||||
int rename_file(const std::string &from, const std::string &to)
|
||||
{
|
||||
int ec = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// Convert to utf-16.
|
||||
std::wstring wide_from = boost::nowide::widen(from);
|
||||
std::wstring wide_to = boost::nowide::widen(to);
|
||||
|
||||
// Retry while we see recoverable errors.
|
||||
// System scanners (eg. indexer) might open the source file when it is written
|
||||
// and closed.
|
||||
bool TryReplace = true;
|
||||
|
||||
// This loop may take more than 2000 x 1ms to finish.
|
||||
for (int i = 0; i < 2000; ++ i) {
|
||||
if (i > 0)
|
||||
// Sleep 1ms
|
||||
::Sleep(1);
|
||||
if (TryReplace) {
|
||||
// Try ReplaceFile first, as it is able to associate a new data stream
|
||||
// with the destination even if the destination file is currently open.
|
||||
if (::ReplaceFileW(wide_to.data(), wide_from.data(), NULL, 0, NULL, NULL))
|
||||
return 0;
|
||||
DWORD ReplaceError = ::GetLastError();
|
||||
ec = -1; // ReplaceError
|
||||
// If ReplaceFileW returned ERROR_UNABLE_TO_MOVE_REPLACEMENT or
|
||||
// ERROR_UNABLE_TO_MOVE_REPLACEMENT_2, retry but only use MoveFileExW().
|
||||
if (ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT ||
|
||||
ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT_2) {
|
||||
TryReplace = false;
|
||||
continue;
|
||||
}
|
||||
// If ReplaceFileW returned ERROR_UNABLE_TO_REMOVE_REPLACED, retry
|
||||
// using ReplaceFileW().
|
||||
if (ReplaceError == ERROR_UNABLE_TO_REMOVE_REPLACED)
|
||||
continue;
|
||||
// We get ERROR_FILE_NOT_FOUND if the destination file is missing.
|
||||
// MoveFileEx can handle this case.
|
||||
if (ReplaceError != ERROR_ACCESS_DENIED && ReplaceError != ERROR_FILE_NOT_FOUND && ReplaceError != ERROR_SHARING_VIOLATION)
|
||||
break;
|
||||
}
|
||||
if (::MoveFileExW(wide_from.c_str(), wide_to.c_str(), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING))
|
||||
return 0;
|
||||
DWORD MoveError = ::GetLastError();
|
||||
ec = -1; // MoveError
|
||||
if (MoveError != ERROR_ACCESS_DENIED && MoveError != ERROR_SHARING_VIOLATION)
|
||||
break;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
boost::nowide::remove(from.c_str());
|
||||
ec = boost::nowide::rename(from.c_str(), to.c_str());
|
||||
|
||||
#endif
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
int copy_file(const std::string &from, const std::string &to)
|
||||
{
|
||||
const boost::filesystem::path source(from);
|
||||
const boost::filesystem::path target(to);
|
||||
static const auto perms = boost::filesystem::owner_read | boost::filesystem::owner_write | boost::filesystem::group_read | boost::filesystem::others_read; // aka 644
|
||||
|
||||
// Make sure the file has correct permission both before and after we copy over it.
|
||||
try {
|
||||
if (boost::filesystem::exists(target))
|
||||
boost::filesystem::permissions(target, perms);
|
||||
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists);
|
||||
boost::filesystem::permissions(target, perms);
|
||||
} catch (std::exception & /* ex */) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#include <xsinit.h>
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <wx/event.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/stdpaths.h>
|
||||
|
||||
// Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx.
|
||||
#include "../../libslic3r/Print.hpp"
|
||||
@ -11,12 +12,28 @@
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace GUI {
|
||||
extern wxPanel *g_wxPlater;
|
||||
};
|
||||
|
||||
BackgroundSlicingProcess::BackgroundSlicingProcess()
|
||||
{
|
||||
m_temp_output_path = wxStandardPaths::Get().GetTempDir().utf8_str().data();
|
||||
m_temp_output_path += (boost::format(".%1%.gcode") % get_current_pid()).str();
|
||||
}
|
||||
|
||||
BackgroundSlicingProcess::~BackgroundSlicingProcess()
|
||||
{
|
||||
this->stop();
|
||||
this->join_background_thread();
|
||||
boost::nowide::remove(m_temp_output_path.c_str());
|
||||
}
|
||||
|
||||
void BackgroundSlicingProcess::thread_proc()
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(m_mutex);
|
||||
@ -41,7 +58,10 @@ void BackgroundSlicingProcess::thread_proc()
|
||||
m_print->process();
|
||||
if (! m_print->canceled()) {
|
||||
wxQueueEvent(GUI::g_wxPlater, new wxCommandEvent(m_event_sliced_id));
|
||||
m_print->export_gcode(m_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() &&
|
||||
copy_file(m_temp_output_path, m_output_path) != 0)
|
||||
throw std::runtime_error("Copying of the temporary G-code to the output G-code failed");
|
||||
}
|
||||
} catch (CanceledException &ex) {
|
||||
// Canceled, this is all right.
|
||||
@ -111,8 +131,10 @@ bool BackgroundSlicingProcess::start()
|
||||
bool BackgroundSlicingProcess::stop()
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(m_mutex);
|
||||
if (m_state == STATE_INITIAL)
|
||||
if (m_state == STATE_INITIAL) {
|
||||
this->m_output_path.clear();
|
||||
return false;
|
||||
}
|
||||
assert(this->running());
|
||||
if (m_state == STATE_STARTED || m_state == STATE_RUNNING) {
|
||||
m_print->cancel();
|
||||
@ -124,6 +146,7 @@ bool BackgroundSlicingProcess::stop()
|
||||
// In the "Finished" or "Canceled" state. Reset the state to "Idle".
|
||||
m_state = STATE_IDLE;
|
||||
}
|
||||
this->m_output_path.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,9 @@ class Print;
|
||||
class BackgroundSlicingProcess
|
||||
{
|
||||
public:
|
||||
BackgroundSlicingProcess() {}
|
||||
// Stop the background processing and finalize the bacgkround processing thread.
|
||||
~BackgroundSlicingProcess() { this->stop(); this->join_background_thread(); }
|
||||
BackgroundSlicingProcess();
|
||||
// Stop the background processing and finalize the bacgkround processing thread, remove temp files.
|
||||
~BackgroundSlicingProcess();
|
||||
|
||||
void set_print(Print *print) { m_print = print; }
|
||||
void set_gcode_preview_data(GCodePreviewData *gpd) { m_gcode_preview_data = gpd; }
|
||||
@ -31,6 +31,8 @@ public:
|
||||
// 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; }
|
||||
|
||||
// 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.
|
||||
bool start();
|
||||
// Cancel the background processing. Returns false if the background processing was not running.
|
||||
@ -68,6 +70,7 @@ private:
|
||||
Print *m_print = nullptr;
|
||||
// Data structure, to which the G-code export writes its annotations.
|
||||
GCodePreviewData *m_gcode_preview_data = nullptr;
|
||||
std::string m_temp_output_path;
|
||||
std::string m_output_path;
|
||||
// Thread, on which the background processing is executed. The thread will always be present
|
||||
// and ready to execute the slicing process.
|
||||
|
@ -5208,9 +5208,9 @@ void GLCanvas3D::_load_shells()
|
||||
|
||||
// adds objects' volumes
|
||||
unsigned int object_id = 0;
|
||||
for (PrintObject* obj : m_print->objects())
|
||||
for (const PrintObject* obj : m_print->objects())
|
||||
{
|
||||
ModelObject* model_obj = obj->model_object();
|
||||
const ModelObject* model_obj = obj->model_object();
|
||||
|
||||
std::vector<int> instance_ids(model_obj->instances.size());
|
||||
for (int i = 0; i < (int)model_obj->instances.size(); ++i)
|
||||
|
@ -383,13 +383,10 @@ void update_after_moving()
|
||||
if (volume_id < 0)
|
||||
return;
|
||||
|
||||
Vec3d m = m_move_options;
|
||||
Vec3d l = m_last_coords;
|
||||
|
||||
auto d = Vec3d(m(0) - l(0), m(1) - l(1), m(2) - l(2));
|
||||
auto volume = (*m_objects)[m_selected_object_id]->volumes[volume_id];
|
||||
auto d = m_move_options - m_last_coords;
|
||||
auto volume = (*m_objects)[m_selected_object_id]->volumes[volume_id];
|
||||
volume->mesh.translate(d(0), d(1), d(2));
|
||||
m_last_coords = m;
|
||||
m_last_coords = m_move_options;
|
||||
|
||||
m_parts_changed = true;
|
||||
parts_changed(m_selected_object_id);
|
||||
|
72
xs/src/slic3r/GUI/ProgressIndicator.hpp
Normal file
72
xs/src/slic3r/GUI/ProgressIndicator.hpp
Normal file
@ -0,0 +1,72 @@
|
||||
#ifndef IPROGRESSINDICATOR_HPP
|
||||
#define IPROGRESSINDICATOR_HPP
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
#include <wx/string.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
/**
|
||||
* @brief Generic progress indication interface.
|
||||
*/
|
||||
class ProgressIndicator {
|
||||
public:
|
||||
using CancelFn = std::function<void(void)>; // Cancel function signature.
|
||||
|
||||
private:
|
||||
float state_ = .0f, max_ = 1.f, step_;
|
||||
CancelFn cancelfunc_ = [](){};
|
||||
|
||||
public:
|
||||
|
||||
inline virtual ~ProgressIndicator() {}
|
||||
|
||||
/// Get the maximum of the progress range.
|
||||
float max() const { return max_; }
|
||||
|
||||
/// Get the current progress state
|
||||
float state() const { return state_; }
|
||||
|
||||
/// Set the maximum of the progress range
|
||||
virtual void max(float maxval) { max_ = maxval; }
|
||||
|
||||
/// Set the current state of the progress.
|
||||
virtual void state(float val) { state_ = val; }
|
||||
|
||||
/**
|
||||
* @brief Number of states int the progress. Can be used instead of giving a
|
||||
* maximum value.
|
||||
*/
|
||||
virtual void states(unsigned statenum) {
|
||||
step_ = max_ / statenum;
|
||||
}
|
||||
|
||||
/// Message shown on the next status update.
|
||||
virtual void message(const wxString&) = 0;
|
||||
|
||||
/// Title of the operation.
|
||||
virtual void title(const wxString&) = 0;
|
||||
|
||||
/// Formatted message for the next status update. Works just like sprintf.
|
||||
virtual void message_fmt(const wxString& fmt, ...);
|
||||
|
||||
/// Set up a cancel callback for the operation if feasible.
|
||||
virtual void on_cancel(CancelFn func = CancelFn()) { cancelfunc_ = func; }
|
||||
|
||||
/**
|
||||
* Explicitly shut down the progress indicator and call the associated
|
||||
* callback.
|
||||
*/
|
||||
virtual void cancel() { cancelfunc_(); }
|
||||
|
||||
/// Convenience function to call message and status update in one function.
|
||||
void update(float st, const wxString& msg) {
|
||||
message(msg); state(st);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // IPROGRESSINDICATOR_HPP
|
@ -15,6 +15,7 @@
|
||||
void set_sliced_event(int event_id);
|
||||
void set_finished_event(int event_id);
|
||||
|
||||
void set_output_path(const char *path);
|
||||
bool start();
|
||||
bool stop();
|
||||
bool apply_config(DynamicPrintConfig *config)
|
||||
|
Loading…
Reference in New Issue
Block a user