mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-11 16:57:53 -06:00
Improved time estimator post-processing
This commit is contained in:
parent
3f5511faa3
commit
9b550fbd5b
3 changed files with 134 additions and 111 deletions
|
@ -662,15 +662,19 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
||||||
throw std::runtime_error(msg);
|
throw std::runtime_error(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (print->config().remaining_times.value) {
|
GCodeTimeEstimator::PostProcessData normal_data = m_normal_time_estimator.get_post_process_data();
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for normal mode" << log_memory_info();
|
GCodeTimeEstimator::PostProcessData silent_data = m_silent_time_estimator.get_post_process_data();
|
||||||
m_normal_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
|
|
||||||
|
bool remaining_times_enabled = print->config().remaining_times.value;
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "Time estimator post processing" << log_memory_info();
|
||||||
|
GCodeTimeEstimator::post_process(path_tmp, 60.0f, remaining_times_enabled ? &normal_data : nullptr, (remaining_times_enabled && m_silent_time_estimator_enabled) ? &silent_data : nullptr);
|
||||||
|
|
||||||
|
if (remaining_times_enabled)
|
||||||
|
{
|
||||||
m_normal_time_estimator.reset();
|
m_normal_time_estimator.reset();
|
||||||
if (m_silent_time_estimator_enabled) {
|
if (m_silent_time_estimator_enabled)
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for silent mode" << log_memory_info();
|
|
||||||
m_silent_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
|
|
||||||
m_silent_time_estimator.reset();
|
m_silent_time_estimator.reset();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// starts analyzer calculations
|
// starts analyzer calculations
|
||||||
|
|
|
@ -173,9 +173,7 @@ namespace Slic3r {
|
||||||
const std::string GCodeTimeEstimator::Normal_Last_M73_Output_Placeholder_Tag = "; _TE_NORMAL_LAST_M73_OUTPUT_PLACEHOLDER";
|
const std::string GCodeTimeEstimator::Normal_Last_M73_Output_Placeholder_Tag = "; _TE_NORMAL_LAST_M73_OUTPUT_PLACEHOLDER";
|
||||||
const std::string GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag = "; _TE_SILENT_LAST_M73_OUTPUT_PLACEHOLDER";
|
const std::string GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag = "; _TE_SILENT_LAST_M73_OUTPUT_PLACEHOLDER";
|
||||||
|
|
||||||
// temporary human readable form to use until not removed from gcode by the new post-process method
|
|
||||||
const std::string GCodeTimeEstimator::Color_Change_Tag = "PRINT_COLOR_CHANGE";
|
const std::string GCodeTimeEstimator::Color_Change_Tag = "PRINT_COLOR_CHANGE";
|
||||||
// const std::string GCodeTimeEstimator::Color_Change_Tag = "_TE_COLOR_CHANGE";
|
|
||||||
|
|
||||||
GCodeTimeEstimator::GCodeTimeEstimator(EMode mode)
|
GCodeTimeEstimator::GCodeTimeEstimator(EMode mode)
|
||||||
: m_mode(mode)
|
: m_mode(mode)
|
||||||
|
@ -273,130 +271,138 @@ namespace Slic3r {
|
||||||
#endif // ENABLE_MOVE_STATS
|
#endif // ENABLE_MOVE_STATS
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCodeTimeEstimator::post_process_remaining_times(const std::string& filename, float interval)
|
bool GCodeTimeEstimator::post_process(const std::string& filename, float interval_sec, const PostProcessData* const normal_mode, const PostProcessData* const silent_mode)
|
||||||
{
|
{
|
||||||
boost::nowide::ifstream in(filename);
|
boost::nowide::ifstream in(filename);
|
||||||
if (!in.good())
|
if (!in.good())
|
||||||
throw std::runtime_error(std::string("Remaining times export failed.\nCannot open file for reading.\n"));
|
throw std::runtime_error(std::string("Time estimator post process export failed.\nCannot open file for reading.\n"));
|
||||||
|
|
||||||
std::string path_tmp = filename + ".times";
|
std::string path_tmp = filename + ".postprocess";
|
||||||
|
|
||||||
FILE* out = boost::nowide::fopen(path_tmp.c_str(), "wb");
|
FILE* out = boost::nowide::fopen(path_tmp.c_str(), "wb");
|
||||||
if (out == nullptr)
|
if (out == nullptr)
|
||||||
throw std::runtime_error(std::string("Remaining times export failed.\nCannot open file for writing.\n"));
|
throw std::runtime_error(std::string("Time estimator post process export failed.\nCannot open file for writing.\n"));
|
||||||
|
|
||||||
std::string time_mask;
|
std::string normal_time_mask = "M73 P%s R%s\n";
|
||||||
switch (m_mode)
|
std::string silent_time_mask = "M73 Q%s S%s\n";
|
||||||
{
|
char line_M73[64];
|
||||||
default:
|
|
||||||
case Normal:
|
|
||||||
{
|
|
||||||
time_mask = "M73 P%s R%s\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Silent:
|
|
||||||
{
|
|
||||||
time_mask = "M73 Q%s S%s\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int g1_lines_count = 0;
|
|
||||||
float last_recorded_time = 0.0f;
|
|
||||||
std::string gcode_line;
|
std::string gcode_line;
|
||||||
// buffer line to export only when greater than 64K to reduce writing calls
|
// buffer line to export only when greater than 64K to reduce writing calls
|
||||||
std::string export_line;
|
std::string export_line;
|
||||||
char time_line[64];
|
|
||||||
G1LineIdToBlockIdMap::const_iterator it_line_id = m_g1_line_ids.begin();
|
|
||||||
while (std::getline(in, gcode_line))
|
|
||||||
{
|
|
||||||
if (!in.good())
|
|
||||||
{
|
|
||||||
fclose(out);
|
|
||||||
throw std::runtime_error(std::string("Remaining times export failed.\nError while reading from file.\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// replaces placeholders for initial line M73 with the real lines
|
// helper function to write to disk
|
||||||
if (((m_mode == Normal) && (gcode_line == Normal_First_M73_Output_Placeholder_Tag)) ||
|
auto write_string = [&](const std::string& str) {
|
||||||
((m_mode == Silent) && (gcode_line == Silent_First_M73_Output_Placeholder_Tag)))
|
|
||||||
{
|
|
||||||
sprintf(time_line, time_mask.c_str(), "0", _get_time_minutes(m_time).c_str());
|
|
||||||
gcode_line = time_line;
|
|
||||||
}
|
|
||||||
// replaces placeholders for final line M73 with the real lines
|
|
||||||
else if (((m_mode == Normal) && (gcode_line == Normal_Last_M73_Output_Placeholder_Tag)) ||
|
|
||||||
((m_mode == Silent) && (gcode_line == Silent_Last_M73_Output_Placeholder_Tag)))
|
|
||||||
{
|
|
||||||
sprintf(time_line, time_mask.c_str(), "100", "0");
|
|
||||||
gcode_line = time_line;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
gcode_line += "\n";
|
|
||||||
|
|
||||||
|
|
||||||
// add remaining time lines where needed
|
|
||||||
m_parser.parse_line(gcode_line,
|
|
||||||
[this, &it_line_id, &g1_lines_count, &last_recorded_time, &time_line, &gcode_line, time_mask, interval](GCodeReader& reader, const GCodeReader::GCodeLine& line)
|
|
||||||
{
|
|
||||||
if (line.cmd_is("G1"))
|
|
||||||
{
|
|
||||||
++g1_lines_count;
|
|
||||||
|
|
||||||
assert(it_line_id == m_g1_line_ids.end() || it_line_id->first >= g1_lines_count);
|
|
||||||
|
|
||||||
const Block *block = nullptr;
|
|
||||||
if (it_line_id != m_g1_line_ids.end() && it_line_id->first == g1_lines_count) {
|
|
||||||
if (line.has_e() && it_line_id->second < (unsigned int)m_blocks.size())
|
|
||||||
block = &m_blocks[it_line_id->second];
|
|
||||||
++it_line_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (block != nullptr && block->elapsed_time != -1.0f) {
|
|
||||||
float block_remaining_time = m_time - block->elapsed_time;
|
|
||||||
if (std::abs(last_recorded_time - block_remaining_time) > interval)
|
|
||||||
{
|
|
||||||
sprintf(time_line, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / m_time)).c_str(), _get_time_minutes(block_remaining_time).c_str());
|
|
||||||
gcode_line += time_line;
|
|
||||||
|
|
||||||
last_recorded_time = block_remaining_time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export_line += gcode_line;
|
|
||||||
if (export_line.length() > 65535)
|
|
||||||
{
|
|
||||||
fwrite((const void*)export_line.c_str(), 1, export_line.length(), out);
|
|
||||||
if (ferror(out))
|
|
||||||
{
|
|
||||||
in.close();
|
|
||||||
fclose(out);
|
|
||||||
boost::nowide::remove(path_tmp.c_str());
|
|
||||||
throw std::runtime_error(std::string("Remaining times export failed.\nIs the disk full?\n"));
|
|
||||||
}
|
|
||||||
export_line.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (export_line.length() > 0)
|
|
||||||
{
|
|
||||||
fwrite((const void*)export_line.c_str(), 1, export_line.length(), out);
|
fwrite((const void*)export_line.c_str(), 1, export_line.length(), out);
|
||||||
if (ferror(out))
|
if (ferror(out))
|
||||||
{
|
{
|
||||||
in.close();
|
in.close();
|
||||||
fclose(out);
|
fclose(out);
|
||||||
boost::nowide::remove(path_tmp.c_str());
|
boost::nowide::remove(path_tmp.c_str());
|
||||||
throw std::runtime_error(std::string("Remaining times export failed.\nIs the disk full?\n"));
|
throw std::runtime_error(std::string("Time estimator post process export failed.\nIs the disk full?\n"));
|
||||||
}
|
}
|
||||||
|
export_line.clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
GCodeReader parser;
|
||||||
|
unsigned int g1_lines_count = 0;
|
||||||
|
int normal_g1_line_id = 0;
|
||||||
|
float normal_last_recorded_time = 0.0f;
|
||||||
|
int silent_g1_line_id = 0;
|
||||||
|
float silent_last_recorded_time = 0.0f;
|
||||||
|
|
||||||
|
// helper function to process g1 lines
|
||||||
|
auto process_g1_line = [&](const PostProcessData* const data, const GCodeReader::GCodeLine& line, int& g1_line_id, float& last_recorded_time, const std::string& time_mask) {
|
||||||
|
if (data == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert((g1_line_id >= (int)data->g1_line_ids.size()) || (data->g1_line_ids[g1_line_id].first >= g1_lines_count));
|
||||||
|
const Block* block = nullptr;
|
||||||
|
const G1LineIdToBlockId& map_item = data->g1_line_ids[g1_line_id];
|
||||||
|
if ((g1_line_id < (int)data->g1_line_ids.size()) && (map_item.first == g1_lines_count))
|
||||||
|
{
|
||||||
|
if (line.has_e() && (map_item.second < (unsigned int)data->blocks.size()))
|
||||||
|
block = &data->blocks[map_item.second];
|
||||||
|
++g1_line_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((block != nullptr) && (block->elapsed_time != -1.0f))
|
||||||
|
{
|
||||||
|
float block_remaining_time = data->time - block->elapsed_time;
|
||||||
|
if (std::abs(last_recorded_time - block_remaining_time) > interval_sec)
|
||||||
|
{
|
||||||
|
sprintf(line_M73, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / data->time)).c_str(), _get_time_minutes(block_remaining_time).c_str());
|
||||||
|
gcode_line += line_M73;
|
||||||
|
|
||||||
|
last_recorded_time = block_remaining_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
while (std::getline(in, gcode_line))
|
||||||
|
{
|
||||||
|
if (!in.good())
|
||||||
|
{
|
||||||
|
fclose(out);
|
||||||
|
throw std::runtime_error(std::string("Time estimator post process export failed.\nError while reading from file.\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// check tags
|
||||||
|
// remove color change tag
|
||||||
|
if (gcode_line == "; " + Color_Change_Tag)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// replaces placeholders for initial line M73 with the real lines
|
||||||
|
if ((normal_mode != nullptr) && (gcode_line == Normal_First_M73_Output_Placeholder_Tag))
|
||||||
|
{
|
||||||
|
sprintf(line_M73, normal_time_mask.c_str(), "0", _get_time_minutes(normal_mode->time).c_str());
|
||||||
|
gcode_line = line_M73;
|
||||||
|
}
|
||||||
|
else if ((silent_mode != nullptr) && (gcode_line == Silent_First_M73_Output_Placeholder_Tag))
|
||||||
|
{
|
||||||
|
sprintf(line_M73, silent_time_mask.c_str(), "0", _get_time_minutes(silent_mode->time).c_str());
|
||||||
|
gcode_line = line_M73;
|
||||||
|
}
|
||||||
|
// replaces placeholders for final line M73 with the real lines
|
||||||
|
else if ((normal_mode != nullptr) && (gcode_line == Normal_Last_M73_Output_Placeholder_Tag))
|
||||||
|
{
|
||||||
|
sprintf(line_M73, normal_time_mask.c_str(), "100", "0");
|
||||||
|
gcode_line = line_M73;
|
||||||
|
}
|
||||||
|
else if ((silent_mode != nullptr) && (gcode_line == Silent_Last_M73_Output_Placeholder_Tag))
|
||||||
|
{
|
||||||
|
sprintf(line_M73, silent_time_mask.c_str(), "100", "0");
|
||||||
|
gcode_line = line_M73;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gcode_line += "\n";
|
||||||
|
|
||||||
|
// add remaining time lines where needed
|
||||||
|
parser.parse_line(gcode_line,
|
||||||
|
[&](GCodeReader& reader, const GCodeReader::GCodeLine& line)
|
||||||
|
{
|
||||||
|
if (line.cmd_is("G1"))
|
||||||
|
{
|
||||||
|
++g1_lines_count;
|
||||||
|
process_g1_line(silent_mode, line, silent_g1_line_id, silent_last_recorded_time, silent_time_mask);
|
||||||
|
process_g1_line(normal_mode, line, normal_g1_line_id, normal_last_recorded_time, normal_time_mask);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export_line += gcode_line;
|
||||||
|
if (export_line.length() > 65535)
|
||||||
|
write_string(export_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!export_line.empty())
|
||||||
|
write_string(export_line);
|
||||||
|
|
||||||
fclose(out);
|
fclose(out);
|
||||||
in.close();
|
in.close();
|
||||||
|
|
||||||
if (rename_file(path_tmp, filename))
|
if (rename_file(path_tmp, filename))
|
||||||
throw std::runtime_error(std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + filename + '\n' +
|
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');
|
"Is " + path_tmp + " locked?" + '\n');
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,9 +213,19 @@ namespace Slic3r {
|
||||||
typedef std::map<Block::EMoveType, MoveStats> MovesStatsMap;
|
typedef std::map<Block::EMoveType, MoveStats> MovesStatsMap;
|
||||||
#endif // ENABLE_MOVE_STATS
|
#endif // ENABLE_MOVE_STATS
|
||||||
|
|
||||||
|
public:
|
||||||
typedef std::pair<unsigned int, unsigned int> G1LineIdToBlockId;
|
typedef std::pair<unsigned int, unsigned int> G1LineIdToBlockId;
|
||||||
typedef std::vector<G1LineIdToBlockId> G1LineIdToBlockIdMap;
|
typedef std::vector<G1LineIdToBlockId> G1LineIdToBlockIdMap;
|
||||||
|
|
||||||
|
struct PostProcessData
|
||||||
|
{
|
||||||
|
const G1LineIdToBlockIdMap& g1_line_ids;
|
||||||
|
const BlocksList& blocks;
|
||||||
|
float time;
|
||||||
|
|
||||||
|
PostProcessData(const G1LineIdToBlockIdMap& g1_line_ids, const BlocksList& blocks, float time) : g1_line_ids(g1_line_ids), blocks(blocks), time(time) {}
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EMode m_mode;
|
EMode m_mode;
|
||||||
GCodeReader m_parser;
|
GCodeReader m_parser;
|
||||||
|
@ -263,11 +273,12 @@ namespace Slic3r {
|
||||||
void calculate_time_from_lines(const std::vector<std::string>& gcode_lines);
|
void calculate_time_from_lines(const std::vector<std::string>& gcode_lines);
|
||||||
|
|
||||||
// Process the gcode contained in the file with the given filename,
|
// Process the gcode contained in the file with the given filename,
|
||||||
// placing in it new lines (M73) containing the remaining time, at the given interval in seconds
|
// replacing placeholders with correspondent new lines M73
|
||||||
// and saving the result back in the same file
|
// placing new lines M73 (containing the remaining time) where needed (in dependence of the given interval in seconds)
|
||||||
// This time estimator should have been already used to calculate the time estimate for the gcode
|
// and removing working tags (as those used for color changes)
|
||||||
// contained in the given file before to call this method
|
// if normal_mode == nullptr no M73 line will be added for normal mode
|
||||||
bool post_process_remaining_times(const std::string& filename, float interval_sec);
|
// if silent_mode == nullptr no M73 line will be added for silent mode
|
||||||
|
static bool post_process(const std::string& filename, float interval_sec, const PostProcessData* const normal_mode, const PostProcessData* const silent_mode);
|
||||||
|
|
||||||
// Set current position on the given axis with the given value
|
// Set current position on the given axis with the given value
|
||||||
void set_axis_position(EAxis axis, float position);
|
void set_axis_position(EAxis axis, float position);
|
||||||
|
@ -362,6 +373,8 @@ namespace Slic3r {
|
||||||
// Return an estimate of the memory consumed by the time estimator.
|
// Return an estimate of the memory consumed by the time estimator.
|
||||||
size_t memory_used() const;
|
size_t memory_used() const;
|
||||||
|
|
||||||
|
PostProcessData get_post_process_data() const { return PostProcessData(m_g1_line_ids, m_blocks, m_time); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _reset();
|
void _reset();
|
||||||
void _reset_time();
|
void _reset_time();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue