summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlperl/lib/Imager/Matrix2d.pm
diff options
context:
space:
mode:
Diffstat (limited to 'Master/tlpkg/tlperl/lib/Imager/Matrix2d.pm')
-rwxr-xr-xMaster/tlpkg/tlperl/lib/Imager/Matrix2d.pm409
1 files changed, 409 insertions, 0 deletions
diff --git a/Master/tlpkg/tlperl/lib/Imager/Matrix2d.pm b/Master/tlpkg/tlperl/lib/Imager/Matrix2d.pm
new file mode 100755
index 00000000000..a1000092ea4
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Imager/Matrix2d.pm
@@ -0,0 +1,409 @@
+package Imager::Matrix2d;
+use strict;
+use vars qw($VERSION);
+
+$VERSION = "1.008";
+
+=head1 NAME
+
+ Imager::Matrix2d - simple wrapper for matrix construction
+
+=head1 SYNOPSIS
+
+ use Imager::Matrix2d;
+ $m1 = Imager::Matrix2d->identity;
+ $m2 = Imager::Matrix2d->rotate(radians=>$angle, x=>$cx, y=>$cy);
+ $m3 = Imager::Matrix2d->translate(x=>$dx, y=>$dy);
+ $m4 = Imager::Matrix2d->shear(x=>$sx, y=>$sy);
+ $m5 = Imager::Matrix2d->reflect(axis=>$axis);
+ $m6 = Imager::Matrix2d->scale(x=>$xratio, y=>$yratio);
+ $m6 = $m1 * $m2;
+ $m7 = $m1 + $m2;
+ use Imager::Matrix2d qw(:handy);
+ # various m2d_* functions imported
+ # where m2d_(.*) calls Imager::Matrix2d->$1()
+
+=head1 DESCRIPTION
+
+This class provides a simple wrapper around a reference to an array of
+9 co-efficients, treated as a matrix:
+
+ [ 0, 1, 2,
+ 3, 4, 5,
+ 6, 7, 8 ]
+
+Most of the methods in this class are constructors. The others are
+overloaded operators.
+
+Note that since Imager represents images with y increasing from top to
+bottom, rotation angles are clockwise, rather than counter-clockwise.
+
+=over
+
+=cut
+
+use vars qw(@EXPORT_OK %EXPORT_TAGS @ISA);
+@ISA = 'Exporter';
+require 'Exporter.pm';
+@EXPORT_OK = qw(m2d_rotate m2d_identity m2d_translate m2d_shear
+ m2d_reflect m2d_scale);
+%EXPORT_TAGS =
+ (
+ handy=> [ qw(m2d_rotate m2d_identity m2d_translate m2d_shear
+ m2d_reflect m2d_scale) ],
+ );
+
+use overload
+ '*' => \&_mult,
+ '+' => \&_add,
+ '""'=>\&_string;
+
+=item identity()
+
+Returns the identity matrix.
+
+=cut
+
+sub identity {
+ return bless [ 1, 0, 0,
+ 0, 1, 0,
+ 0, 0, 1 ], $_[0];
+}
+
+=item rotate(radians=>$angle)
+
+=item rotate(degrees=>$angle)
+
+Creates a matrix that rotates around the origin, or around the point
+(x,y) if the 'x' and 'y' parameters are provided.
+
+=cut
+
+sub rotate {
+ my ($class, %opts) = @_;
+ my $angle;
+
+ if (defined $opts{radians}) {
+ $angle = $opts{radians};
+ }
+ elsif (defined $opts{degrees}) {
+ $angle = $opts{degrees} * 3.1415926535 / 180;
+ }
+ else {
+ $Imager::ERRSTR = "degrees or radians parameter required";
+ return undef;
+ }
+
+ if ($opts{'x'} || $opts{'y'}) {
+ $opts{'x'} ||= 0;
+ $opts{'y'} ||= 0;
+ return $class->translate('x'=>-$opts{'x'}, 'y'=>-$opts{'y'})
+ * $class->rotate(radians=>$angle)
+ * $class->translate('x'=>$opts{'x'}, 'y'=>$opts{'y'});
+ }
+ else {
+ my $sin = sin($angle);
+ my $cos = cos($angle);
+ return bless [ $cos, -$sin, 0,
+ $sin, $cos, 0,
+ 0, 0, 1 ], $class;
+ }
+}
+
+=item translate(x=>$dx, y=>$dy)
+
+=item translate(x=>$dx)
+
+=item translate(y=>$dy)
+
+Translates by the specify amounts.
+
+=cut
+
+sub translate {
+ my ($class, %opts) = @_;
+
+ if (defined $opts{'x'} || defined $opts{'y'}) {
+ my $x = $opts{'x'} || 0;
+ my $y = $opts{'y'} || 0;
+ return bless [ 1, 0, $x,
+ 0, 1, $y,
+ 0, 0, 1 ], $class;
+ }
+
+ $Imager::ERRSTR = 'x or y parameter required';
+ return undef;
+}
+
+=item shear(x=>$sx, y=>$sy)
+
+=item shear(x=>$sx)
+
+=item shear(y=>$sy)
+
+Shear by the given amounts.
+
+=cut
+sub shear {
+ my ($class, %opts) = @_;
+
+ if (defined $opts{'x'} || defined $opts{'y'}) {
+ return bless [ 1, $opts{'x'}||0, 0,
+ $opts{'y'}||0, 1, 0,
+ 0, 0, 1 ], $class;
+ }
+ $Imager::ERRSTR = 'x and y parameters required';
+ return undef;
+}
+
+=item reflect(axis=>$axis)
+
+Reflect around the given axis, either 'x' or 'y'.
+
+=item reflect(radians=>$angle)
+
+=item reflect(degrees=>$angle)
+
+Reflect around a line drawn at the given angle from the origin.
+
+=cut
+
+sub reflect {
+ my ($class, %opts) = @_;
+
+ if (defined $opts{axis}) {
+ my $result = $class->identity;
+ if ($opts{axis} eq "y") {
+ $result->[0] = -$result->[0];
+ }
+ elsif ($opts{axis} eq "x") {
+ $result->[4] = -$result->[4];
+ }
+ else {
+ $Imager::ERRSTR = 'axis must be x or y';
+ return undef;
+ }
+
+ return $result;
+ }
+ my $angle;
+ if (defined $opts{radians}) {
+ $angle = $opts{radians};
+ }
+ elsif (defined $opts{degrees}) {
+ $angle = $opts{degrees} * 3.1415926535 / 180;
+ }
+ else {
+ $Imager::ERRSTR = 'axis, degrees or radians parameter required';
+ return undef;
+ }
+
+ # fun with matrices
+ return $class->rotate(radians=>-$angle) * $class->reflect(axis=>'x')
+ * $class->rotate(radians=>$angle);
+}
+
+=item scale(x=>$xratio, y=>$yratio)
+
+Scales at the given ratios.
+
+You can also specify a center for the scaling with the cx and cy
+parameters.
+
+=cut
+
+sub scale {
+ my ($class, %opts) = @_;
+
+ if (defined $opts{'x'} || defined $opts{'y'}) {
+ $opts{'x'} = 1 unless defined $opts{'x'};
+ $opts{'y'} = 1 unless defined $opts{'y'};
+ if ($opts{cx} || $opts{cy}) {
+ return $class->translate('x'=>-$opts{cx}, 'y'=>-$opts{cy})
+ * $class->scale('x'=>$opts{'x'}, 'y'=>$opts{'y'})
+ * $class->translate('x'=>$opts{cx}, 'y'=>$opts{cy});
+ }
+ else {
+ return bless [ $opts{'x'}, 0, 0,
+ 0, $opts{'y'}, 0,
+ 0, 0, 1 ], $class;
+ }
+ }
+ else {
+ $Imager::ERRSTR = 'x or y parameter required';
+ return undef;
+ }
+}
+
+=item _mult()
+
+Implements the overloaded '*' operator. Internal use.
+
+Currently both the left and right-hand sides of the operator must be
+an Imager::Matrix2d.
+
+=cut
+sub _mult {
+ my ($left, $right, $order) = @_;
+
+ if (ref($right) && UNIVERSAL::isa($right, __PACKAGE__)) {
+ if ($order) {
+ ($left, $right) = ($right, $left);
+ }
+ my @result;
+ for my $i (0..2) {
+ for my $j (0..2) {
+ my $accum = 0;
+ for my $k (0..2) {
+ $accum += $left->[3*$i + $k] * $right->[3*$k + $j];
+ }
+ $result[3*$i+$j] = $accum;
+ }
+ }
+ return bless \@result, __PACKAGE__;
+ }
+ else {
+ # presumably N * matrix or matrix * N
+ return undef; # for now
+ }
+}
+
+=item _add()
+
+Implements the overloaded binary '+' operator.
+
+Currently both the left and right sides of the operator must be
+Imager::Matrix2d objects.
+
+=cut
+sub _add {
+ my ($left, $right, $order) = @_;
+
+ if (ref($right) && UNIVERSAL::isa($right, __PACKAGE__)) {
+ my @result;
+ for (0..8) {
+ push @result, $left->[$_] + $right->[$_];
+ }
+
+ return bless \@result, __PACKAGE__;
+ }
+ else {
+ return undef;
+ }
+}
+
+=item _string()
+
+Implements the overloaded stringification operator.
+
+This returns a string containing 3 lines of text with no terminating
+newline.
+
+I tried to make it fairly nicely formatted. You might disagree :)
+
+=cut
+
+sub _string {
+ my ($m) = @_;
+
+ my $maxlen = 0;
+ for (@$m[0..8]) {
+ if (length() > $maxlen) {
+ $maxlen = length;
+ }
+ }
+ $maxlen <= 9 or $maxlen = 9;
+
+ my @left = ('[ ', ' ', ' ');
+ my @right = ("\n", "\n", ']');
+ my $out;
+ my $width = $maxlen+2;
+ for my $i (0..2) {
+ $out .= $left[$i];
+ for my $j (0..2) {
+ my $val = $m->[$i*3+$j];
+ if (length $val > 9) {
+ $val = sprintf("%9f", $val);
+ if ($val =~ /\./ && $val !~ /e/i) {
+ $val =~ s/0+$//;
+ $val =~ s/\.$//;
+ }
+ $val =~ s/^\s//;
+ }
+ $out .= sprintf("%-${width}s", "$val, ");
+ }
+ $out =~ s/ +\Z/ /;
+ $out .= $right[$i];
+ }
+ $out;
+}
+
+=back
+
+The following functions are shortcuts to the various constructors.
+
+These are not methods.
+
+You can import these methods with:
+
+ use Imager::Matrix2d ':handy';
+
+=over
+
+=item m2d_identity
+
+=item m2d_rotate()
+
+=item m2d_translate()
+
+=item m2d_shear()
+
+=item m2d_reflect()
+
+=item m2d_scale()
+
+=back
+
+=cut
+
+sub m2d_identity {
+ return __PACKAGE__->identity;
+}
+
+sub m2d_rotate {
+ return __PACKAGE__->rotate(@_);
+}
+
+sub m2d_translate {
+ return __PACKAGE__->translate(@_);
+}
+
+sub m2d_shear {
+ return __PACKAGE__->shear(@_);
+}
+
+sub m2d_reflect {
+ return __PACKAGE__->reflect(@_);
+}
+
+sub m2d_scale {
+ return __PACKAGE__->scale(@_);
+}
+
+1;
+
+=head1 AUTHOR
+
+Tony Cook <tony@develop-help.com>
+
+=head1 BUGS
+
+Needs a way to invert matrixes.
+
+=head1 SEE ALSO
+
+Imager(3), Imager::Font(3)
+
+http://imager.perl.org/
+
+=cut