Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | package Pastel::Geometry::AffineTransform;\r |
2 | @ISA = qw(Pastel::Mixin::Mixin );\r | |
3 | use Carp;\r | |
4 | use strict;\r | |
5 | \r | |
6 | # Perl module for Pastel::Geometry::AffineTransform\r | |
7 | # Cared for by Malay<curiouser@ccmb.ap.nic.in>\r | |
8 | # Copyright 2001, Malay Kumar Basu\r | |
9 | # You may distribute this module under the same terms as perl itself\r | |
10 | \r | |
11 | =head1 NAME\r | |
12 | \r | |
13 | Pastel::Geometry::AffineTranform\r | |
14 | \r | |
15 | This module encapsulates the 2D tranformation matrix of graphics.\r | |
16 | \r | |
17 | =head1 DESCRIPTION\r | |
18 | \r | |
19 | Every elements of the graphics object can be geometrically transformed. \r | |
20 | SVG specification allows - Translation, Scaling, Roatation and Skew. \r | |
21 | Transformation itself is represented by a 3 X 3 matrix. Like in Java \r | |
22 | AffineTranform class we will represent it here like this-\r | |
23 | \r | |
24 | [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ]\r | |
25 | [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ]\r | |
26 | [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]\r | |
27 | \r | |
28 | Where x' and y' are the new coordinates and x and y are the old ones.\r | |
29 | In SVG it is represented as-\r | |
30 | <g transform="matrix(m00,m10,m01,m11,m02,m12)">...</g>\r | |
31 | \r | |
32 | <B>Translation:</B>\r | |
33 | \r | |
34 | [ x'] [ 1 0 tx ] [ x ] \r | |
35 | [ y'] = [ 0 1 ty ] [ y ] \r | |
36 | [ 1 ] [ 0 0 1 ] [ 1 ] \r | |
37 | \r | |
38 | Where tx and ty are the distances to translate. It is represented\r | |
39 | in SVG as-\r | |
40 | <g transform="translate(tx, ty)">...</g>\r | |
41 | \r | |
42 | <B>Scaling:</B> \r | |
43 | \r | |
44 | [ x'] [ Sx 0 0 ] [ x ] \r | |
45 | [ y'] = [ 0 Sy 0 ] [ y ] \r | |
46 | [ 1 ] [ 0 0 1 ] [ 1 ]\r | |
47 | \r | |
48 | In SVG-\r | |
49 | <g transform="scale(Sx, Sy)">...</g>\r | |
50 | If Sy is not provided it is assumed to be equals to Sx.\r | |
51 | \r | |
52 | <b>Rotation:</b>\r | |
53 | [ x'] [ cos(a) -sin(a) 0 ] [ x ] \r | |
54 | [ y'] = [ sin(a) cos(a) 0 ] [ y ] \r | |
55 | [ 1 ] [ 0 0 1 ] [ 1 ]\r | |
56 | \r | |
57 | In SVG-\r | |
58 | \r | |
59 | <g transform="rotate(a, [x, y])">...</g>\r | |
60 | If x and y are provided is like translating to that point then rotating\r | |
61 | and then coming to the original position.\r | |
62 | \r | |
63 | <b>SkewX and Y:</b>\r | |
64 | \r | |
65 | <g transform="skewX(a)">...</g>\r | |
66 | <g transform="skewY(a)">...</g>\r | |
67 | \r | |
68 | =head1 SYNOPSIS\r | |
69 | \r | |
70 | use Pastel;\r | |
71 | my $g2 = Pastel::Graphics->new(...);\r | |
72 | # Create two tranfoms\r | |
73 | my $transform1 = Pastel::Geometry::AffineTranform->new();\r | |
74 | my $transform2 = Pastel::Geometry::AffineTranform->new();\r | |
75 | \r | |
76 | # Modify Transfom1\r | |
77 | $transform1->set_to_indentity();\r | |
78 | $transform1->rotate(45);\r | |
79 | \r | |
80 | # Modify Transform2\r | |
81 | $transform2->scale(0.5,0.5);\r | |
82 | \r | |
83 | # Join both the transform\r | |
84 | $transform1->concatanate($transform2);\r | |
85 | \r | |
86 | # To concatanate to existing transform in $g2 call transform()\r | |
87 | $g2->transform($transform1);\r | |
88 | \r | |
89 | # To replace the existing transform\r | |
90 | $g2->set_transform($transform2);\r | |
91 | \r | |
92 | =head1 CONSTRUCTORS \r | |
93 | \r | |
94 | =over 4\r | |
95 | \r | |
96 | =item Pastel::Geometry::AffineTransform->new()\r | |
97 | \r | |
98 | =item Pastel::Geometry::AffineTransform->new(-transform=>$tx)\r | |
99 | \r | |
100 | $tx is another Pastel::Geometry::AffineTransform object. \r | |
101 | \r | |
102 | =item Pastel::Geometry::AffineTransform->new(@array)\r | |
103 | \r | |
104 | @array is 4 or 6 elements numbers representing 4 non-tranaslatable entries\r | |
105 | or the complete array of 6 specifiable entries of 3 X 3 transformation matrix.\r | |
106 | \r | |
107 | =item Pastel::Geometry::AffineTransform->new(-m00=>$n, -m10=>$n, -m01=>$n, -m11=>$n, -m02=>$n, -m12=>, $n)\r | |
108 | \r | |
109 | Complete transformation matrix. $n = numbers.\r | |
110 | \r | |
111 | =item Pastel::Geometry::AffineTransform->new($n1,$n2,$n3,$n4,$n5,$n6)\r | |
112 | \r | |
113 | =item Pastel::Geometry::AffineTransform->new(-m00=>$n, -m10=>$n, -m01=>$n, -m11=>$n)\r | |
114 | \r | |
115 | =back\r | |
116 | \r | |
117 | =cut\r | |
118 | \r | |
119 | sub new {\r | |
120 | my $class = shift;\r | |
121 | my $self = {};\r | |
122 | bless $self, ref($class) || $class;\r | |
123 | $self->_init(@_);\r | |
124 | return $self;\r | |
125 | }\r | |
126 | \r | |
127 | sub _init {\r | |
128 | my ($self, @args) = @_;\r | |
129 | \r | |
130 | if(@args == 0){ # Default empty constructor\r | |
131 | return $self;\r | |
132 | }\r | |
133 | \r | |
134 | if(@args < 4){ # Another Affinetranform object passed??\r | |
135 | \r | |
136 | if( $args[0] =~ /transform/i){ # Check whther a named perl-style? \r | |
137 | \r | |
138 | if($args[1]->isa("Pastel::Geometry::AffineTransform")){\r | |
139 | $self = $args[1]->clone();\r | |
140 | return $self;\r | |
141 | }else {\r | |
142 | croak("Illegal parameters in construction of \r | |
143 | Pastel::Geometry::AffineTransform");\r | |
144 | }\r | |
145 | \r | |
146 | } elsif(ref($args[0]) && \r | |
147 | $args[0]->isa("Pastel::Geometry::Transform")){\r | |
148 | $self = $args[0]->clone();\r | |
149 | return $self;\r | |
150 | } else { \r | |
151 | croak("Illegal parameters in construction of \r | |
152 | Pastel::Geometry::AffineTransform");\r | |
153 | }\r | |
154 | }\r | |
155 | \r | |
156 | if(@args >= 4){ # Definitely matrix data passed \r | |
157 | my(@m) = $self->_rearrange(["M00","M10","M01","M11","M02","M12"],\r | |
158 | @args);\r | |
159 | $self->{m00} = $m[0];\r | |
160 | $self->{m10} = $m[1];\r | |
161 | $self->{m01} = $m[2];\r | |
162 | $self->{m11} = $m[3];\r | |
163 | if(@m > 5){ # Full set of 6 data???\r | |
164 | $self->{m02} = $m[4];\r | |
165 | $self->{m12} = $m[5];\r | |
166 | }\r | |
167 | } \r | |
168 | \r | |
169 | }\r | |
170 | \r | |
171 | 1;\r |