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:
|
||||
--scale Factor for scaling input object (default: 1)
|
||||
--rotate Rotation angle in degrees (0-360, default: 0)
|
||||
--duplicate-x Number of items along X axis (1+, default: 1)
|
||||
--duplicate-y Number of items along Y axis (1+, default: 1)
|
||||
--duplicate Number of items with auto-arrange (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)
|
||||
|
||||
Miscellaneous options:
|
||||
|
@ -137,6 +137,7 @@ our $skirt_height = 1; # layers
|
||||
# transform options
|
||||
our $scale = 1;
|
||||
our $rotate = 0;
|
||||
our $duplicate = 1;
|
||||
our $duplicate_x = 1;
|
||||
our $duplicate_y = 1;
|
||||
our $duplicate_distance = 6; # mm
|
||||
|
@ -10,7 +10,7 @@ our $Options = {
|
||||
# miscellaneous options
|
||||
'notes' => {
|
||||
label => 'Configuration notes',
|
||||
cli => 'notes=s',
|
||||
cli => 'notes=s',
|
||||
type => 's',
|
||||
multiline => 1,
|
||||
width => 350,
|
||||
@ -392,6 +392,11 @@ our $Options = {
|
||||
cli => 'rotate=i',
|
||||
type => 'i',
|
||||
},
|
||||
'duplicate' => {
|
||||
label => 'Copies (auto arrange)',
|
||||
cli => 'duplicate=i',
|
||||
type => 'i',
|
||||
},
|
||||
'duplicate_x' => {
|
||||
label => 'Copies along X',
|
||||
cli => 'duplicate-x=i',
|
||||
@ -599,6 +604,10 @@ sub validate {
|
||||
die "Invalid value for --scale\n"
|
||||
if $Slic3r::scale <= 0;
|
||||
|
||||
# --duplicate
|
||||
die "Invalid value for --duplicate\n"
|
||||
if $Slic3r::duplicate < 1;
|
||||
|
||||
# --duplicate-x
|
||||
die "Invalid value for --duplicate-x\n"
|
||||
if $Slic3r::duplicate_x < 1;
|
||||
@ -606,6 +615,11 @@ sub validate {
|
||||
# --duplicate-y
|
||||
die "Invalid value for --duplicate-y\n"
|
||||
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
|
||||
die "Invalid value for --duplicate-distance\n"
|
||||
@ -619,8 +633,8 @@ sub validate {
|
||||
die "Invalid value for --bridge-flow-ratio\n"
|
||||
if $Slic3r::bridge_flow_ratio <= 0;
|
||||
|
||||
$Slic3r::first_layer_temperature //= $Slic3r::temperature; #/
|
||||
$Slic3r::first_layer_bed_temperature //= $Slic3r::bed_temperature; #/
|
||||
$Slic3r::first_layer_temperature //= $Slic3r::temperature; #/
|
||||
$Slic3r::first_layer_bed_temperature //= $Slic3r::bed_temperature; #/
|
||||
|
||||
# G-code flavors
|
||||
$Slic3r::extrusion_axis = 'A' if $Slic3r::gcode_flavor eq 'mach3';
|
||||
|
@ -60,7 +60,7 @@ sub new {
|
||||
},
|
||||
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 => {
|
||||
title => 'Custom G-code',
|
||||
|
@ -124,17 +124,125 @@ sub BUILD {
|
||||
my $self = shift;
|
||||
|
||||
my $dist = scale $Slic3r::duplicate_distance;
|
||||
$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));
|
||||
|
||||
# generate offsets for copies
|
||||
for my $x_copy (1..$Slic3r::duplicate_x) {
|
||||
for my $y_copy (1..$Slic3r::duplicate_y) {
|
||||
push @{$self->copies}, [
|
||||
($self->x_length + scale $Slic3r::duplicate_distance) * ($x_copy-1),
|
||||
($self->y_length + scale $Slic3r::duplicate_distance) * ($y_copy-1),
|
||||
];
|
||||
|
||||
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_y_length($self->y_length * $Slic3r::duplicate_y + $dist * ($Slic3r::duplicate_y - 1));
|
||||
|
||||
# generate offsets for copies
|
||||
for my $x_copy (1..$Slic3r::duplicate_x) {
|
||||
for my $y_copy (1..$Slic3r::duplicate_y) {
|
||||
push @{$self->copies}, [
|
||||
($self->x_length + $dist) * ($x_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];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,9 +191,9 @@ EOF
|
||||
}
|
||||
|
||||
print $fh <<"EOF";
|
||||
<!--
|
||||
Generated using Slic3r $Slic3r::VERSION
|
||||
http://slic3r.org/
|
||||
<!--
|
||||
Generated using Slic3r $Slic3r::VERSION
|
||||
http://slic3r.org/
|
||||
-->
|
||||
</svg>
|
||||
EOF
|
||||
|
@ -216,8 +216,9 @@ Usage: slic3r.pl [ OPTIONS ] file.stl
|
||||
Transform options:
|
||||
--scale Factor for scaling input object (default: $Slic3r::scale)
|
||||
--rotate Rotation angle in degrees (0-360, default: $Slic3r::rotate)
|
||||
--duplicate-x Number of items along X axis (1+, default: $Slic3r::duplicate_x)
|
||||
--duplicate-y Number of items along Y axis (1+, default: $Slic3r::duplicate_y)
|
||||
--duplicate Number of items with auto-arrange (1+, default: $Slic3r::duplicate)
|
||||
--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)
|
||||
|
||||
Miscellaneous options:
|
||||
|
Loading…
Reference in New Issue
Block a user