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