Merge remote-tracking branch 'origin/et_gcode_window'

This commit is contained in:
enricoturri1966 2021-03-22 08:56:25 +01:00
commit a618bfe078
9 changed files with 335 additions and 7 deletions

View File

@ -312,7 +312,7 @@ endif()
# boost::process was introduced first in version 1.64.0,
# boost::beast::detail::base64 was introduced first in version 1.66.0
set(MINIMUM_BOOST_VERSION "1.66.0")
set(_boost_components "system;filesystem;thread;log;locale;regex;chrono;atomic;date_time")
set(_boost_components "system;filesystem;thread;log;locale;regex;chrono;atomic;date_time;iostreams")
find_package(Boost ${MINIMUM_BOOST_VERSION} REQUIRED COMPONENTS ${_boost_components})
add_library(boost_libs INTERFACE)

View File

@ -757,8 +757,16 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re
BOOST_LOG_TRIVIAL(debug) << "Start processing gcode, " << log_memory_info();
m_processor.process_file(path_tmp, true, [print]() { print->throw_if_canceled(); });
DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics);
#if ENABLE_GCODE_WINDOW
if (result != nullptr) {
*result = std::move(m_processor.extract_result());
// set the filename to the correct value
result->filename = path;
}
#else
if (result != nullptr)
*result = std::move(m_processor.extract_result());
#endif // ENABLE_GCODE_WINDOW
BOOST_LOG_TRIVIAL(debug) << "Finished processing gcode, " << log_memory_info();
if (rename_file(path_tmp, path))

View File

@ -9,6 +9,9 @@
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
#include <boost/nowide/fstream.hpp>
#include <boost/nowide/cstdio.hpp>
#if ENABLE_GCODE_WINDOW
#include <boost/filesystem/path.hpp>
#endif // ENABLE_GCODE_WINDOW
#include <float.h>
#include <assert.h>
@ -974,6 +977,9 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
}
// process gcode
#if ENABLE_GCODE_WINDOW
m_result.filename = filename;
#endif // ENABLE_GCODE_WINDOW
m_result.id = ++s_result_id;
// 1st move must be a dummy move
m_result.moves.emplace_back(MoveVertex());

View File

