use Scalar::Util qw(reftype looks_like_number);
use Carp qw(croak);
-$VERSION = "1.011";
+$VERSION = "1.012";
=head1 NAME
if ($opts{'x'} || $opts{'y'}) {
$opts{'x'} ||= 0;
$opts{'y'} ||= 0;
- return $class->translate('x'=>-$opts{'x'}, 'y'=>-$opts{'y'})
+ return $class->translate('x'=>$opts{'x'}, 'y'=>$opts{'y'})
* $class->rotate(radians=>$angle)
- * $class->translate('x'=>$opts{'x'}, 'y'=>$opts{'y'});
+ * $class->translate('x'=>-$opts{'x'}, 'y'=>-$opts{'y'});
}
else {
my $sin = sin($angle);
}
}
+=item transform($x, $y)
+
+Transform a point the same way matrix_transform does.
+
+=cut
+
+sub transform {
+ my ($self, $x, $y) = @_;
+
+ my $sz = $x * $self->[6] + $y * $self->[7] + $self->[8];
+ my ($sx, $sy);
+ if (abs($sz) > 0.000001) {
+ $sx = ($x * $self->[0] + $y * $self->[1] + $self->[2]) / $sz;
+ $sy = ($x * $self->[3] + $y * $self->[4] + $self->[5]) / $sz;
+ }
+ else {
+ $sx = $sy = 0;
+ }
+
+ return ($sx, $sy);
+}
+
+=item compose(matrix...)
+
+Compose several matrices together for use in transformation.
+
+For example, for three matrices:
+
+ my $out = Imager::Matrix2d->compose($m1, $m2, $m3);
+
+is equivalent to:
+
+ my $out = $m3 * $m2 * $m1;
+
+Returns the identity matrix if no parameters are supplied.
+
+May return the supplied matrix if only one matrix is supplied.
+
+=cut
+
+sub compose {
+ my ($class, @in) = @_;
+
+ @in
+ or return $class->identity;
+
+ my $out = pop @in;
+ for my $m (reverse @in) {
+ $out = $out * $m;
+ }
+
+ return $out;
+}
+
=item _mult()
Implements the overloaded '*' operator. Internal use.
Currently both the left and right-hand sides of the operator must be
an Imager::Matrix2d.
+When composing a matrix for transformation you should multiply the
+matrices in the reverse order of the transformations:
+
+ my $shear = Imager::Matrix2d->shear(x => 0.1);
+ my $rotate = Imager::Matrix2d->rotate(degrees => 45);
+ my $shear_then_rotate = $rotate * $shear;
+
+or use the compose method:
+
+ my $shear_then_rotate = Imager::Matrix2d->compose($shear, $rotate);
+
=cut
sub _mult {
#!perl -w
use strict;
-use Test::More tests => 23;
+use Test::More tests => 25;
use Imager;
+use constant EPSILON => 0.000001;
BEGIN { use_ok('Imager::Matrix2d', ':handy') }
ok($died, "mult by bad scalar died");
like($@, qr/multiply by array ref or number/, "check message");
}
-
}
+{ # rt #99959 Imager::Matrix2d->rotate about (x, y) bug
+ my $rm = Imager::Matrix2d->rotate(degrees => 180, x => 10, y => 5);
+ my ($rx, $ry) = $rm->transform(0, 0);
+ ok(abs($rx - 20) < EPSILON, "x from rotate (0,0) around (10, 5)")
+ or print "# x = $rx\n";
+ ok(abs($ry - 10) < EPSILON, "y from rotate (0,0) around (10, 5)")
+ or print "# y = $ry\n";
+
+}
sub almost_equal {
my ($m1, $m2) = @_;