Refactoring of the G-code preview for lower memory allocation

and for separation of concerns:

The final G-code preview no more uses ExtrusionPaths structure
to hold the G-code path data extracted by parsing the G-code.
Instead, the ExtrusionPath class has been trimmed down back to
the original size before the G-code preview was introduced,
and a new GCodePreviewData::Extrusion::Path class was created to hold
the additional path data as the extruder ID, color change ID
and fan speed.
This commit is contained in:
bubnikv 2019-09-30 16:25:26 +02:00
parent b425ee50a9
commit 272479826f
7 changed files with 64 additions and 41 deletions

View File

@ -14,7 +14,7 @@ class ExtrusionEntityCollection;
class Extruder;
// Each ExtrusionRole value identifies a distinct set of { extruder, speed }
enum ExtrusionRole {
enum ExtrusionRole : uint8_t {
erNone,
erPerimeter,
erExternalPerimeter,
@ -117,25 +117,16 @@ public:
float width;
// Height of the extrusion, used for visualization purposes.
float height;
// Feedrate of the extrusion, used for visualization purposes.
float feedrate;
// Id of the extruder, used for visualization purposes.
unsigned int extruder_id;
// Id of the color, used for visualization purposes in the color printing case.
unsigned int cp_color_id;
// Fan speed for the extrusion, used for visualization purposes.
float fan_speed;
ExtrusionPath(ExtrusionRole role) : mm3_per_mm(-1), width(-1), height(-1), feedrate(0.0f), extruder_id(0), cp_color_id(0), fan_speed(0.0f), m_role(role) {};
ExtrusionPath(ExtrusionRole role, double mm3_per_mm, float width, float height) : mm3_per_mm(mm3_per_mm), width(width), height(height), feedrate(0.0f), extruder_id(0), cp_color_id(0), fan_speed(0.0f), m_role(role) {};
ExtrusionPath(const ExtrusionPath& rhs) : polyline(rhs.polyline), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), feedrate(rhs.feedrate), extruder_id(rhs.extruder_id), cp_color_id(rhs.cp_color_id), fan_speed(rhs.fan_speed), m_role(rhs.m_role) {}
ExtrusionPath(ExtrusionPath&& rhs) : polyline(std::move(rhs.polyline)), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), feedrate(rhs.feedrate), extruder_id(rhs.extruder_id), cp_color_id(rhs.cp_color_id), fan_speed(rhs.fan_speed), m_role(rhs.m_role) {}
ExtrusionPath(const Polyline &polyline, const ExtrusionPath &rhs) : polyline(polyline), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), feedrate(rhs.feedrate), extruder_id(rhs.extruder_id), cp_color_id(rhs.cp_color_id), fan_speed(rhs.fan_speed), m_role(rhs.m_role) {}
ExtrusionPath(Polyline &&polyline, const ExtrusionPath &rhs) : polyline(std::move(polyline)), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), feedrate(rhs.feedrate), extruder_id(rhs.extruder_id), cp_color_id(rhs.cp_color_id), fan_speed(rhs.fan_speed), m_role(rhs.m_role) {}
// ExtrusionPath(ExtrusionRole role, const Flow &flow) : m_role(role), mm3_per_mm(flow.mm3_per_mm()), width(flow.width), height(flow.height), feedrate(0.0f), extruder_id(0) {};
ExtrusionPath(ExtrusionRole role) : mm3_per_mm(-1), width(-1), height(-1), m_role(role) {};
ExtrusionPath(ExtrusionRole role, double mm3_per_mm, float width, float height) : mm3_per_mm(mm3_per_mm), width(width), height(height), m_role(role) {};
ExtrusionPath(const ExtrusionPath& rhs) : polyline(rhs.polyline), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), m_role(rhs.m_role) {}
ExtrusionPath(ExtrusionPath&& rhs) : polyline(std::move(rhs.polyline)), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), m_role(rhs.m_role) {}
ExtrusionPath(const Polyline &polyline, const ExtrusionPath &rhs) : polyline(polyline), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), m_role(rhs.m_role) {}
ExtrusionPath(Polyline &&polyline, const ExtrusionPath &rhs) : polyline(std::move(polyline)), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), m_role(rhs.m_role) {}
ExtrusionPath& operator=(const ExtrusionPath& rhs) { m_role = rhs.m_role; this->mm3_per_mm = rhs.mm3_per_mm; this->width = rhs.width; this->height = rhs.height; this->feedrate = rhs.feedrate, this->extruder_id = rhs.extruder_id, this->cp_color_id = rhs.cp_color_id, this->fan_speed = rhs.fan_speed, this->polyline = rhs.polyline; return *this; }
ExtrusionPath& operator=(ExtrusionPath&& rhs) { m_role = rhs.m_role; this->mm3_per_mm = rhs.mm3_per_mm; this->width = rhs.width; this->height = rhs.height; this->feedrate = rhs.feedrate, this->extruder_id = rhs.extruder_id, this->cp_color_id = rhs.cp_color_id, this->fan_speed = rhs.fan_speed, this->polyline = std::move(rhs.polyline); return *this; }
ExtrusionPath& operator=(const ExtrusionPath& rhs) { m_role = rhs.m_role; this->mm3_per_mm = rhs.mm3_per_mm; this->width = rhs.width; this->height = rhs.height; this->polyline = rhs.polyline; return *this; }
ExtrusionPath& operator=(ExtrusionPath&& rhs) { m_role = rhs.m_role; this->mm3_per_mm = rhs.mm3_per_mm; this->width = rhs.width; this->height = rhs.height; this->polyline = std::move(rhs.polyline); return *this; }
ExtrusionEntity* clone() const override { return new ExtrusionPath(*this); }
// Create a new object, initialize it with this object using the move semantics.

View File

@ -866,7 +866,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
}
// if layer not found, create and return it
layers.emplace_back(z, ExtrusionPaths());
layers.emplace_back(z, GCodePreviewData::Extrusion::Paths());
return layers.back();
}
@ -875,14 +875,18 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
// if the polyline is valid, create the extrusion path from it and store it
if (polyline.is_valid())
{
ExtrusionPath path(data.extrusion_role, data.mm3_per_mm, data.width, data.height);
auto& paths = get_layer_at_z(preview_data.extrusion.layers, z).paths;
paths.emplace_back(GCodePreviewData::Extrusion::Path());
GCodePreviewData::Extrusion::Path &path = paths.back();
path.polyline = polyline;
path.extrusion_role = data.extrusion_role;
path.mm3_per_mm = data.mm3_per_mm;
path.width = data.width;
path.height = data.height;
path.feedrate = data.feedrate;
path.extruder_id = data.extruder_id;
path.fan_speed = data.fan_speed;
path.cp_color_id = data.cp_color_id;
get_layer_at_z(preview_data.extrusion.layers, z).paths.push_back(path);
path.fan_speed = data.fan_speed;
}
}
};

View File

@ -23,7 +23,7 @@ std::vector<unsigned char> GCodePreviewData::Color::as_bytes() const
return ret;
}
GCodePreviewData::Extrusion::Layer::Layer(float z, const ExtrusionPaths& paths)
GCodePreviewData::Extrusion::Layer::Layer(float z, const Paths& paths)
: z(z)
, paths(paths)
{
@ -171,8 +171,8 @@ size_t GCodePreviewData::Extrusion::memory_used() const
size_t out = sizeof(*this);
out += SLIC3R_STDVEC_MEMSIZE(this->layers, Layer);
for (const Layer &layer : this->layers) {
out += SLIC3R_STDVEC_MEMSIZE(layer.paths, ExtrusionPath);
for (const ExtrusionPath &path : layer.paths)
out += SLIC3R_STDVEC_MEMSIZE(layer.paths, Path);
for (const Path &path : layer.paths)
out += SLIC3R_STDVEC_MEMSIZE(path.polyline.points, Point);
}
return out;

View File

@ -87,12 +87,34 @@ public:
static const std::string Default_Extrusion_Role_Names[erCount];
static const EViewType Default_View_Type;
class Path
{
public:
Polyline polyline;
ExtrusionRole extrusion_role;
// Volumetric velocity. mm^3 of plastic per mm of linear head motion. Used by the G-code generator.
float mm3_per_mm;
// Width of the extrusion, used for visualization purposes.
float width;
// Height of the extrusion, used for visualization purposes.
float height;
// Feedrate of the extrusion, used for visualization purposes.
float feedrate;
// Id of the extruder, used for visualization purposes.
uint32_t extruder_id;
// Id of the color, used for visualization purposes in the color printing case.
uint32_t cp_color_id;
// Fan speed for the extrusion, used for visualization purposes.
float fan_speed;
};
using Paths = std::vector<Path>;
struct Layer
{
float z;
ExtrusionPaths paths;
Paths paths;
Layer(float z, const ExtrusionPaths& paths);
Layer(float z, const Paths& paths);
};
typedef std::vector<Layer> LayersList;

View File

@ -1717,13 +1717,18 @@ static void thick_point_to_verts(const Vec3crd& point,
point_to_indexed_vertex_array(point, width, height, volume.indexed_vertex_array);
}
void _3DScene::extrusionentity_to_verts(const Polyline &polyline, float width, float height, float print_z, GLVolume& volume)
{
if (polyline.size() >= 2) {
size_t num_segments = polyline.size() - 1;
thick_lines_to_verts(polyline.lines(), std::vector<double>(num_segments, width), std::vector<double>(num_segments, height), false, print_z, volume);
}
}
// Fill in the qverts and tverts with quads and triangles for the extrusion_path.
void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, GLVolume &volume)
{
Lines lines = extrusion_path.polyline.lines();
std::vector<double> widths(lines.size(), extrusion_path.width);
std::vector<double> heights(lines.size(), extrusion_path.height);
thick_lines_to_verts(lines, widths, heights, false, print_z, volume);
extrusionentity_to_verts(extrusion_path.polyline, extrusion_path.width, extrusion_path.height, print_z, volume);
}
// Fill in the qverts and tverts with quads and triangles for the extrusion_path.

View File

@ -656,6 +656,7 @@ public:
static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GLVolume& volume);
static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GLVolume& volume);
static void extrusionentity_to_verts(const Polyline &polyline, float width, float height, float print_z, GLVolume& volume);
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, GLVolume& volume);
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GLVolume& volume);
static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GLVolume& volume);

View File

@ -4987,13 +4987,13 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
// helper functions to select data in dependence of the extrusion view type
struct Helper
{
static float path_filter(GCodePreviewData::Extrusion::EViewType type, const ExtrusionPath& path)
static float path_filter(GCodePreviewData::Extrusion::EViewType type, const GCodePreviewData::Extrusion::Path& path)
{
switch (type)
{
case GCodePreviewData::Extrusion::FeatureType:
// The role here is used for coloring.
return (float)path.role();
return (float)path.extrusion_role;
case GCodePreviewData::Extrusion::Height:
return path.height;
case GCodePreviewData::Extrusion::Width:
@ -5071,15 +5071,15 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
{
std::vector<size_t> num_paths_per_role(size_t(erCount), 0);
for (const GCodePreviewData::Extrusion::Layer &layer : preview_data.extrusion.layers)
for (const ExtrusionPath &path : layer.paths)
++ num_paths_per_role[size_t(path.role())];
for (const GCodePreviewData::Extrusion::Path &path : layer.paths)
++ num_paths_per_role[size_t(path.extrusion_role)];
std::vector<std::vector<float>> roles_values;
roles_values.assign(size_t(erCount), std::vector<float>());
for (size_t i = 0; i < roles_values.size(); ++ i)
roles_values[i].reserve(num_paths_per_role[i]);
for (const GCodePreviewData::Extrusion::Layer& layer : preview_data.extrusion.layers)
for (const ExtrusionPath& path : layer.paths)
roles_values[size_t(path.role())].emplace_back(Helper::path_filter(preview_data.extrusion.view_type, path));
for (const GCodePreviewData::Extrusion::Path &path : layer.paths)
roles_values[size_t(path.extrusion_role)].emplace_back(Helper::path_filter(preview_data.extrusion.view_type, path));
roles_filters.reserve(size_t(erCount));
size_t num_buffers = 0;
for (std::vector<float> &values : roles_values) {
@ -5107,9 +5107,9 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
// populates volumes
for (const GCodePreviewData::Extrusion::Layer& layer : preview_data.extrusion.layers)
{
for (const ExtrusionPath& path : layer.paths)
for (const GCodePreviewData::Extrusion::Path& path : layer.paths)
{
std::vector<std::pair<float, GLVolume*>> &filters = roles_filters[size_t(path.role())];
std::vector<std::pair<float, GLVolume*>> &filters = roles_filters[size_t(path.extrusion_role)];
auto key = std::make_pair<float, GLVolume*>(Helper::path_filter(preview_data.extrusion.view_type, path), nullptr);
auto it_filter = std::lower_bound(filters.begin(), filters.end(), key);
assert(it_filter != filters.end() && key.first == it_filter->first);
@ -5119,7 +5119,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size());
vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size());
_3DScene::extrusionentity_to_verts(path, layer.z, vol);
_3DScene::extrusionentity_to_verts(path.polyline, path.width, path.height, layer.z, vol);
}
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
for (std::vector<std::pair<float, GLVolume*>> &filters : roles_filters) {