Skip to content

Commit 5e9dca9

Browse files
authored
Merge pull request #1266 from spevans/pr_affine_transform
2 parents 82b286a + 13b0a89 commit 5e9dca9

File tree

2 files changed

+133
-76
lines changed

2 files changed

+133
-76
lines changed

Foundation/AffineTransform.swift

Lines changed: 111 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,20 @@ public struct AffineTransform : ReferenceConvertible, Hashable, CustomStringConv
3232
public var m22: CGFloat
3333
public var tX: CGFloat
3434
public var tY: CGFloat
35-
35+
36+
/// Creates an affine transformation matrix with identity values.
3637
public init() {
37-
self.init(m11: CGFloat(), m12: CGFloat(), m21: CGFloat(), m22: CGFloat(), tX: CGFloat(), tY: CGFloat())
38+
self.init(m11: 1.0, m12: 0.0,
39+
m21: 0.0, m22: 1.0,
40+
tX: 0.0, tY: 0.0)
3841
}
42+
43+
/// Creates an affine transformation.
3944
public init(m11: CGFloat, m12: CGFloat, m21: CGFloat, m22: CGFloat, tX: CGFloat, tY: CGFloat) {
4045
(self.m11, self.m12, self.m21, self.m22) = (m11, m12, m21, m22)
4146
(self.tX, self.tY) = (tX, tY)
4247
}
4348