@ -337,13 +337,15 @@ namespace Slic3r {
std::vector<std::string> filament;
std::string printer;
void reset()
{
void reset() {
print = "";
filament = std::vector<std::string>();
printer = "";
}
};
#if ENABLE_GCODE_WINDOW
std::string filename;
#endif // ENABLE_GCODE_WINDOW
unsigned int id;
std::vector<MoveVertex> moves;
Pointfs bed_shape;

View File

@ -53,6 +53,8 @@
#define ENABLE_GCODE_LINES_ID_IN_H_SLIDER (1 && ENABLE_2_3_1_ALPHA1)
// Enable validation of custom gcode against gcode processor reserved keywords
#define ENABLE_VALIDATE_CUSTOM_GCODE (1 && ENABLE_2_3_1_ALPHA1)
// Enable showing a imgui window containing gcode in preview
#define ENABLE_GCODE_WINDOW (1 && ENABLE_2_3_1_ALPHA1)
#endif // _prusaslicer_technologies_h_

View File

@ -21,6 +21,9 @@
#include <GL/glew.h>
#include <boost/log/trivial.hpp>
#if ENABLE_GCODE_WINDOW
#include <boost/algorithm/string/split.hpp>
#endif // ENABLE_GCODE_WINDOW
#include <boost/nowide/cstdio.hpp>
#include <wx/progdlg.h>
#include <wx/numformatter.h>
@ -280,7 +283,7 @@ void GCodeViewer::SequentialView::Marker::render() const
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Tool position") + ":");
ImGui::SameLine();
char buf[1024];
sprintf(buf, "X: %.2f, Y: %.2f, Z: %.2f", m_world_position(0), m_world_position(1), m_world_position(2));
sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", m_world_position(0), m_world_position(1), m_world_position(2));
imgui.text(std::string(buf));
// force extra frame to automatically update window size
@ -297,6 +300,223 @@ void GCodeViewer::SequentialView::Marker::render() const
ImGui::PopStyleVar();
}
#if ENABLE_GCODE_WINDOW
void GCodeViewer::SequentialView::GCodeWindow::load_gcode()
{
if (m_filename.empty())
return;
try
{
// generate mapping for accessing data in file by line number
boost::nowide::ifstream f(m_filename);
f.seekg(0, f.end);
uint64_t file_length = static_cast<uint64_t>(f.tellg());
f.seekg(0, f.beg);
std::string line;
uint64_t offset = 0;
while (std::getline(f, line)) {
uint64_t line_length = static_cast<uint64_t>(line.length());
m_lines_map.push_back({ offset, line_length });
offset += static_cast<uint64_t>(line_length) + 1;
}
if (offset != file_length) {
// if the final offset does not match with file length, lines are terminated with CR+LF
// so update all offsets accordingly
for (size_t i = 0; i < m_lines_map.size(); ++i) {
m_lines_map[i].first += static_cast<uint64_t>(i);
}
}
}
catch (...)
{
BOOST_LOG_TRIVIAL(error) << "Unable to load data from " << m_filename << ". Cannot show G-code window.";
reset();
return;
}
m_selected_line_id = 0;
m_last_lines_size = 0;
try
{
m_file.open(boost::filesystem::path(m_filename));
}
catch (...)
{
BOOST_LOG_TRIVIAL(error) << "Unable to map file " << m_filename << ". Cannot show G-code window.";
reset();
}
}
void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, uint64_t curr_line_id) const
{
auto update_lines = [this](uint64_t start_id, uint64_t end_id) {
std::vector<Line> ret;
ret.reserve(end_id - start_id + 1);
for (uint64_t id = start_id; id <= end_id; ++id) {
// read line from file
std::string gline(m_file.data() + m_lines_map[id - 1].first, m_lines_map[id - 1].second);
std::string command;
std::string parameters;
std::string comment;
// extract comment
std::vector<std::string> tokens;
boost::split(tokens, gline, boost::is_any_of(";"), boost::token_compress_on);
command = tokens.front();
if (tokens.size() > 1)
comment = ";" + tokens.back();
// extract gcode command and parameters
if (!command.empty()) {
boost::split(tokens, command, boost::is_any_of(" "), boost::token_compress_on);
command = tokens.front();
if (tokens.size() > 1) {
for (size_t i = 1; i < tokens.size(); ++i) {
parameters += " " + tokens[i];
}
}
}
ret.push_back({ command, parameters, comment });
}
return ret;
};
static const ImVec4 LINE_NUMBER_COLOR = ImGuiWrapper::COL_ORANGE_LIGHT;
static const ImVec4 SELECTION_RECT_COLOR = ImGuiWrapper::COL_ORANGE_DARK;
static const ImVec4 COMMAND_COLOR = { 0.8f, 0.8f, 0.0f, 1.0f };
static const ImVec4 PARAMETERS_COLOR = { 1.0f, 1.0f, 1.0f, 1.0f };
static const ImVec4 COMMENT_COLOR = { 0.7f, 0.7f, 0.7f, 1.0f };
if (!m_visible || m_filename.empty() || m_lines_map.empty() || curr_line_id == 0)
return;
// window height
const float wnd_height = bottom - top;
// number of visible lines
const float text_height = ImGui::CalcTextSize("0").y;
const ImGuiStyle& style = ImGui::GetStyle();
const uint64_t lines_count = static_cast<uint64_t>((wnd_height - 2.0f * style.WindowPadding.y + style.ItemSpacing.y) / (text_height + style.ItemSpacing.y));
if (lines_count == 0)
return;
// visible range
const uint64_t half_lines_count = lines_count / 2;
uint64_t start_id = (curr_line_id >= half_lines_count) ? curr_line_id - half_lines_count : 0;
uint64_t end_id = start_id + lines_count - 1;
if (end_id >= static_cast<uint64_t>(m_lines_map.size())) {
end_id = static_cast<uint64_t>(m_lines_map.size()) - 1;
start_id = end_id - lines_count + 1;
}
// updates list of lines to show, if needed
if (m_selected_line_id != curr_line_id || m_last_lines_size != end_id - start_id + 1) {
try
{
*const_cast<std::vector<Line>*>(&m_lines) = update_lines(start_id, end_id);
}
catch (...)
{
BOOST_LOG_TRIVIAL(error) << "Error while loading from file " << m_filename << ". Cannot show G-code window.";
return;
}
*const_cast<uint64_t*>(&m_selected_line_id) = curr_line_id;
*const_cast<size_t*>(&m_last_lines_size) = m_lines.size();
}
// line number's column width
const float id_width = ImGui::CalcTextSize(std::to_string(end_id).c_str()).x;
ImGuiWrapper& imgui = *wxGetApp().imgui();
imgui.set_next_window_pos(0.0f, top, ImGuiCond_Always, 0.0f, 0.0f);
imgui.set_next_window_size(0.0f, wnd_height, ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::SetNextWindowBgAlpha(0.6f);
imgui.begin(std::string("G-code"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove);
// center the text in the window by pushing down the first line
const float f_lines_count = static_cast<float>(lines_count);
ImGui::SetCursorPosY(0.5f * (wnd_height - f_lines_count * text_height - (f_lines_count - 1.0f) * style.ItemSpacing.y));
// render text lines
for (uint64_t id = start_id; id <= end_id; ++id) {
const Line& line = m_lines[id - start_id];
// rect around the current selected line
if (id == curr_line_id) {
const float pos_y = ImGui::GetCursorScreenPos().y;
const float half_ItemSpacing_y = 0.5f * style.ItemSpacing.y;
const float half_padding_x = 0.5f * style.WindowPadding.x;
ImGui::GetWindowDrawList()->AddRect({ half_padding_x, pos_y - half_ItemSpacing_y },
{ ImGui::GetCurrentWindow()->Size.x - half_padding_x, pos_y + text_height + half_ItemSpacing_y },
ImGui::GetColorU32(SELECTION_RECT_COLOR));
}
// render line number
const std::string id_str = std::to_string(id);
// spacer to right align text
ImGui::Dummy({ id_width - ImGui::CalcTextSize(id_str.c_str()).x, text_height });
ImGui::SameLine(0.0f, 0.0f);
ImGui::PushStyleColor(ImGuiCol_Text, LINE_NUMBER_COLOR);
imgui.text(id_str);
ImGui::PopStyleColor();
if (!line.command.empty() || !line.comment.empty())
ImGui::SameLine();
// render command
if (!line.command.empty()) {
ImGui::PushStyleColor(ImGuiCol_Text, COMMAND_COLOR);
imgui.text(line.command);
ImGui::PopStyleColor();
}
// render parameters
if (!line.parameters.empty()) {
ImGui::SameLine(0.0f, 0.0f);
ImGui::PushStyleColor(ImGuiCol_Text, PARAMETERS_COLOR);
imgui.text(line.parameters);
ImGui::PopStyleColor();
}
// render comment
if (!line.comment.empty()) {
if (!line.command.empty())
ImGui::SameLine(0.0f, 0.0f);
ImGui::PushStyleColor(ImGuiCol_Text, COMMENT_COLOR);
imgui.text(line.comment);
ImGui::PopStyleColor();
}
}
imgui.end();
ImGui::PopStyleVar();
}
void GCodeViewer::SequentialView::GCodeWindow::stop_mapping_file()
{
if (m_file.is_open())
m_file.close();
}
void GCodeViewer::SequentialView::render(float legend_height) const
{
marker.render();
float bottom = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size().get_height();
if (wxGetApp().is_editor())
bottom -= wxGetApp().plater()->get_view_toolbar().get_height();
gcode_window.render(legend_height, bottom, static_cast<uint64_t>(gcode_ids[current.last]));
}
#endif // ENABLE_GCODE_WINDOW
const std::vector<GCodeViewer::Color> GCodeViewer::Extrusion_Role_Colors {{
{ 0.75f, 0.75f, 0.75f }, // erNone
{ 1.00f, 0.90f, 0.30f }, // erPerimeter
@ -395,6 +615,11 @@ void GCodeViewer::load(const GCodeProcessor::Result& gcode_result, const Print&
// release gpu memory, if used
reset();
#if ENABLE_GCODE_WINDOW
m_sequential_view.gcode_window.set_filename(gcode_result.filename);
m_sequential_view.gcode_window.load_gcode();
#endif // ENABLE_GCODE_WINDOW
load_toolpaths(gcode_result);
if (m_layers.empty())
@ -548,7 +773,9 @@ void GCodeViewer::reset()
m_layers_z_range = { 0, 0 };
m_roles = std::vector<ExtrusionRole>();
m_time_statistics.reset();
#if ENABLE_GCODE_WINDOW
m_sequential_view.gcode_window.reset();
#endif // ENABLE_GCODE_WINDOW
#if ENABLE_GCODE_VIEWER_STATISTICS
m_statistics.reset_all();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
@ -608,13 +835,22 @@ void GCodeViewer::render() const
glsafe(::glEnable(GL_DEPTH_TEST));
render_toolpaths();
render_shells();
#if ENABLE_GCODE_WINDOW
float legend_height = 0.0f;
render_legend(legend_height);
#else
render_legend();
#endif // ENABLE_GCODE_WINDOW
SequentialView* sequential_view = const_cast<SequentialView*>(&m_sequential_view);
if (sequential_view->current.last != sequential_view->endpoints.last) {
sequential_view->marker.set_world_position(sequential_view->current_position);
#if ENABLE_GCODE_WINDOW
sequential_view->render(legend_height);
#else
sequential_view->marker.render();
#endif // ENABLE_GCODE_WINDOW
}
render_shells();
render_legend();
#if ENABLE_GCODE_VIEWER_STATISTICS
render_statistics();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
@ -3767,7 +4003,11 @@ void GCodeViewer::render_shells() const
// glsafe(::glDepthMask(GL_TRUE));
}
#if ENABLE_GCODE_WINDOW
void GCodeViewer::render_legend(float& legend_height) const
#else
void GCodeViewer::render_legend() const
#endif // ENABLE_GCODE_WINDOW
{
if (!m_legend_enabled)
return;
@ -4452,6 +4692,10 @@ void GCodeViewer::render_legend() const
}
}
#if ENABLE_GCODE_WINDOW
legend_height = ImGui::GetCurrentWindow()->Size.y;
#endif // ENABLE_GCODE_WINDOW
imgui.end();
ImGui::PopStyleVar();
}

View File

@ -5,6 +5,10 @@
#include "libslic3r/GCode/GCodeProcessor.hpp"
#include "GLModel.hpp"
#if ENABLE_GCODE_WINDOW
#include <boost/iostreams/device/mapped_file.hpp>
#endif // ENABLE_GCODE_WINDOW
#include <cstdint>
#include <float.h>
#include <set>
@ -606,6 +610,46 @@ public:
void render() const;
};
#if ENABLE_GCODE_WINDOW
class GCodeWindow
{
struct Line
{
std::string command;
std::string parameters;
std::string comment;
};
bool m_visible{ true };
uint64_t m_selected_line_id{ 0 };
size_t m_last_lines_size{ 0 };
std::string m_filename;
boost::iostreams::mapped_file_source m_file;
// map for accessing data in file by line number
std::vector<std::pair<uint64_t, uint64_t>> m_lines_map;
// current visible lines
std::vector<Line> m_lines;
public:
GCodeWindow() = default;
~GCodeWindow() { stop_mapping_file(); }
void set_filename(const std::string& filename) { m_filename = filename; }
void load_gcode();
void reset() {
stop_mapping_file();
m_lines_map.clear();
m_lines.clear();
m_filename.clear();
}
void toggle_visibility() { m_visible = !m_visible; }
void render(float top, float bottom, uint64_t curr_line_id) const;
private:
void stop_mapping_file();
};
#endif // ENABLE_GCODE_WINDOW
struct Endpoints
{
size_t first{ 0 };
@ -618,9 +662,16 @@ public:
Endpoints last_current;
Vec3f current_position{ Vec3f::Zero() };
Marker marker;
#if ENABLE_GCODE_WINDOW
GCodeWindow gcode_window;
#endif // ENABLE_GCODE_WINDOW
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
std::vector<unsigned int> gcode_ids;
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
#if ENABLE_GCODE_WINDOW
void render(float legend_height) const;
#endif // ENABLE_GCODE_WINDOW
};
enum class EViewType : unsigned char
@ -715,13 +766,21 @@ public:
void export_toolpaths_to_obj(const char* filename) const;
#if ENABLE_GCODE_WINDOW
void toggle_gcode_window_visibility() { m_sequential_view.gcode_window.toggle_visibility(); }
#endif // ENABLE_GCODE_WINDOW
private:
void load_toolpaths(const GCodeProcessor::Result& gcode_result);
void load_shells(const Print& print, bool initialized);
void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const;
void render_toolpaths() const;
void render_shells() const;
#if ENABLE_GCODE_WINDOW
void render_legend(float& legend_height) const;
#else
void render_legend() const;
#endif // ENABLE_GCODE_WINDOW
#if ENABLE_GCODE_VIEWER_STATISTICS
void render_statistics() const;
#endif // ENABLE_GCODE_VIEWER_STATISTICS

View File

@ -2602,6 +2602,10 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
case 'a': { post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; }
case 'B':
case 'b': { zoom_to_bed(); break; }
#if ENABLE_GCODE_WINDOW
case 'C':
case 'c': { m_gcode_viewer.toggle_gcode_window_visibility(); m_dirty = true; request_extra_frame(); break; }
#endif // ENABLE_GCODE_WINDOW
case 'E':
case 'e': { m_labels.show(!m_labels.is_shown()); m_dirty = true; break; }
case 'G':

View File

@ -196,6 +196,9 @@ void KBShortcutsDialog::fill_shortcuts()
{ "D", L("Horizontal slider - Move active thumb Right") },
{ "X", L("On/Off one layer mode of the vertical slider") },
{ "L", L("Show/Hide Legend and Estimated printing time") },
#if ENABLE_GCODE_WINDOW
{ "C", L("Show/Hide G-code window") },
#endif // ENABLE_GCODE_WINDOW
};
m_full_shortcuts.push_back({ { _L("Preview"), "" }, preview_shortcuts });