Modify gcode post-process to allow to insert new gcode lines by backtracing from the current processed line.
Current state is a prototype and the new code is embedded into a new tech: ENABLE_GCODE_POSTPROCESS_BACKTRACE
This commit is contained in:
parent
80e0666401
commit
c9724ae6fd
@ -441,6 +441,9 @@ void GCodeProcessorResult::reset() {
|
|||||||
max_print_height = 0.0f;
|
max_print_height = 0.0f;
|
||||||
settings_ids.reset();
|
settings_ids.reset();
|
||||||
extruders_count = 0;
|
extruders_count = 0;
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
backtrace_enabled = false;
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
extruder_colors = std::vector<std::string>();
|
extruder_colors = std::vector<std::string>();
|
||||||
filament_diameters = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
|
filament_diameters = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
|
||||||
filament_densities = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
|
filament_densities = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
|
||||||
@ -458,6 +461,9 @@ void GCodeProcessorResult::reset() {
|
|||||||
max_print_height = 0.0f;
|
max_print_height = 0.0f;
|
||||||
settings_ids.reset();
|
settings_ids.reset();
|
||||||
extruders_count = 0;
|
extruders_count = 0;
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
backtrace_enabled = false;
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
extruder_colors = std::vector<std::string>();
|
extruder_colors = std::vector<std::string>();
|
||||||
filament_diameters = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
|
filament_diameters = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
|
||||||
filament_densities = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
|
filament_densities = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
|
||||||
@ -551,6 +557,11 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
|||||||
m_producer = EProducer::PrusaSlicer;
|
m_producer = EProducer::PrusaSlicer;
|
||||||
m_flavor = config.gcode_flavor;
|
m_flavor = config.gcode_flavor;
|
||||||
|
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
m_result.backtrace_enabled = config.printer_model.value == "MK3MMU2" || config.printer_model.value == "MK3SMMU2S" ||
|
||||||
|
config.printer_model.value == "MK2.5MMU2" || config.printer_model.value == "MK2.5SMMU2S" || config.printer_model.value == "MK2SMM";
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
|
||||||
size_t extruders_count = config.nozzle_diameter.values.size();
|
size_t extruders_count = config.nozzle_diameter.values.size();
|
||||||
m_result.extruders_count = extruders_count;
|
m_result.extruders_count = extruders_count;
|
||||||
|
|
||||||
@ -3461,18 +3472,259 @@ void GCodeProcessor::post_process()
|
|||||||
last_exported_stop[i] = time_in_minutes(m_time_processor.machines[i].time);
|
last_exported_stop[i] = time_in_minutes(m_time_processor.machines[i].time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
// Helper class to modify and export gcode to file
|
||||||
|
class ExportLines
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Backtrace
|
||||||
|
{
|
||||||
|
float time{ 60.0f };
|
||||||
|
unsigned int steps{ 10 };
|
||||||
|
float time_step() const { return time / float(steps); }
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class EWriteType
|
||||||
|
{
|
||||||
|
BySize,
|
||||||
|
ByTime
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct LineData
|
||||||
|
{
|
||||||
|
std::string line;
|
||||||
|
float time;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
class Statistics
|
||||||
|
{
|
||||||
|
ExportLines& m_parent;
|
||||||
|
size_t m_max_size{ 0 };
|
||||||
|
size_t m_lines_count{ 0 };
|
||||||
|
size_t m_max_lines_count{ 0 };
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Statistics(ExportLines& parent)
|
||||||
|
: m_parent(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void add_line(size_t line_size) {
|
||||||
|
++m_lines_count;
|
||||||
|
m_max_size = std::max(m_max_size, m_parent.get_size() + line_size);
|
||||||
|
m_max_lines_count = std::max(m_max_lines_count, m_lines_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_line() { --m_lines_count; }
|
||||||
|
void remove_all_lines() { m_lines_count = 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
Statistics m_statistics;
|
||||||
|
#endif // NDEBUG
|
||||||
|
|
||||||
|
EWriteType m_write_type{ EWriteType::BySize };
|
||||||
|
// Time machine containing g1 times cache
|
||||||
|
TimeMachine& m_machine;
|
||||||
|
// Current time
|
||||||
|
float m_time{ 0.0f };
|
||||||
|
// Current size in bytes
|
||||||
|
size_t m_size{ 0 };
|
||||||
|
|
||||||
|
// gcode lines cache
|
||||||
|
std::deque<LineData> m_lines;
|
||||||
|
size_t m_added_lines_counter{ 0 };
|
||||||
|
// map of gcode line ids from original to final
|
||||||
|
// used to update m_result.moves[].gcode_id
|
||||||
|
std::vector<std::pair<size_t, size_t>> m_gcode_lines_map;
|
||||||
|
|
||||||
|
size_t m_curr_g1_id{ 0 };
|
||||||
|
size_t m_out_file_pos{ 0 };
|
||||||
|
|
||||||
|
public:
|
||||||
|
ExportLines(EWriteType type, TimeMachine& machine)
|
||||||
|
#ifndef NDEBUG
|
||||||
|
: m_statistics(*this), m_write_type(type), m_machine(machine) {}
|
||||||
|
#else
|
||||||
|
: m_write_type(type), m_machine(machine) {}
|
||||||
|
#endif // NDEBUG
|
||||||
|
|
||||||
|
void update(size_t lines_counter, size_t g1_lines_counter) {
|
||||||
|
m_gcode_lines_map.push_back({ lines_counter, 0 });
|
||||||
|
|
||||||
|
if (g1_lines_counter == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto init_it = m_machine.g1_times_cache.begin() + m_curr_g1_id;
|
||||||
|
auto it = init_it;
|
||||||
|
while (it != m_machine.g1_times_cache.end() && it->id < g1_lines_counter + 1) {
|
||||||
|
++it;
|
||||||
|
++m_curr_g1_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it != init_it || m_curr_g1_id == 0)
|
||||||
|
m_time = it->elapsed_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the given gcode line to the cache
|
||||||
|
void append_line(const std::string& line) {
|
||||||
|
m_lines.push_back({ line, m_time });
|
||||||
|
#ifndef NDEBUG
|
||||||
|
m_statistics.add_line(line.length());
|
||||||
|
#endif // NDEBUG
|
||||||
|
m_size += line.length();
|
||||||
|
++m_added_lines_counter;
|
||||||
|
assert(!m_gcode_lines_map.empty());
|
||||||
|
m_gcode_lines_map.back().second = m_added_lines_counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the gcode lines required by the command cmd by backtracing into the cache
|
||||||
|
void insert_lines(const Backtrace& backtrace, const std::string& cmd, std::function<std::string(unsigned int, float, float)> line_inserter) {
|
||||||
|
assert(!m_lines.empty());
|
||||||
|
const float time_step = backtrace.time_step();
|
||||||
|
size_t rev_it_dist = 0; // distance from the end of the cache of the starting point of the backtrace
|
||||||
|
float last_time_insertion = 0.0f; // used to avoid inserting two lines at the same time
|
||||||
|
for (unsigned int i = 0; i < backtrace.steps; ++i) {
|
||||||
|
const float backtrace_time_i = (i + 1) * time_step;
|
||||||
|
const float time_threshold_i = m_time - backtrace_time_i;
|
||||||
|
auto rev_it = m_lines.rbegin() + rev_it_dist;
|
||||||
|
auto start_rev_it = rev_it;
|
||||||
|
|
||||||
|
// backtrace into the cache to find the place where to insert the line
|
||||||
|
while (rev_it != m_lines.rend() && rev_it->time > time_threshold_i && GCodeReader::GCodeLine::extract_cmd(rev_it->line) != cmd) {
|
||||||
|
++rev_it;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we met the previous evenience of cmd. stop inserting lines
|
||||||
|
if (rev_it != m_lines.rend() && GCodeReader::GCodeLine::extract_cmd(rev_it->line) == cmd)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// insert the line for the current step
|
||||||
|
if (rev_it != m_lines.rend() && rev_it != start_rev_it && rev_it->time != last_time_insertion) {
|
||||||
|
last_time_insertion = rev_it->time;
|
||||||
|
const std::string out_line = line_inserter(i + 1, last_time_insertion, m_time - last_time_insertion);
|
||||||
|
rev_it_dist = std::distance(m_lines.rbegin(), rev_it) + 1;
|
||||||
|
const auto new_it = m_lines.insert(rev_it.base(), { out_line, rev_it->time });
|
||||||
|
#ifndef NDEBUG
|
||||||
|
m_statistics.add_line(out_line.length());
|
||||||
|
#endif // NDEBUG
|
||||||
|
m_size += out_line.length();
|
||||||
|
// synchronize gcode lines map
|
||||||
|
for (auto map_it = m_gcode_lines_map.rbegin(); map_it != m_gcode_lines_map.rbegin() + rev_it_dist - 1; ++map_it) {
|
||||||
|
++map_it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
++m_added_lines_counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write to file:
|
||||||
|
// m_write_type == EWriteType::ByTime - all lines older than m_time - backtrace_time
|
||||||
|
// m_write_type == EWriteType::BySize - all lines if current size is greater than 65535 bytes
|
||||||
|
void write(FilePtr& out, float backtrace_time, GCodeProcessorResult& result, const std::string& out_path) {
|
||||||
|
if (m_lines.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// collect lines to write into a single string
|
||||||
|
std::string out_string;
|
||||||
|
if (!m_lines.empty()) {
|
||||||
|
if (m_write_type == EWriteType::ByTime) {
|
||||||
|
while (m_lines.front().time < m_time - backtrace_time) {
|
||||||
|
const LineData& data = m_lines.front();
|
||||||
|
out_string += data.line;
|
||||||
|
m_size -= data.line.length();
|
||||||
|
m_lines.pop_front();
|
||||||
|
#ifndef NDEBUG
|
||||||
|
m_statistics.remove_line();
|
||||||
|
#endif // NDEBUG
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (m_size > 65535) {
|
||||||
|
while (!m_lines.empty()) {
|
||||||
|
out_string += m_lines.front().line;
|
||||||
|
m_lines.pop_front();
|
||||||
|
}
|
||||||
|
m_size = 0;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
m_statistics.remove_all_lines();
|
||||||
|
#endif // NDEBUG
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write_to_file(out, out_string, result, out_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// flush the current content of the cache to file
|
||||||
|
void flush(FilePtr& out, GCodeProcessorResult& result, const std::string& out_path) {
|
||||||
|
// collect lines to flush into a single string
|
||||||
|
std::string out_string;
|
||||||
|
while (!m_lines.empty()) {
|
||||||
|
out_string += m_lines.front().line;
|
||||||
|
m_lines.pop_front();
|
||||||
|
}
|
||||||
|
m_size = 0;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
m_statistics.remove_all_lines();
|
||||||
|
#endif // NDEBUG
|
||||||
|
|
||||||
|
write_to_file(out, out_string, result, out_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronize_moves(GCodeProcessorResult& result) const {
|
||||||
|
auto it = m_gcode_lines_map.begin();
|
||||||
|
for (GCodeProcessorResult::MoveVertex& move : result.moves) {
|
||||||
|
while (it != m_gcode_lines_map.end() && it->first < move.gcode_id) {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
if (it != m_gcode_lines_map.end() && it->first == move.gcode_id)
|
||||||
|
move.gcode_id = it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t get_size() const { return m_size; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void write_to_file(FilePtr& out, const std::string& out_string, GCodeProcessorResult& result, const std::string& out_path) {
|
||||||
|
if (!out_string.empty()) {
|
||||||
|
fwrite((const void*)out_string.c_str(), 1, out_string.length(), out.f);
|
||||||
|
if (ferror(out.f)) {
|
||||||
|
out.close();
|
||||||
|
boost::nowide::remove(out_path.c_str());
|
||||||
|
throw Slic3r::RuntimeError(std::string("GCode processor post process export failed.\nIs the disk full?\n"));
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < out_string.size(); ++i) {
|
||||||
|
if (out_string[i] == '\n')
|
||||||
|
result.lines_ends.emplace_back(m_out_file_pos + i + 1);
|
||||||
|
}
|
||||||
|
m_out_file_pos += out_string.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ExportLines export_lines(m_result.backtrace_enabled ? ExportLines::EWriteType::ByTime : ExportLines::EWriteType::BySize, m_time_processor.machines[0]);
|
||||||
|
#else
|
||||||
// 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;
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
|
||||||
// replace placeholder lines with the proper final value
|
// replace placeholder lines with the proper final value
|
||||||
// gcode_line is in/out parameter, to reduce expensive memory allocation
|
// gcode_line is in/out parameter, to reduce expensive memory allocation
|
||||||
auto process_placeholders = [&](std::string& gcode_line) {
|
auto process_placeholders = [&](std::string& gcode_line) {
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
bool processed = false;
|
||||||
|
#else
|
||||||
unsigned int extra_lines_count = 0;
|
unsigned int extra_lines_count = 0;
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
|
||||||
// remove trailing '\n'
|
// remove trailing '\n'
|
||||||
auto line = std::string_view(gcode_line).substr(0, gcode_line.length() - 1);
|
auto line = std::string_view(gcode_line).substr(0, gcode_line.length() - 1);
|
||||||
|
|
||||||
|
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
if (line.length() > 1) {
|
if (line.length() > 1) {
|
||||||
line = line.substr(1);
|
line = line.substr(1);
|
||||||
if (m_time_processor.export_remaining_time_enabled &&
|
if (m_time_processor.export_remaining_time_enabled &&
|
||||||
@ -3481,17 +3733,29 @@ void GCodeProcessor::post_process()
|
|||||||
const TimeMachine& machine = m_time_processor.machines[i];
|
const TimeMachine& machine = m_time_processor.machines[i];
|
||||||
if (machine.enabled) {
|
if (machine.enabled) {
|
||||||
// export pair <percent, remaining time>
|
// export pair <percent, remaining time>
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
export_lines.append_line(format_line_M73_main(machine.line_m73_main_mask.c_str(),
|
||||||
|
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? 0 : 100,
|
||||||
|
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? time_in_minutes(machine.time) : 0));
|
||||||
|
processed = true;
|
||||||
|
#else
|
||||||
ret += format_line_M73_main(machine.line_m73_main_mask.c_str(),
|
ret += format_line_M73_main(machine.line_m73_main_mask.c_str(),
|
||||||
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? 0 : 100,
|
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? 0 : 100,
|
||||||
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? time_in_minutes(machine.time) : 0);
|
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? time_in_minutes(machine.time) : 0);
|
||||||
++extra_lines_count;
|
++extra_lines_count;
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
|
||||||
// export remaining time to next printer stop
|
// export remaining time to next printer stop
|
||||||
if (line == reserved_tag(ETags::First_Line_M73_Placeholder) && !machine.stop_times.empty()) {
|
if (line == reserved_tag(ETags::First_Line_M73_Placeholder) && !machine.stop_times.empty()) {
|
||||||
int to_export_stop = time_in_minutes(machine.stop_times.front().elapsed_time);
|
const int to_export_stop = time_in_minutes(machine.stop_times.front().elapsed_time);
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
export_lines.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop));
|
||||||
|
last_exported_stop[i] = to_export_stop;
|
||||||
|
#else
|
||||||
ret += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop);
|
ret += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop);
|
||||||
last_exported_stop[i] = to_export_stop;
|
last_exported_stop[i] = to_export_stop;
|
||||||
++extra_lines_count;
|
++extra_lines_count;
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3505,7 +3769,12 @@ void GCodeProcessor::post_process()
|
|||||||
sprintf(buf, "; estimated printing time (%s mode) = %s\n",
|
sprintf(buf, "; estimated printing time (%s mode) = %s\n",
|
||||||
(mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent",
|
(mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent",
|
||||||
get_time_dhms(machine.time).c_str());
|
get_time_dhms(machine.time).c_str());
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
export_lines.append_line(buf);
|
||||||
|
processed = true;
|
||||||
|
#else
|
||||||
ret += buf;
|
ret += buf;
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||||
@ -3516,16 +3785,25 @@ void GCodeProcessor::post_process()
|
|||||||
sprintf(buf, "; estimated first layer printing time (%s mode) = %s\n",
|
sprintf(buf, "; estimated first layer printing time (%s mode) = %s\n",
|
||||||
(mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent",
|
(mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent",
|
||||||
get_time_dhms(machine.layers_time.empty() ? 0.f : machine.layers_time.front()).c_str());
|
get_time_dhms(machine.layers_time.empty() ? 0.f : machine.layers_time.front()).c_str());
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
export_lines.append_line(buf);
|
||||||
|
processed = true;
|
||||||
|
#else
|
||||||
ret += buf;
|
ret += buf;
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
return processed;
|
||||||
|
#else
|
||||||
if (!ret.empty())
|
if (!ret.empty())
|
||||||
// Not moving the move operator on purpose, so that the gcode_line allocation will grow and it will not be reallocated after handful of lines are processed.
|
// Not moving the move operator on purpose, so that the gcode_line allocation will grow and it will not be reallocated after handful of lines are processed.
|
||||||
gcode_line = ret;
|
gcode_line = ret;
|
||||||
return std::tuple(!ret.empty(), (extra_lines_count == 0) ? extra_lines_count : extra_lines_count - 1);
|
return std::tuple(!ret.empty(), (extra_lines_count == 0) ? extra_lines_count : extra_lines_count - 1);
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<double> filament_mm(m_result.extruders_count, 0.0);
|
std::vector<double> filament_mm(m_result.extruders_count, 0.0);
|
||||||
@ -3599,10 +3877,16 @@ void GCodeProcessor::post_process()
|
|||||||
time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute,
|
time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute,
|
||||||
// Caches, to be modified
|
// Caches, to be modified
|
||||||
&g1_times_cache_it, &last_exported_main, &last_exported_stop,
|
&g1_times_cache_it, &last_exported_main, &last_exported_stop,
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
&export_lines]
|
||||||
|
#else
|
||||||
// String output
|
// String output
|
||||||
&export_line]
|
&export_line]
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
(const size_t g1_lines_counter) {
|
(const size_t g1_lines_counter) {
|
||||||
|
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
unsigned int exported_lines_count = 0;
|
unsigned int exported_lines_count = 0;
|
||||||
|
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
if (m_time_processor.export_remaining_time_enabled) {
|
if (m_time_processor.export_remaining_time_enabled) {
|
||||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||||
const TimeMachine& machine = m_time_processor.machines[i];
|
const TimeMachine& machine = m_time_processor.machines[i];
|
||||||
@ -3616,10 +3900,17 @@ void GCodeProcessor::post_process()
|
|||||||
std::pair<int, int> to_export_main = { int(100.0f * it->elapsed_time / machine.time),
|
std::pair<int, int> to_export_main = { int(100.0f * it->elapsed_time / machine.time),
|
||||||
time_in_minutes(machine.time - it->elapsed_time) };
|
time_in_minutes(machine.time - it->elapsed_time) };
|
||||||
if (last_exported_main[i] != to_export_main) {
|
if (last_exported_main[i] != to_export_main) {
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
export_lines.append_line(format_line_M73_main(machine.line_m73_main_mask.c_str(),
|
||||||
|
to_export_main.first, to_export_main.second));
|
||||||
|
#else
|
||||||
export_line += format_line_M73_main(machine.line_m73_main_mask.c_str(),
|
export_line += format_line_M73_main(machine.line_m73_main_mask.c_str(),
|
||||||
to_export_main.first, to_export_main.second);
|
to_export_main.first, to_export_main.second);
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
last_exported_main[i] = to_export_main;
|
last_exported_main[i] = to_export_main;
|
||||||
|
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
++exported_lines_count;
|
++exported_lines_count;
|
||||||
|
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
}
|
}
|
||||||
// export remaining time to next printer stop
|
// export remaining time to next printer stop
|
||||||
auto it_stop = std::upper_bound(machine.stop_times.begin(), machine.stop_times.end(), it->elapsed_time,
|
auto it_stop = std::upper_bound(machine.stop_times.begin(), machine.stop_times.end(), it->elapsed_time,
|
||||||
@ -3629,9 +3920,15 @@ void GCodeProcessor::post_process()
|
|||||||
if (last_exported_stop[i] != to_export_stop) {
|
if (last_exported_stop[i] != to_export_stop) {
|
||||||
if (to_export_stop > 0) {
|
if (to_export_stop > 0) {
|
||||||
if (last_exported_stop[i] != to_export_stop) {
|
if (last_exported_stop[i] != to_export_stop) {
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
export_lines.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop));
|
||||||
|
#else
|
||||||
export_line += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop);
|
export_line += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop);
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
last_exported_stop[i] = to_export_stop;
|
last_exported_stop[i] = to_export_stop;
|
||||||
|
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
++exported_lines_count;
|
++exported_lines_count;
|
||||||
|
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -3650,13 +3947,22 @@ void GCodeProcessor::post_process()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_last) {
|
if (is_last) {
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
if (std::distance(machine.stop_times.begin(), it_stop) == static_cast<ptrdiff_t>(machine.stop_times.size() - 1))
|
||||||
|
export_lines.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop));
|
||||||
|
else
|
||||||
|
export_lines.append_line(format_line_M73_stop_float(machine.line_m73_stop_mask.c_str(), time_in_last_minute(it_stop->elapsed_time - it->elapsed_time)));
|
||||||
|
#else
|
||||||
if (std::distance(machine.stop_times.begin(), it_stop) == static_cast<ptrdiff_t>(machine.stop_times.size() - 1))
|
if (std::distance(machine.stop_times.begin(), it_stop) == static_cast<ptrdiff_t>(machine.stop_times.size() - 1))
|
||||||
export_line += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop);
|
export_line += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop);
|
||||||
else
|
else
|
||||||
export_line += format_line_M73_stop_float(machine.line_m73_stop_mask.c_str(), time_in_last_minute(it_stop->elapsed_time - it->elapsed_time));
|
export_line += format_line_M73_stop_float(machine.line_m73_stop_mask.c_str(), time_in_last_minute(it_stop->elapsed_time - it->elapsed_time));
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
|
||||||
last_exported_stop[i] = to_export_stop;
|
last_exported_stop[i] = to_export_stop;
|
||||||
|
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
++exported_lines_count;
|
++exported_lines_count;
|
||||||
|
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3665,12 +3971,26 @@ void GCodeProcessor::post_process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
return exported_lines_count;
|
return exported_lines_count;
|
||||||
|
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
// add lines XXX to exported gcode
|
||||||
|
auto process_line_T = [this, &export_lines](const std::string& gcode_line, const size_t g1_lines_counter, const ExportLines::Backtrace& backtrace) {
|
||||||
|
const std::string cmd = GCodeReader::GCodeLine::extract_cmd(gcode_line);
|
||||||
|
export_lines.insert_lines(backtrace, cmd, [](unsigned int id, float time, float time_diff) {
|
||||||
|
const std::string out = "XYYY ; id:" + std::to_string(id) + " time:" + std::to_string(time) + " time diff:" + std::to_string(time_diff) + "\n";
|
||||||
|
return out;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
|
||||||
|
m_result.lines_ends.clear();
|
||||||
|
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
// helper function to write to disk
|
// helper function to write to disk
|
||||||
size_t out_file_pos = 0;
|
size_t out_file_pos = 0;
|
||||||
m_result.lines_ends.clear();
|
|
||||||
auto write_string = [this, &export_line, &out, &out_path, &out_file_pos](const std::string& str) {
|
auto write_string = [this, &export_line, &out, &out_path, &out_file_pos](const std::string& str) {
|
||||||
fwrite((const void*)export_line.c_str(), 1, export_line.length(), out.f);
|
fwrite((const void*)export_line.c_str(), 1, export_line.length(), out.f);
|
||||||
if (ferror(out.f)) {
|
if (ferror(out.f)) {
|
||||||
@ -3684,9 +4004,18 @@ void GCodeProcessor::post_process()
|
|||||||
out_file_pos += export_line.size();
|
out_file_pos += export_line.size();
|
||||||
export_line.clear();
|
export_line.clear();
|
||||||
};
|
};
|
||||||
|
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
|
||||||
unsigned int line_id = 0;
|
unsigned int line_id = 0;
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
// Backtrace data for Tx gcode lines
|
||||||
|
static const ExportLines::Backtrace backtrace_T = { 60.0f, 10 };
|
||||||
|
// In case there are multiple sources of backtracing, keeps track of the longest backtrack time needed
|
||||||
|
// to flush the backtrace cache accordingly
|
||||||
|
float max_backtrace_time = 60.0f;
|
||||||
|
#else
|
||||||
std::vector<std::pair<unsigned int, unsigned int>> offsets;
|
std::vector<std::pair<unsigned int, unsigned int>> offsets;
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
|
||||||
{
|
{
|
||||||
// Read the input stream 64kB at a time, extract lines and process them.
|
// Read the input stream 64kB at a time, extract lines and process them.
|
||||||
@ -3710,14 +4039,39 @@ void GCodeProcessor::post_process()
|
|||||||
gcode_line.insert(gcode_line.end(), it, it_end);
|
gcode_line.insert(gcode_line.end(), it, it_end);
|
||||||
if (eol) {
|
if (eol) {
|
||||||
++line_id;
|
++line_id;
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
export_lines.update(line_id, g1_lines_counter);
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
|
||||||
gcode_line += "\n";
|
gcode_line += "\n";
|
||||||
// replace placeholder lines
|
// replace placeholder lines
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
bool processed = process_placeholders(gcode_line);
|
||||||
|
if (processed)
|
||||||
|
gcode_line.clear();
|
||||||
|
#else
|
||||||
auto [processed, lines_added_count] = process_placeholders(gcode_line);
|
auto [processed, lines_added_count] = process_placeholders(gcode_line);
|
||||||
if (processed && lines_added_count > 0)
|
if (processed && lines_added_count > 0)
|
||||||
offsets.push_back({ line_id, lines_added_count });
|
offsets.push_back({ line_id, lines_added_count });
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
if (!processed)
|
if (!processed)
|
||||||
processed = process_used_filament(gcode_line);
|
processed = process_used_filament(gcode_line);
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
if (!processed && !is_temporary_decoration(gcode_line)) {
|
||||||
|
if (GCodeReader::GCodeLine::cmd_is(gcode_line, "G1"))
|
||||||
|
// add lines M73 where needed
|
||||||
|
process_line_G1(g1_lines_counter++);
|
||||||
|
else if (m_result.backtrace_enabled && GCodeReader::GCodeLine::cmd_starts_with(gcode_line, "T")) {
|
||||||
|
// add lines XXX where needed
|
||||||
|
process_line_T(gcode_line, g1_lines_counter, backtrace_T);
|
||||||
|
max_backtrace_time = std::max(max_backtrace_time, backtrace_T.time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gcode_line.empty())
|
||||||
|
export_lines.append_line(gcode_line);
|
||||||
|
export_lines.write(out, 1.1f * max_backtrace_time, m_result, out_path);
|
||||||
|
#else
|
||||||
if (!processed && !is_temporary_decoration(gcode_line) && GCodeReader::GCodeLine::cmd_is(gcode_line, "G1")) {
|
if (!processed && !is_temporary_decoration(gcode_line) && GCodeReader::GCodeLine::cmd_is(gcode_line, "G1")) {
|
||||||
// remove temporary lines, add lines M73 where needed
|
// remove temporary lines, add lines M73 where needed
|
||||||
unsigned int extra_lines_count = process_line_G1(g1_lines_counter++);
|
unsigned int extra_lines_count = process_line_G1(g1_lines_counter++);
|
||||||
@ -3728,6 +4082,7 @@ void GCodeProcessor::post_process()
|
|||||||
export_line += gcode_line;
|
export_line += gcode_line;
|
||||||
if (export_line.length() > 65535)
|
if (export_line.length() > 65535)
|
||||||
write_string(export_line);
|
write_string(export_line);
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
gcode_line.clear();
|
gcode_line.clear();
|
||||||
}
|
}
|
||||||
// Skip EOL.
|
// Skip EOL.
|
||||||
@ -3742,12 +4097,19 @@ void GCodeProcessor::post_process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
export_lines.flush(out, m_result, out_path);
|
||||||
|
#else
|
||||||
if (!export_line.empty())
|
if (!export_line.empty())
|
||||||
write_string(export_line);
|
write_string(export_line);
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
|
||||||
out.close();
|
out.close();
|
||||||
in.close();
|
in.close();
|
||||||
|
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
export_lines.synchronize_moves(m_result);
|
||||||
|
#else
|
||||||
// updates moves' gcode ids which have been modified by the insertion of the M73 lines
|
// updates moves' gcode ids which have been modified by the insertion of the M73 lines
|
||||||
unsigned int curr_offset_id = 0;
|
unsigned int curr_offset_id = 0;
|
||||||
unsigned int total_offset = 0;
|
unsigned int total_offset = 0;
|
||||||
@ -3758,6 +4120,7 @@ void GCodeProcessor::post_process()
|
|||||||
}
|
}
|
||||||
move.gcode_id += total_offset;
|
move.gcode_id += total_offset;
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
|
||||||
if (rename_file(out_path, m_result.filename))
|
if (rename_file(out_path, m_result.filename))
|
||||||
throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + m_result.filename + '\n' +
|
throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + m_result.filename + '\n' +
|
||||||
|
@ -125,6 +125,9 @@ namespace Slic3r {
|
|||||||
float max_print_height;
|
float max_print_height;
|
||||||
SettingsIds settings_ids;
|
SettingsIds settings_ids;
|
||||||
size_t extruders_count;
|
size_t extruders_count;
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
bool backtrace_enabled;
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
std::vector<std::string> extruder_colors;
|
std::vector<std::string> extruder_colors;
|
||||||
std::vector<float> filament_diameters;
|
std::vector<float> filament_diameters;
|
||||||
std::vector<float> filament_densities;
|
std::vector<float> filament_densities;
|
||||||
|
@ -71,6 +71,18 @@ public:
|
|||||||
return strncmp(cmd, cmd_test, len) == 0 && GCodeReader::is_end_of_word(cmd[len]);
|
return strncmp(cmd, cmd_test, len) == 0 && GCodeReader::is_end_of_word(cmd[len]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
static bool cmd_starts_with(const std::string& gcode_line, const char* cmd_test) {
|
||||||
|
return strncmp(GCodeReader::skip_whitespaces(gcode_line.c_str()), cmd_test, strlen(cmd_test)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string extract_cmd(const std::string& gcode_line) {
|
||||||
|
GCodeLine temp;
|
||||||
|
temp.m_raw = gcode_line;
|
||||||
|
return temp.cmd().data();
|
||||||
|
}
|
||||||
|
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_raw;
|
std::string m_raw;
|
||||||
float m_axis[NUM_AXES];
|
float m_axis[NUM_AXES];
|
||||||
|
@ -58,6 +58,8 @@
|
|||||||
|
|
||||||
// Enable alternative version of file_wildcards()
|
// Enable alternative version of file_wildcards()
|
||||||
#define ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR (1 && ENABLE_2_6_0_ALPHA1)
|
#define ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR (1 && ENABLE_2_6_0_ALPHA1)
|
||||||
|
// Enable gcode postprocess modified to allow for backward insertion of new lines
|
||||||
|
#define ENABLE_GCODE_POSTPROCESS_BACKTRACE (1 && ENABLE_2_6_0_ALPHA1)
|
||||||
|
|
||||||
|
|
||||||
#endif // _prusaslicer_technologies_h_
|
#endif // _prusaslicer_technologies_h_
|
||||||
|
Loading…
Reference in New Issue
Block a user