44-
private init(reference: NSAffineTransform) {
45-
self = reference.transformStruct
46-
}
47-
48-
private var reference : NSAffineTransform {
49-
let ref = NSAffineTransform()
50-
ref.transformStruct = self
51-
return ref
52-
}
53-
5449
/**
5550
Creates an affine transformation matrix from translation values.
5651
The matrix takes the following form:
@@ -191,11 +186,12 @@ public struct AffineTransform : ReferenceConvertible, Hashable, CustomStringConv
191186
)
192187
}
193188

194-
// Scaling
189+
/// Mutates an affine transformation matrix to perform the given scaling in both x and y dimensions.
195190
public mutating func scale(_ scale: CGFloat) {
196191
self.scale(x: scale, y: scale)
197192
}
198193

194+
/// Mutates an affine transformation matrix to perform a scaling in each of the x and y dimensions.
199195
public mutating func scale(x: CGFloat, y: CGFloat) {
200196
m11 = CGFloat(m11.native * x.native)
201197
m12 = CGFloat(m12.native * x.native)
@@ -221,6 +217,7 @@ public struct AffineTransform : ReferenceConvertible, Hashable, CustomStringConv
221217
self = inverse
222218
}
223219

220+
/// Returns an inverted version of the matrix if possible, or nil if not.
224221
public func inverted() -> AffineTransform? {
225222
let determinant = (m11 * m22) - (m12 * m21)
226223
if fabs(determinant.native) <= ε.native {
@@ -236,38 +233,43 @@ public struct AffineTransform : ReferenceConvertible, Hashable, CustomStringConv
236233
return inverse
237234
}
238235

239-
// Transforming with transform
236+
/// Mutates an affine transformation by appending the specified matrix.
240237
public mutating func append(_ transform: AffineTransform) {
241238
self = concatenated(transform)
242239
}
243240

241+
/// Mutates an affine transformation by prepending the specified matrix.
244242
public mutating func prepend(_ transform: AffineTransform) {
245243
self = transform.concatenated(self)
246244
}
247245

248-
// Transforming points and sizes
246+
/// Applies the transform to the specified point and returns the result.
249247
public func transform(_ point: NSPoint) -> NSPoint {
250248
var newPoint = NSPoint()
251249
newPoint.x = (m11 * point.x) + (m21 * point.y) + tX
252250
newPoint.y = (m12 * point.x) + (m22 * point.y) + tY
253251
return newPoint
254252
}
255253

254+
/// Applies the transform to the specified size and returns the result.
256255
public func transform(_ size: NSSize) -> NSSize {
257256
var newSize = NSSize()
258257
newSize.width = (m11 * size.width) + (m21 * size.height)
259258
newSize.height = (m12 * size.width) + (m22 * size.height)
260259
return newSize
261260
}
262261

262+
/// The computed hash value for the transform.
263263
public var hashValue : Int {
264264
return Int((m11 + m12 + m21 + m22 + tX + tY).native)
265265
}
266266

267+
/// A textual description of the transform.
267268
public var description: String {
268269
return "{m11:\(m11), m12:\(m12), m21:\(m21), m22:\(m22), tX:\(tX), tY:\(tY)}"
269270
}
270271

272+
/// A textual description of the transform suitable for debugging.
271273
public var debugDescription: String {
272274
return description
273275
}
@@ -279,8 +281,61 @@ public struct AffineTransform : ReferenceConvertible, Hashable, CustomStringConv
279281
}
280282
}
281283

284+
285+
/// A structure that defines the three-by-three matrix that performs an affine transform between two coordinate systems.
286+
public struct NSAffineTransformStruct {
287+
public var m11: CGFloat
288+
public var m12: CGFloat
289+
public var m21: CGFloat
290+
public var m22: CGFloat
291+
public var tX: CGFloat
292+
public var tY: CGFloat
293+
294+
/// Initializes a zero-filled transformation matrix.
295+
public init() {
296+
m11 = 0.0
297+
m12 = 0.0
298+
m21 = 0.0
299+
m22 = 0.0
300+
tX = 0.0
301+
tY = 0.0
302+
}
303+
304+
/// Initializes a transformation matrix with the given values.
305+
public init(m11: CGFloat, m12: CGFloat, m21: CGFloat, m22: CGFloat, tX: CGFloat, tY: CGFloat) {
306+
self.m11 = m11
307+
self.m12 = m12
308+
self.m21 = m21
309+
self.m22 = m22
310+
self.tX = tX
311+
self.tY = tY
312+
}
313+
}
314+
282315
open class NSAffineTransform : NSObject, NSCopying, NSSecureCoding {
283-
316+
317+
private var affineTransform: AffineTransform
318+
319+
/// The matrix coefficients stored as the transformation matrix.
320+
public var transformStruct: NSAffineTransformStruct {
321+
get {
322+
return NSAffineTransformStruct(m11: affineTransform.m11,
323+
m12: affineTransform.m12,
324+
m21: affineTransform.m21,
325+
m22: affineTransform.m22,
326+
tX: affineTransform.tX,
327+
tY: affineTransform.tY)
328+
}
329+
set {
330+
affineTransform.m11 = newValue.m11
331+
affineTransform.m12 = newValue.m12
332+
affineTransform.m21 = newValue.m21
333+
affineTransform.m22 = newValue.m22
334+
affineTransform.tX = newValue.tX
335+
affineTransform.tY = newValue.tY
336+
}
337+
}
338+
284339
open func encode(with aCoder: NSCoder) {
285340
guard aCoder.allowsKeyedCoding else {
286341
preconditionFailure("Unkeyed coding is unsupported.")
@@ -301,7 +356,7 @@ open class NSAffineTransform : NSObject, NSCopying, NSSecureCoding {
301356
}
302357

303358
open func copy(with zone: NSZone? = nil) -> Any {
304-
return NSAffineTransform(transform: self)
359+
return NSAffineTransform(transform: affineTransform)
305360
}
306361

307362
// Necessary because `NSObject.copy()` returns `self`.
@@ -328,94 +383,97 @@ open class NSAffineTransform : NSObject, NSCopying, NSSecureCoding {
328383
let tX = floatPointer[4]
329384
let tY = floatPointer[5]
330385

331-
self.transformStruct = AffineTransform(m11: CGFloat(m11), m12: CGFloat(m12),
332-
m21: CGFloat(m21), m22: CGFloat(m22),
333-
tX: CGFloat(tX), tY: CGFloat(tY))
386+
affineTransform = AffineTransform(m11: CGFloat(m11), m12: CGFloat(m12),
387+
m21: CGFloat(m21), m22: CGFloat(m22),
388+
tX: CGFloat(tX), tY: CGFloat(tY))
334389
}
335390

336391
open override func isEqual(_ object: Any?) -> Bool {
337392
guard let other = object as? NSAffineTransform else { return false }
338-
return other === self
339-
|| (other.transformStruct == self.transformStruct)
393+
return other === self || (other.affineTransform == self.affineTransform)
340394
}
341395

342396
open override var hashValue: Int {
343-
return transformStruct.hashValue
397+
return affineTransform.hashValue
344398
}
345399

346400
public static var supportsSecureCoding: Bool {
347401
return true
348402
}
349403

350-
// Initialization
351-
public convenience init(transform: NSAffineTransform) {
404+
/// Initializes an affine transform matrix using another transform object.
405+
public convenience init(transform: AffineTransform) {
352406
self.init()
353-
transformStruct = transform.transformStruct
407+
affineTransform = transform
354408
}
355-
409+
410+
/// Initializes an affine transform matrix to the identity matrix.
356411
public override init() {
357-
transformStruct = AffineTransform(
412+
affineTransform = AffineTransform(
358413
m11: CGFloat(1.0), m12: CGFloat(),
359414
m21: CGFloat(), m22: CGFloat(1.0),
360415
tX: CGFloat(), tY: CGFloat()
361416
)
362417
}
363-
364-
// Translating
418+
419+
/// Applies the specified translation factors to the transformation matrix.
365420
open func translateX(by deltaX: CGFloat, yBy deltaY: CGFloat) {
366421
let translation = AffineTransform(translationByX: deltaX, byY: deltaY)
367-
transformStruct = translation.concatenated(transformStruct)
422+
affineTransform = translation.concatenated(affineTransform)
368423
}
369424

370-
// Rotating
425+
/// Applies a rotation factor (measured in degrees) to the transformation matrix.
371426
open func rotate(byDegrees angle: CGFloat) {
372427
let rotation = AffineTransform(rotationByDegrees: angle)
373-
transformStruct = rotation.concatenated(transformStruct)
428+
affineTransform = rotation.concatenated(affineTransform)
374429
}
430+
431+
/// Applies a rotation factor (measured in radians) to the transformation matrix.
375432
open func rotate(byRadians angle: CGFloat) {
376433
let rotation = AffineTransform(rotationByRadians: angle)
377-
transformStruct = rotation.concatenated(transformStruct)
434+
affineTransform = rotation.concatenated(affineTransform)
378435
}
379436

380-
// Scaling
437+
/// Applies the specified scaling factor along both x and y axes to the transformation matrix.
381438
open func scale(by scale: CGFloat) {
382439
scaleX(by: scale, yBy: scale)
383440
}
384441

442+
/// Applies scaling factors to each axis of the transformation matrix.
385443
open func scaleX(by scaleX: CGFloat, yBy scaleY: CGFloat) {
386444
let scale = AffineTransform(scaleByX: scaleX, byY: scaleY)
387-
transformStruct = scale.concatenated(transformStruct)
445+
affineTransform = scale.concatenated(affineTransform)
388446
}
389447

390-
// Inverting
448+
/// Replaces the matrix with its inverse matrix.
391449
open func invert() {
392-
if let inverse = transformStruct.inverted() {
393-
transformStruct = inverse
450+
if let inverse = affineTransform.inverted() {
451+
affineTransform = inverse
394452
}
395453
else {
396454
preconditionFailure("NSAffineTransform: Transform has no inverse")
397455
}
398456
}
399457

400-
// Transforming with transform
401-
open func append(_ transform: NSAffineTransform) {
402-
transformStruct = transformStruct.concatenated(transform.transformStruct)
458+
/// Appends the specified matrix.
459+
open func append(_ transform: AffineTransform) {
460+
affineTransform = affineTransform.concatenated(transform)
403461
}
404-
open func prepend(_ transform: NSAffineTransform) {
405-
transformStruct = transform.transformStruct.concatenated(transformStruct)
462+
463+
/// Prepends the specified matrix.
464+
open func prepend(_ transform: AffineTransform) {
465+
affineTransform = transform.concatenated(affineTransform)
406466
}
407467

408-
// Transforming points and sizes
468+
/// Applies the transform to the specified point and returns the result.
409469
open func transform(_ aPoint: NSPoint) -> NSPoint {
410-
return transformStruct.transform(aPoint)
470+
return affineTransform.transform(aPoint)
411471
}
412472

473+
/// Applies the transform to the specified size and returns the result.
413474
open func transform(_ aSize: NSSize) -> NSSize {
414-
return transformStruct.transform(aSize)
475+
return affineTransform.transform(aSize)
415476
}
416-
417-
// Transform Struct
418-
open var transformStruct: AffineTransform
419477
}
420478

421479
extension AffineTransform : _ObjectTypeBridgeable {
@@ -429,9 +487,7 @@ extension AffineTransform : _ObjectTypeBridgeable {
429487

430488
@_semantics("convertToObjectiveC")
431489
public func _bridgeToObjectiveC() -> NSAffineTransform {
432-
let t = NSAffineTransform()
433-
t.transformStruct = self
434-
return t
490+
return NSAffineTransform(transform: self)
435491
}
436492

437493
public static func _forceBridgeFromObjectiveC(_ x: NSAffineTransform, result: inout AffineTransform?) {
@@ -441,7 +497,8 @@ extension AffineTransform : _ObjectTypeBridgeable {
441497
}
442498

443499
public static func _conditionallyBridgeFromObjectiveC(_ x: NSAffineTransform, result: inout AffineTransform?) -> Bool {
444-
result = x.transformStruct
500+
let ts = x.transformStruct
501+
result = AffineTransform(m11: ts.m11, m12: ts.m12, m21: ts.m21, m22: ts.m22, tX: ts.tX, tY: ts.tY)
445502
return true // Can't fail
446503
}
447504

0 commit comments

Comments
 (0)