'Smooths' a set of points by (recursively) cutting off corners.
#!/usr/bin/perl
=pod
=head1 Chaikin Spline Algorithm
@points = chaikin ([x1,y1],[x2,y2],...,[xn,yn]);
or...
@points = chaikin (points => \@AofA, [weight => 3, depth => 0, closed
+=> 0]);
Implements the Chaikin algorithm for smoothing polygons.
This takes a set of points and cuts off corners, adding two new points
+ for each corner.
For instance, a single 'run' (depth=0) would turn
this . . into . .
. . this . .
. . . . ` . .`
Futher iterations (depth > 0) make the curve smoother.
The weight determines where the 'split' happens. The default (3) split
+s the line into quarters, and places new points at 1/4 and 3/4 the le
+ngth.
Increasing the weight increases the 'tightness' of the curve (a weight
+ of 5 creating new points at 1/6 and 5/6, for example).
If the closed flag is set, a final set of points tending back to the f
+irst is added.
=cut
sub chaikin {
my %opt = @_;
my @po = (defined $opt{points})
? @{$opt{points}} : @_;
my $w = $opt{weight} || 3;
my $div = 1 / ($w + 1);
my @dest = $po[0];
foreach my $p (0..$#po-1) {
push @dest,[map {(($w * $po[$p][$_]) + $po[$p+1][$_]) * $div }
+ (0..1)];
push @dest,[map {($po[$p][$_] + ($w * $po[$p+1][$_])) * $div }
+ (0..1)];
}
if ($opt{closed}) {
push @dest,[map {(($w * $po[$#po][$_]) + $po[0][$_]) * $div }
+(0..1)];
push @dest,[map {($po[$#po][$_] + ($w * $po[0][$_])) * $div }
+(0..1)];
}
else {
push @dest,$po[$#po];
}
if ($opt{depth}--) {
@dest = chaikin(points=>\@dest,depth=>$opt{depth},weight=>$w,c
+losed=>$opt{closed});
}
@dest;
}