Merge remote-tracking branch 'origin/support_improvements'

This commit is contained in:
bubnikv 2018-09-14 15:12:20 +02:00
commit 4ec4c9364e
35 changed files with 905 additions and 385 deletions

View file

@ -238,7 +238,7 @@ sub _update {
my @expolygons = (); my @expolygons = ();
foreach my $volume (@{$self->{model_object}->volumes}) { foreach my $volume (@{$self->{model_object}->volumes}) {
next if !$volume->mesh; next if !$volume->mesh;
next if $volume->modifier; next if !$volume->model_part;
my $expp = $volume->mesh->slice([ $z_cut ])->[0]; my $expp = $volume->mesh->slice([ $z_cut ])->[0];
push @expolygons, @$expp; push @expolygons, @$expp;
} }

View file

@ -16,6 +16,8 @@ use base 'Wx::Panel';
use constant ICON_OBJECT => 0; use constant ICON_OBJECT => 0;
use constant ICON_SOLIDMESH => 1; use constant ICON_SOLIDMESH => 1;
use constant ICON_MODIFIERMESH => 2; use constant ICON_MODIFIERMESH => 2;
use constant ICON_SUPPORT_ENFORCER => 3;
use constant ICON_SUPPORT_BLOCKER => 4;
sub new { sub new {
my ($class, $parent, %params) = @_; my ($class, $parent, %params) = @_;
@ -35,7 +37,7 @@ sub new {
y => 0, y => 0,
z => 0, z => 0,
}; };
# create TreeCtrl # create TreeCtrl
my $tree = $self->{tree} = Wx::TreeCtrl->new($self, -1, wxDefaultPosition, [300, 100], my $tree = $self->{tree} = Wx::TreeCtrl->new($self, -1, wxDefaultPosition, [300, 100],
wxTR_NO_BUTTONS | wxSUNKEN_BORDER | wxTR_HAS_VARIABLE_ROW_HEIGHT wxTR_NO_BUTTONS | wxSUNKEN_BORDER | wxTR_HAS_VARIABLE_ROW_HEIGHT
@ -46,6 +48,8 @@ sub new {
$self->{tree_icons}->Add(Wx::Bitmap->new(Slic3r::var("brick.png"), wxBITMAP_TYPE_PNG)); # ICON_OBJECT $self->{tree_icons}->Add(Wx::Bitmap->new(Slic3r::var("brick.png"), wxBITMAP_TYPE_PNG)); # ICON_OBJECT
$self->{tree_icons}->Add(Wx::Bitmap->new(Slic3r::var("package.png"), wxBITMAP_TYPE_PNG)); # ICON_SOLIDMESH $self->{tree_icons}->Add(Wx::Bitmap->new(Slic3r::var("package.png"), wxBITMAP_TYPE_PNG)); # ICON_SOLIDMESH
$self->{tree_icons}->Add(Wx::Bitmap->new(Slic3r::var("plugin.png"), wxBITMAP_TYPE_PNG)); # ICON_MODIFIERMESH $self->{tree_icons}->Add(Wx::Bitmap->new(Slic3r::var("plugin.png"), wxBITMAP_TYPE_PNG)); # ICON_MODIFIERMESH
$self->{tree_icons}->Add(Wx::Bitmap->new(Slic3r::var("support_enforcer.png"), wxBITMAP_TYPE_PNG)); # ICON_SUPPORT_ENFORCER
$self->{tree_icons}->Add(Wx::Bitmap->new(Slic3r::var("support_blocker.png"), wxBITMAP_TYPE_PNG)); # ICON_SUPPORT_BLOCKER
my $rootId = $tree->AddRoot("Object", ICON_OBJECT); my $rootId = $tree->AddRoot("Object", ICON_OBJECT);
$tree->SetPlData($rootId, { type => 'object' }); $tree->SetPlData($rootId, { type => 'object' });
@ -89,7 +93,14 @@ sub new {
$self->{btn_move_down}->SetFont($Slic3r::GUI::small_font); $self->{btn_move_down}->SetFont($Slic3r::GUI::small_font);
# part settings panel # part settings panel
$self->{settings_panel} = Slic3r::GUI::Plater::OverrideSettingsPanel->new($self, on_change => sub { $self->{part_settings_changed} = 1; $self->_update_canvas; }); $self->{settings_panel} = Slic3r::GUI::Plater::OverrideSettingsPanel->new($self, on_change => sub {
my ($key, $value) = @_;
wxTheApp->CallAfter(sub {
$self->set_part_type($value) if ($key eq "part_type");
$self->{part_settings_changed} = 1;
$self->_update_canvas;
});
});
my $settings_sizer = Wx::StaticBoxSizer->new($self->{staticbox} = Wx::StaticBox->new($self, -1, "Part Settings"), wxVERTICAL); my $settings_sizer = Wx::StaticBoxSizer->new($self->{staticbox} = Wx::StaticBox->new($self, -1, "Part Settings"), wxVERTICAL);
$settings_sizer->Add($self->{settings_panel}, 1, wxEXPAND | wxALL, 0); $settings_sizer->Add($self->{settings_panel}, 1, wxEXPAND | wxALL, 0);
@ -225,8 +236,11 @@ sub reload_tree {
my $selectedId = $rootId; my $selectedId = $rootId;
foreach my $volume_id (0..$#{$object->volumes}) { foreach my $volume_id (0..$#{$object->volumes}) {
my $volume = $object->volumes->[$volume_id]; my $volume = $object->volumes->[$volume_id];
my $icon =
my $icon = $volume->modifier ? ICON_MODIFIERMESH : ICON_SOLIDMESH; $volume->modifier ? ICON_MODIFIERMESH :
$volume->support_enforcer ? ICON_SUPPORT_ENFORCER :
$volume->support_blocker ? ICON_SUPPORT_BLOCKER :
ICON_SOLIDMESH;
my $itemId = $tree->AppendItem($rootId, $volume->name || $volume_id, $icon); my $itemId = $tree->AppendItem($rootId, $volume->name || $volume_id, $icon);
if ($volume_id == $selected_volume_idx) { if ($volume_id == $selected_volume_idx) {
$selectedId = $itemId; $selectedId = $itemId;
@ -288,6 +302,8 @@ sub selection_changed {
if (my $itemData = $self->get_selection) { if (my $itemData = $self->get_selection) {
my ($config, @opt_keys); my ($config, @opt_keys);
my $type = Slic3r::GUI::Plater::OverrideSettingsPanel->TYPE_OBJECT;
my $support = 0;
if ($itemData->{type} eq 'volume') { if ($itemData->{type} eq 'volume') {
# select volume in 3D preview # select volume in 3D preview
if ($self->{canvas}) { if ($self->{canvas}) {
@ -301,16 +317,24 @@ sub selection_changed {
# attach volume config to settings panel # attach volume config to settings panel
my $volume = $self->{model_object}->volumes->[ $itemData->{volume_id} ]; my $volume = $self->{model_object}->volumes->[ $itemData->{volume_id} ];
if ($volume->modifier) { if (! $volume->model_part) {
$self->{optgroup_movers}->enable; $self->{optgroup_movers}->enable;
if ($volume->support_enforcer || $volume->support_blocker) {
$support = 1;
$type = $volume->support_enforcer ?
Slic3r::GUI::Plater::OverrideSettingsPanel->TYPE_SUPPORT_ENFORCER :
Slic3r::GUI::Plater::OverrideSettingsPanel->TYPE_SUPPORT_BLOCKER;
} else {
$type = Slic3r::GUI::Plater::OverrideSettingsPanel->TYPE_MODIFIER;
}
} else { } else {
$type = Slic3r::GUI::Plater::OverrideSettingsPanel->TYPE_PART;
$self->{optgroup_movers}->disable; $self->{optgroup_movers}->disable;
} }
$config = $volume->config; $config = $volume->config;
$self->{staticbox}->SetLabel('Part Settings'); $self->{staticbox}->SetLabel('Part Settings');
# get default values # get default values
@opt_keys = @{Slic3r::Config::PrintRegion->new->get_keys}; @opt_keys = $support ? () : @{Slic3r::Config::PrintRegion->new->get_keys};
} elsif ($itemData->{type} eq 'object') { } elsif ($itemData->{type} eq 'object') {
# select nothing in 3D preview # select nothing in 3D preview
@ -323,33 +347,54 @@ sub selection_changed {
# get default values # get default values
my $default_config = Slic3r::Config::new_from_defaults_keys(\@opt_keys); my $default_config = Slic3r::Config::new_from_defaults_keys(\@opt_keys);
# decide which settings will be shown by default # decide which settings will be shown by default
if ($itemData->{type} eq 'object') { if ($itemData->{type} eq 'object') {
$config->set_ifndef('wipe_into_objects', 0); $config->set_ifndef('wipe_into_objects', 0);
$config->set_ifndef('wipe_into_infill', 0); $config->set_ifndef('wipe_into_infill', 0);
} }
# append default extruder # append default extruder
push @opt_keys, 'extruder'; if (! $support) {
$default_config->set('extruder', 0); push @opt_keys, 'extruder';
$config->set_ifndef('extruder', 0); $default_config->set('extruder', 0);
$config->set_ifndef('extruder', 0);
}
$self->{settings_panel}->set_type($type);
$self->{settings_panel}->set_default_config($default_config); $self->{settings_panel}->set_default_config($default_config);
$self->{settings_panel}->set_config($config); $self->{settings_panel}->set_config($config);
$self->{settings_panel}->set_opt_keys(\@opt_keys); $self->{settings_panel}->set_opt_keys(\@opt_keys);
# disable minus icon to remove the settings # disable minus icon to remove the settings
if ($itemData->{type} eq 'object') { my $fixed_options =
$self->{settings_panel}->set_fixed_options([qw(extruder), qw(wipe_into_infill), qw(wipe_into_objects)]); ($itemData->{type} eq 'object') ? [qw(extruder), qw(wipe_into_infill), qw(wipe_into_objects)] :
} else { $support ? [] : [qw(extruder)];
$self->{settings_panel}->set_fixed_options([qw(extruder)]); $self->{settings_panel}->set_fixed_options($fixed_options);
}
$self->{settings_panel}->enable; $self->{settings_panel}->enable;
} }
Slic3r::GUI::_3DScene::render($self->{canvas}) if $self->{canvas}; Slic3r::GUI::_3DScene::render($self->{canvas}) if $self->{canvas};
} }
sub set_part_type
{
my ($self, $part_type) = @_;
if (my $itemData = $self->get_selection) {
if ($itemData->{type} eq 'volume') {
my $volume = $self->{model_object}->volumes->[ $itemData->{volume_id} ];
if ($part_type == Slic3r::GUI::Plater::OverrideSettingsPanel->TYPE_MODIFIER ||
$part_type == Slic3r::GUI::Plater::OverrideSettingsPanel->TYPE_PART) {
$volume->set_modifier($part_type == Slic3r::GUI::Plater::OverrideSettingsPanel->TYPE_MODIFIER);
} elsif ($part_type == Slic3r::GUI::Plater::OverrideSettingsPanel->TYPE_SUPPORT_ENFORCER) {
$volume->set_support_enforcer;
} elsif ($part_type == Slic3r::GUI::Plater::OverrideSettingsPanel->TYPE_SUPPORT_BLOCKER) {
$volume->set_support_blocker;
}
# We want the icon of the selected item to be changed as well.
$self->reload_tree($itemData->{volume_id});
}
}
}
sub on_btn_load { sub on_btn_load {
my ($self, $is_modifier) = @_; my ($self, $is_modifier) = @_;

View file

@ -7,15 +7,20 @@ use warnings;
use utf8; use utf8;
use List::Util qw(first); use List::Util qw(first);
use Wx qw(:misc :sizer :button wxTAB_TRAVERSAL wxSUNKEN_BORDER wxBITMAP_TYPE_PNG use Wx qw(:misc :sizer :button :combobox wxTAB_TRAVERSAL wxSUNKEN_BORDER wxBITMAP_TYPE_PNG wxTheApp);
wxTheApp); use Wx::Event qw(EVT_BUTTON EVT_COMBOBOX EVT_LEFT_DOWN EVT_MENU);
use Wx::Event qw(EVT_BUTTON EVT_LEFT_DOWN EVT_MENU);
use base 'Wx::ScrolledWindow'; use base 'Wx::ScrolledWindow';
use constant ICON_MATERIAL => 0; use constant ICON_MATERIAL => 0;
use constant ICON_SOLIDMESH => 1; use constant ICON_SOLIDMESH => 1;
use constant ICON_MODIFIERMESH => 2; use constant ICON_MODIFIERMESH => 2;
use constant TYPE_OBJECT => -1;
use constant TYPE_PART => 0;
use constant TYPE_MODIFIER => 1;
use constant TYPE_SUPPORT_ENFORCER => 2;
use constant TYPE_SUPPORT_BLOCKER => 3;
my %icons = ( my %icons = (
'Advanced' => 'wand.png', 'Advanced' => 'wand.png',
'Extruders' => 'funnel.png', 'Extruders' => 'funnel.png',
@ -36,13 +41,14 @@ sub new {
$self->{config} = Slic3r::Config->new; $self->{config} = Slic3r::Config->new;
# On change callback. # On change callback.
$self->{on_change} = $params{on_change}; $self->{on_change} = $params{on_change};
$self->{type} = TYPE_OBJECT;
$self->{fixed_options} = {}; $self->{fixed_options} = {};
$self->{sizer} = Wx::BoxSizer->new(wxVERTICAL); $self->{sizer} = Wx::BoxSizer->new(wxVERTICAL);
$self->{options_sizer} = Wx::BoxSizer->new(wxVERTICAL); $self->{options_sizer} = Wx::BoxSizer->new(wxVERTICAL);
$self->{sizer}->Add($self->{options_sizer}, 0, wxEXPAND | wxALL, 0); $self->{sizer}->Add($self->{options_sizer}, 0, wxEXPAND | wxALL, 0);
# option selector # option selector
{ {
# create the button # create the button
@ -110,6 +116,16 @@ sub set_opt_keys {
$self->{options} = [ sort { $self->{option_labels}{$a} cmp $self->{option_labels}{$b} } @$opt_keys ]; $self->{options} = [ sort { $self->{option_labels}{$a} cmp $self->{option_labels}{$b} } @$opt_keys ];
} }
sub set_type {
my ($self, $type) = @_;
$self->{type} = $type;
if ($type == TYPE_SUPPORT_ENFORCER || $type == TYPE_SUPPORT_BLOCKER) {
$self->{btn_add}->Hide;
} else {
$self->{btn_add}->Show;
}
}
sub set_fixed_options { sub set_fixed_options {
my ($self, $opt_keys) = @_; my ($self, $opt_keys) = @_;
$self->{fixed_options} = { map {$_ => 1} @$opt_keys }; $self->{fixed_options} = { map {$_ => 1} @$opt_keys };
@ -121,12 +137,28 @@ sub update_optgroup {
$self->{options_sizer}->Clear(1); $self->{options_sizer}->Clear(1);
return if !defined $self->{config}; return if !defined $self->{config};
if ($self->{type} != TYPE_OBJECT) {
my $label = Wx::StaticText->new($self, -1, "Type:"),
my $selection = [ "Part", "Modifier", "Support Enforcer", "Support Blocker" ];
my $field = Wx::ComboBox->new($self, -1, $selection->[$self->{type}], wxDefaultPosition, Wx::Size->new(160, -1), $selection, wxCB_READONLY);
my $sizer = Wx::BoxSizer->new(wxHORIZONTAL);
$sizer->Add($label, 1, wxEXPAND | wxALL, 5);
$sizer->Add($field, 0, wxALL, 5);
EVT_COMBOBOX($self, $field, sub {
my $idx = $field->GetSelection; # get index of selected value
$self->{on_change}->("part_type", $idx) if $self->{on_change};
});
$self->{options_sizer}->Add($sizer, 0, wxEXPAND | wxBOTTOM, 0);
}
my %categories = (); my %categories = ();
foreach my $opt_key (@{$self->{config}->get_keys}) { if ($self->{type} != TYPE_SUPPORT_ENFORCER && $self->{type} != TYPE_SUPPORT_BLOCKER) {
my $category = $Slic3r::Config::Options->{$opt_key}{category}; foreach my $opt_key (@{$self->{config}->get_keys}) {
$categories{$category} ||= []; my $category = $Slic3r::Config::Options->{$opt_key}{category};
push @{$categories{$category}}, $opt_key; $categories{$category} ||= [];
push @{$categories{$category}}, $opt_key;
}
} }
foreach my $category (sort keys %categories) { foreach my $category (sort keys %categories) {
my $optgroup = Slic3r::GUI::ConfigOptionsGroup->new( my $optgroup = Slic3r::GUI::ConfigOptionsGroup->new(

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

View file

@ -1225,8 +1225,10 @@ bool EdgeGrid::Grid::signed_distance(const Point &pt, coord_t search_radius, coo
return true; return true;
} }
Polygons EdgeGrid::Grid::contours_simplified(coord_t offset) const Polygons EdgeGrid::Grid::contours_simplified(coord_t offset, bool fill_holes) const
{ {
assert(std::abs(2 * offset) < m_resolution);
typedef std::unordered_multimap<Point, int, PointHash> EndPointMapType; typedef std::unordered_multimap<Point, int, PointHash> EndPointMapType;
// 0) Prepare a binary grid. // 0) Prepare a binary grid.
size_t cell_rows = m_rows + 2; size_t cell_rows = m_rows + 2;
@ -1237,7 +1239,7 @@ Polygons EdgeGrid::Grid::contours_simplified(coord_t offset) const
cell_inside[r * cell_cols + c] = cell_inside_or_crossing(r - 1, c - 1); cell_inside[r * cell_cols + c] = cell_inside_or_crossing(r - 1, c - 1);
// Fill in empty cells, which have a left / right neighbor filled. // Fill in empty cells, which have a left / right neighbor filled.
// Fill in empty cells, which have the top / bottom neighbor filled. // Fill in empty cells, which have the top / bottom neighbor filled.
{ if (fill_holes) {
std::vector<char> cell_inside2(cell_inside); std::vector<char> cell_inside2(cell_inside);
for (int r = 1; r + 1 < int(cell_rows); ++ r) { for (int r = 1; r + 1 < int(cell_rows); ++ r) {
for (int c = 1; c + 1 < int(cell_cols); ++ c) { for (int c = 1; c + 1 < int(cell_cols); ++ c) {

View file

@ -58,7 +58,7 @@ public:
const size_t cols() const { return m_cols; } const size_t cols() const { return m_cols; }
// For supports: Contours enclosing the rasterized edges. // For supports: Contours enclosing the rasterized edges.
Polygons contours_simplified(coord_t offset) const; Polygons contours_simplified(coord_t offset, bool fill_holes) const;
protected: protected:
struct Cell { struct Cell {

View file

@ -61,12 +61,11 @@ ExPolygonCollection::rotate(double angle, const Point &center)
} }
template <class T> template <class T>
bool bool ExPolygonCollection::contains(const T &item) const
ExPolygonCollection::contains(const T &item) const
{ {
for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it) { for (const ExPolygon &poly : this->expolygons)
if (it->contains(item)) return true; if (poly.contains(item))
} return true;
return false; return false;
} }
template bool ExPolygonCollection::contains<Point>(const Point &item) const; template bool ExPolygonCollection::contains<Point>(const Point &item) const;

View file

@ -91,6 +91,8 @@ public:
// Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm. // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
virtual double min_mm3_per_mm() const = 0; virtual double min_mm3_per_mm() const = 0;
virtual Polyline as_polyline() const = 0; virtual Polyline as_polyline() const = 0;
virtual void collect_polylines(Polylines &dst) const = 0;
virtual Polylines as_polylines() const { Polylines dst; this->collect_polylines(dst); return dst; }
virtual double length() const = 0; virtual double length() const = 0;
virtual double total_volume() const = 0; virtual double total_volume() const = 0;
}; };
@ -123,8 +125,11 @@ public:
ExtrusionPath* clone() const { return new ExtrusionPath (*this); } ExtrusionPath* clone() const { return new ExtrusionPath (*this); }
void reverse() { this->polyline.reverse(); } void reverse() { this->polyline.reverse(); }
Point first_point() const { return this->polyline.points.front(); } Point first_point() const override { return this->polyline.points.front(); }
Point last_point() const { return this->polyline.points.back(); } Point last_point() const override { return this->polyline.points.back(); }
size_t size() const { return this->polyline.size(); }
bool empty() const { return this->polyline.empty(); }
bool is_closed() const { return ! this->empty() && this->polyline.points.front() == this->polyline.points.back(); }
// Produce a list of extrusion paths into retval by clipping this path by ExPolygonCollection. // Produce a list of extrusion paths into retval by clipping this path by ExPolygonCollection.
// Currently not used. // Currently not used.
void intersect_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const; void intersect_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const;
@ -133,8 +138,8 @@ public:
void subtract_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const; void subtract_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const;
void clip_end(double distance); void clip_end(double distance);
void simplify(double tolerance); void simplify(double tolerance);
virtual double length() const; double length() const override;
virtual ExtrusionRole role() const { return m_role; } ExtrusionRole role() const override { return m_role; }
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width. // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width.
// Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const; void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const;
@ -149,7 +154,8 @@ public:
// Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm. // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
double min_mm3_per_mm() const { return this->mm3_per_mm; } double min_mm3_per_mm() const { return this->mm3_per_mm; }
Polyline as_polyline() const { return this->polyline; } Polyline as_polyline() const { return this->polyline; }
virtual double total_volume() const { return mm3_per_mm * unscale(length()); } void collect_polylines(Polylines &dst) const override { if (! this->polyline.empty()) dst.emplace_back(this->polyline); }
double total_volume() const override { return mm3_per_mm * unscale(length()); }
private: private:
void _inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const; void _inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const;
@ -178,10 +184,10 @@ public:
bool can_reverse() const { return true; } bool can_reverse() const { return true; }
ExtrusionMultiPath* clone() const { return new ExtrusionMultiPath(*this); } ExtrusionMultiPath* clone() const { return new ExtrusionMultiPath(*this); }
void reverse(); void reverse();
Point first_point() const { return this->paths.front().polyline.points.front(); } Point first_point() const override { return this->paths.front().polyline.points.front(); }
Point last_point() const { return this->paths.back().polyline.points.back(); } Point last_point() const override { return this->paths.back().polyline.points.back(); }
virtual double length() const; double length() const override;
virtual ExtrusionRole role() const { return this->paths.empty() ? erNone : this->paths.front().role(); } ExtrusionRole role() const override { return this->paths.empty() ? erNone : this->paths.front().role(); }
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width. // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width.
// Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const; void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const;
@ -196,7 +202,8 @@ public:
// Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm. // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
double min_mm3_per_mm() const; double min_mm3_per_mm() const;
Polyline as_polyline() const; Polyline as_polyline() const;
virtual double total_volume() const { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; } void collect_polylines(Polylines &dst) const override { Polyline pl = this->as_polyline(); if (! pl.empty()) dst.emplace_back(std::move(pl)); }
double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; }
}; };
// Single continuous extrusion loop, possibly with varying extrusion thickness, extrusion height or bridging / non bridging. // Single continuous extrusion loop, possibly with varying extrusion thickness, extrusion height or bridging / non bridging.
@ -218,18 +225,18 @@ public:
bool make_clockwise(); bool make_clockwise();
bool make_counter_clockwise(); bool make_counter_clockwise();
void reverse(); void reverse();
Point first_point() const { return this->paths.front().polyline.points.front(); } Point first_point() const override { return this->paths.front().polyline.points.front(); }
Point last_point() const { assert(first_point() == this->paths.back().polyline.points.back()); return first_point(); } Point last_point() const override { assert(first_point() == this->paths.back().polyline.points.back()); return first_point(); }
Polygon polygon() const; Polygon polygon() const;
virtual double length() const; double length() const override;
bool split_at_vertex(const Point &point); bool split_at_vertex(const Point &point);
void split_at(const Point &point, bool prefer_non_overhang); void split_at(const Point &point, bool prefer_non_overhang);
void clip_end(double distance, ExtrusionPaths* paths) const; void clip_end(double distance, ExtrusionPaths* paths) const;
// Test, whether the point is extruded by a bridging flow. // Test, whether the point is extruded by a bridging flow.
// This used to be used to avoid placing seams on overhangs, but now the EdgeGrid is used instead. // This used to be used to avoid placing seams on overhangs, but now the EdgeGrid is used instead.
bool has_overhang_point(const Point &point) const; bool has_overhang_point(const Point &point) const;
virtual ExtrusionRole role() const { return this->paths.empty() ? erNone : this->paths.front().role(); } ExtrusionRole role() const override { return this->paths.empty() ? erNone : this->paths.front().role(); }
ExtrusionLoopRole loop_role() const { return m_loop_role; } ExtrusionLoopRole loop_role() const { return m_loop_role; }
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width. // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width.
// Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const; void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const;
@ -244,7 +251,8 @@ public:
// Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm. // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
double min_mm3_per_mm() const; double min_mm3_per_mm() const;
Polyline as_polyline() const { return this->polygon().split_at_first_point(); } Polyline as_polyline() const { return this->polygon().split_at_first_point(); }
virtual double total_volume() const { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; } void collect_polylines(Polylines &dst) const override { Polyline pl = this->as_polyline(); if (! pl.empty()) dst.emplace_back(std::move(pl)); }
double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; }
private: private:
ExtrusionLoopRole m_loop_role; ExtrusionLoopRole m_loop_role;

View file

@ -24,7 +24,7 @@ public:
explicit operator ExtrusionPaths() const; explicit operator ExtrusionPaths() const;
bool is_collection() const { return true; }; bool is_collection() const { return true; };
virtual ExtrusionRole role() const { ExtrusionRole role() const override {
ExtrusionRole out = erNone; ExtrusionRole out = erNone;
for (const ExtrusionEntity *ee : entities) { for (const ExtrusionEntity *ee : entities) {
ExtrusionRole er = ee->role(); ExtrusionRole er = ee->role();
@ -66,11 +66,11 @@ public:
Point last_point() const { return this->entities.back()->last_point(); } Point last_point() const { return this->entities.back()->last_point(); }
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width. // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width.
// Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
virtual void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const; void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const override;
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion spacing. // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion spacing.
// Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
// Useful to calculate area of an infill, which has been really filled in by a 100% rectilinear infill. // Useful to calculate area of an infill, which has been really filled in by a 100% rectilinear infill.
virtual void polygons_covered_by_spacing(Polygons &out, const float scaled_epsilon) const; void polygons_covered_by_spacing(Polygons &out, const float scaled_epsilon) const override;
Polygons polygons_covered_by_width(const float scaled_epsilon = 0.f) const Polygons polygons_covered_by_width(const float scaled_epsilon = 0.f) const
{ Polygons out; this->polygons_covered_by_width(out, scaled_epsilon); return out; } { Polygons out; this->polygons_covered_by_width(out, scaled_epsilon); return out; }
Polygons polygons_covered_by_spacing(const float scaled_epsilon = 0.f) const Polygons polygons_covered_by_spacing(const float scaled_epsilon = 0.f) const
@ -79,14 +79,20 @@ public:
void flatten(ExtrusionEntityCollection* retval) const; void flatten(ExtrusionEntityCollection* retval) const;
ExtrusionEntityCollection flatten() const; ExtrusionEntityCollection flatten() const;
double min_mm3_per_mm() const; double min_mm3_per_mm() const;
virtual double total_volume() const {double volume=0.; for (const auto& ent : entities) volume+=ent->total_volume(); return volume; } double total_volume() const override { double volume=0.; for (const auto& ent : entities) volume+=ent->total_volume(); return volume; }
// Following methods shall never be called on an ExtrusionEntityCollection. // Following methods shall never be called on an ExtrusionEntityCollection.
Polyline as_polyline() const { Polyline as_polyline() const {
CONFESS("Calling as_polyline() on a ExtrusionEntityCollection"); CONFESS("Calling as_polyline() on a ExtrusionEntityCollection");
return Polyline(); return Polyline();
}; };
virtual double length() const {
void collect_polylines(Polylines &dst) const override {
for (ExtrusionEntity* extrusion_entity : this->entities)
extrusion_entity->collect_polylines(dst);
}
double length() const override {
CONFESS("Calling length() on a ExtrusionEntityCollection"); CONFESS("Calling length() on a ExtrusionEntityCollection");
return 0.; return 0.;
} }

View file

@ -115,7 +115,8 @@ Flow support_material_flow(const PrintObject *object, float layer_height)
// if object->config.support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component. // if object->config.support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
float(object->print()->config.nozzle_diameter.get_at(object->config.support_material_extruder-1)), float(object->print()->config.nozzle_diameter.get_at(object->config.support_material_extruder-1)),
(layer_height > 0.f) ? layer_height : float(object->config.layer_height.value), (layer_height > 0.f) ? layer_height : float(object->config.layer_height.value),
false); // bridge_flow_ratio
0.f);
} }
Flow support_material_1st_layer_flow(const PrintObject *object, float layer_height) Flow support_material_1st_layer_flow(const PrintObject *object, float layer_height)
@ -127,7 +128,8 @@ Flow support_material_1st_layer_flow(const PrintObject *object, float layer_heig
(width.value > 0) ? width : object->config.extrusion_width, (width.value > 0) ? width : object->config.extrusion_width,
float(object->print()->config.nozzle_diameter.get_at(object->config.support_material_extruder-1)), float(object->print()->config.nozzle_diameter.get_at(object->config.support_material_extruder-1)),
(layer_height > 0.f) ? layer_height : float(object->config.first_layer_height.get_abs_value(object->config.layer_height.value)), (layer_height > 0.f) ? layer_height : float(object->config.first_layer_height.get_abs_value(object->config.layer_height.value)),
false); // bridge_flow_ratio
0.f);
} }
Flow support_material_interface_flow(const PrintObject *object, float layer_height) Flow support_material_interface_flow(const PrintObject *object, float layer_height)
@ -139,7 +141,8 @@ Flow support_material_interface_flow(const PrintObject *object, float layer_heig
// if object->config.support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component. // if object->config.support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
float(object->print()->config.nozzle_diameter.get_at(object->config.support_material_interface_extruder-1)), float(object->print()->config.nozzle_diameter.get_at(object->config.support_material_interface_extruder-1)),
(layer_height > 0.f) ? layer_height : float(object->config.layer_height.value), (layer_height > 0.f) ? layer_height : float(object->config.layer_height.value),
false); // bridge_flow_ratio
0.f);
} }
} }

View file

@ -71,6 +71,7 @@ const char* VOLUME_TYPE = "volume";
const char* NAME_KEY = "name"; const char* NAME_KEY = "name";
const char* MODIFIER_KEY = "modifier"; const char* MODIFIER_KEY = "modifier";
const char* VOLUME_TYPE_KEY = "volume_type";
const unsigned int VALID_OBJECT_TYPES_COUNT = 1; const unsigned int VALID_OBJECT_TYPES_COUNT = 1;
const char* VALID_OBJECT_TYPES[] = const char* VALID_OBJECT_TYPES[] =
@ -1499,7 +1500,9 @@ namespace Slic3r {
if (metadata.key == NAME_KEY) if (metadata.key == NAME_KEY)
volume->name = metadata.value; volume->name = metadata.value;
else if ((metadata.key == MODIFIER_KEY) && (metadata.value == "1")) else if ((metadata.key == MODIFIER_KEY) && (metadata.value == "1"))
volume->modifier = true; volume->set_type(ModelVolume::PARAMETER_MODIFIER);
else if (metadata.key == VOLUME_TYPE_KEY)
volume->set_type(ModelVolume::type_from_string(metadata.value));
else else
volume->config.set_deserialize(metadata.key, metadata.value); volume->config.set_deserialize(metadata.key, metadata.value);
} }
@ -2015,9 +2018,12 @@ namespace Slic3r {
if (!volume->name.empty()) if (!volume->name.empty())
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << NAME_KEY << "\" " << VALUE_ATTR << "=\"" << xml_escape(volume->name) << "\"/>\n"; stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << NAME_KEY << "\" " << VALUE_ATTR << "=\"" << xml_escape(volume->name) << "\"/>\n";
// stores volume's modifier field // stores volume's modifier field (legacy, to support old slicers)
if (volume->modifier) if (volume->is_modifier())
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MODIFIER_KEY << "\" " << VALUE_ATTR << "=\"1\"/>\n"; stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MODIFIER_KEY << "\" " << VALUE_ATTR << "=\"1\"/>\n";
// stores volume's type (overrides the modifier field above)
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << VOLUME_TYPE_KEY << "\" " <<
VALUE_ATTR << "=\"" << ModelVolume::type_to_string(volume->type()) << "\"/>\n";
// stores volume's config data // stores volume's config data
for (const std::string& key : volume->config.keys()) for (const std::string& key : volume->config.keys())

View file

@ -458,9 +458,14 @@ void AMFParserContext::endElement(const char * /* name */)
p = end + 1; p = end + 1;
} }
m_object->layer_height_profile_valid = true; m_object->layer_height_profile_valid = true;
} else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume && strcmp(opt_key, "modifier") == 0) { } else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume) {
// Is this volume a modifier volume? if (strcmp(opt_key, "modifier") == 0) {
m_volume->modifier = atoi(m_value[1].c_str()) == 1; // Is this volume a modifier volume?
// "modifier" flag comes first in the XML file, so it may be later overwritten by the "type" flag.
m_volume->set_type((atoi(m_value[1].c_str()) == 1) ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART);
} else if (strcmp(opt_key, "volume_type") == 0) {
m_volume->set_type(ModelVolume::type_from_string(m_value[1]));
}
} }
} else if (m_path.size() == 3) { } else if (m_path.size() == 3) {
if (m_path[1] == NODE_TYPE_MATERIAL) { if (m_path[1] == NODE_TYPE_MATERIAL) {
@ -781,8 +786,9 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c
stream << " <metadata type=\"slic3r." << key << "\">" << volume->config.serialize(key) << "</metadata>\n"; stream << " <metadata type=\"slic3r." << key << "\">" << volume->config.serialize(key) << "</metadata>\n";
if (!volume->name.empty()) if (!volume->name.empty())
stream << " <metadata type=\"name\">" << xml_escape(volume->name) << "</metadata>\n"; stream << " <metadata type=\"name\">" << xml_escape(volume->name) << "</metadata>\n";
if (volume->modifier) if (volume->is_modifier())
stream << " <metadata type=\"slic3r.modifier\">1</metadata>\n"; stream << " <metadata type=\"slic3r.modifier\">1</metadata>\n";
stream << " <metadata type=\"slic3r.volume_type\">" << ModelVolume::type_to_string(volume->type()) << "</metadata>\n";
for (int i = 0; i < volume->mesh.stl.stats.number_of_facets; ++i) { for (int i = 0; i < volume->mesh.stl.stats.number_of_facets; ++i) {
stream << " <triangle>\n"; stream << " <triangle>\n";
for (int j = 0; j < 3; ++j) for (int j = 0; j < 3; ++j)

View file

@ -21,45 +21,37 @@ class LayerRegion
friend class Layer; friend class Layer;
public: public:
Layer* layer() { return this->_layer; } Layer* layer() { return this->_layer; }
const Layer* layer() const { return this->_layer; } const Layer* layer() const { return this->_layer; }
PrintRegion* region() { return this->_region; } PrintRegion* region() { return this->_region; }
const PrintRegion* region() const { return this->_region; } const PrintRegion* region() const { return this->_region; }
// collection of surfaces generated by slicing the original geometry // Collection of surfaces generated by slicing the original geometry, divided by type top/bottom/internal.
// divided by type top/bottom/internal SurfaceCollection slices;
SurfaceCollection slices;
// collection of extrusion paths/loops filling gaps
// These fills are generated by the perimeter generator.
// They are not printed on their own, but they are copied to this->fills during infill generation.
ExtrusionEntityCollection thin_fills;
// Unspecified fill polygons, used for overhang detection ("ensure vertical wall thickness feature") // Unspecified fill polygons, used for overhang detection ("ensure vertical wall thickness feature")
// and for re-starting of infills. // and for re-starting of infills.
ExPolygons fill_expolygons; ExPolygons fill_expolygons;
// collection of surfaces for infill generation // collection of surfaces for infill generation
SurfaceCollection fill_surfaces; SurfaceCollection fill_surfaces;
// Collection of extrusion paths/loops filling gaps.
// These fills are generated by the perimeter generator.
// They are not printed on their own, but they are copied to this->fills during infill generation.
ExtrusionEntityCollection thin_fills;
// Collection of perimeter surfaces. This is a cached result of diff(slices, fill_surfaces). // Collection of expolygons representing the bridged areas (thus not needing support material).
// While not necessary, the memory consumption is meager and it speeds up calculation. //FIXME Not used as of now.
// The perimeter_surfaces keep the IDs of the slices (top/bottom/) Polygons bridged;
SurfaceCollection perimeter_surfaces;
// collection of expolygons representing the bridged areas (thus not
// needing support material)
Polygons bridged;
// collection of polylines representing the unsupported bridge edges // collection of polylines representing the unsupported bridge edges
PolylineCollection unsupported_bridge_edges; PolylineCollection unsupported_bridge_edges;
// ordered collection of extrusion paths/loops to build all perimeters // Ordered collection of extrusion paths/loops to build all perimeters.
// (this collection contains only ExtrusionEntityCollection objects) // This collection contains only ExtrusionEntityCollection objects.
ExtrusionEntityCollection perimeters; ExtrusionEntityCollection perimeters;
// Ordered collection of extrusion paths to fill surfaces.
// ordered collection of extrusion paths to fill surfaces // This collection contains only ExtrusionEntityCollection objects.
// (this collection contains only ExtrusionEntityCollection objects) ExtrusionEntityCollection fills;
ExtrusionEntityCollection fills;
Flow flow(FlowRole role, bool bridge = false, double width = -1) const; Flow flow(FlowRole role, bool bridge = false, double width = -1) const;
void slices_to_fill_surfaces_clipped(); void slices_to_fill_surfaces_clipped();

View file

@ -15,8 +15,7 @@
namespace Slic3r { namespace Slic3r {
Flow Flow LayerRegion::flow(FlowRole role, bool bridge, double width) const
LayerRegion::flow(FlowRole role, bool bridge, double width) const
{ {
return this->_region->flow( return this->_region->flow(
role, role,
@ -51,8 +50,7 @@ void LayerRegion::slices_to_fill_surfaces_clipped()
} }
} }
void void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces)
LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces)
{ {
this->perimeters.clear(); this->perimeters.clear();
this->thin_fills.clear(); this->thin_fills.clear();
@ -340,8 +338,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer)
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
} }
void void LayerRegion::prepare_fill_surfaces()
LayerRegion::prepare_fill_surfaces()
{ {
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
export_region_slices_to_svg_debug("2_prepare_fill_surfaces-initial"); export_region_slices_to_svg_debug("2_prepare_fill_surfaces-initial");
@ -382,8 +379,7 @@ LayerRegion::prepare_fill_surfaces()
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
} }
double double LayerRegion::infill_area_threshold() const
LayerRegion::infill_area_threshold() const
{ {
double ss = this->flow(frSolidInfill).scaled_spacing(); double ss = this->flow(frSolidInfill).scaled_spacing();
return ss*ss; return ss*ss;

View file

@ -609,7 +609,7 @@ const BoundingBoxf3& ModelObject::bounding_box() const
if (! m_bounding_box_valid) { if (! m_bounding_box_valid) {
BoundingBoxf3 raw_bbox; BoundingBoxf3 raw_bbox;
for (const ModelVolume *v : this->volumes) for (const ModelVolume *v : this->volumes)
if (! v->modifier) if (v->is_model_part())
// mesh.bounding_box() returns a cached value. // mesh.bounding_box() returns a cached value.
raw_bbox.merge(v->mesh.bounding_box()); raw_bbox.merge(v->mesh.bounding_box());
BoundingBoxf3 bb; BoundingBoxf3 bb;
@ -641,7 +641,7 @@ TriangleMesh ModelObject::raw_mesh() const
{ {
TriangleMesh mesh; TriangleMesh mesh;
for (const ModelVolume *v : this->volumes) for (const ModelVolume *v : this->volumes)
if (! v->modifier) if (v->is_model_part())
mesh.merge(v->mesh); mesh.merge(v->mesh);
return mesh; return mesh;
} }
@ -652,7 +652,7 @@ BoundingBoxf3 ModelObject::raw_bounding_box() const
{ {
BoundingBoxf3 bb; BoundingBoxf3 bb;
for (const ModelVolume *v : this->volumes) for (const ModelVolume *v : this->volumes)
if (! v->modifier) { if (v->is_model_part()) {
if (this->instances.empty()) CONFESS("Can't call raw_bounding_box() with no instances"); if (this->instances.empty()) CONFESS("Can't call raw_bounding_box() with no instances");
bb.merge(this->instances.front()->transform_mesh_bounding_box(&v->mesh, true)); bb.merge(this->instances.front()->transform_mesh_bounding_box(&v->mesh, true));
} }
@ -664,7 +664,7 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_
{ {
BoundingBoxf3 bb; BoundingBoxf3 bb;
for (ModelVolume *v : this->volumes) for (ModelVolume *v : this->volumes)
if (! v->modifier) if (v->is_model_part())
bb.merge(this->instances[instance_idx]->transform_mesh_bounding_box(&v->mesh, dont_translate)); bb.merge(this->instances[instance_idx]->transform_mesh_bounding_box(&v->mesh, dont_translate));
return bb; return bb;
} }
@ -675,7 +675,7 @@ void ModelObject::center_around_origin()
// center this object around the origin // center this object around the origin
BoundingBoxf3 bb; BoundingBoxf3 bb;
for (ModelVolume *v : this->volumes) for (ModelVolume *v : this->volumes)
if (! v->modifier) if (v->is_model_part())
bb.merge(v->mesh.bounding_box()); bb.merge(v->mesh.bounding_box());
// first align to origin on XYZ // first align to origin on XYZ
@ -779,7 +779,7 @@ size_t ModelObject::facets_count() const
{ {
size_t num = 0; size_t num = 0;
for (const ModelVolume *v : this->volumes) for (const ModelVolume *v : this->volumes)
if (! v->modifier) if (v->is_model_part())
num += v->mesh.stl.stats.number_of_facets; num += v->mesh.stl.stats.number_of_facets;
return num; return num;
} }
@ -787,7 +787,7 @@ size_t ModelObject::facets_count() const
bool ModelObject::needed_repair() const bool ModelObject::needed_repair() const
{ {
for (const ModelVolume *v : this->volumes) for (const ModelVolume *v : this->volumes)
if (! v->modifier && v->mesh.needed_repair()) if (v->is_model_part() && v->mesh.needed_repair())
return true; return true;
return false; return false;
} }
@ -803,7 +803,7 @@ void ModelObject::cut(coordf_t z, Model* model) const
lower->input_file = ""; lower->input_file = "";
for (ModelVolume *volume : this->volumes) { for (ModelVolume *volume : this->volumes) {
if (volume->modifier) { if (! volume->is_model_part()) {
// don't cut modifiers // don't cut modifiers
upper->add_volume(*volume); upper->add_volume(*volume);
lower->add_volume(*volume); lower->add_volume(*volume);
@ -855,7 +855,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
ModelVolume* new_volume = new_object->add_volume(*mesh); ModelVolume* new_volume = new_object->add_volume(*mesh);
new_volume->name = volume->name; new_volume->name = volume->name;
new_volume->config = volume->config; new_volume->config = volume->config;
new_volume->modifier = volume->modifier; new_volume->set_type(volume->type());
new_volume->material_id(volume->material_id()); new_volume->material_id(volume->material_id());
new_objects->push_back(new_object); new_objects->push_back(new_object);
@ -869,7 +869,7 @@ void ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_
{ {
for (const ModelVolume* vol : this->volumes) for (const ModelVolume* vol : this->volumes)
{ {
if (!vol->modifier) if (vol->is_model_part())
{ {
for (ModelInstance* inst : this->instances) for (ModelInstance* inst : this->instances)
{ {
@ -973,6 +973,37 @@ const TriangleMesh& ModelVolume::get_convex_hull() const
return m_convex_hull; return m_convex_hull;
} }
ModelVolume::Type ModelVolume::type_from_string(const std::string &s)
{
// Legacy support
if (s == "0")
return MODEL_PART;
if (s == "1")
return PARAMETER_MODIFIER;
// New type (supporting the support enforcers & blockers)
if (s == "ModelPart")
return MODEL_PART;
if (s == "ParameterModifier")
return PARAMETER_MODIFIER;
if (s == "SupportEnforcer")
return SUPPORT_ENFORCER;
if (s == "SupportBlocker")
return SUPPORT_BLOCKER;
}
std::string ModelVolume::type_to_string(const Type t)
{
switch (t) {
case MODEL_PART: return "ModelPart";
case PARAMETER_MODIFIER: return "ParameterModifier";
case SUPPORT_ENFORCER: return "SupportEnforcer";
case SUPPORT_BLOCKER: return "SupportBlocker";
default:
assert(false);
return "ModelPart";
}
}
// Split this volume, append the result to the object owning this volume. // Split this volume, append the result to the object owning this volume.
// Return the number of volumes created from this one. // Return the number of volumes created from this one.
// This is useful to assign different materials to different volumes of an object. // This is useful to assign different materials to different volumes of an object.

View file

@ -165,15 +165,27 @@ public:
// Configuration parameters specific to an object model geometry or a modifier volume, // Configuration parameters specific to an object model geometry or a modifier volume,
// overriding the global Slic3r settings and the ModelObject settings. // overriding the global Slic3r settings and the ModelObject settings.
DynamicPrintConfig config; DynamicPrintConfig config;
// Is it an object to be printed, or a modifier volume?
bool modifier; enum Type {
MODEL_TYPE_INVALID = -1,
MODEL_PART = 0,
PARAMETER_MODIFIER,
SUPPORT_ENFORCER,
SUPPORT_BLOCKER,
};
// A parent object owning this modifier volume. // A parent object owning this modifier volume.
ModelObject* get_object() const { return this->object; }; ModelObject* get_object() const { return this->object; };
Type type() const { return m_type; }
void set_type(const Type t) { m_type = t; }
bool is_model_part() const { return m_type == MODEL_PART; }
bool is_modifier() const { return m_type == PARAMETER_MODIFIER; }
bool is_support_enforcer() const { return m_type == SUPPORT_ENFORCER; }
bool is_support_blocker() const { return m_type == SUPPORT_BLOCKER; }
t_model_material_id material_id() const { return this->_material_id; } t_model_material_id material_id() const { return this->_material_id; }
void material_id(t_model_material_id material_id); void material_id(t_model_material_id material_id);
ModelMaterial* material() const; ModelMaterial* material() const;
void set_material(t_model_material_id material_id, const ModelMaterial &material); void set_material(t_model_material_id material_id, const ModelMaterial &material);
// Split this volume, append the result to the object owning this volume. // Split this volume, append the result to the object owning this volume.
// Return the number of volumes created from this one. // Return the number of volumes created from this one.
// This is useful to assign different materials to different volumes of an object. // This is useful to assign different materials to different volumes of an object.
@ -184,24 +196,30 @@ public:
void calculate_convex_hull(); void calculate_convex_hull();
const TriangleMesh& get_convex_hull() const; const TriangleMesh& get_convex_hull() const;
// Helpers for loading / storing into AMF / 3MF files.
static Type type_from_string(const std::string &s);
static std::string type_to_string(const Type t);
private: private:
// Parent object owning this ModelVolume. // Parent object owning this ModelVolume.
ModelObject* object; ModelObject* object;
t_model_material_id _material_id; // Is it an object to be printed, or a modifier volume?
Type m_type;
t_model_material_id _material_id;
ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), modifier(false), object(object) ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(MODEL_PART), object(object)
{ {
if (mesh.stl.stats.number_of_facets > 1) if (mesh.stl.stats.number_of_facets > 1)
calculate_convex_hull(); calculate_convex_hull();
} }
ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) : mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), modifier(false), object(object) {} ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) : mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), m_type(MODEL_PART), object(object) {}
ModelVolume(ModelObject *object, const ModelVolume &other) : ModelVolume(ModelObject *object, const ModelVolume &other) :
name(other.name), mesh(other.mesh), m_convex_hull(other.m_convex_hull), config(other.config), modifier(other.modifier), object(object) name(other.name), mesh(other.mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object)
{ {
this->material_id(other.material_id()); this->material_id(other.material_id());
} }
ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) : ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) :
name(other.name), mesh(std::move(mesh)), config(other.config), modifier(other.modifier), object(object) name(other.name), mesh(std::move(mesh)), config(other.config), m_type(other.m_type), object(object)
{ {
this->material_id(other.material_id()); this->material_id(other.material_id());
if (mesh.stl.stats.number_of_facets > 1) if (mesh.stl.stats.number_of_facets > 1)

View file

@ -34,8 +34,10 @@ public:
Point first_point() const; Point first_point() const;
virtual Point last_point() const = 0; virtual Point last_point() const = 0;
virtual Lines lines() const = 0; virtual Lines lines() const = 0;
size_t size() const { return points.size(); }
bool empty() const { return points.empty(); }
double length() const; double length() const;
bool is_valid() const { return this->points.size() >= 2; } bool is_valid() const { return this->points.size() >= 2; }
int find_point(const Point &point) const; int find_point(const Point &point) const;
bool has_boundary_point(const Point &point) const; bool has_boundary_point(const Point &point) const;

View file

@ -103,6 +103,12 @@ inline void polygons_rotate(Polygons &polys, double angle)
p.rotate(cos_angle, sin_angle); p.rotate(cos_angle, sin_angle);
} }
inline void polygons_reverse(Polygons &polys)
{
for (Polygon &p : polys)
p.reverse();
}
inline Points to_points(const Polygon &poly) inline Points to_points(const Polygon &poly)
{ {
return poly.points; return poly.points;

View file

@ -193,23 +193,19 @@ Polyline::split_at(const Point &point, Polyline* p1, Polyline* p2) const
} }
} }
bool bool Polyline::is_straight() const
Polyline::is_straight() const
{ {
/* Check that each segment's direction is equal to the line connecting // Check that each segment's direction is equal to the line connecting
first point and last point. (Checking each line against the previous // first point and last point. (Checking each line against the previous
one would cause the error to accumulate.) */ // one would cause the error to accumulate.)
double dir = Line(this->first_point(), this->last_point()).direction(); double dir = Line(this->first_point(), this->last_point()).direction();
for (const auto &line: this->lines())
Lines lines = this->lines(); if (! line.parallel_to(dir))
for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) { return false;
if (!line->parallel_to(dir)) return false;
}
return true; return true;
} }
std::string std::string Polyline::wkt() const
Polyline::wkt() const
{ {
std::ostringstream wkt; std::ostringstream wkt;
wkt << "LINESTRING(("; wkt << "LINESTRING((";

View file

@ -362,9 +362,12 @@ void Print::add_model_object(ModelObject* model_object, int idx)
// Invalidate all print steps. // Invalidate all print steps.
this->invalidate_all_steps(); this->invalidate_all_steps();
for (size_t volume_id = 0; volume_id < model_object->volumes.size(); ++ volume_id) { size_t volume_id = 0;
for (const ModelVolume *volume : model_object->volumes) {
if (! volume->is_model_part() && ! volume->is_modifier())
continue;
// Get the config applied to this volume. // Get the config applied to this volume.
PrintRegionConfig config = this->_region_config_from_model_volume(*model_object->volumes[volume_id]); PrintRegionConfig config = this->_region_config_from_model_volume(*volume);
// Find an existing print region with the same config. // Find an existing print region with the same config.
size_t region_id = size_t(-1); size_t region_id = size_t(-1);
for (size_t i = 0; i < this->regions.size(); ++ i) for (size_t i = 0; i < this->regions.size(); ++ i)
@ -379,6 +382,7 @@ void Print::add_model_object(ModelObject* model_object, int idx)
} }
// Assign volume to a region. // Assign volume to a region.
object->add_region_volume(region_id, volume_id); object->add_region_volume(region_id, volume_id);
++ volume_id;
} }
// Apply config to print object. // Apply config to print object.
@ -853,7 +857,7 @@ void Print::auto_assign_extruders(ModelObject* model_object) const
for (size_t volume_id = 0; volume_id < model_object->volumes.size(); ++ volume_id) { for (size_t volume_id = 0; volume_id < model_object->volumes.size(); ++ volume_id) {
ModelVolume *volume = model_object->volumes[volume_id]; ModelVolume *volume = model_object->volumes[volume_id];
//FIXME Vojtech: This assigns an extruder ID even to a modifier volume, if it has a material assigned. //FIXME Vojtech: This assigns an extruder ID even to a modifier volume, if it has a material assigned.
if (! volume->material_id().empty() && ! volume->config.has("extruder")) if ((volume->is_model_part() || volume->is_modifier()) && ! volume->material_id().empty() && ! volume->config.has("extruder"))
volume->config.opt<ConfigOptionInt>("extruder", true)->value = int(volume_id + 1); volume->config.opt<ConfigOptionInt>("extruder", true)->value = int(volume_id + 1);
} }
} }

View file

@ -80,7 +80,10 @@ public:
Print* print() { return this->_print; } Print* print() { return this->_print; }
Flow flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const; Flow flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const;
// Average diameter of nozzles participating on extruding this region.
coordf_t nozzle_dmr_avg(const PrintConfig &print_config) const; coordf_t nozzle_dmr_avg(const PrintConfig &print_config) const;
// Average diameter of nozzles participating on extruding this region.
coordf_t bridging_height_avg(const PrintConfig &print_config) const;
private: private:
Print* _print; Print* _print;
@ -211,6 +214,10 @@ public:
bool is_printable() const { return !this->_shifted_copies.empty(); } bool is_printable() const { return !this->_shifted_copies.empty(); }
// Helpers to slice support enforcer / blocker meshes by the support generator.
std::vector<ExPolygons> slice_support_enforcers() const;
std::vector<ExPolygons> slice_support_blockers() const;
private: private:
Print* _print; Print* _print;
ModelObject* _model_object; ModelObject* _model_object;
@ -222,6 +229,7 @@ private:
~PrintObject() {} ~PrintObject() {}
std::vector<ExPolygons> _slice_region(size_t region_id, const std::vector<float> &z, bool modifier); std::vector<ExPolygons> _slice_region(size_t region_id, const std::vector<float> &z, bool modifier);
std::vector<ExPolygons> _slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const;
}; };
typedef std::vector<PrintObject*> PrintObjectPtrs; typedef std::vector<PrintObject*> PrintObjectPtrs;

View file

@ -1696,6 +1696,14 @@ PrintConfigDef::PrintConfigDef()
def->cli = "support-material!"; def->cli = "support-material!";
def->default_value = new ConfigOptionBool(false); def->default_value = new ConfigOptionBool(false);
def = this->add("support_material_auto", coBool);
def->label = L("Auto generated supports");
def->category = L("Support material");
def->tooltip = L("If checked, supports will be generated automatically based on the overhang threshold value."\
" If unchecked, supports will be generated inside the \"Support Enforcer\" volumes only.");
def->cli = "support-material-auto!";
def->default_value = new ConfigOptionBool(true);
def = this->add("support_material_xy_spacing", coFloatOrPercent); def = this->add("support_material_xy_spacing", coFloatOrPercent);
def->label = L("XY separation between an object and its support"); def->label = L("XY separation between an object and its support");
def->category = L("Support material"); def->category = L("Support material");
@ -1734,7 +1742,7 @@ PrintConfigDef::PrintConfigDef()
"for the first object layer."); "for the first object layer.");
def->sidetext = L("mm"); def->sidetext = L("mm");
def->cli = "support-material-contact-distance=f"; def->cli = "support-material-contact-distance=f";
def->min = 0; // def->min = 0;
def->enum_values.push_back("0"); def->enum_values.push_back("0");
def->enum_values.push_back("0.2"); def->enum_values.push_back("0.2");
def->enum_labels.push_back((boost::format("0 (%1%)") % L("soluble")).str()); def->enum_labels.push_back((boost::format("0 (%1%)") % L("soluble")).str());

View file

@ -323,6 +323,7 @@ public:
ConfigOptionFloatOrPercent extrusion_width; ConfigOptionFloatOrPercent extrusion_width;
ConfigOptionFloatOrPercent first_layer_height; ConfigOptionFloatOrPercent first_layer_height;
ConfigOptionBool infill_only_where_needed; ConfigOptionBool infill_only_where_needed;
// Force the generation of solid shells between adjacent materials/volumes.
ConfigOptionBool interface_shells; ConfigOptionBool interface_shells;
ConfigOptionFloat layer_height; ConfigOptionFloat layer_height;
ConfigOptionInt raft_layers; ConfigOptionInt raft_layers;
@ -330,6 +331,9 @@ public:
// ConfigOptionFloat seam_preferred_direction; // ConfigOptionFloat seam_preferred_direction;
// ConfigOptionFloat seam_preferred_direction_jitter; // ConfigOptionFloat seam_preferred_direction_jitter;
ConfigOptionBool support_material; ConfigOptionBool support_material;
// Automatic supports (generated based on support_material_threshold).
ConfigOptionBool support_material_auto;
// Direction of the support pattern (in XY plane).
ConfigOptionFloat support_material_angle; ConfigOptionFloat support_material_angle;
ConfigOptionBool support_material_buildplate_only; ConfigOptionBool support_material_buildplate_only;
ConfigOptionFloat support_material_contact_distance; ConfigOptionFloat support_material_contact_distance;
@ -339,12 +343,15 @@ public:
ConfigOptionBool support_material_interface_contact_loops; ConfigOptionBool support_material_interface_contact_loops;
ConfigOptionInt support_material_interface_extruder; ConfigOptionInt support_material_interface_extruder;
ConfigOptionInt support_material_interface_layers; ConfigOptionInt support_material_interface_layers;
// Spacing between interface lines (the hatching distance). Set zero to get a solid interface.
ConfigOptionFloat support_material_interface_spacing; ConfigOptionFloat support_material_interface_spacing;
ConfigOptionFloatOrPercent support_material_interface_speed; ConfigOptionFloatOrPercent support_material_interface_speed;
ConfigOptionEnum<SupportMaterialPattern> support_material_pattern; ConfigOptionEnum<SupportMaterialPattern> support_material_pattern;
// Spacing between support material lines (the hatching distance).
ConfigOptionFloat support_material_spacing; ConfigOptionFloat support_material_spacing;
ConfigOptionFloat support_material_speed; ConfigOptionFloat support_material_speed;
ConfigOptionBool support_material_synchronize_layers; ConfigOptionBool support_material_synchronize_layers;
// Overhang angle threshold.
ConfigOptionInt support_material_threshold; ConfigOptionInt support_material_threshold;
ConfigOptionBool support_material_with_sheath; ConfigOptionBool support_material_with_sheath;
ConfigOptionFloatOrPercent support_material_xy_spacing; ConfigOptionFloatOrPercent support_material_xy_spacing;
@ -367,6 +374,7 @@ protected:
// OPT_PTR(seam_preferred_direction); // OPT_PTR(seam_preferred_direction);
// OPT_PTR(seam_preferred_direction_jitter); // OPT_PTR(seam_preferred_direction_jitter);
OPT_PTR(support_material); OPT_PTR(support_material);
OPT_PTR(support_material_auto);
OPT_PTR(support_material_angle); OPT_PTR(support_material_angle);
OPT_PTR(support_material_buildplate_only); OPT_PTR(support_material_buildplate_only);
OPT_PTR(support_material_contact_distance); OPT_PTR(support_material_contact_distance);
@ -414,10 +422,12 @@ public:
ConfigOptionInt infill_every_layers; ConfigOptionInt infill_every_layers;
ConfigOptionFloatOrPercent infill_overlap; ConfigOptionFloatOrPercent infill_overlap;
ConfigOptionFloat infill_speed; ConfigOptionFloat infill_speed;
// Detect bridging perimeters
ConfigOptionBool overhangs; ConfigOptionBool overhangs;
ConfigOptionInt perimeter_extruder; ConfigOptionInt perimeter_extruder;
ConfigOptionFloatOrPercent perimeter_extrusion_width; ConfigOptionFloatOrPercent perimeter_extrusion_width;
ConfigOptionFloat perimeter_speed; ConfigOptionFloat perimeter_speed;
// Total number of perimeters.
ConfigOptionInt perimeters; ConfigOptionInt perimeters;
ConfigOptionFloatOrPercent small_perimeter_speed; ConfigOptionFloatOrPercent small_perimeter_speed;
ConfigOptionFloat solid_infill_below_area; ConfigOptionFloat solid_infill_below_area;
@ -425,6 +435,7 @@ public:
ConfigOptionFloatOrPercent solid_infill_extrusion_width; ConfigOptionFloatOrPercent solid_infill_extrusion_width;
ConfigOptionInt solid_infill_every_layers; ConfigOptionInt solid_infill_every_layers;
ConfigOptionFloatOrPercent solid_infill_speed; ConfigOptionFloatOrPercent solid_infill_speed;
// Detect thin walls.
ConfigOptionBool thin_walls; ConfigOptionBool thin_walls;
ConfigOptionFloatOrPercent top_infill_extrusion_width; ConfigOptionFloatOrPercent top_infill_extrusion_width;
ConfigOptionInt top_solid_layers; ConfigOptionInt top_solid_layers;

View file

@ -172,6 +172,7 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
steps.emplace_back(posSlice); steps.emplace_back(posSlice);
} else if ( } else if (
opt_key == "support_material" opt_key == "support_material"
|| opt_key == "support_material_auto"
|| opt_key == "support_material_angle" || opt_key == "support_material_angle"
|| opt_key == "support_material_buildplate_only" || opt_key == "support_material_buildplate_only"
|| opt_key == "support_material_enforce_layers" || opt_key == "support_material_enforce_layers"
@ -1320,29 +1321,62 @@ end:
std::vector<ExPolygons> PrintObject::_slice_region(size_t region_id, const std::vector<float> &z, bool modifier) std::vector<ExPolygons> PrintObject::_slice_region(size_t region_id, const std::vector<float> &z, bool modifier)
{ {
std::vector<ExPolygons> layers; std::vector<const ModelVolume*> volumes;
if (region_id < this->region_volumes.size()) { if (region_id < this->region_volumes.size()) {
std::vector<int> &volumes = this->region_volumes[region_id]; for (int volume_id : this->region_volumes[region_id]) {
if (! volumes.empty()) { const ModelVolume *volume = this->model_object()->volumes[volume_id];
// Compose mesh. if (modifier ? volume->is_modifier() : volume->is_model_part())
//FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them. volumes.emplace_back(volume);
TriangleMesh mesh; }
for (int volume_id : volumes) { }
ModelVolume *volume = this->model_object()->volumes[volume_id]; return this->_slice_volumes(z, volumes);
if (volume->modifier == modifier) }
mesh.merge(volume->mesh);
} std::vector<ExPolygons> PrintObject::slice_support_enforcers() const
if (mesh.stl.stats.number_of_facets > 0) { {
// transform mesh std::vector<const ModelVolume*> volumes;
// we ignore the per-instance transformations currently and only for (const ModelVolume *volume : this->model_object()->volumes)
// consider the first one if (volume->is_support_enforcer())
this->model_object()->instances.front()->transform_mesh(&mesh, true); volumes.emplace_back(volume);
// align mesh to Z = 0 (it should be already aligned actually) and apply XY shift std::vector<float> zs;
mesh.translate(- float(unscale(this->_copies_shift.x)), - float(unscale(this->_copies_shift.y)), -float(this->model_object()->bounding_box().min.z)); zs.reserve(this->layers.size());
// perform actual slicing for (const Layer *l : this->layers)
TriangleMeshSlicer mslicer(&mesh); zs.emplace_back(l->slice_z);
mslicer.slice(z, &layers); return this->_slice_volumes(zs, volumes);
} }
std::vector<ExPolygons> PrintObject::slice_support_blockers() const
{
std::vector<const ModelVolume*> volumes;
for (const ModelVolume *volume : this->model_object()->volumes)
if (volume->is_support_blocker())
volumes.emplace_back(volume);
std::vector<float> zs;
zs.reserve(this->layers.size());
for (const Layer *l : this->layers)
zs.emplace_back(l->slice_z);
return this->_slice_volumes(zs, volumes);
}
std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const
{
std::vector<ExPolygons> layers;
if (! volumes.empty()) {
// Compose mesh.
//FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
TriangleMesh mesh;
for (const ModelVolume *v : volumes)
mesh.merge(v->mesh);
if (mesh.stl.stats.number_of_facets > 0) {
// transform mesh
// we ignore the per-instance transformations currently and only
// consider the first one
this->model_object()->instances.front()->transform_mesh(&mesh, true);
// align mesh to Z = 0 (it should be already aligned actually) and apply XY shift
mesh.translate(- float(unscale(this->_copies_shift.x)), - float(unscale(this->_copies_shift.y)), -float(this->model_object()->bounding_box().min.z));
// perform actual slicing
TriangleMeshSlicer mslicer(&mesh);
mslicer.slice(z, &layers);
} }
} }
return layers; return layers;

View file

@ -57,4 +57,9 @@ coordf_t PrintRegion::nozzle_dmr_avg(const PrintConfig &print_config) const
print_config.nozzle_diameter.get_at(this->config.solid_infill_extruder.value - 1)) / 3.; print_config.nozzle_diameter.get_at(this->config.solid_infill_extruder.value - 1)) / 3.;
} }
coordf_t PrintRegion::bridging_height_avg(const PrintConfig &print_config) const
{
return this->nozzle_dmr_avg(print_config) * sqrt(this->config.bridge_flow_ratio.value);
}
} }

View file

@ -224,9 +224,9 @@ std::vector<coordf_t> layer_height_profile_adaptive(
// 1) Initialize the SlicingAdaptive class with the object meshes. // 1) Initialize the SlicingAdaptive class with the object meshes.
SlicingAdaptive as; SlicingAdaptive as;
as.set_slicing_parameters(slicing_params); as.set_slicing_parameters(slicing_params);
for (ModelVolumePtrs::const_iterator it = volumes.begin(); it != volumes.end(); ++ it) for (const ModelVolume *volume : volumes)
if (! (*it)->modifier) if (volume->is_model_part())
as.add_mesh(&(*it)->mesh); as.add_mesh(&volume->mesh);
as.prepare(); as.prepare();
// 2) Generate layers using the algorithm of @platsch // 2) Generate layers using the algorithm of @platsch

File diff suppressed because it is too large Load diff

View file

@ -12,6 +12,7 @@ class PrintConfig;
class PrintObjectConfig; class PrintObjectConfig;
// how much we extend support around the actual contact area // how much we extend support around the actual contact area
//FIXME this should be dependent on the nozzle diameter!
#define SUPPORT_MATERIAL_MARGIN 1.5 #define SUPPORT_MATERIAL_MARGIN 1.5
// This class manages raft and supports for a single PrintObject. // This class manages raft and supports for a single PrintObject.
@ -71,6 +72,21 @@ public:
overhang_polygons = nullptr; overhang_polygons = nullptr;
} }
void reset() {
layer_type = sltUnknown;
print_z = 0.;
bottom_z = 0.;
height = 0.;
idx_object_layer_above = size_t(-1);
idx_object_layer_below = size_t(-1);
bridging = false;
polygons.clear();
delete contact_polygons;
contact_polygons = nullptr;
delete overhang_polygons;
overhang_polygons = nullptr;
}
bool operator==(const MyLayer &layer2) const { bool operator==(const MyLayer &layer2) const {
return print_z == layer2.print_z && height == layer2.height && bridging == layer2.bridging; return print_z == layer2.print_z && height == layer2.height && bridging == layer2.bridging;
} }

View file

@ -37,6 +37,11 @@ public:
void clear() { surfaces.clear(); } void clear() { surfaces.clear(); }
bool empty() const { return surfaces.empty(); } bool empty() const { return surfaces.empty(); }
bool has(SurfaceType type) const {
for (const Surface &surface : this->surfaces)
if (surface.surface_type == type) return true;
return false;
}
void set(const SurfaceCollection &coll) { surfaces = coll.surfaces; } void set(const SurfaceCollection &coll) { surfaces = coll.surfaces; }
void set(SurfaceCollection &&coll) { surfaces = std::move(coll.surfaces); } void set(SurfaceCollection &&coll) { surfaces = std::move(coll.surfaces); }

View file

@ -622,7 +622,7 @@ std::vector<int> GLVolumeCollection::load_object(
const ModelVolume *model_volume = model_object->volumes[volume_idx]; const ModelVolume *model_volume = model_object->volumes[volume_idx];
int extruder_id = -1; int extruder_id = -1;
if (!model_volume->modifier) if (model_volume->is_model_part())
{ {
extruder_id = model_volume->config.has("extruder") ? model_volume->config.option("extruder")->getInt() : 0; extruder_id = model_volume->config.has("extruder") ? model_volume->config.option("extruder")->getInt() : 0;
if (extruder_id == 0) if (extruder_id == 0)
@ -635,7 +635,16 @@ std::vector<int> GLVolumeCollection::load_object(
volumes_idx.push_back(int(this->volumes.size())); volumes_idx.push_back(int(this->volumes.size()));
float color[4]; float color[4];
memcpy(color, colors[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3); memcpy(color, colors[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3);
color[3] = model_volume->modifier ? 0.5f : 1.f; if (model_volume->is_support_blocker()) {
color[0] = 1.0f;
color[1] = 0.2f;
color[2] = 0.2f;
} else if (model_volume->is_support_enforcer()) {
color[0] = 0.2f;
color[1] = 0.2f;
color[2] = 1.0f;
}
color[3] = model_volume->is_model_part() ? 1.f : 0.5f;
this->volumes.emplace_back(new GLVolume(color)); this->volumes.emplace_back(new GLVolume(color));
GLVolume &v = *this->volumes.back(); GLVolume &v = *this->volumes.back();
if (use_VBOs) if (use_VBOs)
@ -658,15 +667,15 @@ std::vector<int> GLVolumeCollection::load_object(
else if (drag_by == "instance") else if (drag_by == "instance")
v.drag_group_id = obj_idx * 1000 + instance_idx; v.drag_group_id = obj_idx * 1000 + instance_idx;
if (!model_volume->modifier) if (model_volume->is_model_part())
{ {
v.set_convex_hull(model_volume->get_convex_hull()); v.set_convex_hull(model_volume->get_convex_hull());
v.layer_height_texture = layer_height_texture; v.layer_height_texture = layer_height_texture;
if (extruder_id != -1) if (extruder_id != -1)
v.extruder_id = extruder_id; v.extruder_id = extruder_id;
} }
v.is_modifier = model_volume->modifier; v.is_modifier = ! model_volume->is_model_part();
v.shader_outside_printer_detection_enabled = !model_volume->modifier; v.shader_outside_printer_detection_enabled = model_volume->is_model_part();
v.set_origin(Pointf3(instance->offset.x, instance->offset.y, 0.0)); v.set_origin(Pointf3(instance->offset.x, instance->offset.y, 0.0));
v.set_angle_z(instance->rotation); v.set_angle_z(instance->rotation);
v.set_scale_factor(instance->scaling_factor); v.set_scale_factor(instance->scaling_factor);

View file

@ -292,7 +292,7 @@ const std::vector<std::string>& Preset::print_options()
"top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed", "top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed",
"bridge_speed", "gap_fill_speed", "travel_speed", "first_layer_speed", "perimeter_acceleration", "infill_acceleration", "bridge_speed", "gap_fill_speed", "travel_speed", "first_layer_speed", "perimeter_acceleration", "infill_acceleration",
"bridge_acceleration", "first_layer_acceleration", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "bridge_acceleration", "first_layer_acceleration", "default_acceleration", "skirts", "skirt_distance", "skirt_height",
"min_skirt_length", "brim_width", "support_material", "support_material_threshold", "support_material_enforce_layers", "min_skirt_length", "brim_width", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers",
"raft_layers", "support_material_pattern", "support_material_with_sheath", "support_material_spacing", "raft_layers", "support_material_pattern", "support_material_with_sheath", "support_material_spacing",
"support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers",
"support_material_interface_spacing", "support_material_interface_contact_loops", "support_material_contact_distance", "support_material_interface_spacing", "support_material_interface_contact_loops", "support_material_contact_distance",

View file

@ -847,6 +847,7 @@ void TabPrint::build()
page = add_options_page(_(L("Support material")), "building.png"); page = add_options_page(_(L("Support material")), "building.png");
optgroup = page->new_optgroup(_(L("Support material"))); optgroup = page->new_optgroup(_(L("Support material")));
optgroup->append_single_option_line("support_material"); optgroup->append_single_option_line("support_material");
optgroup->append_single_option_line("support_material_auto");
optgroup->append_single_option_line("support_material_threshold"); optgroup->append_single_option_line("support_material_threshold");
optgroup->append_single_option_line("support_material_enforce_layers"); optgroup->append_single_option_line("support_material_enforce_layers");
@ -1183,13 +1184,15 @@ void TabPrint::update()
bool have_raft = m_config->opt_int("raft_layers") > 0; bool have_raft = m_config->opt_int("raft_layers") > 0;
bool have_support_material = m_config->opt_bool("support_material") || have_raft; bool have_support_material = m_config->opt_bool("support_material") || have_raft;
bool have_support_material_auto = have_support_material && m_config->opt_bool("support_material_auto");
bool have_support_interface = m_config->opt_int("support_material_interface_layers") > 0; bool have_support_interface = m_config->opt_int("support_material_interface_layers") > 0;
bool have_support_soluble = have_support_material && m_config->opt_float("support_material_contact_distance") == 0; bool have_support_soluble = have_support_material && m_config->opt_float("support_material_contact_distance") == 0;
for (auto el : {"support_material_threshold", "support_material_pattern", "support_material_with_sheath", for (auto el : {"support_material_pattern", "support_material_with_sheath",
"support_material_spacing", "support_material_angle", "support_material_interface_layers", "support_material_spacing", "support_material_angle", "support_material_interface_layers",
"dont_support_bridges", "support_material_extrusion_width", "support_material_contact_distance", "dont_support_bridges", "support_material_extrusion_width", "support_material_contact_distance",
"support_material_xy_spacing" }) "support_material_xy_spacing" })
get_field(el)->toggle(have_support_material); get_field(el)->toggle(have_support_material);
get_field("support_material_threshold")->toggle(have_support_material_auto);
for (auto el : {"support_material_interface_spacing", "support_material_interface_extruder", for (auto el : {"support_material_interface_spacing", "support_material_interface_extruder",
"support_material_interface_speed", "support_material_interface_contact_loops" }) "support_material_interface_speed", "support_material_interface_contact_loops" })

View file

@ -17,8 +17,6 @@
%code%{ RETVAL = &THIS->thin_fills; %}; %code%{ RETVAL = &THIS->thin_fills; %};
Ref<SurfaceCollection> fill_surfaces() Ref<SurfaceCollection> fill_surfaces()
%code%{ RETVAL = &THIS->fill_surfaces; %}; %code%{ RETVAL = &THIS->fill_surfaces; %};
Ref<SurfaceCollection> perimeter_surfaces()
%code%{ RETVAL = &THIS->perimeter_surfaces; %};
Polygons bridged() Polygons bridged()
%code%{ RETVAL = THIS->bridged; %}; %code%{ RETVAL = THIS->bridged; %};
Ref<PolylineCollection> unsupported_bridge_edges() Ref<PolylineCollection> unsupported_bridge_edges()

View file

@ -340,9 +340,19 @@ ModelMaterial::attributes()
%code%{ RETVAL = &THIS->mesh; %}; %code%{ RETVAL = &THIS->mesh; %};
bool modifier() bool modifier()
%code%{ RETVAL = THIS->modifier; %}; %code%{ RETVAL = THIS->is_modifier(); %};
void set_modifier(bool modifier) void set_modifier(bool modifier)
%code%{ THIS->modifier = modifier; %}; %code%{ THIS->set_type(modifier ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART); %};
bool model_part()
%code%{ RETVAL = THIS->is_model_part(); %};
bool support_enforcer()
%code%{ RETVAL = THIS->is_support_enforcer(); %};
void set_support_enforcer()
%code%{ THIS->set_type(ModelVolume::SUPPORT_ENFORCER); %};
bool support_blocker()
%code%{ RETVAL = THIS->is_support_blocker(); %};
void set_support_blocker()
%code%{ THIS->set_type(ModelVolume::SUPPORT_BLOCKER); %};
size_t split(unsigned int max_extruders); size_t split(unsigned int max_extruders);