mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-08 23:46:24 -06:00
ENH: CLI: refine logic
1. return error when there is object partly inside the plate; 2. add the status callback for progress indicating 3. add the version in help 4. fix the return state of validation from 1 to -51 Change-Id: I716057bd5b28a4beb2871614b94708a0860af1a2
This commit is contained in:
parent
8278be8d26
commit
55f55e3ad9
2 changed files with 209 additions and 6 deletions
|
@ -22,6 +22,13 @@
|
|||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
|
||||
#if defined(__linux__) || defined(__LINUX__)
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <boost/thread.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/nowide/args.hpp>
|
||||
|
@ -98,6 +105,8 @@ using namespace Slic3r;
|
|||
|
||||
#define CLI_NO_SUITABLE_OBJECTS -50
|
||||
#define CLI_VALIDATE_ERROR -51
|
||||
#define CLI_OBJECTS_PARTLY_INSIDE -52
|
||||
|
||||
#define CLI_SLICING_ERROR -100
|
||||
|
||||
|
||||
|
@ -122,6 +131,155 @@ std::map<int, std::string> cli_errors = {
|
|||
{CLI_SLICING_ERROR, "Slice error"}
|
||||
};
|
||||
|
||||
#if defined(__linux__) || defined(__LINUX__)
|
||||
#define PIPE_BUFFER_SIZE 64
|
||||
|
||||
typedef struct _cli_callback_mgr {
|
||||
int m_plate_count {0};
|
||||
int m_plate_index;
|
||||
int m_progress { 0 };
|
||||
std::string m_message;
|
||||
int m_warning_step;
|
||||
bool m_exit {false};
|
||||
bool m_data_ready {false};
|
||||
bool m_started {false};
|
||||
boost::thread m_thread;
|
||||
// Mutex and condition variable to synchronize m_thread with the UI thread.
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_condition;
|
||||
int m_pipe_fd{-1};
|
||||
|
||||
bool is_started()
|
||||
{
|
||||
bool result;
|
||||
std::unique_lock<std::mutex> lck(m_mutex);
|
||||
result = m_started;
|
||||
lck.unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void set_plate_info(int index, int count)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(m_mutex);
|
||||
m_plate_count = count;
|
||||
m_plate_index = index;
|
||||
lck.unlock();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void notify()
|
||||
{
|
||||
if (m_pipe_fd < 0)
|
||||
return;
|
||||
|
||||
std::string notify_message;
|
||||
notify_message = "Plate "+ std::to_string(m_plate_index) + "/" +std::to_string(m_plate_count)+ ": Percent " + std::to_string(m_progress) + ": "+m_message;
|
||||
|
||||
char pipe_message[PIPE_BUFFER_SIZE] = {0};
|
||||
strncpy(pipe_message, notify_message.c_str(), PIPE_BUFFER_SIZE);
|
||||
|
||||
int ret = write(m_pipe_fd, pipe_message,PIPE_BUFFER_SIZE);
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": write returns "<<ret;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void thread_proc()
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(m_mutex);
|
||||
m_started = true;
|
||||
m_data_ready = false;
|
||||
lck.unlock();
|
||||
m_condition.notify_one();
|
||||
BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::thread_proc started.";
|
||||
while(1) {
|
||||
lck.lock();
|
||||
m_condition.wait(lck, [this](){ return m_data_ready || m_exit; });
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": wakup.";
|
||||
if (m_exit) {
|
||||
BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::thread_proc will exit.";
|
||||
break;
|
||||
}
|
||||
notify();
|
||||
m_data_ready = false;
|
||||
lck.unlock();
|
||||
m_condition.notify_one();
|
||||
}
|
||||
lck.unlock();
|
||||
BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::thread_proc exit.";
|
||||
}
|
||||
|
||||
void update(int percent, std::string message, int warning_step)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": percent="<<percent<< ", warning_step = "<< m_warning_step<<", message="<<message;
|
||||
std::unique_lock<std::mutex> lck(m_mutex);
|
||||
if (!m_started) {
|
||||
lck.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_progress >= percent) {
|
||||
//already update before
|
||||
lck.unlock();
|
||||
return;
|
||||
}
|
||||
m_message = message;
|
||||
m_progress = percent;
|
||||
m_warning_step = warning_step;
|
||||
m_data_ready = true;
|
||||
lck.unlock();
|
||||
m_condition.notify_one();
|
||||
return;
|
||||
}
|
||||
|
||||
bool start(std::string pipe_name)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::start enter.";
|
||||
m_pipe_fd = open(pipe_name.c_str(),O_WRONLY|O_NONBLOCK);
|
||||
if (m_pipe_fd < 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << "could not create pipe for "<<pipe_name;
|
||||
return false;
|
||||
}
|
||||
std::unique_lock<std::mutex> lck(m_mutex);
|
||||
m_thread = create_thread([this]{
|
||||
this->thread_proc();
|
||||
});
|
||||
lck.unlock();
|
||||
BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::start successfully.";
|
||||
return true;
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::stop enter.";
|
||||
std::unique_lock<std::mutex> lck(m_mutex);
|
||||
if (m_pipe_fd > 0) {
|
||||
close(m_pipe_fd);
|
||||
m_pipe_fd = -1;
|
||||
}
|
||||
if (!m_started) {
|
||||
lck.unlock();
|
||||
return;
|
||||
}
|
||||
m_exit = true;
|
||||
lck.unlock();
|
||||
m_condition.notify_one();
|
||||
// Wait until the worker thread exits.
|
||||
m_thread.join();
|
||||
BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::stop successfully.";
|
||||
}
|
||||
}cli_callback_mgr_t;
|
||||
|
||||
cli_callback_mgr_t g_cli_callback_mgr;
|
||||
|
||||
void cli_status_callback(const PrintBase::SlicingStatus& slicing_status)
|
||||
{
|
||||
g_cli_callback_mgr.update(slicing_status.percent, slicing_status.text, slicing_status.warning_step);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static PrinterTechnology get_printer_technology(const DynamicConfig &config)
|
||||
{
|
||||
|
@ -130,10 +288,18 @@ static PrinterTechnology get_printer_technology(const DynamicConfig &config)
|
|||
}
|
||||
|
||||
//BBS: add flush and exit
|
||||
#if defined(__linux__) || defined(__LINUX__)
|
||||
#define flush_and_exit(ret) { boost::nowide::cout << __FUNCTION__ << " found error, return "<<ret<<", exit..." << std::endl;\
|
||||
g_cli_callback_mgr.stop();\
|
||||
boost::nowide::cout.flush();\
|
||||
boost::nowide::cerr.flush();\
|
||||
return(ret);}
|
||||
#else
|
||||
#define flush_and_exit(ret) { boost::nowide::cout << __FUNCTION__ << " found error, exit" << std::endl;\
|
||||
boost::nowide::cout.flush();\
|
||||
boost::nowide::cerr.flush();\
|
||||
return(ret);}
|
||||
#endif
|
||||
|
||||
static void glfw_callback(int error_code, const char* description)
|
||||
{
|
||||
|
@ -604,7 +770,7 @@ int CLI::run(int argc, char **argv)
|
|||
m_print_config.apply(fff_print_config, true);
|
||||
} else {
|
||||
boost::nowide::cerr << "invalid printer_technology " << std::endl;
|
||||
flush_and_exit(1);
|
||||
flush_and_exit(CLI_INVALID_PRINTER_TECH);
|
||||
/*assert(printer_technology == ptSLA);
|
||||
sla_print_config.filename_format.value = "[input_filename_base].sl1";
|
||||
|
||||
|
@ -1050,6 +1216,11 @@ int CLI::run(int argc, char **argv)
|
|||
this->print_help(true, ptFFF);
|
||||
} else if (opt_key == "help_sla") {
|
||||
this->print_help(true, ptSLA);
|
||||
} else if (opt_key == "pipe") {
|
||||
#if defined(__linux__) || defined(__LINUX__)
|
||||
std::string pipe_name = m_config.option<ConfigOptionString>("pipe")->value;
|
||||
g_cli_callback_mgr.start(pipe_name);
|
||||
#endif
|
||||
} else if (opt_key == "export_settings") {
|
||||
//FIXME check for mixing the FFF / SLA parameters.
|
||||
// or better save fff_print_config vs. sla_print_config
|
||||
|
@ -1147,6 +1318,20 @@ int CLI::run(int argc, char **argv)
|
|||
BuildVolume build_volume(part_plate->get_shape(), print_height);
|
||||
model.update_print_volume_state(build_volume);
|
||||
unsigned int count = model.update_print_volume_state(build_volume);
|
||||
|
||||
if (count == 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Nothing to be sliced, Either the print is empty or no object is fully inside the print volume before apply." << std::endl;
|
||||
flush_and_exit(CLI_NO_SUITABLE_OBJECTS);
|
||||
}
|
||||
else {
|
||||
for (ModelObject* model_object : model.objects)
|
||||
for (ModelInstance *i : model_object->instances)
|
||||
if (i->print_volume_state == ModelInstancePVS_Partly_Outside)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Found Object " << model_object->name <<" partly inside, can not be sliced." << std::endl;
|
||||
flush_and_exit(CLI_OBJECTS_PARTLY_INSIDE);
|
||||
}
|
||||
}
|
||||
// BBS: TODO
|
||||
//BOOST_LOG_TRIVIAL(info) << boost::format("print_volume {%1%,%2%,%3%}->{%4%, %5%, %6%}, has %7% printables") % print_volume.min(0) % print_volume.min(1)
|
||||
// % print_volume.min(2) % print_volume.max(0) % print_volume.max(1) % print_volume.max(2) % count << std::endl;
|
||||
|
@ -1178,19 +1363,27 @@ int CLI::run(int argc, char **argv)
|
|||
boost::nowide::cerr << err.string << std::endl;
|
||||
//BBS: continue for other plates
|
||||
//continue;
|
||||
flush_and_exit(1);
|
||||
flush_and_exit(CLI_VALIDATE_ERROR);
|
||||
}
|
||||
else if (!warning.string.empty())
|
||||
BOOST_LOG_TRIVIAL(info) << "got warnings: "<< warning.string << std::endl;
|
||||
|
||||
if (print->empty()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Nothing to be sliced, Either the print is empty or no object is fully inside the print volume." << std::endl;
|
||||
BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Nothing to be sliced, Either the print is empty or no object is fully inside the print volume after apply." << std::endl;
|
||||
flush_and_exit(CLI_NO_SUITABLE_OBJECTS);
|
||||
}
|
||||
else
|
||||
try {
|
||||
std::string outfile_final;
|
||||
BOOST_LOG_TRIVIAL(info) << "start Print::process for partplate "<<index << std::endl;
|
||||
BOOST_LOG_TRIVIAL(info) << "start Print::process for partplate "<<index+1 << std::endl;
|
||||
#if defined(__linux__) || defined(__LINUX__)
|
||||
BOOST_LOG_TRIVIAL(info) << "cli callback mgr started: "<<g_cli_callback_mgr.m_started << std::endl;
|
||||
if (g_cli_callback_mgr.is_started()) {
|
||||
BOOST_LOG_TRIVIAL(info) << "set print's callback to cli_status_callback.";
|
||||
print->set_status_callback(cli_status_callback);
|
||||
g_cli_callback_mgr.set_plate_info(index+1, (plate_to_slice== 0)?partplate_list.get_plate_count():1);
|
||||
}
|
||||
#endif
|
||||
print->process();
|
||||
if (printer_technology == ptFFF) {
|
||||
// The outfile is processed by a PlaceholderParser.
|
||||
|
@ -1225,7 +1418,7 @@ int CLI::run(int argc, char **argv)
|
|||
BOOST_LOG_TRIVIAL(info) << "Slicing result exported to " << outfile << std::endl;
|
||||
part_plate->update_slice_result_valid_state(true);
|
||||
} catch (const std::exception &ex) {
|
||||
BOOST_LOG_TRIVIAL(info) << "found slicing or export error for partplate "<<index << std::endl;
|
||||
BOOST_LOG_TRIVIAL(info) << "found slicing or export error for partplate "<<index+1 << std::endl;
|
||||
boost::nowide::cerr << ex.what() << std::endl;
|
||||
//continue;
|
||||
flush_and_exit(CLI_SLICING_ERROR);
|
||||
|
@ -1512,6 +1705,10 @@ int CLI::run(int argc, char **argv)
|
|||
glfwTerminate();
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__LINUX__)
|
||||
g_cli_callback_mgr.stop();
|
||||
#endif
|
||||
|
||||
//BBS: flush logs
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", Finished" << std::endl;
|
||||
boost::nowide::cout.flush();
|
||||
|
@ -1630,7 +1827,7 @@ bool CLI::setup(int argc, char **argv)
|
|||
void CLI::print_help(bool include_print_options, PrinterTechnology printer_technology) const
|
||||
{
|
||||
boost::nowide::cout
|
||||
<< SLIC3R_BUILD_ID << ":"
|
||||
<< SLIC3R_APP_KEY <<"-"<< SLIC3R_VERSION << ":"
|
||||
<< std::endl
|
||||
<< "Usage: bambu-studio [ OPTIONS ] [ file.3mf/file.stl ... ]" << std::endl
|
||||
<< std::endl
|
||||
|
|
|
@ -4342,6 +4342,12 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
|||
def->tooltip = L("Export settings to a file.");
|
||||
def->cli_params = "settings.json";
|
||||
def->set_default_value(new ConfigOptionString("output.json"));
|
||||
|
||||
def = this->add("pipe", coString);
|
||||
def->label = L("Send progress to pipe");
|
||||
def->tooltip = L("Send progress to pipe.");
|
||||
def->cli_params = "pipename";
|
||||
def->set_default_value(new ConfigOptionString("cli_pipe"));
|
||||
}
|
||||
|
||||
//BBS: remove unused command currently
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue