From 0f4bec8af0d3c31741db8765fc8ed3fee437312e Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Mon, 8 Jan 2018 13:44:10 +0100 Subject: [PATCH 01/23] gcode preview - first installment - wip --- lib/Slic3r/GUI/3DScene.pm | 9 + lib/Slic3r/GUI/Plater.pm | 12 + lib/Slic3r/GUI/Plater/3DPreview.pm | 113 +++- lib/Slic3r/GUI/Plater/3DToolpaths.pm | 24 +- xs/src/libslic3r/BoundingBox.cpp | 12 + xs/src/libslic3r/BoundingBox.hpp | 54 ++ xs/src/libslic3r/ExtrusionEntity.hpp | 29 +- xs/src/libslic3r/GCode.cpp | 114 ++++ xs/src/libslic3r/GCode.hpp | 61 ++ xs/src/libslic3r/GCode/Analyzer.cpp | 960 +++++++++++++++++++++++++++ xs/src/libslic3r/GCode/Analyzer.hpp | 382 ++++++++++- xs/src/libslic3r/Line.cpp | 14 + xs/src/libslic3r/Line.hpp | 27 + xs/src/libslic3r/MultiPoint.cpp | 59 ++ xs/src/libslic3r/MultiPoint.hpp | 28 + xs/src/libslic3r/Point.hpp | 60 ++ xs/src/libslic3r/Polyline.cpp | 18 + xs/src/libslic3r/Polyline.hpp | 12 + xs/src/libslic3r/Print.cpp | 35 + xs/src/libslic3r/Print.hpp | 21 + xs/src/libslic3r/libslic3r.h | 17 + xs/src/slic3r/GUI/3DScene.cpp | 479 ++++++++++++- xs/src/slic3r/GUI/3DScene.hpp | 23 + xs/xsp/GUI_3DScene.xsp | 8 + xs/xsp/Print.xsp | 8 + 25 files changed, 2552 insertions(+), 27 deletions(-) diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index 730216a8b..f97586073 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -1979,6 +1979,15 @@ sub load_wipe_tower_toolpaths { if ($print->step_done(STEP_WIPE_TOWER)); } +# ===================== ENRICO_GCODE_PREVIEW ================================================== +sub load_gcode_preview { + my ($self, $print) = @_; + + $self->SetCurrent($self->GetContext) if $self->UseVBOs; + Slic3r::GUI::_3DScene::load_gcode_preview($print, $self->volumes, $self->UseVBOs); +} +# ===================== ENRICO_GCODE_PREVIEW ================================================== + sub set_toolpaths_range { my ($self, $min_z, $max_z) = @_; $self->volumes->set_range($min_z, $max_z); diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 10d65475c..63e628f3e 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -776,6 +776,9 @@ sub remove { splice @{$self->{objects}}, $obj_idx, 1; $self->{model}->delete_object($obj_idx); $self->{print}->delete_object($obj_idx); +# ===================== ENRICO_GCODE_PREVIEW ================================================== + $self->{print}->clear_gcode_preview_data; +# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->{list}->DeleteItem($obj_idx); $self->object_list_changed; @@ -796,6 +799,9 @@ sub reset { @{$self->{objects}} = (); $self->{model}->clear_objects; $self->{print}->clear_objects; +# ===================== ENRICO_GCODE_PREVIEW ================================================== + $self->{print}->clear_gcode_preview_data; +# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->{list}->DeleteAllItems; $self->object_list_changed; @@ -1435,6 +1441,12 @@ sub on_export_completed { # this updates buttons status $self->object_list_changed; + +# ===================== ENRICO_GCODE_PREVIEW ================================================== + # refresh preview + $self->{toolpaths2D}->reload_print if $self->{toolpaths2D}; + $self->{preview3D}->reload_print if $self->{preview3D}; +# ===================== ENRICO_GCODE_PREVIEW ================================================== } sub do_print { diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index c7d4cc4a8..9ff3461e0 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -5,10 +5,16 @@ use utf8; use Slic3r::Print::State ':steps'; use Wx qw(:misc :sizer :slider :statictext :keycode wxWHITE); -use Wx::Event qw(EVT_SLIDER EVT_KEY_DOWN EVT_CHECKBOX); +# ===================== ENRICO_GCODE_PREVIEW ================================================== +use Wx::Event qw(EVT_SLIDER EVT_KEY_DOWN EVT_CHECKBOX EVT_CHOICE EVT_CHECKLISTBOX); +#use Wx::Event qw(EVT_SLIDER EVT_KEY_DOWN EVT_CHECKBOX); +# ===================== ENRICO_GCODE_PREVIEW ================================================== use base qw(Wx::Panel Class::Accessor); -__PACKAGE__->mk_accessors(qw(print enabled _loaded canvas slider_low slider_high single_layer)); +# ===================== ENRICO_GCODE_PREVIEW ================================================== +__PACKAGE__->mk_accessors(qw(print enabled _loaded canvas slider_low slider_high single_layer auto_zoom)); +#__PACKAGE__->mk_accessors(qw(print enabled _loaded canvas slider_low slider_high single_layer)); +# ===================== ENRICO_GCODE_PREVIEW ================================================== sub new { my $class = shift; @@ -18,6 +24,9 @@ sub new { $self->{config} = $config; $self->{number_extruders} = 1; $self->{preferred_color_mode} = 'feature'; +# ===================== ENRICO_GCODE_PREVIEW ================================================== + $self->auto_zoom(1); +# ===================== ENRICO_GCODE_PREVIEW ================================================== # init GUI elements my $canvas = Slic3r::GUI::3DScene->new($self); @@ -60,6 +69,35 @@ sub new { my $checkbox_singlelayer = $self->{checkbox_singlelayer} = Wx::CheckBox->new($self, -1, "1 Layer"); my $checkbox_color_by_extruder = $self->{checkbox_color_by_extruder} = Wx::CheckBox->new($self, -1, "Tool"); +# ===================== ENRICO_GCODE_PREVIEW ================================================== + my $choice_view_type = Wx::Choice->new($self, -1); + $choice_view_type->Append("Feature type"); + $choice_view_type->Append("Height"); + $choice_view_type->Append("Width"); + $choice_view_type->Append("Speed"); + $choice_view_type->SetSelection(0); + + my $checklist_features = Wx::CheckListBox->new($self, -1, wxDefaultPosition, [-1, 150]); + $checklist_features->Append("Perimeter"); + $checklist_features->Append("External perimeter"); + $checklist_features->Append("Overhang perimeter"); + $checklist_features->Append("Internal infill"); + $checklist_features->Append("Solid infill"); + $checklist_features->Append("Top solid infill"); + $checklist_features->Append("Bridge infill"); + $checklist_features->Append("Gap fill"); + $checklist_features->Append("Skirt"); + $checklist_features->Append("Support material"); + $checklist_features->Append("Support material interface"); + for (my $i = 0; $i < $checklist_features->GetCount(); $i += 1) + { + $checklist_features->Check($i, 1); + } + + my $checkbox_travel = Wx::CheckBox->new($self, -1, "Travel"); + my $checkbox_retractions = Wx::CheckBox->new($self, -1, "Retractions"); +# ===================== ENRICO_GCODE_PREVIEW ================================================== + my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL); my $vsizer = Wx::BoxSizer->new(wxVERTICAL); my $vsizer_outer = Wx::BoxSizer->new(wxVERTICAL); @@ -73,6 +111,12 @@ sub new { $vsizer_outer->Add($hsizer, 3, wxALIGN_CENTER_HORIZONTAL, 0); $vsizer_outer->Add($checkbox_singlelayer, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, 5); $vsizer_outer->Add($checkbox_color_by_extruder, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, 5); +# ===================== ENRICO_GCODE_PREVIEW ================================================== + $vsizer_outer->Add($choice_view_type, 0, wxEXPAND | wxALL | wxALIGN_CENTER_HORIZONTAL, 5); + $vsizer_outer->Add($checklist_features, 0, wxTOP | wxALL | wxALIGN_CENTER_HORIZONTAL, 5); + $vsizer_outer->Add($checkbox_travel, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + $vsizer_outer->Add($checkbox_retractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); +# ===================== ENRICO_GCODE_PREVIEW ================================================== my $sizer = Wx::BoxSizer->new(wxHORIZONTAL); $sizer->Add($canvas, 1, wxALL | wxEXPAND, 0); @@ -153,6 +197,39 @@ sub new { $self->reload_print; }); +# ===================== ENRICO_GCODE_PREVIEW ================================================== + EVT_CHOICE($self, $choice_view_type, sub { + my $selection = $choice_view_type->GetCurrentSelection(); + $self->print->set_gcode_preview_type($selection); + $self->auto_zoom(0); + $self->reload_print; + }); + EVT_CHECKLISTBOX($self, $checklist_features, sub { + my $flags = 0; + for (my $i = 0; $i < $checklist_features->GetCount(); $i += 1) + { + if ($checklist_features->IsChecked($i)) + { + $flags += 2 ** $i; + } + } + + $self->print->set_gcode_preview_extrusion_flags($flags); + $self->auto_zoom(0); + $self->reload_print; + }); + EVT_CHECKBOX($self, $checkbox_travel, sub { + $self->print->set_gcode_preview_travel_visible($checkbox_travel->IsChecked()); + $self->auto_zoom(0); + $self->reload_print; + }); + EVT_CHECKBOX($self, $checkbox_retractions, sub { + $self->print->set_gcode_preview_retractions_visible($checkbox_retractions->IsChecked()); + $self->auto_zoom(0); + $self->reload_print; + }); +# ===================== ENRICO_GCODE_PREVIEW ================================================== + $self->SetSizer($sizer); $self->SetMinSize($self->GetSize); $sizer->SetSizeHints($self); @@ -258,18 +335,30 @@ sub load_print { } if ($self->IsShown) { +# ===================== ENRICO_GCODE_PREVIEW ================================================== + $self->canvas->load_gcode_preview($self->print); + # load skirt and brim - $self->canvas->load_print_toolpaths($self->print, \@colors); - $self->canvas->load_wipe_tower_toolpaths($self->print, \@colors); - - foreach my $object (@{$self->print->objects}) { - $self->canvas->load_print_object_toolpaths($object, \@colors); - - # Show the objects in very transparent color. - #my @volume_ids = $self->canvas->load_object($object->model_object); - #$self->canvas->volumes->[$_]->color->[3] = 0.2 for @volume_ids; - } +# $self->canvas->load_print_toolpaths($self->print, \@colors); +# $self->canvas->load_wipe_tower_toolpaths($self->print, \@colors); +# +# foreach my $object (@{$self->print->objects}) { +# $self->canvas->load_print_object_toolpaths($object, \@colors); +# +# # Show the objects in very transparent color. +# #my @volume_ids = $self->canvas->load_object($object->model_object); +# #$self->canvas->volumes->[$_]->color->[3] = 0.2 for @volume_ids; +# } +# ===================== ENRICO_GCODE_PREVIEW ================================================== +# ===================== ENRICO_GCODE_PREVIEW ================================================== + if ($self->auto_zoom) + { +# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->canvas->zoom_to_volumes; +# ===================== ENRICO_GCODE_PREVIEW ================================================== + $self->auto_zoom(1); + } +# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->_loaded(1); } diff --git a/lib/Slic3r/GUI/Plater/3DToolpaths.pm b/lib/Slic3r/GUI/Plater/3DToolpaths.pm index fb904b0fd..3dbe59d57 100644 --- a/lib/Slic3r/GUI/Plater/3DToolpaths.pm +++ b/lib/Slic3r/GUI/Plater/3DToolpaths.pm @@ -122,16 +122,20 @@ sub load_print { } if ($self->IsShown) { - # load skirt and brim - $self->canvas->load_print_toolpaths($self->print); - - foreach my $object (@{$self->print->objects}) { - $self->canvas->load_print_object_toolpaths($object); - - # Show the objects in very transparent color. - #my @volume_ids = $self->canvas->load_object($object->model_object); - #$self->canvas->volumes->[$_]->color->[3] = 0.2 for @volume_ids; - } +# ===================== ENRICO_GCODE_PREVIEW ================================================== + $self->canvas->load_gcode_preview($self->print); + +# # load skirt and brim +# $self->canvas->load_print_toolpaths($self->print); +# +# foreach my $object (@{$self->print->objects}) { +# $self->canvas->load_print_object_toolpaths($object); +# +# # Show the objects in very transparent color. +# #my @volume_ids = $self->canvas->load_object($object->model_object); +# #$self->canvas->volumes->[$_]->color->[3] = 0.2 for @volume_ids; +# } +# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->canvas->zoom_to_volumes; $self->_loaded(1); } diff --git a/xs/src/libslic3r/BoundingBox.cpp b/xs/src/libslic3r/BoundingBox.cpp index 46a43ca69..929488a3a 100644 --- a/xs/src/libslic3r/BoundingBox.cpp +++ b/xs/src/libslic3r/BoundingBox.cpp @@ -4,6 +4,9 @@ namespace Slic3r { +//############################################################################################################ +#if !ENRICO_GCODE_PREVIEW +//############################################################################################################ template <class PointClass> BoundingBoxBase<PointClass>::BoundingBoxBase(const std::vector<PointClass> &points) { @@ -20,9 +23,15 @@ BoundingBoxBase<PointClass>::BoundingBoxBase(const std::vector<PointClass> &poin } this->defined = true; } +//############################################################################################################ +#endif // !ENRICO_GCODE_PREVIEW +//############################################################################################################ template BoundingBoxBase<Point>::BoundingBoxBase(const std::vector<Point> &points); template BoundingBoxBase<Pointf>::BoundingBoxBase(const std::vector<Pointf> &points); +//############################################################################################################ +#if !ENRICO_GCODE_PREVIEW +//############################################################################################################ template <class PointClass> BoundingBox3Base<PointClass>::BoundingBox3Base(const std::vector<PointClass> &points) : BoundingBoxBase<PointClass>(points) @@ -36,6 +45,9 @@ BoundingBox3Base<PointClass>::BoundingBox3Base(const std::vector<PointClass> &po this->max.z = std::max(it->z, this->max.z); } } +//############################################################################################################ +#endif // !ENRICO_GCODE_PREVIEW +//############################################################################################################ template BoundingBox3Base<Pointf3>::BoundingBox3Base(const std::vector<Pointf3> &points); BoundingBox::BoundingBox(const Lines &lines) diff --git a/xs/src/libslic3r/BoundingBox.hpp b/xs/src/libslic3r/BoundingBox.hpp index 90179d3f9..f1782805b 100644 --- a/xs/src/libslic3r/BoundingBox.hpp +++ b/xs/src/libslic3r/BoundingBox.hpp @@ -23,7 +23,31 @@ public: BoundingBoxBase() : defined(false) {}; BoundingBoxBase(const PointClass &pmin, const PointClass &pmax) : min(pmin), max(pmax), defined(pmin.x < pmax.x && pmin.y < pmax.y) {} +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + BoundingBoxBase(const std::vector<PointClass>& points) + { + if (points.empty()) + CONFESS("Empty point set supplied to BoundingBoxBase constructor"); + + std::vector<PointClass>::const_iterator it = points.begin(); + this->min.x = this->max.x = it->x; + this->min.y = this->max.y = it->y; + for (++it; it != points.end(); ++it) + { + this->min.x = std::min(it->x, this->min.x); + this->min.y = std::min(it->y, this->min.y); + this->max.x = std::max(it->x, this->max.x); + this->max.y = std::max(it->y, this->max.y); + } + this->defined = (this->min.x < this->max.x) && (this->min.y < this->max.y); + } +#else +//############################################################################################################ BoundingBoxBase(const std::vector<PointClass> &points); +//############################################################################################################ +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ void merge(const PointClass &point); void merge(const std::vector<PointClass> &points); void merge(const BoundingBoxBase<PointClass> &bb); @@ -54,7 +78,29 @@ public: BoundingBox3Base(const PointClass &pmin, const PointClass &pmax) : BoundingBoxBase<PointClass>(pmin, pmax) { if (pmin.z >= pmax.z) BoundingBoxBase<PointClass>::defined = false; } +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + BoundingBox3Base(const std::vector<PointClass>& points) + : BoundingBoxBase<PointClass>(points) + { + if (points.empty()) + CONFESS("Empty point set supplied to BoundingBox3Base constructor"); + + std::vector<PointClass>::const_iterator it = points.begin(); + this->min.z = this->max.z = it->z; + for (++it; it != points.end(); ++it) + { + this->min.z = std::min(it->z, this->min.z); + this->max.z = std::max(it->z, this->max.z); + } + this->defined &= (this->min.z < this->max.z); + } +#else +//############################################################################################################ BoundingBox3Base(const std::vector<PointClass> &points); +//############################################################################################################ +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ void merge(const PointClass &point); void merge(const std::vector<PointClass> &points); void merge(const BoundingBox3Base<PointClass> &bb); @@ -92,7 +138,15 @@ class BoundingBox3 : public BoundingBox3Base<Point3> public: BoundingBox3() : BoundingBox3Base<Point3>() {}; BoundingBox3(const Point3 &pmin, const Point3 &pmax) : BoundingBox3Base<Point3>(pmin, pmax) {}; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + BoundingBox3(const Points3& points) : BoundingBox3Base<Point3>(points) {}; +#else +//############################################################################################################ BoundingBox3(const std::vector<Point3> &points) : BoundingBox3Base<Point3>(points) {}; +//############################################################################################################ +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ }; class BoundingBoxf : public BoundingBoxBase<Pointf> diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp index 6e5b123dc..282a0b5d4 100644 --- a/xs/src/libslic3r/ExtrusionEntity.hpp +++ b/xs/src/libslic3r/ExtrusionEntity.hpp @@ -104,15 +104,42 @@ public: float width; // Height of the extrusion, used for visualization purposed. float height; - +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + // Feedrate of the extrusion, used for visualization purposed. + float feedrate; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + ExtrusionPath(ExtrusionRole role) : mm3_per_mm(-1), width(-1), height(-1), feedrate(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), 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), 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), 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) {}; +#else +//############################################################################################################ 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(ExtrusionRole role, const Flow &flow) : m_role(role), mm3_per_mm(flow.mm3_per_mm()), width(flow.width), height(flow.height) {}; +//############################################################################################################ +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + ExtrusionPath& operator=(const ExtrusionPath &rhs) { this->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->polyline = rhs.polyline; return *this; } + ExtrusionPath& operator=(ExtrusionPath &&rhs) { this->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->polyline = std::move(rhs.polyline); return *this; } +#else +//############################################################################################################ ExtrusionPath& operator=(const ExtrusionPath &rhs) { this->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) { this->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; } +//############################################################################################################ +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ ExtrusionPath* clone() const { return new ExtrusionPath (*this); } void reverse() { this->polyline.reverse(); } diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index e85b21f80..97347b9b9 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -401,6 +401,18 @@ void GCode::_do_export(Print &print, FILE *file) // resets time estimator m_time_estimator.reset(); +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + // resets analyzer + m_analyzer.reset(); + + // resets analyzer's tracking data + m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm; + m_last_width = GCodeAnalyzer::Default_Width; + m_last_height = GCodeAnalyzer::Default_Height; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + // How many times will be change_layer() called? // change_layer() in turn increments the progress bar status. m_layer_count = 0; @@ -809,6 +821,13 @@ void GCode::_do_export(Print &print, FILE *file) _write_format(file, "; %s = %s\n", key.c_str(), cfg->serialize(key).c_str()); } } + +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + // starts analizer calculations + m_analyzer.calc_gcode_preview_data(print); +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ } std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override) @@ -1300,12 +1319,18 @@ void GCode::process_layer( if (print_object == nullptr) // This layer is empty for this particular object, it has neither object extrusions nor support extrusions at this print_z. continue; +//############################################################################################################ +#if !ENRICO_GCODE_PREVIEW +//############################################################################################################ if (m_enable_analyzer_markers) { // Store the binary pointer to the layer object directly into the G-code to be accessed by the GCodeAnalyzer. char buf[64]; sprintf(buf, ";_LAYEROBJ:%p\n", m_layer); gcode += buf; } +//############################################################################################################ +#endif // !ENRICO_GCODE_PREVIEW +//############################################################################################################ m_config.apply(print_object->config, true); m_layer = layers[layer_id].layer(); if (m_config.avoid_crossing_perimeters) @@ -1997,13 +2022,36 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill return gcode; } +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +void GCode::_write(FILE* file, const char *what) +#else +//############################################################################################################ void GCode::_write(FILE* file, const char *what, size_t size) +//############################################################################################################ +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ { +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + if (what != nullptr) { + // apply analyzer, if enabled + const char* gcode = m_enable_analyzer ? m_analyzer.process_gcode(what).c_str() : what; + + // writes string to file + fwrite(gcode, 1, ::strlen(gcode), file); + // updates time estimator and gcode lines vector + m_time_estimator.add_gcode_block(gcode); +#else +//############################################################################################################ if (size > 0) { // writes string to file fwrite(what, 1, size, file); // updates time estimator and gcode lines vector m_time_estimator.add_gcode_block(what); +//############################################################################################################ +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ } } @@ -2037,7 +2085,15 @@ void GCode::_write_format(FILE* file, const char* format, ...) char *bufptr = buffer_dynamic ? (char*)malloc(buflen) : buffer; int res = ::vsnprintf(bufptr, buflen, format, args); if (res > 0) +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + _write(file, bufptr); +#else +//############################################################################################################ _write(file, bufptr, res); +//############################################################################################################ +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ if (buffer_dynamic) free(bufptr); @@ -2122,6 +2178,60 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, double F = speed * 60; // convert mm/sec to mm/min // extrude arc or line +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + if (m_enable_extrusion_role_markers || m_enable_analyzer) + { + if (path.role() != m_last_extrusion_role) + { + m_last_extrusion_role = path.role(); + if (m_enable_extrusion_role_markers) + { + char buf[32]; + sprintf(buf, ";_EXTRUSION_ROLE:%d\n", int(m_last_extrusion_role)); + gcode += buf; + } + if (m_enable_analyzer) + { + char buf[32]; + sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), int(m_last_extrusion_role)); + gcode += buf; + } + } + } + + // adds analyzer tags and updates analyzer's tracking data + if (m_enable_analyzer) + { + if (m_last_mm3_per_mm != path.mm3_per_mm) + { + m_last_mm3_per_mm = path.mm3_per_mm; + + char buf[32]; + sprintf(buf, ";%s%f\n", GCodeAnalyzer::Mm3_Per_Mm_Tag.c_str(), m_last_mm3_per_mm); + gcode += buf; + } + + if (m_last_width != path.width) + { + m_last_width = path.width; + + char buf[32]; + sprintf(buf, ";%s%f\n", GCodeAnalyzer::Width_Tag.c_str(), m_last_width); + gcode += buf; + } + + if (m_last_height != path.height) + { + m_last_height = path.height; + + char buf[32]; + sprintf(buf, ";%s%f\n", GCodeAnalyzer::Height_Tag.c_str(), m_last_height); + gcode += buf; + } + } +#else +//############################################################################################################ if (m_enable_extrusion_role_markers || m_enable_analyzer_markers) { if (path.role() != m_last_extrusion_role) { m_last_extrusion_role = path.role(); @@ -2130,6 +2240,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, gcode += buf; } } +//############################################################################################################ +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + std::string comment; if (m_enable_cooling_markers) { if (is_bridge(path.role())) diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index 5c622ec2d..97d6d6927 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -17,6 +17,11 @@ #include "GCode/WipeTower.hpp" #include "GCodeTimeEstimator.hpp" #include "EdgeGrid.hpp" +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +#include "GCode/Analyzer.hpp" +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ #include <memory> #include <string> @@ -118,13 +123,28 @@ public: m_enable_loop_clipping(true), m_enable_cooling_markers(false), m_enable_extrusion_role_markers(false), +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + m_enable_analyzer(true), +#else +//############################################################################################################ m_enable_analyzer_markers(false), +//############################################################################################################ +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ m_layer_count(0), m_layer_index(-1), m_layer(nullptr), m_volumetric_speed(0), m_last_pos_defined(false), m_last_extrusion_role(erNone), +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + m_last_mm3_per_mm(GCodeAnalyzer::Default_mm3_per_mm), + m_last_width(GCodeAnalyzer::Default_Width), + m_last_height(GCodeAnalyzer::Default_Height), +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ m_brim_done(false), m_second_layer_things_done(false), m_last_obj_copy(nullptr, Point(std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max())) @@ -149,6 +169,12 @@ public: // inside the generated string and after the G-code export finishes. std::string placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override = nullptr); bool enable_cooling_markers() const { return m_enable_cooling_markers; } +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + bool enable_analyzer() const { return m_enable_analyzer; } + void enable_analyzer(bool enable) { m_enable_analyzer = enable; } +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ // For Perl bindings, to be used exclusively by unit tests. unsigned int layer_count() const { return m_layer_count; } @@ -241,9 +267,20 @@ protected: // Markers for the Pressure Equalizer to recognize the extrusion type. // The Pressure Equalizer removes the markers from the final G-code. bool m_enable_extrusion_role_markers; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + // Enableds the G-code Analyzer. + // Extended markers will be added during G-code generation. + // The G-code Analyzer will remove these comments from the final G-code. + bool m_enable_analyzer; +#else +//############################################################################################################ // Extended markers for the G-code Analyzer. // The G-code Analyzer will remove these comments from the final G-code. bool m_enable_analyzer_markers; +//############################################################################################################ +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ // How many times will change_layer() be called? // change_layer() will update the progress bar. unsigned int m_layer_count; @@ -256,6 +293,14 @@ protected: double m_volumetric_speed; // Support for the extrusion role markers. Which marker is active? ExtrusionRole m_last_extrusion_role; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + // Support for G-Code Analyzer + double m_last_mm3_per_mm; + float m_last_width; + float m_last_height; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ Point m_last_pos; bool m_last_pos_defined; @@ -277,9 +322,25 @@ protected: // Time estimator GCodeTimeEstimator m_time_estimator; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + // Analyzer + GCodeAnalyzer m_analyzer; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + // Write a string into a file. +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + void _write(FILE* file, const std::string& what) { this->_write(file, what.c_str()); } + void _write(FILE* file, const char *what); +#else +//############################################################################################################ void _write(FILE* file, const std::string& what) { this->_write(file, what.c_str(), what.size()); } void _write(FILE* file, const char *what, size_t size); +//############################################################################################################ +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ // Write a string into a file. // Add a newline, if the string does not end with a newline already. diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp index ab2955eb5..467e2b6ae 100644 --- a/xs/src/libslic3r/GCode/Analyzer.cpp +++ b/xs/src/libslic3r/GCode/Analyzer.cpp @@ -4,11 +4,31 @@ #include "../libslic3r.h" #include "../PrintConfig.hpp" +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +#include "Print.hpp" +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ #include "Analyzer.hpp" +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +static const std::string AXIS_STR = "XYZE"; +static const float MMMIN_TO_MMSEC = 1.0f / 60.0f; +static const float INCHES_TO_MM = 25.4f; +static const float DEFAULT_FEEDRATE = 0.0f; +static const unsigned int DEFAULT_EXTRUDER_ID = 0; +static const Slic3r::Pointf3 DEFAULT_START_POSITION = Slic3r::Pointf3(0.0f, 0.0f, 0.0f); +static const float DEFAULT_START_EXTRUSION = 0.0f; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + namespace Slic3r { +//############################################################################################################ +#if !ENRICO_GCODE_PREVIEW +//############################################################################################################ void GCodeMovesDB::reset() { for (size_t i = 0; i < m_layers.size(); ++ i) @@ -322,5 +342,945 @@ void GCodeAnalyzer::push_to_output(const char *text, const size_t len, bool add_ output_buffer[output_buffer_length ++] = '\n'; output_buffer[output_buffer_length] = 0; } +//############################################################################################################ +#endif // !ENRICO_GCODE_PREVIEW +//############################################################################################################ + +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +const std::string GCodeAnalyzer::Extrusion_Role_Tag = "_ANALYZER_EXTR_ROLE:"; +const std::string GCodeAnalyzer::Mm3_Per_Mm_Tag = "_ANALYZER_MM3_PER_MM:"; +const std::string GCodeAnalyzer::Width_Tag = "_ANALYZER_WIDTH:"; +const std::string GCodeAnalyzer::Height_Tag = "_ANALYZER_HEIGHT:"; + +const double GCodeAnalyzer::Default_mm3_per_mm = 0.0; +const float GCodeAnalyzer::Default_Width = 0.0f; +const float GCodeAnalyzer::Default_Height = 0.0f; + +GCodeAnalyzer::Metadata::Metadata() + : extrusion_role(erNone) + , extruder_id(DEFAULT_EXTRUDER_ID) + , mm3_per_mm(GCodeAnalyzer::Default_mm3_per_mm) + , width(GCodeAnalyzer::Default_Width) + , height(GCodeAnalyzer::Default_Height) + , feedrate(DEFAULT_FEEDRATE) +{ +} + +GCodeAnalyzer::Metadata::Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate) + : extrusion_role(extrusion_role) + , extruder_id(extruder_id) + , mm3_per_mm(mm3_per_mm) + , width(width) + , height(height) + , feedrate(feedrate) +{ +} + +bool GCodeAnalyzer::Metadata::operator != (const GCodeAnalyzer::Metadata& other) const +{ + if (extrusion_role != other.extrusion_role) + return true; + + if (extruder_id != other.extruder_id) + return true; + + if (mm3_per_mm != other.mm3_per_mm) + return true; + + if (width != other.width) + return true; + + if (height != other.height) + return true; + + if (feedrate != other.feedrate) + return true; + + return false; +} + +GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder) + : type(type) + , data(extrusion_role, extruder_id, mm3_per_mm, width, height, feedrate) + , start_position(start_position) + , end_position(end_position) + , delta_extruder(delta_extruder) +{ +} + +GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, const GCodeAnalyzer::Metadata& data, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder) + : type(type) + , data(data) + , start_position(start_position) + , end_position(end_position) + , delta_extruder(delta_extruder) +{ +} + +const GCodeAnalyzer::PreviewData::Color GCodeAnalyzer::PreviewData::Color::Dummy(0.0f, 0.0f, 0.0f, 0.0f); + +GCodeAnalyzer::PreviewData::Color::Color() +{ + rgba[0] = 1.0f; + rgba[1] = 1.0f; + rgba[2] = 1.0f; + rgba[3] = 1.0f; +} + +GCodeAnalyzer::PreviewData::Color::Color(float r, float g, float b, float a) +{ + rgba[0] = r; + rgba[1] = g; + rgba[2] = b; + rgba[3] = a; +} + +GCodeAnalyzer::PreviewData::Extrusion::Layer::Layer(float z, const ExtrusionPaths& paths) + : z(z) + , paths(paths) +{ +} + +GCodeAnalyzer::PreviewData::Travel::Polyline::Polyline(EType type, EDirection direction, const Polyline3& polyline) + : type(type) + , direction(direction) + , polyline(polyline) +{ +} + +const GCodeAnalyzer::PreviewData::Color GCodeAnalyzer::PreviewData::Range::Default_Colors[Colors_Count] = +{ + Color(0.043f, 0.173f, 0.478f, 1.0f), + Color(0.075f, 0.349f, 0.522f, 1.0f), + Color(0.110f, 0.533f, 0.569f, 1.0f), + Color(0.016f, 0.839f, 0.059f, 1.0f), + Color(0.667f, 0.949f, 0.000f, 1.0f), + Color(0.988f, 0.975f, 0.012f, 1.0f), + Color(0.961f, 0.808f, 0.039f, 1.0f), + Color(0.890f, 0.533f, 0.125f, 1.0f), + Color(0.820f, 0.408f, 0.188f, 1.0f), + Color(0.761f, 0.322f, 0.235f, 1.0f) +}; + +GCodeAnalyzer::PreviewData::Range::Range() +{ + reset(); +} + +void GCodeAnalyzer::PreviewData::Range::reset() +{ + min = FLT_MAX; + max = -FLT_MAX; +} + +bool GCodeAnalyzer::PreviewData::Range::empty() const +{ + return min == max; +} + +void GCodeAnalyzer::PreviewData::Range::update_from(float value) +{ + min = std::min(min, value); + max = std::max(max, value); +} + +void GCodeAnalyzer::PreviewData::Range::set_from(const Range& other) +{ + min = other.min; + max = other.max; +} + +const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::Range::get_color_at_max() const +{ + return colors[Colors_Count - 1]; +} + +const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::Range::get_color_at(float value) const +{ + return empty() ? get_color_at_max() : colors[clamp((unsigned int)0, Colors_Count - 1, unsigned int((value - min) / _step()))]; +} + +float GCodeAnalyzer::PreviewData::Range::_step() const +{ + return (max - min) / (float)Colors_Count; +} + +const GCodeAnalyzer::PreviewData::Color GCodeAnalyzer::PreviewData::Extrusion::Default_Extrusion_Role_Colors[Num_Extrusion_Roles] = +{ + Color(0.0f, 0.0f, 0.0f, 1.0f), // erNone + Color(1.0f, 0.0f, 0.0f, 1.0f), // erPerimeter + Color(0.0f, 1.0f, 0.0f, 1.0f), // erExternalPerimeter + Color(0.0f, 0.0f, 1.0f, 1.0f), // erOverhangPerimeter + Color(1.0f, 1.0f, 0.0f, 1.0f), // erInternalInfill + Color(1.0f, 0.0f, 1.0f, 1.0f), // erSolidInfill + Color(0.0f, 1.0f, 1.0f, 1.0f), // erTopSolidInfill + Color(0.5f, 0.5f, 0.5f, 1.0f), // erBridgeInfill + Color(1.0f, 1.0f, 1.0f, 1.0f), // erGapFill + Color(0.5f, 0.0f, 0.0f, 1.0f), // erSkirt + Color(0.0f, 0.5f, 0.0f, 1.0f), // erSupportMaterial + Color(0.0f, 0.0f, 0.5f, 1.0f), // erSupportMaterialInterface + Color(0.0f, 0.0f, 0.0f, 1.0f) // erMixed +}; + +const GCodeAnalyzer::PreviewData::Extrusion::EViewType GCodeAnalyzer::PreviewData::Extrusion::Default_View_Type = GCodeAnalyzer::PreviewData::Extrusion::FeatureType; + +void GCodeAnalyzer::PreviewData::Extrusion::set_default() +{ + view_type = Default_View_Type; + + ::memcpy((void*)role_colors, (const void*)Default_Extrusion_Role_Colors, Num_Extrusion_Roles * sizeof(Color)); + ::memcpy((void*)ranges.height.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color)); + ::memcpy((void*)ranges.width.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color)); + ::memcpy((void*)ranges.feedrate.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color)); + + role_flags = 0; + for (unsigned int i = 0; i < Num_Extrusion_Roles; ++i) + { + role_flags += (unsigned int)::exp2((double)i); + } +} + +bool GCodeAnalyzer::PreviewData::Extrusion::is_role_flag_set(ExtrusionRole role) const +{ + if ((role < erPerimeter) || (erSupportMaterialInterface < role)) + return false; + + unsigned int flag = (unsigned int)::exp2((double)(role - erPerimeter)); + return (role_flags & flag) == flag; +} + +const float GCodeAnalyzer::PreviewData::Travel::Default_Width = 0.075f; +const float GCodeAnalyzer::PreviewData::Travel::Default_Height = 0.075f; +const GCodeAnalyzer::PreviewData::Color GCodeAnalyzer::PreviewData::Travel::Default_Type_Colors[Num_Types] = +{ + Color(0.0f, 0.0f, 0.75f, 1.0f), // Move + Color(0.0f, 0.75f, 0.0f, 1.0f), // Extrude + Color(0.75f, 0.0f, 0.0f, 1.0f), // Retract +}; + +void GCodeAnalyzer::PreviewData::Travel::set_default() +{ + width = Default_Width; + height = Default_Height; + ::memcpy((void*)type_colors, (const void*)Default_Type_Colors, Num_Types * sizeof(Color)); + is_visible = false; +} + +void GCodeAnalyzer::PreviewData::Retraction::set_default() +{ + is_visible = false; +}; + +GCodeAnalyzer::PreviewData::PreviewData() +{ + set_default(); +} + +void GCodeAnalyzer::PreviewData::set_default() +{ + extrusion.set_default(); + travel.set_default(); + retraction.set_default(); +} + +void GCodeAnalyzer::PreviewData::reset() +{ + extrusion.layers.clear(); + travel.polylines.clear(); + retraction.positions.clear(); +} + +const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::get_extrusion_role_color(ExtrusionRole role) const +{ + return extrusion.role_colors[role]; +} + +const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::get_extrusion_height_color(float height) const +{ + return extrusion.ranges.height.get_color_at(height); +} + +const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::get_extrusion_width_color(float width) const +{ + return extrusion.ranges.width.get_color_at(width); +} + +const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::get_extrusion_feedrate_color(float feedrate) const +{ + return extrusion.ranges.feedrate.get_color_at(feedrate); +} + +GCodeAnalyzer::GCodeAnalyzer() +{ + reset(); +} + +void GCodeAnalyzer::reset() +{ + _set_units(Millimeters); + _set_positioning_xyz_type(Absolute); + _set_positioning_e_type(Relative); + _set_extrusion_role(erNone); + _set_extruder_id(DEFAULT_EXTRUDER_ID); + _set_mm3_per_mm(Default_mm3_per_mm); + _set_width(Default_Width); + _set_height(Default_Height); + _set_feedrate(DEFAULT_FEEDRATE); + _set_start_position(DEFAULT_START_POSITION); + _set_start_extrusion(DEFAULT_START_EXTRUSION); + _reset_axes_position(); + + m_moves_map.clear(); +} + +const std::string& GCodeAnalyzer::process_gcode(const std::string& gcode) +{ + m_process_output = ""; + + m_parser.parse_buffer(gcode, + [this](GCodeReader& reader, const GCodeReader::GCodeLine& line) + { this->_process_gcode_line(reader, line); }); + + return m_process_output; +} + +void GCodeAnalyzer::calc_gcode_preview_data(Print& print) +{ + // resets preview data + print.gcode_preview.reset(); + + // calculates extrusion layers + _calc_gcode_preview_extrusion_layers(print); + + // calculates travel + _calc_gcode_preview_travel(print); + + // calculates retractions + _calc_gcode_preview_retractions(print); +} + +void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line) +{ + // processes 'special' comments contained in line + if (_process_tags(line)) + return; + + // sets new start position/extrusion + _set_start_position(_get_end_position()); + _set_start_extrusion(_get_axis_position(E)); + + // processes 'normal' gcode lines + std::string cmd = line.cmd(); + if (cmd.length() > 1) + { + switch (::toupper(cmd[0])) + { + case 'G': + { + switch (::atoi(&cmd[1])) + { + case 1: // Move + { + _processG1(line); + break; + } + case 22: // Firmware controlled Retract + { + _processG22(line); + break; + } + case 23: // Firmware controlled Unretract + { + _processG23(line); + break; + } + case 90: // Set to Absolute Positioning + { + _processG90(line); + break; + } + case 91: // Set to Relative Positioning + { + _processG91(line); + break; + } + case 92: // Set Position + { + _processG92(line); + break; + } + } + + break; + } + case 'M': + { + switch (::atoi(&cmd[1])) + { + case 82: // Set extruder to absolute mode + { + _processM82(line); + break; + } + case 83: // Set extruder to relative mode + { + _processM83(line); + break; + } + } + + break; + } + case 'T': // Select Tools + { + _processT(line); + break; + } + } + } + + // puts the line back into the gcode + m_process_output += line.raw() + "\n"; +} + +// Returns the new absolute position on the given axis in dependence of the given parameters +float axis_absolute_position_from_G1_line(GCodeAnalyzer::EAxis axis, const GCodeReader::GCodeLine& lineG1, GCodeAnalyzer::EUnits units, GCodeAnalyzer::EPositioningType type, float current_absolute_position) +{ + float lengthsScaleFactor = (units == GCodeAnalyzer::Inches) ? INCHES_TO_MM : 1.0f; + if (lineG1.has(Slic3r::Axis(axis))) + { + float ret = lineG1.value(Slic3r::Axis(axis)) * lengthsScaleFactor; + return (type == GCodeAnalyzer::Absolute) ? ret : current_absolute_position + ret; + } + else + return current_absolute_position; +} + +void GCodeAnalyzer::_processG1(const GCodeReader::GCodeLine& line) +{ + // updates axes positions from line + EUnits units = _get_units(); + float new_pos[Num_Axis]; + for (unsigned char a = X; a < Num_Axis; ++a) + { + new_pos[a] = axis_absolute_position_from_G1_line((EAxis)a, line, units, (a == E) ? _get_positioning_e_type() : _get_positioning_xyz_type(), _get_axis_position((EAxis)a)); + } + + // updates feedrate from line, if present + if (line.has_f()) + _set_feedrate(line.f() * MMMIN_TO_MMSEC); + + // calculates movement deltas + float delta_pos[Num_Axis]; + for (unsigned char a = X; a < Num_Axis; ++a) + { + delta_pos[a] = new_pos[a] - _get_axis_position((EAxis)a); + } + + // Detects move type + GCodeMove::EType type = GCodeMove::Noop; + + if (delta_pos[E] < 0.0f) + { + if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f) || (delta_pos[Z] != 0.0f)) + type = GCodeMove::Move; + else + type = GCodeMove::Retract; + } + else if (delta_pos[E] > 0.0f) + { + if ((delta_pos[X] == 0.0f) && (delta_pos[Y] == 0.0f) && (delta_pos[Z] == 0.0f)) + type = GCodeMove::Unretract; + else if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f)) + type = GCodeMove::Extrude; + } + else if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f) || (delta_pos[Z] != 0.0f)) + type = GCodeMove::Move; + + ExtrusionRole role = _get_extrusion_role(); + if ((type == GCodeMove::Extrude) && ((_get_width() == 0.0f) || (_get_height() == 0.0f) || (role < erPerimeter) || (erSupportMaterialInterface < role))) + type = GCodeMove::Move; + + // updates axis positions + for (unsigned char a = X; a < Num_Axis; ++a) + { + _set_axis_position((EAxis)a, new_pos[a]); + } + + // stores the move + if (type != GCodeMove::Noop) + _store_move(type); +} + +void GCodeAnalyzer::_processG22(const GCodeReader::GCodeLine& line) +{ + // stores retract move + _store_move(GCodeMove::Retract); +} + +void GCodeAnalyzer::_processG23(const GCodeReader::GCodeLine& line) +{ + // stores unretract move + _store_move(GCodeMove::Unretract); +} + +void GCodeAnalyzer::_processG90(const GCodeReader::GCodeLine& line) +{ + _set_positioning_xyz_type(Absolute); +} + +void GCodeAnalyzer::_processG91(const GCodeReader::GCodeLine& line) +{ + _set_positioning_xyz_type(Relative); +} + +void GCodeAnalyzer::_processG92(const GCodeReader::GCodeLine& line) +{ + float lengthsScaleFactor = (_get_units() == Inches) ? INCHES_TO_MM : 1.0f; + bool anyFound = false; + + if (line.has_x()) + { + _set_axis_position(X, line.x() * lengthsScaleFactor); + anyFound = true; + } + + if (line.has_y()) + { + _set_axis_position(Y, line.y() * lengthsScaleFactor); + anyFound = true; + } + + if (line.has_z()) + { + _set_axis_position(Z, line.z() * lengthsScaleFactor); + anyFound = true; + } + + if (line.has_e()) + { + _set_axis_position(E, line.e() * lengthsScaleFactor); + anyFound = true; + } + + if (!anyFound) + { + for (unsigned char a = X; a < Num_Axis; ++a) + { + _set_axis_position((EAxis)a, 0.0f); + } + } +} + +void GCodeAnalyzer::_processM82(const GCodeReader::GCodeLine& line) +{ + _set_positioning_e_type(Absolute); +} + +void GCodeAnalyzer::_processM83(const GCodeReader::GCodeLine& line) +{ + _set_positioning_e_type(Relative); +} + +void GCodeAnalyzer::_processT(const GCodeReader::GCodeLine& line) +{ + std::string cmd = line.cmd(); + if (cmd.length() > 1) + { + int id = (int)::strtol(cmd.substr(1).c_str(), nullptr, 10); + // todo - add id validity check ? + if (_get_extruder_id() != id) + { + _set_extruder_id(id); + + // stores tool change move + _store_move(GCodeMove::Tool_change); + } + } +} + +bool GCodeAnalyzer::_process_tags(const GCodeReader::GCodeLine& line) +{ + std::string comment = line.comment(); + + // extrusion role tag + size_t pos = comment.find(Extrusion_Role_Tag); + if (pos != comment.npos) + { + _process_extrusion_role_tag(comment, pos); + return true; + } + + // mm3 per mm tag + pos = comment.find(Mm3_Per_Mm_Tag); + if (pos != comment.npos) + { + _process_mm3_per_mm_tag(comment, pos); + return true; + } + + // width tag + pos = comment.find(Width_Tag); + if (pos != comment.npos) + { + _process_width_tag(comment, pos); + return true; + } + + // height tag + pos = comment.find(Height_Tag); + if (pos != comment.npos) + { + _process_height_tag(comment, pos); + return true; + } + + return false; +} + +void GCodeAnalyzer::_process_extrusion_role_tag(const std::string& comment, size_t pos) +{ + int role = (int)::strtol(comment.substr(pos + Extrusion_Role_Tag.length()).c_str(), nullptr, 10); + if (_is_valid_extrusion_role(role)) + _set_extrusion_role((ExtrusionRole)role); + else + { + // todo: show some error ? + } +} + +void GCodeAnalyzer::_process_mm3_per_mm_tag(const std::string& comment, size_t pos) +{ + _set_mm3_per_mm(::strtod(comment.substr(pos + Mm3_Per_Mm_Tag.length()).c_str(), nullptr)); +} + +void GCodeAnalyzer::_process_width_tag(const std::string& comment, size_t pos) +{ + _set_width((float)::strtod(comment.substr(pos + Width_Tag.length()).c_str(), nullptr)); +} + +void GCodeAnalyzer::_process_height_tag(const std::string& comment, size_t pos) +{ + _set_height((float)::strtod(comment.substr(pos + Height_Tag.length()).c_str(), nullptr)); +} + +void GCodeAnalyzer::_set_units(GCodeAnalyzer::EUnits units) +{ + m_state.units = units; +} + +GCodeAnalyzer::EUnits GCodeAnalyzer::_get_units() const +{ + return m_state.units; +} + +void GCodeAnalyzer::_set_positioning_xyz_type(GCodeAnalyzer::EPositioningType type) +{ + m_state.positioning_xyz_type = type; +} + +GCodeAnalyzer::EPositioningType GCodeAnalyzer::_get_positioning_xyz_type() const +{ + return m_state.positioning_xyz_type; +} + +void GCodeAnalyzer::_set_positioning_e_type(GCodeAnalyzer::EPositioningType type) +{ + m_state.positioning_e_type = type; +} + +GCodeAnalyzer::EPositioningType GCodeAnalyzer::_get_positioning_e_type() const +{ + return m_state.positioning_e_type; +} + +void GCodeAnalyzer::_set_extrusion_role(ExtrusionRole extrusion_role) +{ + m_state.data.extrusion_role = extrusion_role; +} + +ExtrusionRole GCodeAnalyzer::_get_extrusion_role() const +{ + return m_state.data.extrusion_role; +} + +void GCodeAnalyzer::_set_extruder_id(unsigned int id) +{ + m_state.data.extruder_id = id; +} + +unsigned int GCodeAnalyzer::_get_extruder_id() const +{ + return m_state.data.extruder_id; +} + +void GCodeAnalyzer::_set_mm3_per_mm(double value) +{ + m_state.data.mm3_per_mm = value; +} + +double GCodeAnalyzer::_get_mm3_per_mm() const +{ + return m_state.data.mm3_per_mm; +} + +void GCodeAnalyzer::_set_width(float width) +{ + m_state.data.width = width; +} + +float GCodeAnalyzer::_get_width() const +{ + return m_state.data.width; +} + +void GCodeAnalyzer::_set_height(float height) +{ + m_state.data.height = height; +} + +float GCodeAnalyzer::_get_height() const +{ + return m_state.data.height; +} + +void GCodeAnalyzer::_set_feedrate(float feedrate_mm_sec) +{ + m_state.data.feedrate = feedrate_mm_sec; +} + +float GCodeAnalyzer::_get_feedrate() const +{ + return m_state.data.feedrate; +} + +void GCodeAnalyzer::_set_axis_position(EAxis axis, float position) +{ + m_state.position[axis] = position; +} + +float GCodeAnalyzer::_get_axis_position(EAxis axis) const +{ + return m_state.position[axis]; +} + +void GCodeAnalyzer::_reset_axes_position() +{ + ::memset((void*)m_state.position, 0, Num_Axis * sizeof(float)); +} + +void GCodeAnalyzer::_set_start_position(const Pointf3& position) +{ + m_state.start_position = position; +} + +const Pointf3& GCodeAnalyzer::_get_start_position() const +{ + return m_state.start_position; +} + +void GCodeAnalyzer::_set_start_extrusion(float extrusion) +{ + m_state.start_extrusion = extrusion; +} + +float GCodeAnalyzer::_get_start_extrusion() const +{ + return m_state.start_extrusion; +} + +float GCodeAnalyzer::_get_delta_extrusion() const +{ + return _get_axis_position(E) - m_state.start_extrusion; +} + +Pointf3 GCodeAnalyzer::_get_end_position() const +{ + return Pointf3(m_state.position[X], m_state.position[Y], m_state.position[Z]); +} + +void GCodeAnalyzer::_store_move(GCodeAnalyzer::GCodeMove::EType type) +{ + // if type non mapped yet, map it + TypeToMovesMap::iterator it = m_moves_map.find(type); + if (it == m_moves_map.end()) + it = m_moves_map.insert(TypeToMovesMap::value_type(type, GCodeMovesList())).first; + + // store move + it->second.emplace_back(type, _get_extrusion_role(), _get_extruder_id(), _get_mm3_per_mm(), _get_width(), _get_height(), _get_feedrate(), _get_start_position(), _get_end_position(), _get_delta_extrusion()); +} + +bool GCodeAnalyzer::_is_valid_extrusion_role(int value) const +{ + return ((int)erNone <= value) && (value <= (int)erMixed); +} + +void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(Print& print) +{ + struct Helper + { + static PreviewData::Extrusion::Layer& get_layer_at_z(PreviewData::Extrusion::LayersList& layers, float z) + { + for (PreviewData::Extrusion::Layer& layer : layers) + { + // if layer found, return it + if (layer.z == z) + return layer; + } + + // if layer not found, create and return it + layers.emplace_back(z, ExtrusionPaths()); + return layers.back(); + } + + static void store_polyline(const Polyline& polyline, const Metadata& data, float z, Print& print) + { + // 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); + path.polyline = polyline; + path.feedrate = data.feedrate; + + get_layer_at_z(print.gcode_preview.extrusion.layers, z).paths.push_back(path); + } + } + }; + + TypeToMovesMap::iterator extrude_moves = m_moves_map.find(GCodeMove::Extrude); + if (extrude_moves == m_moves_map.end()) + return; + + Metadata data; + float z = FLT_MAX; + Polyline polyline; + Pointf3 position(FLT_MAX, FLT_MAX, FLT_MAX); + PreviewData::Range height_range; + PreviewData::Range width_range; + PreviewData::Range feedrate_range; + + // constructs the polylines while traversing the moves + for (const GCodeMove& move : extrude_moves->second) + { + if ((data != move.data) || (data.feedrate != move.data.feedrate) || (z != move.start_position.z) || (position != move.start_position)) + { + // store current polyline + Helper::store_polyline(polyline, data, z, print); + + // reset current polyline + polyline = Polyline(); + + // add both vertices of the move + polyline.append(Point(scale_(move.start_position.x), scale_(move.start_position.y))); + polyline.append(Point(scale_(move.end_position.x), scale_(move.end_position.y))); + + // update current values + data = move.data; + z = move.start_position.z; + height_range.update_from(move.data.height); + width_range.update_from(move.data.width); + feedrate_range.update_from(move.data.feedrate); + } + else + // append end vertex of the move to current polyline + polyline.append(Point(scale_(move.end_position.x), scale_(move.end_position.y))); + + // update current values + position = move.end_position; + } + + // store last polyline + Helper::store_polyline(polyline, data, z, print); + + // updates preview ranges data + print.gcode_preview.extrusion.ranges.height.set_from(height_range); + print.gcode_preview.extrusion.ranges.width.set_from(width_range); + print.gcode_preview.extrusion.ranges.feedrate.set_from(feedrate_range); +} + +void GCodeAnalyzer::_calc_gcode_preview_travel(Print& print) +{ + struct Helper + { + static void store_polyline(const Polyline3& polyline, PreviewData::Travel::EType type, PreviewData::Travel::Polyline::EDirection direction, Print& print) + { + // if the polyline is valid, store it + if (polyline.is_valid()) + print.gcode_preview.travel.polylines.emplace_back(type, direction, polyline); + } + }; + + TypeToMovesMap::iterator travel_moves = m_moves_map.find(GCodeMove::Move); + if (travel_moves == m_moves_map.end()) + return; + + Polyline3 polyline; + Pointf3 position(FLT_MAX, FLT_MAX, FLT_MAX); + PreviewData::Travel::EType type = PreviewData::Travel::Num_Types; + PreviewData::Travel::Polyline::EDirection direction = PreviewData::Travel::Polyline::Num_Directions; + + // constructs the polylines while traversing the moves + for (const GCodeMove& move : travel_moves->second) + { + PreviewData::Travel::EType move_type = (move.delta_extruder < 0.0f) ? PreviewData::Travel::Retract : ((move.delta_extruder > 0.0f) ? PreviewData::Travel::Extrude : PreviewData::Travel::Move); + PreviewData::Travel::Polyline::EDirection move_direction = ((move.start_position.x != move.end_position.x) || (move.start_position.y != move.end_position.y)) ? PreviewData::Travel::Polyline::Generic : PreviewData::Travel::Polyline::Vertical; + + if ((type != move_type) || (direction != move_direction) || (position != move.start_position)) + { + // store current polyline + Helper::store_polyline(polyline, type, direction, print); + + // reset current polyline + polyline = Polyline3(); + + // add both vertices of the move + polyline.append(Point3(scale_(move.start_position.x), scale_(move.start_position.y), scale_(move.start_position.z))); + polyline.append(Point3(scale_(move.end_position.x), scale_(move.end_position.y), scale_(move.end_position.z))); + } + else + // append end vertex of the move to current polyline + polyline.append(Point3(scale_(move.end_position.x), scale_(move.end_position.y), scale_(move.end_position.z))); + + // update current values + position = move.end_position; + type = move_type; + } + + // store last polyline + Helper::store_polyline(polyline, type, direction, print); +} + +void GCodeAnalyzer::_calc_gcode_preview_retractions(Print& print) +{ + TypeToMovesMap::iterator retraction_moves = m_moves_map.find(GCodeMove::Retract); + if (retraction_moves == m_moves_map.end()) + return; + + for (const GCodeMove& move : retraction_moves->second) + { + print.gcode_preview.retraction.positions.emplace_back(scale_(move.start_position.x), scale_(move.start_position.y), scale_(move.start_position.z)); + } + + int a = 0; +} + +GCodeAnalyzer::PreviewData::Color operator + (const GCodeAnalyzer::PreviewData::Color& c1, const GCodeAnalyzer::PreviewData::Color& c2) +{ + return GCodeAnalyzer::PreviewData::Color(clamp(0.0f, 1.0f, c1.rgba[0] + c2.rgba[0]), + clamp(0.0f, 1.0f, c1.rgba[1] + c2.rgba[1]), + clamp(0.0f, 1.0f, c1.rgba[2] + c2.rgba[2]), + clamp(0.0f, 1.0f, c1.rgba[3] + c2.rgba[3])); +} + +GCodeAnalyzer::PreviewData::Color operator * (float f, const GCodeAnalyzer::PreviewData::Color& color) +{ + return GCodeAnalyzer::PreviewData::Color(clamp(0.0f, 1.0f, f * color.rgba[0]), + clamp(0.0f, 1.0f, f * color.rgba[1]), + clamp(0.0f, 1.0f, f * color.rgba[2]), + clamp(0.0f, 1.0f, f * color.rgba[3])); +} +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ } // namespace Slic3r diff --git a/xs/src/libslic3r/GCode/Analyzer.hpp b/xs/src/libslic3r/GCode/Analyzer.hpp index 9e84e33c4..8236772fb 100644 --- a/xs/src/libslic3r/GCode/Analyzer.hpp +++ b/xs/src/libslic3r/GCode/Analyzer.hpp @@ -1,12 +1,28 @@ -#ifndef slic3r_GCode_PressureEqualizer_hpp_ -#define slic3r_GCode_PressureEqualizer_hpp_ +#ifndef slic3r_GCode_Analyzer_hpp_ +#define slic3r_GCode_Analyzer_hpp_ #include "../libslic3r.h" #include "../PrintConfig.hpp" #include "../ExtrusionEntity.hpp" +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +#include "Point.hpp" +#include "GCodeReader.hpp" +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + namespace Slic3r { +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + class Print; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + +//############################################################################################################ +#if !ENRICO_GCODE_PREVIEW +//############################################################################################################ enum GCodeMoveType { GCODE_MOVE_TYPE_NOOP, @@ -146,7 +162,367 @@ private: // Push the text to the end of the output_buffer. void push_to_output(const char *text, const size_t len, bool add_eol = true); }; +//############################################################################################################ +#endif // !ENRICO_GCODE_PREVIEW +//############################################################################################################ + +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +class GCodeAnalyzer +{ +public: + static const std::string Extrusion_Role_Tag; + static const std::string Mm3_Per_Mm_Tag; + static const std::string Width_Tag; + static const std::string Height_Tag; + + static const double Default_mm3_per_mm; + static const float Default_Width; + static const float Default_Height; + + enum EUnits : unsigned char + { + Millimeters, + Inches + }; + + enum EAxis : unsigned char + { + X, + Y, + Z, + E, + Num_Axis + }; + + enum EPositioningType : unsigned char + { + Absolute, + Relative + }; + + struct Metadata + { + ExtrusionRole extrusion_role; + unsigned int extruder_id; + double mm3_per_mm; + float width; + float height; + float feedrate; + + Metadata(); + Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate); + + bool operator != (const Metadata& other) const; + }; + + struct GCodeMove + { + enum EType : unsigned char + { + Noop, + Retract, + Unretract, + Tool_change, + Move, + Extrude, + Num_Types + }; + + EType type; + Metadata data; + Pointf3 start_position; + Pointf3 end_position; + float delta_extruder; + + GCodeMove(EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder); + GCodeMove(EType type, const Metadata& data, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder); + }; + + typedef std::vector<GCodeMove> GCodeMovesList; + typedef std::map<GCodeMove::EType, GCodeMovesList> TypeToMovesMap; + +private: + struct State + { + EUnits units; + EPositioningType positioning_xyz_type; + EPositioningType positioning_e_type; + Metadata data; + Pointf3 start_position; + float start_extrusion; + float position[Num_Axis]; + }; + +public: + struct PreviewData + { + struct Color + { + float rgba[4]; + + Color(); + Color(float r, float g, float b, float a); + + static const Color Dummy; + }; + + struct Range + { + static const unsigned int Colors_Count = 10; + static const Color Default_Colors[Colors_Count]; + + Color colors[Colors_Count]; + float min; + float max; + + Range(); + + void reset(); + bool empty() const; + void update_from(float value); + void set_from(const Range& other); + + const Color& get_color_at(float value) const; + const Color& get_color_at_max() const; + + private: + float _step() const; + }; + + struct Extrusion + { + enum EViewType : unsigned char + { + FeatureType, + Height, + Width, + Feedrate, + Num_View_Types + }; + + static const unsigned int Num_Extrusion_Roles = (unsigned int)erMixed + 1; + static const Color Default_Extrusion_Role_Colors[Num_Extrusion_Roles]; + static const EViewType Default_View_Type; + + struct Ranges + { + Range height; + Range width; + Range feedrate; + }; + + struct Layer + { + float z; + ExtrusionPaths paths; + + Layer(float z, const ExtrusionPaths& paths); + }; + + typedef std::vector<Layer> LayersList; + + EViewType view_type; + Color role_colors[Num_Extrusion_Roles]; + Ranges ranges; + LayersList layers; + unsigned int role_flags; + + void set_default(); + bool is_role_flag_set(ExtrusionRole role) const; + }; + + struct Travel + { + enum EType : unsigned char + { + Move, + Extrude, + Retract, + Num_Types + }; + + static const float Default_Width; + static const float Default_Height; + static const Color Default_Type_Colors[Num_Types]; + + struct Polyline + { + enum EDirection + { + Vertical, + Generic, + Num_Directions + }; + + EType type; + EDirection direction; + Polyline3 polyline; + + Polyline(EType type, EDirection direction, const Polyline3& polyline); + }; + + typedef std::vector<Polyline> PolylinesList; + + PolylinesList polylines; + float width; + float height; + Color type_colors[Num_Types]; + bool is_visible; + + void set_default(); + }; + + struct Retraction + { + Points3 positions; + bool is_visible; + + void set_default(); + }; + + Extrusion extrusion; + Travel travel; + Retraction retraction; + + PreviewData(); + + void set_default(); + void reset(); + + const Color& get_extrusion_role_color(ExtrusionRole role) const; + const Color& get_extrusion_height_color(float height) const; + const Color& get_extrusion_width_color(float width) const; + const Color& get_extrusion_feedrate_color(float feedrate) const; + }; + +private: + State m_state; + GCodeReader m_parser; + TypeToMovesMap m_moves_map; + + // The output of process_layer() + std::string m_process_output; + +public: + GCodeAnalyzer(); + + // Reinitialize the analyzer + void reset(); + + // Adds the gcode contained in the given string to the analysis and returns it after removing the workcodes + const std::string& process_gcode(const std::string& gcode); + + // Calculates all data needed for gcode visualization + void calc_gcode_preview_data(Print& print); + +private: + // Processes the given gcode line + void _process_gcode_line(GCodeReader& reader, const GCodeReader::GCodeLine& line); + + // Move + void _processG1(const GCodeReader::GCodeLine& line); + + // Firmware controlled Retract + void _processG22(const GCodeReader::GCodeLine& line); + + // Firmware controlled Unretract + void _processG23(const GCodeReader::GCodeLine& line); + + // Set to Absolute Positioning + void _processG90(const GCodeReader::GCodeLine& line); + + // Set to Relative Positioning + void _processG91(const GCodeReader::GCodeLine& line); + + // Set Position + void _processG92(const GCodeReader::GCodeLine& line); + + // Set extruder to absolute mode + void _processM82(const GCodeReader::GCodeLine& line); + + // Set extruder to relative mode + void _processM83(const GCodeReader::GCodeLine& line); + + // Processes T line (Select Tool) + void _processT(const GCodeReader::GCodeLine& line); + + // Processes the tags + // Returns true if any tag has been processed + bool _process_tags(const GCodeReader::GCodeLine& line); + + // Processes extrusion role tag + void _process_extrusion_role_tag(const std::string& comment, size_t pos); + + // Processes mm3_per_mm tag + void _process_mm3_per_mm_tag(const std::string& comment, size_t pos); + + // Processes width tag + void _process_width_tag(const std::string& comment, size_t pos); + + // Processes height tag + void _process_height_tag(const std::string& comment, size_t pos); + + void _set_units(EUnits units); + EUnits _get_units() const; + + void _set_positioning_xyz_type(EPositioningType type); + EPositioningType _get_positioning_xyz_type() const; + + void _set_positioning_e_type(EPositioningType type); + EPositioningType _get_positioning_e_type() const; + + void _set_extrusion_role(ExtrusionRole extrusion_role); + ExtrusionRole _get_extrusion_role() const; + + void _set_extruder_id(unsigned int id); + unsigned int _get_extruder_id() const; + + void _set_mm3_per_mm(double value); + double _get_mm3_per_mm() const; + + void _set_width(float width); + float _get_width() const; + + void _set_height(float height); + float _get_height() const; + + void _set_feedrate(float feedrate_mm_sec); + float _get_feedrate() const; + + void _set_axis_position(EAxis axis, float position); + float _get_axis_position(EAxis axis) const; + + // Sets axes position to zero + void _reset_axes_position(); + + void _set_start_position(const Pointf3& position); + const Pointf3& _get_start_position() const; + + void _set_start_extrusion(float extrusion); + float _get_start_extrusion() const; + float _get_delta_extrusion() const; + + // Returns current xyz position (from m_state.position[]) + Pointf3 _get_end_position() const; + + // Adds a new move with the given data + void _store_move(GCodeMove::EType type); + + // Checks if the given int is a valid extrusion role (contained into enum ExtrusionRole) + bool _is_valid_extrusion_role(int value) const; + + void _calc_gcode_preview_extrusion_layers(Print& print); + void _calc_gcode_preview_travel(Print& print); + void _calc_gcode_preview_retractions(Print& print); +}; + +GCodeAnalyzer::PreviewData::Color operator + (const GCodeAnalyzer::PreviewData::Color& c1, const GCodeAnalyzer::PreviewData::Color& c2); +GCodeAnalyzer::PreviewData::Color operator * (float f, const GCodeAnalyzer::PreviewData::Color& color); + +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ } // namespace Slic3r -#endif /* slic3r_GCode_PressureEqualizer_hpp_ */ +#endif /* slic3r_GCode_Analyzer_hpp_ */ diff --git a/xs/src/libslic3r/Line.cpp b/xs/src/libslic3r/Line.cpp index c7afc80c7..a4d36d38b 100644 --- a/xs/src/libslic3r/Line.cpp +++ b/xs/src/libslic3r/Line.cpp @@ -218,6 +218,20 @@ Line::ccw(const Point& point) const return point.ccw(*this); } +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +double Line3::length() const +{ + return a.distance_to(b); +} + +Vector3 Line3::vector() const +{ + return Vector3(b.x - a.x, b.y - a.y, b.z - a.z); +} +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + Pointf3 Linef3::intersect_plane(double z) const { diff --git a/xs/src/libslic3r/Line.hpp b/xs/src/libslic3r/Line.hpp index 1be508f11..514a9ca04 100644 --- a/xs/src/libslic3r/Line.hpp +++ b/xs/src/libslic3r/Line.hpp @@ -7,10 +7,20 @@ namespace Slic3r { class Line; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +class Line3; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ class Linef3; class Polyline; class ThickLine; typedef std::vector<Line> Lines; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +typedef std::vector<Line3> Lines3; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ typedef std::vector<ThickLine> ThickLines; class Line @@ -56,6 +66,23 @@ class ThickLine : public Line ThickLine(Point _a, Point _b) : Line(_a, _b), a_width(0), b_width(0) {}; }; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +class Line3 +{ +public: + Point3 a; + Point3 b; + + Line3() {} + Line3(const Point3& _a, const Point3& _b) : a(_a), b(_b) {} + + double length() const; + Vector3 vector() const; +}; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + class Linef { public: diff --git a/xs/src/libslic3r/MultiPoint.cpp b/xs/src/libslic3r/MultiPoint.cpp index 7929747a0..54c639a96 100644 --- a/xs/src/libslic3r/MultiPoint.cpp +++ b/xs/src/libslic3r/MultiPoint.cpp @@ -214,6 +214,65 @@ MultiPoint::_douglas_peucker(const Points &points, const double tolerance) return results; } +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +void MultiPoint3::translate(double x, double y) +{ + for (Point3& p : points) + { + p.translate(x, y); + } +} + +void MultiPoint3::translate(const Point& vector) +{ + translate(vector.x, vector.y); +} + +double MultiPoint3::length() const +{ + Lines3 lines = this->lines(); + double len = 0.0; + for (const Line3& line : lines) + { + len += line.length(); + } + return len; +} + +BoundingBox3 MultiPoint3::bounding_box() const +{ + return BoundingBox3(points); +} + +bool MultiPoint3::remove_duplicate_points() +{ + size_t j = 0; + for (size_t i = 1; i < points.size(); ++i) + { + if (points[j].coincides_with(points[i])) + { + // Just increase index i. + } + else + { + ++j; + if (j < i) + points[j] = points[i]; + } + } + + if (++j < points.size()) + { + points.erase(points.begin() + j, points.end()); + return true; + } + + return false; +} +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + BoundingBox get_extents(const MultiPoint &mp) { return BoundingBox(mp.points); diff --git a/xs/src/libslic3r/MultiPoint.hpp b/xs/src/libslic3r/MultiPoint.hpp index 3d1346e4c..ed5bad3a8 100644 --- a/xs/src/libslic3r/MultiPoint.hpp +++ b/xs/src/libslic3r/MultiPoint.hpp @@ -10,6 +10,11 @@ namespace Slic3r { class BoundingBox; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +class BoundingBox3; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ class MultiPoint { @@ -79,6 +84,29 @@ public: static Points _douglas_peucker(const Points &points, const double tolerance); }; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +class MultiPoint3 +{ +public: + Points3 points; + + void append(const Point3& point) { this->points.push_back(point); } + + void translate(double x, double y); + void translate(const Point& vector); + virtual Lines3 lines() const = 0; + double length() const; + bool is_valid() const { return this->points.size() >= 2; } + + BoundingBox3 bounding_box() const; + + // Remove exact duplicates, return true if any duplicate has been removed. + bool remove_duplicate_points(); +}; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + extern BoundingBox get_extents(const MultiPoint &mp); extern BoundingBox get_extents_rotated(const std::vector<Point> &points, double angle); extern BoundingBox get_extents_rotated(const MultiPoint &mp, double angle); diff --git a/xs/src/libslic3r/Point.hpp b/xs/src/libslic3r/Point.hpp index 77e07bec8..a322bc4fa 100644 --- a/xs/src/libslic3r/Point.hpp +++ b/xs/src/libslic3r/Point.hpp @@ -14,14 +14,29 @@ class Line; class Linef; class MultiPoint; class Point; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +class Point3; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ class Pointf; class Pointf3; typedef Point Vector; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +typedef Point3 Vector3; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ typedef Pointf Vectorf; typedef Pointf3 Vectorf3; typedef std::vector<Point> Points; typedef std::vector<Point*> PointPtrs; typedef std::vector<const Point*> PointConstPtrs; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +typedef std::vector<Point3> Points3; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ typedef std::vector<Pointf> Pointfs; typedef std::vector<Pointf3> Pointf3s; @@ -186,10 +201,24 @@ public: static Point3 new_scale(coordf_t x, coordf_t y, coordf_t z) { return Point3(coord_t(scale_(x)), coord_t(scale_(y)), coord_t(scale_(z))); } bool operator==(const Point3 &rhs) const { return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z; } bool operator!=(const Point3 &rhs) const { return ! (*this == rhs); } +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + bool coincides_with(const Point3& rhs) const { return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z; } +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ private: // Hide the following inherited methods: +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + bool operator==(const Point &rhs) const; + bool operator!=(const Point &rhs) const; +#else +//############################################################################################################ bool operator==(const Point &rhs); bool operator!=(const Point &rhs); +//############################################################################################################ +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ }; std::ostream& operator<<(std::ostream &stm, const Pointf &pointf); @@ -244,6 +273,11 @@ public: static Pointf3 new_unscale(coord_t x, coord_t y, coord_t z) { return Pointf3(unscale(x), unscale(y), unscale(z)); }; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + static Pointf3 new_unscale(const Point3& p) { return Pointf3(unscale(p.x), unscale(p.y), unscale(p.z)); } +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ void scale(double factor); void translate(const Vectorf3 &vector); void translate(double x, double y, double z); @@ -256,10 +290,36 @@ public: private: // Hide the following inherited methods: +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + bool operator==(const Pointf &rhs) const; + bool operator!=(const Pointf &rhs) const; +#else +//############################################################################################################ bool operator==(const Pointf &rhs); bool operator!=(const Pointf &rhs); +//############################################################################################################ +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ }; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +inline Pointf3 operator+(const Pointf3& p1, const Pointf3& p2) { return Pointf3(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z); } +inline Pointf3 operator-(const Pointf3& p1, const Pointf3& p2) { return Pointf3(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z); } +inline Pointf3 operator-(const Pointf3& p) { return Pointf3(-p.x, -p.y, -p.z); } +inline Pointf3 operator*(double scalar, const Pointf3& p) { return Pointf3(scalar * p.x, scalar * p.y, scalar * p.z); } +inline Pointf3 operator*(const Pointf3& p, double scalar) { return Pointf3(scalar * p.x, scalar * p.y, scalar * p.z); } +inline Pointf3 cross(const Pointf3& v1, const Pointf3& v2) { return Pointf3(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x); } +inline coordf_t dot(const Pointf3& v1, const Pointf3& v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } +inline Pointf3 normalize(const Pointf3& v) +{ + coordf_t len = ::sqrt(sqr(v.x) + sqr(v.y) + sqr(v.z)); + return (len != 0.0) ? 1.0 / len * v : Pointf3(0.0, 0.0, 0.0); +} +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + template<typename TO> inline TO convert_to(const Point &src) { return TO(typename TO::coord_type(src.x), typename TO::coord_type(src.y)); } template<typename TO> inline TO convert_to(const Pointf &src) { return TO(typename TO::coord_type(src.x), typename TO::coord_type(src.y)); } template<typename TO> inline TO convert_to(const Point3 &src) { return TO(typename TO::coord_type(src.x), typename TO::coord_type(src.y), typename TO::coord_type(src.z)); } diff --git a/xs/src/libslic3r/Polyline.cpp b/xs/src/libslic3r/Polyline.cpp index 672777ce1..9462332ff 100644 --- a/xs/src/libslic3r/Polyline.cpp +++ b/xs/src/libslic3r/Polyline.cpp @@ -278,4 +278,22 @@ ThickPolyline::reverse() std::swap(this->endpoints.first, this->endpoints.second); } +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +Lines3 Polyline3::lines() const +{ + Lines3 lines; + if (points.size() >= 2) + { + lines.reserve(points.size() - 1); + for (Points3::const_iterator it = points.begin(); it != points.end() - 1; ++it) + { + lines.emplace_back(*it, *(it + 1)); + } + } + return lines; +} +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + } diff --git a/xs/src/libslic3r/Polyline.hpp b/xs/src/libslic3r/Polyline.hpp index ac59c6378..95ee72d0c 100644 --- a/xs/src/libslic3r/Polyline.hpp +++ b/xs/src/libslic3r/Polyline.hpp @@ -129,6 +129,18 @@ class ThickPolyline : public Polyline { void reverse(); }; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +class Polyline3 : public MultiPoint3 +{ +public: + virtual Lines3 lines() const; +}; + +typedef std::vector<Polyline3> Polylines3; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + } #endif diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 773998394..a6cb09e6d 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -66,6 +66,41 @@ bool Print::reload_model_instances() return invalidated; } +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +void Print::clear_gcode_preview_data() +{ + gcode_preview.reset(); +} + +void Print::set_gcode_preview_type(unsigned char type) +{ + if ((0 <= type) && (type < GCodeAnalyzer::PreviewData::Extrusion::Num_View_Types)) + gcode_preview.extrusion.view_type = (GCodeAnalyzer::PreviewData::Extrusion::EViewType)type; +} + +void Print::set_gcode_preview_extrusion_flags(unsigned int flags) +{ + gcode_preview.extrusion.role_flags = flags; +} + +bool Print::is_gcode_preview_extrusion_role_enabled(ExtrusionRole role) +{ + return gcode_preview.extrusion.is_role_flag_set(role); +} + +void Print::set_gcode_preview_travel_visible(bool visible) +{ + gcode_preview.travel.is_visible = visible; +} + +void Print::set_gcode_preview_retractions_visible(bool visible) +{ + gcode_preview.retraction.is_visible = visible; +} +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + PrintRegion* Print::add_region() { regions.push_back(new PrintRegion(this)); diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index c56e64c6c..7a69973de 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -15,6 +15,11 @@ #include "Slicing.hpp" #include "GCode/ToolOrdering.hpp" #include "GCode/WipeTower.hpp" +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +#include "GCode/Analyzer.hpp" +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ #include "tbb/atomic.h" @@ -240,6 +245,11 @@ public: // ordered collections of extrusion paths to build skirt loops and brim ExtrusionEntityCollection skirt, brim; +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + GCodeAnalyzer::PreviewData gcode_preview; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ Print() : total_used_filament(0), total_extruded_volume(0) { restart(); } ~Print() { clear_objects(); } @@ -253,6 +263,17 @@ public: void reload_object(size_t idx); bool reload_model_instances(); +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + void clear_gcode_preview_data(); + void set_gcode_preview_type(unsigned char type); + void set_gcode_preview_extrusion_flags(unsigned int flags); + bool is_gcode_preview_extrusion_role_enabled(ExtrusionRole role); + void set_gcode_preview_travel_visible(bool visible); + void set_gcode_preview_retractions_visible(bool visible); +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + // methods for handling regions PrintRegion* get_region(size_t idx) { return regions.at(idx); } const PrintRegion* get_region(size_t idx) const { return regions.at(idx); } diff --git a/xs/src/libslic3r/libslic3r.h b/xs/src/libslic3r/libslic3r.h index 7c694b05e..24d7f4889 100644 --- a/xs/src/libslic3r/libslic3r.h +++ b/xs/src/libslic3r/libslic3r.h @@ -163,12 +163,29 @@ static inline T clamp(const T low, const T high, const T value) return std::max(low, std::min(high, value)); } +//############################################################################################################ +#define ENRICO_GCODE_PREVIEW 1 +//############################################################################################################ + +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +template <typename T, typename Number> +static inline T lerp(const T& a, const T& b, Number t) +{ + assert((t >= Number(-EPSILON)) && (t <= Number(1) + Number(EPSILON))); + return (Number(1) - t) * a + t * b; +} +#else +//############################################################################################################ template <typename T> static inline T lerp(const T a, const T b, const T t) { assert(t >= T(-EPSILON) && t <= T(1.+EPSILON)); return (1. - t) * a + t * b; } +//############################################################################################################ +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ } // namespace Slic3r diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 81dbcdacc..85c044db8 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -8,6 +8,11 @@ #include "../../libslic3r/Geometry.hpp" #include "../../libslic3r/Print.hpp" #include "../../libslic3r/Slicing.hpp" +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +#include "GCode/Analyzer.hpp" +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ #include <stdio.h> #include <stdlib.h> @@ -605,6 +610,279 @@ static void thick_lines_to_indexed_vertex_array( #undef BOTTOM } +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +// caller is responsible for supplying NO lines with zero length +static void thick_lines_to_indexed_vertex_array(const Lines3& lines, + const std::vector<double>& widths, + const std::vector<double>& heights, + bool closed, + GLIndexedVertexArray& volume) +{ + assert(!lines.empty()); + if (lines.empty()) + return; + +#define LEFT 0 +#define RIGHT 1 +#define TOP 2 +#define BOTTOM 3 + + // left, right, top, bottom + int idx_initial[4] = { -1, -1, -1, -1 }; + int idx_prev[4] = { -1, -1, -1, -1 }; + double z_prev = 0.0; + Vectorf3 n_right_prev; + Vectorf3 n_top_prev; + Vectorf3 unit_v_prev; + double width_initial = 0.0; + + // new vertices around the line endpoints + // left, right, top, bottom + Pointf3 a[4]; + Pointf3 b[4]; + + // loop once more in case of closed loops + size_t lines_end = closed ? (lines.size() + 1) : lines.size(); + for (size_t ii = 0; ii < lines_end; ++ii) + { + size_t i = (ii == lines.size()) ? 0 : ii; + + const Line3& line = lines[i]; + double height = heights[i]; + double width = widths[i]; + + Vectorf3 unit_v = normalize(Vectorf3::new_unscale(line.vector())); + + Vectorf3 n_top; + Vectorf3 n_right; + Vectorf3 unit_positive_z(0.0, 0.0, 1.0); + +// float dot_z = dot(unit_v, unit_positive_z); +// bool is_vertical = ::fabs(dot_z) > 0.99999; + + if ((line.a.x == line.b.x) && (line.a.y == line.b.y)) +// if (is_vertical) + { + // vertical segment + n_right = (line.a.z < line.b.z) ? Vectorf3(-1.0, 0.0, 0.0) : Vectorf3(1.0, 0.0, 0.0); + n_top = Vectorf3(0.0, 1.0, 0.0); + } + else + { + // generic segment + n_right = normalize(cross(unit_v, unit_positive_z)); + n_top = normalize(cross(n_right, unit_v)); + } + + Vectorf3 rl_displacement = 0.5 * width * n_right; + Vectorf3 tb_displacement = 0.5 * height * n_top; + Pointf3 l_a = Pointf3::new_unscale(line.a); + Pointf3 l_b = Pointf3::new_unscale(line.b); + + a[RIGHT] = l_a + rl_displacement; + a[LEFT] = l_a - rl_displacement; + a[TOP] = l_a + tb_displacement; + a[BOTTOM] = l_a - tb_displacement; + b[RIGHT] = l_b + rl_displacement; + b[LEFT] = l_b - rl_displacement; + b[TOP] = l_b + tb_displacement; + b[BOTTOM] = l_b - tb_displacement; + + Vectorf3 n_bottom = -n_top; + Vectorf3 n_left = -n_right; + + int idx_a[4]; + int idx_b[4]; + int idx_last = int(volume.vertices_and_normals_interleaved.size() / 6); + + bool z_different = (z_prev != l_a.z); + z_prev = l_b.z; + + // Share top / bottom vertices if possible. + if (ii == 0) + { + idx_a[TOP] = idx_last++; + volume.push_geometry(a[TOP], n_top); + } + else + idx_a[TOP] = idx_prev[TOP]; + + if ((ii == 0) || z_different) + { + // Start of the 1st line segment or a change of the layer thickness while maintaining the print_z. + idx_a[BOTTOM] = idx_last++; + volume.push_geometry(a[BOTTOM], n_bottom); + idx_a[LEFT] = idx_last++; + volume.push_geometry(a[LEFT], n_left); + idx_a[RIGHT] = idx_last++; + volume.push_geometry(a[RIGHT], n_right); + } + else + idx_a[BOTTOM] = idx_prev[BOTTOM]; + + if (ii == 0) + { + // Start of the 1st line segment. + width_initial = width; + ::memcpy(idx_initial, idx_a, sizeof(int) * 4); + } + else + { + // Continuing a previous segment. + // Share left / right vertices if possible. + double v_dot = dot(unit_v_prev, unit_v); + bool is_sharp = v_dot < 0.707; // sin(45 degrees) + bool is_right_turn = dot(n_top_prev, cross(unit_v_prev, unit_v)) > 0.0; + + if (is_sharp) + { + // Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn. + idx_a[RIGHT] = idx_last++; + volume.push_geometry(a[RIGHT], n_right); + idx_a[LEFT] = idx_last++; + volume.push_geometry(a[LEFT], n_left); + } + + if (v_dot > 0.9) + { + // The two successive segments are nearly collinear. + idx_a[LEFT] = idx_prev[LEFT]; + idx_a[RIGHT] = idx_prev[RIGHT]; + } + else if (!is_sharp) + { + // Create a sharp corner with an overshot and average the left / right normals. + // At the crease angle of 45 degrees, the overshot at the corner will be less than (1-1/cos(PI/8)) = 8.2% over an arc. + + // averages normals + Vectorf3 average_n_right = normalize(0.5 * (n_right + n_right_prev)); + Vectorf3 average_n_left = -average_n_right; + Vectorf3 average_rl_displacement = 0.5 * width * average_n_right; + + // updates vertices around a + a[RIGHT] = l_a + average_rl_displacement; + a[LEFT] = l_a - average_rl_displacement; + + // updates previous line normals + float* normal_left_prev = volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT] * 6; + normal_left_prev[0] = float(average_n_left.x); + normal_left_prev[1] = float(average_n_left.y); + normal_left_prev[2] = float(average_n_left.z); + + float* normal_right_prev = volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6; + normal_right_prev[0] = float(average_n_right.x); + normal_right_prev[1] = float(average_n_right.y); + normal_right_prev[2] = float(average_n_right.z); + + // updates previous line's vertices around b + float* b_left_prev = normal_left_prev + 3; + b_left_prev[0] = float(a[LEFT].x); + b_left_prev[1] = float(a[LEFT].y); + b_left_prev[2] = float(a[LEFT].z); + + float* b_right_prev = normal_right_prev + 3; + b_right_prev[0] = float(a[RIGHT].x); + b_right_prev[1] = float(a[RIGHT].y); + b_right_prev[2] = float(a[RIGHT].z); + + idx_a[LEFT] = idx_prev[LEFT]; + idx_a[RIGHT] = idx_prev[RIGHT]; + } + else if (is_right_turn) + { + // Right turn. Fill in the right turn wedge. + volume.push_triangle(idx_prev[RIGHT], idx_a[RIGHT], idx_prev[TOP]); + volume.push_triangle(idx_prev[RIGHT], idx_prev[BOTTOM], idx_a[RIGHT]); + } + else + { + // Left turn. Fill in the left turn wedge. + volume.push_triangle(idx_prev[LEFT], idx_prev[TOP], idx_a[LEFT]); + volume.push_triangle(idx_prev[LEFT], idx_a[LEFT], idx_prev[BOTTOM]); + } + + if (ii == lines.size()) + { + if (!is_sharp) + { + // Closing a loop with smooth transition. Unify the closing left / right vertices. + ::memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[LEFT] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT] * 6, sizeof(float) * 6); + ::memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[RIGHT] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6, sizeof(float) * 6); + volume.vertices_and_normals_interleaved.erase(volume.vertices_and_normals_interleaved.end() - 12, volume.vertices_and_normals_interleaved.end()); + // Replace the left / right vertex indices to point to the start of the loop. + for (size_t u = volume.quad_indices.size() - 16; u < volume.quad_indices.size(); ++u) + { + if (volume.quad_indices[u] == idx_prev[LEFT]) + volume.quad_indices[u] = idx_initial[LEFT]; + else if (volume.quad_indices[u] == idx_prev[RIGHT]) + volume.quad_indices[u] = idx_initial[RIGHT]; + } + } + + // This is the last iteration, only required to solve the transition. + break; + } + } + + // Only new allocate top / bottom vertices, if not closing a loop. + if (closed && (ii + 1 == lines.size())) + idx_b[TOP] = idx_initial[TOP]; + else + { + idx_b[TOP] = idx_last++; + volume.push_geometry(b[TOP], n_top); + } + + if (closed && (ii + 1 == lines.size()) && (width == width_initial)) + idx_b[BOTTOM] = idx_initial[BOTTOM]; + else + { + idx_b[BOTTOM] = idx_last++; + volume.push_geometry(b[BOTTOM], n_bottom); + } + + // Generate new vertices for the end of this line segment. + idx_b[LEFT] = idx_last++; + volume.push_geometry(b[LEFT], n_left); + idx_b[RIGHT] = idx_last++; + volume.push_geometry(b[RIGHT], n_right); + + ::memcpy(idx_prev, idx_b, 4 * sizeof(int)); + n_right_prev = n_right; + n_top_prev = n_top; + unit_v_prev = unit_v; + + if (!closed) + { + // Terminate open paths with caps. + if (i == 0) + volume.push_quad(idx_a[BOTTOM], idx_a[RIGHT], idx_a[TOP], idx_a[LEFT]); + + // We don't use 'else' because both cases are true if we have only one line. + if (i + 1 == lines.size()) + volume.push_quad(idx_b[BOTTOM], idx_b[LEFT], idx_b[TOP], idx_b[RIGHT]); + } + + // Add quads for a straight hollow tube-like segment. + // bottom-right face + volume.push_quad(idx_a[BOTTOM], idx_b[BOTTOM], idx_b[RIGHT], idx_a[RIGHT]); + // top-right face + volume.push_quad(idx_a[RIGHT], idx_b[RIGHT], idx_b[TOP], idx_a[TOP]); + // top-left face + volume.push_quad(idx_a[TOP], idx_b[TOP], idx_b[LEFT], idx_a[LEFT]); + // bottom-left face + volume.push_quad(idx_a[LEFT], idx_b[LEFT], idx_b[BOTTOM], idx_a[BOTTOM]); + } + +#undef LEFT +#undef RIGHT +#undef TOP +#undef BOTTOM +} +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + static void thick_lines_to_verts( const Lines &lines, const std::vector<double> &widths, @@ -616,6 +894,19 @@ static void thick_lines_to_verts( thick_lines_to_indexed_vertex_array(lines, widths, heights, closed, top_z, volume.indexed_vertex_array); } +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +static void thick_lines_to_verts(const Lines3& lines, + const std::vector<double>& widths, + const std::vector<double>& heights, + bool closed, + GLVolume& volume) +{ + thick_lines_to_indexed_vertex_array(lines, widths, heights, closed, volume.indexed_vertex_array); +} +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + // Fill in the qverts and tverts with quads and triangles for the extrusion_path. static inline void extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, const Point ©, GLVolume &volume) { @@ -699,6 +990,21 @@ static void extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity, fl } } +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +static void polyline3_to_verts(const Polyline3& polyline, double width, double height, const Point& copy, GLVolume& volume) +{ + Polyline3 p = polyline; + p.remove_duplicate_points(); + p.translate(copy); + Lines3 lines = polyline.lines(); + std::vector<double> widths(lines.size(), width); + std::vector<double> heights(lines.size(), height); + thick_lines_to_verts(lines, widths, heights, false, volume); +} +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + void _3DScene::_glew_init() { glewInit(); @@ -731,6 +1037,17 @@ static inline std::vector<float> parse_colors(const std::vector<std::string> &sc return output; } +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +void _3DScene::load_gcode_preview(const Print* print, GLVolumeCollection* volumes, bool use_VBOs) +{ + _load_gcode_extrusion_paths(*print, *volumes, use_VBOs); + _load_gcode_travel_paths(*print, *volumes, use_VBOs); + _load_gcode_retractions(*print, *volumes, use_VBOs); +} +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + // Create 3D thick extrusion lines for a skirt and brim. // Adds a new Slic3r::GUI::3DScene::Volume to volumes. void _3DScene::_load_print_toolpaths( @@ -739,7 +1056,7 @@ void _3DScene::_load_print_toolpaths( const std::vector<std::string> &tool_colors, bool use_VBOs) { - if (! print->has_skirt() && print->config.brim_width.value == 0) + if (!print->has_skirt() && print->config.brim_width.value == 0) return; const float color[] = { 0.5f, 1.0f, 0.5f, 1.f }; // greenish @@ -1088,4 +1405,164 @@ void _3DScene::_load_wipe_tower_toolpaths( BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end"; } +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +void _3DScene::_load_gcode_extrusion_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) +{ + // helper functions to extract data from path in dependence of the selected extrusion view type + struct PathHelper + { + static float path_filter(GCodeAnalyzer::PreviewData::Extrusion::EViewType type, const ExtrusionPath& path) + { + switch (type) + { + case GCodeAnalyzer::PreviewData::Extrusion::FeatureType: + return (float)path.role(); + case GCodeAnalyzer::PreviewData::Extrusion::Height: + return path.height; + case GCodeAnalyzer::PreviewData::Extrusion::Width: + return path.width; + case GCodeAnalyzer::PreviewData::Extrusion::Feedrate: + return path.feedrate; + } + + return 0.0f; + } + + static const GCodeAnalyzer::PreviewData::Color& path_color(const GCodeAnalyzer::PreviewData& data, const ExtrusionPath& path) + { + switch (data.extrusion.view_type) + { + case GCodeAnalyzer::PreviewData::Extrusion::FeatureType: + return data.get_extrusion_role_color(path.role()); + case GCodeAnalyzer::PreviewData::Extrusion::Height: + return data.get_extrusion_height_color(path.height); + case GCodeAnalyzer::PreviewData::Extrusion::Width: + return data.get_extrusion_width_color(path.width); + case GCodeAnalyzer::PreviewData::Extrusion::Feedrate: + return data.get_extrusion_feedrate_color(path.feedrate); + } + + return GCodeAnalyzer::PreviewData::Color::Dummy; + } + }; + + Point origin(0, 0); + for (const GCodeAnalyzer::PreviewData::Extrusion::Layer& layer : print.gcode_preview.extrusion.layers) + { + float filter = FLT_MAX; + GLVolume* volume = nullptr; + + for (const ExtrusionPath& path : layer.paths) + { + if (print.gcode_preview.extrusion.is_role_flag_set(path.role())) + { + float path_filter = PathHelper::path_filter(print.gcode_preview.extrusion.view_type, path); + if (filter == path_filter) + { + // adds path to current volume + if (volume != nullptr) + extrusionentity_to_verts(path, layer.z, origin, *volume); + } + else + { + if (volume != nullptr) + { + // finalizes current volume + volume->bounding_box = volume->indexed_vertex_array.bounding_box(); + volume->indexed_vertex_array.finalize_geometry(use_VBOs); + volume = nullptr; + } + + // adds new volume + volumes.volumes.emplace_back(new GLVolume(PathHelper::path_color(print.gcode_preview, path).rgba)); + volume = volumes.volumes.back(); + if (volume != nullptr) + { + volume->print_zs.push_back(layer.z); + volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); + volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); + + // adds path to current volume + extrusionentity_to_verts(path, layer.z, origin, *volume); + } + + // updates current filter + filter = path_filter; + } + } + } + + if (volume != nullptr) + { + // finalizes last volume on layer + volume->bounding_box = volume->indexed_vertex_array.bounding_box(); + volume->indexed_vertex_array.finalize_geometry(use_VBOs); + } + } +} + +void _3DScene::_load_gcode_travel_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) +{ + struct TypeMatch + { + GCodeAnalyzer::PreviewData::Travel::EType type; + + TypeMatch(GCodeAnalyzer::PreviewData::Travel::EType type) + : type(type) + { + } + + bool operator () (const GCodeAnalyzer::PreviewData::Travel::Polyline& p) const + { + return p.type == type; + } + }; + + if (print.gcode_preview.travel.is_visible) + { + Point origin(0, 0); + for (unsigned int i = (unsigned int)GCodeAnalyzer::PreviewData::Travel::Move; i < (unsigned int)GCodeAnalyzer::PreviewData::Travel::Num_Types; ++i) + { + GCodeAnalyzer::PreviewData::Travel::EType type = (GCodeAnalyzer::PreviewData::Travel::EType)i; + if (std::count_if(print.gcode_preview.travel.polylines.begin(), print.gcode_preview.travel.polylines.end(), TypeMatch(type)) > 0) + { + volumes.volumes.emplace_back(new GLVolume(print.gcode_preview.travel.type_colors[i].rgba)); + GLVolume* volume = volumes.volumes.back(); + + if (volume != nullptr) + { + for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) + { + if (polyline.type == type) + { + const BoundingBox3& bbox = polyline.polyline.bounding_box(); + coordf_t print_z = unscale(bbox.max.z); + volume->print_zs.push_back(print_z); + volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); + volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); + + // adds polyline to volume + polyline3_to_verts(polyline.polyline, print.gcode_preview.travel.width, print.gcode_preview.travel.height, origin, *volume); + } + } + + // finalizes volume + volume->bounding_box = volume->indexed_vertex_array.bounding_box(); + volume->indexed_vertex_array.finalize_geometry(use_VBOs); + } + } + } + } +} + +void _3DScene::_load_gcode_retractions(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) +{ + if (print.gcode_preview.retraction.is_visible) + { + } +} +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + } diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 27eeb7ca8..d4fc0ed67 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -106,6 +106,14 @@ public: push_geometry(float(x), float(y), float(z), float(nx), float(ny), float(nz)); } +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + inline void push_geometry(const Pointf3& p, const Vectorf3& n) { + push_geometry(p.x, p.y, p.z, n.x, n.y, n.z); + } +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + inline void push_triangle(int idx1, int idx2, int idx3) { if (this->triangle_indices.size() + 3 > this->vertices_and_normals_interleaved.capacity()) this->triangle_indices.reserve(next_highest_power_of_2(this->triangle_indices.size() + 3)); @@ -344,6 +352,12 @@ class _3DScene public: static void _glew_init(); +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + static void load_gcode_preview(const Print* print, GLVolumeCollection* volumes, bool use_VBOs); +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + static void _load_print_toolpaths( const Print *print, GLVolumeCollection *volumes, @@ -362,6 +376,15 @@ public: GLVolumeCollection *volumes, const std::vector<std::string> &tool_colors_str, bool use_VBOs); + +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +private: + static void _load_gcode_extrusion_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); + static void _load_gcode_travel_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); + static void _load_gcode_retractions(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ }; } diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 13f0d42f2..186511cc4 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -168,4 +168,12 @@ _load_wipe_tower_toolpaths(print, volumes, tool_colors, use_VBOs) CODE: _3DScene::_load_wipe_tower_toolpaths(print, volumes, tool_colors, use_VBOs != 0); +void +load_gcode_preview(print, volumes, use_VBOs) + Print *print; + GLVolumeCollection *volumes; + int use_VBOs; + CODE: + _3DScene::load_gcode_preview(print, volumes, use_VBOs != 0); + %} diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index cbc04a804..e3e1704fe 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -165,6 +165,14 @@ _constant() size_t object_count() %code%{ RETVAL = THIS->objects.size(); %}; +// ===================== ENRICO_GCODE_PREVIEW ================================================== + void clear_gcode_preview_data(); + void set_gcode_preview_type(unsigned char type); + void set_gcode_preview_extrusion_flags(unsigned int flags); + void set_gcode_preview_travel_visible(bool visible); + void set_gcode_preview_retractions_visible(bool visible); +// ===================== ENRICO_GCODE_PREVIEW ================================================== + PrintRegionPtrs* regions() %code%{ RETVAL = &THIS->regions; %}; Ref<PrintRegion> get_region(int idx); From 6a744238b9a4d266b1028d1b86998553c0f61df8 Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Mon, 8 Jan 2018 16:05:01 +0100 Subject: [PATCH 02/23] Added preview of retractions and unretractions --- lib/Slic3r/GUI/Plater/3DPreview.pm | 9 ++- xs/src/libslic3r/GCode/Analyzer.cpp | 33 +++++++- xs/src/libslic3r/GCode/Analyzer.hpp | 18 ++++- xs/src/libslic3r/Print.cpp | 5 ++ xs/src/libslic3r/Print.hpp | 1 + xs/src/slic3r/GUI/3DScene.cpp | 115 ++++++++++++++++++++++++++++ xs/src/slic3r/GUI/3DScene.hpp | 1 + xs/xsp/Print.xsp | 1 + 8 files changed, 179 insertions(+), 4 deletions(-) diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index 9ff3461e0..488938267 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -94,8 +94,9 @@ sub new { $checklist_features->Check($i, 1); } - my $checkbox_travel = Wx::CheckBox->new($self, -1, "Travel"); + my $checkbox_travel = Wx::CheckBox->new($self, -1, "Travel"); my $checkbox_retractions = Wx::CheckBox->new($self, -1, "Retractions"); + my $checkbox_unretractions = Wx::CheckBox->new($self, -1, "Unretractions"); # ===================== ENRICO_GCODE_PREVIEW ================================================== my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL); @@ -116,6 +117,7 @@ sub new { $vsizer_outer->Add($checklist_features, 0, wxTOP | wxALL | wxALIGN_CENTER_HORIZONTAL, 5); $vsizer_outer->Add($checkbox_travel, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); $vsizer_outer->Add($checkbox_retractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + $vsizer_outer->Add($checkbox_unretractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); # ===================== ENRICO_GCODE_PREVIEW ================================================== my $sizer = Wx::BoxSizer->new(wxHORIZONTAL); @@ -228,6 +230,11 @@ sub new { $self->auto_zoom(0); $self->reload_print; }); + EVT_CHECKBOX($self, $checkbox_unretractions, sub { + $self->print->set_gcode_preview_unretractions_visible($checkbox_unretractions->IsChecked()); + $self->auto_zoom(0); + $self->reload_print; + }); # ===================== ENRICO_GCODE_PREVIEW ================================================== $self->SetSizer($sizer); diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp index 467e2b6ae..e00bd5daf 100644 --- a/xs/src/libslic3r/GCode/Analyzer.cpp +++ b/xs/src/libslic3r/GCode/Analyzer.cpp @@ -567,8 +567,18 @@ void GCodeAnalyzer::PreviewData::Travel::set_default() is_visible = false; } +const GCodeAnalyzer::PreviewData::Color GCodeAnalyzer::PreviewData::Retraction::Default_Color = GCodeAnalyzer::PreviewData::Color(1.0f, 1.0f, 1.0f, 1.0f); + +GCodeAnalyzer::PreviewData::Retraction::Position::Position(const Point3& position, float width, float height) + : position(position) + , width(width) + , height(height) +{ +} + void GCodeAnalyzer::PreviewData::Retraction::set_default() { + color = Default_Color; is_visible = false; }; @@ -582,6 +592,7 @@ void GCodeAnalyzer::PreviewData::set_default() extrusion.set_default(); travel.set_default(); retraction.set_default(); + unretraction.set_default(); } void GCodeAnalyzer::PreviewData::reset() @@ -589,6 +600,7 @@ void GCodeAnalyzer::PreviewData::reset() extrusion.layers.clear(); travel.polylines.clear(); retraction.positions.clear(); + unretraction.positions.clear(); } const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::get_extrusion_role_color(ExtrusionRole role) const @@ -658,6 +670,9 @@ void GCodeAnalyzer::calc_gcode_preview_data(Print& print) // calculates retractions _calc_gcode_preview_retractions(print); + + // calculates unretractions + _calc_gcode_preview_unretractions(print); } void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line) @@ -1259,10 +1274,24 @@ void GCodeAnalyzer::_calc_gcode_preview_retractions(Print& print) for (const GCodeMove& move : retraction_moves->second) { - print.gcode_preview.retraction.positions.emplace_back(scale_(move.start_position.x), scale_(move.start_position.y), scale_(move.start_position.z)); + // store position + Point3 position(scale_(move.start_position.x), scale_(move.start_position.y), scale_(move.start_position.z)); + print.gcode_preview.retraction.positions.emplace_back(position, move.data.width, move.data.height); } +} - int a = 0; +void GCodeAnalyzer::_calc_gcode_preview_unretractions(Print& print) +{ + TypeToMovesMap::iterator unretraction_moves = m_moves_map.find(GCodeMove::Unretract); + if (unretraction_moves == m_moves_map.end()) + return; + + for (const GCodeMove& move : unretraction_moves->second) + { + // store position + Point3 position(scale_(move.start_position.x), scale_(move.start_position.y), scale_(move.start_position.z)); + print.gcode_preview.unretraction.positions.emplace_back(position, move.data.width, move.data.height); + } } GCodeAnalyzer::PreviewData::Color operator + (const GCodeAnalyzer::PreviewData::Color& c1, const GCodeAnalyzer::PreviewData::Color& c2) diff --git a/xs/src/libslic3r/GCode/Analyzer.hpp b/xs/src/libslic3r/GCode/Analyzer.hpp index 8236772fb..afc863998 100644 --- a/xs/src/libslic3r/GCode/Analyzer.hpp +++ b/xs/src/libslic3r/GCode/Analyzer.hpp @@ -375,7 +375,21 @@ public: struct Retraction { - Points3 positions; + static const Color Default_Color; + + struct Position + { + Point3 position; + float width; + float height; + + Position(const Point3& position, float width, float height); + }; + + typedef std::vector<Position> PositionsList; + + PositionsList positions; + Color color; bool is_visible; void set_default(); @@ -384,6 +398,7 @@ public: Extrusion extrusion; Travel travel; Retraction retraction; + Retraction unretraction; PreviewData(); @@ -515,6 +530,7 @@ private: void _calc_gcode_preview_extrusion_layers(Print& print); void _calc_gcode_preview_travel(Print& print); void _calc_gcode_preview_retractions(Print& print); + void _calc_gcode_preview_unretractions(Print& print); }; GCodeAnalyzer::PreviewData::Color operator + (const GCodeAnalyzer::PreviewData::Color& c1, const GCodeAnalyzer::PreviewData::Color& c2); diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 0d984d6da..2173ae9b1 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -98,6 +98,11 @@ void Print::set_gcode_preview_retractions_visible(bool visible) { gcode_preview.retraction.is_visible = visible; } + +void Print::set_gcode_preview_unretractions_visible(bool visible) +{ + gcode_preview.unretraction.is_visible = visible; +} #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 7a69973de..2ded86ee9 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -271,6 +271,7 @@ public: bool is_gcode_preview_extrusion_role_enabled(ExtrusionRole role); void set_gcode_preview_travel_visible(bool visible); void set_gcode_preview_retractions_visible(bool visible); + void set_gcode_preview_unretractions_visible(bool visible); #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 85c044db8..4429d7449 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -880,6 +880,56 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines, #undef TOP #undef BOTTOM } + +static void point_to_indexed_vertex_array(const Point3& point, + double width, + double height, + GLIndexedVertexArray& volume) +{ + // builds a double piramid, with vertices on the local axes, around the point + + Pointf3 center = Pointf3::new_unscale(point); + + double scale_factor = 1.0; + double w = scale_factor * width; + double h = scale_factor * height; + + // new vertices ids + int idx_last = int(volume.vertices_and_normals_interleaved.size() / 6); + int idxs[6]; + for (int i = 0; i < 6; ++i) + { + idxs[i] = idx_last + i; + } + + Vectorf3 displacement_x(w, 0.0, 0.0); + Vectorf3 displacement_y(0.0, w, 0.0); + Vectorf3 displacement_z(0.0, 0.0, h); + + Vectorf3 unit_x(1.0, 0.0, 0.0); + Vectorf3 unit_y(0.0, 1.0, 0.0); + Vectorf3 unit_z(0.0, 0.0, 1.0); + + // vertices + volume.push_geometry(center - displacement_x, -unit_x); // idxs[0] + volume.push_geometry(center + displacement_x, unit_x); // idxs[1] + volume.push_geometry(center - displacement_y, -unit_y); // idxs[2] + volume.push_geometry(center + displacement_y, unit_y); // idxs[3] + volume.push_geometry(center - displacement_z, -unit_z); // idxs[4] + volume.push_geometry(center + displacement_z, unit_z); // idxs[5] + + // top piramid faces + volume.push_triangle(idxs[0], idxs[2], idxs[5]); + volume.push_triangle(idxs[2], idxs[1], idxs[5]); + volume.push_triangle(idxs[1], idxs[3], idxs[5]); + volume.push_triangle(idxs[3], idxs[0], idxs[5]); + + // bottom piramid faces + volume.push_triangle(idxs[2], idxs[0], idxs[4]); + volume.push_triangle(idxs[1], idxs[2], idxs[4]); + volume.push_triangle(idxs[3], idxs[1], idxs[4]); + volume.push_triangle(idxs[0], idxs[3], idxs[4]); +} #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ @@ -904,6 +954,14 @@ static void thick_lines_to_verts(const Lines3& lines, { thick_lines_to_indexed_vertex_array(lines, widths, heights, closed, volume.indexed_vertex_array); } + +static void point_to_verts(const Point3& point, + double width, + double height, + GLVolume& volume) +{ + point_to_indexed_vertex_array(point, width, height, volume.indexed_vertex_array); +} #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ @@ -1002,6 +1060,13 @@ static void polyline3_to_verts(const Polyline3& polyline, double width, double h std::vector<double> heights(lines.size(), height); thick_lines_to_verts(lines, widths, heights, false, volume); } + +static void point3_to_verts(const Point3& point, double width, double height, const Point& copy, GLVolume& volume) +{ + Point3 p = point; + p.translate(copy); + point_to_verts(p, width, height, volume); +} #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ @@ -1044,6 +1109,7 @@ void _3DScene::load_gcode_preview(const Print* print, GLVolumeCollection* volume _load_gcode_extrusion_paths(*print, *volumes, use_VBOs); _load_gcode_travel_paths(*print, *volumes, use_VBOs); _load_gcode_retractions(*print, *volumes, use_VBOs); + _load_gcode_unretractions(*print, *volumes, use_VBOs); } #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ @@ -1560,6 +1626,55 @@ void _3DScene::_load_gcode_retractions(const Print& print, GLVolumeCollection& v { if (print.gcode_preview.retraction.is_visible) { + volumes.volumes.emplace_back(new GLVolume(print.gcode_preview.retraction.color.rgba)); + GLVolume* volume = volumes.volumes.back(); + + if (volume != nullptr) + { + Point origin(0, 0); + for (const GCodeAnalyzer::PreviewData::Retraction::Position& position : print.gcode_preview.retraction.positions) + { + coordf_t print_z = unscale(position.position.z); + volume->print_zs.push_back(print_z); + volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); + volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); + + // adds point to volume + point3_to_verts(position.position, position.width, position.height, origin, *volume); + } + + // finalizes volume + volume->bounding_box = volume->indexed_vertex_array.bounding_box(); + volume->indexed_vertex_array.finalize_geometry(use_VBOs); + } + } +} + +void _3DScene::_load_gcode_unretractions(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) +{ + if (print.gcode_preview.unretraction.is_visible) + { + volumes.volumes.emplace_back(new GLVolume(print.gcode_preview.unretraction.color.rgba)); + GLVolume* volume = volumes.volumes.back(); + + if (volume != nullptr) + { + Point origin(0, 0); + for (const GCodeAnalyzer::PreviewData::Retraction::Position& position : print.gcode_preview.unretraction.positions) + { + coordf_t print_z = unscale(position.position.z); + volume->print_zs.push_back(print_z); + volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); + volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); + + // adds point to volume + point3_to_verts(position.position, position.width, position.height, origin, *volume); + } + + // finalizes volume + volume->bounding_box = volume->indexed_vertex_array.bounding_box(); + volume->indexed_vertex_array.finalize_geometry(use_VBOs); + } } } #endif // ENRICO_GCODE_PREVIEW diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index d4fc0ed67..35c41ec2f 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -383,6 +383,7 @@ private: static void _load_gcode_extrusion_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); static void _load_gcode_travel_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); static void _load_gcode_retractions(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); + static void _load_gcode_unretractions(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ }; diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index e3e1704fe..d29e087c0 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -171,6 +171,7 @@ _constant() void set_gcode_preview_extrusion_flags(unsigned int flags); void set_gcode_preview_travel_visible(bool visible); void set_gcode_preview_retractions_visible(bool visible); + void set_gcode_preview_unretractions_visible(bool visible); // ===================== ENRICO_GCODE_PREVIEW ================================================== PrintRegionPtrs* regions() From bbc9a0abe6a318a27ff3b18b23f4ae18f845946d Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Wed, 10 Jan 2018 13:43:00 +0100 Subject: [PATCH 03/23] Parallelization of extrude path render geometry generation --- lib/Slic3r/GUI/Plater/3DPreview.pm | 6 +- xs/src/libslic3r/GCode/Analyzer.cpp | 4 + xs/src/slic3r/GUI/3DScene.cpp | 257 ++++++++++++++++++---------- 3 files changed, 171 insertions(+), 96 deletions(-) diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index 488938267..e7fb2aa22 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -205,6 +205,7 @@ sub new { $self->print->set_gcode_preview_type($selection); $self->auto_zoom(0); $self->reload_print; + $self->auto_zoom(1); }); EVT_CHECKLISTBOX($self, $checklist_features, sub { my $flags = 0; @@ -219,21 +220,25 @@ sub new { $self->print->set_gcode_preview_extrusion_flags($flags); $self->auto_zoom(0); $self->reload_print; + $self->auto_zoom(1); }); EVT_CHECKBOX($self, $checkbox_travel, sub { $self->print->set_gcode_preview_travel_visible($checkbox_travel->IsChecked()); $self->auto_zoom(0); $self->reload_print; + $self->auto_zoom(1); }); EVT_CHECKBOX($self, $checkbox_retractions, sub { $self->print->set_gcode_preview_retractions_visible($checkbox_retractions->IsChecked()); $self->auto_zoom(0); $self->reload_print; + $self->auto_zoom(1); }); EVT_CHECKBOX($self, $checkbox_unretractions, sub { $self->print->set_gcode_preview_unretractions_visible($checkbox_unretractions->IsChecked()); $self->auto_zoom(0); $self->reload_print; + $self->auto_zoom(1); }); # ===================== ENRICO_GCODE_PREVIEW ================================================== @@ -363,7 +368,6 @@ sub load_print { # ===================== ENRICO_GCODE_PREVIEW ================================================== $self->canvas->zoom_to_volumes; # ===================== ENRICO_GCODE_PREVIEW ================================================== - $self->auto_zoom(1); } # ===================== ENRICO_GCODE_PREVIEW ================================================== $self->_loaded(1); diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp index e00bd5daf..b7d1e742f 100644 --- a/xs/src/libslic3r/GCode/Analyzer.cpp +++ b/xs/src/libslic3r/GCode/Analyzer.cpp @@ -1181,6 +1181,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(Print& print) if ((data != move.data) || (data.feedrate != move.data.feedrate) || (z != move.start_position.z) || (position != move.start_position)) { // store current polyline + polyline.remove_duplicate_points(); Helper::store_polyline(polyline, data, z, print); // reset current polyline @@ -1206,6 +1207,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(Print& print) } // store last polyline + polyline.remove_duplicate_points(); Helper::store_polyline(polyline, data, z, print); // updates preview ranges data @@ -1244,6 +1246,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(Print& print) if ((type != move_type) || (direction != move_direction) || (position != move.start_position)) { // store current polyline + polyline.remove_duplicate_points(); Helper::store_polyline(polyline, type, direction, print); // reset current polyline @@ -1263,6 +1266,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(Print& print) } // store last polyline + polyline.remove_duplicate_points(); Helper::store_polyline(polyline, type, direction, print); } diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 4429d7449..8af45e6b2 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -658,11 +658,7 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines, Vectorf3 n_right; Vectorf3 unit_positive_z(0.0, 0.0, 1.0); -// float dot_z = dot(unit_v, unit_positive_z); -// bool is_vertical = ::fabs(dot_z) > 0.99999; - if ((line.a.x == line.b.x) && (line.a.y == line.b.y)) -// if (is_vertical) { // vertical segment n_right = (line.a.z < line.b.z) ? Vectorf3(-1.0, 0.0, 0.0) : Vectorf3(1.0, 0.0, 0.0); @@ -955,13 +951,22 @@ static void thick_lines_to_verts(const Lines3& lines, thick_lines_to_indexed_vertex_array(lines, widths, heights, closed, volume.indexed_vertex_array); } -static void point_to_verts(const Point3& point, +static void thick_point_to_verts(const Point3& point, double width, double height, GLVolume& volume) { point_to_indexed_vertex_array(point, width, height, volume.indexed_vertex_array); } + +// Fill in the qverts and tverts with quads and triangles for the extrusion_path. +static inline void 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); +} #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ @@ -1050,22 +1055,17 @@ static void extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity, fl //############################################################################################################ #if ENRICO_GCODE_PREVIEW -static void polyline3_to_verts(const Polyline3& polyline, double width, double height, const Point& copy, GLVolume& volume) +static void polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume) { - Polyline3 p = polyline; - p.remove_duplicate_points(); - p.translate(copy); Lines3 lines = polyline.lines(); std::vector<double> widths(lines.size(), width); std::vector<double> heights(lines.size(), height); thick_lines_to_verts(lines, widths, heights, false, volume); } -static void point3_to_verts(const Point3& point, double width, double height, const Point& copy, GLVolume& volume) +static void point3_to_verts(const Point3& point, double width, double height, GLVolume& volume) { - Point3 p = point; - p.translate(copy); - point_to_verts(p, width, height, volume); + thick_point_to_verts(point, width, height, volume); } #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ @@ -1513,58 +1513,92 @@ void _3DScene::_load_gcode_extrusion_paths(const Print& print, GLVolumeCollectio } }; - Point origin(0, 0); - for (const GCodeAnalyzer::PreviewData::Extrusion::Layer& layer : print.gcode_preview.extrusion.layers) + // temporary structure to contain data needed for parallelization + struct Ctxt { - float filter = FLT_MAX; - GLVolume* volume = nullptr; + const Print* print; + const GCodeAnalyzer::PreviewData::Extrusion::LayersList* layers; + } ctxt; - for (const ExtrusionPath& path : layer.paths) - { - if (print.gcode_preview.extrusion.is_role_flag_set(path.role())) - { - float path_filter = PathHelper::path_filter(print.gcode_preview.extrusion.view_type, path); - if (filter == path_filter) - { - // adds path to current volume - if (volume != nullptr) - extrusionentity_to_verts(path, layer.z, origin, *volume); - } - else - { - if (volume != nullptr) - { - // finalizes current volume - volume->bounding_box = volume->indexed_vertex_array.bounding_box(); - volume->indexed_vertex_array.finalize_geometry(use_VBOs); - volume = nullptr; - } - - // adds new volume - volumes.volumes.emplace_back(new GLVolume(PathHelper::path_color(print.gcode_preview, path).rgba)); - volume = volumes.volumes.back(); - if (volume != nullptr) - { - volume->print_zs.push_back(layer.z); - volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); - volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); - - // adds path to current volume - extrusionentity_to_verts(path, layer.z, origin, *volume); - } - - // updates current filter - filter = path_filter; - } - } - } + // fills data in temporary variable + ctxt.print = &print; + ctxt.layers = &print.gcode_preview.extrusion.layers; + // lambda for creating new volumes in a thread-safe way + tbb::spin_mutex new_volume_mutex; + auto new_volume = [&volumes, &new_volume_mutex](const float* color) -> GLVolume* + { + // allocate a new volume + GLVolume* volume = new GLVolume(color); if (volume != nullptr) { - // finalizes last volume on layer - volume->bounding_box = volume->indexed_vertex_array.bounding_box(); - volume->indexed_vertex_array.finalize_geometry(use_VBOs); + // adds the new volume to the collection + new_volume_mutex.lock(); + volumes.volumes.emplace_back(volume); + new_volume_mutex.unlock(); } + return volume; + }; + + size_t initial_volumes_count = volumes.volumes.size(); + + // generates volumes using parallelization + tbb::parallel_for(tbb::blocked_range<size_t>(0, ctxt.layers->size()), [&ctxt, &new_volume](const tbb::blocked_range<size_t>& range) + { + for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) + { + const GCodeAnalyzer::PreviewData::Extrusion::Layer& layer = ctxt.layers->operator[](idx_layer); + float filter = FLT_MAX; + GLVolume* volume = nullptr; + + for (const ExtrusionPath& path : layer.paths) + { + if (ctxt.print->gcode_preview.extrusion.is_role_flag_set(path.role())) + { + float path_filter = PathHelper::path_filter(ctxt.print->gcode_preview.extrusion.view_type, path); + if (filter == path_filter) + { + // adds path to current volume + if (volume != nullptr) + extrusionentity_to_verts(path, layer.z, *volume); + } + else + { + if (volume != nullptr) + { + // finalizes current volume + volume->bounding_box = volume->indexed_vertex_array.bounding_box(); + volume = nullptr; + } + + // adds new volume + volume = new_volume(PathHelper::path_color(ctxt.print->gcode_preview, path).rgba); + if (volume != nullptr) + { + volume->print_zs.push_back(layer.z); + volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); + volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); + + // adds path to current volume + extrusionentity_to_verts(path, layer.z, *volume); + } + + // updates current filter + filter = path_filter; + } + } + } + + if (volume != nullptr) + // finalizes last volume on layer + volume->bounding_box = volume->indexed_vertex_array.bounding_box(); + } + }); + + // sends geometry to gpu + for (size_t i = initial_volumes_count; i < volumes.volumes.size(); ++i) + { + volumes.volumes[i]->indexed_vertex_array.finalize_geometry(use_VBOs); } } @@ -1587,36 +1621,71 @@ void _3DScene::_load_gcode_travel_paths(const Print& print, GLVolumeCollection& if (print.gcode_preview.travel.is_visible) { - Point origin(0, 0); - for (unsigned int i = (unsigned int)GCodeAnalyzer::PreviewData::Travel::Move; i < (unsigned int)GCodeAnalyzer::PreviewData::Travel::Num_Types; ++i) + size_t initial_volumes_count = volumes.volumes.size(); + unsigned int types_count = (unsigned int)GCodeAnalyzer::PreviewData::Travel::Num_Types; + + // creates a new volume for each travel type + for (unsigned int i = 0; i < types_count; ++i) { - GCodeAnalyzer::PreviewData::Travel::EType type = (GCodeAnalyzer::PreviewData::Travel::EType)i; - if (std::count_if(print.gcode_preview.travel.polylines.begin(), print.gcode_preview.travel.polylines.end(), TypeMatch(type)) > 0) + GLVolume* volume = new GLVolume(print.gcode_preview.travel.type_colors[i].rgba); + if (volume != nullptr) + volumes.volumes.emplace_back(volume); + else { - volumes.volumes.emplace_back(new GLVolume(print.gcode_preview.travel.type_colors[i].rgba)); - GLVolume* volume = volumes.volumes.back(); - - if (volume != nullptr) + // an error occourred - restore to previous state and return + std::vector<GLVolume*>::iterator begin = volumes.volumes.begin() + initial_volumes_count; + std::vector<GLVolume*>::iterator end = volumes.volumes.end(); + for (std::vector<GLVolume*>::iterator it = begin; it < end; ++it) { - for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) - { - if (polyline.type == type) - { - const BoundingBox3& bbox = polyline.polyline.bounding_box(); - coordf_t print_z = unscale(bbox.max.z); - volume->print_zs.push_back(print_z); - volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); - volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); - - // adds polyline to volume - polyline3_to_verts(polyline.polyline, print.gcode_preview.travel.width, print.gcode_preview.travel.height, origin, *volume); - } - } - - // finalizes volume - volume->bounding_box = volume->indexed_vertex_array.bounding_box(); - volume->indexed_vertex_array.finalize_geometry(use_VBOs); + GLVolume* volume = *it; + delete volume; } + volumes.volumes.erase(begin, end); + return; + } + } + + for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) + { + unsigned int type = (unsigned int)polyline.type; + if (type < types_count) + { + const BoundingBox3& bbox = polyline.polyline.bounding_box(); + coordf_t print_z = unscale(bbox.max.z); + + // selects volume from polyline type + GLVolume* volume = volumes.volumes[initial_volumes_count + type]; + volume->print_zs.push_back(print_z); + volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); + volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); + + // adds polyline to volume + polyline3_to_verts(polyline.polyline, print.gcode_preview.travel.width, print.gcode_preview.travel.height, *volume); + } + } + + // removes empty volumes + std::vector<GLVolume*>::iterator it = volumes.volumes.begin() + initial_volumes_count; + while (it != volumes.volumes.end()) + { + GLVolume* volume = *it; + if (volume->print_zs.empty()) + { + delete volume; + it = volumes.volumes.erase(it); + } + else + ++it; + } + + // finalize volumes and sends geometry to gpu + if (volumes.volumes.size() > initial_volumes_count) + { + for (size_t i = initial_volumes_count; i < volumes.volumes.size(); ++i) + { + GLVolume* volume = volumes.volumes[i]; + volume->bounding_box = volume->indexed_vertex_array.bounding_box(); + volume->indexed_vertex_array.finalize_geometry(use_VBOs); } } } @@ -1626,12 +1695,11 @@ void _3DScene::_load_gcode_retractions(const Print& print, GLVolumeCollection& v { if (print.gcode_preview.retraction.is_visible) { - volumes.volumes.emplace_back(new GLVolume(print.gcode_preview.retraction.color.rgba)); - GLVolume* volume = volumes.volumes.back(); - + GLVolume* volume = new GLVolume(print.gcode_preview.retraction.color.rgba); if (volume != nullptr) { - Point origin(0, 0); + volumes.volumes.emplace_back(volume); + for (const GCodeAnalyzer::PreviewData::Retraction::Position& position : print.gcode_preview.retraction.positions) { coordf_t print_z = unscale(position.position.z); @@ -1640,7 +1708,7 @@ void _3DScene::_load_gcode_retractions(const Print& print, GLVolumeCollection& v volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); // adds point to volume - point3_to_verts(position.position, position.width, position.height, origin, *volume); + point3_to_verts(position.position, position.width, position.height, *volume); } // finalizes volume @@ -1654,12 +1722,11 @@ void _3DScene::_load_gcode_unretractions(const Print& print, GLVolumeCollection& { if (print.gcode_preview.unretraction.is_visible) { - volumes.volumes.emplace_back(new GLVolume(print.gcode_preview.unretraction.color.rgba)); - GLVolume* volume = volumes.volumes.back(); - + GLVolume* volume = new GLVolume(print.gcode_preview.unretraction.color.rgba); if (volume != nullptr) { - Point origin(0, 0); + volumes.volumes.emplace_back(volume); + for (const GCodeAnalyzer::PreviewData::Retraction::Position& position : print.gcode_preview.unretraction.positions) { coordf_t print_z = unscale(position.position.z); @@ -1668,7 +1735,7 @@ void _3DScene::_load_gcode_unretractions(const Print& print, GLVolumeCollection& volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); // adds point to volume - point3_to_verts(position.position, position.width, position.height, origin, *volume); + point3_to_verts(position.position, position.width, position.height, *volume); } // finalizes volume From a8a4c11b5bcffa431304f1a9879619b08be21f7e Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Thu, 11 Jan 2018 14:09:54 +0100 Subject: [PATCH 04/23] New algorithm for GLVolumes generation and reuse of already generated geometry --- lib/Slic3r/GUI/Plater/3DPreview.pm | 38 +- xs/src/libslic3r/GCode/Analyzer.cpp | 7 +- xs/src/libslic3r/GCode/Analyzer.hpp | 2 + xs/src/slic3r/GUI/3DScene.cpp | 530 ++++++++++++++++++---------- xs/src/slic3r/GUI/3DScene.hpp | 48 +++ 5 files changed, 426 insertions(+), 199 deletions(-) diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index e7fb2aa22..0af7a2ebf 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -209,35 +209,33 @@ sub new { }); EVT_CHECKLISTBOX($self, $checklist_features, sub { my $flags = 0; - for (my $i = 0; $i < $checklist_features->GetCount(); $i += 1) - { - if ($checklist_features->IsChecked($i)) - { + for (my $i = 0; $i < $checklist_features->GetCount(); $i += 1) { + if ($checklist_features->IsChecked($i)) { $flags += 2 ** $i; } } $self->print->set_gcode_preview_extrusion_flags($flags); $self->auto_zoom(0); - $self->reload_print; + $self->refresh_print; $self->auto_zoom(1); }); EVT_CHECKBOX($self, $checkbox_travel, sub { $self->print->set_gcode_preview_travel_visible($checkbox_travel->IsChecked()); $self->auto_zoom(0); - $self->reload_print; + $self->refresh_print; $self->auto_zoom(1); }); EVT_CHECKBOX($self, $checkbox_retractions, sub { $self->print->set_gcode_preview_retractions_visible($checkbox_retractions->IsChecked()); $self->auto_zoom(0); - $self->reload_print; + $self->refresh_print; $self->auto_zoom(1); }); EVT_CHECKBOX($self, $checkbox_unretractions, sub { $self->print->set_gcode_preview_unretractions_visible($checkbox_unretractions->IsChecked()); $self->auto_zoom(0); - $self->reload_print; + $self->refresh_print; $self->auto_zoom(1); }); # ===================== ENRICO_GCODE_PREVIEW ================================================== @@ -260,13 +258,29 @@ sub reload_print { $self->_loaded(0); if (! $self->IsShown && ! $force) { - $self->{reload_delayed} = 1; +# ===================== ENRICO_GCODE_PREVIEW ================================================== +# $self->{reload_delayed} = 1; +# ===================== ENRICO_GCODE_PREVIEW ================================================== return; } $self->load_print; } +# ===================== ENRICO_GCODE_PREVIEW ================================================== +sub refresh_print { + my ($self) = @_; + + $self->_loaded(0); + + if (! $self->IsShown) { + return; + } + + $self->load_print; +} +# ===================== ENRICO_GCODE_PREVIEW ================================================== + sub load_print { my ($self) = @_; @@ -431,8 +445,10 @@ sub set_number_extruders { # Called by the Platter wxNotebook when this page is activated. sub OnActivate { - my ($self) = @_; - $self->reload_print(1) if ($self->{reload_delayed}); +# ===================== ENRICO_GCODE_PREVIEW ================================================== +# my ($self) = @_; +# $self->reload_print(1) if ($self->{reload_delayed}); +# ===================== ENRICO_GCODE_PREVIEW ================================================== } 1; diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp index b7d1e742f..07f047923 100644 --- a/xs/src/libslic3r/GCode/Analyzer.cpp +++ b/xs/src/libslic3r/GCode/Analyzer.cpp @@ -542,12 +542,17 @@ void GCodeAnalyzer::PreviewData::Extrusion::set_default() } bool GCodeAnalyzer::PreviewData::Extrusion::is_role_flag_set(ExtrusionRole role) const +{ + return is_role_flag_set(role_flags, role); +} + +bool GCodeAnalyzer::PreviewData::Extrusion::is_role_flag_set(unsigned int flags, ExtrusionRole role) { if ((role < erPerimeter) || (erSupportMaterialInterface < role)) return false; unsigned int flag = (unsigned int)::exp2((double)(role - erPerimeter)); - return (role_flags & flag) == flag; + return (flags & flag) == flag; } const float GCodeAnalyzer::PreviewData::Travel::Default_Width = 0.075f; diff --git a/xs/src/libslic3r/GCode/Analyzer.hpp b/xs/src/libslic3r/GCode/Analyzer.hpp index afc863998..567892b8e 100644 --- a/xs/src/libslic3r/GCode/Analyzer.hpp +++ b/xs/src/libslic3r/GCode/Analyzer.hpp @@ -330,6 +330,8 @@ public: void set_default(); bool is_role_flag_set(ExtrusionRole role) const; + + static bool is_role_flag_set(unsigned int flags, ExtrusionRole role); }; struct Travel diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 8af45e6b2..f79d210a4 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -8,11 +8,13 @@ #include "../../libslic3r/Geometry.hpp" #include "../../libslic3r/Print.hpp" #include "../../libslic3r/Slicing.hpp" -//############################################################################################################ #if ENRICO_GCODE_PREVIEW #include "GCode/Analyzer.hpp" #endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ + +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#include "enrico/wintimer.h" +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #include <stdio.h> #include <stdlib.h> @@ -206,6 +208,13 @@ void GLVolume::set_range(double min_z, double max_z) void GLVolume::render() const { +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENRICO_GCODE_PREVIEW + if (!is_active) + return; +#endif // ENRICO_GCODE_PREVIEW +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + glCullFace(GL_BACK); glPushMatrix(); glTranslated(this->origin.x, this->origin.y, this->origin.z); @@ -336,7 +345,13 @@ void GLVolumeCollection::render_VBOs() const GLint color_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "uniform_color") : -1; for (GLVolume *volume : this->volumes) { - if (! volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id) +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENRICO_GCODE_PREVIEW + if (!volume->is_active) + continue; +#endif // ENRICO_GCODE_PREVIEW +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + if (!volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id) continue; GLsizei n_triangles = GLsizei(std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first)); GLsizei n_quads = GLsizei(std::min(volume->indexed_vertex_array.quad_indices_size, volume->qverts_range.second - volume->qverts_range.first)); @@ -374,6 +389,12 @@ void GLVolumeCollection::render_legacy() const for (GLVolume *volume : this->volumes) { assert(! volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENRICO_GCODE_PREVIEW + if (!volume->is_active) + continue; +#endif // ENRICO_GCODE_PREVIEW +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ GLsizei n_triangles = GLsizei(std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first)); GLsizei n_quads = GLsizei(std::min(volume->indexed_vertex_array.quad_indices_size, volume->qverts_range.second - volume->qverts_range.first)); if (n_triangles + n_quads == 0) @@ -1067,6 +1088,20 @@ static void point3_to_verts(const Point3& point, double width, double height, GL { thick_point_to_verts(point, width, height, volume); } + +_3DScene::GCodePreviewData::FirstVolume::FirstVolume(_3DScene::GCodePreviewData::EType type, unsigned int flag, unsigned int id) + : type(type) + , flag(flag) + , id(id) +{ +} + +void _3DScene::GCodePreviewData::reset() +{ + first_volumes.clear(); +} + +_3DScene::GCodePreviewData _3DScene::s_gcode_preview_data; #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ @@ -1106,10 +1141,30 @@ static inline std::vector<float> parse_colors(const std::vector<std::string> &sc #if ENRICO_GCODE_PREVIEW void _3DScene::load_gcode_preview(const Print* print, GLVolumeCollection* volumes, bool use_VBOs) { - _load_gcode_extrusion_paths(*print, *volumes, use_VBOs); - _load_gcode_travel_paths(*print, *volumes, use_VBOs); - _load_gcode_retractions(*print, *volumes, use_VBOs); - _load_gcode_unretractions(*print, *volumes, use_VBOs); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + WinTimer timer; + timer.Start(); + + std::cout << "#############################################################################" << std::endl; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + if (volumes->empty()) + { + s_gcode_preview_data.reset(); + + _load_gcode_extrusion_paths(*print, *volumes, use_VBOs); + _load_gcode_travel_paths(*print, *volumes, use_VBOs); + _load_gcode_retractions(*print, *volumes, use_VBOs); + _load_gcode_unretractions(*print, *volumes, use_VBOs); + } + + _update_gcode_volumes_visibility(*print, *volumes); + +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + std::cout << "VOLUMES COUNT = " << volumes->volumes.size() << std::endl; + std::cout << "FIRST VOLUMES COUNT = " << s_gcode_preview_data.first_volumes.size() << std::endl; + std::cout << "load_gcode_preview() = " << timer.GetElapsedTimeMillisec() << " ms" << std::endl; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ @@ -1475,8 +1530,13 @@ void _3DScene::_load_wipe_tower_toolpaths( #if ENRICO_GCODE_PREVIEW void _3DScene::_load_gcode_extrusion_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) { - // helper functions to extract data from path in dependence of the selected extrusion view type - struct PathHelper +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + WinTimer timer; + timer.Start(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + // helper functions to select data in dependence of the extrusion view type + struct Helper { static float path_filter(GCodeAnalyzer::PreviewData::Extrusion::EViewType type, const ExtrusionPath& path) { @@ -1495,144 +1555,88 @@ void _3DScene::_load_gcode_extrusion_paths(const Print& print, GLVolumeCollectio return 0.0f; } - static const GCodeAnalyzer::PreviewData::Color& path_color(const GCodeAnalyzer::PreviewData& data, const ExtrusionPath& path) + static const GCodeAnalyzer::PreviewData::Color& path_color(const GCodeAnalyzer::PreviewData& data, float value) { switch (data.extrusion.view_type) { case GCodeAnalyzer::PreviewData::Extrusion::FeatureType: - return data.get_extrusion_role_color(path.role()); + return data.get_extrusion_role_color((ExtrusionRole)(int)value); case GCodeAnalyzer::PreviewData::Extrusion::Height: - return data.get_extrusion_height_color(path.height); + return data.get_extrusion_height_color(value); case GCodeAnalyzer::PreviewData::Extrusion::Width: - return data.get_extrusion_width_color(path.width); + return data.get_extrusion_width_color(value); case GCodeAnalyzer::PreviewData::Extrusion::Feedrate: - return data.get_extrusion_feedrate_color(path.feedrate); + return data.get_extrusion_feedrate_color(value); } return GCodeAnalyzer::PreviewData::Color::Dummy; } }; - // temporary structure to contain data needed for parallelization - struct Ctxt + // Helper structure for filters + struct Filter { - const Print* print; - const GCodeAnalyzer::PreviewData::Extrusion::LayersList* layers; - } ctxt; + float value; + ExtrusionRole role; + GLVolume* volume; - // fills data in temporary variable - ctxt.print = &print; - ctxt.layers = &print.gcode_preview.extrusion.layers; - - // lambda for creating new volumes in a thread-safe way - tbb::spin_mutex new_volume_mutex; - auto new_volume = [&volumes, &new_volume_mutex](const float* color) -> GLVolume* - { - // allocate a new volume - GLVolume* volume = new GLVolume(color); - if (volume != nullptr) + Filter(float value, ExtrusionRole role) + : value(value) + , role(role) + , volume(nullptr) { - // adds the new volume to the collection - new_volume_mutex.lock(); - volumes.volumes.emplace_back(volume); - new_volume_mutex.unlock(); } - return volume; + + bool operator == (const Filter& other) const + { + if (value != other.value) + return false; + + if (role != other.role) + return false; + + return true; + } }; + typedef std::vector<Filter> FiltersList; + size_t initial_volumes_count = volumes.volumes.size(); - // generates volumes using parallelization - tbb::parallel_for(tbb::blocked_range<size_t>(0, ctxt.layers->size()), [&ctxt, &new_volume](const tbb::blocked_range<size_t>& range) + // detects filters + FiltersList filters; + for (const GCodeAnalyzer::PreviewData::Extrusion::Layer& layer : print.gcode_preview.extrusion.layers) { - for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) + for (const ExtrusionPath& path : layer.paths) { - const GCodeAnalyzer::PreviewData::Extrusion::Layer& layer = ctxt.layers->operator[](idx_layer); - float filter = FLT_MAX; - GLVolume* volume = nullptr; - - for (const ExtrusionPath& path : layer.paths) - { - if (ctxt.print->gcode_preview.extrusion.is_role_flag_set(path.role())) - { - float path_filter = PathHelper::path_filter(ctxt.print->gcode_preview.extrusion.view_type, path); - if (filter == path_filter) - { - // adds path to current volume - if (volume != nullptr) - extrusionentity_to_verts(path, layer.z, *volume); - } - else - { - if (volume != nullptr) - { - // finalizes current volume - volume->bounding_box = volume->indexed_vertex_array.bounding_box(); - volume = nullptr; - } - - // adds new volume - volume = new_volume(PathHelper::path_color(ctxt.print->gcode_preview, path).rgba); - if (volume != nullptr) - { - volume->print_zs.push_back(layer.z); - volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); - volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); - - // adds path to current volume - extrusionentity_to_verts(path, layer.z, *volume); - } - - // updates current filter - filter = path_filter; - } - } - } - - if (volume != nullptr) - // finalizes last volume on layer - volume->bounding_box = volume->indexed_vertex_array.bounding_box(); + ExtrusionRole role = path.role(); + float path_filter = Helper::path_filter(print.gcode_preview.extrusion.view_type, path); + if (std::find(filters.begin(), filters.end(), Filter(path_filter, role)) == filters.end()) + filters.emplace_back(path_filter, role); } - }); - - // sends geometry to gpu - for (size_t i = initial_volumes_count; i < volumes.volumes.size(); ++i) - { - volumes.volumes[i]->indexed_vertex_array.finalize_geometry(use_VBOs); } -} -void _3DScene::_load_gcode_travel_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) -{ - struct TypeMatch + // nothing to render, return + if (filters.empty()) + return; + + // creates a new volume for each filter + for (Filter& filter : filters) { - GCodeAnalyzer::PreviewData::Travel::EType type; + s_gcode_preview_data.first_volumes.emplace_back(GCodePreviewData::Extrusion, (unsigned int)filter.role, (unsigned int)volumes.volumes.size()); - TypeMatch(GCodeAnalyzer::PreviewData::Travel::EType type) - : type(type) + GLVolume* volume = new GLVolume(Helper::path_color(print.gcode_preview, filter.value).rgba); + if (volume != nullptr) { + filter.volume = volume; + volumes.volumes.emplace_back(volume); } - - bool operator () (const GCodeAnalyzer::PreviewData::Travel::Polyline& p) const + else { - return p.type == type; - } - }; - - if (print.gcode_preview.travel.is_visible) - { - size_t initial_volumes_count = volumes.volumes.size(); - unsigned int types_count = (unsigned int)GCodeAnalyzer::PreviewData::Travel::Num_Types; - - // creates a new volume for each travel type - for (unsigned int i = 0; i < types_count; ++i) - { - GLVolume* volume = new GLVolume(print.gcode_preview.travel.type_colors[i].rgba); - if (volume != nullptr) - volumes.volumes.emplace_back(volume); - else + // an error occourred - restore to previous state and return + s_gcode_preview_data.first_volumes.pop_back(); + if (initial_volumes_count != volumes.volumes.size()) { - // an error occourred - restore to previous state and return std::vector<GLVolume*>::iterator begin = volumes.volumes.begin() + initial_volumes_count; std::vector<GLVolume*>::iterator end = volumes.volumes.end(); for (std::vector<GLVolume*>::iterator it = begin; it < end; ++it) @@ -1644,103 +1648,255 @@ void _3DScene::_load_gcode_travel_paths(const Print& print, GLVolumeCollection& return; } } + } - for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) + // populates volumes + for (const GCodeAnalyzer::PreviewData::Extrusion::Layer& layer : print.gcode_preview.extrusion.layers) + { + for (const ExtrusionPath& path : layer.paths) { - unsigned int type = (unsigned int)polyline.type; - if (type < types_count) + float path_filter = Helper::path_filter(print.gcode_preview.extrusion.view_type, path); + FiltersList::iterator filter = std::find(filters.begin(), filters.end(), Filter(path_filter, path.role())); + if (filter != filters.end()) { - const BoundingBox3& bbox = polyline.polyline.bounding_box(); - coordf_t print_z = unscale(bbox.max.z); + filter->volume->print_zs.push_back(layer.z); + filter->volume->offsets.push_back(filter->volume->indexed_vertex_array.quad_indices.size()); + filter->volume->offsets.push_back(filter->volume->indexed_vertex_array.triangle_indices.size()); - // selects volume from polyline type - GLVolume* volume = volumes.volumes[initial_volumes_count + type]; - volume->print_zs.push_back(print_z); - volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); - volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); - - // adds polyline to volume - polyline3_to_verts(polyline.polyline, print.gcode_preview.travel.width, print.gcode_preview.travel.height, *volume); - } - } - - // removes empty volumes - std::vector<GLVolume*>::iterator it = volumes.volumes.begin() + initial_volumes_count; - while (it != volumes.volumes.end()) - { - GLVolume* volume = *it; - if (volume->print_zs.empty()) - { - delete volume; - it = volumes.volumes.erase(it); - } - else - ++it; - } - - // finalize volumes and sends geometry to gpu - if (volumes.volumes.size() > initial_volumes_count) - { - for (size_t i = initial_volumes_count; i < volumes.volumes.size(); ++i) - { - GLVolume* volume = volumes.volumes[i]; - volume->bounding_box = volume->indexed_vertex_array.bounding_box(); - volume->indexed_vertex_array.finalize_geometry(use_VBOs); + extrusionentity_to_verts(path, layer.z, *filter->volume); } } } + + // finalize volumes and sends geometry to gpu + if (volumes.volumes.size() > initial_volumes_count) + { + for (size_t i = initial_volumes_count; i < volumes.volumes.size(); ++i) + { + GLVolume* volume = volumes.volumes[i]; + volume->bounding_box = volume->indexed_vertex_array.bounding_box(); + volume->indexed_vertex_array.finalize_geometry(use_VBOs); + } + } + +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + std::cout << "_load_gcode_extrusion_paths() = " << timer.GetElapsedTimeMillisec() << " ms" << std::endl; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +} + +void _3DScene::_load_gcode_travel_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) +{ +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + WinTimer timer; + timer.Start(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + // Helper structure for types + struct Type + { + GCodeAnalyzer::PreviewData::Travel::EType value; + GLVolume* volume; + + explicit Type(GCodeAnalyzer::PreviewData::Travel::EType value) + : value(value) + , volume(nullptr) + { + } + + bool operator == (const Type& other) const + { + return value == other.value; + } + }; + + typedef std::vector<Type> TypesList; + + size_t initial_volumes_count = volumes.volumes.size(); + s_gcode_preview_data.first_volumes.emplace_back(GCodePreviewData::Travel, 0, (unsigned int)initial_volumes_count); + + // detects types + TypesList types; + for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) + { + if (std::find(types.begin(), types.end(), Type(polyline.type)) == types.end()) + types.emplace_back(polyline.type); + } + + // nothing to render, return + if (types.empty()) + return; + + // creates a new volume for each type + for (Type& type : types) + { + GLVolume* volume = new GLVolume(print.gcode_preview.travel.type_colors[type.value].rgba); + if (volume != nullptr) + { + type.volume = volume; + volumes.volumes.emplace_back(volume); + } + else + { + // an error occourred - restore to previous state and return + if (initial_volumes_count != volumes.volumes.size()) + { + std::vector<GLVolume*>::iterator begin = volumes.volumes.begin() + initial_volumes_count; + std::vector<GLVolume*>::iterator end = volumes.volumes.end(); + for (std::vector<GLVolume*>::iterator it = begin; it < end; ++it) + { + GLVolume* volume = *it; + delete volume; + } + volumes.volumes.erase(begin, end); + return; + } + } + } + + // populates volumes + for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) + { + TypesList::iterator type = std::find(types.begin(), types.end(), Type(polyline.type)); + if (type != types.end()) + { + type->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().max.z)); + type->volume->offsets.push_back(type->volume->indexed_vertex_array.quad_indices.size()); + type->volume->offsets.push_back(type->volume->indexed_vertex_array.triangle_indices.size()); + + polyline3_to_verts(polyline.polyline, print.gcode_preview.travel.width, print.gcode_preview.travel.height, *type->volume); + } + } + + // finalize volumes and sends geometry to gpu + if (volumes.volumes.size() > initial_volumes_count) + { + for (size_t i = initial_volumes_count; i < volumes.volumes.size(); ++i) + { + GLVolume* volume = volumes.volumes[i]; + volume->bounding_box = volume->indexed_vertex_array.bounding_box(); + volume->indexed_vertex_array.finalize_geometry(use_VBOs); + } + } + +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + std::cout << "_load_gcode_travel_paths() = " << timer.GetElapsedTimeMillisec() << " ms" << std::endl; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } void _3DScene::_load_gcode_retractions(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) { - if (print.gcode_preview.retraction.is_visible) +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + WinTimer timer; + timer.Start(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + s_gcode_preview_data.first_volumes.emplace_back(GCodePreviewData::Retraction, 0, (unsigned int)volumes.volumes.size()); + + // nothing to render, return + if (print.gcode_preview.retraction.positions.empty()) + return; + + GLVolume* volume = new GLVolume(print.gcode_preview.retraction.color.rgba); + if (volume != nullptr) { - GLVolume* volume = new GLVolume(print.gcode_preview.retraction.color.rgba); - if (volume != nullptr) + volumes.volumes.emplace_back(volume); + + for (const GCodeAnalyzer::PreviewData::Retraction::Position& position : print.gcode_preview.retraction.positions) { - volumes.volumes.emplace_back(volume); + volume->print_zs.push_back(unscale(position.position.z)); + volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); + volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); - for (const GCodeAnalyzer::PreviewData::Retraction::Position& position : print.gcode_preview.retraction.positions) - { - coordf_t print_z = unscale(position.position.z); - volume->print_zs.push_back(print_z); - volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); - volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); - - // adds point to volume - point3_to_verts(position.position, position.width, position.height, *volume); - } - - // finalizes volume - volume->bounding_box = volume->indexed_vertex_array.bounding_box(); - volume->indexed_vertex_array.finalize_geometry(use_VBOs); + point3_to_verts(position.position, position.width, position.height, *volume); } + + // finalize volumes and sends geometry to gpu + volume->bounding_box = volume->indexed_vertex_array.bounding_box(); + volume->indexed_vertex_array.finalize_geometry(use_VBOs); } + +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + std::cout << "_load_gcode_retractions() = " << timer.GetElapsedTimeMillisec() << " ms" << std::endl; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } void _3DScene::_load_gcode_unretractions(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) { - if (print.gcode_preview.unretraction.is_visible) +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + WinTimer timer; + timer.Start(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + s_gcode_preview_data.first_volumes.emplace_back(GCodePreviewData::Unretraction, 0, (unsigned int)volumes.volumes.size()); + + // nothing to render, return + if (print.gcode_preview.unretraction.positions.empty()) + return; + + GLVolume* volume = new GLVolume(print.gcode_preview.unretraction.color.rgba); + if (volume != nullptr) { - GLVolume* volume = new GLVolume(print.gcode_preview.unretraction.color.rgba); - if (volume != nullptr) + volumes.volumes.emplace_back(volume); + + for (const GCodeAnalyzer::PreviewData::Retraction::Position& position : print.gcode_preview.unretraction.positions) { - volumes.volumes.emplace_back(volume); + volume->print_zs.push_back(unscale(position.position.z)); + volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); + volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); - for (const GCodeAnalyzer::PreviewData::Retraction::Position& position : print.gcode_preview.unretraction.positions) + point3_to_verts(position.position, position.width, position.height, *volume); + } + + // finalize volumes and sends geometry to gpu + volume->bounding_box = volume->indexed_vertex_array.bounding_box(); + volume->indexed_vertex_array.finalize_geometry(use_VBOs); + } + +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + std::cout << "_load_gcode_unretractions() = " << timer.GetElapsedTimeMillisec() << " ms" << std::endl; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +} + +void _3DScene::_update_gcode_volumes_visibility(const Print& print, GLVolumeCollection& volumes) +{ + unsigned int size = (unsigned int)s_gcode_preview_data.first_volumes.size(); + for (unsigned int i = 0; i < size; ++i) + { + std::vector<GLVolume*>::iterator begin = volumes.volumes.begin() + s_gcode_preview_data.first_volumes[i].id; + std::vector<GLVolume*>::iterator end = (i + 1 < size) ? volumes.volumes.begin() + s_gcode_preview_data.first_volumes[i + 1].id : volumes.volumes.end(); + + for (std::vector<GLVolume*>::iterator it = begin; it != end; ++it) + { + GLVolume* volume = *it; + + switch (s_gcode_preview_data.first_volumes[i].type) { - coordf_t print_z = unscale(position.position.z); - volume->print_zs.push_back(print_z); - volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); - volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); - - // adds point to volume - point3_to_verts(position.position, position.width, position.height, *volume); + case GCodePreviewData::Extrusion: + { + volume->is_active = print.gcode_preview.extrusion.is_role_flag_set((ExtrusionRole)s_gcode_preview_data.first_volumes[i].flag); + break; + } + case GCodePreviewData::Travel: + { + volume->is_active = print.gcode_preview.travel.is_visible; + break; + } + case GCodePreviewData::Retraction: + { + volume->is_active = print.gcode_preview.retraction.is_visible; + break; + } + case GCodePreviewData::Unretraction: + { + volume->is_active = print.gcode_preview.unretraction.is_visible; + break; + } + default: + { + volume->is_active = false; + break; + } } - - // finalizes volume - volume->bounding_box = volume->indexed_vertex_array.bounding_box(); - volume->indexed_vertex_array.finalize_geometry(use_VBOs); } } } diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 35c41ec2f..ba8a6a977 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -215,6 +215,11 @@ public: select_group_id(-1), drag_group_id(-1), selected(false), +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENRICO_GCODE_PREVIEW + is_active(true), +#endif // ENRICO_GCODE_PREVIEW +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ hover(false), tverts_range(0, size_t(-1)), qverts_range(0, size_t(-1)) @@ -251,6 +256,12 @@ public: int drag_group_id; // Is this object selected? bool selected; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if ENRICO_GCODE_PREVIEW + // Whether or not this volume is active for rendering + bool is_active; +#endif // ENRICO_GCODE_PREVIEW +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Boolean: Is mouse over this object? bool hover; @@ -266,6 +277,7 @@ public: // Offset into qverts & tverts, or offsets into indices stored into an OpenGL name_index_buffer. std::vector<size_t> offsets; + int object_idx() const { return this->composite_id / 1000000; } int volume_idx() const { return (this->composite_id / 1000) % 1000; } int instance_idx() const { return this->composite_id % 1000; } @@ -349,6 +361,36 @@ private: class _3DScene { +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW + struct GCodePreviewData + { + enum EType + { + Extrusion, + Travel, + Retraction, + Unretraction, + Num_Geometry_Types + }; + + struct FirstVolume + { + EType type; + unsigned int flag; + unsigned int id; + + FirstVolume(EType type, unsigned int flag, unsigned int id); + }; + + std::vector<FirstVolume> first_volumes; + + void reset(); + }; + + static GCodePreviewData s_gcode_preview_data; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ public: static void _glew_init(); @@ -380,10 +422,16 @@ public: //############################################################################################################ #if ENRICO_GCODE_PREVIEW private: + // generates gcode extrusion paths geometry static void _load_gcode_extrusion_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); + // generates gcode travel paths geometry static void _load_gcode_travel_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); + // generates gcode retractions geometry static void _load_gcode_retractions(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); + // generates gcode unretractions geometry static void _load_gcode_unretractions(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); + // sets gcode geometry visibility according to user selection + static void _update_gcode_volumes_visibility(const Print& print, GLVolumeCollection& volumes); #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ }; From 473bd024fed525aa048aee789cdf8d49f0a33d31 Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Fri, 12 Jan 2018 08:55:55 +0100 Subject: [PATCH 05/23] removed debug code --- xs/src/slic3r/GUI/3DScene.cpp | 65 ++++------------------------------- xs/src/slic3r/GUI/3DScene.hpp | 8 ++--- 2 files changed, 10 insertions(+), 63 deletions(-) diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index f79d210a4..60e3ac722 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -12,10 +12,6 @@ #include "GCode/Analyzer.hpp" #endif // ENRICO_GCODE_PREVIEW -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -#include "enrico/wintimer.h" -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -208,12 +204,12 @@ void GLVolume::set_range(double min_z, double max_z) void GLVolume::render() const { -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +//############################################################################################################ #if ENRICO_GCODE_PREVIEW if (!is_active) return; #endif // ENRICO_GCODE_PREVIEW -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +//############################################################################################################ glCullFace(GL_BACK); glPushMatrix(); @@ -345,12 +341,12 @@ void GLVolumeCollection::render_VBOs() const GLint color_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "uniform_color") : -1; for (GLVolume *volume : this->volumes) { -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +//############################################################################################################ #if ENRICO_GCODE_PREVIEW if (!volume->is_active) continue; #endif // ENRICO_GCODE_PREVIEW -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +//############################################################################################################ if (!volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id) continue; GLsizei n_triangles = GLsizei(std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first)); @@ -389,12 +385,12 @@ void GLVolumeCollection::render_legacy() const for (GLVolume *volume : this->volumes) { assert(! volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +//############################################################################################################ #if ENRICO_GCODE_PREVIEW if (!volume->is_active) continue; #endif // ENRICO_GCODE_PREVIEW -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +//############################################################################################################ GLsizei n_triangles = GLsizei(std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first)); GLsizei n_quads = GLsizei(std::min(volume->indexed_vertex_array.quad_indices_size, volume->qverts_range.second - volume->qverts_range.first)); if (n_triangles + n_quads == 0) @@ -1141,13 +1137,6 @@ static inline std::vector<float> parse_colors(const std::vector<std::string> &sc #if ENRICO_GCODE_PREVIEW void _3DScene::load_gcode_preview(const Print* print, GLVolumeCollection* volumes, bool use_VBOs) { -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - WinTimer timer; - timer.Start(); - - std::cout << "#############################################################################" << std::endl; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - if (volumes->empty()) { s_gcode_preview_data.reset(); @@ -1159,12 +1148,6 @@ void _3DScene::load_gcode_preview(const Print* print, GLVolumeCollection* volume } _update_gcode_volumes_visibility(*print, *volumes); - -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - std::cout << "VOLUMES COUNT = " << volumes->volumes.size() << std::endl; - std::cout << "FIRST VOLUMES COUNT = " << s_gcode_preview_data.first_volumes.size() << std::endl; - std::cout << "load_gcode_preview() = " << timer.GetElapsedTimeMillisec() << " ms" << std::endl; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ @@ -1530,11 +1513,6 @@ void _3DScene::_load_wipe_tower_toolpaths( #if ENRICO_GCODE_PREVIEW void _3DScene::_load_gcode_extrusion_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) { -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - WinTimer timer; - timer.Start(); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - // helper functions to select data in dependence of the extrusion view type struct Helper { @@ -1678,19 +1656,10 @@ void _3DScene::_load_gcode_extrusion_paths(const Print& print, GLVolumeCollectio volume->indexed_vertex_array.finalize_geometry(use_VBOs); } } - -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - std::cout << "_load_gcode_extrusion_paths() = " << timer.GetElapsedTimeMillisec() << " ms" << std::endl; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } void _3DScene::_load_gcode_travel_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) { -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - WinTimer timer; - timer.Start(); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - // Helper structure for types struct Type { @@ -1777,19 +1746,10 @@ void _3DScene::_load_gcode_travel_paths(const Print& print, GLVolumeCollection& volume->indexed_vertex_array.finalize_geometry(use_VBOs); } } - -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - std::cout << "_load_gcode_travel_paths() = " << timer.GetElapsedTimeMillisec() << " ms" << std::endl; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } void _3DScene::_load_gcode_retractions(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) { -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - WinTimer timer; - timer.Start(); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - s_gcode_preview_data.first_volumes.emplace_back(GCodePreviewData::Retraction, 0, (unsigned int)volumes.volumes.size()); // nothing to render, return @@ -1814,19 +1774,10 @@ void _3DScene::_load_gcode_retractions(const Print& print, GLVolumeCollection& v volume->bounding_box = volume->indexed_vertex_array.bounding_box(); volume->indexed_vertex_array.finalize_geometry(use_VBOs); } - -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - std::cout << "_load_gcode_retractions() = " << timer.GetElapsedTimeMillisec() << " ms" << std::endl; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } void _3DScene::_load_gcode_unretractions(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) { -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - WinTimer timer; - timer.Start(); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - s_gcode_preview_data.first_volumes.emplace_back(GCodePreviewData::Unretraction, 0, (unsigned int)volumes.volumes.size()); // nothing to render, return @@ -1851,10 +1802,6 @@ void _3DScene::_load_gcode_unretractions(const Print& print, GLVolumeCollection& volume->bounding_box = volume->indexed_vertex_array.bounding_box(); volume->indexed_vertex_array.finalize_geometry(use_VBOs); } - -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - std::cout << "_load_gcode_unretractions() = " << timer.GetElapsedTimeMillisec() << " ms" << std::endl; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } void _3DScene::_update_gcode_volumes_visibility(const Print& print, GLVolumeCollection& volumes) diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index ba8a6a977..8e16136d5 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -215,11 +215,11 @@ public: select_group_id(-1), drag_group_id(-1), selected(false), -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +//############################################################################################################ #if ENRICO_GCODE_PREVIEW is_active(true), #endif // ENRICO_GCODE_PREVIEW -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +//############################################################################################################ hover(false), tverts_range(0, size_t(-1)), qverts_range(0, size_t(-1)) @@ -256,12 +256,12 @@ public: int drag_group_id; // Is this object selected? bool selected; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +//############################################################################################################ #if ENRICO_GCODE_PREVIEW // Whether or not this volume is active for rendering bool is_active; #endif // ENRICO_GCODE_PREVIEW -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +//############################################################################################################ // Boolean: Is mouse over this object? bool hover; From f62c66f460f24d85054e3aff420333ea0dc56b0a Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Fri, 12 Jan 2018 10:26:01 +0100 Subject: [PATCH 06/23] merge with master --- xs/src/libslic3r/GCode/Analyzer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xs/src/libslic3r/GCode/Analyzer.hpp b/xs/src/libslic3r/GCode/Analyzer.hpp index 567892b8e..2f5dafb3c 100644 --- a/xs/src/libslic3r/GCode/Analyzer.hpp +++ b/xs/src/libslic3r/GCode/Analyzer.hpp @@ -303,7 +303,7 @@ public: static const unsigned int Num_Extrusion_Roles = (unsigned int)erMixed + 1; static const Color Default_Extrusion_Role_Colors[Num_Extrusion_Roles]; - static const EViewType Default_View_Type; + static const EViewType Default_View_Type; struct Ranges { From cc1aaceea6ade49413df01d3dee42ff8c56b2441 Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Fri, 12 Jan 2018 11:09:53 +0100 Subject: [PATCH 07/23] fixed compile on linux and osx --- xs/src/libslic3r/BoundingBox.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xs/src/libslic3r/BoundingBox.hpp b/xs/src/libslic3r/BoundingBox.hpp index f1782805b..1a15315fb 100644 --- a/xs/src/libslic3r/BoundingBox.hpp +++ b/xs/src/libslic3r/BoundingBox.hpp @@ -30,7 +30,7 @@ public: if (points.empty()) CONFESS("Empty point set supplied to BoundingBoxBase constructor"); - std::vector<PointClass>::const_iterator it = points.begin(); + typename std::vector<PointClass>::const_iterator it = points.begin(); this->min.x = this->max.x = it->x; this->min.y = this->max.y = it->y; for (++it; it != points.end(); ++it) @@ -86,7 +86,7 @@ public: if (points.empty()) CONFESS("Empty point set supplied to BoundingBox3Base constructor"); - std::vector<PointClass>::const_iterator it = points.begin(); + typename std::vector<PointClass>::const_iterator it = points.begin(); this->min.z = this->max.z = it->z; for (++it; it != points.end(); ++it) { From 9e0dd2a96a12bb187767a702145c776ab5ea9d19 Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Fri, 12 Jan 2018 11:42:50 +0100 Subject: [PATCH 08/23] fix-attempt to build on linux and osx --- xs/src/libslic3r/GCode/Analyzer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp index 07f047923..5372ff302 100644 --- a/xs/src/libslic3r/GCode/Analyzer.cpp +++ b/xs/src/libslic3r/GCode/Analyzer.cpp @@ -498,7 +498,7 @@ const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::Range::get_ const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::Range::get_color_at(float value) const { - return empty() ? get_color_at_max() : colors[clamp((unsigned int)0, Colors_Count - 1, unsigned int((value - min) / _step()))]; + return empty() ? get_color_at_max() : colors[clamp((unsigned int)0, Colors_Count - 1, (unsigned int)((value - min) / _step()))]; } float GCodeAnalyzer::PreviewData::Range::_step() const @@ -910,7 +910,7 @@ void GCodeAnalyzer::_processT(const GCodeReader::GCodeLine& line) { int id = (int)::strtol(cmd.substr(1).c_str(), nullptr, 10); // todo - add id validity check ? - if (_get_extruder_id() != id) + if (_get_extruder_id() != (unsigned int)id) { _set_extruder_id(id); From c63e6b74fa15d69bb0ca9ab5b62f8cfd3129d616 Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Tue, 16 Jan 2018 14:59:06 +0100 Subject: [PATCH 09/23] GCode Preview - Added legend texture --- lib/Slic3r/GUI/3DScene.pm | 119 ++++++++++++++- lib/Slic3r/GUI/Plater.pm | 13 +- xs/src/libslic3r/GCode/Analyzer.cpp | 112 +++++++++++++- xs/src/libslic3r/GCode/Analyzer.hpp | 29 +++- xs/src/slic3r/GUI/3DScene.cpp | 224 ++++++++++++++++++++++++++++ xs/src/slic3r/GUI/3DScene.hpp | 43 ++++++ xs/xsp/GUI_3DScene.xsp | 21 +++ 7 files changed, 548 insertions(+), 13 deletions(-) diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index f97586073..ddd18f88d 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -30,6 +30,7 @@ use Slic3r::Geometry qw(PI); # _dirty: boolean flag indicating, that the screen has to be redrawn on EVT_IDLE. # volumes: reference to vector of Slic3r::GUI::3DScene::Volume. # _camera_type: 'perspective' or 'ortho' +# ===================== ENRICO_GCODE_PREVIEW ================================================== __PACKAGE__->mk_accessors( qw(_quat _dirty init enable_picking enable_moving @@ -66,7 +67,50 @@ __PACKAGE__->mk_accessors( qw(_quat _dirty init _camera_target _camera_distance _zoom + + _legend_enabled + ) ); + +#__PACKAGE__->mk_accessors( qw(_quat _dirty init +# enable_picking +# enable_moving +# use_plain_shader +# on_viewport_changed +# on_hover +# on_select +# on_double_click +# on_right_click +# on_move +# on_model_update +# volumes +# _sphi _stheta +# cutting_plane_z +# cut_lines_vertices +# bed_shape +# bed_triangles +# bed_grid_lines +# bed_polygon +# background +# origin +# _mouse_pos +# _hover_volume_idx +# +# _drag_volume_idx +# _drag_start_pos +# _drag_volume_center_offset +# _drag_start_xy +# _dragged +# +# _layer_height_edited +# +# _camera_type +# _camera_target +# _camera_distance +# _zoom +# +# ) ); +# ===================== ENRICO_GCODE_PREVIEW ================================================== use constant TRACKBALLSIZE => 0.8; use constant TURNTABLE_MODE => 1; @@ -137,6 +181,9 @@ sub new { $self->_stheta(45); $self->_sphi(45); $self->_zoom(1); +# ===================== ENRICO_GCODE_PREVIEW ================================================== + $self->_legend_enabled(0); +# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->use_plain_shader(0); # Collection of GLVolume objects @@ -209,6 +256,13 @@ sub new { return $self; } +# ===================== ENRICO_GCODE_PREVIEW ================================================== +sub set_legend_enabled { + my ($self, $value) = @_; + $self->_legend_enabled($value); +} +# ===================== ENRICO_GCODE_PREVIEW ================================================== + sub Destroy { my ($self) = @_; $self->{layer_height_edit_timer}->Stop; @@ -1316,6 +1370,11 @@ sub Render { glDisable(GL_BLEND); } +# ===================== ENRICO_GCODE_PREVIEW ================================================== + # draw gcode preview legend + $self->draw_legend; +# ===================== ENRICO_GCODE_PREVIEW ================================================== + $self->draw_active_object_annotations; $self->SwapBuffers(); @@ -1449,12 +1508,38 @@ sub _variable_layer_thickness_load_reset_image { # Paint the tooltip. sub _render_image { my ($self, $image, $l, $r, $b, $t) = @_; +# ===================== ENRICO_GCODE_PREVIEW ================================================== + $self->_render_texture($image->{texture_id}, $l, $r, $b, $t); + +# glColor4f(1.,1.,1.,1.); +# glDisable(GL_LIGHTING); +# glEnable(GL_BLEND); +# glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +# glEnable(GL_TEXTURE_2D); +# glBindTexture(GL_TEXTURE_2D, $image->{texture_id}); +# glBegin(GL_QUADS); +# glTexCoord2d(0.,1.); glVertex3f($l, $b, 0); +# glTexCoord2d(1.,1.); glVertex3f($r, $b, 0); +# glTexCoord2d(1.,0.); glVertex3f($r, $t, 0); +# glTexCoord2d(0.,0.); glVertex3f($l, $t, 0); +# glEnd(); +# glBindTexture(GL_TEXTURE_2D, 0); +# glDisable(GL_TEXTURE_2D); +# glDisable(GL_BLEND); +# glEnable(GL_LIGHTING); +# ===================== ENRICO_GCODE_PREVIEW ================================================== +} + +# ===================== ENRICO_GCODE_PREVIEW ================================================== +sub _render_texture { + my ($self, $tex_id, $l, $r, $b, $t) = @_; + glColor4f(1.,1.,1.,1.); glDisable(GL_LIGHTING); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, $image->{texture_id}); + glBindTexture(GL_TEXTURE_2D, $tex_id); glBegin(GL_QUADS); glTexCoord2d(0.,1.); glVertex3f($l, $b, 0); glTexCoord2d(1.,1.); glVertex3f($r, $b, 0); @@ -1466,6 +1551,7 @@ sub _render_image { glDisable(GL_BLEND); glEnable(GL_LIGHTING); } +# ===================== ENRICO_GCODE_PREVIEW ================================================== sub draw_active_object_annotations { # $fakecolor is a boolean indicating, that the objects shall be rendered in a color coding the object index for picking. @@ -1579,6 +1665,37 @@ sub draw_active_object_annotations { glEnable(GL_DEPTH_TEST); } +# ===================== ENRICO_GCODE_PREVIEW ================================================== +sub draw_legend { + my ($self) = @_; + + if ($self->_legend_enabled) + { + my $tex_id = Slic3r::GUI::_3DScene::get_legend_texture_id; + if ($tex_id > 0) + { + glDisable(GL_DEPTH_TEST); + glPushMatrix(); + glLoadIdentity(); + + my $tex_w = Slic3r::GUI::_3DScene::get_legend_texture_width; + my $tex_h = Slic3r::GUI::_3DScene::get_legend_texture_height; + + my ($cw, $ch) = $self->GetSizeWH; + + my $l = (-0.5 * $cw) / $self->_zoom; + my $t = (0.5 * $ch) / $self->_zoom; + my $r = $l + $tex_w / $self->_zoom; + my $b = $t - $tex_h / $self->_zoom; + $self->_render_texture($tex_id, $l, $r, $b, $t); + + glPopMatrix(); + glEnable(GL_DEPTH_TEST); + } + } +} +# ===================== ENRICO_GCODE_PREVIEW ================================================== + sub opengl_info { my ($self, %params) = @_; diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 63e628f3e..d7afe0e30 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -153,8 +153,17 @@ sub new { EVT_NOTEBOOK_PAGE_CHANGED($self, $self->{preview_notebook}, sub { my $preview = $self->{preview_notebook}->GetCurrentPage; - $self->{preview3D}->load_print(1) if ($preview == $self->{preview3D}); - $preview->OnActivate if $preview->can('OnActivate'); +# ===================== ENRICO_GCODE_PREVIEW ================================================== + if ($preview == $self->{preview3D}) + { + $self->{preview3D}->canvas->set_legend_enabled(1); + $self->{preview3D}->load_print(1); + } else { + $self->{preview3D}->canvas->set_legend_enabled(0); + } +# $self->{preview3D}->load_print(1) if ($preview == $self->{preview3D}); +# ===================== ENRICO_GCODE_PREVIEW ================================================== + $preview->OnActivate if $preview->can('OnActivate'); }); # toolbar for object manipulation diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp index 5372ff302..ae857e37e 100644 --- a/xs/src/libslic3r/GCode/Analyzer.cpp +++ b/xs/src/libslic3r/GCode/Analyzer.cpp @@ -436,6 +436,16 @@ GCodeAnalyzer::PreviewData::Color::Color(float r, float g, float b, float a) rgba[3] = a; } +std::vector<unsigned char> GCodeAnalyzer::PreviewData::Color::as_bytes() const +{ + std::vector<unsigned char> ret; + for (unsigned int i = 0; i < 4; ++i) + { + ret.push_back((unsigned char)(255.0f * rgba[i])); + } + return ret; +} + GCodeAnalyzer::PreviewData::Extrusion::Layer::Layer(float z, const ExtrusionPaths& paths) : z(z) , paths(paths) @@ -491,6 +501,11 @@ void GCodeAnalyzer::PreviewData::Range::set_from(const Range& other) max = other.max; } +float GCodeAnalyzer::PreviewData::Range::step_size() const +{ + return (max - min) / (float)Colors_Count; +} + const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::Range::get_color_at_max() const { return colors[Colors_Count - 1]; @@ -498,12 +513,13 @@ const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::Range::get_ const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::Range::get_color_at(float value) const { - return empty() ? get_color_at_max() : colors[clamp((unsigned int)0, Colors_Count - 1, (unsigned int)((value - min) / _step()))]; + return empty() ? get_color_at_max() : colors[clamp((unsigned int)0, Colors_Count - 1, (unsigned int)((value - min) / step_size()))]; } -float GCodeAnalyzer::PreviewData::Range::_step() const +GCodeAnalyzer::PreviewData::LegendItem::LegendItem(const std::string& text, const GCodeAnalyzer::PreviewData::Color& color) + : text(text) + , color(color) { - return (max - min) / (float)Colors_Count; } const GCodeAnalyzer::PreviewData::Color GCodeAnalyzer::PreviewData::Extrusion::Default_Extrusion_Role_Colors[Num_Extrusion_Roles] = @@ -523,6 +539,23 @@ const GCodeAnalyzer::PreviewData::Color GCodeAnalyzer::PreviewData::Extrusion::D Color(0.0f, 0.0f, 0.0f, 1.0f) // erMixed }; +const std::string GCodeAnalyzer::PreviewData::Extrusion::Default_Extrusion_Role_Names[Num_Extrusion_Roles] +{ + "None", + "Perimeter", + "External perimeter", + "Overhang perimeter", + "Internal infill", + "Solid infill", + "Top solid infill", + "Bridge infill", + "Gap fill", + "Skirt", + "Support material", + "Support material interface", + "Mixed" +}; + const GCodeAnalyzer::PreviewData::Extrusion::EViewType GCodeAnalyzer::PreviewData::Extrusion::Default_View_Type = GCodeAnalyzer::PreviewData::Extrusion::FeatureType; void GCodeAnalyzer::PreviewData::Extrusion::set_default() @@ -534,6 +567,11 @@ void GCodeAnalyzer::PreviewData::Extrusion::set_default() ::memcpy((void*)ranges.width.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color)); ::memcpy((void*)ranges.feedrate.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color)); + for (unsigned int i = 0; i < Num_Extrusion_Roles; ++i) + { + role_names[i] = Default_Extrusion_Role_Names[i]; + } + role_flags = 0; for (unsigned int i = 0; i < Num_Extrusion_Roles; ++i) { @@ -628,6 +666,74 @@ const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::get_extrusi return extrusion.ranges.feedrate.get_color_at(feedrate); } +std::string GCodeAnalyzer::PreviewData::get_legend_title() const +{ + switch (extrusion.view_type) + { + case Extrusion::FeatureType: + return "Feature type"; + case Extrusion::Height: + return "Height (mm)"; + case Extrusion::Width: + return "Width (mm)"; + case Extrusion::Feedrate: + return "Speed (mm/min)"; + } + + return ""; +} + +GCodeAnalyzer::PreviewData::LegendItemsList GCodeAnalyzer::PreviewData::get_legend_items() const +{ + struct Helper + { + static void FillListFromRange(LegendItemsList& list, const Range& range, unsigned int decimals, float scale_factor) + { + list.reserve(Range::Colors_Count); + float step = range.step_size(); + for (unsigned int i = 0; i < Range::Colors_Count; ++i) + { + char buf[32]; + sprintf(buf, "%.*f/%.*f", decimals, scale_factor * (range.min + (float)i * step), decimals, scale_factor * (range.min + (float)(i + 1) * step)); + list.emplace_back(buf, range.colors[i]); + } + } + }; + + LegendItemsList items; + + switch (extrusion.view_type) + { + case Extrusion::FeatureType: + { + items.reserve(erMixed - erPerimeter + 1); + for (unsigned int i = (unsigned int)erPerimeter; i < (unsigned int)erMixed; ++i) + { + items.emplace_back(extrusion.role_names[i], extrusion.role_colors[i]); + } + + break; + } + case Extrusion::Height: + { + Helper::FillListFromRange(items, extrusion.ranges.height, 3, 1.0f); + break; + } + case Extrusion::Width: + { + Helper::FillListFromRange(items, extrusion.ranges.width, 3, 1.0f); + break; + } + case Extrusion::Feedrate: + { + Helper::FillListFromRange(items, extrusion.ranges.feedrate, 0, 60.0f); + break; + } + } + + return items; +} + GCodeAnalyzer::GCodeAnalyzer() { reset(); diff --git a/xs/src/libslic3r/GCode/Analyzer.hpp b/xs/src/libslic3r/GCode/Analyzer.hpp index 2f5dafb3c..26c525b4c 100644 --- a/xs/src/libslic3r/GCode/Analyzer.hpp +++ b/xs/src/libslic3r/GCode/Analyzer.hpp @@ -206,9 +206,9 @@ public: ExtrusionRole extrusion_role; unsigned int extruder_id; double mm3_per_mm; - float width; - float height; - float feedrate; + float width; // mm + float height; // mm + float feedrate; // mm/s Metadata(); Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate); @@ -264,6 +264,8 @@ public: Color(); Color(float r, float g, float b, float a); + std::vector<unsigned char> as_bytes() const; + static const Color Dummy; }; @@ -282,14 +284,22 @@ public: bool empty() const; void update_from(float value); void set_from(const Range& other); + float step_size() const; const Color& get_color_at(float value) const; const Color& get_color_at_max() const; - - private: - float _step() const; }; + struct LegendItem + { + std::string text; + Color color; + + LegendItem(const std::string& text, const Color& color); + }; + + typedef std::vector<LegendItem> LegendItemsList; + struct Extrusion { enum EViewType : unsigned char @@ -303,7 +313,8 @@ public: static const unsigned int Num_Extrusion_Roles = (unsigned int)erMixed + 1; static const Color Default_Extrusion_Role_Colors[Num_Extrusion_Roles]; - static const EViewType Default_View_Type; + static const std::string Default_Extrusion_Role_Names[Num_Extrusion_Roles]; + static const EViewType Default_View_Type; struct Ranges { @@ -324,6 +335,7 @@ public: EViewType view_type; Color role_colors[Num_Extrusion_Roles]; + std::string role_names[Num_Extrusion_Roles]; Ranges ranges; LayersList layers; unsigned int role_flags; @@ -411,6 +423,9 @@ public: const Color& get_extrusion_height_color(float height) const; const Color& get_extrusion_width_color(float width) const; const Color& get_extrusion_feedrate_color(float feedrate) const; + + std::string get_legend_title() const; + LegendItemsList get_legend_items() const; }; private: diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 60e3ac722..676d75c2f 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -8,9 +8,11 @@ #include "../../libslic3r/Geometry.hpp" #include "../../libslic3r/Print.hpp" #include "../../libslic3r/Slicing.hpp" +//############################################################################################################ #if ENRICO_GCODE_PREVIEW #include "GCode/Analyzer.hpp" #endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ #include <stdio.h> #include <stdlib.h> @@ -23,6 +25,15 @@ #include <tbb/parallel_for.h> #include <tbb/spin_mutex.h> +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +#include <wx/bitmap.h> +#include <wx/dcmemory.h> +#include <wx/image.h> +#include <wx/settings.h> +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + namespace Slic3r { void GLIndexedVertexArray::load_mesh_flat_shading(const TriangleMesh &mesh) @@ -1098,6 +1109,197 @@ void _3DScene::GCodePreviewData::reset() } _3DScene::GCodePreviewData _3DScene::s_gcode_preview_data; +_3DScene::LegendTexture _3DScene::s_legend_texture; + +const unsigned char _3DScene::LegendTexture::Squares_Border_Color[3] = { 64, 64, 64 }; +const unsigned char _3DScene::LegendTexture::Background_Color[3] = { 9, 91, 134 }; +const unsigned char _3DScene::LegendTexture::Opacity = 255; + +_3DScene::LegendTexture::LegendTexture() + : m_tex_id(0) + , m_tex_width(0) + , m_tex_height(0) +{ +} + +_3DScene::LegendTexture::~LegendTexture() +{ + _destroy_texture(); +} + +bool _3DScene::LegendTexture::generate_texture(const Print& print) +{ + _destroy_texture(); + + // collects items to render + const std::string& title = print.gcode_preview.get_legend_title(); + const GCodeAnalyzer::PreviewData::LegendItemsList& items = print.gcode_preview.get_legend_items(); + + unsigned int items_count = (unsigned int)items.size(); + if (items_count == 0) + // nothing to render, return + return false; + + wxMemoryDC memDC; + // select default font + memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + + // calculates texture size + wxCoord w, h; + memDC.GetTextExtent(title, &w, &h); + unsigned int title_width = (unsigned int)w; + unsigned int title_height = (unsigned int)h; + + unsigned int max_text_width = 0; + unsigned int max_text_height = 0; + for (const GCodeAnalyzer::PreviewData::LegendItem& item : items) + { + memDC.GetTextExtent(item.text, &w, &h); + max_text_width = std::max(max_text_width, (unsigned int)w); + max_text_height = std::max(max_text_height, (unsigned int)h); + } + + m_tex_width = std::max(2 * Px_Border + title_width, 2 * (Px_Border + Px_Square_Contour) + Px_Square + Px_Text_Offset + max_text_width); + m_tex_height = 2 * (Px_Border + Px_Square_Contour) + title_height + Px_Title_Offset + items_count * Px_Square; + if (items_count > 1) + m_tex_height += (items_count - 1) * Px_Square_Contour; + + // generates bitmap + wxBitmap bitmap(m_tex_width, m_tex_height); + +#if defined(__APPLE__) || defined(_MSC_VER) + bitmap.UseAlpha(); +#endif + + memDC.SelectObject(bitmap); + memDC.SetBackground(wxBrush(wxColour(Background_Color[0], Background_Color[1], Background_Color[2]))); + memDC.Clear(); + + memDC.SetTextForeground(*wxWHITE); + + // draw title + unsigned int title_x = Px_Border; + unsigned int title_y = Px_Border; + memDC.DrawText(title, title_x, title_y); + + // draw icons contours as background + unsigned int squares_contour_x = Px_Border; + unsigned int squares_contour_y = Px_Border + title_height + Px_Title_Offset; + unsigned int squares_contour_width = Px_Square + 2 * Px_Square_Contour; + unsigned int squares_contour_height = items_count * Px_Square + 2 * Px_Square_Contour; + if (items_count > 1) + squares_contour_height += (items_count - 1) * Px_Square_Contour; + + wxColour color(Squares_Border_Color[0], Squares_Border_Color[1], Squares_Border_Color[2]); + wxPen pen(color); + wxBrush brush(color); + memDC.SetPen(pen); + memDC.SetBrush(brush); + memDC.DrawRectangle(wxRect(squares_contour_x, squares_contour_y, squares_contour_width, squares_contour_height)); + + // draw items (colored icon + text) + unsigned int icon_x = squares_contour_x + Px_Square_Contour; + unsigned int icon_x_inner = icon_x + 1; + unsigned int icon_y = squares_contour_y + Px_Square_Contour; + unsigned int icon_y_step = Px_Square + Px_Square_Contour; + + unsigned int text_x = icon_x + Px_Square + Px_Text_Offset; + unsigned int text_y_offset = (Px_Square - max_text_height) / 2; + + unsigned int px_inner_square = Px_Square - 2; + + for (const GCodeAnalyzer::PreviewData::LegendItem& item : items) + { + // draw darker icon perimeter + const std::vector<unsigned char>& item_color_bytes = item.color.as_bytes(); + wxImage::HSVValue dark_hsv = wxImage::RGBtoHSV(wxImage::RGBValue(item_color_bytes[0], item_color_bytes[1], item_color_bytes[2])); + dark_hsv.value *= 0.75; + wxImage::RGBValue dark_rgb = wxImage::HSVtoRGB(dark_hsv); + color.Set(dark_rgb.red, dark_rgb.green, dark_rgb.blue, item_color_bytes[3]); + pen.SetColour(color); + brush.SetColour(color); + memDC.SetPen(pen); + memDC.SetBrush(brush); + memDC.DrawRectangle(wxRect(icon_x, icon_y, Px_Square, Px_Square)); + + // draw icon interior + color.Set(item_color_bytes[0], item_color_bytes[1], item_color_bytes[2], item_color_bytes[3]); + pen.SetColour(color); + brush.SetColour(color); + memDC.SetPen(pen); + memDC.SetBrush(brush); + memDC.DrawRectangle(wxRect(icon_x_inner, icon_y + 1, px_inner_square, px_inner_square)); + + // draw text + memDC.DrawText(item.text, text_x, icon_y + text_y_offset); + + // update y + icon_y += icon_y_step; + } + + memDC.SelectObject(wxNullBitmap); + + return _create_texture(print, bitmap); +} + +unsigned int _3DScene::LegendTexture::get_texture_id() const +{ + return m_tex_id; +} + +unsigned int _3DScene::LegendTexture::get_texture_width() const +{ + return m_tex_width; +} + +unsigned int _3DScene::LegendTexture::get_texture_height() const +{ + return m_tex_height; +} + +bool _3DScene::LegendTexture::_create_texture(const Print& print, const wxBitmap& bitmap) +{ + if ((m_tex_width == 0) || (m_tex_height == 0)) + return false; + + wxImage image = bitmap.ConvertToImage(); + image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]); + + // prepare buffer + std::vector<unsigned char> buffer(4 * m_tex_width * m_tex_height, 0); + for (unsigned int h = 0; h < m_tex_height; ++h) + { + unsigned int hh = h * m_tex_width; + for (unsigned int w = 0; w < m_tex_width; ++w) + { + unsigned char* px_ptr = buffer.data() + 4 * (hh + w); + *px_ptr++ = image.GetRed(w, h); + *px_ptr++ = image.GetGreen(w, h); + *px_ptr++ = image.GetBlue(w, h); + *px_ptr++ = image.IsTransparent(w, h) ? 0 : Opacity; + } + } + + // sends buffer to gpu + ::glGenTextures(1, &m_tex_id); + ::glBindTexture(GL_TEXTURE_2D, m_tex_id); + ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)buffer.data()); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); + ::glBindTexture(GL_TEXTURE_2D, 0); + + return true; +} + +void _3DScene::LegendTexture::_destroy_texture() +{ + if (m_tex_id > 0) + { + ::glDeleteTextures(1, &m_tex_id); + m_tex_id = 0; + } +} #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ @@ -1145,10 +1347,27 @@ void _3DScene::load_gcode_preview(const Print* print, GLVolumeCollection* volume _load_gcode_travel_paths(*print, *volumes, use_VBOs); _load_gcode_retractions(*print, *volumes, use_VBOs); _load_gcode_unretractions(*print, *volumes, use_VBOs); + + _generate_legend_texture(*print); } _update_gcode_volumes_visibility(*print, *volumes); } + +unsigned int _3DScene::get_legend_texture_id() +{ + return s_legend_texture.get_texture_id(); +} + +unsigned int _3DScene::get_legend_texture_width() +{ + return s_legend_texture.get_texture_width(); +} + +unsigned int _3DScene::get_legend_texture_height() +{ + return s_legend_texture.get_texture_height(); +} #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ @@ -1847,6 +2066,11 @@ void _3DScene::_update_gcode_volumes_visibility(const Print& print, GLVolumeColl } } } + +void _3DScene::_generate_legend_texture(const Print& print) +{ + s_legend_texture.generate_texture(print); +} #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 8e16136d5..f869304aa 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -7,6 +7,12 @@ #include "../../libslic3r/TriangleMesh.hpp" #include "../../libslic3r/Utils.hpp" +//############################################################################################################ +#if ENRICO_GCODE_PREVIEW +class wxBitmap; +#endif // ENRICO_GCODE_PREVIEW +//############################################################################################################ + namespace Slic3r { class Print; @@ -389,6 +395,38 @@ class _3DScene }; static GCodePreviewData s_gcode_preview_data; + + class LegendTexture + { + static const unsigned int Px_Title_Offset = 5; + static const unsigned int Px_Text_Offset = 5; + static const unsigned int Px_Square = 20; + static const unsigned int Px_Square_Contour = 1; + static const unsigned int Px_Border = Px_Square / 2; + static const unsigned char Squares_Border_Color[3]; + static const unsigned char Background_Color[3]; + static const unsigned char Opacity; + + unsigned int m_tex_id; + unsigned int m_tex_width; + unsigned int m_tex_height; + + public: + LegendTexture(); + ~LegendTexture(); + + bool generate_texture(const Print& print); + + unsigned int get_texture_id() const; + unsigned int get_texture_width() const; + unsigned int get_texture_height() const; + + private: + bool _create_texture(const Print& print, const wxBitmap& bitmap); + void _destroy_texture(); + }; + + static LegendTexture s_legend_texture; #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ public: @@ -397,6 +435,9 @@ public: //############################################################################################################ #if ENRICO_GCODE_PREVIEW static void load_gcode_preview(const Print* print, GLVolumeCollection* volumes, bool use_VBOs); + static unsigned int get_legend_texture_id(); + static unsigned int get_legend_texture_width(); + static unsigned int get_legend_texture_height(); #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ @@ -432,6 +473,8 @@ private: static void _load_gcode_unretractions(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); // sets gcode geometry visibility according to user selection static void _update_gcode_volumes_visibility(const Print& print, GLVolumeCollection& volumes); + // generates the legend texture in dependence of the current shown view type + static void _generate_legend_texture(const Print& print); #endif // ENRICO_GCODE_PREVIEW //############################################################################################################ }; diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 186511cc4..f6d729f98 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -141,6 +141,27 @@ _glew_init() CODE: _3DScene::_glew_init(); +unsigned int +get_legend_texture_id() + CODE: + RETVAL = _3DScene::get_legend_texture_id(); + OUTPUT: + RETVAL + +unsigned int +get_legend_texture_width() + CODE: + RETVAL = _3DScene::get_legend_texture_width(); + OUTPUT: + RETVAL + +unsigned int +get_legend_texture_height() + CODE: + RETVAL = _3DScene::get_legend_texture_height(); + OUTPUT: + RETVAL + void _load_print_toolpaths(print, volumes, tool_colors, use_VBOs) Print *print; From a417cf955d1300558f8bfa231984656f69a6d52d Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Wed, 17 Jan 2018 10:39:05 +0100 Subject: [PATCH 10/23] GCode Preview - Code cleanup --- lib/Slic3r/GUI/3DScene.pm | 72 ------ lib/Slic3r/GUI/Plater.pm | 10 +- lib/Slic3r/GUI/Plater/3DPreview.pm | 32 +-- lib/Slic3r/GUI/Plater/3DToolpaths.pm | 3 +- xs/src/libslic3r/BoundingBox.cpp | 41 ---- xs/src/libslic3r/BoundingBox.hpp | 24 -- xs/src/libslic3r/ExtrusionEntity.hpp | 25 -- xs/src/libslic3r/GCode.cpp | 65 +----- xs/src/libslic3r/GCode.hpp | 47 ---- xs/src/libslic3r/GCode/Analyzer.cpp | 333 +-------------------------- xs/src/libslic3r/GCode/Analyzer.hpp | 161 +------------ xs/src/libslic3r/Line.cpp | 4 - xs/src/libslic3r/Line.hpp | 12 - xs/src/libslic3r/MultiPoint.cpp | 4 - xs/src/libslic3r/MultiPoint.hpp | 8 - xs/src/libslic3r/Point.hpp | 42 ---- xs/src/libslic3r/Polyline.cpp | 4 - xs/src/libslic3r/Polyline.hpp | 4 - xs/src/libslic3r/Print.cpp | 4 - xs/src/libslic3r/Print.hpp | 12 - xs/src/libslic3r/libslic3r.h | 17 -- xs/src/slic3r/GUI/3DScene.cpp | 42 +--- xs/src/slic3r/GUI/3DScene.hpp | 31 +-- xs/xsp/Print.xsp | 2 - 24 files changed, 12 insertions(+), 987 deletions(-) diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index ddd18f88d..daceb8c49 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -30,7 +30,6 @@ use Slic3r::Geometry qw(PI); # _dirty: boolean flag indicating, that the screen has to be redrawn on EVT_IDLE. # volumes: reference to vector of Slic3r::GUI::3DScene::Volume. # _camera_type: 'perspective' or 'ortho' -# ===================== ENRICO_GCODE_PREVIEW ================================================== __PACKAGE__->mk_accessors( qw(_quat _dirty init enable_picking enable_moving @@ -72,46 +71,6 @@ __PACKAGE__->mk_accessors( qw(_quat _dirty init ) ); -#__PACKAGE__->mk_accessors( qw(_quat _dirty init -# enable_picking -# enable_moving -# use_plain_shader -# on_viewport_changed -# on_hover -# on_select -# on_double_click -# on_right_click -# on_move -# on_model_update -# volumes -# _sphi _stheta -# cutting_plane_z -# cut_lines_vertices -# bed_shape -# bed_triangles -# bed_grid_lines -# bed_polygon -# background -# origin -# _mouse_pos -# _hover_volume_idx -# -# _drag_volume_idx -# _drag_start_pos -# _drag_volume_center_offset -# _drag_start_xy -# _dragged -# -# _layer_height_edited -# -# _camera_type -# _camera_target -# _camera_distance -# _zoom -# -# ) ); -# ===================== ENRICO_GCODE_PREVIEW ================================================== - use constant TRACKBALLSIZE => 0.8; use constant TURNTABLE_MODE => 1; use constant GROUND_Z => -0.02; @@ -181,9 +140,7 @@ sub new { $self->_stheta(45); $self->_sphi(45); $self->_zoom(1); -# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->_legend_enabled(0); -# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->use_plain_shader(0); # Collection of GLVolume objects @@ -256,12 +213,10 @@ sub new { return $self; } -# ===================== ENRICO_GCODE_PREVIEW ================================================== sub set_legend_enabled { my ($self, $value) = @_; $self->_legend_enabled($value); } -# ===================== ENRICO_GCODE_PREVIEW ================================================== sub Destroy { my ($self) = @_; @@ -1370,10 +1325,8 @@ sub Render { glDisable(GL_BLEND); } -# ===================== ENRICO_GCODE_PREVIEW ================================================== # draw gcode preview legend $self->draw_legend; -# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->draw_active_object_annotations; @@ -1508,29 +1461,9 @@ sub _variable_layer_thickness_load_reset_image { # Paint the tooltip. sub _render_image { my ($self, $image, $l, $r, $b, $t) = @_; -# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->_render_texture($image->{texture_id}, $l, $r, $b, $t); - -# glColor4f(1.,1.,1.,1.); -# glDisable(GL_LIGHTING); -# glEnable(GL_BLEND); -# glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -# glEnable(GL_TEXTURE_2D); -# glBindTexture(GL_TEXTURE_2D, $image->{texture_id}); -# glBegin(GL_QUADS); -# glTexCoord2d(0.,1.); glVertex3f($l, $b, 0); -# glTexCoord2d(1.,1.); glVertex3f($r, $b, 0); -# glTexCoord2d(1.,0.); glVertex3f($r, $t, 0); -# glTexCoord2d(0.,0.); glVertex3f($l, $t, 0); -# glEnd(); -# glBindTexture(GL_TEXTURE_2D, 0); -# glDisable(GL_TEXTURE_2D); -# glDisable(GL_BLEND); -# glEnable(GL_LIGHTING); -# ===================== ENRICO_GCODE_PREVIEW ================================================== } -# ===================== ENRICO_GCODE_PREVIEW ================================================== sub _render_texture { my ($self, $tex_id, $l, $r, $b, $t) = @_; @@ -1551,7 +1484,6 @@ sub _render_texture { glDisable(GL_BLEND); glEnable(GL_LIGHTING); } -# ===================== ENRICO_GCODE_PREVIEW ================================================== sub draw_active_object_annotations { # $fakecolor is a boolean indicating, that the objects shall be rendered in a color coding the object index for picking. @@ -1665,7 +1597,6 @@ sub draw_active_object_annotations { glEnable(GL_DEPTH_TEST); } -# ===================== ENRICO_GCODE_PREVIEW ================================================== sub draw_legend { my ($self) = @_; @@ -1694,7 +1625,6 @@ sub draw_legend { } } } -# ===================== ENRICO_GCODE_PREVIEW ================================================== sub opengl_info { @@ -2096,14 +2026,12 @@ sub load_wipe_tower_toolpaths { if ($print->step_done(STEP_WIPE_TOWER)); } -# ===================== ENRICO_GCODE_PREVIEW ================================================== sub load_gcode_preview { my ($self, $print) = @_; $self->SetCurrent($self->GetContext) if $self->UseVBOs; Slic3r::GUI::_3DScene::load_gcode_preview($print, $self->volumes, $self->UseVBOs); } -# ===================== ENRICO_GCODE_PREVIEW ================================================== sub set_toolpaths_range { my ($self, $min_z, $max_z) = @_; diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index d7afe0e30..321bb7112 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -153,7 +153,6 @@ sub new { EVT_NOTEBOOK_PAGE_CHANGED($self, $self->{preview_notebook}, sub { my $preview = $self->{preview_notebook}->GetCurrentPage; -# ===================== ENRICO_GCODE_PREVIEW ================================================== if ($preview == $self->{preview3D}) { $self->{preview3D}->canvas->set_legend_enabled(1); @@ -161,8 +160,7 @@ sub new { } else { $self->{preview3D}->canvas->set_legend_enabled(0); } -# $self->{preview3D}->load_print(1) if ($preview == $self->{preview3D}); -# ===================== ENRICO_GCODE_PREVIEW ================================================== + $preview->OnActivate if $preview->can('OnActivate'); }); @@ -785,9 +783,7 @@ sub remove { splice @{$self->{objects}}, $obj_idx, 1; $self->{model}->delete_object($obj_idx); $self->{print}->delete_object($obj_idx); -# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->{print}->clear_gcode_preview_data; -# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->{list}->DeleteItem($obj_idx); $self->object_list_changed; @@ -808,9 +804,7 @@ sub reset { @{$self->{objects}} = (); $self->{model}->clear_objects; $self->{print}->clear_objects; -# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->{print}->clear_gcode_preview_data; -# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->{list}->DeleteAllItems; $self->object_list_changed; @@ -1451,11 +1445,9 @@ sub on_export_completed { # this updates buttons status $self->object_list_changed; -# ===================== ENRICO_GCODE_PREVIEW ================================================== # refresh preview $self->{toolpaths2D}->reload_print if $self->{toolpaths2D}; $self->{preview3D}->reload_print if $self->{preview3D}; -# ===================== ENRICO_GCODE_PREVIEW ================================================== } sub do_print { diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index 0af7a2ebf..379c557b6 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -5,16 +5,10 @@ use utf8; use Slic3r::Print::State ':steps'; use Wx qw(:misc :sizer :slider :statictext :keycode wxWHITE); -# ===================== ENRICO_GCODE_PREVIEW ================================================== use Wx::Event qw(EVT_SLIDER EVT_KEY_DOWN EVT_CHECKBOX EVT_CHOICE EVT_CHECKLISTBOX); -#use Wx::Event qw(EVT_SLIDER EVT_KEY_DOWN EVT_CHECKBOX); -# ===================== ENRICO_GCODE_PREVIEW ================================================== use base qw(Wx::Panel Class::Accessor); -# ===================== ENRICO_GCODE_PREVIEW ================================================== __PACKAGE__->mk_accessors(qw(print enabled _loaded canvas slider_low slider_high single_layer auto_zoom)); -#__PACKAGE__->mk_accessors(qw(print enabled _loaded canvas slider_low slider_high single_layer)); -# ===================== ENRICO_GCODE_PREVIEW ================================================== sub new { my $class = shift; @@ -24,9 +18,7 @@ sub new { $self->{config} = $config; $self->{number_extruders} = 1; $self->{preferred_color_mode} = 'feature'; -# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->auto_zoom(1); -# ===================== ENRICO_GCODE_PREVIEW ================================================== # init GUI elements my $canvas = Slic3r::GUI::3DScene->new($self); @@ -69,7 +61,6 @@ sub new { my $checkbox_singlelayer = $self->{checkbox_singlelayer} = Wx::CheckBox->new($self, -1, "1 Layer"); my $checkbox_color_by_extruder = $self->{checkbox_color_by_extruder} = Wx::CheckBox->new($self, -1, "Tool"); -# ===================== ENRICO_GCODE_PREVIEW ================================================== my $choice_view_type = Wx::Choice->new($self, -1); $choice_view_type->Append("Feature type"); $choice_view_type->Append("Height"); @@ -96,8 +87,7 @@ sub new { my $checkbox_travel = Wx::CheckBox->new($self, -1, "Travel"); my $checkbox_retractions = Wx::CheckBox->new($self, -1, "Retractions"); - my $checkbox_unretractions = Wx::CheckBox->new($self, -1, "Unretractions"); -# ===================== ENRICO_GCODE_PREVIEW ================================================== + my $checkbox_unretractions = Wx::CheckBox->new($self, -1, "Unretractions"); my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL); my $vsizer = Wx::BoxSizer->new(wxVERTICAL); @@ -112,13 +102,11 @@ sub new { $vsizer_outer->Add($hsizer, 3, wxALIGN_CENTER_HORIZONTAL, 0); $vsizer_outer->Add($checkbox_singlelayer, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, 5); $vsizer_outer->Add($checkbox_color_by_extruder, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, 5); -# ===================== ENRICO_GCODE_PREVIEW ================================================== $vsizer_outer->Add($choice_view_type, 0, wxEXPAND | wxALL | wxALIGN_CENTER_HORIZONTAL, 5); $vsizer_outer->Add($checklist_features, 0, wxTOP | wxALL | wxALIGN_CENTER_HORIZONTAL, 5); $vsizer_outer->Add($checkbox_travel, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); $vsizer_outer->Add($checkbox_retractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); $vsizer_outer->Add($checkbox_unretractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); -# ===================== ENRICO_GCODE_PREVIEW ================================================== my $sizer = Wx::BoxSizer->new(wxHORIZONTAL); $sizer->Add($canvas, 1, wxALL | wxEXPAND, 0); @@ -199,7 +187,6 @@ sub new { $self->reload_print; }); -# ===================== ENRICO_GCODE_PREVIEW ================================================== EVT_CHOICE($self, $choice_view_type, sub { my $selection = $choice_view_type->GetCurrentSelection(); $self->print->set_gcode_preview_type($selection); @@ -238,7 +225,6 @@ sub new { $self->refresh_print; $self->auto_zoom(1); }); -# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->SetSizer($sizer); $self->SetMinSize($self->GetSize); @@ -258,16 +244,13 @@ sub reload_print { $self->_loaded(0); if (! $self->IsShown && ! $force) { -# ===================== ENRICO_GCODE_PREVIEW ================================================== # $self->{reload_delayed} = 1; -# ===================== ENRICO_GCODE_PREVIEW ================================================== return; } $self->load_print; } -# ===================== ENRICO_GCODE_PREVIEW ================================================== sub refresh_print { my ($self) = @_; @@ -279,7 +262,6 @@ sub refresh_print { $self->load_print; } -# ===================== ENRICO_GCODE_PREVIEW ================================================== sub load_print { my ($self) = @_; @@ -361,10 +343,9 @@ sub load_print { } if ($self->IsShown) { -# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->canvas->load_gcode_preview($self->print); - # load skirt and brim +# # load skirt and brim # $self->canvas->load_print_toolpaths($self->print, \@colors); # $self->canvas->load_wipe_tower_toolpaths($self->print, \@colors); # @@ -375,15 +356,10 @@ sub load_print { # #my @volume_ids = $self->canvas->load_object($object->model_object); # #$self->canvas->volumes->[$_]->color->[3] = 0.2 for @volume_ids; # } -# ===================== ENRICO_GCODE_PREVIEW ================================================== -# ===================== ENRICO_GCODE_PREVIEW ================================================== if ($self->auto_zoom) { -# ===================== ENRICO_GCODE_PREVIEW ================================================== - $self->canvas->zoom_to_volumes; -# ===================== ENRICO_GCODE_PREVIEW ================================================== + $self->canvas->zoom_to_volumes; } -# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->_loaded(1); } @@ -445,10 +421,8 @@ sub set_number_extruders { # Called by the Platter wxNotebook when this page is activated. sub OnActivate { -# ===================== ENRICO_GCODE_PREVIEW ================================================== # my ($self) = @_; # $self->reload_print(1) if ($self->{reload_delayed}); -# ===================== ENRICO_GCODE_PREVIEW ================================================== } 1; diff --git a/lib/Slic3r/GUI/Plater/3DToolpaths.pm b/lib/Slic3r/GUI/Plater/3DToolpaths.pm index 3dbe59d57..776d8217b 100644 --- a/lib/Slic3r/GUI/Plater/3DToolpaths.pm +++ b/lib/Slic3r/GUI/Plater/3DToolpaths.pm @@ -122,7 +122,6 @@ sub load_print { } if ($self->IsShown) { -# ===================== ENRICO_GCODE_PREVIEW ================================================== $self->canvas->load_gcode_preview($self->print); # # load skirt and brim @@ -135,7 +134,7 @@ sub load_print { # #my @volume_ids = $self->canvas->load_object($object->model_object); # #$self->canvas->volumes->[$_]->color->[3] = 0.2 for @volume_ids; # } -# ===================== ENRICO_GCODE_PREVIEW ================================================== + $self->canvas->zoom_to_volumes; $self->_loaded(1); } diff --git a/xs/src/libslic3r/BoundingBox.cpp b/xs/src/libslic3r/BoundingBox.cpp index 929488a3a..91ba88d84 100644 --- a/xs/src/libslic3r/BoundingBox.cpp +++ b/xs/src/libslic3r/BoundingBox.cpp @@ -4,50 +4,9 @@ namespace Slic3r { -//############################################################################################################ -#if !ENRICO_GCODE_PREVIEW -//############################################################################################################ -template <class PointClass> -BoundingBoxBase<PointClass>::BoundingBoxBase(const std::vector<PointClass> &points) -{ - if (points.empty()) - CONFESS("Empty point set supplied to BoundingBoxBase constructor"); - typename std::vector<PointClass>::const_iterator it = points.begin(); - this->min.x = this->max.x = it->x; - this->min.y = this->max.y = it->y; - for (++it; it != points.end(); ++it) { - this->min.x = std::min(it->x, this->min.x); - this->min.y = std::min(it->y, this->min.y); - this->max.x = std::max(it->x, this->max.x); - this->max.y = std::max(it->y, this->max.y); - } - this->defined = true; -} -//############################################################################################################ -#endif // !ENRICO_GCODE_PREVIEW -//############################################################################################################ template BoundingBoxBase<Point>::BoundingBoxBase(const std::vector<Point> &points); template BoundingBoxBase<Pointf>::BoundingBoxBase(const std::vector<Pointf> &points); -//############################################################################################################ -#if !ENRICO_GCODE_PREVIEW -//############################################################################################################ -template <class PointClass> -BoundingBox3Base<PointClass>::BoundingBox3Base(const std::vector<PointClass> &points) - : BoundingBoxBase<PointClass>(points) -{ - if (points.empty()) - CONFESS("Empty point set supplied to BoundingBox3Base constructor"); - typename std::vector<PointClass>::const_iterator it = points.begin(); - this->min.z = this->max.z = it->z; - for (++it; it != points.end(); ++it) { - this->min.z = std::min(it->z, this->min.z); - this->max.z = std::max(it->z, this->max.z); - } -} -//############################################################################################################ -#endif // !ENRICO_GCODE_PREVIEW -//############################################################################################################ template BoundingBox3Base<Pointf3>::BoundingBox3Base(const std::vector<Pointf3> &points); BoundingBox::BoundingBox(const Lines &lines) diff --git a/xs/src/libslic3r/BoundingBox.hpp b/xs/src/libslic3r/BoundingBox.hpp index 1a15315fb..a7334308c 100644 --- a/xs/src/libslic3r/BoundingBox.hpp +++ b/xs/src/libslic3r/BoundingBox.hpp @@ -23,8 +23,6 @@ public: BoundingBoxBase() : defined(false) {}; BoundingBoxBase(const PointClass &pmin, const PointClass &pmax) : min(pmin), max(pmax), defined(pmin.x < pmax.x && pmin.y < pmax.y) {} -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW BoundingBoxBase(const std::vector<PointClass>& points) { if (points.empty()) @@ -42,12 +40,6 @@ public: } this->defined = (this->min.x < this->max.x) && (this->min.y < this->max.y); } -#else -//############################################################################################################ - BoundingBoxBase(const std::vector<PointClass> &points); -//############################################################################################################ -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ void merge(const PointClass &point); void merge(const std::vector<PointClass> &points); void merge(const BoundingBoxBase<PointClass> &bb); @@ -78,8 +70,6 @@ public: BoundingBox3Base(const PointClass &pmin, const PointClass &pmax) : BoundingBoxBase<PointClass>(pmin, pmax) { if (pmin.z >= pmax.z) BoundingBoxBase<PointClass>::defined = false; } -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW BoundingBox3Base(const std::vector<PointClass>& points) : BoundingBoxBase<PointClass>(points) { @@ -95,12 +85,6 @@ public: } this->defined &= (this->min.z < this->max.z); } -#else -//############################################################################################################ - BoundingBox3Base(const std::vector<PointClass> &points); -//############################################################################################################ -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ void merge(const PointClass &point); void merge(const std::vector<PointClass> &points); void merge(const BoundingBox3Base<PointClass> &bb); @@ -138,15 +122,7 @@ class BoundingBox3 : public BoundingBox3Base<Point3> public: BoundingBox3() : BoundingBox3Base<Point3>() {}; BoundingBox3(const Point3 &pmin, const Point3 &pmax) : BoundingBox3Base<Point3>(pmin, pmax) {}; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW BoundingBox3(const Points3& points) : BoundingBox3Base<Point3>(points) {}; -#else -//############################################################################################################ - BoundingBox3(const std::vector<Point3> &points) : BoundingBox3Base<Point3>(points) {}; -//############################################################################################################ -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ }; class BoundingBoxf : public BoundingBoxBase<Pointf> diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp index 282a0b5d4..a85ccda06 100644 --- a/xs/src/libslic3r/ExtrusionEntity.hpp +++ b/xs/src/libslic3r/ExtrusionEntity.hpp @@ -104,42 +104,17 @@ public: float width; // Height of the extrusion, used for visualization purposed. float height; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW // Feedrate of the extrusion, used for visualization purposed. float feedrate; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW ExtrusionPath(ExtrusionRole role) : mm3_per_mm(-1), width(-1), height(-1), feedrate(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), 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), 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), 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) {}; -#else -//############################################################################################################ - 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(ExtrusionRole role, const Flow &flow) : m_role(role), mm3_per_mm(flow.mm3_per_mm()), width(flow.width), height(flow.height) {}; -//############################################################################################################ -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW ExtrusionPath& operator=(const ExtrusionPath &rhs) { this->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->polyline = rhs.polyline; return *this; } ExtrusionPath& operator=(ExtrusionPath &&rhs) { this->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->polyline = std::move(rhs.polyline); return *this; } -#else -//############################################################################################################ - ExtrusionPath& operator=(const ExtrusionPath &rhs) { this->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) { this->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; } -//############################################################################################################ -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ ExtrusionPath* clone() const { return new ExtrusionPath (*this); } void reverse() { this->polyline.reverse(); } diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index a15318239..14402a1e1 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -402,8 +402,6 @@ void GCode::_do_export(Print &print, FILE *file) m_time_estimator.reset(); m_time_estimator.set_dialect(print.config.gcode_flavor); -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW // resets analyzer m_analyzer.reset(); @@ -411,8 +409,6 @@ void GCode::_do_export(Print &print, FILE *file) m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm; m_last_width = GCodeAnalyzer::Default_Width; m_last_height = GCodeAnalyzer::Default_Height; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ // How many times will be change_layer() called? // change_layer() in turn increments the progress bar status. @@ -823,12 +819,8 @@ void GCode::_do_export(Print &print, FILE *file) } } -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW // starts analizer calculations m_analyzer.calc_gcode_preview_data(print); -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ } std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override) @@ -1320,18 +1312,7 @@ void GCode::process_layer( if (print_object == nullptr) // This layer is empty for this particular object, it has neither object extrusions nor support extrusions at this print_z. continue; -//############################################################################################################ -#if !ENRICO_GCODE_PREVIEW -//############################################################################################################ - if (m_enable_analyzer_markers) { - // Store the binary pointer to the layer object directly into the G-code to be accessed by the GCodeAnalyzer. - char buf[64]; - sprintf(buf, ";_LAYEROBJ:%p\n", m_layer); - gcode += buf; - } -//############################################################################################################ -#endif // !ENRICO_GCODE_PREVIEW -//############################################################################################################ + m_config.apply(print_object->config, true); m_layer = layers[layer_id].layer(); if (m_config.avoid_crossing_perimeters) @@ -2023,18 +2004,8 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill return gcode; } -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW void GCode::_write(FILE* file, const char *what) -#else -//############################################################################################################ -void GCode::_write(FILE* file, const char *what, size_t size) -//############################################################################################################ -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ { -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW if (what != nullptr) { // apply analyzer, if enabled const char* gcode = m_enable_analyzer ? m_analyzer.process_gcode(what).c_str() : what; @@ -2043,16 +2014,6 @@ void GCode::_write(FILE* file, const char *what, size_t size) fwrite(gcode, 1, ::strlen(gcode), file); // updates time estimator and gcode lines vector m_time_estimator.add_gcode_block(gcode); -#else -//############################################################################################################ - if (size > 0) { - // writes string to file - fwrite(what, 1, size, file); - // updates time estimator and gcode lines vector - m_time_estimator.add_gcode_block(what); -//############################################################################################################ -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ } } @@ -2086,15 +2047,8 @@ void GCode::_write_format(FILE* file, const char* format, ...) char *bufptr = buffer_dynamic ? (char*)malloc(buflen) : buffer; int res = ::vsnprintf(bufptr, buflen, format, args); if (res > 0) -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW _write(file, bufptr); -#else -//############################################################################################################ - _write(file, bufptr, res); -//############################################################################################################ -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ + if (buffer_dynamic) free(bufptr); @@ -2179,8 +2133,6 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, double F = speed * 60; // convert mm/sec to mm/min // extrude arc or line -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW if (m_enable_extrusion_role_markers || m_enable_analyzer) { if (path.role() != m_last_extrusion_role) @@ -2231,19 +2183,6 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, gcode += buf; } } -#else -//############################################################################################################ - if (m_enable_extrusion_role_markers || m_enable_analyzer_markers) { - if (path.role() != m_last_extrusion_role) { - m_last_extrusion_role = path.role(); - char buf[32]; - sprintf(buf, ";_EXTRUSION_ROLE:%d\n", int(path.role())); - gcode += buf; - } - } -//############################################################################################################ -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ std::string comment; if (m_enable_cooling_markers) { diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index 97d6d6927..6e42c52d0 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -17,11 +17,7 @@ #include "GCode/WipeTower.hpp" #include "GCodeTimeEstimator.hpp" #include "EdgeGrid.hpp" -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW #include "GCode/Analyzer.hpp" -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ #include <memory> #include <string> @@ -123,28 +119,16 @@ public: m_enable_loop_clipping(true), m_enable_cooling_markers(false), m_enable_extrusion_role_markers(false), -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW m_enable_analyzer(true), -#else -//############################################################################################################ - m_enable_analyzer_markers(false), -//############################################################################################################ -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ m_layer_count(0), m_layer_index(-1), m_layer(nullptr), m_volumetric_speed(0), m_last_pos_defined(false), m_last_extrusion_role(erNone), -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW m_last_mm3_per_mm(GCodeAnalyzer::Default_mm3_per_mm), m_last_width(GCodeAnalyzer::Default_Width), m_last_height(GCodeAnalyzer::Default_Height), -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ m_brim_done(false), m_second_layer_things_done(false), m_last_obj_copy(nullptr, Point(std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max())) @@ -169,12 +153,8 @@ public: // inside the generated string and after the G-code export finishes. std::string placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override = nullptr); bool enable_cooling_markers() const { return m_enable_cooling_markers; } -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW bool enable_analyzer() const { return m_enable_analyzer; } void enable_analyzer(bool enable) { m_enable_analyzer = enable; } -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ // For Perl bindings, to be used exclusively by unit tests. unsigned int layer_count() const { return m_layer_count; } @@ -267,20 +247,10 @@ protected: // Markers for the Pressure Equalizer to recognize the extrusion type. // The Pressure Equalizer removes the markers from the final G-code. bool m_enable_extrusion_role_markers; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW // Enableds the G-code Analyzer. // Extended markers will be added during G-code generation. // The G-code Analyzer will remove these comments from the final G-code. bool m_enable_analyzer; -#else -//############################################################################################################ - // Extended markers for the G-code Analyzer. - // The G-code Analyzer will remove these comments from the final G-code. - bool m_enable_analyzer_markers; -//############################################################################################################ -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ // How many times will change_layer() be called? // change_layer() will update the progress bar. unsigned int m_layer_count; @@ -293,14 +263,10 @@ protected: double m_volumetric_speed; // Support for the extrusion role markers. Which marker is active? ExtrusionRole m_last_extrusion_role; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW // Support for G-Code Analyzer double m_last_mm3_per_mm; float m_last_width; float m_last_height; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ Point m_last_pos; bool m_last_pos_defined; @@ -322,25 +288,12 @@ protected: // Time estimator GCodeTimeEstimator m_time_estimator; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW // Analyzer GCodeAnalyzer m_analyzer; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ // Write a string into a file. -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW void _write(FILE* file, const std::string& what) { this->_write(file, what.c_str()); } void _write(FILE* file, const char *what); -#else -//############################################################################################################ - void _write(FILE* file, const std::string& what) { this->_write(file, what.c_str(), what.size()); } - void _write(FILE* file, const char *what, size_t size); -//############################################################################################################ -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ // Write a string into a file. // Add a newline, if the string does not end with a newline already. diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp index ae857e37e..49b709ec2 100644 --- a/xs/src/libslic3r/GCode/Analyzer.cpp +++ b/xs/src/libslic3r/GCode/Analyzer.cpp @@ -4,16 +4,10 @@ #include "../libslic3r.h" #include "../PrintConfig.hpp" -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW #include "Print.hpp" -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ #include "Analyzer.hpp" -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW static const std::string AXIS_STR = "XYZE"; static const float MMMIN_TO_MMSEC = 1.0f / 60.0f; static const float INCHES_TO_MM = 25.4f; @@ -21,333 +15,9 @@ static const float DEFAULT_FEEDRATE = 0.0f; static const unsigned int DEFAULT_EXTRUDER_ID = 0; static const Slic3r::Pointf3 DEFAULT_START_POSITION = Slic3r::Pointf3(0.0f, 0.0f, 0.0f); static const float DEFAULT_START_EXTRUSION = 0.0f; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ namespace Slic3r { -//############################################################################################################ -#if !ENRICO_GCODE_PREVIEW -//############################################################################################################ -void GCodeMovesDB::reset() -{ - for (size_t i = 0; i < m_layers.size(); ++ i) - delete m_layers[i]; - m_layers.clear(); -} - -GCodeAnalyzer::GCodeAnalyzer(const Slic3r::GCodeConfig *config) : - m_config(config) -{ - reset(); - m_moves = new GCodeMovesDB(); -} - -GCodeAnalyzer::~GCodeAnalyzer() -{ - delete m_moves; -} - -void GCodeAnalyzer::reset() -{ - output_buffer.clear(); - output_buffer_length = 0; - - m_current_extruder = 0; - // Zero the position of the XYZE axes + the current feed - memset(m_current_pos, 0, sizeof(float) * 5); - m_current_extrusion_role = erNone; - m_current_extrusion_width = 0; - m_current_extrusion_height = 0; - // Expect the first command to fill the nozzle (deretract). - m_retracted = true; - m_moves->reset(); -} - -const char* GCodeAnalyzer::process(const char *szGCode, bool flush) -{ - // Reset length of the output_buffer. - output_buffer_length = 0; - - if (szGCode != 0) { - const char *p = szGCode; - while (*p != 0) { - // Find end of the line. - const char *endl = p; - // Slic3r always generates end of lines in a Unix style. - for (; *endl != 0 && *endl != '\n'; ++ endl) ; - // Process a G-code line, store it into the provided GCodeLine object. - bool should_output = process_line(p, endl - p); - if (*endl == '\n') - ++ endl; - if (should_output) - push_to_output(p, endl - p); - p = endl; - } - } - - return output_buffer.data(); -} - -// Is a white space? -static inline bool is_ws(const char c) { return c == ' ' || c == '\t'; } -// Is it an end of line? Consider a comment to be an end of line as well. -static inline bool is_eol(const char c) { return c == 0 || c == '\r' || c == '\n' || c == ';'; }; -// Is it a white space or end of line? -static inline bool is_ws_or_eol(const char c) { return is_ws(c) || is_eol(c); }; - -// Eat whitespaces. -static void eatws(const char *&line) -{ - while (is_ws(*line)) - ++ line; -} - -// Parse an int starting at the current position of a line. -// If succeeded, the line pointer is advanced. -static inline int parse_int(const char *&line) -{ - char *endptr = NULL; - long result = strtol(line, &endptr, 10); - if (endptr == NULL || !is_ws_or_eol(*endptr)) - throw std::runtime_error("GCodeAnalyzer: Error parsing an int"); - line = endptr; - return int(result); -}; - -// Parse an int starting at the current position of a line. -// If succeeded, the line pointer is advanced. -static inline float parse_float(const char *&line) -{ - char *endptr = NULL; - float result = strtof(line, &endptr); - if (endptr == NULL || !is_ws_or_eol(*endptr)) - throw std::runtime_error("GCodeAnalyzer: Error parsing a float"); - line = endptr; - return result; -}; - -#define EXTRUSION_ROLE_TAG ";_EXTRUSION_ROLE:" -bool GCodeAnalyzer::process_line(const char *line, const size_t len) -{ - if (strncmp(line, EXTRUSION_ROLE_TAG, strlen(EXTRUSION_ROLE_TAG)) == 0) { - line += strlen(EXTRUSION_ROLE_TAG); - int role = atoi(line); - this->m_current_extrusion_role = ExtrusionRole(role); - return false; - } - -/* - // Set the type, copy the line to the buffer. - buf.type = GCODE_MOVE_TYPE_OTHER; - buf.modified = false; - if (buf.raw.size() < len + 1) - buf.raw.assign(line, line + len + 1); - else - memcpy(buf.raw.data(), line, len); - buf.raw[len] = 0; - buf.raw_length = len; - - memcpy(buf.pos_start, m_current_pos, sizeof(float)*5); - memcpy(buf.pos_end, m_current_pos, sizeof(float)*5); - memset(buf.pos_provided, 0, 5); - - buf.volumetric_extrusion_rate = 0.f; - buf.volumetric_extrusion_rate_start = 0.f; - buf.volumetric_extrusion_rate_end = 0.f; - buf.max_volumetric_extrusion_rate_slope_positive = 0.f; - buf.max_volumetric_extrusion_rate_slope_negative = 0.f; - buf.extrusion_role = m_current_extrusion_role; - - // Parse the G-code line, store the result into the buf. - switch (toupper(*line ++)) { - case 'G': { - int gcode = parse_int(line); - eatws(line); - switch (gcode) { - case 0: - case 1: - { - // G0, G1: A FFF 3D printer does not make a difference between the two. - float new_pos[5]; - memcpy(new_pos, m_current_pos, sizeof(float)*5); - bool changed[5] = { false, false, false, false, false }; - while (!is_eol(*line)) { - char axis = toupper(*line++); - int i = -1; - switch (axis) { - case 'X': - case 'Y': - case 'Z': - i = axis - 'X'; - break; - case 'E': - i = 3; - break; - case 'F': - i = 4; - break; - default: - assert(false); - } - if (i == -1) - throw std::runtime_error(std::string("GCodeAnalyzer: Invalid axis for G0/G1: ") + axis); - buf.pos_provided[i] = true; - new_pos[i] = parse_float(line); - if (i == 3 && m_config->use_relative_e_distances.value) - new_pos[i] += m_current_pos[i]; - changed[i] = new_pos[i] != m_current_pos[i]; - eatws(line); - } - if (changed[3]) { - // Extrusion, retract or unretract. - float diff = new_pos[3] - m_current_pos[3]; - if (diff < 0) { - buf.type = GCODE_MOVE_TYPE_RETRACT; - m_retracted = true; - } else if (! changed[0] && ! changed[1] && ! changed[2]) { - // assert(m_retracted); - buf.type = GCODE_MOVE_TYPE_UNRETRACT; - m_retracted = false; - } else { - assert(changed[0] || changed[1]); - // Moving in XY plane. - buf.type = GCODE_MOVE_TYPE_EXTRUDE; - // Calculate the volumetric extrusion rate. - float diff[4]; - for (size_t i = 0; i < 4; ++ i) - diff[i] = new_pos[i] - m_current_pos[i]; - // volumetric extrusion rate = A_filament * F_xyz * L_e / L_xyz [mm^3/min] - float len2 = diff[0]*diff[0]+diff[1]*diff[1]+diff[2]*diff[2]; - float rate = m_filament_crossections[m_current_extruder] * new_pos[4] * sqrt((diff[3]*diff[3])/len2); - buf.volumetric_extrusion_rate = rate; - buf.volumetric_extrusion_rate_start = rate; - buf.volumetric_extrusion_rate_end = rate; - m_stat.update(rate, sqrt(len2)); - if (rate < 10.f) { - printf("Extremely low flow rate: %f\n", rate); - } - } - } else if (changed[0] || changed[1] || changed[2]) { - // Moving without extrusion. - buf.type = GCODE_MOVE_TYPE_MOVE; - } - memcpy(m_current_pos, new_pos, sizeof(float) * 5); - break; - } - case 92: - { - // G92 : Set Position - // Set a logical coordinate position to a new value without actually moving the machine motors. - // Which axes to set? - bool set = false; - while (!is_eol(*line)) { - char axis = toupper(*line++); - switch (axis) { - case 'X': - case 'Y': - case 'Z': - m_current_pos[axis - 'X'] = (!is_ws_or_eol(*line)) ? parse_float(line) : 0.f; - set = true; - break; - case 'E': - m_current_pos[3] = (!is_ws_or_eol(*line)) ? parse_float(line) : 0.f; - set = true; - break; - default: - throw std::runtime_error(std::string("GCodeAnalyzer: Incorrect axis in a G92 G-code: ") + axis); - } - eatws(line); - } - assert(set); - break; - } - case 10: - case 22: - // Firmware retract. - buf.type = GCODE_MOVE_TYPE_RETRACT; - m_retracted = true; - break; - case 11: - case 23: - // Firmware unretract. - buf.type = GCODE_MOVE_TYPE_UNRETRACT; - m_retracted = false; - break; - default: - // Ignore the rest. - break; - } - break; - } - case 'M': { - int mcode = parse_int(line); - eatws(line); - switch (mcode) { - default: - // Ignore the rest of the M-codes. - break; - } - break; - } - case 'T': - { - // Activate an extruder head. - int new_extruder = parse_int(line); - if (new_extruder != m_current_extruder) { - m_current_extruder = new_extruder; - m_retracted = true; - buf.type = GCODE_MOVE_TYPE_TOOL_CHANGE; - } else { - buf.type = GCODE_MOVE_TYPE_NOOP; - } - break; - } - } - - buf.extruder_id = m_current_extruder; - memcpy(buf.pos_end, m_current_pos, sizeof(float)*5); -*/ - return true; -} - -void GCodeAnalyzer::push_to_output(const char *text, const size_t len, bool add_eol) -{ - // New length of the output buffer content. - size_t len_new = output_buffer_length + len + 1; - if (add_eol) - ++ len_new; - - // Resize the output buffer to a power of 2 higher than the required memory. - if (output_buffer.size() < len_new) { - size_t v = len_new; - // Compute the next highest power of 2 of 32-bit v - // http://graphics.stanford.edu/~seander/bithacks.html - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - output_buffer.resize(v); - } - - // Copy the text to the output. - if (len != 0) { - memcpy(output_buffer.data() + output_buffer_length, text, len); - output_buffer_length += len; - } - if (add_eol) - output_buffer[output_buffer_length ++] = '\n'; - output_buffer[output_buffer_length] = 0; -} -//############################################################################################################ -#endif // !ENRICO_GCODE_PREVIEW -//############################################################################################################ - -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW const std::string GCodeAnalyzer::Extrusion_Role_Tag = "_ANALYZER_EXTR_ROLE:"; const std::string GCodeAnalyzer::Mm3_Per_Mm_Tag = "_ANALYZER_MM3_PER_MM:"; const std::string GCodeAnalyzer::Width_Tag = "_ANALYZER_WIDTH:"; @@ -539,6 +209,7 @@ const GCodeAnalyzer::PreviewData::Color GCodeAnalyzer::PreviewData::Extrusion::D Color(0.0f, 0.0f, 0.0f, 1.0f) // erMixed }; +// todo: merge with Slic3r::ExtrusionRole2String() from GCode.cpp const std::string GCodeAnalyzer::PreviewData::Extrusion::Default_Extrusion_Role_Names[Num_Extrusion_Roles] { "None", @@ -1424,7 +1095,5 @@ GCodeAnalyzer::PreviewData::Color operator * (float f, const GCodeAnalyzer::Prev clamp(0.0f, 1.0f, f * color.rgba[2]), clamp(0.0f, 1.0f, f * color.rgba[3])); } -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ } // namespace Slic3r diff --git a/xs/src/libslic3r/GCode/Analyzer.hpp b/xs/src/libslic3r/GCode/Analyzer.hpp index 26c525b4c..c4e71799b 100644 --- a/xs/src/libslic3r/GCode/Analyzer.hpp +++ b/xs/src/libslic3r/GCode/Analyzer.hpp @@ -5,169 +5,13 @@ #include "../PrintConfig.hpp" #include "../ExtrusionEntity.hpp" -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW #include "Point.hpp" #include "GCodeReader.hpp" -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ namespace Slic3r { -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW - class Print; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ +class Print; -//############################################################################################################ -#if !ENRICO_GCODE_PREVIEW -//############################################################################################################ -enum GCodeMoveType -{ - GCODE_MOVE_TYPE_NOOP, - GCODE_MOVE_TYPE_RETRACT, - GCODE_MOVE_TYPE_UNRETRACT, - GCODE_MOVE_TYPE_TOOL_CHANGE, - GCODE_MOVE_TYPE_MOVE, - GCODE_MOVE_TYPE_EXTRUDE, -}; - -// For visualization purposes, for the purposes of the G-code analysis and timing. -// The size of this structure is 56B. -// Keep the size of this structure as small as possible, because all moves of a complete print -// may be held in RAM. -struct GCodeMove -{ - bool moving_xy(const float* pos_start) const { return fabs(pos_end[0] - pos_start[0]) > 0.f || fabs(pos_end[1] - pos_start[1]) > 0.f; } - bool moving_xy() const { return moving_xy(get_pos_start()); } - bool moving_z (const float* pos_start) const { return fabs(pos_end[2] - pos_start[2]) > 0.f; } - bool moving_z () const { return moving_z(get_pos_start()); } - bool extruding(const float* pos_start) const { return moving_xy() && pos_end[3] > pos_start[3]; } - bool extruding() const { return extruding(get_pos_start()); } - bool retracting(const float* pos_start) const { return pos_end[3] < pos_start[3]; } - bool retracting() const { return retracting(get_pos_start()); } - bool deretracting(const float* pos_start) const { return ! moving_xy() && pos_end[3] > pos_start[3]; } - bool deretracting() const { return deretracting(get_pos_start()); } - - float dist_xy2(const float* pos_start) const { return (pos_end[0] - pos_start[0]) * (pos_end[0] - pos_start[0]) + (pos_end[1] - pos_start[1]) * (pos_end[1] - pos_start[1]); } - float dist_xy2() const { return dist_xy2(get_pos_start()); } - float dist_xyz2(const float* pos_start) const { return (pos_end[0] - pos_start[0]) * (pos_end[0] - pos_start[0]) + (pos_end[1] - pos_start[1]) * (pos_end[1] - pos_start[1]) + (pos_end[2] - pos_start[2]) * (pos_end[2] - pos_start[2]); } - float dist_xyz2() const { return dist_xyz2(get_pos_start()); } - - float dist_xy(const float* pos_start) const { return sqrt(dist_xy2(pos_start)); } - float dist_xy() const { return dist_xy(get_pos_start()); } - float dist_xyz(const float* pos_start) const { return sqrt(dist_xyz2(pos_start)); } - float dist_xyz() const { return dist_xyz(get_pos_start()); } - - float dist_e(const float* pos_start) const { return fabs(pos_end[3] - pos_start[3]); } - float dist_e() const { return dist_e(get_pos_start()); } - - float feedrate() const { return pos_end[4]; } - float time(const float* pos_start) const { return dist_xyz(pos_start) / feedrate(); } - float time() const { return time(get_pos_start()); } - float time_inv(const float* pos_start) const { return feedrate() / dist_xyz(pos_start); } - float time_inv() const { return time_inv(get_pos_start()); } - - const float* get_pos_start() const { assert(type != GCODE_MOVE_TYPE_NOOP); return this[-1].pos_end; } - - // Pack the enums to conserve space. With C++x11 the allocation size could be declared for enums, but for old C++ this is the only portable way. - // GCodeLineType - uint8_t type; - // Index of the active extruder. - uint8_t extruder_id; - // ExtrusionRole - uint8_t extrusion_role; - // For example, is it a bridge flow? Is the fan on? - uint8_t flags; - // X,Y,Z,E,F. Storing the state of the currently active extruder only. - float pos_end[5]; - // Extrusion width, height for this segment in um. - uint16_t extrusion_width; - uint16_t extrusion_height; -}; - -typedef std::vector<GCodeMove> GCodeMoves; - -struct GCodeLayer -{ - // Index of an object printed. - size_t object_idx; - // Index of an object instance printed. - size_t object_instance_idx; - // Index of the layer printed. - size_t layer_idx; - // Top z coordinate of the layer printed. - float layer_z_top; - - // Moves over this layer. The 0th move is always of type GCODELINETYPE_NOOP and - // it sets the initial position and tool for the layer. - GCodeMoves moves; - - // Indices into m_moves, where the tool changes happen. - // This is useful, if one wants to display just only a piece of the path quickly. - std::vector<size_t> tool_changes; -}; - -typedef std::vector<GCodeLayer*> GCodeLayerPtrs; - -class GCodeMovesDB -{ -public: - GCodeMovesDB() {}; - ~GCodeMovesDB() { reset(); } - void reset(); - GCodeLayerPtrs m_layers; -}; - -// Processes a G-code to extract moves and their types. -// This information is then used to render the print simulation colored by the extrusion type -// or various speeds. -// The GCodeAnalyzer is employed as a G-Code filter. It reads the G-code as it is generated, -// parses the comments generated by Slic3r just for the analyzer, and removes these comments. -class GCodeAnalyzer -{ -public: - GCodeAnalyzer(const Slic3r::GCodeConfig *config); - ~GCodeAnalyzer(); - - void reset(); - - // Process a next batch of G-code lines. Flush the internal buffers if asked for. - const char* process(const char *szGCode, bool flush); - // Length of the buffer returned by process(). - size_t get_output_buffer_length() const { return output_buffer_length; } - -private: - // Keeps the reference, does not own the config. - const Slic3r::GCodeConfig *m_config; - - // Internal data. - // X,Y,Z,E,F - float m_current_pos[5]; - size_t m_current_extruder; - ExtrusionRole m_current_extrusion_role; - uint16_t m_current_extrusion_width; - uint16_t m_current_extrusion_height; - bool m_retracted; - - GCodeMovesDB *m_moves; - - // Output buffer will only grow. It will not be reallocated over and over. - std::vector<char> output_buffer; - size_t output_buffer_length; - - bool process_line(const char *line, const size_t len); - - // Push the text to the end of the output_buffer. - void push_to_output(const char *text, const size_t len, bool add_eol = true); -}; -//############################################################################################################ -#endif // !ENRICO_GCODE_PREVIEW -//############################################################################################################ - -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW class GCodeAnalyzer { public: @@ -553,9 +397,6 @@ private: GCodeAnalyzer::PreviewData::Color operator + (const GCodeAnalyzer::PreviewData::Color& c1, const GCodeAnalyzer::PreviewData::Color& c2); GCodeAnalyzer::PreviewData::Color operator * (float f, const GCodeAnalyzer::PreviewData::Color& color); -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ - } // namespace Slic3r #endif /* slic3r_GCode_Analyzer_hpp_ */ diff --git a/xs/src/libslic3r/Line.cpp b/xs/src/libslic3r/Line.cpp index a4d36d38b..e9d5d7742 100644 --- a/xs/src/libslic3r/Line.cpp +++ b/xs/src/libslic3r/Line.cpp @@ -218,8 +218,6 @@ Line::ccw(const Point& point) const return point.ccw(*this); } -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW double Line3::length() const { return a.distance_to(b); @@ -229,8 +227,6 @@ Vector3 Line3::vector() const { return Vector3(b.x - a.x, b.y - a.y, b.z - a.z); } -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ Pointf3 Linef3::intersect_plane(double z) const diff --git a/xs/src/libslic3r/Line.hpp b/xs/src/libslic3r/Line.hpp index 514a9ca04..4826017ab 100644 --- a/xs/src/libslic3r/Line.hpp +++ b/xs/src/libslic3r/Line.hpp @@ -7,20 +7,12 @@ namespace Slic3r { class Line; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW class Line3; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ class Linef3; class Polyline; class ThickLine; typedef std::vector<Line> Lines; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW typedef std::vector<Line3> Lines3; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ typedef std::vector<ThickLine> ThickLines; class Line @@ -66,8 +58,6 @@ class ThickLine : public Line ThickLine(Point _a, Point _b) : Line(_a, _b), a_width(0), b_width(0) {}; }; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW class Line3 { public: @@ -80,8 +70,6 @@ public: double length() const; Vector3 vector() const; }; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ class Linef { diff --git a/xs/src/libslic3r/MultiPoint.cpp b/xs/src/libslic3r/MultiPoint.cpp index 54c639a96..2e65492cd 100644 --- a/xs/src/libslic3r/MultiPoint.cpp +++ b/xs/src/libslic3r/MultiPoint.cpp @@ -214,8 +214,6 @@ MultiPoint::_douglas_peucker(const Points &points, const double tolerance) return results; } -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW void MultiPoint3::translate(double x, double y) { for (Point3& p : points) @@ -270,8 +268,6 @@ bool MultiPoint3::remove_duplicate_points() return false; } -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ BoundingBox get_extents(const MultiPoint &mp) { diff --git a/xs/src/libslic3r/MultiPoint.hpp b/xs/src/libslic3r/MultiPoint.hpp index ed5bad3a8..0970e9a67 100644 --- a/xs/src/libslic3r/MultiPoint.hpp +++ b/xs/src/libslic3r/MultiPoint.hpp @@ -10,11 +10,7 @@ namespace Slic3r { class BoundingBox; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW class BoundingBox3; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ class MultiPoint { @@ -84,8 +80,6 @@ public: static Points _douglas_peucker(const Points &points, const double tolerance); }; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW class MultiPoint3 { public: @@ -104,8 +98,6 @@ public: // Remove exact duplicates, return true if any duplicate has been removed. bool remove_duplicate_points(); }; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ extern BoundingBox get_extents(const MultiPoint &mp); extern BoundingBox get_extents_rotated(const std::vector<Point> &points, double angle); diff --git a/xs/src/libslic3r/Point.hpp b/xs/src/libslic3r/Point.hpp index a322bc4fa..efed236c8 100644 --- a/xs/src/libslic3r/Point.hpp +++ b/xs/src/libslic3r/Point.hpp @@ -14,29 +14,17 @@ class Line; class Linef; class MultiPoint; class Point; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW class Point3; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ class Pointf; class Pointf3; typedef Point Vector; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW typedef Point3 Vector3; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ typedef Pointf Vectorf; typedef Pointf3 Vectorf3; typedef std::vector<Point> Points; typedef std::vector<Point*> PointPtrs; typedef std::vector<const Point*> PointConstPtrs; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW typedef std::vector<Point3> Points3; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ typedef std::vector<Pointf> Pointfs; typedef std::vector<Pointf3> Pointf3s; @@ -201,24 +189,11 @@ public: static Point3 new_scale(coordf_t x, coordf_t y, coordf_t z) { return Point3(coord_t(scale_(x)), coord_t(scale_(y)), coord_t(scale_(z))); } bool operator==(const Point3 &rhs) const { return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z; } bool operator!=(const Point3 &rhs) const { return ! (*this == rhs); } -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW bool coincides_with(const Point3& rhs) const { return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z; } -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ private: // Hide the following inherited methods: -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW bool operator==(const Point &rhs) const; bool operator!=(const Point &rhs) const; -#else -//############################################################################################################ - bool operator==(const Point &rhs); - bool operator!=(const Point &rhs); -//############################################################################################################ -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ }; std::ostream& operator<<(std::ostream &stm, const Pointf &pointf); @@ -273,11 +248,7 @@ public: static Pointf3 new_unscale(coord_t x, coord_t y, coord_t z) { return Pointf3(unscale(x), unscale(y), unscale(z)); }; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW static Pointf3 new_unscale(const Point3& p) { return Pointf3(unscale(p.x), unscale(p.y), unscale(p.z)); } -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ void scale(double factor); void translate(const Vectorf3 &vector); void translate(double x, double y, double z); @@ -290,21 +261,10 @@ public: private: // Hide the following inherited methods: -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW bool operator==(const Pointf &rhs) const; bool operator!=(const Pointf &rhs) const; -#else -//############################################################################################################ - bool operator==(const Pointf &rhs); - bool operator!=(const Pointf &rhs); -//############################################################################################################ -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ }; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW inline Pointf3 operator+(const Pointf3& p1, const Pointf3& p2) { return Pointf3(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z); } inline Pointf3 operator-(const Pointf3& p1, const Pointf3& p2) { return Pointf3(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z); } inline Pointf3 operator-(const Pointf3& p) { return Pointf3(-p.x, -p.y, -p.z); } @@ -317,8 +277,6 @@ inline Pointf3 normalize(const Pointf3& v) coordf_t len = ::sqrt(sqr(v.x) + sqr(v.y) + sqr(v.z)); return (len != 0.0) ? 1.0 / len * v : Pointf3(0.0, 0.0, 0.0); } -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ template<typename TO> inline TO convert_to(const Point &src) { return TO(typename TO::coord_type(src.x), typename TO::coord_type(src.y)); } template<typename TO> inline TO convert_to(const Pointf &src) { return TO(typename TO::coord_type(src.x), typename TO::coord_type(src.y)); } diff --git a/xs/src/libslic3r/Polyline.cpp b/xs/src/libslic3r/Polyline.cpp index 9462332ff..3432506c6 100644 --- a/xs/src/libslic3r/Polyline.cpp +++ b/xs/src/libslic3r/Polyline.cpp @@ -278,8 +278,6 @@ ThickPolyline::reverse() std::swap(this->endpoints.first, this->endpoints.second); } -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW Lines3 Polyline3::lines() const { Lines3 lines; @@ -293,7 +291,5 @@ Lines3 Polyline3::lines() const } return lines; } -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ } diff --git a/xs/src/libslic3r/Polyline.hpp b/xs/src/libslic3r/Polyline.hpp index 95ee72d0c..a1d777692 100644 --- a/xs/src/libslic3r/Polyline.hpp +++ b/xs/src/libslic3r/Polyline.hpp @@ -129,8 +129,6 @@ class ThickPolyline : public Polyline { void reverse(); }; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW class Polyline3 : public MultiPoint3 { public: @@ -138,8 +136,6 @@ public: }; typedef std::vector<Polyline3> Polylines3; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ } diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 2173ae9b1..d0af38327 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -66,8 +66,6 @@ bool Print::reload_model_instances() return invalidated; } -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW void Print::clear_gcode_preview_data() { gcode_preview.reset(); @@ -103,8 +101,6 @@ void Print::set_gcode_preview_unretractions_visible(bool visible) { gcode_preview.unretraction.is_visible = visible; } -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ PrintRegion* Print::add_region() { diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 2ded86ee9..4c2284446 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -15,11 +15,7 @@ #include "Slicing.hpp" #include "GCode/ToolOrdering.hpp" #include "GCode/WipeTower.hpp" -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW #include "GCode/Analyzer.hpp" -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ #include "tbb/atomic.h" @@ -245,11 +241,7 @@ public: // ordered collections of extrusion paths to build skirt loops and brim ExtrusionEntityCollection skirt, brim; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW GCodeAnalyzer::PreviewData gcode_preview; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ Print() : total_used_filament(0), total_extruded_volume(0) { restart(); } ~Print() { clear_objects(); } @@ -263,8 +255,6 @@ public: void reload_object(size_t idx); bool reload_model_instances(); -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW void clear_gcode_preview_data(); void set_gcode_preview_type(unsigned char type); void set_gcode_preview_extrusion_flags(unsigned int flags); @@ -272,8 +262,6 @@ public: void set_gcode_preview_travel_visible(bool visible); void set_gcode_preview_retractions_visible(bool visible); void set_gcode_preview_unretractions_visible(bool visible); -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ // methods for handling regions PrintRegion* get_region(size_t idx) { return regions.at(idx); } diff --git a/xs/src/libslic3r/libslic3r.h b/xs/src/libslic3r/libslic3r.h index 24d7f4889..5a6a0eaeb 100644 --- a/xs/src/libslic3r/libslic3r.h +++ b/xs/src/libslic3r/libslic3r.h @@ -163,29 +163,12 @@ static inline T clamp(const T low, const T high, const T value) return std::max(low, std::min(high, value)); } -//############################################################################################################ -#define ENRICO_GCODE_PREVIEW 1 -//############################################################################################################ - -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW template <typename T, typename Number> static inline T lerp(const T& a, const T& b, Number t) { assert((t >= Number(-EPSILON)) && (t <= Number(1) + Number(EPSILON))); return (Number(1) - t) * a + t * b; } -#else -//############################################################################################################ -template <typename T> -static inline T lerp(const T a, const T b, const T t) -{ - assert(t >= T(-EPSILON) && t <= T(1.+EPSILON)); - return (1. - t) * a + t * b; -} -//############################################################################################################ -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ } // namespace Slic3r diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 676d75c2f..a79e38035 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -8,11 +8,7 @@ #include "../../libslic3r/Geometry.hpp" #include "../../libslic3r/Print.hpp" #include "../../libslic3r/Slicing.hpp" -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW #include "GCode/Analyzer.hpp" -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ #include <stdio.h> #include <stdlib.h> @@ -25,14 +21,10 @@ #include <tbb/parallel_for.h> #include <tbb/spin_mutex.h> -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW #include <wx/bitmap.h> #include <wx/dcmemory.h> #include <wx/image.h> #include <wx/settings.h> -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ namespace Slic3r { @@ -215,12 +207,8 @@ void GLVolume::set_range(double min_z, double max_z) void GLVolume::render() const { -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW if (!is_active) return; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ glCullFace(GL_BACK); glPushMatrix(); @@ -352,12 +340,9 @@ void GLVolumeCollection::render_VBOs() const GLint color_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "uniform_color") : -1; for (GLVolume *volume : this->volumes) { -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW if (!volume->is_active) continue; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ + if (!volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id) continue; GLsizei n_triangles = GLsizei(std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first)); @@ -396,12 +381,9 @@ void GLVolumeCollection::render_legacy() const for (GLVolume *volume : this->volumes) { assert(! volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id); -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW if (!volume->is_active) continue; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ + GLsizei n_triangles = GLsizei(std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first)); GLsizei n_quads = GLsizei(std::min(volume->indexed_vertex_array.quad_indices_size, volume->qverts_range.second - volume->qverts_range.first)); if (n_triangles + n_quads == 0) @@ -638,8 +620,6 @@ static void thick_lines_to_indexed_vertex_array( #undef BOTTOM } -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW // caller is responsible for supplying NO lines with zero length static void thick_lines_to_indexed_vertex_array(const Lines3& lines, const std::vector<double>& widths, @@ -954,8 +934,6 @@ static void point_to_indexed_vertex_array(const Point3& point, volume.push_triangle(idxs[3], idxs[1], idxs[4]); volume.push_triangle(idxs[0], idxs[3], idxs[4]); } -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ static void thick_lines_to_verts( const Lines &lines, @@ -968,8 +946,6 @@ static void thick_lines_to_verts( thick_lines_to_indexed_vertex_array(lines, widths, heights, closed, top_z, volume.indexed_vertex_array); } -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, @@ -995,8 +971,6 @@ static inline void extrusionentity_to_verts(const ExtrusionPath &extrusion_path, std::vector<double> heights(lines.size(), extrusion_path.height); thick_lines_to_verts(lines, widths, heights, false, print_z, volume); } -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ // Fill in the qverts and tverts with quads and triangles for the extrusion_path. static inline void extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, const Point ©, GLVolume &volume) @@ -1081,8 +1055,6 @@ static void extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity, fl } } -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW static void polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume) { Lines3 lines = polyline.lines(); @@ -1300,8 +1272,6 @@ void _3DScene::LegendTexture::_destroy_texture() m_tex_id = 0; } } -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ void _3DScene::_glew_init() { @@ -1335,8 +1305,6 @@ static inline std::vector<float> parse_colors(const std::vector<std::string> &sc return output; } -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW void _3DScene::load_gcode_preview(const Print* print, GLVolumeCollection* volumes, bool use_VBOs) { if (volumes->empty()) @@ -1368,8 +1336,6 @@ unsigned int _3DScene::get_legend_texture_height() { return s_legend_texture.get_texture_height(); } -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ // Create 3D thick extrusion lines for a skirt and brim. // Adds a new Slic3r::GUI::3DScene::Volume to volumes. @@ -1728,8 +1694,6 @@ void _3DScene::_load_wipe_tower_toolpaths( BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end"; } -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW void _3DScene::_load_gcode_extrusion_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) { // helper functions to select data in dependence of the extrusion view type @@ -2071,7 +2035,5 @@ void _3DScene::_generate_legend_texture(const Print& print) { s_legend_texture.generate_texture(print); } -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ } diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index f869304aa..ba1a9af71 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -7,11 +7,7 @@ #include "../../libslic3r/TriangleMesh.hpp" #include "../../libslic3r/Utils.hpp" -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW class wxBitmap; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ namespace Slic3r { @@ -112,13 +108,9 @@ public: push_geometry(float(x), float(y), float(z), float(nx), float(ny), float(nz)); } -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW inline void push_geometry(const Pointf3& p, const Vectorf3& n) { push_geometry(p.x, p.y, p.z, n.x, n.y, n.z); } -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ inline void push_triangle(int idx1, int idx2, int idx3) { if (this->triangle_indices.size() + 3 > this->vertices_and_normals_interleaved.capacity()) @@ -221,11 +213,7 @@ public: select_group_id(-1), drag_group_id(-1), selected(false), -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW is_active(true), -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ hover(false), tverts_range(0, size_t(-1)), qverts_range(0, size_t(-1)) @@ -262,12 +250,8 @@ public: int drag_group_id; // Is this object selected? bool selected; -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW // Whether or not this volume is active for rendering - bool is_active; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ + bool is_active; // Boolean: Is mouse over this object? bool hover; @@ -367,8 +351,6 @@ private: class _3DScene { -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW struct GCodePreviewData { enum EType @@ -427,19 +409,13 @@ class _3DScene }; static LegendTexture s_legend_texture; -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ public: static void _glew_init(); -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW static void load_gcode_preview(const Print* print, GLVolumeCollection* volumes, bool use_VBOs); static unsigned int get_legend_texture_id(); static unsigned int get_legend_texture_width(); static unsigned int get_legend_texture_height(); -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ static void _load_print_toolpaths( const Print *print, @@ -453,15 +429,12 @@ public: const std::vector<std::string> &tool_colors, bool use_VBOs); - static void _load_wipe_tower_toolpaths( const Print *print, GLVolumeCollection *volumes, const std::vector<std::string> &tool_colors_str, bool use_VBOs); -//############################################################################################################ -#if ENRICO_GCODE_PREVIEW private: // generates gcode extrusion paths geometry static void _load_gcode_extrusion_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); @@ -475,8 +448,6 @@ private: static void _update_gcode_volumes_visibility(const Print& print, GLVolumeCollection& volumes); // generates the legend texture in dependence of the current shown view type static void _generate_legend_texture(const Print& print); -#endif // ENRICO_GCODE_PREVIEW -//############################################################################################################ }; } diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index d29e087c0..4df4a5865 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -165,14 +165,12 @@ _constant() size_t object_count() %code%{ RETVAL = THIS->objects.size(); %}; -// ===================== ENRICO_GCODE_PREVIEW ================================================== void clear_gcode_preview_data(); void set_gcode_preview_type(unsigned char type); void set_gcode_preview_extrusion_flags(unsigned int flags); void set_gcode_preview_travel_visible(bool visible); void set_gcode_preview_retractions_visible(bool visible); void set_gcode_preview_unretractions_visible(bool visible); -// ===================== ENRICO_GCODE_PREVIEW ================================================== PrintRegionPtrs* regions() %code%{ RETVAL = &THIS->regions; %}; From d2d2a3fa8ec1dbd4b03e3a2de9f1afcd4b377a27 Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Wed, 31 Jan 2018 10:34:00 +0100 Subject: [PATCH 11/23] speed in mm/s --- xs/src/libslic3r/GCode/Analyzer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp index 49b709ec2..8d27cf63c 100644 --- a/xs/src/libslic3r/GCode/Analyzer.cpp +++ b/xs/src/libslic3r/GCode/Analyzer.cpp @@ -348,7 +348,7 @@ std::string GCodeAnalyzer::PreviewData::get_legend_title() const case Extrusion::Width: return "Width (mm)"; case Extrusion::Feedrate: - return "Speed (mm/min)"; + return "Speed (mm/s)"; } return ""; @@ -397,7 +397,7 @@ GCodeAnalyzer::PreviewData::LegendItemsList GCodeAnalyzer::PreviewData::get_lege } case Extrusion::Feedrate: { - Helper::FillListFromRange(items, extrusion.ranges.feedrate, 0, 60.0f); + Helper::FillListFromRange(items, extrusion.ranges.feedrate, 0, 1.0f); break; } } From c550ad22683aea32a8df96afbf3d963408d0b4b7 Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Wed, 31 Jan 2018 11:35:35 +0100 Subject: [PATCH 12/23] GCode Preview - Travel moves colored by speed --- xs/src/libslic3r/GCode/Analyzer.cpp | 15 +-- xs/src/libslic3r/GCode/Analyzer.hpp | 3 +- xs/src/slic3r/GUI/3DScene.cpp | 156 +++++++++++++++++++++------- 3 files changed, 130 insertions(+), 44 deletions(-) diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp index 8d27cf63c..2ddb319fc 100644 --- a/xs/src/libslic3r/GCode/Analyzer.cpp +++ b/xs/src/libslic3r/GCode/Analyzer.cpp @@ -122,9 +122,10 @@ GCodeAnalyzer::PreviewData::Extrusion::Layer::Layer(float z, const ExtrusionPath { } -GCodeAnalyzer::PreviewData::Travel::Polyline::Polyline(EType type, EDirection direction, const Polyline3& polyline) +GCodeAnalyzer::PreviewData::Travel::Polyline::Polyline(EType type, EDirection direction, float feedrate, const Polyline3& polyline) : type(type) , direction(direction) + , feedrate(feedrate) , polyline(polyline) { } @@ -1002,11 +1003,11 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(Print& print) { struct Helper { - static void store_polyline(const Polyline3& polyline, PreviewData::Travel::EType type, PreviewData::Travel::Polyline::EDirection direction, Print& print) + static void store_polyline(const Polyline3& polyline, PreviewData::Travel::EType type, PreviewData::Travel::Polyline::EDirection direction, float feedrate, Print& print) { // if the polyline is valid, store it if (polyline.is_valid()) - print.gcode_preview.travel.polylines.emplace_back(type, direction, polyline); + print.gcode_preview.travel.polylines.emplace_back(type, direction, feedrate, polyline); } }; @@ -1018,6 +1019,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(Print& print) Pointf3 position(FLT_MAX, FLT_MAX, FLT_MAX); PreviewData::Travel::EType type = PreviewData::Travel::Num_Types; PreviewData::Travel::Polyline::EDirection direction = PreviewData::Travel::Polyline::Num_Directions; + float feedrate = FLT_MAX; // constructs the polylines while traversing the moves for (const GCodeMove& move : travel_moves->second) @@ -1025,11 +1027,11 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(Print& print) PreviewData::Travel::EType move_type = (move.delta_extruder < 0.0f) ? PreviewData::Travel::Retract : ((move.delta_extruder > 0.0f) ? PreviewData::Travel::Extrude : PreviewData::Travel::Move); PreviewData::Travel::Polyline::EDirection move_direction = ((move.start_position.x != move.end_position.x) || (move.start_position.y != move.end_position.y)) ? PreviewData::Travel::Polyline::Generic : PreviewData::Travel::Polyline::Vertical; - if ((type != move_type) || (direction != move_direction) || (position != move.start_position)) + if ((type != move_type) || (direction != move_direction) || (feedrate != move.data.feedrate) || (position != move.start_position)) { // store current polyline polyline.remove_duplicate_points(); - Helper::store_polyline(polyline, type, direction, print); + Helper::store_polyline(polyline, type, direction, feedrate, print); // reset current polyline polyline = Polyline3(); @@ -1045,11 +1047,12 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(Print& print) // update current values position = move.end_position; type = move_type; + feedrate = move.data.feedrate; } // store last polyline polyline.remove_duplicate_points(); - Helper::store_polyline(polyline, type, direction, print); + Helper::store_polyline(polyline, type, direction, feedrate, print); } void GCodeAnalyzer::_calc_gcode_preview_retractions(Print& print) diff --git a/xs/src/libslic3r/GCode/Analyzer.hpp b/xs/src/libslic3r/GCode/Analyzer.hpp index c4e71799b..a72874a35 100644 --- a/xs/src/libslic3r/GCode/Analyzer.hpp +++ b/xs/src/libslic3r/GCode/Analyzer.hpp @@ -215,9 +215,10 @@ public: EType type; EDirection direction; + float feedrate; Polyline3 polyline; - Polyline(EType type, EDirection direction, const Polyline3& polyline); + Polyline(EType type, EDirection direction, float feedrate, const Polyline3& polyline); }; typedef std::vector<Polyline> PolylinesList; diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index a79e38035..589a23e86 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -1863,59 +1863,141 @@ void _3DScene::_load_gcode_travel_paths(const Print& print, GLVolumeCollection& typedef std::vector<Type> TypesList; + // Helper structure for feedrate + struct Feedrate + { + float value; + GLVolume* volume; + + explicit Feedrate(float value) + : value(value) + , volume(nullptr) + { + } + + bool operator == (const Feedrate& other) const + { + return value == other.value; + } + }; + + typedef std::vector<Feedrate> FeedratesList; + size_t initial_volumes_count = volumes.volumes.size(); s_gcode_preview_data.first_volumes.emplace_back(GCodePreviewData::Travel, 0, (unsigned int)initial_volumes_count); - // detects types - TypesList types; - for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) + if (print.gcode_preview.extrusion.view_type == GCodeAnalyzer::PreviewData::Extrusion::Feedrate) { - if (std::find(types.begin(), types.end(), Type(polyline.type)) == types.end()) - types.emplace_back(polyline.type); - } + // colors travels by feedrate - // nothing to render, return - if (types.empty()) - return; - - // creates a new volume for each type - for (Type& type : types) - { - GLVolume* volume = new GLVolume(print.gcode_preview.travel.type_colors[type.value].rgba); - if (volume != nullptr) + // detects feedrates + FeedratesList feedrates; + for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) { - type.volume = volume; - volumes.volumes.emplace_back(volume); + if (std::find(feedrates.begin(), feedrates.end(), Feedrate(polyline.feedrate)) == feedrates.end()) + feedrates.emplace_back(polyline.feedrate); } - else + + // nothing to render, return + if (feedrates.empty()) + return; + + // creates a new volume for each feedrate + for (Feedrate& feedrate : feedrates) { - // an error occourred - restore to previous state and return - if (initial_volumes_count != volumes.volumes.size()) + GLVolume* volume = new GLVolume(print.gcode_preview.get_extrusion_feedrate_color(feedrate.value).rgba); + if (volume != nullptr) { - std::vector<GLVolume*>::iterator begin = volumes.volumes.begin() + initial_volumes_count; - std::vector<GLVolume*>::iterator end = volumes.volumes.end(); - for (std::vector<GLVolume*>::iterator it = begin; it < end; ++it) + feedrate.volume = volume; + volumes.volumes.emplace_back(volume); + } + else + { + // an error occourred - restore to previous state and return + if (initial_volumes_count != volumes.volumes.size()) { - GLVolume* volume = *it; - delete volume; + std::vector<GLVolume*>::iterator begin = volumes.volumes.begin() + initial_volumes_count; + std::vector<GLVolume*>::iterator end = volumes.volumes.end(); + for (std::vector<GLVolume*>::iterator it = begin; it < end; ++it) + { + GLVolume* volume = *it; + delete volume; + } + volumes.volumes.erase(begin, end); + return; } - volumes.volumes.erase(begin, end); - return; + } + } + + // populates volumes + for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) + { + FeedratesList::iterator feedrate = std::find(feedrates.begin(), feedrates.end(), Feedrate(polyline.feedrate)); + if (feedrate != feedrates.end()) + { + feedrate->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().max.z)); + feedrate->volume->offsets.push_back(feedrate->volume->indexed_vertex_array.quad_indices.size()); + feedrate->volume->offsets.push_back(feedrate->volume->indexed_vertex_array.triangle_indices.size()); + + polyline3_to_verts(polyline.polyline, print.gcode_preview.travel.width, print.gcode_preview.travel.height, *feedrate->volume); } } } - - // populates volumes - for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) + else { - TypesList::iterator type = std::find(types.begin(), types.end(), Type(polyline.type)); - if (type != types.end()) - { - type->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().max.z)); - type->volume->offsets.push_back(type->volume->indexed_vertex_array.quad_indices.size()); - type->volume->offsets.push_back(type->volume->indexed_vertex_array.triangle_indices.size()); + // colors travels by travel type - polyline3_to_verts(polyline.polyline, print.gcode_preview.travel.width, print.gcode_preview.travel.height, *type->volume); + // detects types + TypesList types; + for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) + { + if (std::find(types.begin(), types.end(), Type(polyline.type)) == types.end()) + types.emplace_back(polyline.type); + } + + // nothing to render, return + if (types.empty()) + return; + + // creates a new volume for each type + for (Type& type : types) + { + GLVolume* volume = new GLVolume(print.gcode_preview.travel.type_colors[type.value].rgba); + if (volume != nullptr) + { + type.volume = volume; + volumes.volumes.emplace_back(volume); + } + else + { + // an error occourred - restore to previous state and return + if (initial_volumes_count != volumes.volumes.size()) + { + std::vector<GLVolume*>::iterator begin = volumes.volumes.begin() + initial_volumes_count; + std::vector<GLVolume*>::iterator end = volumes.volumes.end(); + for (std::vector<GLVolume*>::iterator it = begin; it < end; ++it) + { + GLVolume* volume = *it; + delete volume; + } + volumes.volumes.erase(begin, end); + return; + } + } + } + + // populates volumes + for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) + { + TypesList::iterator type = std::find(types.begin(), types.end(), Type(polyline.type)); + if (type != types.end()) + { + type->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().max.z)); + type->volume->offsets.push_back(type->volume->indexed_vertex_array.quad_indices.size()); + type->volume->offsets.push_back(type->volume->indexed_vertex_array.triangle_indices.size()); + + polyline3_to_verts(polyline.polyline, print.gcode_preview.travel.width, print.gcode_preview.travel.height, *type->volume); + } } } From 787a5f1715ddba98f9df25e49dd5da653ad5e85f Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Fri, 2 Feb 2018 12:38:35 +0100 Subject: [PATCH 13/23] GCode Preview - New Layout --- lib/Slic3r/GUI/Plater/3DPreview.pm | 62 +++++++++++++------------ xs/CMakeLists.txt | 2 + xs/src/slic3r/GUI/GUI.cpp | 48 +++++++++++++++++++ xs/src/slic3r/GUI/GUI.hpp | 13 +++++- xs/src/slic3r/GUI/wxExtensions.cpp | 74 ++++++++++++++++++++++++++++++ xs/src/slic3r/GUI/wxExtensions.hpp | 27 +++++++++++ xs/xsp/GUI.xsp | 7 +++ 7 files changed, 202 insertions(+), 31 deletions(-) create mode 100644 xs/src/slic3r/GUI/wxExtensions.cpp create mode 100644 xs/src/slic3r/GUI/wxExtensions.hpp diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index 379c557b6..ed84135e2 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -4,7 +4,7 @@ use warnings; use utf8; use Slic3r::Print::State ':steps'; -use Wx qw(:misc :sizer :slider :statictext :keycode wxWHITE); +use Wx qw(:misc :sizer :slider :statictext :keycode wxWHITE wxCB_READONLY); use Wx::Event qw(EVT_SLIDER EVT_KEY_DOWN EVT_CHECKBOX EVT_CHOICE EVT_CHECKLISTBOX); use base qw(Wx::Panel Class::Accessor); @@ -61,29 +61,24 @@ sub new { my $checkbox_singlelayer = $self->{checkbox_singlelayer} = Wx::CheckBox->new($self, -1, "1 Layer"); my $checkbox_color_by_extruder = $self->{checkbox_color_by_extruder} = Wx::CheckBox->new($self, -1, "Tool"); + my $label_view_type = $self->{label_view_type} = Wx::StaticText->new($self, -1, "View"); + my $choice_view_type = Wx::Choice->new($self, -1); $choice_view_type->Append("Feature type"); $choice_view_type->Append("Height"); $choice_view_type->Append("Width"); $choice_view_type->Append("Speed"); $choice_view_type->SetSelection(0); + + my $label_show_features = $self->{label_show_features} = Wx::StaticText->new($self, -1, "Show"); - my $checklist_features = Wx::CheckListBox->new($self, -1, wxDefaultPosition, [-1, 150]); - $checklist_features->Append("Perimeter"); - $checklist_features->Append("External perimeter"); - $checklist_features->Append("Overhang perimeter"); - $checklist_features->Append("Internal infill"); - $checklist_features->Append("Solid infill"); - $checklist_features->Append("Top solid infill"); - $checklist_features->Append("Bridge infill"); - $checklist_features->Append("Gap fill"); - $checklist_features->Append("Skirt"); - $checklist_features->Append("Support material"); - $checklist_features->Append("Support material interface"); - for (my $i = 0; $i < $checklist_features->GetCount(); $i += 1) - { - $checklist_features->Check($i, 1); - } + my $combochecklist_features = Wx::ComboCtrl->new(); + $combochecklist_features->Create($self, -1, "Feature types", wxDefaultPosition, [200, -1], wxCB_READONLY); + $combochecklist_features->UseAltPopupWindow(); + $combochecklist_features->EnablePopupAnimation(0); + my $feature_text = "Feature types"; + my $feature_items = "Perimeter|External perimeter|Overhang perimeter|Internal infill|Solid infill|Top solid infill|Bridge infill|Gap fill|Skirt|Support material|Support material interface"; + Slic3r::GUI::create_combochecklist($combochecklist_features, $feature_text, $feature_items, 1); my $checkbox_travel = Wx::CheckBox->new($self, -1, "Travel"); my $checkbox_retractions = Wx::CheckBox->new($self, -1, "Retractions"); @@ -102,15 +97,27 @@ sub new { $vsizer_outer->Add($hsizer, 3, wxALIGN_CENTER_HORIZONTAL, 0); $vsizer_outer->Add($checkbox_singlelayer, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, 5); $vsizer_outer->Add($checkbox_color_by_extruder, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, 5); - $vsizer_outer->Add($choice_view_type, 0, wxEXPAND | wxALL | wxALIGN_CENTER_HORIZONTAL, 5); - $vsizer_outer->Add($checklist_features, 0, wxTOP | wxALL | wxALIGN_CENTER_HORIZONTAL, 5); - $vsizer_outer->Add($checkbox_travel, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); - $vsizer_outer->Add($checkbox_retractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); - $vsizer_outer->Add($checkbox_unretractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + my $bottom_sizer = Wx::BoxSizer->new(wxHORIZONTAL); + $bottom_sizer->Add($label_view_type, 0, wxALIGN_CENTER_VERTICAL, 5); + $bottom_sizer->Add($choice_view_type, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + $bottom_sizer->AddSpacer(10); + $bottom_sizer->Add($label_show_features, 0, wxALIGN_CENTER_VERTICAL, 5); + $bottom_sizer->Add($combochecklist_features, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + $bottom_sizer->AddSpacer(20); + $bottom_sizer->Add($checkbox_travel, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + $bottom_sizer->AddSpacer(10); + $bottom_sizer->Add($checkbox_retractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + $bottom_sizer->AddSpacer(10); + $bottom_sizer->Add($checkbox_unretractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + my $sizer = Wx::BoxSizer->new(wxHORIZONTAL); $sizer->Add($canvas, 1, wxALL | wxEXPAND, 0); $sizer->Add($vsizer_outer, 0, wxTOP | wxBOTTOM | wxEXPAND, 5); + + my $main_sizer = Wx::BoxSizer->new(wxVERTICAL); + $main_sizer->Add($sizer, 1, wxALL | wxEXPAND, 0); + $main_sizer->Add($bottom_sizer, 0, wxALL | wxEXPAND, 0); EVT_SLIDER($self, $slider_low, sub { $slider_high->SetValue($slider_low->GetValue) if $self->single_layer; @@ -194,13 +201,8 @@ sub new { $self->reload_print; $self->auto_zoom(1); }); - EVT_CHECKLISTBOX($self, $checklist_features, sub { - my $flags = 0; - for (my $i = 0; $i < $checklist_features->GetCount(); $i += 1) { - if ($checklist_features->IsChecked($i)) { - $flags += 2 ** $i; - } - } + EVT_CHECKLISTBOX($self, $combochecklist_features, sub { + my $flags = Slic3r::GUI::combochecklist_get_flags($combochecklist_features); $self->print->set_gcode_preview_extrusion_flags($flags); $self->auto_zoom(0); @@ -226,7 +228,7 @@ sub new { $self->auto_zoom(1); }); - $self->SetSizer($sizer); + $self->SetSizer($main_sizer); $self->SetMinSize($self->GetSize); $sizer->SetSizeHints($self); diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index 9e23112c5..de475eaa0 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -177,6 +177,8 @@ add_library(libslic3r_gui STATIC ${LIBDIR}/slic3r/GUI/PresetHints.hpp ${LIBDIR}/slic3r/GUI/GUI.cpp ${LIBDIR}/slic3r/GUI/GUI.hpp + ${LIBDIR}/slic3r/GUI/wxExtensions.cpp + ${LIBDIR}/slic3r/GUI/wxExtensions.hpp ) add_library(admesh STATIC diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 8db0508f1..7d107ecbc 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -5,6 +5,9 @@ #include <boost/algorithm/string/predicate.hpp> #include <boost/filesystem.hpp> +#include <boost/algorithm/string/split.hpp> +#include <boost/algorithm/string/classification.hpp> + #if __APPLE__ #import <IOKit/pwr_mgt/IOPMLib.h> #elif _WIN32 @@ -20,6 +23,9 @@ #include <wx/notebook.h> #include <wx/panel.h> #include <wx/sizer.h> +#include <wx/combo.h> + +#include "slic3r/gui/wxextensions.hpp" namespace Slic3r { namespace GUI { @@ -183,4 +189,46 @@ void create_preset_tab(const char *name) g_wxTabPanel->AddPage(panel, name); } +void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string items, bool initial_value) +{ + wxCheckListBoxComboPopup* popup = new wxCheckListBoxComboPopup(-1); + if (popup != nullptr) + { + comboCtrl->SetPopupControl(popup); + popup->SetStringValue(text); + popup->Connect(-1, wxEVT_CHECKLISTBOX, wxCommandEventHandler(wxCheckListBoxComboPopup::OnCheckListBox), nullptr, popup); + popup->Connect(-1, wxEVT_LISTBOX, wxCommandEventHandler(wxCheckListBoxComboPopup::OnListBoxSelection), nullptr, popup); + + std::vector<std::string> items_str; + boost::split(items_str, items, boost::is_any_of("|"), boost::token_compress_off); + + for (const std::string& item : items_str) + { + popup->Append(item); + } + + for (unsigned int i = 0; i < popup->GetCount(); ++i) + { + popup->Check(i, initial_value); + } + } +} + +int combochecklist_get_flags(wxComboCtrl* comboCtrl) +{ + int flags = 0; + + wxCheckListBoxComboPopup* popup = wxDynamicCast(comboCtrl->GetPopupControl(), wxCheckListBoxComboPopup); + if (popup != nullptr) + { + for (unsigned int i = 0; i < popup->GetCount(); ++i) + { + if (popup->IsChecked(i)) + flags += (int)std::pow(2.0f, (float)i); + } + } + + return flags; +} + } } diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index 3634e0bc8..f15ba15d6 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -8,6 +8,7 @@ class wxApp; class wxFrame; class wxMenuBar; class wxNotebook; +class wxComboCtrl; namespace Slic3r { namespace GUI { @@ -27,6 +28,16 @@ void add_debug_menu(wxMenuBar *menu); // add it at the end of the tab panel. void create_preset_tab(const char *name); -} } +// Creates a wxCheckListBoxComboPopup inside the given wxComboCtrl, filled with the given text and items. +// Items are all initialized to the given value. +// Items must be separated by '|', for example "Item1|Item2|Item3", and so on. +void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string items, bool initial_value); + +// Returns the current state of the items listed in the wxCheckListBoxComboPopup contained in the given wxComboCtrl, +// encoded inside an int. +int combochecklist_get_flags(wxComboCtrl* comboCtrl); + +} +} #endif diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp new file mode 100644 index 000000000..d8f0434c7 --- /dev/null +++ b/xs/src/slic3r/GUI/wxExtensions.cpp @@ -0,0 +1,74 @@ +#include "wxExtensions.hpp" + +const unsigned int wxCheckListBoxComboPopup::Height = 200; + +wxCheckListBoxComboPopup::wxCheckListBoxComboPopup(wxWindowID id) + : m_id(id) + , m_text(wxEmptyString) +{ +} + +bool wxCheckListBoxComboPopup::Create(wxWindow* parent) +{ + return wxCheckListBox::Create(parent, m_id, wxPoint(0, 0)); +} + +wxWindow* wxCheckListBoxComboPopup::GetControl() +{ + return this; +} + +void wxCheckListBoxComboPopup::SetStringValue(const wxString& value) +{ + m_text = value; +} + +wxString wxCheckListBoxComboPopup::GetStringValue() const +{ + return m_text; +} + +wxSize wxCheckListBoxComboPopup::GetAdjustedSize(int minWidth, int prefHeight, int maxHeight) +{ + // matches owner wxComboCtrl's width + + wxComboCtrl* cmb = GetComboCtrl(); + if (cmb != nullptr) + { + wxSize size = GetComboCtrl()->GetSize(); + size.SetHeight(Height); + return size; + } + else + return wxSize(200, Height); +} + +void wxCheckListBoxComboPopup::OnCheckListBox(wxCommandEvent& evt) +{ + // forwards the checklistbox event to the owner wxComboCtrl + + wxComboCtrl* cmb = GetComboCtrl(); + if (cmb != nullptr) + { + wxCommandEvent event(wxEVT_CHECKLISTBOX, cmb->GetId()); + cmb->ProcessWindowEvent(event); + } +} + +void wxCheckListBoxComboPopup::OnListBoxSelection(wxCommandEvent& evt) +{ + // transforms list box item selection event into checklistbox item toggle event + + int selId = GetSelection(); + if (selId != wxNOT_FOUND) + { + Toggle((unsigned int)selId); + SetSelection(wxNOT_FOUND); + + wxCommandEvent event(wxEVT_CHECKLISTBOX, GetId()); + event.SetInt(selId); + event.SetEventObject(this); + event.SetString(GetString(selId)); + ProcessEvent(event); + } +} diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp new file mode 100644 index 000000000..96d59069d --- /dev/null +++ b/xs/src/slic3r/GUI/wxExtensions.hpp @@ -0,0 +1,27 @@ +#ifndef slic3r_GUI_wxExtensions_hpp_ +#define slic3r_GUI_wxExtensions_hpp_ + +#include <wx/checklst.h> +#include <wx/combo.h> + +class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup +{ + static const unsigned int Height; + + wxWindowID m_id; + wxString m_text; + +public: + explicit wxCheckListBoxComboPopup(wxWindowID id); + + virtual bool Create(wxWindow* parent); + virtual wxWindow* GetControl(); + virtual void SetStringValue(const wxString& value); + virtual wxString GetStringValue() const; + virtual wxSize GetAdjustedSize(int minWidth, int prefHeight, int maxHeight); + + void OnCheckListBox(wxCommandEvent& evt); + void OnListBoxSelection(wxCommandEvent& evt); +}; + +#endif // slic3r_GUI_wxExtensions_hpp_ diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp index d6b55dbf1..3b2c47e26 100644 --- a/xs/xsp/GUI.xsp +++ b/xs/xsp/GUI.xsp @@ -37,3 +37,10 @@ void add_debug_menu(SV *ui) void create_preset_tab(const char *name) %code%{ Slic3r::GUI::create_preset_tab(name); %}; + +void create_combochecklist(SV *ui, std::string text, std::string items, bool initial_value) + %code%{ Slic3r::GUI::create_combochecklist((wxComboCtrl*)wxPli_sv_2_object(aTHX_ ui, "Wx::ComboCtrl"), text, items, initial_value); %}; + +int combochecklist_get_flags(SV *ui) + %code%{ RETVAL=Slic3r::GUI::combochecklist_get_flags((wxComboCtrl*)wxPli_sv_2_object(aTHX_ ui, "Wx::ComboCtrl")); %}; + \ No newline at end of file From a5c47517183ca9721bd97d22830d52a294e59b63 Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Fri, 2 Feb 2018 12:58:31 +0100 Subject: [PATCH 14/23] GCode Preview - void wxCheckListBoxComboPopup::OnListBoxSelection(wxCommandEvent& evt) fixed for OsX and Linux --- xs/src/slic3r/GUI/wxExtensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp index d8f0434c7..7fe799019 100644 --- a/xs/src/slic3r/GUI/wxExtensions.cpp +++ b/xs/src/slic3r/GUI/wxExtensions.cpp @@ -62,7 +62,7 @@ void wxCheckListBoxComboPopup::OnListBoxSelection(wxCommandEvent& evt) int selId = GetSelection(); if (selId != wxNOT_FOUND) { - Toggle((unsigned int)selId); + Check((unsigned int)selId, !IsChecked((unsigned int)selId)); SetSelection(wxNOT_FOUND); wxCommandEvent event(wxEVT_CHECKLISTBOX, GetId()); From 556c9c236f2437a4733b783225a1edb7f85561ac Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Fri, 2 Feb 2018 13:28:37 +0100 Subject: [PATCH 15/23] GCode Preview - fixed Linux build (include in GUI.cpp) --- xs/src/slic3r/GUI/GUI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 7d107ecbc..1f09f19a8 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -25,7 +25,7 @@ #include <wx/sizer.h> #include <wx/combo.h> -#include "slic3r/gui/wxextensions.hpp" +#include "../../slic3r/gui/wxextensions.hpp" namespace Slic3r { namespace GUI { From fe8dfb9c9b4a4bab5a5d1d19fe09750d2147ee6d Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Fri, 2 Feb 2018 13:56:25 +0100 Subject: [PATCH 16/23] GCode Preview - fixed Linux build (include in GUI.cpp) 2nd attempt --- xs/src/slic3r/GUI/GUI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 1f09f19a8..749ed0c69 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -25,7 +25,7 @@ #include <wx/sizer.h> #include <wx/combo.h> -#include "../../slic3r/gui/wxextensions.hpp" +#include "wxExtensions.hpp" namespace Slic3r { namespace GUI { From f9dd251276c997b503c845ea9678291c1e3239b2 Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Mon, 5 Feb 2018 13:16:08 +0100 Subject: [PATCH 17/23] GCode Preview - Added feature type for wipe tower --- lib/Slic3r/GUI/Plater/3DPreview.pm | 2 +- xs/src/libslic3r/ExtrusionEntity.hpp | 1 + xs/src/libslic3r/GCode.cpp | 2 ++ xs/src/libslic3r/GCode/Analyzer.cpp | 37 ++++++++++++--------- xs/src/libslic3r/GCode/Analyzer.hpp | 2 ++ xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 17 ++++++++++ 6 files changed, 45 insertions(+), 16 deletions(-) diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index ed84135e2..af0cb16c8 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -77,7 +77,7 @@ sub new { $combochecklist_features->UseAltPopupWindow(); $combochecklist_features->EnablePopupAnimation(0); my $feature_text = "Feature types"; - my $feature_items = "Perimeter|External perimeter|Overhang perimeter|Internal infill|Solid infill|Top solid infill|Bridge infill|Gap fill|Skirt|Support material|Support material interface"; + my $feature_items = "Perimeter|External perimeter|Overhang perimeter|Internal infill|Solid infill|Top solid infill|Bridge infill|Gap fill|Skirt|Support material|Support material interface|Wipe tower"; Slic3r::GUI::create_combochecklist($combochecklist_features, $feature_text, $feature_items, 1); my $checkbox_travel = Wx::CheckBox->new($self, -1, "Travel"); diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp index a85ccda06..650a806f6 100644 --- a/xs/src/libslic3r/ExtrusionEntity.hpp +++ b/xs/src/libslic3r/ExtrusionEntity.hpp @@ -25,6 +25,7 @@ enum ExtrusionRole { erSkirt, erSupportMaterial, erSupportMaterialInterface, + erWipeTower, // Extrusion role for a collection with multiple extrusion roles. erMixed, }; diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 14402a1e1..c256268e5 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1454,7 +1454,9 @@ static inline const char* ExtrusionRole2String(const ExtrusionRole role) case erSkirt: return "erSkirt"; case erSupportMaterial: return "erSupportMaterial"; case erSupportMaterialInterface: return "erSupportMaterialInterface"; + case erWipeTower: return "erWipeTower"; case erMixed: return "erMixed"; + default: return "erInvalid"; }; } diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp index 2ddb319fc..b4d7f2596 100644 --- a/xs/src/libslic3r/GCode/Analyzer.cpp +++ b/xs/src/libslic3r/GCode/Analyzer.cpp @@ -195,19 +195,20 @@ GCodeAnalyzer::PreviewData::LegendItem::LegendItem(const std::string& text, cons const GCodeAnalyzer::PreviewData::Color GCodeAnalyzer::PreviewData::Extrusion::Default_Extrusion_Role_Colors[Num_Extrusion_Roles] = { - Color(0.0f, 0.0f, 0.0f, 1.0f), // erNone - Color(1.0f, 0.0f, 0.0f, 1.0f), // erPerimeter - Color(0.0f, 1.0f, 0.0f, 1.0f), // erExternalPerimeter - Color(0.0f, 0.0f, 1.0f, 1.0f), // erOverhangPerimeter - Color(1.0f, 1.0f, 0.0f, 1.0f), // erInternalInfill - Color(1.0f, 0.0f, 1.0f, 1.0f), // erSolidInfill - Color(0.0f, 1.0f, 1.0f, 1.0f), // erTopSolidInfill - Color(0.5f, 0.5f, 0.5f, 1.0f), // erBridgeInfill - Color(1.0f, 1.0f, 1.0f, 1.0f), // erGapFill - Color(0.5f, 0.0f, 0.0f, 1.0f), // erSkirt - Color(0.0f, 0.5f, 0.0f, 1.0f), // erSupportMaterial - Color(0.0f, 0.0f, 0.5f, 1.0f), // erSupportMaterialInterface - Color(0.0f, 0.0f, 0.0f, 1.0f) // erMixed + Color(0.0f, 0.0f, 0.0f, 1.0f), // erNone + Color(1.0f, 0.0f, 0.0f, 1.0f), // erPerimeter + Color(0.0f, 1.0f, 0.0f, 1.0f), // erExternalPerimeter + Color(0.0f, 0.0f, 1.0f, 1.0f), // erOverhangPerimeter + Color(1.0f, 1.0f, 0.0f, 1.0f), // erInternalInfill + Color(1.0f, 0.0f, 1.0f, 1.0f), // erSolidInfill + Color(0.0f, 1.0f, 1.0f, 1.0f), // erTopSolidInfill + Color(0.5f, 0.5f, 0.5f, 1.0f), // erBridgeInfill + Color(1.0f, 1.0f, 1.0f, 1.0f), // erGapFill + Color(0.5f, 0.0f, 0.0f, 1.0f), // erSkirt + Color(0.0f, 0.5f, 0.0f, 1.0f), // erSupportMaterial + Color(0.0f, 0.0f, 0.5f, 1.0f), // erSupportMaterialInterface + Color(0.7f, 0.89f, 0.67f, 1.0f), // erWipeTower + Color(0.0f, 0.0f, 0.0f, 1.0f) // erMixed }; // todo: merge with Slic3r::ExtrusionRole2String() from GCode.cpp @@ -225,6 +226,7 @@ const std::string GCodeAnalyzer::PreviewData::Extrusion::Default_Extrusion_Role_ "Skirt", "Support material", "Support material interface", + "Wipe tower", "Mixed" }; @@ -258,7 +260,7 @@ bool GCodeAnalyzer::PreviewData::Extrusion::is_role_flag_set(ExtrusionRole role) bool GCodeAnalyzer::PreviewData::Extrusion::is_role_flag_set(unsigned int flags, ExtrusionRole role) { - if ((role < erPerimeter) || (erSupportMaterialInterface < role)) + if (!is_valid_extrusion_role(role)) return false; unsigned int flag = (unsigned int)::exp2((double)(role - erPerimeter)); @@ -458,6 +460,11 @@ void GCodeAnalyzer::calc_gcode_preview_data(Print& print) _calc_gcode_preview_unretractions(print); } +bool GCodeAnalyzer::is_valid_extrusion_role(ExtrusionRole role) +{ + return ((erPerimeter <= role) && (role < erMixed)); +} + void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line) { // processes 'special' comments contained in line @@ -597,7 +604,7 @@ void GCodeAnalyzer::_processG1(const GCodeReader::GCodeLine& line) type = GCodeMove::Move; ExtrusionRole role = _get_extrusion_role(); - if ((type == GCodeMove::Extrude) && ((_get_width() == 0.0f) || (_get_height() == 0.0f) || (role < erPerimeter) || (erSupportMaterialInterface < role))) + if ((type == GCodeMove::Extrude) && ((_get_width() == 0.0f) || (_get_height() == 0.0f) || !is_valid_extrusion_role(role))) type = GCodeMove::Move; // updates axis positions diff --git a/xs/src/libslic3r/GCode/Analyzer.hpp b/xs/src/libslic3r/GCode/Analyzer.hpp index a72874a35..1671c35ca 100644 --- a/xs/src/libslic3r/GCode/Analyzer.hpp +++ b/xs/src/libslic3r/GCode/Analyzer.hpp @@ -293,6 +293,8 @@ public: // Calculates all data needed for gcode visualization void calc_gcode_preview_data(Print& print); + static bool is_valid_extrusion_role(ExtrusionRole role); + private: // Processes the given gcode line void _process_gcode_line(GCodeReader& reader, const GCodeReader::GCodeLine& line); diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index 858845e3d..99c6c757f 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -6,6 +6,8 @@ #include <iostream> #include <vector> +#include "Analyzer.hpp" + #if defined(__linux) || defined(__GNUC__ ) #include <strings.h> #endif /* __linux */ @@ -419,6 +421,11 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime( // Increase the extruder driver current to allow fast ramming. .set_extruder_trimpot(750); + // adds tag for analyzer + char buf[32]; + sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erWipeTower); + writer.append(buf); + if (purpose == PURPOSE_EXTRUDE || purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) { float y_end = 0.f; for (size_t idx_tool = 0; idx_tool < tools.size(); ++ idx_tool) { @@ -554,6 +561,11 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo writer.set_initial_position(initial_position); } + // adds tag for analyzer + char buf[32]; + sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erWipeTower); + writer.append(buf); + if (purpose == PURPOSE_EXTRUDE || purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) { // Increase the extruder driver current to allow fast ramming. writer.set_extruder_trimpot(750); @@ -637,6 +649,11 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::toolchange_Brim(Purpose purpose, b else writer.set_initial_position(initial_position); + // adds tag for analyzer + char buf[32]; + sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erWipeTower); + writer.append(buf); + if (purpose == PURPOSE_EXTRUDE || purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) { // Prime the extruder 10*m_perimeter_width left along the vertical edge of the wipe tower. writer.extrude_explicit(wipeTower_box.ld - xy(m_perimeter_width * 6.f, 0), From 6ff9021e040e9cc4ed7d20e5772600122f2af7de Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Tue, 6 Feb 2018 12:43:25 +0100 Subject: [PATCH 18/23] GCode Preview - Legend texture shown only when gcode is available --- lib/Slic3r/GUI/3DScene.pm | 32 ++++++++++++++++++------------ lib/Slic3r/GUI/Plater.pm | 2 ++ lib/Slic3r/GUI/Plater/3DPreview.pm | 3 +++ xs/src/slic3r/GUI/3DScene.cpp | 17 +++++++++++++++- xs/src/slic3r/GUI/3DScene.hpp | 6 ++++++ xs/src/slic3r/GUI/GUI.cpp | 9 ++++++--- xs/src/slic3r/GUI/wxExtensions.cpp | 12 +++-------- xs/src/slic3r/GUI/wxExtensions.hpp | 3 --- xs/xsp/GUI_3DScene.xsp | 7 ++++++- 9 files changed, 61 insertions(+), 30 deletions(-) diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index daceb8c49..f567c2f72 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -1605,23 +1605,25 @@ sub draw_legend { my $tex_id = Slic3r::GUI::_3DScene::get_legend_texture_id; if ($tex_id > 0) { - glDisable(GL_DEPTH_TEST); - glPushMatrix(); - glLoadIdentity(); - my $tex_w = Slic3r::GUI::_3DScene::get_legend_texture_width; my $tex_h = Slic3r::GUI::_3DScene::get_legend_texture_height; - - my ($cw, $ch) = $self->GetSizeWH; + if (($tex_w > 0) && ($tex_h > 0)) + { + glDisable(GL_DEPTH_TEST); + glPushMatrix(); + glLoadIdentity(); + + my ($cw, $ch) = $self->GetSizeWH; - my $l = (-0.5 * $cw) / $self->_zoom; - my $t = (0.5 * $ch) / $self->_zoom; - my $r = $l + $tex_w / $self->_zoom; - my $b = $t - $tex_h / $self->_zoom; - $self->_render_texture($tex_id, $l, $r, $b, $t); + my $l = (-0.5 * $cw) / $self->_zoom; + my $t = (0.5 * $ch) / $self->_zoom; + my $r = $l + $tex_w / $self->_zoom; + my $b = $t - $tex_h / $self->_zoom; + $self->_render_texture($tex_id, $l, $r, $b, $t); - glPopMatrix(); - glEnable(GL_DEPTH_TEST); + glPopMatrix(); + glEnable(GL_DEPTH_TEST); + } } } } @@ -2038,4 +2040,8 @@ sub set_toolpaths_range { $self->volumes->set_range($min_z, $max_z); } +sub reset_legend_texture { + Slic3r::GUI::_3DScene::reset_legend_texture(); +} + 1; diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 321bb7112..014aee53c 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -1261,6 +1261,8 @@ sub reslice { $self->stop_background_process; # Rather perform one additional unnecessary update of the print object instead of skipping a pending async update. $self->async_apply_config; + # Reset gcode data + $self->{print}->clear_gcode_preview_data; $self->statusbar->SetCancelCallback(sub { $self->stop_background_process; $self->statusbar->SetStatusText("Slicing cancelled"); diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index af0cb16c8..9c3c95d1a 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -290,6 +290,9 @@ sub load_print { $self->set_z_range(0,0); $self->slider_low->Hide; $self->slider_high->Hide; + $self->{z_label_low}->SetLabel(""); + $self->{z_label_high}->SetLabel(""); + $self->canvas->reset_legend_texture(); $self->canvas->Refresh; # clears canvas return; } diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 589a23e86..15e905ee4 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -1229,6 +1229,11 @@ unsigned int _3DScene::LegendTexture::get_texture_height() const return m_tex_height; } +void _3DScene::LegendTexture::reset_texture() +{ + _destroy_texture(); +} + bool _3DScene::LegendTexture::_create_texture(const Print& print, const wxBitmap& bitmap) { if ((m_tex_width == 0) || (m_tex_height == 0)) @@ -1270,6 +1275,8 @@ void _3DScene::LegendTexture::_destroy_texture() { ::glDeleteTextures(1, &m_tex_id); m_tex_id = 0; + m_tex_height = 0; + m_tex_width = 0; } } @@ -1316,7 +1323,10 @@ void _3DScene::load_gcode_preview(const Print* print, GLVolumeCollection* volume _load_gcode_retractions(*print, *volumes, use_VBOs); _load_gcode_unretractions(*print, *volumes, use_VBOs); - _generate_legend_texture(*print); + if (volumes->empty()) + reset_legend_texture(); + else + _generate_legend_texture(*print); } _update_gcode_volumes_visibility(*print, *volumes); @@ -1337,6 +1347,11 @@ unsigned int _3DScene::get_legend_texture_height() return s_legend_texture.get_texture_height(); } +void _3DScene::reset_legend_texture() +{ + s_legend_texture.reset_texture(); +} + // Create 3D thick extrusion lines for a skirt and brim. // Adds a new Slic3r::GUI::3DScene::Volume to volumes. void _3DScene::_load_print_toolpaths( diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index ba1a9af71..4c73bdb7d 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -403,20 +403,26 @@ class _3DScene unsigned int get_texture_width() const; unsigned int get_texture_height() const; + void reset_texture(); + private: bool _create_texture(const Print& print, const wxBitmap& bitmap); void _destroy_texture(); }; static LegendTexture s_legend_texture; + public: static void _glew_init(); static void load_gcode_preview(const Print* print, GLVolumeCollection* volumes, bool use_VBOs); + static unsigned int get_legend_texture_id(); static unsigned int get_legend_texture_width(); static unsigned int get_legend_texture_height(); + static void reset_legend_texture(); + static void _load_print_toolpaths( const Print *print, GLVolumeCollection *volumes, diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 749ed0c69..775cfdcf6 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -191,13 +191,16 @@ void create_preset_tab(const char *name) void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string items, bool initial_value) { - wxCheckListBoxComboPopup* popup = new wxCheckListBoxComboPopup(-1); + if (comboCtrl == nullptr) + return; + + wxCheckListBoxComboPopup* popup = new wxCheckListBoxComboPopup; if (popup != nullptr) { comboCtrl->SetPopupControl(popup); popup->SetStringValue(text); - popup->Connect(-1, wxEVT_CHECKLISTBOX, wxCommandEventHandler(wxCheckListBoxComboPopup::OnCheckListBox), nullptr, popup); - popup->Connect(-1, wxEVT_LISTBOX, wxCommandEventHandler(wxCheckListBoxComboPopup::OnListBoxSelection), nullptr, popup); + popup->Connect(wxID_ANY, wxEVT_CHECKLISTBOX, wxCommandEventHandler(wxCheckListBoxComboPopup::OnCheckListBox), nullptr, popup); + popup->Connect(wxID_ANY, wxEVT_LISTBOX, wxCommandEventHandler(wxCheckListBoxComboPopup::OnListBoxSelection), nullptr, popup); std::vector<std::string> items_str; boost::split(items_str, items, boost::is_any_of("|"), boost::token_compress_off); diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp index 7fe799019..b5f0595f8 100644 --- a/xs/src/slic3r/GUI/wxExtensions.cpp +++ b/xs/src/slic3r/GUI/wxExtensions.cpp @@ -1,16 +1,10 @@ #include "wxExtensions.hpp" -const unsigned int wxCheckListBoxComboPopup::Height = 200; - -wxCheckListBoxComboPopup::wxCheckListBoxComboPopup(wxWindowID id) - : m_id(id) - , m_text(wxEmptyString) -{ -} +const unsigned int wxCheckListBoxComboPopup::Height = 210; bool wxCheckListBoxComboPopup::Create(wxWindow* parent) { - return wxCheckListBox::Create(parent, m_id, wxPoint(0, 0)); + return wxCheckListBox::Create(parent, wxID_HIGHEST + 1, wxPoint(0, 0)); } wxWindow* wxCheckListBoxComboPopup::GetControl() @@ -51,6 +45,7 @@ void wxCheckListBoxComboPopup::OnCheckListBox(wxCommandEvent& evt) if (cmb != nullptr) { wxCommandEvent event(wxEVT_CHECKLISTBOX, cmb->GetId()); + event.SetEventObject(cmb); cmb->ProcessWindowEvent(event); } } @@ -68,7 +63,6 @@ void wxCheckListBoxComboPopup::OnListBoxSelection(wxCommandEvent& evt) wxCommandEvent event(wxEVT_CHECKLISTBOX, GetId()); event.SetInt(selId); event.SetEventObject(this); - event.SetString(GetString(selId)); ProcessEvent(event); } } diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp index 96d59069d..8e62f766c 100644 --- a/xs/src/slic3r/GUI/wxExtensions.hpp +++ b/xs/src/slic3r/GUI/wxExtensions.hpp @@ -8,12 +8,9 @@ class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup { static const unsigned int Height; - wxWindowID m_id; wxString m_text; public: - explicit wxCheckListBoxComboPopup(wxWindowID id); - virtual bool Create(wxWindow* parent); virtual wxWindow* GetControl(); virtual void SetStringValue(const wxString& value); diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index f6d729f98..6c56a06d9 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -161,7 +161,12 @@ get_legend_texture_height() RETVAL = _3DScene::get_legend_texture_height(); OUTPUT: RETVAL - + +void +reset_legend_texture() + CODE: + _3DScene::reset_legend_texture(); + void _load_print_toolpaths(print, volumes, tool_colors, use_VBOs) Print *print; From 0d6a0136583850038f7e905daf674dececb6e00d Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Wed, 7 Feb 2018 09:07:37 +0100 Subject: [PATCH 19/23] GCode Preview - Coloring by tool --- lib/Slic3r/GUI/3DScene.pm | 4 +- lib/Slic3r/GUI/Plater/3DPreview.pm | 45 +--- xs/src/libslic3r/ExtrusionEntity.hpp | 16 +- xs/src/libslic3r/GCode/Analyzer.cpp | 42 +++- xs/src/libslic3r/GCode/Analyzer.hpp | 6 +- xs/src/slic3r/GUI/3DScene.cpp | 347 +++++++++++++++++---------- xs/src/slic3r/GUI/3DScene.hpp | 13 +- xs/xsp/GUI_3DScene.xsp | 11 +- 8 files changed, 289 insertions(+), 195 deletions(-) diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index f567c2f72..f63dad079 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -2029,10 +2029,10 @@ sub load_wipe_tower_toolpaths { } sub load_gcode_preview { - my ($self, $print) = @_; + my ($self, $print, $colors) = @_; $self->SetCurrent($self->GetContext) if $self->UseVBOs; - Slic3r::GUI::_3DScene::load_gcode_preview($print, $self->volumes, $self->UseVBOs); + Slic3r::GUI::_3DScene::load_gcode_preview($print, $self->volumes, $colors, $self->UseVBOs); } sub set_toolpaths_range { diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index 9c3c95d1a..2b853dbb3 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -17,7 +17,6 @@ sub new { my $self = $class->SUPER::new($parent, -1, wxDefaultPosition); $self->{config} = $config; $self->{number_extruders} = 1; - $self->{preferred_color_mode} = 'feature'; $self->auto_zoom(1); # init GUI elements @@ -57,9 +56,7 @@ sub new { $z_label_high->SetFont($Slic3r::GUI::small_font); $self->single_layer(0); - $self->{color_by_extruder} = 0; my $checkbox_singlelayer = $self->{checkbox_singlelayer} = Wx::CheckBox->new($self, -1, "1 Layer"); - my $checkbox_color_by_extruder = $self->{checkbox_color_by_extruder} = Wx::CheckBox->new($self, -1, "Tool"); my $label_view_type = $self->{label_view_type} = Wx::StaticText->new($self, -1, "View"); @@ -68,6 +65,7 @@ sub new { $choice_view_type->Append("Height"); $choice_view_type->Append("Width"); $choice_view_type->Append("Speed"); + $choice_view_type->Append("Tool"); $choice_view_type->SetSelection(0); my $label_show_features = $self->{label_show_features} = Wx::StaticText->new($self, -1, "Show"); @@ -96,7 +94,6 @@ sub new { $hsizer->Add($vsizer, 0, wxEXPAND, 0); $vsizer_outer->Add($hsizer, 3, wxALIGN_CENTER_HORIZONTAL, 0); $vsizer_outer->Add($checkbox_singlelayer, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, 5); - $vsizer_outer->Add($checkbox_color_by_extruder, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, 5); my $bottom_sizer = Wx::BoxSizer->new(wxHORIZONTAL); $bottom_sizer->Add($label_view_type, 0, wxALIGN_CENTER_VERTICAL, 5); @@ -188,12 +185,6 @@ sub new { $self->set_z_idx_high($slider_high->GetValue); } }); - EVT_CHECKBOX($self, $checkbox_color_by_extruder, sub { - $self->{color_by_extruder} = $checkbox_color_by_extruder->GetValue(); - $self->{preferred_color_mode} = $self->{color_by_extruder} ? 'tool' : 'feature'; - $self->reload_print; - }); - EVT_CHOICE($self, $choice_view_type, sub { my $selection = $choice_view_type->GetCurrentSelection(); $self->print->set_gcode_preview_type($selection); @@ -322,33 +313,19 @@ sub load_print { $self->slider_high->Show; $self->Layout; - my $by_tool = $self->{color_by_extruder}; - if ($self->{preferred_color_mode} eq 'tool_or_feature') { - # It is left to Slic3r to decide whether the print shall be colored by the tool or by the feature. - # Color by feature if it is a single extruder print. - my $extruders = $self->{print}->extruders; - $by_tool = scalar(@{$extruders}) > 1; - $self->{color_by_extruder} = $by_tool; - $self->{checkbox_color_by_extruder}->SetValue($by_tool); - $self->{preferred_color_mode} = 'tool_or_feature'; - } - # Collect colors per extruder. - # Leave it empty, if the print should be colored by a feature. my @colors = (); - if ($by_tool) { - my @extruder_colors = @{$self->{config}->extruder_colour}; - my @filament_colors = @{$self->{config}->filament_colour}; - for (my $i = 0; $i <= $#extruder_colors; $i += 1) { - my $color = $extruder_colors[$i]; - $color = $filament_colors[$i] if (! defined($color) || $color !~ m/^#[[:xdigit:]]{6}/); - $color = '#FFFFFF' if (! defined($color) || $color !~ m/^#[[:xdigit:]]{6}/); - push @colors, $color; - } + my @extruder_colors = @{$self->{config}->extruder_colour}; + my @filament_colors = @{$self->{config}->filament_colour}; + for (my $i = 0; $i <= $#extruder_colors; $i += 1) { + my $color = $extruder_colors[$i]; + $color = $filament_colors[$i] if (! defined($color) || $color !~ m/^#[[:xdigit:]]{6}/); + $color = '#FFFFFF' if (! defined($color) || $color !~ m/^#[[:xdigit:]]{6}/); + push @colors, $color; } if ($self->IsShown) { - $self->canvas->load_gcode_preview($self->print); + $self->canvas->load_gcode_preview($self->print, \@colors); # # load skirt and brim # $self->canvas->load_print_toolpaths($self->print, \@colors); @@ -417,10 +394,6 @@ sub set_number_extruders { my ($self, $number_extruders) = @_; if ($self->{number_extruders} != $number_extruders) { $self->{number_extruders} = $number_extruders; - my $by_tool = $number_extruders > 1; - $self->{color_by_extruder} = $by_tool; - $self->{checkbox_color_by_extruder}->SetValue($by_tool); - $self->{preferred_color_mode} = $by_tool ? 'tool_or_feature' : 'feature'; } } diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp index 650a806f6..f5e243419 100644 --- a/xs/src/libslic3r/ExtrusionEntity.hpp +++ b/xs/src/libslic3r/ExtrusionEntity.hpp @@ -107,15 +107,17 @@ public: float height; // Feedrate of the extrusion, used for visualization purposed. float feedrate; + // Id of the extruder, used for visualization purposed. + unsigned int extruder_id; - ExtrusionPath(ExtrusionRole role) : mm3_per_mm(-1), width(-1), height(-1), feedrate(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), 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), 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), 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) {}; + ExtrusionPath(ExtrusionRole role) : mm3_per_mm(-1), width(-1), height(-1), feedrate(0.0f), extruder_id(0), 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), 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), 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), 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& operator=(const ExtrusionPath &rhs) { this->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->polyline = rhs.polyline; return *this; } - ExtrusionPath& operator=(ExtrusionPath &&rhs) { this->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->polyline = std::move(rhs.polyline); return *this; } + ExtrusionPath& operator=(const ExtrusionPath &rhs) { this->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->polyline = rhs.polyline; return *this; } + ExtrusionPath& operator=(ExtrusionPath &&rhs) { this->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->polyline = std::move(rhs.polyline); return *this; } ExtrusionPath* clone() const { return new ExtrusionPath (*this); } void reverse() { this->polyline.reverse(); } diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp index b4d7f2596..0288770b0 100644 --- a/xs/src/libslic3r/GCode/Analyzer.cpp +++ b/xs/src/libslic3r/GCode/Analyzer.cpp @@ -122,10 +122,11 @@ GCodeAnalyzer::PreviewData::Extrusion::Layer::Layer(float z, const ExtrusionPath { } -GCodeAnalyzer::PreviewData::Travel::Polyline::Polyline(EType type, EDirection direction, float feedrate, const Polyline3& polyline) +GCodeAnalyzer::PreviewData::Travel::Polyline::Polyline(EType type, EDirection direction, float feedrate, unsigned int extruder_id, const Polyline3& polyline) : type(type) , direction(direction) , feedrate(feedrate) + , extruder_id(extruder_id) , polyline(polyline) { } @@ -352,12 +353,14 @@ std::string GCodeAnalyzer::PreviewData::get_legend_title() const return "Width (mm)"; case Extrusion::Feedrate: return "Speed (mm/s)"; + case Extrusion::Tool: + return "Tool"; } return ""; } -GCodeAnalyzer::PreviewData::LegendItemsList GCodeAnalyzer::PreviewData::get_legend_items() const +GCodeAnalyzer::PreviewData::LegendItemsList GCodeAnalyzer::PreviewData::get_legend_items(const std::vector<float>& tool_colors) const { struct Helper { @@ -401,6 +404,23 @@ GCodeAnalyzer::PreviewData::LegendItemsList GCodeAnalyzer::PreviewData::get_lege case Extrusion::Feedrate: { Helper::FillListFromRange(items, extrusion.ranges.feedrate, 0, 1.0f); + break; + } + case Extrusion::Tool: + { + unsigned int tools_colors_count = tool_colors.size() / 4; + items.reserve(tools_colors_count); + for (unsigned int i = 0; i < tools_colors_count; ++i) + { + char buf[32]; + sprintf(buf, "Extruder %d", i + 1); + + GCodeAnalyzer::PreviewData::Color color; + ::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float)); + + items.emplace_back(buf, color); + } + break; } } @@ -693,9 +713,8 @@ void GCodeAnalyzer::_processT(const GCodeReader::GCodeLine& line) std::string cmd = line.cmd(); if (cmd.length() > 1) { - int id = (int)::strtol(cmd.substr(1).c_str(), nullptr, 10); - // todo - add id validity check ? - if (_get_extruder_id() != (unsigned int)id) + unsigned int id = (unsigned int)::strtol(cmd.substr(1).c_str(), nullptr, 10); + if (_get_extruder_id() != id) { _set_extruder_id(id); @@ -947,6 +966,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(Print& print) ExtrusionPath path(data.extrusion_role, data.mm3_per_mm, data.width, data.height); path.polyline = polyline; path.feedrate = data.feedrate; + path.extruder_id = data.extruder_id; get_layer_at_z(print.gcode_preview.extrusion.layers, z).paths.push_back(path); } @@ -1010,11 +1030,11 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(Print& print) { struct Helper { - static void store_polyline(const Polyline3& polyline, PreviewData::Travel::EType type, PreviewData::Travel::Polyline::EDirection direction, float feedrate, Print& print) + static void store_polyline(const Polyline3& polyline, PreviewData::Travel::EType type, PreviewData::Travel::Polyline::EDirection direction, float feedrate, unsigned int extruder_id, Print& print) { // if the polyline is valid, store it if (polyline.is_valid()) - print.gcode_preview.travel.polylines.emplace_back(type, direction, feedrate, polyline); + print.gcode_preview.travel.polylines.emplace_back(type, direction, feedrate, extruder_id, polyline); } }; @@ -1027,6 +1047,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(Print& print) PreviewData::Travel::EType type = PreviewData::Travel::Num_Types; PreviewData::Travel::Polyline::EDirection direction = PreviewData::Travel::Polyline::Num_Directions; float feedrate = FLT_MAX; + unsigned int extruder_id = -1; // constructs the polylines while traversing the moves for (const GCodeMove& move : travel_moves->second) @@ -1034,11 +1055,11 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(Print& print) PreviewData::Travel::EType move_type = (move.delta_extruder < 0.0f) ? PreviewData::Travel::Retract : ((move.delta_extruder > 0.0f) ? PreviewData::Travel::Extrude : PreviewData::Travel::Move); PreviewData::Travel::Polyline::EDirection move_direction = ((move.start_position.x != move.end_position.x) || (move.start_position.y != move.end_position.y)) ? PreviewData::Travel::Polyline::Generic : PreviewData::Travel::Polyline::Vertical; - if ((type != move_type) || (direction != move_direction) || (feedrate != move.data.feedrate) || (position != move.start_position)) + if ((type != move_type) || (direction != move_direction) || (feedrate != move.data.feedrate) || (position != move.start_position) || (extruder_id != move.data.extruder_id)) { // store current polyline polyline.remove_duplicate_points(); - Helper::store_polyline(polyline, type, direction, feedrate, print); + Helper::store_polyline(polyline, type, direction, feedrate, extruder_id, print); // reset current polyline polyline = Polyline3(); @@ -1055,11 +1076,12 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(Print& print) position = move.end_position; type = move_type; feedrate = move.data.feedrate; + extruder_id = move.data.extruder_id; } // store last polyline polyline.remove_duplicate_points(); - Helper::store_polyline(polyline, type, direction, feedrate, print); + Helper::store_polyline(polyline, type, direction, feedrate, extruder_id, print); } void GCodeAnalyzer::_calc_gcode_preview_retractions(Print& print) diff --git a/xs/src/libslic3r/GCode/Analyzer.hpp b/xs/src/libslic3r/GCode/Analyzer.hpp index 1671c35ca..34f1537af 100644 --- a/xs/src/libslic3r/GCode/Analyzer.hpp +++ b/xs/src/libslic3r/GCode/Analyzer.hpp @@ -152,6 +152,7 @@ public: Height, Width, Feedrate, + Tool, Num_View_Types }; @@ -216,9 +217,10 @@ public: EType type; EDirection direction; float feedrate; + unsigned int extruder_id; Polyline3 polyline; - Polyline(EType type, EDirection direction, float feedrate, const Polyline3& polyline); + Polyline(EType type, EDirection direction, float feedrate, unsigned int extruder_id, const Polyline3& polyline); }; typedef std::vector<Polyline> PolylinesList; @@ -270,7 +272,7 @@ public: const Color& get_extrusion_feedrate_color(float feedrate) const; std::string get_legend_title() const; - LegendItemsList get_legend_items() const; + LegendItemsList get_legend_items(const std::vector<float>& tool_colors) const; }; private: diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 15e905ee4..96cbabbe9 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -1099,13 +1099,13 @@ _3DScene::LegendTexture::~LegendTexture() _destroy_texture(); } -bool _3DScene::LegendTexture::generate_texture(const Print& print) +bool _3DScene::LegendTexture::generate_texture(const Print& print, const std::vector<float>& tool_colors) { _destroy_texture(); // collects items to render const std::string& title = print.gcode_preview.get_legend_title(); - const GCodeAnalyzer::PreviewData::LegendItemsList& items = print.gcode_preview.get_legend_items(); + const GCodeAnalyzer::PreviewData::LegendItemsList& items = print.gcode_preview.get_legend_items(tool_colors); unsigned int items_count = (unsigned int)items.size(); if (items_count == 0) @@ -1312,21 +1312,23 @@ static inline std::vector<float> parse_colors(const std::vector<std::string> &sc return output; } -void _3DScene::load_gcode_preview(const Print* print, GLVolumeCollection* volumes, bool use_VBOs) +void _3DScene::load_gcode_preview(const Print* print, GLVolumeCollection* volumes, const std::vector<std::string>& str_tool_colors, bool use_VBOs) { if (volumes->empty()) { + std::vector<float> tool_colors = parse_colors(str_tool_colors); + s_gcode_preview_data.reset(); - _load_gcode_extrusion_paths(*print, *volumes, use_VBOs); - _load_gcode_travel_paths(*print, *volumes, use_VBOs); + _load_gcode_extrusion_paths(*print, *volumes, tool_colors, use_VBOs); + _load_gcode_travel_paths(*print, *volumes, tool_colors, use_VBOs); _load_gcode_retractions(*print, *volumes, use_VBOs); _load_gcode_unretractions(*print, *volumes, use_VBOs); if (volumes->empty()) reset_legend_texture(); else - _generate_legend_texture(*print); + _generate_legend_texture(*print, tool_colors); } _update_gcode_volumes_visibility(*print, *volumes); @@ -1709,7 +1711,7 @@ void _3DScene::_load_wipe_tower_toolpaths( BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end"; } -void _3DScene::_load_gcode_extrusion_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) +void _3DScene::_load_gcode_extrusion_paths(const Print& print, GLVolumeCollection& volumes, const std::vector<float>& tool_colors, bool use_VBOs) { // helper functions to select data in dependence of the extrusion view type struct Helper @@ -1726,12 +1728,14 @@ void _3DScene::_load_gcode_extrusion_paths(const Print& print, GLVolumeCollectio return path.width; case GCodeAnalyzer::PreviewData::Extrusion::Feedrate: return path.feedrate; + case GCodeAnalyzer::PreviewData::Extrusion::Tool: + return (float)path.extruder_id; } return 0.0f; } - static const GCodeAnalyzer::PreviewData::Color& path_color(const GCodeAnalyzer::PreviewData& data, float value) + static const GCodeAnalyzer::PreviewData::Color& path_color(const GCodeAnalyzer::PreviewData& data, const std::vector<float>& tool_colors, float value) { switch (data.extrusion.view_type) { @@ -1743,6 +1747,12 @@ void _3DScene::_load_gcode_extrusion_paths(const Print& print, GLVolumeCollectio return data.get_extrusion_width_color(value); case GCodeAnalyzer::PreviewData::Extrusion::Feedrate: return data.get_extrusion_feedrate_color(value); + case GCodeAnalyzer::PreviewData::Extrusion::Tool: + { + static GCodeAnalyzer::PreviewData::Color color; + ::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + (unsigned int)value * 4), 4 * sizeof(float)); + return color; + } } return GCodeAnalyzer::PreviewData::Color::Dummy; @@ -1801,7 +1811,7 @@ void _3DScene::_load_gcode_extrusion_paths(const Print& print, GLVolumeCollectio { s_gcode_preview_data.first_volumes.emplace_back(GCodePreviewData::Extrusion, (unsigned int)filter.role, (unsigned int)volumes.volumes.size()); - GLVolume* volume = new GLVolume(Helper::path_color(print.gcode_preview, filter.value).rgba); + GLVolume* volume = new GLVolume(Helper::path_color(print.gcode_preview, tool_colors, filter.value).rgba); if (volume != nullptr) { filter.volume = volume; @@ -1856,7 +1866,62 @@ void _3DScene::_load_gcode_extrusion_paths(const Print& print, GLVolumeCollectio } } -void _3DScene::_load_gcode_travel_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) +void _3DScene::_load_gcode_travel_paths(const Print& print, GLVolumeCollection& volumes, const std::vector<float>& tool_colors, bool use_VBOs) +{ + size_t initial_volumes_count = volumes.volumes.size(); + s_gcode_preview_data.first_volumes.emplace_back(GCodePreviewData::Travel, 0, (unsigned int)initial_volumes_count); + + bool res = true; + switch (print.gcode_preview.extrusion.view_type) + { + case GCodeAnalyzer::PreviewData::Extrusion::Feedrate: + { + res = _travel_paths_by_feedrate(print, volumes); + break; + } + case GCodeAnalyzer::PreviewData::Extrusion::Tool: + { + res = _travel_paths_by_tool(print, volumes, tool_colors); + break; + } + default: + { + res = _travel_paths_by_type(print, volumes); + break; + } + } + + if (!res) + { + // an error occourred - restore to previous state and return + if (initial_volumes_count != volumes.volumes.size()) + { + std::vector<GLVolume*>::iterator begin = volumes.volumes.begin() + initial_volumes_count; + std::vector<GLVolume*>::iterator end = volumes.volumes.end(); + for (std::vector<GLVolume*>::iterator it = begin; it < end; ++it) + { + GLVolume* volume = *it; + delete volume; + } + volumes.volumes.erase(begin, end); + } + + return; + } + + // finalize volumes and sends geometry to gpu + if (volumes.volumes.size() > initial_volumes_count) + { + for (size_t i = initial_volumes_count; i < volumes.volumes.size(); ++i) + { + GLVolume* volume = volumes.volumes[i]; + volume->bounding_box = volume->indexed_vertex_array.bounding_box(); + volume->indexed_vertex_array.finalize_geometry(use_VBOs); + } + } +} + +bool _3DScene::_travel_paths_by_type(const Print& print, GLVolumeCollection& volumes) { // Helper structure for types struct Type @@ -1878,6 +1943,52 @@ void _3DScene::_load_gcode_travel_paths(const Print& print, GLVolumeCollection& typedef std::vector<Type> TypesList; + // colors travels by travel type + + // detects types + TypesList types; + for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) + { + if (std::find(types.begin(), types.end(), Type(polyline.type)) == types.end()) + types.emplace_back(polyline.type); + } + + // nothing to render, return + if (types.empty()) + return true; + + // creates a new volume for each type + for (Type& type : types) + { + GLVolume* volume = new GLVolume(print.gcode_preview.travel.type_colors[type.value].rgba); + if (volume == nullptr) + return false; + else + { + type.volume = volume; + volumes.volumes.emplace_back(volume); + } + } + + // populates volumes + for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) + { + TypesList::iterator type = std::find(types.begin(), types.end(), Type(polyline.type)); + if (type != types.end()) + { + type->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().max.z)); + type->volume->offsets.push_back(type->volume->indexed_vertex_array.quad_indices.size()); + type->volume->offsets.push_back(type->volume->indexed_vertex_array.triangle_indices.size()); + + polyline3_to_verts(polyline.polyline, print.gcode_preview.travel.width, print.gcode_preview.travel.height, *type->volume); + } + } + + return true; +} + +bool _3DScene::_travel_paths_by_feedrate(const Print& print, GLVolumeCollection& volumes) +{ // Helper structure for feedrate struct Feedrate { @@ -1898,134 +2009,114 @@ void _3DScene::_load_gcode_travel_paths(const Print& print, GLVolumeCollection& typedef std::vector<Feedrate> FeedratesList; - size_t initial_volumes_count = volumes.volumes.size(); - s_gcode_preview_data.first_volumes.emplace_back(GCodePreviewData::Travel, 0, (unsigned int)initial_volumes_count); + // colors travels by feedrate - if (print.gcode_preview.extrusion.view_type == GCodeAnalyzer::PreviewData::Extrusion::Feedrate) + // detects feedrates + FeedratesList feedrates; + for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) { - // colors travels by feedrate - - // detects feedrates - FeedratesList feedrates; - for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) - { - if (std::find(feedrates.begin(), feedrates.end(), Feedrate(polyline.feedrate)) == feedrates.end()) - feedrates.emplace_back(polyline.feedrate); - } - - // nothing to render, return - if (feedrates.empty()) - return; - - // creates a new volume for each feedrate - for (Feedrate& feedrate : feedrates) - { - GLVolume* volume = new GLVolume(print.gcode_preview.get_extrusion_feedrate_color(feedrate.value).rgba); - if (volume != nullptr) - { - feedrate.volume = volume; - volumes.volumes.emplace_back(volume); - } - else - { - // an error occourred - restore to previous state and return - if (initial_volumes_count != volumes.volumes.size()) - { - std::vector<GLVolume*>::iterator begin = volumes.volumes.begin() + initial_volumes_count; - std::vector<GLVolume*>::iterator end = volumes.volumes.end(); - for (std::vector<GLVolume*>::iterator it = begin; it < end; ++it) - { - GLVolume* volume = *it; - delete volume; - } - volumes.volumes.erase(begin, end); - return; - } - } - } - - // populates volumes - for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) - { - FeedratesList::iterator feedrate = std::find(feedrates.begin(), feedrates.end(), Feedrate(polyline.feedrate)); - if (feedrate != feedrates.end()) - { - feedrate->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().max.z)); - feedrate->volume->offsets.push_back(feedrate->volume->indexed_vertex_array.quad_indices.size()); - feedrate->volume->offsets.push_back(feedrate->volume->indexed_vertex_array.triangle_indices.size()); - - polyline3_to_verts(polyline.polyline, print.gcode_preview.travel.width, print.gcode_preview.travel.height, *feedrate->volume); - } - } + if (std::find(feedrates.begin(), feedrates.end(), Feedrate(polyline.feedrate)) == feedrates.end()) + feedrates.emplace_back(polyline.feedrate); } - else + + // nothing to render, return + if (feedrates.empty()) + return true; + + // creates a new volume for each feedrate + for (Feedrate& feedrate : feedrates) { - // colors travels by travel type - - // detects types - TypesList types; - for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) + GLVolume* volume = new GLVolume(print.gcode_preview.get_extrusion_feedrate_color(feedrate.value).rgba); + if (volume == nullptr) + return false; + else { - if (std::find(types.begin(), types.end(), Type(polyline.type)) == types.end()) - types.emplace_back(polyline.type); - } - - // nothing to render, return - if (types.empty()) - return; - - // creates a new volume for each type - for (Type& type : types) - { - GLVolume* volume = new GLVolume(print.gcode_preview.travel.type_colors[type.value].rgba); - if (volume != nullptr) - { - type.volume = volume; - volumes.volumes.emplace_back(volume); - } - else - { - // an error occourred - restore to previous state and return - if (initial_volumes_count != volumes.volumes.size()) - { - std::vector<GLVolume*>::iterator begin = volumes.volumes.begin() + initial_volumes_count; - std::vector<GLVolume*>::iterator end = volumes.volumes.end(); - for (std::vector<GLVolume*>::iterator it = begin; it < end; ++it) - { - GLVolume* volume = *it; - delete volume; - } - volumes.volumes.erase(begin, end); - return; - } - } - } - - // populates volumes - for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) - { - TypesList::iterator type = std::find(types.begin(), types.end(), Type(polyline.type)); - if (type != types.end()) - { - type->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().max.z)); - type->volume->offsets.push_back(type->volume->indexed_vertex_array.quad_indices.size()); - type->volume->offsets.push_back(type->volume->indexed_vertex_array.triangle_indices.size()); - - polyline3_to_verts(polyline.polyline, print.gcode_preview.travel.width, print.gcode_preview.travel.height, *type->volume); - } + feedrate.volume = volume; + volumes.volumes.emplace_back(volume); } } - // finalize volumes and sends geometry to gpu - if (volumes.volumes.size() > initial_volumes_count) + // populates volumes + for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) { - for (size_t i = initial_volumes_count; i < volumes.volumes.size(); ++i) + FeedratesList::iterator feedrate = std::find(feedrates.begin(), feedrates.end(), Feedrate(polyline.feedrate)); + if (feedrate != feedrates.end()) { - GLVolume* volume = volumes.volumes[i]; - volume->bounding_box = volume->indexed_vertex_array.bounding_box(); - volume->indexed_vertex_array.finalize_geometry(use_VBOs); + feedrate->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().max.z)); + feedrate->volume->offsets.push_back(feedrate->volume->indexed_vertex_array.quad_indices.size()); + feedrate->volume->offsets.push_back(feedrate->volume->indexed_vertex_array.triangle_indices.size()); + + polyline3_to_verts(polyline.polyline, print.gcode_preview.travel.width, print.gcode_preview.travel.height, *feedrate->volume); } } + + return true; +} + +bool _3DScene::_travel_paths_by_tool(const Print& print, GLVolumeCollection& volumes, const std::vector<float>& tool_colors) +{ + // Helper structure for tool + struct Tool + { + unsigned int value; + GLVolume* volume; + + explicit Tool(unsigned int value) + : value(value) + , volume(nullptr) + { + } + + bool operator == (const Tool& other) const + { + return value == other.value; + } + }; + + typedef std::vector<Tool> ToolsList; + + // colors travels by tool + + // detects tools + ToolsList tools; + for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) + { + if (std::find(tools.begin(), tools.end(), Tool(polyline.extruder_id)) == tools.end()) + tools.emplace_back(polyline.extruder_id); + } + + // nothing to render, return + if (tools.empty()) + return true; + + // creates a new volume for each tool + for (Tool& tool : tools) + { + GLVolume* volume = new GLVolume(tool_colors.data() + tool.value * 4); + if (volume == nullptr) + return false; + else + { + tool.volume = volume; + volumes.volumes.emplace_back(volume); + } + } + + // populates volumes + for (const GCodeAnalyzer::PreviewData::Travel::Polyline& polyline : print.gcode_preview.travel.polylines) + { + ToolsList::iterator tool = std::find(tools.begin(), tools.end(), Tool(polyline.extruder_id)); + if (tool != tools.end()) + { + tool->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().max.z)); + tool->volume->offsets.push_back(tool->volume->indexed_vertex_array.quad_indices.size()); + tool->volume->offsets.push_back(tool->volume->indexed_vertex_array.triangle_indices.size()); + + polyline3_to_verts(polyline.polyline, print.gcode_preview.travel.width, print.gcode_preview.travel.height, *tool->volume); + } + } + + return true; } void _3DScene::_load_gcode_retractions(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) @@ -2128,9 +2219,9 @@ void _3DScene::_update_gcode_volumes_visibility(const Print& print, GLVolumeColl } } -void _3DScene::_generate_legend_texture(const Print& print) +void _3DScene::_generate_legend_texture(const Print& print, const std::vector<float>& tool_colors) { - s_legend_texture.generate_texture(print); + s_legend_texture.generate_texture(print, tool_colors); } } diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 4c73bdb7d..2b7f2de47 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -397,7 +397,7 @@ class _3DScene LegendTexture(); ~LegendTexture(); - bool generate_texture(const Print& print); + bool generate_texture(const Print& print, const std::vector<float>& tool_colors); unsigned int get_texture_id() const; unsigned int get_texture_width() const; @@ -415,7 +415,7 @@ class _3DScene public: static void _glew_init(); - static void load_gcode_preview(const Print* print, GLVolumeCollection* volumes, bool use_VBOs); + static void load_gcode_preview(const Print* print, GLVolumeCollection* volumes, const std::vector<std::string>& str_tool_colors, bool use_VBOs); static unsigned int get_legend_texture_id(); static unsigned int get_legend_texture_width(); @@ -443,9 +443,12 @@ public: private: // generates gcode extrusion paths geometry - static void _load_gcode_extrusion_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); + static void _load_gcode_extrusion_paths(const Print& print, GLVolumeCollection& volumes, const std::vector<float>& tool_colors, bool use_VBOs); // generates gcode travel paths geometry - static void _load_gcode_travel_paths(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); + static void _load_gcode_travel_paths(const Print& print, GLVolumeCollection& volumes, const std::vector<float>& tool_colors, bool use_VBOs); + static bool _travel_paths_by_type(const Print& print, GLVolumeCollection& volumes); + static bool _travel_paths_by_feedrate(const Print& print, GLVolumeCollection& volumes); + static bool _travel_paths_by_tool(const Print& print, GLVolumeCollection& volumes, const std::vector<float>& tool_colors); // generates gcode retractions geometry static void _load_gcode_retractions(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); // generates gcode unretractions geometry @@ -453,7 +456,7 @@ private: // sets gcode geometry visibility according to user selection static void _update_gcode_volumes_visibility(const Print& print, GLVolumeCollection& volumes); // generates the legend texture in dependence of the current shown view type - static void _generate_legend_texture(const Print& print); + static void _generate_legend_texture(const Print& print, const std::vector<float>& tool_colors); }; } diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 6c56a06d9..7520ce6c2 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -195,11 +195,12 @@ _load_wipe_tower_toolpaths(print, volumes, tool_colors, use_VBOs) _3DScene::_load_wipe_tower_toolpaths(print, volumes, tool_colors, use_VBOs != 0); void -load_gcode_preview(print, volumes, use_VBOs) - Print *print; - GLVolumeCollection *volumes; - int use_VBOs; +load_gcode_preview(print, volumes, str_tool_colors, use_VBOs) + Print *print; + GLVolumeCollection *volumes; + std::vector<std::string> str_tool_colors; + int use_VBOs; CODE: - _3DScene::load_gcode_preview(print, volumes, use_VBOs != 0); + _3DScene::load_gcode_preview(print, volumes, str_tool_colors, use_VBOs != 0); %} From 6b14e7cc5417c8f0b7477c0d86ac2e25a101a27c Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Wed, 7 Feb 2018 10:22:35 +0100 Subject: [PATCH 20/23] GCode Preview - Fixed behavior of the feature types combo --- lib/Slic3r/GUI/Plater/3DPreview.pm | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index 2b853dbb3..1f7408b7a 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -72,7 +72,6 @@ sub new { my $combochecklist_features = Wx::ComboCtrl->new(); $combochecklist_features->Create($self, -1, "Feature types", wxDefaultPosition, [200, -1], wxCB_READONLY); - $combochecklist_features->UseAltPopupWindow(); $combochecklist_features->EnablePopupAnimation(0); my $feature_text = "Feature types"; my $feature_items = "Perimeter|External perimeter|Overhang perimeter|Internal infill|Solid infill|Top solid infill|Bridge infill|Gap fill|Skirt|Support material|Support material interface|Wipe tower"; From 3f006dc11a7f18fa9e5a9921432b8267e55ebdcb Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Mon, 12 Feb 2018 09:04:05 +0100 Subject: [PATCH 21/23] GCode Preview - Added objects and wipe tower transparent shells --- lib/Slic3r/GUI/Plater/3DPreview.pm | 9 +++ xs/src/libslic3r/GCode/Analyzer.cpp | 8 ++- xs/src/libslic3r/GCode/Analyzer.hpp | 8 +++ xs/src/libslic3r/Print.cpp | 5 ++ xs/src/libslic3r/Print.hpp | 1 + xs/src/slic3r/GUI/3DScene.cpp | 94 +++++++++++++++++++++++++++++ xs/src/slic3r/GUI/3DScene.hpp | 27 +++++++++ xs/xsp/Print.xsp | 1 + 8 files changed, 152 insertions(+), 1 deletion(-) diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index 1f7408b7a..fb1a9bbfc 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -80,6 +80,7 @@ sub new { my $checkbox_travel = Wx::CheckBox->new($self, -1, "Travel"); my $checkbox_retractions = Wx::CheckBox->new($self, -1, "Retractions"); my $checkbox_unretractions = Wx::CheckBox->new($self, -1, "Unretractions"); + my $checkbox_shells = Wx::CheckBox->new($self, -1, "Shells"); my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL); my $vsizer = Wx::BoxSizer->new(wxVERTICAL); @@ -106,6 +107,8 @@ sub new { $bottom_sizer->Add($checkbox_retractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); $bottom_sizer->AddSpacer(10); $bottom_sizer->Add($checkbox_unretractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + $bottom_sizer->AddSpacer(10); + $bottom_sizer->Add($checkbox_shells, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); my $sizer = Wx::BoxSizer->new(wxHORIZONTAL); $sizer->Add($canvas, 1, wxALL | wxEXPAND, 0); @@ -217,6 +220,12 @@ sub new { $self->refresh_print; $self->auto_zoom(1); }); + EVT_CHECKBOX($self, $checkbox_shells, sub { + $self->print->set_gcode_preview_shells_visible($checkbox_shells->IsChecked()); + $self->auto_zoom(0); + $self->refresh_print; + $self->auto_zoom(1); + }); $self->SetSizer($main_sizer); $self->SetMinSize($self->GetSize); diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp index 0288770b0..c64857566 100644 --- a/xs/src/libslic3r/GCode/Analyzer.cpp +++ b/xs/src/libslic3r/GCode/Analyzer.cpp @@ -298,7 +298,12 @@ void GCodeAnalyzer::PreviewData::Retraction::set_default() { color = Default_Color; is_visible = false; -}; +} + +void GCodeAnalyzer::PreviewData::Shell::set_default() +{ + is_visible = false; +} GCodeAnalyzer::PreviewData::PreviewData() { @@ -311,6 +316,7 @@ void GCodeAnalyzer::PreviewData::set_default() travel.set_default(); retraction.set_default(); unretraction.set_default(); + shell.set_default(); } void GCodeAnalyzer::PreviewData::reset() diff --git a/xs/src/libslic3r/GCode/Analyzer.hpp b/xs/src/libslic3r/GCode/Analyzer.hpp index 34f1537af..6d0213422 100644 --- a/xs/src/libslic3r/GCode/Analyzer.hpp +++ b/xs/src/libslic3r/GCode/Analyzer.hpp @@ -256,10 +256,18 @@ public: void set_default(); }; + struct Shell + { + bool is_visible; + + void set_default(); + }; + Extrusion extrusion; Travel travel; Retraction retraction; Retraction unretraction; + Shell shell; PreviewData(); diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index d0af38327..172b26cc4 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -102,6 +102,11 @@ void Print::set_gcode_preview_unretractions_visible(bool visible) gcode_preview.unretraction.is_visible = visible; } +void Print::set_gcode_preview_shells_visible(bool visible) +{ + gcode_preview.shell.is_visible = visible; +} + PrintRegion* Print::add_region() { regions.push_back(new PrintRegion(this)); diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 4c2284446..0a6c143b9 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -262,6 +262,7 @@ public: void set_gcode_preview_travel_visible(bool visible); void set_gcode_preview_retractions_visible(bool visible); void set_gcode_preview_unretractions_visible(bool visible); + void set_gcode_preview_shells_visible(bool visible); // methods for handling regions PrintRegion* get_region(size_t idx) { return regions.at(idx); } diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 96cbabbe9..553239a6f 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -348,7 +348,32 @@ void GLVolumeCollection::render_VBOs() const GLsizei n_triangles = GLsizei(std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first)); GLsizei n_quads = GLsizei(std::min(volume->indexed_vertex_array.quad_indices_size, volume->qverts_range.second - volume->qverts_range.first)); if (n_triangles + n_quads == 0) + { + if (_render_interleaved_only_volumes.enabled) + { + ::glDisableClientState(GL_VERTEX_ARRAY); + ::glDisableClientState(GL_NORMAL_ARRAY); + ::glEnable(GL_BLEND); + ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + if (color_id >= 0) + { + float color[4]; + ::memcpy((void*)color, (const void*)volume->color, 3 * sizeof(float)); + color[3] = _render_interleaved_only_volumes.alpha; + ::glUniform4fv(color_id, 1, (const GLfloat*)color); + } + else + ::glColor4f(volume->color[0], volume->color[1], volume->color[2], _render_interleaved_only_volumes.alpha); + + volume->render(); + + ::glDisable(GL_BLEND); + ::glEnableClientState(GL_VERTEX_ARRAY); + ::glEnableClientState(GL_NORMAL_ARRAY); + } continue; + } if (color_id >= 0) glUniform4fv(color_id, 1, (const GLfloat*)volume->color); else @@ -387,7 +412,23 @@ void GLVolumeCollection::render_legacy() const GLsizei n_triangles = GLsizei(std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first)); GLsizei n_quads = GLsizei(std::min(volume->indexed_vertex_array.quad_indices_size, volume->qverts_range.second - volume->qverts_range.first)); if (n_triangles + n_quads == 0) + { + if (_render_interleaved_only_volumes.enabled) + { + ::glDisableClientState(GL_VERTEX_ARRAY); + ::glDisableClientState(GL_NORMAL_ARRAY); + ::glEnable(GL_BLEND); + ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + ::glColor4f(volume->color[0], volume->color[1], volume->color[2], _render_interleaved_only_volumes.alpha); + volume->render(); + + ::glDisable(GL_BLEND); + ::glEnableClientState(GL_VERTEX_ARRAY); + ::glEnableClientState(GL_NORMAL_ARRAY); + } continue; + } glColor4f(volume->color[0], volume->color[1], volume->color[2], volume->color[3]); glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), volume->indexed_vertex_array.vertices_and_normals_interleaved.data() + 3); glNormalPointer(GL_FLOAT, 6 * sizeof(float), volume->indexed_vertex_array.vertices_and_normals_interleaved.data()); @@ -1314,6 +1355,9 @@ static inline std::vector<float> parse_colors(const std::vector<std::string> &sc void _3DScene::load_gcode_preview(const Print* print, GLVolumeCollection* volumes, const std::vector<std::string>& str_tool_colors, bool use_VBOs) { + if ((print == nullptr) || (volumes == nullptr)) + return; + if (volumes->empty()) { std::vector<float> tool_colors = parse_colors(str_tool_colors); @@ -1326,9 +1370,17 @@ void _3DScene::load_gcode_preview(const Print* print, GLVolumeCollection* volume _load_gcode_unretractions(*print, *volumes, use_VBOs); if (volumes->empty()) + { reset_legend_texture(); + volumes->set_render_interleaved_only_volumes(GLVolumeCollection::RenderInterleavedOnlyVolumes(false, 0.0f)); + } else + { _generate_legend_texture(*print, tool_colors); + + _load_shells(*print, *volumes, use_VBOs); + volumes->set_render_interleaved_only_volumes(GLVolumeCollection::RenderInterleavedOnlyVolumes(true, 0.25f)); + } } _update_gcode_volumes_visibility(*print, *volumes); @@ -2209,6 +2261,11 @@ void _3DScene::_update_gcode_volumes_visibility(const Print& print, GLVolumeColl volume->is_active = print.gcode_preview.unretraction.is_visible; break; } + case GCodePreviewData::Shell: + { + volume->is_active = print.gcode_preview.shell.is_visible; + break; + } default: { volume->is_active = false; @@ -2224,4 +2281,41 @@ void _3DScene::_generate_legend_texture(const Print& print, const std::vector<fl s_legend_texture.generate_texture(print, tool_colors); } +void _3DScene::_load_shells(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) +{ + size_t initial_volumes_count = volumes.volumes.size(); + s_gcode_preview_data.first_volumes.emplace_back(GCodePreviewData::Shell, 0, (unsigned int)initial_volumes_count); + + if (print.objects.empty()) + // nothing to render, return + return; + + // adds objects' volumes + unsigned int object_id = 0; + for (PrintObject* obj : print.objects) + { + ModelObject* model_obj = obj->model_object(); + + std::vector<int> instance_ids(model_obj->instances.size()); + for (int i = 0; i < model_obj->instances.size(); ++i) + { + instance_ids[i] = i; + } + + for (ModelInstance* instance : model_obj->instances) + { + volumes.load_object(model_obj, object_id, instance_ids, "object", "object", "object", use_VBOs); + } + + ++object_id; + } + + // adds wipe tower's volume + coordf_t max_z = print.objects[0]->model_object()->get_model()->bounding_box().max.z; + const PrintConfig& config = print.config; + unsigned int extruders_count = config.nozzle_diameter.size(); + if ((extruders_count > 1) && config.single_extruder_multi_material && config.wipe_tower && !config.complete_objects) + volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, config.wipe_tower_per_color_wipe * (extruders_count - 1), max_z, use_VBOs); +} + } diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 2b7f2de47..44e5dbea3 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -309,6 +309,28 @@ public: class GLVolumeCollection { +public: + struct RenderInterleavedOnlyVolumes + { + bool enabled; + float alpha; // [0..1] + + RenderInterleavedOnlyVolumes() + : enabled(false) + , alpha(0.0f) + { + } + + RenderInterleavedOnlyVolumes(bool enabled, float alpha) + : enabled(enabled) + , alpha(alpha) + { + } + }; + +private: + RenderInterleavedOnlyVolumes _render_interleaved_only_volumes; + public: std::vector<GLVolume*> volumes; @@ -344,6 +366,8 @@ public: bool empty() const { return volumes.empty(); } void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); } + void set_render_interleaved_only_volumes(const RenderInterleavedOnlyVolumes& render_interleaved_only_volumes) { _render_interleaved_only_volumes = render_interleaved_only_volumes; } + private: GLVolumeCollection(const GLVolumeCollection &other); GLVolumeCollection& operator=(const GLVolumeCollection &); @@ -359,6 +383,7 @@ class _3DScene Travel, Retraction, Unretraction, + Shell, Num_Geometry_Types }; @@ -457,6 +482,8 @@ private: static void _update_gcode_volumes_visibility(const Print& print, GLVolumeCollection& volumes); // generates the legend texture in dependence of the current shown view type static void _generate_legend_texture(const Print& print, const std::vector<float>& tool_colors); + // generates objects and wipe tower geometry + static void _load_shells(const Print& print, GLVolumeCollection& volumes, bool use_VBOs); }; } diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index 4df4a5865..4f870df68 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -171,6 +171,7 @@ _constant() void set_gcode_preview_travel_visible(bool visible); void set_gcode_preview_retractions_visible(bool visible); void set_gcode_preview_unretractions_visible(bool visible); + void set_gcode_preview_shells_visible(bool visible); PrintRegionPtrs* regions() %code%{ RETVAL = &THIS->regions; %}; From f4522cd2fc193d747fbbce566b028ba62ffd0ddd Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Tue, 13 Feb 2018 13:16:23 +0100 Subject: [PATCH 22/23] GCode Preview - Customizable extrusion role colors by editing 3DPreview.pm --- lib/Slic3r/GUI/Plater/3DPreview.pm | 18 +++++++++++++ xs/src/libslic3r/GCode/Analyzer.cpp | 12 +++++++++ xs/src/libslic3r/GCode/Analyzer.hpp | 2 ++ xs/src/libslic3r/Print.cpp | 42 +++++++++++++++++++++++++++++ xs/src/libslic3r/Print.hpp | 12 +++++++++ xs/xsp/Print.xsp | 1 + 6 files changed, 87 insertions(+) diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index fb1a9bbfc..f0175f5a4 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -233,6 +233,24 @@ sub new { # init canvas $self->print($print); + + # sets colors for gcode preview extrusion roles + my @extrusion_roles_colors = ( + 'Perimeter' => 'FF0000', + 'External perimeter' => '00FF00', + 'Overhang perimeter' => '0000FF', + 'Internal infill' => 'FFFF00', + 'Solid infill' => 'FF00FF', + 'Top solid infill' => '00FFFF', + 'Bridge infill' => '7F7F7F', + 'Gap fill' => 'FFFFFF', + 'Skirt' => '7F0000', + 'Support material' => '007F00', + 'Support material interface' => '00007F', + 'Wipe tower' => 'B3E3AB', + ); + $self->print->set_gcode_extrusion_paths_colors(\@extrusion_roles_colors); + $self->reload_print; return $self; diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp index c64857566..02e999bb4 100644 --- a/xs/src/libslic3r/GCode/Analyzer.cpp +++ b/xs/src/libslic3r/GCode/Analyzer.cpp @@ -347,6 +347,18 @@ const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::get_extrusi return extrusion.ranges.feedrate.get_color_at(feedrate); } +void GCodeAnalyzer::PreviewData::set_extrusion_role_color(const std::string& role_name, float red, float green, float blue, float alpha) +{ + for (unsigned int i = 0; i < Extrusion::Num_Extrusion_Roles; ++i) + { + if (role_name == extrusion.role_names[i]) + { + extrusion.role_colors[i] = Color(red, green, blue, alpha); + break; + } + } +} + std::string GCodeAnalyzer::PreviewData::get_legend_title() const { switch (extrusion.view_type) diff --git a/xs/src/libslic3r/GCode/Analyzer.hpp b/xs/src/libslic3r/GCode/Analyzer.hpp index 6d0213422..121360dbc 100644 --- a/xs/src/libslic3r/GCode/Analyzer.hpp +++ b/xs/src/libslic3r/GCode/Analyzer.hpp @@ -279,6 +279,8 @@ public: const Color& get_extrusion_width_color(float width) const; const Color& get_extrusion_feedrate_color(float feedrate) const; + void set_extrusion_role_color(const std::string& role_name, float red, float green, float blue, float alpha); + std::string get_legend_title() const; LegendItemsList get_legend_items(const std::vector<float>& tool_colors) const; }; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 172b26cc4..bf0951f11 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -107,6 +107,48 @@ void Print::set_gcode_preview_shells_visible(bool visible) gcode_preview.shell.is_visible = visible; } +void Print::set_gcode_extrusion_paths_colors(const std::vector<std::string>& colors) +{ + unsigned int size = (unsigned int)colors.size(); + + if (size % 2 != 0) + return; + + for (unsigned int i = 0; i < size; i += 2) + { + const std::string& color_str = colors[i + 1]; + + if (color_str.size() == 6) + { + bool valid = true; + for (int c = 0; c < 6; ++c) + { + if (::isxdigit(color_str[c]) == 0) + { + valid = false; + break; + } + } + + if (valid) + { + unsigned int color; + std::stringstream ss; + ss << std::hex << color_str; + ss >> color; + + float den = 1.0f / 255.0f; + + float r = (float)((color & 0xFF0000) >> 16) * den; + float g = (float)((color & 0x00FF00) >> 8) * den; + float b = (float)(color & 0x0000FF) * den; + + gcode_preview.set_extrusion_role_color(colors[i], r, g, b, 1.0f); + } + } + } +} + PrintRegion* Print::add_region() { regions.push_back(new PrintRegion(this)); diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 0a6c143b9..da94917fc 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -264,6 +264,18 @@ public: void set_gcode_preview_unretractions_visible(bool visible); void set_gcode_preview_shells_visible(bool visible); + // Sets the extrusion path colors from the given strings vector. + // Data in the vector should be formatted as follows: + // std::vector<std::string> role_colors = + // { <role_1>, <color_1>, + // <role_2>, <color_2>, + // <role_3>, <color_3>, + // ... + // <role_N>, <color_N> }; + // where <role_X> should be a string from GCodeAnalyzer::PreviewData::Extrusion::Default_Extrusion_Role_Names[] + // and <color_X> an RGB color in hex format (i.e. red = FF0000) + void set_gcode_extrusion_paths_colors(const std::vector<std::string>& colors); + // methods for handling regions PrintRegion* get_region(size_t idx) { return regions.at(idx); } const PrintRegion* get_region(size_t idx) const { return regions.at(idx); } diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index 4f870df68..5749c20db 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -172,6 +172,7 @@ _constant() void set_gcode_preview_retractions_visible(bool visible); void set_gcode_preview_unretractions_visible(bool visible); void set_gcode_preview_shells_visible(bool visible); + void set_gcode_extrusion_paths_colors(std::vector<std::string> colors); PrintRegionPtrs* regions() %code%{ RETVAL = &THIS->regions; %}; From 6cf82643626c1d8196694cf1cf7f0657fc2134bb Mon Sep 17 00:00:00 2001 From: bubnikv <bubnikv@gmail.com> Date: Tue, 13 Feb 2018 17:46:23 +0100 Subject: [PATCH 23/23] Re-enabled $combochecklist_features->UseAltPopupWindow(), without this line the combo box popup was not reacting to mouse events on Windows 10. --- lib/Slic3r/GUI/Plater/3DPreview.pm | 3 +++ xs/src/slic3r/GUI/GUI.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index f0175f5a4..6f96b8a96 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -72,6 +72,9 @@ sub new { my $combochecklist_features = Wx::ComboCtrl->new(); $combochecklist_features->Create($self, -1, "Feature types", wxDefaultPosition, [200, -1], wxCB_READONLY); + #FIXME If the following line is removed, the combo box popup list will not react to mouse clicks. + # On the other side, with this line the combo box popup cannot be closed by clicking on the combo button on Windows 10. + $combochecklist_features->UseAltPopupWindow(); $combochecklist_features->EnablePopupAnimation(0); my $feature_text = "Feature types"; my $feature_items = "Perimeter|External perimeter|Overhang perimeter|Internal infill|Solid infill|Top solid infill|Bridge infill|Gap fill|Skirt|Support material|Support material interface|Wipe tower"; diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 775cfdcf6..809ee8508 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -227,7 +227,7 @@ int combochecklist_get_flags(wxComboCtrl* comboCtrl) for (unsigned int i = 0; i < popup->GetCount(); ++i) { if (popup->IsChecked(i)) - flags += (int)std::pow(2.0f, (float)i); + flags |= 1 << i; } }