New 3D Honeycomb infill pattern (credits: David Eccles (gringer)). #1646

This commit is contained in:
Alessandro Ranellucci 2014-07-26 17:07:43 +02:00
parent d508be5ae8
commit 53f2d6bb4b
6 changed files with 222 additions and 1 deletions

View File

@ -16,6 +16,7 @@ my %prereqs = qw(
Math::PlanePath 53 Math::PlanePath 53
Module::Build::WithXSpp 0.14 Module::Build::WithXSpp 0.14
Moo 1.003001 Moo 1.003001
POSIX 0
Scalar::Util 0 Scalar::Util 0
Test::Harness 0 Test::Harness 0
Test::More 0 Test::More 0

View File

@ -2,6 +2,7 @@ package Slic3r::Fill;
use Moo; use Moo;
use Slic3r::ExtrusionPath ':roles'; use Slic3r::ExtrusionPath ':roles';
use Slic3r::Fill::3DHoneycomb;
use Slic3r::Fill::ArchimedeanChords; use Slic3r::Fill::ArchimedeanChords;
use Slic3r::Fill::Base; use Slic3r::Fill::Base;
use Slic3r::Fill::Concentric; use Slic3r::Fill::Concentric;
@ -30,6 +31,7 @@ our %FillTypes = (
line => 'Slic3r::Fill::Line', line => 'Slic3r::Fill::Line',
concentric => 'Slic3r::Fill::Concentric', concentric => 'Slic3r::Fill::Concentric',
honeycomb => 'Slic3r::Fill::Honeycomb', honeycomb => 'Slic3r::Fill::Honeycomb',
'3dhoneycomb' => 'Slic3r::Fill::3DHoneycomb',
); );
sub filler { sub filler {
@ -213,6 +215,7 @@ sub make_fill {
my $f = $self->filler($filler); my $f = $self->filler($filler);
$f->layer_id($layerm->id); $f->layer_id($layerm->id);
$f->z($layerm->print_z);
$f->angle(deg2rad($layerm->config->fill_angle)); $f->angle(deg2rad($layerm->config->fill_angle));
my ($params, @polylines) = $f->fill_surface( my ($params, @polylines) = $f->fill_surface(
$surface, $surface,

View File

@ -0,0 +1,213 @@
package Slic3r::Fill::3DHoneycomb;
use Moo;
extends 'Slic3r::Fill::Base';
use POSIX qw(ceil fmod);
use Slic3r::Geometry qw(scale scaled_epsilon);
use Slic3r::Geometry::Clipper qw(intersection_pl);
sub fill_surface {
my ($self, $surface, %params) = @_;
my $expolygon = $surface->expolygon;
my $bb = $expolygon->bounding_box;
my $size = $bb->size;
my $distance = $params{flow}->scaled_spacing / $params{density};
# generate pattern
my @polylines = map Slic3r::Polyline->new(@$_),
makeGrid(
scale($self->z),
$distance,
ceil($size->x / $distance),
ceil($size->y / $distance), #//
($self->layer_id % 2) + 1,
);
# move pattern in place
$_->translate($bb->x_min, $bb->y_min) for @polylines;
# clip pattern to boundaries
@polylines = @{intersection_pl(\@polylines, \@$expolygon)};
# connect lines
unless ($params{dont_connect} || !@polylines) { # prevent calling leftmost_point() on empty collections
my ($expolygon_off) = @{$expolygon->offset_ex(scaled_epsilon)};
my $collection = Slic3r::Polyline::Collection->new(@polylines);
@polylines = ();
foreach my $polyline (@{$collection->chained_path_from($collection->leftmost_point, 0)}) {
# try to append this polyline to previous one if any
if (@polylines) {
my $line = Slic3r::Line->new($polylines[-1]->last_point, $polyline->first_point);
if ($line->length <= 1.5*$distance && $expolygon_off->contains_line($line)) {
$polylines[-1]->append_polyline($polyline);
next;
}
}
# make a clone before $collection goes out of scope
push @polylines, $polyline->clone;
}
}
# TODO: return ExtrusionLoop objects to get better chained paths
return { flow => $params{flow} }, @polylines;
}
=head1 DESCRIPTION
Creates a contiguous sequence of points at a specified height that make
up a horizontal slice of the edges of a space filling truncated
octahedron tesselation. The octahedrons are oriented so that the
square faces are in the horizontal plane with edges parallel to the X
and Y axes.
Credits: David Eccles (gringer).
=head2 makeGrid(z, gridSize, gridWidth, gridHeight, curveType)
Generate a set of curves (array of array of 2d points) that describe a
horizontal slice of a truncated regular octahedron with a specified
grid square size.
=cut
sub makeGrid {
my ($z, $gridSize, $gridWidth, $gridHeight, $curveType) = @_;
my $scaleFactor = $gridSize;
my $normalisedZ = $z / $scaleFactor;
my @points = makeNormalisedGrid($normalisedZ, $gridWidth, $gridHeight, $curveType);
foreach my $lineRef (@points) {
foreach my $pointRef (@$lineRef) {
$pointRef->[0] *= $scaleFactor;
$pointRef->[1] *= $scaleFactor;
}
}
return @points;
}
=head1 FUNCTIONS
=cut
=head2 colinearPoints(offset, gridLength)
Generate an array of points that are in the same direction as the
basic printing line (i.e. Y points for columns, X points for rows)
Note: a negative offset only causes a change in the perpendicular
direction
=cut
sub colinearPoints {
my ($offset, $baseLocation, $gridLength) = @_;
my @points = ();
push @points, $baseLocation - abs($offset/2);
for (my $i = 0; $i < $gridLength; $i++) {
push @points, $baseLocation + $i + abs($offset/2);
push @points, $baseLocation + ($i+1) - abs($offset/2);
}
push @points, $baseLocation + $gridLength + abs($offset/2);
return @points;
}
=head2 colinearPoints(offset, baseLocation, gridLength)
Generate an array of points for the dimension that is perpendicular to
the basic printing line (i.e. X points for columns, Y points for rows)
=cut
sub perpendPoints {
my ($offset, $baseLocation, $gridLength) = @_;
my @points = ();
my $side = 2*(($baseLocation) % 2) - 1;
push @points, $baseLocation - $offset/2 * $side;
for (my $i = 0; $i < $gridLength; $i++) {
$side = 2*(($i+$baseLocation) % 2) - 1;
push @points, $baseLocation + $offset/2 * $side;
push @points, $baseLocation + $offset/2 * $side;
}
push @points, $baseLocation - $offset/2 * $side;
return @points;
}
=head2 trim(pointArrayRef, minX, minY, maxX, maxY)
Trims an array of points to specified rectangular limits. Point
components that are outside these limits are set to the limits.
=cut
sub trim {
my ($pointArrayRef, $minX, $minY, $maxX, $maxY) = @_;
foreach (@$pointArrayRef) {
$_->[0] = ($_->[0] < $minX) ? $minX : (($_->[0] > $maxX) ? $maxX : $_->[0]);
$_->[1] = ($_->[1] < $minY) ? $minY : (($_->[1] > $maxY) ? $maxY : $_->[1]);
}
}
=head2 makeNormalisedGrid(z, gridWidth, gridHeight, curveType)
Generate a set of curves (array of array of 2d points) that describe a
horizontal slice of a truncated regular octahedron with edge length 1.
curveType specifies which lines to print, 1 for vertical lines
(columns), 2 for horizontal lines (rows), and 3 for both.
=cut
sub makeNormalisedGrid {
my ($z, $gridWidth, $gridHeight, $curveType) = @_;
# offset required to create a regular octagram
my $octagramGap = 1 / (1 + sqrt(2));
# sawtooth wave function for range f($z) = [-$octagramGap .. $octagramGap]
my $offset = (abs((fmod($z * sqrt(2), 4)) - 2) - 1) * $octagramGap;
my @points = ();
if (($curveType & 1) != 0) {
for (my $x = 0; $x <= $gridWidth; $x++) {
my @xPoints = perpendPoints($offset, $x, $gridHeight);
my @yPoints = colinearPoints($offset, 0, $gridHeight);
# This is essentially @newPoints = zip(@xPoints, @yPoints)
my @newPoints = map [ $xPoints[$_], $yPoints[$_] ], 0..$#xPoints;
# trim points to grid edges
#trim(\@newPoints, 0, 0, $gridWidth, $gridHeight);
if ($x % 2 == 0){
push @points, [ @newPoints ];
} else {
push @points, [ reverse @newPoints ];
}
}
}
if (($curveType & 2) != 0) {
for (my $y = 0; $y <= $gridHeight; $y++) {
my @xPoints = colinearPoints($offset, 0, $gridWidth);
my @yPoints = perpendPoints($offset, $y, $gridWidth);
my @newPoints = map [ $xPoints[$_], $yPoints[$_] ], 0..$#xPoints;
# trim points to grid edges
#trim(\@newPoints, 0, 0, $gridWidth, $gridHeight);
if ($y % 2 == 0) {
push @points, [ @newPoints ];
} else {
push @points, [ reverse @newPoints ];
}
}
}
return @points;
}
1;

View File

@ -2,6 +2,7 @@ package Slic3r::Fill::Base;
use Moo; use Moo;
has 'layer_id' => (is => 'rw'); has 'layer_id' => (is => 'rw');
has 'z' => (is => 'rw'); # in unscaled coordinates
has 'angle' => (is => 'rw'); # in radians, ccw, 0 = East has 'angle' => (is => 'rw'); # in radians, ccw, 0 = East
has 'bounding_box' => (is => 'ro', required => 0); # Slic3r::Geometry::BoundingBox object has 'bounding_box' => (is => 'ro', required => 0); # Slic3r::Geometry::BoundingBox object

View File

@ -271,6 +271,7 @@ PrintConfigDef::build_def() {
Options["fill_pattern"].enum_values.push_back("line"); Options["fill_pattern"].enum_values.push_back("line");
Options["fill_pattern"].enum_values.push_back("concentric"); Options["fill_pattern"].enum_values.push_back("concentric");
Options["fill_pattern"].enum_values.push_back("honeycomb"); Options["fill_pattern"].enum_values.push_back("honeycomb");
Options["fill_pattern"].enum_values.push_back("3dhoneycomb");
Options["fill_pattern"].enum_values.push_back("hilbertcurve"); Options["fill_pattern"].enum_values.push_back("hilbertcurve");
Options["fill_pattern"].enum_values.push_back("archimedeanchords"); Options["fill_pattern"].enum_values.push_back("archimedeanchords");
Options["fill_pattern"].enum_values.push_back("octagramspiral"); Options["fill_pattern"].enum_values.push_back("octagramspiral");
@ -278,6 +279,7 @@ PrintConfigDef::build_def() {
Options["fill_pattern"].enum_labels.push_back("line"); Options["fill_pattern"].enum_labels.push_back("line");
Options["fill_pattern"].enum_labels.push_back("concentric"); Options["fill_pattern"].enum_labels.push_back("concentric");
Options["fill_pattern"].enum_labels.push_back("honeycomb"); Options["fill_pattern"].enum_labels.push_back("honeycomb");
Options["fill_pattern"].enum_labels.push_back("3D honeycomb");
Options["fill_pattern"].enum_labels.push_back("hilbertcurve (slow)"); Options["fill_pattern"].enum_labels.push_back("hilbertcurve (slow)");
Options["fill_pattern"].enum_labels.push_back("archimedeanchords (slow)"); Options["fill_pattern"].enum_labels.push_back("archimedeanchords (slow)");
Options["fill_pattern"].enum_labels.push_back("octagramspiral (slow)"); Options["fill_pattern"].enum_labels.push_back("octagramspiral (slow)");

View File

@ -10,7 +10,7 @@ enum GCodeFlavor {
}; };
enum InfillPattern { enum InfillPattern {
ipRectilinear, ipLine, ipConcentric, ipHoneycomb, ipRectilinear, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
}; };
@ -39,6 +39,7 @@ template<> inline t_config_enum_values ConfigOptionEnum<InfillPattern>::get_enum
keys_map["line"] = ipLine; keys_map["line"] = ipLine;
keys_map["concentric"] = ipConcentric; keys_map["concentric"] = ipConcentric;
keys_map["honeycomb"] = ipHoneycomb; keys_map["honeycomb"] = ipHoneycomb;
keys_map["3dhoneycomb"] = ip3DHoneycomb;
keys_map["hilbertcurve"] = ipHilbertCurve; keys_map["hilbertcurve"] = ipHilbertCurve;
keys_map["archimedeanchords"] = ipArchimedeanChords; keys_map["archimedeanchords"] = ipArchimedeanChords;
keys_map["octagramspiral"] = ipOctagramSpiral; keys_map["octagramspiral"] = ipOctagramSpiral;