| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| |
| #if os(OSX) || os(iOS) |
| import Darwin |
| #elseif os(Linux) || CYGWIN |
| import Glibc |
| #endif |
| |
| private let ε: CGFloat = CGFloat(2.22045e-16) |
| |
| |
| /** |
| AffineTransform represents an affine transformation matrix of the following form: |
| |
| [ m11 m12 0 ] |
| [ m21 m22 0 ] |
| [ tX tY 1 ] |
| */ |
| public struct AffineTransform : ReferenceConvertible, Hashable, CustomStringConvertible { |
| public typealias ReferenceType = NSAffineTransform |
| |
| public var m11: CGFloat |
| public var m12: CGFloat |
| public var m21: CGFloat |
| public var m22: CGFloat |
| public var tX: CGFloat |
| public var tY: CGFloat |
| |
| /// Creates an affine transformation matrix with identity values. |
| public init() { |
| self.init(m11: 1.0, m12: 0.0, |
| m21: 0.0, m22: 1.0, |
| tX: 0.0, tY: 0.0) |
| } |
| |
| /// Creates an affine transformation. |
| public init(m11: CGFloat, m12: CGFloat, m21: CGFloat, m22: CGFloat, tX: CGFloat, tY: CGFloat) { |
| (self.m11, self.m12, self.m21, self.m22) = (m11, m12, m21, m22) |
| (self.tX, self.tY) = (tX, tY) |
| } |
| |
| /** |
| Creates an affine transformation matrix from translation values. |
| The matrix takes the following form: |
| |
| [ 1 0 0 ] |
| [ 0 1 0 ] |
| [ x y 1 ] |
| */ |
| public init(translationByX x: CGFloat, byY y: CGFloat) { |
| self.init(m11: CGFloat(1.0), m12: CGFloat(0.0), |
| m21: CGFloat(0.0), m22: CGFloat(1.0), |
| tX: x, tY: y) |
| } |
| |
| /** |
| Creates an affine transformation matrix from scaling values. |
| The matrix takes the following form: |
| |
| [ x 0 0 ] |
| [ 0 y 0 ] |
| [ 0 0 1 ] |
| */ |
| public init(scaleByX x: CGFloat, byY y: CGFloat) { |
| self.init(m11: x, m12: CGFloat(0.0), |
| m21: CGFloat(0.0), m22: y, |
| tX: CGFloat(0.0), tY: CGFloat(0.0)) |
| } |
| |
| /** |
| Creates an affine transformation matrix from scaling a single value. |
| The matrix takes the following form: |
| |
| [ f 0 0 ] |
| [ 0 f 0 ] |
| [ 0 0 1 ] |
| */ |
| public init(scale factor: CGFloat) { |
| self.init(scaleByX: factor, byY: factor) |
| } |
| |
| /** |
| Creates an affine transformation matrix from rotation value (angle in radians). |
| The matrix takes the following form: |
| |
| [ cos α sin α 0 ] |
| [ -sin α cos α 0 ] |
| [ 0 0 1 ] |
| */ |
| public init(rotationByRadians angle: CGFloat) { |
| let sine = sin(angle) |
| let cosine = cos(angle) |
| |
| self.init(m11: cosine, m12: sine, m21: -sine, m22: cosine, tX: CGFloat(0.0), tY: CGFloat(0.0)) |
| } |
| |
| /** |
| Creates an affine transformation matrix from a rotation value (angle in degrees). |
| The matrix takes the following form: |
| |
| [ cos α sin α 0 ] |
| [ -sin α cos α 0 ] |
| [ 0 0 1 ] |
| */ |
| public init(rotationByDegrees angle: CGFloat) { |
| let α = angle * .pi / 180.0 |
| self.init(rotationByRadians: α) |
| } |
| |
| /** |
| An identity affine transformation matrix |
| |
| [ 1 0 0 ] |
| [ 0 1 0 ] |
| [ 0 0 1 ] |
| */ |
| public static let identity = AffineTransform(m11: CGFloat(1.0), m12: CGFloat(0.0), m21: CGFloat(0.0), m22: CGFloat(1.0), tX: CGFloat(0.0), tY: CGFloat(0.0)) |
| |
| // Translating |
| public mutating func translate(x: CGFloat, y: CGFloat) { |
| tX += m11 * x + m21 * y |
| tY += m12 * x + m22 * y |
| } |
| |
| /** |
| Mutates an affine transformation matrix from a rotation value (angle α in degrees). |
| The matrix takes the following form: |
| |
| [ cos α sin α 0 ] |
| [ -sin α cos α 0 ] |
| [ 0 0 1 ] |
| */ |
| public mutating func rotate(byDegrees angle: CGFloat) { |
| let α = angle * .pi / 180.0 |
| return rotate(byRadians: α) |
| } |
| |
| /** |
| Mutates an affine transformation matrix from a rotation value (angle α in radians). |
| The matrix takes the following form: |
| |
| [ cos α sin α 0 ] |
| [ -sin α cos α 0 ] |
| [ 0 0 1 ] |
| */ |
| public mutating func rotate(byRadians angle: CGFloat) { |
| let sine = sin(angle) |
| let cosine = cos(angle) |
| |
| m11 = cosine |
| m12 = sine |
| m21 = -sine |
| m22 = cosine |
| } |
| |
| /** |
| Creates an affine transformation matrix by combining the receiver with `transformStruct`. |
| That is, it computes `T * M` and returns the result, where `T` is the receiver's and `M` is |
| the `transformStruct`'s affine transformation matrix. |
| The resulting matrix takes the following form: |
| |
| [ m11_T m12_T 0 ] [ m11_M m12_M 0 ] |
| T * M = [ m21_T m22_T 0 ] [ m21_M m22_M 0 ] |
| [ tX_T tY_T 1 ] [ tX_M tY_M 1 ] |
| |
| [ (m11_T*m11_M + m12_T*m21_M) (m11_T*m12_M + m12_T*m22_M) 0 ] |
| = [ (m21_T*m11_M + m22_T*m21_M) (m21_T*m12_M + m22_T*m22_M) 0 ] |
| [ (tX_T*m11_M + tY_T*m21_M + tX_M) (tX_T*m12_M + tY_T*m22_M + tY_M) 1 ] |
| */ |
| internal func concatenated(_ other: AffineTransform) -> AffineTransform { |
| let (t, m) = (self, other) |
| |
| // this could be optimized with a vector version |
| return AffineTransform( |
| m11: (t.m11 * m.m11) + (t.m12 * m.m21), m12: (t.m11 * m.m12) + (t.m12 * m.m22), |
| m21: (t.m21 * m.m11) + (t.m22 * m.m21), m22: (t.m21 * m.m12) + (t.m22 * m.m22), |
| tX: (t.tX * m.m11) + (t.tY * m.m21) + m.tX, |
| tY: (t.tX * m.m12) + (t.tY * m.m22) + m.tY |
| ) |
| } |
| |
| /// Mutates an affine transformation matrix to perform the given scaling in both x and y dimensions. |
| public mutating func scale(_ scale: CGFloat) { |
| self.scale(x: scale, y: scale) |
| } |
| |
| /// Mutates an affine transformation matrix to perform a scaling in each of the x and y dimensions. |
| public mutating func scale(x: CGFloat, y: CGFloat) { |
| m11 = CGFloat(m11.native * x.native) |
| m12 = CGFloat(m12.native * x.native) |
| m21 = CGFloat(m21.native * y.native) |
| m22 = CGFloat(m22.native * y.native) |
| } |
| |
| /** |
| Inverts the transformation matrix if possible. Matrices with a determinant that is less than |
| the smallest valid representation of a double value greater than zero are considered to be |
| invalid for representing as an inverse. If the input AffineTransform can potentially fall into |
| this case then the inverted() method is suggested to be used instead since that will return |
| an optional value that will be nil in the case that the matrix cannot be inverted. |
| |
| D = (m11 * m22) - (m12 * m21) |
| |
| D < ε the inverse is undefined and will be nil |
| */ |
| public mutating func invert() { |
| guard let inverse = inverted() else { |
| fatalError("Transform has no inverse") |
| } |
| self = inverse |
| } |
| |
| /// Returns an inverted version of the matrix if possible, or nil if not. |
| public func inverted() -> AffineTransform? { |
| let determinant = (m11 * m22) - (m12 * m21) |
| if fabs(determinant.native) <= ε.native { |
| return nil |
| } |
| var inverse = AffineTransform() |
| inverse.m11 = m22 / determinant |
| inverse.m12 = -m12 / determinant |
| inverse.m21 = -m21 / determinant |
| inverse.m22 = m11 / determinant |
| inverse.tX = (m21 * tY - m22 * tX) / determinant |
| inverse.tY = (m12 * tX - m11 * tY) / determinant |
| return inverse |
| } |
| |
| /// Mutates an affine transformation by appending the specified matrix. |
| public mutating func append(_ transform: AffineTransform) { |
| self = concatenated(transform) |
| } |
| |
| /// Mutates an affine transformation by prepending the specified matrix. |
| public mutating func prepend(_ transform: AffineTransform) { |
| self = transform.concatenated(self) |
| } |
| |
| /// Applies the transform to the specified point and returns the result. |
| public func transform(_ point: NSPoint) -> NSPoint { |
| var newPoint = NSPoint() |
| newPoint.x = (m11 * point.x) + (m21 * point.y) + tX |
| newPoint.y = (m12 * point.x) + (m22 * point.y) + tY |
| return newPoint |
| } |
| |
| /// Applies the transform to the specified size and returns the result. |
| public func transform(_ size: NSSize) -> NSSize { |
| var newSize = NSSize() |
| newSize.width = (m11 * size.width) + (m21 * size.height) |
| newSize.height = (m12 * size.width) + (m22 * size.height) |
| return newSize |
| } |
| |
| /// The computed hash value for the transform. |
| public var hashValue : Int { |
| return Int((m11 + m12 + m21 + m22 + tX + tY).native) |
| } |
| |
| /// A textual description of the transform. |
| public var description: String { |
| return "{m11:\(m11), m12:\(m12), m21:\(m21), m22:\(m22), tX:\(tX), tY:\(tY)}" |
| } |
| |
| /// A textual description of the transform suitable for debugging. |
| public var debugDescription: String { |
| return description |
| } |
| |
| public static func ==(lhs: AffineTransform, rhs: AffineTransform) -> Bool { |
| return lhs.m11 == rhs.m11 && lhs.m12 == rhs.m12 && |
| lhs.m21 == rhs.m21 && lhs.m22 == rhs.m22 && |
| lhs.tX == rhs.tX && lhs.tY == rhs.tY |
| } |
| } |
| |
| |
| /// A structure that defines the three-by-three matrix that performs an affine transform between two coordinate systems. |
| public struct NSAffineTransformStruct { |
| public var m11: CGFloat |
| public var m12: CGFloat |
| public var m21: CGFloat |
| public var m22: CGFloat |
| public var tX: CGFloat |
| public var tY: CGFloat |
| |
| /// Initializes a zero-filled transformation matrix. |
| public init() { |
| m11 = 0.0 |
| m12 = 0.0 |
| m21 = 0.0 |
| m22 = 0.0 |
| tX = 0.0 |
| tY = 0.0 |
| } |
| |
| /// Initializes a transformation matrix with the given values. |
| public init(m11: CGFloat, m12: CGFloat, m21: CGFloat, m22: CGFloat, tX: CGFloat, tY: CGFloat) { |
| self.m11 = m11 |
| self.m12 = m12 |
| self.m21 = m21 |
| self.m22 = m22 |
| self.tX = tX |
| self.tY = tY |
| } |
| } |
| |
| open class NSAffineTransform : NSObject, NSCopying, NSSecureCoding { |
| |
| private var affineTransform: AffineTransform |
| |
| /// The matrix coefficients stored as the transformation matrix. |
| public var transformStruct: NSAffineTransformStruct { |
| get { |
| return NSAffineTransformStruct(m11: affineTransform.m11, |
| m12: affineTransform.m12, |
| m21: affineTransform.m21, |
| m22: affineTransform.m22, |
| tX: affineTransform.tX, |
| tY: affineTransform.tY) |
| } |
| set { |
| affineTransform.m11 = newValue.m11 |
| affineTransform.m12 = newValue.m12 |
| affineTransform.m21 = newValue.m21 |
| affineTransform.m22 = newValue.m22 |
| affineTransform.tX = newValue.tX |
| affineTransform.tY = newValue.tY |
| } |
| } |
| |
| open func encode(with aCoder: NSCoder) { |
| guard aCoder.allowsKeyedCoding else { |
| preconditionFailure("Unkeyed coding is unsupported.") |
| } |
| |
| let array = [ |
| Float(transformStruct.m11), |
| Float(transformStruct.m12), |
| Float(transformStruct.m21), |
| Float(transformStruct.m22), |
| Float(transformStruct.tX), |
| Float(transformStruct.tY), |
| ] |
| |
| array.withUnsafeBytes { pointer in |
| aCoder.encodeValue(ofObjCType: "[6f]", at: UnsafeRawPointer(pointer.baseAddress!)) |
| } |
| } |
| |
| open func copy(with zone: NSZone? = nil) -> Any { |
| return NSAffineTransform(transform: affineTransform) |
| } |
| |
| // Necessary because `NSObject.copy()` returns `self`. |
| open override func copy() -> Any { |
| return copy(with: nil) |
| } |
| |
| public required init?(coder aDecoder: NSCoder) { |
| guard aDecoder.allowsKeyedCoding else { |
| preconditionFailure("Unkeyed coding is unsupported.") |
| } |
| |
| let pointer = UnsafeMutableRawPointer.allocate(bytes: MemoryLayout<Float>.stride * 6, alignedTo: 1) |
| defer { |
| pointer.deallocate(bytes: MemoryLayout<Float>.stride * 6, alignedTo: 1) |
| } |
| aDecoder.decodeValue(ofObjCType: "[6f]", at: pointer) |
| |
| let floatPointer = pointer.bindMemory(to: Float.self, capacity: 6) |
| let m11 = floatPointer[0] |
| let m12 = floatPointer[1] |
| let m21 = floatPointer[2] |
| let m22 = floatPointer[3] |
| let tX = floatPointer[4] |
| let tY = floatPointer[5] |
| |
| affineTransform = AffineTransform(m11: CGFloat(m11), m12: CGFloat(m12), |
| m21: CGFloat(m21), m22: CGFloat(m22), |
| tX: CGFloat(tX), tY: CGFloat(tY)) |
| } |
| |
| open override func isEqual(_ object: Any?) -> Bool { |
| guard let other = object as? NSAffineTransform else { return false } |
| return other === self || (other.affineTransform == self.affineTransform) |
| } |
| |
| open override var hashValue: Int { |
| return affineTransform.hashValue |
| } |
| |
| public static var supportsSecureCoding: Bool { |
| return true |
| } |
| |
| /// Initializes an affine transform matrix using another transform object. |
| public convenience init(transform: AffineTransform) { |
| self.init() |
| affineTransform = transform |
| } |
| |
| /// Initializes an affine transform matrix to the identity matrix. |
| public override init() { |
| affineTransform = AffineTransform( |
| m11: CGFloat(1.0), m12: CGFloat(), |
| m21: CGFloat(), m22: CGFloat(1.0), |
| tX: CGFloat(), tY: CGFloat() |
| ) |
| } |
| |
| /// Applies the specified translation factors to the transformation matrix. |
| open func translateX(by deltaX: CGFloat, yBy deltaY: CGFloat) { |
| let translation = AffineTransform(translationByX: deltaX, byY: deltaY) |
| affineTransform = translation.concatenated(affineTransform) |
| } |
| |
| /// Applies a rotation factor (measured in degrees) to the transformation matrix. |
| open func rotate(byDegrees angle: CGFloat) { |
| let rotation = AffineTransform(rotationByDegrees: angle) |
| affineTransform = rotation.concatenated(affineTransform) |
| } |
| |
| /// Applies a rotation factor (measured in radians) to the transformation matrix. |
| open func rotate(byRadians angle: CGFloat) { |
| let rotation = AffineTransform(rotationByRadians: angle) |
| affineTransform = rotation.concatenated(affineTransform) |
| } |
| |
| /// Applies the specified scaling factor along both x and y axes to the transformation matrix. |
| open func scale(by scale: CGFloat) { |
| scaleX(by: scale, yBy: scale) |
| } |
| |
| /// Applies scaling factors to each axis of the transformation matrix. |
| open func scaleX(by scaleX: CGFloat, yBy scaleY: CGFloat) { |
| let scale = AffineTransform(scaleByX: scaleX, byY: scaleY) |
| affineTransform = scale.concatenated(affineTransform) |
| } |
| |
| /// Replaces the matrix with its inverse matrix. |
| open func invert() { |
| if let inverse = affineTransform.inverted() { |
| affineTransform = inverse |
| } |
| else { |
| preconditionFailure("NSAffineTransform: Transform has no inverse") |
| } |
| } |
| |
| /// Appends the specified matrix. |
| open func append(_ transform: AffineTransform) { |
| affineTransform = affineTransform.concatenated(transform) |
| } |
| |
| /// Prepends the specified matrix. |
| open func prepend(_ transform: AffineTransform) { |
| affineTransform = transform.concatenated(affineTransform) |
| } |
| |
| /// Applies the transform to the specified point and returns the result. |
| open func transform(_ aPoint: NSPoint) -> NSPoint { |
| return affineTransform.transform(aPoint) |
| } |
| |
| /// Applies the transform to the specified size and returns the result. |
| open func transform(_ aSize: NSSize) -> NSSize { |
| return affineTransform.transform(aSize) |
| } |
| } |
| |
| extension AffineTransform : _ObjectTypeBridgeable { |
| public static func _isBridgedToObjectiveC() -> Bool { |
| return true |
| } |
| |
| public static func _getObjectiveCType() -> Any.Type { |
| return NSAffineTransform.self |
| } |
| |
| @_semantics("convertToObjectiveC") |
| public func _bridgeToObjectiveC() -> NSAffineTransform { |
| return NSAffineTransform(transform: self) |
| } |
| |
| public static func _forceBridgeFromObjectiveC(_ x: NSAffineTransform, result: inout AffineTransform?) { |
| if !_conditionallyBridgeFromObjectiveC(x, result: &result) { |
| fatalError("Unable to bridge type") |
| } |
| } |
| |
| public static func _conditionallyBridgeFromObjectiveC(_ x: NSAffineTransform, result: inout AffineTransform?) -> Bool { |
| let ts = x.transformStruct |
| result = AffineTransform(m11: ts.m11, m12: ts.m12, m21: ts.m21, m22: ts.m22, tX: ts.tX, tY: ts.tY) |
| return true // Can't fail |
| } |
| |
| public static func _unconditionallyBridgeFromObjectiveC(_ x: NSAffineTransform?) -> AffineTransform { |
| var result: AffineTransform? |
| _forceBridgeFromObjectiveC(x!, result: &result) |
| return result! |
| } |
| } |
| |
| extension NSAffineTransform : _StructTypeBridgeable { |
| public typealias _StructType = AffineTransform |
| |
| public func _bridgeToSwift() -> AffineTransform { |
| return AffineTransform._unconditionallyBridgeFromObjectiveC(self) |
| } |
| } |
| |
| extension AffineTransform : Codable { |
| public init(from decoder: Decoder) throws { |
| var container = try decoder.unkeyedContainer() |
| m11 = try container.decode(CGFloat.self) |
| m12 = try container.decode(CGFloat.self) |
| m21 = try container.decode(CGFloat.self) |
| m22 = try container.decode(CGFloat.self) |
| tX = try container.decode(CGFloat.self) |
| tY = try container.decode(CGFloat.self) |
| } |
| |
| public func encode(to encoder: Encoder) throws { |
| var container = encoder.unkeyedContainer() |
| try container.encode(self.m11) |
| try container.encode(self.m12) |
| try container.encode(self.m21) |
| try container.encode(self.m22) |
| try container.encode(self.tX) |
| try container.encode(self.tY) |
| } |
| } |