2018-03-23 11:41:20 +01:00
#include "BackgroundSlicingProcess.hpp"
2018-10-02 13:23:38 +02:00
#include "GUI_App.hpp"
2020-03-04 09:24:13 +01:00
#include "GUI.hpp"
2020-05-26 17:42:57 +02:00
#include "MainFrame.hpp"
2018-03-23 11:41:20 +01:00
2018-11-06 11:54:36 +01:00
#include <wx/app.h>
2018-03-23 11:41:20 +01:00
#include <wx/panel.h>
2018-09-14 09:28:00 +02:00
#include <wx/stdpaths.h>
2018-03-23 11:41:20 +01:00
2018-11-13 17:33:03 +01:00
// For zipped archive creation
#include <wx/stdstream.h>
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
2019-10-24 08:46:39 +02:00
#include <miniz.h>
2018-09-12 11:59:02 +02:00
// Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx.
2018-11-08 20:18:40 +01:00
#include "libslic3r/Print.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/GCode/PostProcessor.hpp"
2020-05-07 10:49:12 +02:00
#if !ENABLE_GCODE_VIEWER
2018-12-19 14:47:16 +01:00
#include "libslic3r/GCode/PreviewData.hpp"
2020-05-07 10:49:12 +02:00
#endif // !ENABLE_GCODE_VIEWER
2020-04-13 12:31:37 +02:00
#include "libslic3r/Format/SL1.hpp"
2019-04-15 16:14:19 +02:00
#include "libslic3r/libslic3r.h"
2018-09-12 11:59:02 +02:00
2018-03-23 11:41:20 +01:00
#include <cassert>
#include <stdexcept>
2018-12-11 10:33:11 +01:00
#include <cctype>
2018-03-23 11:41:20 +01:00
2020-02-28 11:13:14 +01:00
#include <boost/format/format_fwd.hpp>
#include <boost/filesystem/operations.hpp>
2018-12-12 12:00:45 +01:00
#include <boost/log/trivial.hpp>
2018-09-14 09:28:00 +02:00
#include <boost/nowide/cstdio.hpp>
2019-05-04 02:07:07 +02:00
#include "I18N.hpp"
2019-12-18 14:09:16 +01:00
#include "RemovableDriveManager.hpp"
2018-09-14 09:28:00 +02:00
2020-02-28 11:13:14 +01:00
#include "slic3r/Utils/Thread.hpp"
2020-05-26 17:42:57 +02:00
#include "slic3r/GUI/Plater.hpp"
2020-02-28 11:13:14 +01:00
2018-03-23 11:41:20 +01:00
namespace Slic3r {
2020-09-14 16:27:55 +02:00
bool SlicingProcessCompletedEvent :: critical_error () const
{
try {
this -> rethrow_exception ();
} catch ( const Slic3r :: SlicingError & ex ) {
// Exception derived from SlicingError is non-critical.
return false ;
} catch (...) {
}
2020-09-14 16:27:38 +02:00
return true ;
2020-09-14 16:27:55 +02:00
}
std :: string SlicingProcessCompletedEvent :: format_error_message () const
{
std :: string error ;
try {
this -> rethrow_exception ();
} catch ( const std :: bad_alloc & ex ) {
wxString errmsg = GUI :: from_u8 (( boost :: format ( _utf8 ( L ( "%s has encountered an error. It was likely caused by running out of memory. "
"If you are sure you have enough RAM on your system, this may also be a bug and we would "
"be glad if you reported it." ))) % SLIC3R_APP_NAME ). str ());
error = std :: string ( errmsg . ToUTF8 ()) + " \n\n " + std :: string ( ex . what ());
} catch ( std :: exception & ex ) {
error = ex . what ();
} catch (...) {
error = "Unknown C++ exception." ;
}
return error ;
}
2018-09-14 09:28:00 +02:00
BackgroundSlicingProcess :: BackgroundSlicingProcess ()
{
2018-10-24 21:03:12 +02:00
boost :: filesystem :: path temp_path ( wxStandardPaths :: Get (). GetTempDir (). utf8_str (). data ());
temp_path /= ( boost :: format ( ".%1%.gcode" ) % get_current_pid ()). str ();
m_temp_output_path = temp_path . string ();
2018-09-14 09:28:00 +02:00
}
BackgroundSlicingProcess ::~ BackgroundSlicingProcess ()
{
this -> stop ();
this -> join_background_thread ();
boost :: nowide :: remove ( m_temp_output_path . c_str ());
}
2018-12-03 13:14:28 +01:00
bool BackgroundSlicingProcess :: select_technology ( PrinterTechnology tech )
2018-11-08 20:18:40 +01:00
{
2018-12-03 13:14:28 +01:00
bool changed = false ;
2018-11-08 20:18:40 +01:00
if ( m_print == nullptr || m_print -> technology () != tech ) {
if ( m_print != nullptr )
this -> reset ();
switch ( tech ) {
case ptFFF : m_print = m_fff_print ; break ;
case ptSLA : m_print = m_sla_print ; break ;
2019-10-29 10:40:34 +01:00
default : assert ( false ); break ;
2018-11-08 20:18:40 +01:00
}
2018-12-03 13:14:28 +01:00
changed = true ;
2018-11-08 20:18:40 +01:00
}
assert ( m_print != nullptr );
2018-12-03 13:14:28 +01:00
return changed ;
2018-11-08 20:18:40 +01:00
}
2018-11-22 15:29:59 +01:00
PrinterTechnology BackgroundSlicingProcess :: current_printer_technology () const
{
return m_print -> technology ();
}
2019-05-17 16:27:00 +02:00
std :: string BackgroundSlicingProcess :: output_filepath_for_project ( const boost :: filesystem :: path & project_path )
{
assert ( m_print != nullptr );
if ( project_path . empty ())
return m_print -> output_filepath ( "" );
return m_print -> output_filepath ( project_path . parent_path (). string (), project_path . stem (). string ());
}
2018-11-08 20:18:40 +01:00
// This function may one day be merged into the Print, but historically the print was separated
// from the G-code generator.
void BackgroundSlicingProcess :: process_fff ()
{
assert ( m_print == m_fff_print );
m_print -> process ();
2020-08-03 15:36:55 +02:00
wxCommandEvent evt ( m_event_slicing_completed_id );
evt . SetInt (( int )( m_fff_print -> step_state_with_timestamp ( PrintStep :: psBrim ). timestamp ));
wxQueueEvent ( GUI :: wxGetApp (). mainframe -> m_plater , evt . Clone ());
2020-03-02 15:13:23 +01:00
#if ENABLE_GCODE_VIEWER
2020-05-07 10:49:12 +02:00
m_fff_print -> export_gcode ( m_temp_output_path , m_gcode_result , m_thumbnail_cb );
2019-10-23 13:31:24 +02:00
#else
2020-08-04 09:58:19 +02:00
m_fff_print -> export_gcode ( m_temp_output_path , m_gcode_preview_data , m_thumbnail_cb );
2020-03-02 15:13:23 +01:00
#endif // ENABLE_GCODE_VIEWER
2018-11-16 18:28:50 +01:00
if ( this -> set_step_started ( bspsGCodeFinalize )) {
if ( ! m_export_path . empty ()) {
2020-08-03 15:36:55 +02:00
wxQueueEvent ( GUI :: wxGetApp (). mainframe -> m_plater , new wxCommandEvent ( m_event_export_began_id ));
2018-11-16 18:28:50 +01:00
//FIXME localize the messages
2018-12-12 12:00:45 +01:00
// Perform the final post-processing of the export path by applying the print statistics over the file name.
2018-12-12 15:09:20 +01:00
std :: string export_path = m_fff_print -> print_statistics (). finalize_output_path ( m_export_path );
2020-03-12 12:43:01 +01:00
int copy_ret_val = copy_file ( m_temp_output_path , export_path , m_export_path_on_removable_media );
2020-03-06 15:10:58 +01:00
switch ( copy_ret_val ) {
2020-02-27 10:44:25 +01:00
case SUCCESS : break ; // no error
case FAIL_COPY_FILE :
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( _utf8 ( L ( "Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?" )));
2020-02-27 10:44:25 +01:00
break ;
case FAIL_FILES_DIFFERENT :
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError (( boost :: format ( _utf8 ( L ( "Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp." ))) % export_path ). str ());
2020-02-21 11:17:48 +01:00
break ;
2020-02-27 10:44:25 +01:00
case FAIL_RENAMING :
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError (( boost :: format ( _utf8 ( L ( "Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again." ))) % export_path ). str ());
2020-02-21 11:17:48 +01:00
break ;
2020-02-27 10:44:25 +01:00
case FAIL_CHECK_ORIGIN_NOT_OPENED :
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError (( boost :: format ( _utf8 ( L ( "Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp." ))) % m_temp_output_path % export_path ). str ());
2020-02-21 11:17:48 +01:00
break ;
2020-02-27 10:44:25 +01:00
case FAIL_CHECK_TARGET_NOT_OPENED :
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError (( boost :: format ( _utf8 ( L ( "Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp." ))) % export_path ). str ());
2020-02-21 11:17:48 +01:00
break ;
default :
2020-02-27 10:44:25 +01:00
BOOST_LOG_TRIVIAL ( warning ) << "Unexpected fail code(" << ( int ) copy_ret_val << ") durring copy_file() to " << export_path << "." ;
2020-02-21 11:17:48 +01:00
break ;
2020-01-02 11:28:37 +01:00
}
2020-02-21 11:17:48 +01:00
2019-05-09 19:58:16 +02:00
m_print -> set_status ( 95 , _utf8 ( L ( "Running post-processing scripts" )));
2018-12-12 12:00:45 +01:00
run_post_process_scripts ( export_path , m_fff_print -> config ());
2019-05-09 19:58:16 +02:00
m_print -> set_status ( 100 , ( boost :: format ( _utf8 ( L ( "G-code file exported to %1%" ))) % export_path ). str ());
2018-12-14 15:27:34 +01:00
} else if ( ! m_upload_job . empty ()) {
2020-08-03 15:36:55 +02:00
wxQueueEvent ( GUI :: wxGetApp (). mainframe -> m_plater , new wxCommandEvent ( m_event_export_began_id ));
2018-12-20 16:35:54 +01:00
prepare_upload ();
2018-11-16 18:28:50 +01:00
} else {
2019-05-09 19:58:16 +02:00
m_print -> set_status ( 100 , _utf8 ( L ( "Slicing complete" )));
2018-11-08 20:18:40 +01:00
}
2018-11-16 18:28:50 +01:00
this -> set_step_done ( bspsGCodeFinalize );
}
2018-11-08 20:18:40 +01:00
}
2019-10-24 08:46:39 +02:00
static void write_thumbnail ( Zipper & zipper , const ThumbnailData & data )
2019-10-23 17:10:14 +02:00
{
2019-10-24 08:46:39 +02:00
size_t png_size = 0 ;
void * png_data = tdefl_write_image_to_png_file_in_memory_ex (( const void * ) data . pixels . data (), data . width , data . height , 4 , & png_size , MZ_DEFAULT_LEVEL , 1 );
if ( png_data != nullptr )
{
2019-10-25 13:59:13 +02:00
zipper . add_entry ( "thumbnail/thumbnail" + std :: to_string ( data . width ) + "x" + std :: to_string ( data . height ) + ".png" , ( const std :: uint8_t * ) png_data , png_size );
2019-10-24 08:46:39 +02:00
mz_free ( png_data );
}
2019-10-23 17:10:14 +02:00
}
2018-11-16 18:28:50 +01:00
void BackgroundSlicingProcess :: process_sla ()
{
2018-11-13 11:53:54 +01:00
assert ( m_print == m_sla_print );
m_print -> process ();
2018-11-16 18:28:50 +01:00
if ( this -> set_step_started ( bspsGCodeFinalize )) {
2018-11-13 11:53:54 +01:00
if ( ! m_export_path . empty ()) {
2020-08-03 15:36:55 +02:00
wxQueueEvent ( GUI :: wxGetApp (). mainframe -> m_plater , new wxCommandEvent ( m_event_export_began_id ));
2019-10-23 17:10:14 +02:00
const std :: string export_path = m_sla_print -> print_statistics (). finalize_output_path ( m_export_path );
Zipper zipper ( export_path );
2020-04-13 12:31:37 +02:00
m_sla_archive . export_print ( zipper , * m_sla_print );
2019-10-24 08:46:39 +02:00
2019-11-22 12:39:03 +01:00
if ( m_thumbnail_cb != nullptr )
2019-10-25 13:59:13 +02:00
{
2019-11-22 12:39:03 +01:00
ThumbnailsList thumbnails ;
2019-11-28 14:18:24 +01:00
m_thumbnail_cb ( thumbnails , current_print () -> full_print_config (). option < ConfigOptionPoints > ( "thumbnails" ) -> values , true , true , true , true );
// m_thumbnail_cb(thumbnails, current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, false, true, true); // renders also supports and pad
2019-11-22 12:39:03 +01:00
for ( const ThumbnailData & data : thumbnails )
2019-10-25 13:59:13 +02:00
{
if ( data . is_valid ())
write_thumbnail ( zipper , data );
}
}
2019-10-23 17:10:14 +02:00
zipper . finalize ();
2019-05-09 19:58:16 +02:00
m_print -> set_status ( 100 , ( boost :: format ( _utf8 ( L ( "Masked SLA file exported to %1%" ))) % export_path ). str ());
2018-12-20 16:35:54 +01:00
} else if ( ! m_upload_job . empty ()) {
2020-08-03 15:36:55 +02:00
wxQueueEvent ( GUI :: wxGetApp (). mainframe -> m_plater , new wxCommandEvent ( m_event_export_began_id ));
2018-12-20 16:35:54 +01:00
prepare_upload ();
} else {
2019-05-09 19:58:16 +02:00
m_print -> set_status ( 100 , _utf8 ( L ( "Slicing complete" )));
2018-11-13 11:53:54 +01:00
}
this -> set_step_done ( bspsGCodeFinalize );
}
}
2018-03-23 11:41:20 +01:00
void BackgroundSlicingProcess :: thread_proc ()
{
2018-11-08 20:18:40 +01:00
assert ( m_print != nullptr );
assert ( m_print == m_fff_print || m_print == m_sla_print );
2018-03-23 11:41:20 +01:00
std :: unique_lock < std :: mutex > lck ( m_mutex );
// Let the caller know we are ready to run the background processing task.
m_state = STATE_IDLE ;
lck . unlock ();
m_condition . notify_one ();
for (;;) {
2018-03-28 17:05:31 +02:00
assert ( m_state == STATE_IDLE || m_state == STATE_CANCELED || m_state == STATE_FINISHED );
2018-03-23 11:41:20 +01:00
// Wait until a new task is ready to be executed, or this thread should be finished.
lck . lock ();
m_condition . wait ( lck , [ this ](){ return m_state == STATE_STARTED || m_state == STATE_EXIT ; });
if ( m_state == STATE_EXIT )
// Exiting this thread.
break ;
// Process the background slicing task.
m_state = STATE_RUNNING ;
lck . unlock ();
2020-09-14 16:27:55 +02:00
std :: exception_ptr exception ;
2018-03-23 11:41:20 +01:00
try {
assert ( m_print != nullptr );
2018-11-08 20:18:40 +01:00
switch ( m_print -> technology ()) {
case ptFFF : this -> process_fff (); break ;
2018-11-13 11:53:54 +01:00
case ptSLA : this -> process_sla (); break ;
2018-11-08 20:18:40 +01:00
default : m_print -> process (); break ;
}
2018-10-31 16:22:36 +01:00
} catch ( CanceledException & /* ex */ ) {
2018-03-28 17:05:31 +02:00
// Canceled, this is all right.
assert ( m_print -> canceled ());
2018-03-23 11:41:20 +01:00
} catch (...) {
2020-09-14 16:27:55 +02:00
exception = std :: current_exception ();
2018-03-23 11:41:20 +01:00
}
2019-02-21 11:40:56 +01:00
m_print -> finalize ();
2018-03-23 11:41:20 +01:00
lck . lock ();
m_state = m_print -> canceled () ? STATE_CANCELED : STATE_FINISHED ;
2018-10-30 09:27:31 +01:00
if ( m_print -> cancel_status () != Print :: CANCELED_INTERNAL ) {
// Only post the canceled event, if canceled by user.
// Don't post the canceled event, if canceled from Print::apply().
2020-09-14 16:27:55 +02:00
SlicingProcessCompletedEvent evt ( m_event_finished_id , 0 ,
( m_state == STATE_CANCELED ) ? SlicingProcessCompletedEvent :: Cancelled :
exception ? SlicingProcessCompletedEvent :: Error : SlicingProcessCompletedEvent :: Finished , exception );
2018-10-30 09:27:31 +01:00
wxQueueEvent ( GUI :: wxGetApp (). mainframe -> m_plater , evt . Clone ());
}
2018-03-28 17:05:31 +02:00
m_print -> restart ();
2018-03-23 11:41:20 +01:00
lck . unlock ();
// Let the UI thread wake up if it is waiting for the background task to finish.
m_condition . notify_one ();
// Let the UI thread see the result.
}
m_state = STATE_EXITED ;
lck . unlock ();
// End of the background processing thread. The UI thread should join m_thread now.
}
2018-11-06 11:54:36 +01:00
void BackgroundSlicingProcess :: thread_proc_safe ()
{
try {
this -> thread_proc ();
} catch (...) {
wxTheApp -> OnUnhandledException ();
}
}
2018-03-23 11:41:20 +01:00
void BackgroundSlicingProcess :: join_background_thread ()
{
std :: unique_lock < std :: mutex > lck ( m_mutex );
if ( m_state == STATE_INITIAL ) {
// Worker thread has not been started yet.
assert ( ! m_thread . joinable ());
} else {
assert ( m_state == STATE_IDLE );
assert ( m_thread . joinable ());
// Notify the worker thread to exit.
m_state = STATE_EXIT ;
lck . unlock ();
m_condition . notify_one ();
// Wait until the worker thread exits.
m_thread . join ();
}
}
bool BackgroundSlicingProcess :: start ()
{
2018-11-08 20:18:40 +01:00
if ( m_print -> empty ())
// The print is empty (no object in Model, or all objects are out of the print bed).
return false ;
2018-03-23 11:41:20 +01:00
std :: unique_lock < std :: mutex > lck ( m_mutex );
if ( m_state == STATE_INITIAL ) {
// The worker thread is not running yet. Start it.
assert ( ! m_thread . joinable ());
2019-11-07 12:57:40 +01:00
m_thread = create_thread ([ this ]{ this -> thread_proc_safe ();});
2018-03-23 11:41:20 +01:00
// Wait until the worker thread is ready to execute the background processing task.
m_condition . wait ( lck , [ this ](){ return m_state == STATE_IDLE ; });
}
assert ( m_state == STATE_IDLE || this -> running ());
if ( this -> running ())
// The background processing thread is already running.
return false ;
if ( ! this -> idle ())
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( "Cannot start a background task, the worker thread is not idle." );
2018-03-23 11:41:20 +01:00
m_state = STATE_STARTED ;
2018-10-30 09:27:31 +01:00
m_print -> set_cancel_callback ([ this ](){ this -> stop_internal (); });
2018-03-23 11:41:20 +01:00
lck . unlock ();
m_condition . notify_one ();
return true ;
}
bool BackgroundSlicingProcess :: stop ()
{
2018-11-16 18:28:50 +01:00
// m_print->state_mutex() shall NOT be held. Unfortunately there is no interface to test for it.
2018-03-23 11:41:20 +01:00
std :: unique_lock < std :: mutex > lck ( m_mutex );
2018-09-14 09:28:00 +02:00
if ( m_state == STATE_INITIAL ) {
2018-10-23 15:27:31 +02:00
// this->m_export_path.clear();
2018-03-23 11:41:20 +01:00
return false ;
2018-09-14 09:28:00 +02:00
}
2018-10-18 18:06:40 +02:00
// assert(this->running());
2018-03-23 11:41:20 +01:00
if ( m_state == STATE_STARTED || m_state == STATE_RUNNING ) {
m_print -> cancel ();
// Wait until the background processing stops by being canceled.
m_condition . wait ( lck , [ this ](){ return m_state == STATE_CANCELED ; });
2018-03-28 17:05:31 +02:00
// In the "Canceled" state. Reset the state to "Idle".
m_state = STATE_IDLE ;
2018-10-23 22:53:43 +02:00
m_print -> set_cancel_callback ([](){});
2018-03-28 17:05:31 +02:00
} else if ( m_state == STATE_FINISHED || m_state == STATE_CANCELED ) {
// In the "Finished" or "Canceled" state. Reset the state to "Idle".
m_state = STATE_IDLE ;
2018-10-23 22:53:43 +02:00
m_print -> set_cancel_callback ([](){});
2018-03-23 11:41:20 +01:00
}
2018-10-23 15:27:31 +02:00
// this->m_export_path.clear();
2018-03-23 11:41:20 +01:00
return true ;
}
2018-11-08 14:23:17 +01:00
bool BackgroundSlicingProcess :: reset ()
{
bool stopped = this -> stop ();
this -> reset_export ();
m_print -> clear ();
2018-11-08 20:18:40 +01:00
this -> invalidate_all_steps ();
2018-11-08 14:23:17 +01:00
return stopped ;
}
2018-10-30 09:27:31 +01:00
// To be called by Print::apply() through the Print::m_cancel_callback to stop the background
// processing before changing any data of running or finalized milestones.
// This function shall not trigger any UI update through the wxWidgets event.
void BackgroundSlicingProcess :: stop_internal ()
{
2018-11-16 18:28:50 +01:00
// m_print->state_mutex() shall be held. Unfortunately there is no interface to test for it.
if ( m_state == STATE_IDLE )
// The worker thread is waiting on m_mutex/m_condition for wake up. The following lock of the mutex would block.
return ;
2018-10-30 09:27:31 +01:00
std :: unique_lock < std :: mutex > lck ( m_mutex );
assert ( m_state == STATE_STARTED || m_state == STATE_RUNNING || m_state == STATE_FINISHED || m_state == STATE_CANCELED );
if ( m_state == STATE_STARTED || m_state == STATE_RUNNING ) {
2018-11-16 18:28:50 +01:00
// At this point of time the worker thread may be blocking on m_print->state_mutex().
// Set the print state to canceled before unlocking the state_mutex(), so when the worker thread wakes up,
// it throws the CanceledException().
2018-10-30 09:27:31 +01:00
m_print -> cancel_internal ();
2018-11-16 18:28:50 +01:00
// Allow the worker thread to wake up if blocking on a milestone.
m_print -> state_mutex (). unlock ();
2018-10-30 09:27:31 +01:00
// Wait until the background processing stops by being canceled.
m_condition . wait ( lck , [ this ](){ return m_state == STATE_CANCELED ; });
2018-11-16 18:28:50 +01:00
// Lock it back to be in a consistent state.
m_print -> state_mutex (). lock ();
2018-10-30 09:27:31 +01:00
}
// In the "Canceled" state. Reset the state to "Idle".
m_state = STATE_IDLE ;
m_print -> set_cancel_callback ([](){});
2018-11-13 17:45:44 +01:00
}
bool BackgroundSlicingProcess :: empty () const
{
assert ( m_print != nullptr );
return m_print -> empty ();
2018-10-30 09:27:31 +01:00
}
2018-11-08 20:18:40 +01:00
std :: string BackgroundSlicingProcess :: validate ()
2018-03-23 11:41:20 +01:00
{
2018-11-08 20:18:40 +01:00
assert ( m_print != nullptr );
return m_print -> validate ();
2018-03-23 11:41:20 +01:00
}
2018-10-18 18:06:40 +02:00
// 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.
2018-10-23 22:53:43 +02:00
Print :: ApplyStatus BackgroundSlicingProcess :: apply ( const Model & model , const DynamicPrintConfig & config )
2018-10-18 18:06:40 +02:00
{
2018-11-08 20:18:40 +01:00
assert ( m_print != nullptr );
assert ( config . opt_enum < PrinterTechnology > ( "printer_technology" ) == m_print -> technology ());
2018-10-23 22:53:43 +02:00
Print :: ApplyStatus invalidated = m_print -> apply ( model , config );
2020-03-02 15:13:23 +01:00
#if ENABLE_GCODE_VIEWER
if (( invalidated & PrintBase :: APPLY_STATUS_INVALIDATED ) != 0 && m_print -> technology () == ptFFF &&
! this -> m_fff_print -> is_step_done ( psGCodeExport ))
{
// Some FFF status was invalidated, and the G-code was not exported yet.
// Let the G-code preview UI know that the final G-code preview is not valid.
// In addition, this early memory deallocation reduces memory footprint.
2020-05-07 10:49:12 +02:00
if ( m_gcode_result != nullptr )
2020-03-02 15:13:23 +01:00
m_gcode_result -> reset ();
}
#else
2018-12-19 14:47:16 +01:00
if (( invalidated & PrintBase :: APPLY_STATUS_INVALIDATED ) != 0 && m_print -> technology () == ptFFF &&
m_gcode_preview_data != nullptr && ! this -> m_fff_print -> is_step_done ( psGCodeExport )) {
// Some FFF status was invalidated, and the G-code was not exported yet.
// Let the G-code preview UI know that the final G-code preview is not valid.
// In addition, this early memory deallocation reduces memory footprint.
m_gcode_preview_data -> reset ();
}
2020-03-02 15:13:23 +01:00
#endif // ENABLE_GCODE_VIEWER
2018-10-18 18:06:40 +02:00
return invalidated ;
}
2019-02-21 11:40:56 +01:00
void BackgroundSlicingProcess :: set_task ( const PrintBase :: TaskParams & params )
{
assert ( m_print != nullptr );
m_print -> set_task ( params );
}
2018-10-23 15:27:31 +02:00
// Set the output path of the G-code.
2020-03-12 12:43:01 +01:00
void BackgroundSlicingProcess :: schedule_export ( const std :: string & path , bool export_path_on_removable_media )
2018-10-23 15:27:31 +02:00
{
assert ( m_export_path . empty ());
if ( ! m_export_path . empty ())
return ;
// Guard against entering the export step before changing the export path.
2018-11-16 18:28:50 +01:00
tbb :: mutex :: scoped_lock lock ( m_print -> state_mutex ());
2018-10-23 15:27:31 +02:00
this -> invalidate_step ( bspsGCodeFinalize );
m_export_path = path ;
2020-03-12 12:43:01 +01:00
m_export_path_on_removable_media = export_path_on_removable_media ;
2018-10-23 15:27:31 +02:00
}
2018-12-11 10:33:11 +01:00
void BackgroundSlicingProcess :: schedule_upload ( Slic3r :: PrintHostJob upload_job )
{
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_print -> state_mutex ());
this -> invalidate_step ( bspsGCodeFinalize );
2018-12-19 14:47:16 +01:00
m_export_path . clear ();
2018-12-11 10:33:11 +01:00
m_upload_job = std :: move ( upload_job );
}
2018-10-23 15:27:31 +02:00
void BackgroundSlicingProcess :: reset_export ()
{
assert ( ! this -> running ());
if ( ! this -> running ()) {
m_export_path . clear ();
2020-03-12 12:43:01 +01:00
m_export_path_on_removable_media = false ;
2018-10-23 15:27:31 +02:00
// invalidate_step expects the mutex to be locked.
2018-11-16 18:28:50 +01:00
tbb :: mutex :: scoped_lock lock ( m_print -> state_mutex ());
2018-10-23 15:27:31 +02:00
this -> invalidate_step ( bspsGCodeFinalize );
}
}
2018-11-16 18:28:50 +01:00
bool BackgroundSlicingProcess :: set_step_started ( BackgroundSlicingProcessStep step )
2018-10-23 15:27:31 +02:00
{
2018-11-16 18:28:50 +01:00
return m_step_state . set_started ( step , m_print -> state_mutex (), [ this ](){ this -> throw_if_canceled (); });
2018-10-23 15:27:31 +02:00
}
void BackgroundSlicingProcess :: set_step_done ( BackgroundSlicingProcessStep step )
{
2018-11-16 18:28:50 +01:00
m_step_state . set_done ( step , m_print -> state_mutex (), [ this ](){ this -> throw_if_canceled (); });
}
bool BackgroundSlicingProcess :: is_step_done ( BackgroundSlicingProcessStep step ) const
{
return m_step_state . is_done ( step , m_print -> state_mutex ());
2018-10-23 15:27:31 +02:00
}
bool BackgroundSlicingProcess :: invalidate_step ( BackgroundSlicingProcessStep step )
{
2018-11-16 18:28:50 +01:00
bool invalidated = m_step_state . invalidate ( step , [ this ](){ this -> stop_internal (); });
2018-10-23 15:27:31 +02:00
return invalidated ;
}
bool BackgroundSlicingProcess :: invalidate_all_steps ()
{
2018-11-16 18:28:50 +01:00
return m_step_state . invalidate_all ([ this ](){ this -> stop_internal (); });
2018-10-23 15:27:31 +02:00
}
2018-12-20 16:35:54 +01:00
void BackgroundSlicingProcess :: prepare_upload ()
{
// A print host upload job has been scheduled, enqueue it to the printhost job queue
// XXX: is fs::path::string() right?
// Generate a unique temp path to which the gcode/zip file is copied/exported
boost :: filesystem :: path source_path = boost :: filesystem :: temp_directory_path ()
2019-04-15 16:14:19 +02:00
/ boost :: filesystem :: unique_path ( "." SLIC3R_APP_KEY ".upload.%%%%-%%%%-%%%%-%%%%" );
2018-12-20 16:35:54 +01:00
if ( m_print == m_fff_print ) {
2019-05-09 19:58:16 +02:00
m_print -> set_status ( 95 , _utf8 ( L ( "Running post-processing scripts" )));
2020-02-27 10:44:25 +01:00
if ( copy_file ( m_temp_output_path , source_path . string ()) != SUCCESS ) {
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( _utf8 ( L ( "Copying of the temporary G-code to the output G-code failed" )));
2018-12-20 16:35:54 +01:00
}
2019-01-29 08:57:00 +01:00
run_post_process_scripts ( source_path . string (), m_fff_print -> config ());
2019-10-23 17:10:14 +02:00
m_upload_job . upload_data . upload_path = m_fff_print -> print_statistics (). finalize_output_path ( m_upload_job . upload_data . upload_path . string ());
2019-03-15 12:34:58 +01:00
} else {
2019-10-23 17:10:14 +02:00
m_upload_job . upload_data . upload_path = m_sla_print -> print_statistics (). finalize_output_path ( m_upload_job . upload_data . upload_path . string ());
2020-04-13 12:31:37 +02:00
2019-10-23 17:10:14 +02:00
Zipper zipper { source_path . string ()};
2020-04-13 12:31:37 +02:00
m_sla_archive . export_print ( zipper , * m_sla_print , m_upload_job . upload_data . upload_path . string ());
2019-11-22 12:39:03 +01:00
if ( m_thumbnail_cb != nullptr )
2019-10-25 13:59:13 +02:00
{
2019-11-22 12:39:03 +01:00
ThumbnailsList thumbnails ;
2019-11-28 14:18:24 +01:00
m_thumbnail_cb ( thumbnails , current_print () -> full_print_config (). option < ConfigOptionPoints > ( "thumbnails" ) -> values , true , true , true , true );
// m_thumbnail_cb(thumbnails, current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, false, true, true); // renders also supports and pad
2019-11-22 12:39:03 +01:00
for ( const ThumbnailData & data : thumbnails )
2019-10-25 13:59:13 +02:00
{
if ( data . is_valid ())
write_thumbnail ( zipper , data );
}
}
2019-10-23 17:10:14 +02:00
zipper . finalize ();
2019-10-23 16:01:23 +02:00
}
2018-12-20 16:35:54 +01:00
2019-10-23 17:10:14 +02:00
m_print -> set_status ( 100 , ( boost :: format ( _utf8 ( L ( "Scheduling upload to `%1%`. See Window -> Print Host Upload Queue" ))) % m_upload_job . printhost -> get_host ()). str ());
2018-12-20 16:35:54 +01:00
m_upload_job . upload_data . source_path = std :: move ( source_path );
GUI :: wxGetApp (). printhost_job_queue (). enqueue ( std :: move ( m_upload_job ));
}
2018-03-23 11:41:20 +01:00
}; // namespace Slic3r