1 /*****
2 * transform.h
3 * Andy Hammerlindl 2002/05/22
4 *
5 * The transform datatype stores an affine transformation on the plane
6 * The datamembers are x, y, xx, xy, yx, and yy. A pair (x,y) is
7 * transformed as
8 * x' = t.x + t.xx * x + t.xy * y
9 * y' = t.y + t.yx * x + t.yy * y
10 *****/
11
12 #ifndef TRANSFORM_H
13 #define TRANSFORM_H
14
15 #include <iostream>
16
17 #include "pair.h"
18
19 namespace camp {
20
21 class transform : public gc {
22 double x;
23 double y;
24 double xx;
25 double xy;
26 double yx;
27 double yy;
28
29 public:
transform()30 transform()
31 : x(0.0), y(0.0), xx(1.0), xy(0.0), yx(0.0), yy(1.0) {}
32
~transform()33 virtual ~transform() {}
34
transform(double x,double y,double xx,double xy,double yx,double yy)35 transform(double x, double y,
36 double xx, double xy,
37 double yx, double yy)
38 : x(x), y(y), xx(xx), xy(xy), yx(yx), yy(yy) {}
39
getx()40 double getx() const { return x; }
gety()41 double gety() const { return y; }
getxx()42 double getxx() const { return xx; }
getxy()43 double getxy() const { return xy; }
getyx()44 double getyx() const { return yx; }
getyy()45 double getyy() const { return yy; }
46
47 friend transform operator+ (const transform& t, const transform& s)
48 {
49 return transform(t.x + s.x, t.y + s.y,
50 t.xx + s.xx, t.xy + s.xy,
51 t.yx + s.yx, t.yy + s.yy);
52 }
53
54 friend transform operator- (const transform& t, const transform& s)
55 {
56 return transform(t.x - s.x, t.y - s.y,
57 t.xx - s.xx, t.xy - s.xy,
58 t.yx - s.yx, t.yy - s.yy);
59 }
60
61 friend transform operator- (const transform& t)
62 {
63 return transform(-t.x, -t.y,
64 -t.xx, -t.xy,
65 -t.yx, -t.yy);
66 }
67
68 friend pair operator* (const transform& t, const pair& z)
69 {
70 double x = z.getx(), y = z.gety();
71 return pair(t.x + t.xx * x + t.xy * y, t.y + t.yx * x + t.yy * y);
72 }
73
74 // Calculates the composition of t and s, so for a pair, z,
75 // t * (s * z) == (t * s) * z
76 // Can be thought of as matrix multiplication.
77 friend transform operator* (const transform& t, const transform& s)
78 {
79 return transform(t.x + t.xx * s.x + t.xy * s.y,
80 t.y + t.yx * s.x + t.yy * s.y,
81 t.xx * s.xx + t.xy * s.yx,
82 t.xx * s.xy + t.xy * s.yy,
83 t.yx * s.xx + t.yy * s.yx,
84 t.yx * s.xy + t.yy * s.yy);
85 }
86
87 friend bool operator== (const transform& t1, const transform& t2)
88 {
89 return t1.x == t2.x && t1.y == t2.y &&
90 t1.xx == t2.xx && t1.xy == t2.xy &&
91 t1.yx == t2.yx && t1.yy == t2.yy;
92 }
93
94 friend bool operator!= (const transform& t1, const transform& t2)
95 {
96 return !(t1 == t2);
97 }
98
isIdentity()99 bool isIdentity() const
100 {
101 return x == 0.0 && y == 0.0 &&
102 xx == 1.0 && xy == 0.0 && yx == 0.0 && yy == 1.0;
103 }
104
isNull()105 bool isNull() const
106 {
107 return x == 0.0 && y == 0.0 &&
108 xx == 0.0 && xy == 0.0 && yx == 0.0 && yy == 0.0;
109 }
110
111 // Calculates the determinant, as if it were a matrix.
det(const transform & t)112 friend double det(const transform& t)
113 {
114 return t.xx * t.yy - t.xy * t.yx;
115 }
116
117 // Tells if the transformation is invertible (bijective).
invertible()118 bool invertible() const
119 {
120 return det(*this) != 0.0;
121 }
122
inverse(const transform & t)123 friend transform inverse(const transform& t)
124 {
125 double d = det(t);
126 if (d == 0.0)
127 reportError("inverting singular transform");
128
129 d=1.0/d;
130 return transform((t.xy * t.y - t.yy * t.x)*d,
131 (t.yx * t.x - t.xx * t.y)*d,
132 t.yy*d, -t.xy*d, -t.yx*d, t.xx*d);
133 }
134
135 friend ostream& operator<< (ostream& out, const transform& t)
136 {
137 return out << "(" << t.x << ","
138 << t.y << ","
139 << t.xx << ","
140 << t.xy << ","
141 << t.yx << ","
142 << t.yy << ")";
143 }
144 };
145
146 // The common transforms
147 static const transform identity;
148
shift(pair z)149 inline transform shift(pair z)
150 {
151 return transform (z.getx(), z.gety(), 1.0, 0.0, 0.0, 1.0);
152 }
153
xscale(double s)154 inline transform xscale(double s)
155 {
156 return transform (0.0, 0.0, s, 0.0, 0.0, 1.0);
157 }
158
yscale(double s)159 inline transform yscale(double s)
160 {
161 return transform (0.0, 0.0, 1.0, 0.0, 0.0, s);
162 }
163
scale(double s)164 inline transform scale(double s)
165 {
166 return transform (0.0, 0.0, s, 0.0, 0.0, s);
167 }
168
scale(double x,double y)169 inline transform scale(double x, double y)
170 {
171 return transform (0.0, 0.0, x, 0.0, 0.0, y);
172 }
173
scale(pair z)174 inline transform scale(pair z)
175 {
176 // Equivalent to multiplication by z.
177 double x = z.getx(), y = z.gety();
178 return transform (0.0, 0.0, x, -y, y, x);
179 }
180
slant(double s)181 inline transform slant(double s)
182 {
183 return transform (0.0, 0.0, 1.0, s, 0.0, 1.0);
184 }
185
rotate(double theta)186 inline transform rotate(double theta)
187 {
188 double s = sin(theta), c = cos(theta);
189 return transform (0.0, 0.0, c, -s, s, c);
190 }
191
192 // return rotate(angle(v)) if z != (0,0); otherwise return identity.
rotate(pair z)193 inline transform rotate(pair z)
194 {
195 double d=z.length();
196 if(d == 0.0) return identity;
197 d=1.0/d;
198 return transform (0.0, 0.0, d*z.getx(), -d*z.gety(), d*z.gety(), d*z.getx());
199 }
200
rotatearound(pair z,double theta)201 inline transform rotatearound(pair z, double theta)
202 {
203 // Notice the operators are applied from right to left.
204 // Could be optimized.
205 return shift(z) * rotate(theta) * shift(-z);
206 }
207
reflectabout(pair z,pair w)208 inline transform reflectabout(pair z, pair w)
209 {
210 if (z == w)
211 reportError("points determining line to reflect about must be distinct");
212
213 // Also could be optimized.
214 transform basis = shift(z) * scale(w-z);
215 transform flip = yscale(-1.0);
216
217 return basis * flip * inverse(basis);
218 }
219
220 // Return the rotational part of t.
rotation(transform t)221 inline transform rotation(transform t)
222 {
223 pair z(2.0*t.getxx()*t.getyy(),t.getyx()*t.getyy()-t.getxx()*t.getxy());
224 if(t.getxx() < 0) z=-z;
225 return rotate(atan2(z.gety(),z.getx()));
226 }
227
228 // Remove the x and y components, so that the new transform maps zero to zero.
shiftless(transform t)229 inline transform shiftless(transform t)
230 {
231 return transform(0, 0, t.getxx(), t.getxy(), t.getyx(), t.getyy());
232 }
233
234 // Return the translational component of t.
shift(transform t)235 inline transform shift(transform t)
236 {
237 return transform(t.getx(), t.gety(), 1.0, 0, 0, 1.0);
238 }
239
240 // Return the translational pair of t.
shiftpair(transform t)241 inline pair shiftpair(transform t)
242 {
243 return pair(t.getx(), t.gety());
244 }
245
matrix(pair lb,pair rt)246 inline transform matrix(pair lb, pair rt)
247 {
248 pair size=rt-lb;
249 return transform(lb.getx(),lb.gety(),size.getx(),0,0,size.gety());
250 }
251
252 } //namespace camp
253
254 GC_DECLARE_PTRFREE(camp::transform);
255
256 #endif
257