initial implementation of algorithm for #249
fix typo that put things in the wrong position use int() builtin instead of POSIX::floor() fix typo use alternate method of creating local routines remove aliases for new duplicate option use coderefs for linear interpolate function, make binary insertion sort inline add \n at end of die message regarding too many objects for print area fix case where no duplication is done fix whitespace according to slic3r coding style assume 200x200 bed area if center is 0,0 Some cleanup to the autoarrange duplication logic
This commit is contained in:
parent
7a786844f6
commit
f2edfd1a76
@ -193,8 +193,9 @@ The author is Alessandro Ranellucci (me).
|
|||||||
Transform options:
|
Transform options:
|
||||||
--scale Factor for scaling input object (default: 1)
|
--scale Factor for scaling input object (default: 1)
|
||||||
--rotate Rotation angle in degrees (0-360, default: 0)
|
--rotate Rotation angle in degrees (0-360, default: 0)
|
||||||
--duplicate-x Number of items along X axis (1+, default: 1)
|
--duplicate Number of items with auto-arrange (1+, default: 1)
|
||||||
--duplicate-y Number of items along Y axis (1+, default: 1)
|
--duplicate-x Number of items along X axis for manual arrangement (1+, default: 1)
|
||||||
|
--duplicate-y Number of items along Y axis for manual arrangement (1+, default: 1)
|
||||||
--duplicate-distance Distance in mm between copies (default: 6)
|
--duplicate-distance Distance in mm between copies (default: 6)
|
||||||
|
|
||||||
Miscellaneous options:
|
Miscellaneous options:
|
||||||
|
@ -137,6 +137,7 @@ our $skirt_height = 1; # layers
|
|||||||
# transform options
|
# transform options
|
||||||
our $scale = 1;
|
our $scale = 1;
|
||||||
our $rotate = 0;
|
our $rotate = 0;
|
||||||
|
our $duplicate = 1;
|
||||||
our $duplicate_x = 1;
|
our $duplicate_x = 1;
|
||||||
our $duplicate_y = 1;
|
our $duplicate_y = 1;
|
||||||
our $duplicate_distance = 6; # mm
|
our $duplicate_distance = 6; # mm
|
||||||
|
@ -392,6 +392,11 @@ our $Options = {
|
|||||||
cli => 'rotate=i',
|
cli => 'rotate=i',
|
||||||
type => 'i',
|
type => 'i',
|
||||||
},
|
},
|
||||||
|
'duplicate' => {
|
||||||
|
label => 'Copies (auto arrange)',
|
||||||
|
cli => 'duplicate=i',
|
||||||
|
type => 'i',
|
||||||
|
},
|
||||||
'duplicate_x' => {
|
'duplicate_x' => {
|
||||||
label => 'Copies along X',
|
label => 'Copies along X',
|
||||||
cli => 'duplicate-x=i',
|
cli => 'duplicate-x=i',
|
||||||
@ -599,6 +604,10 @@ sub validate {
|
|||||||
die "Invalid value for --scale\n"
|
die "Invalid value for --scale\n"
|
||||||
if $Slic3r::scale <= 0;
|
if $Slic3r::scale <= 0;
|
||||||
|
|
||||||
|
# --duplicate
|
||||||
|
die "Invalid value for --duplicate\n"
|
||||||
|
if $Slic3r::duplicate < 1;
|
||||||
|
|
||||||
# --duplicate-x
|
# --duplicate-x
|
||||||
die "Invalid value for --duplicate-x\n"
|
die "Invalid value for --duplicate-x\n"
|
||||||
if $Slic3r::duplicate_x < 1;
|
if $Slic3r::duplicate_x < 1;
|
||||||
@ -607,6 +616,11 @@ sub validate {
|
|||||||
die "Invalid value for --duplicate-y\n"
|
die "Invalid value for --duplicate-y\n"
|
||||||
if $Slic3r::duplicate_y < 1;
|
if $Slic3r::duplicate_y < 1;
|
||||||
|
|
||||||
|
# reflect actual quantity in 'duplicate' setting for use with output-filename-format, ie both --duplicate 15 and --duplicate-x 3 --duplicate-y 5 will make an appropriate filename
|
||||||
|
if ($Slic3r::duplicate == 1 && (($Slic3r::duplicate_x > 1) || ($Slic3r::duplicate_y > 1))) {
|
||||||
|
$Slic3r::duplicate = $Slic3r::duplicate_x * $Slic3r::duplicate_y;
|
||||||
|
}
|
||||||
|
|
||||||
# --duplicate-distance
|
# --duplicate-distance
|
||||||
die "Invalid value for --duplicate-distance\n"
|
die "Invalid value for --duplicate-distance\n"
|
||||||
if $Slic3r::duplicate_distance < 1;
|
if $Slic3r::duplicate_distance < 1;
|
||||||
|
@ -60,7 +60,7 @@ sub new {
|
|||||||
},
|
},
|
||||||
transform => {
|
transform => {
|
||||||
title => 'Transform',
|
title => 'Transform',
|
||||||
options => [qw(scale rotate duplicate_x duplicate_y duplicate_distance)],
|
options => [qw(scale rotate duplicate duplicate_x duplicate_y duplicate_distance)],
|
||||||
},
|
},
|
||||||
gcode => {
|
gcode => {
|
||||||
title => 'Custom G-code',
|
title => 'Custom G-code',
|
||||||
|
@ -124,6 +124,8 @@ sub BUILD {
|
|||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
my $dist = scale $Slic3r::duplicate_distance;
|
my $dist = scale $Slic3r::duplicate_distance;
|
||||||
|
|
||||||
|
if ($Slic3r::duplicate_x > 1 || $Slic3r::duplicate_y > 1) {
|
||||||
$self->total_x_length($self->x_length * $Slic3r::duplicate_x + $dist * ($Slic3r::duplicate_x - 1));
|
$self->total_x_length($self->x_length * $Slic3r::duplicate_x + $dist * ($Slic3r::duplicate_x - 1));
|
||||||
$self->total_y_length($self->y_length * $Slic3r::duplicate_y + $dist * ($Slic3r::duplicate_y - 1));
|
$self->total_y_length($self->y_length * $Slic3r::duplicate_y + $dist * ($Slic3r::duplicate_y - 1));
|
||||||
|
|
||||||
@ -131,11 +133,117 @@ sub BUILD {
|
|||||||
for my $x_copy (1..$Slic3r::duplicate_x) {
|
for my $x_copy (1..$Slic3r::duplicate_x) {
|
||||||
for my $y_copy (1..$Slic3r::duplicate_y) {
|
for my $y_copy (1..$Slic3r::duplicate_y) {
|
||||||
push @{$self->copies}, [
|
push @{$self->copies}, [
|
||||||
($self->x_length + scale $Slic3r::duplicate_distance) * ($x_copy-1),
|
($self->x_length + $dist) * ($x_copy-1),
|
||||||
($self->y_length + scale $Slic3r::duplicate_distance) * ($y_copy-1),
|
($self->y_length + $dist) * ($y_copy-1),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} elsif ($Slic3r::duplicate > 1) {
|
||||||
|
my $linint = sub {
|
||||||
|
my ($value, $oldmin, $oldmax, $newmin, $newmax) = @_;
|
||||||
|
return ($value - $oldmin) * ($newmax - $newmin) / ($oldmax - $oldmin) + $newmin;
|
||||||
|
};
|
||||||
|
|
||||||
|
# use center location to determine print area. assume X200 Y200 if center is 0,0
|
||||||
|
# TODO: add user configuration for bed area with new gui
|
||||||
|
my $printx = $Slic3r::print_center->[X] * 2 || 200;
|
||||||
|
my $printy = $Slic3r::print_center->[Y] * 2 || 200;
|
||||||
|
|
||||||
|
# use actual part size plus separation distance (half on each side) in spacing algorithm
|
||||||
|
my $partx = unscale($self->x_length) + $Slic3r::duplicate_distance;
|
||||||
|
my $party = unscale($self->y_length) + $Slic3r::duplicate_distance;
|
||||||
|
|
||||||
|
# this is how many cells we have available into which to put parts
|
||||||
|
my $cellw = int($printx / $partx);
|
||||||
|
my $cellh = int($printy / $party);
|
||||||
|
die "$Slic3r::duplicate parts won't fit in your print area!\n" if $Slic3r::duplicate > ($cellw * $cellh);
|
||||||
|
|
||||||
|
# width and height of space used by cells
|
||||||
|
my $w = $cellw * $partx;
|
||||||
|
my $h = $cellh * $party;
|
||||||
|
|
||||||
|
# left and right border positions of space used by cells
|
||||||
|
my $l = ($printx - $w) / 2;
|
||||||
|
my $r = $l + $w;
|
||||||
|
|
||||||
|
# top and bottom border positions
|
||||||
|
my $t = ($printy - $h) / 2;
|
||||||
|
my $b = $t + $h;
|
||||||
|
|
||||||
|
# list of cells, sorted by distance from center
|
||||||
|
my @cellsorder;
|
||||||
|
|
||||||
|
# work out distance for all cells, sort into list
|
||||||
|
for my $i (0..$cellw-1) {
|
||||||
|
for my $j (0..$cellh-1) {
|
||||||
|
my $cx = $linint->($i + 0.5, 0, $cellw, $l, $r);
|
||||||
|
my $cy = $linint->($j + 0.5, 0, $cellh, $t, $b);
|
||||||
|
|
||||||
|
my $xd = abs(($printx / 2) - $cx);
|
||||||
|
my $yd = abs(($printy / 2) - $cy);
|
||||||
|
|
||||||
|
my $c = {
|
||||||
|
location => [$cx, $cy],
|
||||||
|
index => [$i, $j],
|
||||||
|
distance => $xd * $xd + $yd * $yd - abs(($cellw / 2) - ($i + 0.5)),
|
||||||
|
};
|
||||||
|
|
||||||
|
BINARYINSERTIONSORT: {
|
||||||
|
my $index = $c->{distance};
|
||||||
|
my $low = 0;
|
||||||
|
my $high = @cellsorder;
|
||||||
|
while ($low < $high) {
|
||||||
|
my $mid = ($low + (($high - $low) / 2)) | 0;
|
||||||
|
my $midval = $cellsorder[$mid]->[0];
|
||||||
|
|
||||||
|
if ($midval < $index) {
|
||||||
|
$low = $mid + 1;
|
||||||
|
} elsif ($midval > $index) {
|
||||||
|
$high = $mid;
|
||||||
|
} else {
|
||||||
|
splice @cellsorder, $mid, 0, [$index, $c];
|
||||||
|
last BINARYINSERTIONSORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
splice @cellsorder, $low, 0, [$index, $c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# the extents of cells actually used by objects
|
||||||
|
my ($lx, $ty, $rx, $by) = (0, 0, 0, 0);
|
||||||
|
|
||||||
|
# now find cells actually used by objects, map out the extents so we can position correctly
|
||||||
|
for my $i (1..$Slic3r::duplicate) {
|
||||||
|
my $c = $cellsorder[$i - 1];
|
||||||
|
my $cx = $c->[1]->{index}->[0];
|
||||||
|
my $cy = $c->[1]->{index}->[1];
|
||||||
|
if ($i == 1) {
|
||||||
|
$lx = $rx = $cx;
|
||||||
|
$ty = $by = $cy;
|
||||||
|
} else {
|
||||||
|
$rx = $cx if $cx > $rx;
|
||||||
|
$lx = $cx if $cx < $lx;
|
||||||
|
$by = $cy if $cy > $by;
|
||||||
|
$ty = $cy if $cy < $ty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# now we actually place objects into cells, positioned such that the left and bottom borders are at 0
|
||||||
|
for my $i (1..$Slic3r::duplicate) {
|
||||||
|
my $c = shift @cellsorder;
|
||||||
|
my $cx = $c->[1]->{index}->[0] - $lx;
|
||||||
|
my $cy = $c->[1]->{index}->[1] - $ty;
|
||||||
|
|
||||||
|
push @{$self->copies}, [scale($cx * $partx - (unscale($self->x_length) / 2)), scale($cy * $party - (unscale($self->y_length) / 2))];
|
||||||
|
}
|
||||||
|
# save size of area used
|
||||||
|
$self->total_x_length(scale(($rx - $lx) * $partx));
|
||||||
|
$self->total_y_length(scale(($by - $ty) * $party));
|
||||||
|
} else {
|
||||||
|
$self->total_x_length($self->x_length);
|
||||||
|
$self->total_y_length($self->y_length);
|
||||||
|
push @{$self->copies}, [0, 0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub layer_count {
|
sub layer_count {
|
||||||
|
@ -216,8 +216,9 @@ Usage: slic3r.pl [ OPTIONS ] file.stl
|
|||||||
Transform options:
|
Transform options:
|
||||||
--scale Factor for scaling input object (default: $Slic3r::scale)
|
--scale Factor for scaling input object (default: $Slic3r::scale)
|
||||||
--rotate Rotation angle in degrees (0-360, default: $Slic3r::rotate)
|
--rotate Rotation angle in degrees (0-360, default: $Slic3r::rotate)
|
||||||
--duplicate-x Number of items along X axis (1+, default: $Slic3r::duplicate_x)
|
--duplicate Number of items with auto-arrange (1+, default: $Slic3r::duplicate)
|
||||||
--duplicate-y Number of items along Y axis (1+, default: $Slic3r::duplicate_y)
|
--duplicate-x Number of items along X axis for manual arrangement (1+, default: $Slic3r::duplicate_x)
|
||||||
|
--duplicate-y Number of items along Y axis for manual arrangement (1+, default: $Slic3r::duplicate_y)
|
||||||
--duplicate-distance Distance in mm between copies (default: $Slic3r::duplicate_distance)
|
--duplicate-distance Distance in mm between copies (default: $Slic3r::duplicate_distance)
|
||||||
|
|
||||||
Miscellaneous options:
|
Miscellaneous options:
|
||||||
|
Loading…
Reference in New Issue
Block a user