New support material pattern: pillars!
This commit is contained in:
parent
499b34dea1
commit
3e93a14912
@ -4,7 +4,7 @@ use Moo;
|
|||||||
use List::Util qw(sum min max);
|
use List::Util qw(sum min max);
|
||||||
use Slic3r::ExtrusionPath ':roles';
|
use Slic3r::ExtrusionPath ':roles';
|
||||||
use Slic3r::Flow ':roles';
|
use Slic3r::Flow ':roles';
|
||||||
use Slic3r::Geometry qw(scale scaled_epsilon PI rad2deg deg2rad);
|
use Slic3r::Geometry qw(scale scaled_epsilon PI rad2deg deg2rad convex_hull);
|
||||||
use Slic3r::Geometry::Clipper qw(offset diff union union_ex intersection offset_ex offset2
|
use Slic3r::Geometry::Clipper qw(offset diff union union_ex intersection offset_ex offset2
|
||||||
intersection_pl);
|
intersection_pl);
|
||||||
use Slic3r::Surface ':types';
|
use Slic3r::Surface ':types';
|
||||||
@ -23,6 +23,10 @@ use constant MARGIN => 1.5;
|
|||||||
# increment used to reach MARGIN in steps to avoid trespassing thin objects
|
# increment used to reach MARGIN in steps to avoid trespassing thin objects
|
||||||
use constant MARGIN_STEP => MARGIN/3;
|
use constant MARGIN_STEP => MARGIN/3;
|
||||||
|
|
||||||
|
# generate a tree-like structure to save material
|
||||||
|
use constant PILLAR_SIZE => 2.5;
|
||||||
|
use constant PILLAR_SPACING => 10;
|
||||||
|
|
||||||
sub generate {
|
sub generate {
|
||||||
my ($self, $object) = @_;
|
my ($self, $object) = @_;
|
||||||
|
|
||||||
@ -40,7 +44,7 @@ sub generate {
|
|||||||
|
|
||||||
# We now know the upper and lower boundaries for our support material object
|
# We now know the upper and lower boundaries for our support material object
|
||||||
# (@$contact_z and @$top_z), so we can generate intermediate layers.
|
# (@$contact_z and @$top_z), so we can generate intermediate layers.
|
||||||
my ($support_z) = $self->support_layers_z(
|
my $support_z = $self->support_layers_z(
|
||||||
[ sort keys %$contact ],
|
[ sort keys %$contact ],
|
||||||
[ sort keys %$top ],
|
[ sort keys %$top ],
|
||||||
max(map $_->height, @{$object->layers})
|
max(map $_->height, @{$object->layers})
|
||||||
@ -49,14 +53,21 @@ sub generate {
|
|||||||
# If we wanted to apply some special logic to the first support layers lying on
|
# If we wanted to apply some special logic to the first support layers lying on
|
||||||
# object's top surfaces this is the place to detect them
|
# object's top surfaces this is the place to detect them
|
||||||
|
|
||||||
|
my $shape = [];
|
||||||
|
if ($self->object_config->support_material_pattern eq 'pillars') {
|
||||||
|
$self->generate_pillars_shape($contact, $support_z, $shape);
|
||||||
|
}
|
||||||
|
|
||||||
# Propagate contact layers downwards to generate interface layers
|
# Propagate contact layers downwards to generate interface layers
|
||||||
my ($interface) = $self->generate_interface_layers($support_z, $contact, $top);
|
my ($interface) = $self->generate_interface_layers($support_z, $contact, $top);
|
||||||
$self->clip_with_object($interface, $support_z, $object);
|
$self->clip_with_object($interface, $support_z, $object);
|
||||||
|
$self->clip_with_shape($interface, $shape) if @$shape;
|
||||||
|
|
||||||
# Propagate contact layers and interface layers downwards to generate
|
# Propagate contact layers and interface layers downwards to generate
|
||||||
# the main support layers.
|
# the main support layers.
|
||||||
my ($base) = $self->generate_base_layers($support_z, $contact, $interface, $top);
|
my ($base) = $self->generate_base_layers($support_z, $contact, $interface, $top);
|
||||||
$self->clip_with_object($base, $support_z, $object);
|
$self->clip_with_object($base, $support_z, $object);
|
||||||
|
$self->clip_with_shape($base, $shape) if @$shape;
|
||||||
|
|
||||||
# Install support layers into object.
|
# Install support layers into object.
|
||||||
push @{$object->support_layers}, map Slic3r::Layer::Support->new(
|
push @{$object->support_layers}, map Slic3r::Layer::Support->new(
|
||||||
@ -405,6 +416,8 @@ sub generate_toolpaths {
|
|||||||
if ($pattern eq 'rectilinear-grid') {
|
if ($pattern eq 'rectilinear-grid') {
|
||||||
$pattern = 'rectilinear';
|
$pattern = 'rectilinear';
|
||||||
push @angles, $angles[0] + 90;
|
push @angles, $angles[0] + 90;
|
||||||
|
} elsif ($pattern eq 'pillars') {
|
||||||
|
$pattern = 'honeycomb';
|
||||||
}
|
}
|
||||||
|
|
||||||
my %fillers = (
|
my %fillers = (
|
||||||
@ -629,6 +642,89 @@ sub generate_toolpaths {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub generate_pillars_shape {
|
||||||
|
my ($self, $contact, $support_z, $shape) = @_;
|
||||||
|
|
||||||
|
my $pillar_size = scale PILLAR_SIZE;
|
||||||
|
my $pillar_spacing = scale PILLAR_SPACING;
|
||||||
|
|
||||||
|
my $grid; # arrayref of polygons
|
||||||
|
{
|
||||||
|
my $pillar = Slic3r::Polygon->new(
|
||||||
|
[0,0],
|
||||||
|
[$pillar_size, 0],
|
||||||
|
[$pillar_size, $pillar_size],
|
||||||
|
[0, $pillar_size],
|
||||||
|
);
|
||||||
|
|
||||||
|
my @pillars = ();
|
||||||
|
my $bb = Slic3r::Geometry::BoundingBox->new_from_points([ map @$_, map @$_, values %$contact ]);
|
||||||
|
for (my $x = $bb->x_min; $x <= $bb->x_max-$pillar_size; $x += $pillar_spacing) {
|
||||||
|
for (my $y = $bb->y_min; $y <= $bb->y_max-$pillar_size; $y += $pillar_spacing) {
|
||||||
|
push @pillars, my $p = $pillar->clone;
|
||||||
|
$p->translate($x, $y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$grid = union(\@pillars);
|
||||||
|
}
|
||||||
|
|
||||||
|
# add pillars to every layer
|
||||||
|
for my $i (0..$#$support_z) {
|
||||||
|
$shape->[$i] = [ @$grid ];
|
||||||
|
}
|
||||||
|
|
||||||
|
# build capitals
|
||||||
|
for my $i (0..$#$support_z) {
|
||||||
|
my $z = $support_z->[$i];
|
||||||
|
|
||||||
|
my $capitals = intersection(
|
||||||
|
$grid,
|
||||||
|
$contact->{$z} // [],
|
||||||
|
);
|
||||||
|
|
||||||
|
# work on one pillar at time (if any) to prevent the capitals from being merged
|
||||||
|
# but store the contact area supported by the capital because we need to make
|
||||||
|
# sure nothing is left
|
||||||
|
my $contact_supported_by_capitals = [];
|
||||||
|
foreach my $capital (@$capitals) {
|
||||||
|
# enlarge capital tops
|
||||||
|
$capital = offset([$capital], +($pillar_spacing - $pillar_size)/2);
|
||||||
|
push @$contact_supported_by_capitals, @$capital;
|
||||||
|
|
||||||
|
for (my $j = $i-1; $j >= 0; $j--) {
|
||||||
|
my $jz = $support_z->[$j];
|
||||||
|
$capital = offset($capital, -$self->interface_flow->scaled_width/2);
|
||||||
|
last if !@$capitals;
|
||||||
|
push @{ $shape->[$j] }, @$capital;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Capitals will not generally cover the whole contact area because there will be
|
||||||
|
# remainders. For now we handle this situation by projecting such unsupported
|
||||||
|
# areas to the ground, just like we would do with a normal support.
|
||||||
|
my $contact_not_supported_by_capitals = diff(
|
||||||
|
$contact->{$z} // [],
|
||||||
|
$contact_supported_by_capitals,
|
||||||
|
);
|
||||||
|
if (@$contact_not_supported_by_capitals) {
|
||||||
|
for (my $j = $i-1; $j >= 0; $j--) {
|
||||||
|
push @{ $shape->[$j] }, @$contact_not_supported_by_capitals;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub clip_with_shape {
|
||||||
|
my ($self, $support, $shape) = @_;
|
||||||
|
|
||||||
|
foreach my $i (keys %$support) {
|
||||||
|
$support->{$i} = intersection(
|
||||||
|
$support->{$i},
|
||||||
|
$shape->[$i],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# this method returns the indices of the layers overlapping with the given one
|
# this method returns the indices of the layers overlapping with the given one
|
||||||
sub overlapping_layers {
|
sub overlapping_layers {
|
||||||
my ($self, $i, $support_z) = @_;
|
my ($self, $i, $support_z) = @_;
|
||||||
|
@ -14,6 +14,10 @@ enum InfillPattern {
|
|||||||
ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
|
ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SupportMaterialPattern {
|
||||||
|
smpRectilinear, smpRectilinearGrid, smpHoneycomb, smpPillars,
|
||||||
|
};
|
||||||
|
|
||||||
template<> inline t_config_enum_values ConfigOptionEnum<GCodeFlavor>::get_enum_values() {
|
template<> inline t_config_enum_values ConfigOptionEnum<GCodeFlavor>::get_enum_values() {
|
||||||
t_config_enum_values keys_map;
|
t_config_enum_values keys_map;
|
||||||
keys_map["reprap"] = gcfRepRap;
|
keys_map["reprap"] = gcfRepRap;
|
||||||
@ -37,6 +41,15 @@ template<> inline t_config_enum_values ConfigOptionEnum<InfillPattern>::get_enum
|
|||||||
return keys_map;
|
return keys_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<> inline t_config_enum_values ConfigOptionEnum<SupportMaterialPattern>::get_enum_values() {
|
||||||
|
t_config_enum_values keys_map;
|
||||||
|
keys_map["rectilinear"] = smpRectilinear;
|
||||||
|
keys_map["rectilinear-grid"] = smpRectilinearGrid;
|
||||||
|
keys_map["honeycomb"] = smpHoneycomb;
|
||||||
|
keys_map["pillars"] = smpPillars;
|
||||||
|
return keys_map;
|
||||||
|
}
|
||||||
|
|
||||||
class PrintConfigDef
|
class PrintConfigDef
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -758,12 +771,15 @@ class PrintConfigDef
|
|||||||
Options["support_material_pattern"].tooltip = "Pattern used to generate support material.";
|
Options["support_material_pattern"].tooltip = "Pattern used to generate support material.";
|
||||||
Options["support_material_pattern"].cli = "support-material-pattern=s";
|
Options["support_material_pattern"].cli = "support-material-pattern=s";
|
||||||
Options["support_material_pattern"].scope = "object";
|
Options["support_material_pattern"].scope = "object";
|
||||||
|
Options["support_material_pattern"].enum_keys_map = ConfigOptionEnum<SupportMaterialPattern>::get_enum_values();
|
||||||
Options["support_material_pattern"].enum_values.push_back("rectilinear");
|
Options["support_material_pattern"].enum_values.push_back("rectilinear");
|
||||||
Options["support_material_pattern"].enum_values.push_back("rectilinear-grid");
|
Options["support_material_pattern"].enum_values.push_back("rectilinear-grid");
|
||||||
Options["support_material_pattern"].enum_values.push_back("honeycomb");
|
Options["support_material_pattern"].enum_values.push_back("honeycomb");
|
||||||
|
Options["support_material_pattern"].enum_values.push_back("pillars");
|
||||||
Options["support_material_pattern"].enum_labels.push_back("rectilinear");
|
Options["support_material_pattern"].enum_labels.push_back("rectilinear");
|
||||||
Options["support_material_pattern"].enum_labels.push_back("rectilinear grid");
|
Options["support_material_pattern"].enum_labels.push_back("rectilinear grid");
|
||||||
Options["support_material_pattern"].enum_labels.push_back("honeycomb");
|
Options["support_material_pattern"].enum_labels.push_back("honeycomb");
|
||||||
|
Options["support_material_pattern"].enum_labels.push_back("pillars");
|
||||||
|
|
||||||
Options["support_material_spacing"].type = coFloat;
|
Options["support_material_spacing"].type = coFloat;
|
||||||
Options["support_material_spacing"].label = "Pattern spacing";
|
Options["support_material_spacing"].label = "Pattern spacing";
|
||||||
@ -894,7 +910,7 @@ class PrintObjectConfig : public virtual StaticConfig
|
|||||||
ConfigOptionInt support_material_interface_extruder;
|
ConfigOptionInt support_material_interface_extruder;
|
||||||
ConfigOptionInt support_material_interface_layers;
|
ConfigOptionInt support_material_interface_layers;
|
||||||
ConfigOptionFloat support_material_interface_spacing;
|
ConfigOptionFloat support_material_interface_spacing;
|
||||||
ConfigOptionEnum<InfillPattern> support_material_pattern;
|
ConfigOptionEnum<SupportMaterialPattern> support_material_pattern;
|
||||||
ConfigOptionFloat support_material_spacing;
|
ConfigOptionFloat support_material_spacing;
|
||||||
ConfigOptionFloat support_material_speed;
|
ConfigOptionFloat support_material_speed;
|
||||||
ConfigOptionInt support_material_threshold;
|
ConfigOptionInt support_material_threshold;
|
||||||
@ -918,7 +934,7 @@ class PrintObjectConfig : public virtual StaticConfig
|
|||||||
this->support_material_interface_extruder.value = 1;
|
this->support_material_interface_extruder.value = 1;
|
||||||
this->support_material_interface_layers.value = 3;
|
this->support_material_interface_layers.value = 3;
|
||||||
this->support_material_interface_spacing.value = 0;
|
this->support_material_interface_spacing.value = 0;
|
||||||
this->support_material_pattern.value = ipHoneycomb;
|
this->support_material_pattern.value = smpHoneycomb;
|
||||||
this->support_material_spacing.value = 2.5;
|
this->support_material_spacing.value = 2.5;
|
||||||
this->support_material_speed.value = 60;
|
this->support_material_speed.value = 60;
|
||||||
this->support_material_threshold.value = 0;
|
this->support_material_threshold.value = 0;
|
||||||
|
@ -4,7 +4,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Slic3r::XS;
|
use Slic3r::XS;
|
||||||
use Test::More tests => 89;
|
use Test::More tests => 91;
|
||||||
|
|
||||||
foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) {
|
foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) {
|
||||||
$config->set('layer_height', 0.3);
|
$config->set('layer_height', 0.3);
|
||||||
@ -47,10 +47,13 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) {
|
|||||||
is $config->get('gcode_flavor'), 'teacup', 'set/get enum';
|
is $config->get('gcode_flavor'), 'teacup', 'set/get enum';
|
||||||
is $config->serialize('gcode_flavor'), 'teacup', 'serialize enum';
|
is $config->serialize('gcode_flavor'), 'teacup', 'serialize enum';
|
||||||
$config->set_deserialize('gcode_flavor', 'mach3');
|
$config->set_deserialize('gcode_flavor', 'mach3');
|
||||||
is $config->get('gcode_flavor'), 'mach3', 'deserialize enum';
|
is $config->get('gcode_flavor'), 'mach3', 'deserialize enum (gcode_flavor)';
|
||||||
|
|
||||||
$config->set_deserialize('fill_pattern', 'line');
|
$config->set_deserialize('fill_pattern', 'line');
|
||||||
is $config->get('fill_pattern'), 'line', 'deserialize enum';
|
is $config->get('fill_pattern'), 'line', 'deserialize enum (fill_pattern)';
|
||||||
|
|
||||||
|
$config->set_deserialize('support_material_pattern', 'pillars');
|
||||||
|
is $config->get('support_material_pattern'), 'pillars', 'deserialize enum (support_material_pattern)';
|
||||||
|
|
||||||
$config->set('extruder_offset', [[10,20],[30,45]]);
|
$config->set('extruder_offset', [[10,20],[30,45]]);
|
||||||
is_deeply $config->get('extruder_offset'), [[10,20],[30,45]], 'set/get points';
|
is_deeply $config->get('extruder_offset'), [[10,20],[30,45]], 'set/get points';
|
||||||
|
Loading…
Reference in New Issue
Block a user