gcode preview - first installment - wip
This commit is contained in:
parent
696d420dc8
commit
0f4bec8af0
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -122,16 +122,20 @@ sub load_print {
|
||||
}
|
||||
|
||||
if ($self->IsShown) {
|
||||
# load skirt and brim
|
||||
$self->canvas->load_print_toolpaths($self->print);
|
||||
# ===================== ENRICO_GCODE_PREVIEW ==================================================
|
||||
$self->canvas->load_gcode_preview($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;
|
||||
}
|
||||
# # 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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
@ -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(); }
|
||||
|
@ -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()))
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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_ */
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)); }
|
||||
|
@ -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
|
||||
//############################################################################################################
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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); }
|
||||
|
@ -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
|
||||
|
||||
|
@ -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(
|
||||
@ -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
|
||||
//############################################################################################################
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
//############################################################################################################
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
%}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user