7
7
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
8
8
//
9
9
10
+ #if os(OSX) || os(iOS)
11
+ import Darwin
12
+ #elseif os(Linux)
13
+ import Glibc
14
+ #endif
10
15
11
16
public struct NSAffineTransformStruct {
12
17
public var m11 : CGFloat
@@ -15,7 +20,11 @@ public struct NSAffineTransformStruct {
15
20
public var m22 : CGFloat
16
21
public var tX : CGFloat
17
22
public var tY : CGFloat
18
- public init ( ) { NSUnimplemented ( ) }
23
+
24
+ public init ( ) {
25
+ self . init ( m11: CGFloat ( ) , m12: CGFloat ( ) , m21: CGFloat ( ) , m22: CGFloat ( ) , tX: CGFloat ( ) , tY: CGFloat ( ) )
26
+ }
27
+
19
28
public init ( m11: CGFloat , m12: CGFloat , m21: CGFloat , m22: CGFloat , tX: CGFloat , tY: CGFloat ) {
20
29
( self . m11, self . m12, self . m21, self . m22) = ( m11, m12, m21, m22)
21
30
( self . tX, self . tY) = ( tX, tY)
@@ -28,7 +37,11 @@ public class NSAffineTransform : NSObject, NSCopying, NSSecureCoding {
28
37
NSUnimplemented ( )
29
38
}
30
39
public func copyWithZone( zone: NSZone ) -> AnyObject {
31
- NSUnimplemented ( )
40
+ return NSAffineTransform ( transform: self )
41
+ }
42
+ // Necessary because `NSObject.copy()` returns `self`.
43
+ public override func copy( ) -> AnyObject {
44
+ return copyWithZone ( nil )
32
45
}
33
46
public required init ? ( coder aDecoder: NSCoder ) {
34
47
NSUnimplemented ( )
@@ -38,95 +51,246 @@ public class NSAffineTransform : NSObject, NSCopying, NSSecureCoding {
38
51
}
39
52
40
53
// Initialization
41
- public convenience init ( transform: NSAffineTransform ) { NSUnimplemented ( ) }
54
+ public convenience init ( transform: NSAffineTransform ) {
55
+ self . init ( )
56
+ transformStruct = transform. transformStruct
57
+ }
58
+
42
59
public override init ( ) {
43
- transformStruct = NSAffineTransformStruct ( m11: CGFloat ( 1.0 ) , m12: CGFloat ( ) , m21: CGFloat ( ) , m22: CGFloat ( 1.0 ) , tX: CGFloat ( ) , tY: CGFloat ( ) )
60
+ transformStruct = NSAffineTransformStruct (
61
+ m11: CGFloat ( 1.0 ) , m12: CGFloat ( ) ,
62
+ m21: CGFloat ( ) , m22: CGFloat ( 1.0 ) ,
63
+ tX: CGFloat ( ) , tY: CGFloat ( )
64
+ )
44
65
}
45
66
46
67
// Translating
47
68
public func translateXBy( deltaX: CGFloat , yBy deltaY: CGFloat ) {
48
- let matrix = transformStruct. matrix3x3
49
- let translationMatrix = Matrix3x3 ( CGFloat ( 1.0 ) , CGFloat ( ) , deltaX,
50
- CGFloat ( ) , CGFloat ( 1.0 ) , deltaY,
51
- CGFloat ( ) , CGFloat ( ) , CGFloat ( 1.0 ) )
52
- let product = multiplyMatrix3x3 ( matrix, byMatrix3x3: translationMatrix)
53
- transformStruct = NSAffineTransformStruct ( matrix: product)
69
+ let translation = NSAffineTransformStruct . translation ( tX: deltaX, tY: deltaY)
70
+
71
+ transformStruct = transformStruct. concat ( translation)
54
72
}
55
73
56
74
// Rotating
57
- public func rotateByDegrees( angle: CGFloat ) { NSUnimplemented ( ) }
58
- public func rotateByRadians( angle: CGFloat ) { NSUnimplemented ( ) }
75
+ public func rotateByDegrees( angle: CGFloat ) {
76
+ let rotation = NSAffineTransformStruct . rotation ( degrees: angle)
77
+
78
+ transformStruct = transformStruct. concat ( rotation)
79
+ }
80
+ public func rotateByRadians( angle: CGFloat ) {
81
+ let rotation = NSAffineTransformStruct . rotation ( radians: angle)
82
+
83
+ transformStruct = transformStruct. concat ( rotation)
84
+ }
59
85
60
86
// Scaling
61
- public func scaleBy( scale: CGFloat ) { NSUnimplemented ( ) }
62
- public func scaleXBy( scaleX: CGFloat , yBy scaleY: CGFloat ) { NSUnimplemented ( ) }
87
+ public func scaleBy( scale: CGFloat ) {
88
+ let scale = NSAffineTransformStruct . scale ( sX: scale, sY: scale)
89
+
90
+ transformStruct = transformStruct. concat ( scale)
91
+ }
92
+ public func scaleXBy( scaleX: CGFloat , yBy scaleY: CGFloat ) {
93
+ let scale = NSAffineTransformStruct . scale ( sX: scaleX, sY: scaleY)
94
+
95
+ transformStruct = transformStruct. concat ( scale)
96
+ }
63
97
64
98
// Inverting
65
- public func invert( ) { NSUnimplemented ( ) }
99
+ public func invert( ) {
100
+ if let inverse = transformStruct. inverse {
101
+ transformStruct = inverse
102
+ }
103
+ else {
104
+ preconditionFailure ( " NSAffineTransform: Transform has no inverse " )
105
+ }
106
+ }
66
107
67
108
// Transforming with transform
68
- public func appendTransform( transform: NSAffineTransform ) { NSUnimplemented ( ) }
69
- public func prependTransform( transform: NSAffineTransform ) { NSUnimplemented ( ) }
109
+ public func appendTransform( transform: NSAffineTransform ) {
110
+ transformStruct = transformStruct. concat ( transform. transformStruct)
111
+ }
112
+ public func prependTransform( transform: NSAffineTransform ) {
113
+ transformStruct = transform. transformStruct. concat ( transformStruct)
114
+ }
70
115
71
116
// Transforming points and sizes
72
117
public func transformPoint( aPoint: NSPoint ) -> NSPoint {
73
- let matrix = transformStruct. matrix3x3
74
- let vector = Vector3 ( aPoint. x, aPoint. y, CGFloat ( 1.0 ) )
75
- let resultVector = multiplyMatrix3x3 ( matrix, byVector3: vector)
76
- return NSMakePoint ( resultVector. m1, resultVector. m2)
118
+ return transformStruct. applied ( toPoint: aPoint)
77
119
}
78
120
79
121
public func transformSize( aSize: NSSize ) -> NSSize {
80
- let matrix = transformStruct. matrix3x3
81
- let vector = Vector3 ( aSize. width, aSize. height, CGFloat ( 1.0 ) )
82
- let resultVector = multiplyMatrix3x3 ( matrix, byVector3: vector)
83
- return NSMakeSize ( resultVector. m1, resultVector. m2)
122
+ return transformStruct. applied ( toSize: aSize)
84
123
}
85
124
86
125
// Transform Struct
87
126
public var transformStruct : NSAffineTransformStruct
88
127
}
89
128
90
- // Private helper functions and structures for linear algebra operations.
91
- private typealias Vector3 = ( m1: CGFloat , m2: CGFloat , m3: CGFloat )
92
- private typealias Matrix3x3 =
93
- ( m11: CGFloat , m12: CGFloat , m13: CGFloat ,
94
- m21: CGFloat , m22: CGFloat , m23: CGFloat ,
95
- m31: CGFloat , m32: CGFloat , m33: CGFloat )
96
-
97
- private func multiplyMatrix3x3( matrix: Matrix3x3 , byVector3 vector: Vector3 ) -> Vector3 {
98
- let x = matrix. m11 * vector. m1 + matrix. m12 * vector. m2 + matrix. m13 * vector. m3
99
- let y = matrix. m21 * vector. m1 + matrix. m22 * vector. m2 + matrix. m23 * vector. m3
100
- let z = matrix. m31 * vector. m1 + matrix. m32 * vector. m2 + matrix. m33 * vector. m3
101
-
102
- return Vector3 ( x, y, z)
103
- }
104
-
105
- private func multiplyMatrix3x3( matrix: Matrix3x3 , byMatrix3x3 otherMatrix: Matrix3x3 ) -> Matrix3x3 {
106
- let column1 = Vector3 ( otherMatrix. m11, otherMatrix. m21, otherMatrix. m31)
107
- let newColumn1 = multiplyMatrix3x3 ( matrix, byVector3: column1)
108
-
109
- let column2 = Vector3 ( otherMatrix. m12, otherMatrix. m22, otherMatrix. m32)
110
- let newColumn2 = multiplyMatrix3x3 ( matrix, byVector3: column2)
111
-
112
- let column3 = Vector3 ( otherMatrix. m13, otherMatrix. m23, otherMatrix. m33)
113
- let newColumn3 = multiplyMatrix3x3 ( matrix, byVector3: column3)
114
-
115
- return Matrix3x3 ( newColumn1. m1, newColumn2. m1, newColumn3. m1,
116
- newColumn1. m2, newColumn2. m2, newColumn3. m2,
117
- newColumn1. m3, newColumn2. m3, newColumn3. m3)
118
- }
119
129
120
130
private extension NSAffineTransformStruct {
121
- init ( matrix: Matrix3x3 ) {
122
- self . init ( m11: matrix. m11, m12: matrix. m12,
123
- m21: matrix. m21, m22: matrix. m22,
124
- tX: matrix. m13, tY: matrix. m23)
131
+ /**
132
+ Creates an affine transformation matrix from translation values.
133
+ The matrix takes the following form:
134
+
135
+ [ 1 0 tX ]
136
+ [ 0 1 tY ]
137
+ [ 0 0 1 ]
138
+ */
139
+ static func translation( tX tX: CGFloat , tY: CGFloat ) -> NSAffineTransformStruct {
140
+ return NSAffineTransformStruct (
141
+ m11: CGFloat ( 1.0 ) , m12: CGFloat ( ) ,
142
+ m21: CGFloat ( ) , m22: CGFloat ( 1.0 ) ,
143
+ tX: tX, tY: tY
144
+ )
145
+ }
146
+
147
+ /**
148
+ Creates an affine transformation matrix from scaling values.
149
+ The matrix takes the following form:
150
+
151
+ [ sX 0 0 ]
152
+ [ 0 sY 0 ]
153
+ [ 0 0 1 ]
154
+ */
155
+ static func scale( sX sX: CGFloat , sY: CGFloat ) -> NSAffineTransformStruct {
156
+ return NSAffineTransformStruct (
157
+ m11: sX, m12: CGFloat ( ) ,
158
+ m21: CGFloat ( ) , m22: sY,
159
+ tX: CGFloat ( ) , tY: CGFloat ( )
160
+ )
161
+ }
162
+
163
+ /**
164
+ Creates an affine transformation matrix from rotation value (angle in radians).
165
+ The matrix takes the following form:
166
+
167
+ [ cos α -sin α 0 ]
168
+ [ sin α cos α 0 ]
169
+ [ 0 0 1 ]
170
+ */
171
+ static func rotation( radians angle: CGFloat ) -> NSAffineTransformStruct {
172
+ let α = Double ( angle)
173
+
174
+ return NSAffineTransformStruct (
175
+ m11: CGFloat ( cos ( α) ) , m12: CGFloat ( - sin( α) ) ,
176
+ m21: CGFloat ( sin ( α) ) , m22: CGFloat ( cos ( α) ) ,
177
+ tX: CGFloat ( ) , tY: CGFloat ( )
178
+ )
179
+ }
180
+
181
+ /**
182
+ Creates an affine transformation matrix from a rotation value (angle in degrees).
183
+ The matrix takes the following form:
184
+
185
+ [ cos α -sin α 0 ]
186
+ [ sin α cos α 0 ]
187
+ [ 0 0 1 ]
188
+ */
189
+ static func rotation( degrees angle: CGFloat ) -> NSAffineTransformStruct {
190
+ let α = Double ( angle) * M_PI / 180.0
191
+
192
+ return rotation ( radians: CGFloat ( α) )
125
193
}
194
+
195
+ /**
196
+ Creates an affine transformation matrix by combining the receiver with `transformStruct`.
197
+ That is, it computes `T * M` and returns the result, where `T` is the receiver's and `M` is
198
+ the `transformStruct`'s affine transformation matrix.
199
+ The resulting matrix takes the following form:
200
+
201
+ [ m11_T m12_T tX_T ] [ m11_M m12_M tX_M ]
202
+ T * M = [ m21_T m22_T tY_T ] [ m21_M m22_M tY_M ]
203
+ [ 0 0 1 ] [ 0 0 1 ]
204
+
205
+ [ (m11_T*m11_M + m12_T*m21_M) (m11_T*m12_M + m12_T*m22_M) (m11_T*tX_M + m12_T*tY_M + tX_T) ]
206
+ = [ (m21_T*m11_M + m22_T*m21_M) (m21_T*m12_M + m22_T*m22_M) (m21_T*tX_M + m22_T*tY_M + tY_T) ]
207
+ [ 0 0 1 ]
208
+ */
209
+ func concat( transformStruct: NSAffineTransformStruct ) -> NSAffineTransformStruct {
210
+ let ( t, m) = ( self , transformStruct)
126
211
127
- var matrix3x3 : Matrix3x3 {
128
- return Matrix3x3 ( m11, m12, tX,
129
- m21, m22, tY,
130
- CGFloat ( ) , CGFloat ( ) , CGFloat ( ) )
212
+ return NSAffineTransformStruct (
213
+ m11: ( t. m11 * m. m11) + ( t. m12 * m. m21) , m12: ( t. m11 * m. m12) + ( t. m12 * m. m22) ,
214
+ m21: ( t. m21 * m. m11) + ( t. m22 * m. m21) , m22: ( t. m21 * m. m12) + ( t. m22 * m. m22) ,
215
+ tX: ( t. m11 * m. tX) + ( t. m12 * m. tY) + t. tX,
216
+ tY: ( t. m21 * m. tX) + ( t. m22 * m. tY) + t. tY
217
+ )
218
+ }
219
+
220
+ /**
221
+ Applies the affine transformation to `toPoint` and returns the result.
222
+ The resulting point takes the following form:
223
+
224
+ [ x' ] [ x ] [ m11 m12 tX ] [ x ] [ m11*x + m12*y + tX ]
225
+ [ y' ] = T [ y ] = [ m21 m22 tY ] [ y ] = [ m21*x + m22*y + tY ]
226
+ [ 1 ] [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]
227
+ */
228
+ func applied( toPoint p: NSPoint ) -> NSPoint {
229
+ let x = ( m11 * p. x) + ( m12 * p. y) + tX
230
+ let y = ( m21 * p. x) + ( m22 * p. y) + tY
231
+
232
+ return NSPoint ( x: x, y: y)
233
+ }
234
+
235
+ /**
236
+ Applies the affine transformation to `toSize` and returns the result.
237
+ The resulting size takes the following form:
238
+
239
+ [ w' ] [ w ] [ m11 m12 tX ] [ w ] [ m11*w + m12*h ]
240
+ [ h' ] = T [ h ] = [ m21 m22 tY ] [ h ] = [ m21*w + m22*h ]
241
+ [ 0 ] [ 0 ] [ 0 0 1 ] [ 1 ] [ 0 ]
242
+
243
+ Note: Translation has no effect on the size.
244
+ */
245
+ func applied( toSize s: NSSize ) -> NSSize {
246
+ let w = ( m11 * s. width) + ( m12 * s. height)
247
+ let h = ( m21 * s. width) + ( m22 * s. height)
248
+
249
+ return NSSize ( width: w, height: h)
250
+ }
251
+
252
+
253
+ /**
254
+ Returns the inverse affine transformation matrix or `nil` if it has no inverse.
255
+ The receiver's affine transformation matrix can be divided into matrix sub-block as
256
+
257
+ [ M t ]
258
+ [ 0 1 ]
259
+
260
+ where `M` represents the linear map and `t` the translation vector.
261
+
262
+ The inversion can then be calculated as
263
+
264
+ [ inv(M) -inv(M) * t ]
265
+ [ 0 1 ]
266
+
267
+ if `M` is invertible.
268
+ */
269
+ var inverse : NSAffineTransformStruct ? {
270
+ get {
271
+ // Calculate determinant of M: det(M)
272
+ let det = ( m11 * m22) - ( m12 * m21)
273
+ if det == CGFloat ( ) {
274
+ return nil
275
+ }
276
+
277
+ let detReciprocal = CGFloat ( 1.0 ) / det
278
+
279
+ // Calculate the inverse of M: inv(M)
280
+ let ( invM11, invM12) = ( detReciprocal * m22, detReciprocal * - m12)
281
+ let ( invM21, invM22) = ( detReciprocal * - m21, detReciprocal * m11)
282
+
283
+ // Calculate -inv(M)*t
284
+ let invTX = ( ( - invM11 * tX) + ( - invM12 * tY) )
285
+ let invTY = ( ( - invM21 * tX) + ( - invM22 * tY) )
286
+
287
+ return NSAffineTransformStruct (
288
+ m11: invM11, m12: invM12,
289
+ m21: invM21, m22: invM22,
290
+ tX: invTX, tY: invTY
291
+ )
292
+ }
131
293
}
132
294
}
295
+
296
+
0 commit comments