WIP: G-code find / replace using a new gcode_substitutions PrintConfig

parameter.
This commit is contained in:
Vojtech Bubnik 2022-01-06 13:01:49 +01:00 committed by YuSanka
parent c54b8908dd
commit 658f01b64b
7 changed files with 129 additions and 2 deletions

View File

@ -98,6 +98,8 @@ add_library(libslic3r STATIC
GCode/ThumbnailData.hpp
GCode/CoolingBuffer.cpp
GCode/CoolingBuffer.hpp
GCode/FindReplace.cpp
GCode/FindReplace.hpp
GCode/PostProcessor.cpp
GCode/PostProcessor.hpp
# GCode/PressureEqualizer.cpp

View File

@ -1155,6 +1155,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
m_enable_extrusion_role_markers = false;
#endif /* HAS_PRESSURE_EQUALIZER */
if (! print.config().gcode_substitutions.values.empty())
m_find_replace = make_unique<GCodeFindReplace>(print.config());
// Write information on the generator.
file.write_format("; %s\n\n", Slic3r::header_slic3r_generated().c_str());
@ -1560,13 +1563,21 @@ void GCode::process_layers(
[&cooling_buffer = *this->m_cooling_buffer.get()](GCode::LayerResult in) -> std::string {
return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
});
const auto find_replace = tbb::make_filter<std::string, std::string>(slic3r_tbb_filtermode::serial_in_order,
[&self = *this->m_find_replace.get()](std::string s) -> std::string {
return self.process_layer(std::move(s));
});
const auto output = tbb::make_filter<std::string, void>(slic3r_tbb_filtermode::serial_in_order,
[&output_stream](std::string s) { output_stream.write(s); }
);
// The pipeline elements are joined using const references, thus no copying is performed.
if (m_spiral_vase)
if (m_spiral_vase && m_find_replace)
tbb::parallel_pipeline(12, generator & spiral_vase & cooling & find_replace & output);
else if (m_spiral_vase)
tbb::parallel_pipeline(12, generator & spiral_vase & cooling & output);
else if (m_find_replace)
tbb::parallel_pipeline(12, generator & cooling & find_replace & output);
else
tbb::parallel_pipeline(12, generator & cooling & output);
}
@ -1603,13 +1614,21 @@ void GCode::process_layers(
[&cooling_buffer = *this->m_cooling_buffer.get()](GCode::LayerResult in)->std::string {
return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
});
const auto find_replace = tbb::make_filter<std::string, std::string>(slic3r_tbb_filtermode::serial_in_order,
[&self = *this->m_find_replace.get()](std::string s) -> std::string {
return self.process_layer(std::move(s));
});
const auto output = tbb::make_filter<std::string, void>(slic3r_tbb_filtermode::serial_in_order,
[&output_stream](std::string s) { output_stream.write(s); }
);
// The pipeline elements are joined using const references, thus no copying is performed.
if (m_spiral_vase)
if (m_spiral_vase && m_find_replace)
tbb::parallel_pipeline(12, generator & spiral_vase & cooling & find_replace & output);
else if (m_spiral_vase)
tbb::parallel_pipeline(12, generator & spiral_vase & cooling & output);
else if (m_find_replace)
tbb::parallel_pipeline(12, generator & cooling & find_replace & output);
else
tbb::parallel_pipeline(12, generator & cooling & output);
}

View File

@ -10,6 +10,7 @@
#include "PrintConfig.hpp"
#include "GCode/AvoidCrossingPerimeters.hpp"
#include "GCode/CoolingBuffer.hpp"
#include "GCode/FindReplace.hpp"
#include "GCode/SpiralVase.hpp"
#include "GCode/ToolOrdering.hpp"
#include "GCode/WipeTower.hpp"
@ -393,6 +394,7 @@ private:
std::unique_ptr<CoolingBuffer> m_cooling_buffer;
std::unique_ptr<SpiralVase> m_spiral_vase;
std::unique_ptr<GCodeFindReplace> m_find_replace;
#ifdef HAS_PRESSURE_EQUALIZER
std::unique_ptr<PressureEqualizer> m_pressure_equalizer;
#endif /* HAS_PRESSURE_EQUALIZER */

View File

@ -0,0 +1,71 @@
#include "FindReplace.hpp"
#include "../Utils.hpp"
namespace Slic3r {
GCodeFindReplace::GCodeFindReplace(const PrintConfig &print_config)
{
const std::vector<std::string> &subst = print_config.gcode_substitutions.values;
if ((subst.size() % 3) != 0)
throw RuntimeError("Invalid length of gcode_substitutions parameter");
m_substitutions.reserve(subst.size() / 3);
for (size_t i = 0; i < subst.size(); i += 3) {
boost::regex pattern;
try {
pattern.assign(subst[i]);
} catch (const std::exception &ex) {
throw RuntimeError(std::string("Invalid gcode_substitutions parameter, failed to compile regular expression: ") + ex.what());
}
m_substitutions.push_back({ std::move(pattern), subst[i + 1] });
}
}
class ToStringIterator
{
public:
using iterator_category = std::output_iterator_tag;
using value_type = void;
using difference_type = void;
using pointer = void;
using reference = void;
ToStringIterator(std::string &data) : m_data(&data) {}
ToStringIterator& operator=(const char val) {
size_t needs = m_data->size() + 1;
if (m_data->capacity() < needs)
m_data->reserve(next_highest_power_of_2(needs));
m_data->push_back(val);
return *this;
}
ToStringIterator& operator*() { return *this; }
ToStringIterator& operator++() { return *this; }
ToStringIterator operator++(int) { return *this; }
private:
std::string *m_data;
};
std::string GCodeFindReplace::process_layer(const std::string &ain)
{
std::string out;
const std::string *in = &ain;
std::string temp;
temp.reserve(in->size());
for (const Substitution &substitution : m_substitutions) {
temp.clear();
temp.reserve(in->size());
boost::regex_replace(ToStringIterator(temp), in->begin(), in->end(),
substitution.pattern, substitution.format, boost::match_default | boost::format_all);
std::swap(out, temp);
in = &out;
}
return out;
}
}

View File

@ -0,0 +1,26 @@
#ifndef slic3r_FindReplace_hpp_
#define slic3r_FindReplace_hpp_
#include "../PrintConfig.hpp"
#include <boost/regex.hpp>
namespace Slic3r {
class GCodeFindReplace {
public:
GCodeFindReplace(const PrintConfig &print_config);
std::string process_layer(const std::string &gcode);
private:
struct Substitution {
boost::regex pattern;
std::string format;
};
std::vector<Substitution> m_substitutions;
};
}
#endif // slic3r_FindReplace_hpp_

View File

@ -1357,6 +1357,12 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(0));
def = this->add("gcode_substitutions", coStrings);
def->label = L("G-code substitutions");
def->tooltip = L("Find / replace patterns in G-code lines and substitute them.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionStrings());
def = this->add("high_current_on_filament_swap", coBool);
def->label = L("High extruder current on filament swap");
def->tooltip = L("It may be beneficial to increase the extruder motor current during the filament exchange"

View File

@ -641,6 +641,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBool, gcode_comments))
((ConfigOptionEnum<GCodeFlavor>, gcode_flavor))
((ConfigOptionBool, gcode_label_objects))
((ConfigOptionStrings, gcode_substitutions))
((ConfigOptionString, layer_gcode))
((ConfigOptionFloat, max_print_speed))
((ConfigOptionFloat, max_volumetric_speed))