1/** <title>NSAffineTransform.m</title>
2
3   <abstract>
4   This class provides a way to perform affine transforms.  It provides
5   a matrix for transforming from one coordinate system to another.
6   </abstract>
7   Copyright (C) 1996,1999 Free Software Foundation, Inc.
8
9   Author: Ovidiu Predescu <ovidiu@net-community.com>
10   Date: August 1997
11   Author: Richard Frith-Macdonald <richard@brainstorm.co.uk>
12   Date: March 1999
13
14   This file is part of the GNUstep GUI Library.
15
16   This library is free software; you can redistribute it and/or
17   modify it under the terms of the GNU Lesser General Public
18   License as published by the Free Software Foundation; either
19   version 2 of the License, or (at your option) any later version.
20
21   This library is distributed in the hope that it will be useful,
22   but WITHOUT ANY WARRANTY; without even the implied warranty of
23   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
24   Lesser General Public License for more details.
25
26   You should have received a copy of the GNU Lesser General Public
27   License along with this library; see the file COPYING.LIB.
28   If not, see <http://www.gnu.org/licenses/> or write to the
29   Free Software Foundation, 51 Franklin Street, Fifth Floor,
30   Boston, MA 02110-1301, USA.
31*/
32
33#import "config.h"
34#include <math.h>
35
36#import <Foundation/NSArray.h>
37#import <Foundation/NSDebug.h>
38#import <Foundation/NSException.h>
39#import <Foundation/NSString.h>
40
41#import "AppKit/NSAffineTransform.h"
42#import "AppKit/NSBezierPath.h"
43#import "AppKit/PSOperators.h"
44
45/* Private definitions */
46#define A matrix.m11
47#define B matrix.m12
48#define C matrix.m21
49#define D matrix.m22
50#define TX matrix.tX
51#define TY matrix.tY
52
53/* A Postscript matrix looks like this:
54
55  /  a  b  0 \
56  |  c  d  0 |
57  \ tx ty  1 /
58
59 */
60
61static const CGFloat pi = 3.1415926535897932384626434;
62
63@implementation NSAffineTransform (GUIAdditions)
64
65/**
66 * Concatenates the receiver's matrix with the one in the current graphics
67 * context.
68 */
69- (void) concat
70{
71  // FIXME Should use GSConcatCTM:
72  NSAffineTransformStruct ats = [self transformStruct];
73  CGFloat floatMatrix[6];
74
75  floatMatrix[0] = ats.m11;
76  floatMatrix[1] = ats.m12;
77  floatMatrix[2] = ats.m21;
78  floatMatrix[3] = ats.m22;
79  floatMatrix[4] = ats.tX;
80  floatMatrix[5] = ats.tY;
81  PSconcat(floatMatrix);
82}
83
84
85/**
86 * Get the currently active graphics context's transformation
87 * matrix and set it into the receiver.
88 */
89- (void) set
90{
91  GSSetCTM(GSCurrentContext(), self);
92}
93
94/**
95 * <p>Applies the receiver's transformation matrix to each point in
96 * the bezier path, then returns the result.  The original bezier
97 * path is not modified.
98 * </p>
99 */
100- (NSBezierPath*) transformBezierPath: (NSBezierPath*)aPath
101{
102  NSBezierPath *path = [aPath copy];
103
104  [path transformUsingAffineTransform: self];
105  return AUTORELEASE(path);
106}
107
108@end /* NSAffineTransform (GUIAdditions) */
109
110@implementation NSAffineTransform (GNUstep)
111
112- (void) scaleTo: (CGFloat)sx : (CGFloat)sy
113{
114  NSAffineTransformStruct matrix = [self transformStruct];
115
116  /* If it's rotated.  */
117  if (B != 0  ||  C != 0)
118    {
119      // FIXME: This case does not handle shear.
120      CGFloat angle = [self rotationAngle];
121
122      // Keep the translation and add scaling
123      A = sx; B = 0;
124      C = 0; D = sy;
125      [self setTransformStruct: matrix];
126
127      // Prepend the rotation to the scaling and translation
128      [self rotateByDegrees: angle];
129    }
130  else
131    {
132      A = sx; B = 0;
133      C = 0; D = sy;
134      [self setTransformStruct: matrix];
135    }
136}
137
138- (void) translateToPoint: (NSPoint)point
139{
140  [self translateXBy: point.x yBy: point.y];
141}
142
143- (void) makeIdentityMatrix
144{
145  [self init];
146}
147
148- (void) setFrameOrigin: (NSPoint)point
149{
150  NSAffineTransformStruct matrix = [self transformStruct];
151  CGFloat dx = point.x - TX;
152  CGFloat dy = point.y - TY;
153
154  [self translateXBy: dx yBy: dy];
155}
156
157- (void) setFrameRotation: (CGFloat)angle
158{
159  [self rotateByDegrees: angle - [self rotationAngle]];
160}
161
162- (CGFloat) rotationAngle
163{
164  NSAffineTransformStruct matrix = [self transformStruct];
165  CGFloat rotationAngle = atan2(-C, A);
166
167  rotationAngle *= 180.0 / pi;
168  if (rotationAngle < 0.0)
169    rotationAngle += 360.0;
170
171  return rotationAngle;
172}
173
174- (void) concatenateWith: (NSAffineTransform*)anotherMatrix
175{
176  GSOnceMLog(@"deprecated ... use -prependTransform:");
177  [self prependTransform: anotherMatrix];
178}
179
180- (void) concatenateWithMatrix: (const float[6])anotherMatrix
181{
182  NSAffineTransformStruct amat;
183  NSAffineTransform 	*other;
184
185  GSOnceMLog(@"deprecated ... use -prependTransform:");
186  amat.m11 = anotherMatrix[0];
187  amat.m12 = anotherMatrix[1];
188  amat.m21 = anotherMatrix[2];
189  amat.m22 = anotherMatrix[3];
190  amat.tX  = anotherMatrix[4];
191  amat.tY  = anotherMatrix[5];
192  other = [NSAffineTransform new];
193  [other setTransformStruct: amat];
194  [self prependTransform: other];
195  RELEASE(other);
196}
197
198- (void)inverse
199{
200  GSOnceMLog(@"deprecated ... use -invert:");
201  [self invert];
202}
203
204- (BOOL) isRotated
205{
206  NSAffineTransformStruct matrix = [self transformStruct];
207
208  if (B == 0 && C == 0)
209    {
210      return NO;
211    }
212  else
213    {
214      return YES;
215    }
216}
217
218- (void) boundingRectFor: (NSRect)rect result: (NSRect*)newRect
219{
220  NSAffineTransformStruct matrix = [self transformStruct];
221  /* Shortcuts of the usual rect values */
222  CGFloat x = rect.origin.x;
223  CGFloat y = rect.origin.y;
224  CGFloat width = rect.size.width;
225  CGFloat height = rect.size.height;
226  CGFloat xc[3];
227  CGFloat yc[3];
228  CGFloat min_x;
229  CGFloat max_x;
230  CGFloat min_y;
231  CGFloat max_y;
232  int i;
233
234  max_x = A * x + C * y + TX;
235  max_y = B * x + D * y + TY;
236  xc[0] = max_x + A * width;
237  yc[0] = max_y + B * width;
238  xc[1] = max_x + C * height;
239  yc[1] = max_y + D * height;
240  xc[2] = max_x + A * width + C * height;
241  yc[2] = max_y + B * width + D * height;
242
243  min_x = max_x;
244  min_y = max_y;
245
246  for (i = 0; i < 3; i++)
247    {
248      if (xc[i] < min_x)
249	min_x = xc[i];
250      if (xc[i] > max_x)
251	max_x = xc[i];
252
253      if (yc[i] < min_y)
254	 min_y = yc[i];
255      if (yc[i] > max_y)
256	max_y = yc[i];
257    }
258
259  newRect->origin.x = min_x;
260  newRect->origin.y = min_y;
261  newRect->size.width = max_x -min_x;
262  newRect->size.height = max_y -min_y;
263}
264
265- (NSPoint) pointInMatrixSpace: (NSPoint)point
266{
267  GSOnceMLog(@"deprecated ... use -transformPoint:");
268  return [self transformPoint: point];
269}
270
271- (NSPoint) deltaPointInMatrixSpace: (NSPoint)point
272{
273  NSAffineTransformStruct matrix = [self transformStruct];
274  NSPoint new;
275
276  new.x = A * point.x + C * point.y;
277  new.y = B * point.x + D * point.y;
278
279  return new;
280}
281
282- (NSSize) sizeInMatrixSpace: (NSSize)size
283{
284  GSOnceMLog(@"deprecated ... use -transformSize:");
285  return [self transformSize: size];
286}
287
288- (NSRect) rectInMatrixSpace: (NSRect)rect
289{
290  NSRect new;
291
292  new.origin = [self transformPoint: rect.origin];
293  new.size = [self transformSize: rect.size];
294
295  if (new.size.width < 0)
296    {
297      new.origin.x += new.size.width;
298      new.size.width *= -1;
299    }
300
301  if (new.size.height < 0)
302    {
303      new.origin.y += new.size.height;
304      new.size.height *= -1;
305    }
306
307  return new;
308}
309
310- (void) setMatrix: (const float[6])replace
311{
312  NSAffineTransformStruct matrix;
313
314  GSOnceMLog(@"deprecated ... use -setTransformStruct:");
315  matrix.m11 = replace[0];
316  matrix.m12 = replace[1];
317  matrix.m21 = replace[2];
318  matrix.m22 = replace[3];
319  matrix.tX = replace[4];
320  matrix.tY = replace[5];
321  [self setTransformStruct: matrix];
322}
323
324- (void) getMatrix: (float[6])replace
325{
326  NSAffineTransformStruct matrix = [self transformStruct];
327
328  GSOnceMLog(@"deprecated ... use -transformStruct");
329  replace[0] = matrix.m11;
330  replace[1] = matrix.m12;
331  replace[2] = matrix.m21;
332  replace[3] = matrix.m22;
333  replace[4] = matrix.tX;
334  replace[5] = matrix.tY;
335}
336
337- (void) takeMatrixFromTransform: (NSAffineTransform *)aTransform
338{
339  NSAffineTransformStruct matrix;
340
341  GSOnceMLog(@"deprecated ... use -transformStruct and setTransformStruct:");
342  matrix = [aTransform transformStruct];
343  [self setTransformStruct: matrix];
344}
345
346
347@end /* NSAffineTransform (GNUstep) */
348
349