├── .github └── workflows │ └── tests.yml ├── .gitignore ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── CGPointVector │ ├── CGAffineTransform.swift │ ├── CGPoint.swift │ ├── CGRect.swift │ ├── CGSize.swift │ └── CGVector.swift └── Tests ├── CGPointVectorTests ├── CGAffineTransformTests.swift ├── CGPointTests.swift ├── CGPointVectorTests.swift ├── CGRectTests.swift ├── CGSizeTests.swift └── CGVectorTests.swift └── LinuxMain.swift /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: "CGPointVector CI" 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: macos-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Build 17 | run: swift build -c release -v 18 | - name: Test 19 | run: swift test -c release -v 20 | 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 koher 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "CGPointVector", 8 | platforms: [ 9 | .iOS(.v8), 10 | .macOS(.v10_10), 11 | .tvOS(.v9), 12 | .watchOS(.v2), 13 | ], 14 | products: [ 15 | // Products define the executables and libraries produced by a package, and make them visible to other packages. 16 | .library( 17 | name: "CGPointVector", 18 | targets: ["CGPointVector"]), 19 | ], 20 | dependencies: [ 21 | // Dependencies declare other packages that this package depends on. 22 | // .package(url: /* package url */, from: "1.0.0"), 23 | ], 24 | targets: [ 25 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 26 | // Targets can depend on other targets in this package, and on products in packages which this package depends on. 27 | .target( 28 | name: "CGPointVector", 29 | dependencies: [], 30 | path: "Sources"), 31 | .testTarget( 32 | name: "CGPointVectorTests", 33 | dependencies: ["CGPointVector"]), 34 | ], 35 | swiftLanguageVersions: [.v5] 36 | ) 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CGPointVector 2 | 3 | [![CGPointVector CI](https://github.com/koher/CGPointVector/actions/workflows/tests.yml/badge.svg)](https://github.com/koher/CGPointVector/actions) 4 | 5 | _CGPointVector_ provides the extension for arithmetic operations with _CGPoint_ in __Swift__, which are convenient when _CGPoint_ values are used as vectors. 6 | 7 | ```swift 8 | let a = CGPoint(x: 1, y: 2), b = CGPoint(x: -3, y: 5) 9 | 10 | let sum = a + b // (-2.0, 7.0) 11 | let distance = (b - a).length // 5.0 12 | let direction = (b - a).unit // (-0.8, 0.6) 13 | let rotated = a * CGAffineTransform(rotationAngle: CGFloat.pi / 2) // (-2.0, 1.0) 14 | ``` 15 | 16 | ## Usage 17 | 18 | ```swift 19 | import CGPointVector 20 | 21 | let a = CGPoint(x: 3.0, y: -4.0) 22 | let b = CGPoint(x: 2.0, y: -5.0) 23 | 24 | let sum = a + b // (5.0, -9.0) 25 | let length = a.length // 5.0 26 | let distance = a.distance(from: b) // 1.4142135623731 27 | let unitVector = a.unit // (0.6, -0.8) 28 | let dotProduct = a.dot(b) // 26.0 29 | let angle = a.angle(from: b) // 0.26299473168091936 30 | ``` 31 | 32 | ## License 33 | 34 | [The MIT License](LICENSE) 35 | -------------------------------------------------------------------------------- /Sources/CGPointVector/CGAffineTransform.swift: -------------------------------------------------------------------------------- 1 | import CoreGraphics 2 | 3 | extension CGAffineTransform { 4 | public func isNearlyEqual(to transform: CGAffineTransform, epsilon: CGFloat) -> Bool { 5 | return abs(a - transform.a) < epsilon && abs(b - transform.b) < epsilon && abs(c - transform.c) < epsilon && abs(d - transform.d) < epsilon && abs(tx - transform.tx) < epsilon && abs(ty - transform.ty) < epsilon 6 | } 7 | } 8 | 9 | extension CGAffineTransform: CustomStringConvertible { 10 | public var description: String { 11 | return "(\(a), \(b), \(c), \(d), \(tx), \(ty))" 12 | } 13 | } 14 | 15 | extension CGAffineTransform { 16 | public static func * (lhs: CGAffineTransform, rhs: CGAffineTransform) -> CGAffineTransform { 17 | return lhs.concatenating(rhs) 18 | } 19 | 20 | public static func *= (lhs: inout CGAffineTransform, rhs: CGAffineTransform) { 21 | lhs = lhs * rhs 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/CGPointVector/CGPoint.swift: -------------------------------------------------------------------------------- 1 | import CoreGraphics 2 | 3 | extension CGPoint { 4 | public func isNearlyEqual(to point: CGPoint, epsilon: CGFloat) -> Bool { 5 | let difference = self - point 6 | return abs(difference.x) < epsilon && abs(difference.y) < epsilon 7 | } 8 | 9 | public var length: CGFloat { 10 | return hypot(x, y) 11 | } 12 | 13 | public var squareLength: CGFloat { 14 | return x * x + y * y 15 | } 16 | 17 | public var unit: CGPoint { 18 | return self * (1.0 / length) 19 | } 20 | 21 | public var phase: CGFloat { 22 | return atan2(y, x) 23 | } 24 | 25 | public func distance(from point: CGPoint) -> CGFloat { 26 | return (self - point).length 27 | } 28 | 29 | public func squareDistance(from point: CGPoint) -> CGFloat { 30 | return (self - point).squareLength 31 | } 32 | 33 | public func angle(from point: CGPoint) -> CGFloat { 34 | return acos(cos(from: point)) 35 | } 36 | 37 | public func cos(from point: CGPoint) -> CGFloat { 38 | let squareLength1 = self.squareLength 39 | guard squareLength1 > 0.0 else { return 1.0 } 40 | let squareLength2 = point.squareLength 41 | guard squareLength2 > 0.0 else { return 1.0 } 42 | return Swift.min(Swift.max(self.dot(point) / sqrt(squareLength1 * squareLength2), -1.0), 1.0) 43 | } 44 | 45 | public func dot(_ other: CGPoint) -> CGFloat { 46 | return self.x * other.x + self.y * other.y 47 | } 48 | } 49 | 50 | extension CGPoint: CustomStringConvertible { 51 | public var description: String { 52 | return "(\(x), \(y))" 53 | } 54 | } 55 | 56 | extension CGPoint { 57 | public static prefix func + (value: CGPoint) -> CGPoint { 58 | return value 59 | } 60 | 61 | public static prefix func - (value: CGPoint) -> CGPoint { 62 | return CGPoint(x: -value.x, y: -value.y) 63 | } 64 | 65 | public static func + (lhs: CGPoint, rhs: CGPoint) -> CGPoint { 66 | return CGPoint(x: lhs.x + rhs.x, y: lhs.y + rhs.y) 67 | } 68 | 69 | public static func - (lhs: CGPoint, rhs: CGPoint) -> CGPoint { 70 | return CGPoint(x: lhs.x - rhs.x, y: lhs.y - rhs.y) 71 | } 72 | 73 | public static func * (lhs: CGPoint, rhs: CGPoint) -> CGPoint { 74 | return CGPoint(x: lhs.x * rhs.x, y: lhs.y * rhs.y) 75 | } 76 | 77 | public static func * (lhs: CGPoint, rhs: CGFloat) -> CGPoint { 78 | return CGPoint(x: lhs.x * rhs, y: lhs.y * rhs) 79 | } 80 | 81 | public static func * (lhs: CGFloat, rhs: CGPoint) -> CGPoint { 82 | return CGPoint(x: rhs.x * lhs, y: rhs.y * lhs) 83 | } 84 | 85 | public static func / (lhs: CGPoint, rhs: CGPoint) -> CGPoint { 86 | return CGPoint(x: lhs.x / rhs.x, y: lhs.y / rhs.y) 87 | } 88 | 89 | public static func / (lhs: CGPoint, rhs: CGFloat) -> CGPoint { 90 | return CGPoint(x: lhs.x / rhs, y: lhs.y / rhs) 91 | } 92 | 93 | public static func * (lhs: CGPoint, rhs: CGAffineTransform) -> CGPoint { 94 | return lhs.applying(rhs) 95 | } 96 | 97 | public static func += (lhs: inout CGPoint, rhs: CGPoint) { 98 | lhs = lhs + rhs 99 | } 100 | 101 | public static func -= (lhs: inout CGPoint, rhs: CGPoint) { 102 | lhs = lhs - rhs 103 | } 104 | 105 | public static func *= (lhs: inout CGPoint, rhs: CGPoint) { 106 | lhs = lhs * rhs 107 | } 108 | 109 | public static func *= (lhs: inout CGPoint, rhs: CGFloat) { 110 | lhs = lhs * rhs 111 | } 112 | 113 | public static func /= (lhs: inout CGPoint, rhs: CGPoint) { 114 | lhs = lhs / rhs 115 | } 116 | 117 | public static func /= (lhs: inout CGPoint, rhs: CGFloat) { 118 | lhs = lhs / rhs 119 | } 120 | 121 | public static func *= (lhs: inout CGPoint, rhs: CGAffineTransform) { 122 | lhs = lhs * rhs 123 | } 124 | } 125 | 126 | extension CGPoint { 127 | public static func + (lhs: CGPoint, rhs: CGSize) -> CGPoint { 128 | return CGPoint(x: lhs.x + rhs.width, y: lhs.y + rhs.height) 129 | } 130 | 131 | public static func - (lhs: CGPoint, rhs: CGSize) -> CGPoint { 132 | return CGPoint(x: lhs.x - rhs.width, y: lhs.y - rhs.height) 133 | } 134 | 135 | public static func * (lhs: CGPoint, rhs: CGSize) -> CGPoint { 136 | return CGPoint(x: lhs.x * rhs.width, y: lhs.y * rhs.height) 137 | } 138 | 139 | public static func / (lhs: CGPoint, rhs: CGSize) -> CGPoint { 140 | return CGPoint(x: lhs.x / rhs.width, y: lhs.y / rhs.height) 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /Sources/CGPointVector/CGRect.swift: -------------------------------------------------------------------------------- 1 | import CoreGraphics 2 | 3 | extension CGRect { 4 | public func isNearlyEqual(to rect: CGRect, epsilon: CGFloat) -> Bool { 5 | let difference1 = self.origin - rect.origin 6 | let difference2 = (self.origin + self.size) - (rect.origin + rect.size) 7 | return abs(difference1.x) < epsilon && abs(difference1.y) < epsilon 8 | && abs(difference2.x) < epsilon && abs(difference2.y) < epsilon 9 | } 10 | 11 | public var center: CGPoint { 12 | return CGPoint(x: midX, y: midY) 13 | } 14 | } 15 | 16 | extension CGRect: CustomStringConvertible { 17 | public var description: String { 18 | return "(\(origin.description), \(size.description))" 19 | } 20 | } 21 | 22 | extension CGRect { 23 | public static func * (lhs: CGRect, rhs: CGAffineTransform) -> CGRect { 24 | return lhs.applying(rhs) 25 | } 26 | 27 | public static func *= (lhs: inout CGRect, rhs: CGAffineTransform) { 28 | lhs = lhs * rhs 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/CGPointVector/CGSize.swift: -------------------------------------------------------------------------------- 1 | import CoreGraphics 2 | 3 | extension CGSize { 4 | public func isNearlyEqual(to point: CGSize, epsilon: CGFloat) -> Bool { 5 | let difference = self - point 6 | return abs(difference.width) < epsilon && abs(difference.height) < epsilon 7 | } 8 | 9 | public var length: CGFloat { 10 | return hypot(width, height) 11 | } 12 | 13 | public var squareLength: CGFloat { 14 | return width * width + height * height 15 | } 16 | 17 | public var unit: CGSize { 18 | return self * (1.0 / length) 19 | } 20 | 21 | public var phase: CGFloat { 22 | return atan2(height, width) 23 | } 24 | 25 | public func distance(from point: CGSize) -> CGFloat { 26 | return (self - point).length 27 | } 28 | 29 | public func squareDistance(from point: CGSize) -> CGFloat { 30 | return (self - point).squareLength 31 | } 32 | 33 | public func angle(from point: CGSize) -> CGFloat { 34 | return acos(cos(from: point)) 35 | } 36 | 37 | public func cos(from point: CGSize) -> CGFloat { 38 | let squareLength1 = self.squareLength 39 | guard squareLength1 > 0.0 else { return 1.0 } 40 | let squareLength2 = point.squareLength 41 | guard squareLength2 > 0.0 else { return 1.0 } 42 | return Swift.min(Swift.max(self.dot(point) / sqrt(squareLength1 * squareLength2), -1.0), 1.0) 43 | } 44 | 45 | public func dot(_ other: CGSize) -> CGFloat { 46 | return self.width * other.width + self.height * other.height 47 | } 48 | } 49 | 50 | extension CGSize: CustomStringConvertible { 51 | public var description: String { 52 | return "(\(width), \(height))" 53 | } 54 | } 55 | 56 | extension CGSize { 57 | public static prefix func + (value: CGSize) -> CGSize { 58 | return value 59 | } 60 | 61 | public static prefix func - (value: CGSize) -> CGSize { 62 | return CGSize(width: -value.width, height: -value.height) 63 | } 64 | 65 | public static func + (lhs: CGSize, rhs: CGSize) -> CGSize { 66 | return CGSize(width: lhs.width + rhs.width, height: lhs.height + rhs.height) 67 | } 68 | 69 | public static func - (lhs: CGSize, rhs: CGSize) -> CGSize { 70 | return CGSize(width: lhs.width - rhs.width, height: lhs.height - rhs.height) 71 | } 72 | 73 | public static func * (lhs: CGSize, rhs: CGSize) -> CGSize { 74 | return CGSize(width: lhs.width * rhs.width, height: lhs.height * rhs.height) 75 | } 76 | 77 | public static func * (lhs: CGSize, rhs: CGFloat) -> CGSize { 78 | return CGSize(width: lhs.width * rhs, height: lhs.height * rhs) 79 | } 80 | 81 | public static func * (lhs: CGFloat, rhs: CGSize) -> CGSize { 82 | return CGSize(width: rhs.width * lhs, height: rhs.height * lhs) 83 | } 84 | 85 | public static func / (lhs: CGSize, rhs: CGSize) -> CGSize { 86 | return CGSize(width: lhs.width / rhs.width, height: lhs.height / rhs.height) 87 | } 88 | 89 | public static func / (lhs: CGSize, rhs: CGFloat) -> CGSize { 90 | return CGSize(width: lhs.width / rhs, height: lhs.height / rhs) 91 | } 92 | 93 | public static func += (lhs: inout CGSize, rhs: CGSize) { 94 | lhs = lhs + rhs 95 | } 96 | 97 | public static func -= (lhs: inout CGSize, rhs: CGSize) { 98 | lhs = lhs - rhs 99 | } 100 | 101 | public static func *= (lhs: inout CGSize, rhs: CGSize) { 102 | lhs = lhs * rhs 103 | } 104 | 105 | public static func *= (lhs: inout CGSize, rhs: CGFloat) { 106 | lhs = lhs * rhs 107 | } 108 | 109 | public static func /= (lhs: inout CGSize, rhs: CGSize) { 110 | lhs = lhs / rhs 111 | } 112 | 113 | public static func /= (lhs: inout CGSize, rhs: CGFloat) { 114 | lhs = lhs / rhs 115 | } 116 | } 117 | 118 | extension CGSize { 119 | public static func + (lhs: CGSize, rhs: CGPoint) -> CGPoint { 120 | return CGPoint(x: lhs.width + rhs.x, y: lhs.height + rhs.y) 121 | } 122 | 123 | public static func - (lhs: CGSize, rhs: CGPoint) -> CGPoint { 124 | return CGPoint(x: lhs.width - rhs.x, y: lhs.height - rhs.y) 125 | } 126 | 127 | public static func * (lhs: CGSize, rhs: CGPoint) -> CGPoint { 128 | return CGPoint(x: lhs.width * rhs.x, y: lhs.height * rhs.y) 129 | } 130 | 131 | public static func / (lhs: CGSize, rhs: CGPoint) -> CGPoint { 132 | return CGPoint(x: lhs.width / rhs.x, y: lhs.height / rhs.y) 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /Sources/CGPointVector/CGVector.swift: -------------------------------------------------------------------------------- 1 | import CoreGraphics 2 | 3 | extension CGVector { 4 | public func isNearlyEqual(to point: CGVector, epsilon: CGFloat) -> Bool { 5 | let difference = self - point 6 | return abs(difference.dx) < epsilon && abs(difference.dy) < epsilon 7 | } 8 | 9 | public var length: CGFloat { 10 | return hypot(dx, dy) 11 | } 12 | 13 | public var squareLength: CGFloat { 14 | return dx * dx + dy * dy 15 | } 16 | 17 | public var unit: CGVector { 18 | return self * (1.0 / length) 19 | } 20 | 21 | public var phase: CGFloat { 22 | return atan2(dy, dx) 23 | } 24 | 25 | public func distance(from point: CGVector) -> CGFloat { 26 | return (self - point).length 27 | } 28 | 29 | public func squareDistance(from point: CGVector) -> CGFloat { 30 | return (self - point).squareLength 31 | } 32 | 33 | public func angle(from point: CGVector) -> CGFloat { 34 | return acos(cos(from: point)) 35 | } 36 | 37 | public func cos(from point: CGVector) -> CGFloat { 38 | let squareLength1 = self.squareLength 39 | guard squareLength1 > 0.0 else { return 1.0 } 40 | let squareLength2 = point.squareLength 41 | guard squareLength2 > 0.0 else { return 1.0 } 42 | return Swift.min(Swift.max(self.dot(point) / sqrt(squareLength1 * squareLength2), -1.0), 1.0) 43 | } 44 | 45 | public func dot(_ other: CGVector) -> CGFloat { 46 | return self.dx * other.dx + self.dy * other.dy 47 | } 48 | } 49 | 50 | extension CGVector: CustomStringConvertible { 51 | public var description: String { 52 | return "(\(dx), \(dy))" 53 | } 54 | } 55 | 56 | extension CGVector { 57 | public static prefix func + (value: CGVector) -> CGVector { 58 | return value 59 | } 60 | 61 | public static prefix func - (value: CGVector) -> CGVector { 62 | return CGVector(dx: -value.dx, dy: -value.dy) 63 | } 64 | 65 | public static func + (lhs: CGVector, rhs: CGVector) -> CGVector { 66 | return CGVector(dx: lhs.dx + rhs.dx, dy: lhs.dy + rhs.dy) 67 | } 68 | 69 | public static func - (lhs: CGVector, rhs: CGVector) -> CGVector { 70 | return CGVector(dx: lhs.dx - rhs.dx, dy: lhs.dy - rhs.dy) 71 | } 72 | 73 | public static func * (lhs: CGVector, rhs: CGVector) -> CGVector { 74 | return CGVector(dx: lhs.dx * rhs.dx, dy: lhs.dy * rhs.dy) 75 | } 76 | 77 | public static func * (lhs: CGVector, rhs: CGFloat) -> CGVector { 78 | return CGVector(dx: lhs.dx * rhs, dy: lhs.dy * rhs) 79 | } 80 | 81 | public static func * (lhs: CGFloat, rhs: CGVector) -> CGVector { 82 | return CGVector(dx: rhs.dx * lhs, dy: rhs.dy * lhs) 83 | } 84 | 85 | public static func / (lhs: CGVector, rhs: CGVector) -> CGVector { 86 | return CGVector(dx: lhs.dx / rhs.dx, dy: lhs.dy / rhs.dy) 87 | } 88 | 89 | public static func / (lhs: CGVector, rhs: CGFloat) -> CGVector { 90 | return CGVector(dx: lhs.dx / rhs, dy: lhs.dy / rhs) 91 | } 92 | 93 | public static func * (lhs: CGVector, rhs: CGAffineTransform) -> CGVector { 94 | let point = CGPoint(x: lhs.dx, y: lhs.dy).applying(rhs) 95 | return CGVector(dx: point.x, dy: point.y) 96 | } 97 | 98 | public static func += (lhs: inout CGVector, rhs: CGVector) { 99 | lhs = lhs + rhs 100 | } 101 | 102 | public static func -= (lhs: inout CGVector, rhs: CGVector) { 103 | lhs = lhs - rhs 104 | } 105 | 106 | public static func *= (lhs: inout CGVector, rhs: CGVector) { 107 | lhs = lhs * rhs 108 | } 109 | 110 | public static func *= (lhs: inout CGVector, rhs: CGFloat) { 111 | lhs = lhs * rhs 112 | } 113 | 114 | public static func /= (lhs: inout CGVector, rhs: CGVector) { 115 | lhs = lhs / rhs 116 | } 117 | 118 | public static func /= (lhs: inout CGVector, rhs: CGFloat) { 119 | lhs = lhs / rhs 120 | } 121 | 122 | public static func *= (lhs: inout CGVector, rhs: CGAffineTransform) { 123 | lhs = lhs * rhs 124 | } 125 | } 126 | 127 | extension CGVector { 128 | public static func + (lhs: CGVector, rhs: CGPoint) -> CGPoint { 129 | return CGPoint(x: lhs.dx + rhs.x, y: lhs.dy + rhs.y) 130 | } 131 | 132 | public static func - (lhs: CGVector, rhs: CGPoint) -> CGPoint { 133 | return CGPoint(x: lhs.dx - rhs.x, y: lhs.dy - rhs.y) 134 | } 135 | 136 | public static func * (lhs: CGVector, rhs: CGPoint) -> CGPoint { 137 | return CGPoint(x: lhs.dx * rhs.x, y: lhs.dy * rhs.y) 138 | } 139 | 140 | public static func / (lhs: CGVector, rhs: CGPoint) -> CGPoint { 141 | return CGPoint(x: lhs.dx / rhs.x, y: lhs.dy / rhs.y) 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /Tests/CGPointVectorTests/CGAffineTransformTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import CGPointVector 3 | 4 | class CGAffineTransormTests: XCTestCase { 5 | let torelance: CGFloat = 1.0e-5; 6 | 7 | func testisNearlyEqual() { 8 | XCTAssertFalse(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 9 | .isNearlyEqual(to: CGAffineTransform(a: 0.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0), epsilon: 1.0)) 10 | XCTAssertTrue(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 11 | .isNearlyEqual(to: CGAffineTransform(a: 0.1, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0), epsilon: 1.0)) 12 | XCTAssertTrue(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 13 | .isNearlyEqual(to: CGAffineTransform(a: 1.9, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0), epsilon: 1.0)) 14 | XCTAssertFalse(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 15 | .isNearlyEqual(to: CGAffineTransform(a: 2.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0), epsilon: 1.0)) 16 | 17 | XCTAssertFalse(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 18 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 1.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0), epsilon: 1.0)) 19 | XCTAssertTrue(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 20 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 1.1, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0), epsilon: 1.0)) 21 | XCTAssertTrue(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 22 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.9, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0), epsilon: 1.0)) 23 | XCTAssertFalse(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 24 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 3.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0), epsilon: 1.0)) 25 | 26 | XCTAssertFalse(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 27 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 2.0, d: 4.0, tx: 5.0, ty: 6.0), epsilon: 1.0)) 28 | XCTAssertTrue(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 29 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 2.1, d: 4.0, tx: 5.0, ty: 6.0), epsilon: 1.0)) 30 | XCTAssertTrue(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 31 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 3.9, d: 4.0, tx: 5.0, ty: 6.0), epsilon: 1.0)) 32 | XCTAssertFalse(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 33 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 4.0, d: 4.0, tx: 5.0, ty: 6.0), epsilon: 1.0)) 34 | 35 | XCTAssertFalse(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 36 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 3.0, tx: 5.0, ty: 6.0), epsilon: 1.0)) 37 | XCTAssertTrue(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 38 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 3.1, tx: 5.0, ty: 6.0), epsilon: 1.0)) 39 | XCTAssertTrue(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 40 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.9, tx: 5.0, ty: 6.0), epsilon: 1.0)) 41 | XCTAssertFalse(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 42 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 5.0, tx: 5.0, ty: 6.0), epsilon: 1.0)) 43 | 44 | XCTAssertFalse(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 45 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 4.0, ty: 6.0), epsilon: 1.0)) 46 | XCTAssertTrue(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 47 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 4.1, ty: 6.0), epsilon: 1.0)) 48 | XCTAssertTrue(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 49 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.9, ty: 6.0), epsilon: 1.0)) 50 | XCTAssertFalse(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 51 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 6.0, ty: 6.0), epsilon: 1.0)) 52 | 53 | XCTAssertFalse(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 54 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 5.0), epsilon: 1.0)) 55 | XCTAssertTrue(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 56 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 5.1), epsilon: 1.0)) 57 | XCTAssertTrue(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 58 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.9), epsilon: 1.0)) 59 | XCTAssertFalse(CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 6.0) 60 | .isNearlyEqual(to: CGAffineTransform(a: 1.0, b: 2.0, c: 3.0, d: 4.0, tx: 5.0, ty: 7.0), epsilon: 1.0)) 61 | } 62 | 63 | func testDescription() { 64 | XCTAssertEqual(CGAffineTransform(a: 1, b: 2, c: 3, d: 4, tx: 5, ty: 6).description, "(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)") 65 | } 66 | 67 | func testMatmul() { 68 | XCTAssertTrue((CGAffineTransform(a: 1, b: 2, c: 3, d: 4, tx: 5, ty: 6) * CGAffineTransform(a: 6, b: 5, c: 4, d: 3, tx: 2, ty: 1)) 69 | .isNearlyEqual(to: CGAffineTransform(a: 14, b: 11, c: 34, d: 27, tx: 56, ty: 44), epsilon: torelance)) 70 | } 71 | 72 | func testMatmulAssignment() { 73 | var a = CGAffineTransform(a: 1, b: 2, c: 3, d: 4, tx: 5, ty: 6) 74 | a *= CGAffineTransform(a: 6, b: 5, c: 4, d: 3, tx: 2, ty: 1) 75 | print(a) 76 | 77 | XCTAssertTrue(a.isNearlyEqual(to: CGAffineTransform(a: 1, b: 2, c: 3, d: 4, tx: 5, ty: 6) 78 | * CGAffineTransform(a: 6, b: 5, c: 4, d: 3, tx: 2, ty: 1), epsilon: torelance)) 79 | } 80 | 81 | static var allTests : [(String, (CGAffineTransormTests) -> () throws -> Void)] { 82 | return [ 83 | ("testisNearlyEqual", testisNearlyEqual), 84 | ("testDescription", testDescription), 85 | ("testMatmul", testMatmul), 86 | ("testMatmulAssignment", testMatmulAssignment), 87 | ] 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Tests/CGPointVectorTests/CGPointTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import CGPointVector 3 | 4 | class CGPointTests: XCTestCase { 5 | let torelance: CGFloat = 1.0e-5; 6 | 7 | func testisNearlyEqual() { 8 | XCTAssertFalse(CGPoint(x: 1.0, y: 2.0).isNearlyEqual(to: CGPoint(x: 0.5, y: 2.0), epsilon: 0.5)) 9 | XCTAssertTrue(CGPoint(x: 1.0, y: 2.0).isNearlyEqual(to: CGPoint(x: 0.51, y: 2.0), epsilon: 0.5)) 10 | XCTAssertTrue(CGPoint(x: 1.0, y: 2.0).isNearlyEqual(to: CGPoint(x: 1.49, y: 2.0), epsilon: 0.5)) 11 | XCTAssertFalse(CGPoint(x: 1.0, y: 2.0).isNearlyEqual(to: CGPoint(x: 0.4, y: 2.0), epsilon: 0.5)) 12 | 13 | XCTAssertFalse(CGPoint(x: 1.0, y: 2.0).isNearlyEqual(to: CGPoint(x: 1.0, y: 1.0), epsilon: 1.0)) 14 | XCTAssertTrue(CGPoint(x: 1.0, y: 2.0).isNearlyEqual(to: CGPoint(x: 1.0, y: 1.1), epsilon: 1.0)) 15 | XCTAssertTrue(CGPoint(x: 1.0, y: 2.0).isNearlyEqual(to: CGPoint(x: 1.0, y: 2.9), epsilon: 1.0)) 16 | XCTAssertFalse(CGPoint(x: 1.0, y: 2.0).isNearlyEqual(to: CGPoint(x: 1.0, y: 3.0), epsilon: 1.0)) 17 | } 18 | 19 | func testLength() { 20 | XCTAssertEqual(CGPoint(x: 3.0, y: -4.0).length, 5.0, accuracy: torelance) 21 | XCTAssertEqual(CGPoint(x: .greatestFiniteMagnitude, y: 0.0).length, .greatestFiniteMagnitude) 22 | XCTAssertEqual(CGPoint(x: 0.0, y: .leastNonzeroMagnitude).length, .leastNonzeroMagnitude) 23 | } 24 | 25 | func testSquareLength() { 26 | XCTAssertEqual(CGPoint(x: 3.0, y: -4.0).squareLength, 25.0, accuracy: torelance) 27 | } 28 | 29 | func testUnit() { 30 | XCTAssertTrue(CGPoint(x: 3.0, y: -4.0).unit.isNearlyEqual(to: CGPoint(x: 0.6, y: -0.8), epsilon: torelance)) 31 | } 32 | 33 | func testPhase() { 34 | XCTAssertEqual(CGPoint(x: 1.0, y: sqrt(3)).phase, CGFloat.pi / 3, accuracy: torelance) 35 | } 36 | 37 | func testDistance() { 38 | XCTAssertEqual(CGPoint(x: 1.0, y: 2.0).distance(from: CGPoint(x: -3.0, y: 5.0)), 5.0, accuracy: torelance) 39 | } 40 | 41 | func testSquareDistance() { 42 | XCTAssertEqual(CGPoint(x: 1.0, y: 2.0).squareDistance(from: CGPoint(x: -3.0, y: 5.0)), 25.0, accuracy: torelance) 43 | } 44 | 45 | func testAngle() { 46 | XCTAssertEqual(CGPoint(x: 1.0, y: 0.0).angle(from: CGPoint(x: sqrt(3.0), y: 1.0)), CGFloat.pi / 6, accuracy: torelance) 47 | XCTAssertEqual(CGPoint(x: 1.0, y: 0.0).angle(from: .zero), 0.0, accuracy: torelance) 48 | XCTAssertEqual(CGPoint.zero.angle(from: CGPoint(x: 0.0, y: 1.0)), 0.0, accuracy: torelance) 49 | XCTAssertEqual(CGPoint.zero.angle(from: .zero), 0.0, accuracy: torelance) 50 | } 51 | 52 | func testCos() { 53 | XCTAssertEqual(CGPoint(x: 1.0, y: 0.0).cos(from: CGPoint(x: 1.0, y: sqrt(3.0))), 0.5, accuracy: torelance) 54 | XCTAssertEqual(CGPoint(x: 1.0, y: 0.0).cos(from: .zero), 1.0, accuracy: torelance) 55 | XCTAssertEqual(CGPoint.zero.cos(from: CGPoint(x: 0.0, y: 1.0)), 1.0, accuracy: torelance) 56 | XCTAssertEqual(CGPoint.zero.cos(from: .zero), 1.0, accuracy: torelance) 57 | } 58 | 59 | func testDot() { 60 | XCTAssertEqual(CGPoint(x: 1.0, y: 2.0).dot(CGPoint(x: -3.0, y: 4.0)), 5.0, accuracy: torelance) 61 | } 62 | 63 | func testDescription() { 64 | XCTAssertEqual(CGPoint(x: 1.0, y: 2.0).description, "(1.0, 2.0)") 65 | } 66 | 67 | func testPrefixPlus() { 68 | XCTAssertTrue((+CGPoint(x: 1.0, y: -2.0)).isNearlyEqual(to: CGPoint(x: 1.0, y: -2.0), epsilon: torelance)) 69 | } 70 | 71 | func testNegate() { 72 | XCTAssertTrue((-CGPoint(x: 1.0, y: -2.0)).isNearlyEqual(to: CGPoint(x: -1.0, y: 2.0), epsilon: torelance)) 73 | } 74 | 75 | func testAdd() { 76 | XCTAssertTrue((CGPoint(x: 1.0, y: 2.0) + CGPoint(x: 3.0, y: -4.0)).isNearlyEqual(to: CGPoint(x: 4.0, y: -2.0), epsilon: torelance)) 77 | XCTAssertTrue((CGPoint(x: 1.0, y: 2.0) + CGSize(width: 3.0, height: -4.0)).isNearlyEqual(to: CGPoint(x: 4.0, y: -2.0), epsilon: torelance)) 78 | } 79 | 80 | func testSubtract() { 81 | XCTAssertTrue((CGPoint(x: 3.0, y: 2.0) - CGPoint(x: 1.0, y: 4.0)).isNearlyEqual(to: CGPoint(x: 2.0, y: -2.0), epsilon: torelance)) 82 | XCTAssertTrue((CGPoint(x: 3.0, y: 2.0) - CGSize(width: 1.0, height: 4.0)).isNearlyEqual(to: CGPoint(x: 2.0, y: -2.0), epsilon: torelance)) 83 | } 84 | 85 | func testMultiply() { 86 | XCTAssertTrue((CGPoint(x: 2.0, y: 3.0) * CGPoint(x: 5.0, y: 7.0)).isNearlyEqual(to: CGPoint(x: 10.0, y: 21.0), epsilon: torelance)) 87 | XCTAssertTrue((CGPoint(x: 2.0, y: 3.0) * CGSize(width: 5.0, height: 7.0)).isNearlyEqual(to: CGPoint(x: 10.0, y: 21.0), epsilon: torelance)) 88 | XCTAssertTrue((CGPoint(x: 1.0, y: -2.0) * 3.0).isNearlyEqual(to: CGPoint(x: 3.0, y: -6.0), epsilon: torelance)) 89 | XCTAssertTrue((3.0 * CGPoint(x: 1.0, y: -2.0)).isNearlyEqual(to: CGPoint(x: 3.0, y: -6.0), epsilon: torelance)) 90 | } 91 | 92 | func testDivide() { 93 | XCTAssertTrue((CGPoint(x: 8.0, y: 27.0) / CGPoint(x: 2.0, y: 3.0)).isNearlyEqual(to: CGPoint(x: 4.0, y: 9.0), epsilon: torelance)) 94 | XCTAssertTrue((CGPoint(x: 8.0, y: 27.0) / CGSize(width: 2.0, height: 3.0)).isNearlyEqual(to: CGPoint(x: 4.0, y: 9.0), epsilon: torelance)) 95 | XCTAssertTrue((CGPoint(x: 8.0, y: -2.0) / 4.0).isNearlyEqual(to: CGPoint(x: 2.0, y: -0.5), epsilon: torelance)) 96 | } 97 | 98 | func testMatmul() { 99 | XCTAssertTrue((CGPoint(x: 1.0, y: 1.0) * CGAffineTransform(rotationAngle: CGFloat.pi / 4)).isNearlyEqual(to: CGPoint(x: 0.0, y: sqrt(2)), epsilon: torelance)) 100 | XCTAssertTrue((CGPoint(x: 1.0, y: 1.0) * CGAffineTransform(translationX: 1.0, y: -2.0)).isNearlyEqual(to: CGPoint(x: 2.0, y: -1.0), epsilon: torelance)) 101 | XCTAssertTrue((CGPoint(x: 1.0, y: 2.0) * CGAffineTransform(a: 3.0, b: 4.0, c: 5.0, d: 6.0, tx: 7.0, ty: 8.0)).isNearlyEqual(to: CGPoint(x: 20, y: 24), epsilon: torelance)) 102 | } 103 | 104 | func testAdditionAssignment() { 105 | var a = CGPoint(x: 1.0, y: 2.0) 106 | a += CGPoint(x: 3.0, y: -4.0) 107 | XCTAssertTrue(a.isNearlyEqual(to: CGPoint(x: 1.0, y: 2.0) 108 | + CGPoint(x: 3.0, y: -4.0), epsilon: torelance)) 109 | } 110 | 111 | func testSuntractionAssignment() { 112 | var a = CGPoint(x: 3.0, y: 2.0) 113 | a -= CGPoint(x: 1.0, y: 4.0) 114 | XCTAssertTrue(a.isNearlyEqual(to: CGPoint(x: 3.0, y: 2.0) 115 | - CGPoint(x: 1.0, y: 4.0), epsilon: torelance)) 116 | } 117 | 118 | func testMultiplicationAssignment() { 119 | var a = CGPoint(x: 1.0, y: -2.0) 120 | a *= 3.0 121 | XCTAssertTrue(a.isNearlyEqual(to: CGPoint(x: 1.0, y: -2.0) * 3, epsilon: torelance)) 122 | } 123 | 124 | func testDivisionAssignment() { 125 | var a = CGPoint(x: 8.0, y: -2.0) 126 | a /= 4.0 127 | XCTAssertTrue(a.isNearlyEqual(to: CGPoint(x: 8.0, y: -2.0) / 4.0, epsilon: torelance)) 128 | } 129 | 130 | func testMatmulAssignment() { 131 | var a = CGPoint(x: 1.0, y: 1.0) 132 | a *= CGAffineTransform(rotationAngle: CGFloat.pi / 4) 133 | XCTAssertTrue(a.isNearlyEqual(to: CGPoint(x: 0.0, y: sqrt(2)), epsilon: torelance)) 134 | } 135 | 136 | static var allTests : [(String, (CGPointTests) -> () throws -> Void)] { 137 | return [ 138 | ("testisNearlyEqual", testisNearlyEqual), 139 | ("testLength", testLength), 140 | ("testSquareLength", testSquareLength), 141 | ("testUnit", testUnit), 142 | ("testPhase", testPhase), 143 | ("testDistance", testDistance), 144 | ("testSquareDistance", testSquareDistance), 145 | ("testAngle", testAngle), 146 | ("testCos", testCos), 147 | ("testDot", testDot), 148 | ("testDescription", testDescription), 149 | ("testPrefixPlus", testPrefixPlus), 150 | ("testNegate", testNegate), 151 | ("testAdd", testAdd), 152 | ("testSubtract", testSubtract), 153 | ("testMultiply", testMultiply), 154 | ("testDivide", testDivide), 155 | ("testMatmul", testMatmul), 156 | ("testAdditionAssignment", testAdditionAssignment), 157 | ("testSuntractionAssignment", testSuntractionAssignment), 158 | ("testMultiplicationAssignment", testMultiplicationAssignment), 159 | ("testDivisionAssignment", testDivisionAssignment), 160 | ("testMatmulAssignment", testMatmulAssignment), 161 | ] 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /Tests/CGPointVectorTests/CGPointVectorTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import CGPointVector 3 | 4 | class CGPointVectorTests: XCTestCase { 5 | let torelance: CGFloat = 1.0e-5; 6 | 7 | func testExample() { 8 | let a = CGPoint(x: 1, y: 2), b = CGPoint(x: -3, y: 5) 9 | 10 | let sum = a + b // (-2.0, 7.0) 11 | let distance = (b - a).length // 5.0 12 | let direction = (b - a).unit // (-0.8, 0.6) 13 | let rotated = a * CGAffineTransform(rotationAngle: CGFloat.pi / 2) // (-2.0, 1.0) 14 | 15 | XCTAssertTrue(sum.isNearlyEqual(to: CGPoint(x: -2.0, y: 7.0), epsilon: torelance)) 16 | XCTAssertEqual(distance, 5.0, accuracy: torelance) 17 | XCTAssertTrue(direction.isNearlyEqual(to: CGPoint(x: -0.8, y: 0.6), epsilon: torelance)) 18 | XCTAssertTrue(rotated.isNearlyEqual(to: CGPoint(x: -2.0, y: 1.0), epsilon: torelance)) 19 | } 20 | 21 | func testUsage() { 22 | let a = CGPoint(x: 3.0, y: -4.0) 23 | let b = CGPoint(x: 2.0, y: -5.0) 24 | 25 | let sum = a + b // (5.0, -9.0) 26 | let length = a.length // 5.0 27 | let distance = a.distance(from: b) // 1.4142135623731 28 | let unitVector = a.unit // (0.6, -0.8) 29 | let dotProduct = a.dot(b) // 26.0 30 | let angle = a.angle(from: b) // 0.26299473168091936 31 | 32 | XCTAssertTrue(sum.isNearlyEqual(to: CGPoint(x: 5.0, y: -9.0), epsilon: torelance)) 33 | XCTAssertEqual(length, 5.0, accuracy: torelance) 34 | XCTAssertEqual(distance, 1.4142135623731, accuracy: torelance) 35 | XCTAssertTrue(unitVector.isNearlyEqual(to: CGPoint(x: 0.6, y: -0.8), epsilon: torelance)) 36 | XCTAssertEqual(dotProduct, 26.0, accuracy: torelance) 37 | XCTAssertEqual(angle, 0.26299473168091936, accuracy: torelance) 38 | } 39 | 40 | static var allTests : [(String, (CGPointVectorTests) -> () throws -> Void)] { 41 | return [ 42 | ("testExample", testExample), 43 | ("testUsage", testUsage), 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Tests/CGPointVectorTests/CGRectTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import CGPointVector 3 | 4 | class CGRectTests: XCTestCase { 5 | let torelance: CGFloat = 1.0e-5; 6 | 7 | func testisNearlyEqual() { 8 | XCTAssertFalse(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 0.0, y: 2.0, width: 3.0, height: 4.0), epsilon: 1.0)) 9 | XCTAssertTrue(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 0.1, y: 2.0, width: 3.0, height: 4.0), epsilon: 1.0)) 10 | XCTAssertTrue(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 1.9, y: 2.0, width: 3.0, height: 4.0), epsilon: 1.0)) 11 | XCTAssertFalse(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 2.0, y: 2.0, width: 3.0, height: 4.0), epsilon: 1.0)) 12 | 13 | XCTAssertFalse(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 1.0, y: 1.0, width: 3.0, height: 4.0), epsilon: 1.0)) 14 | XCTAssertTrue(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 1.0, y: 1.1, width: 3.0, height: 4.0), epsilon: 1.0)) 15 | XCTAssertTrue(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 1.0, y: 2.9, width: 3.0, height: 4.0), epsilon: 1.0)) 16 | XCTAssertFalse(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 1.0, y: 3.0, width: 3.0, height: 4.0), epsilon: 1.0)) 17 | 18 | XCTAssertFalse(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 1.0, y: 2.0, width: 2.0, height: 4.0), epsilon: 1.0)) 19 | XCTAssertTrue(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 1.0, y: 2.0, width: 2.1, height: 4.0), epsilon: 1.0)) 20 | XCTAssertTrue(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 1.0, y: 2.0, width: 3.9, height: 4.0), epsilon: 1.0)) 21 | XCTAssertFalse(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 1.0, y: 2.0, width: 4.0, height: 4.0), epsilon: 1.0)) 22 | 23 | XCTAssertFalse(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 1.0, y: 2.0, width: 3.0, height: 3.0), epsilon: 1.0)) 24 | XCTAssertTrue(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 1.0, y: 2.0, width: 3.0, height: 3.1), epsilon: 1.0)) 25 | XCTAssertTrue(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.9), epsilon: 1.0)) 26 | XCTAssertFalse(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).isNearlyEqual(to: CGRect(x: 1.0, y: 2.0, width: 3.0, height: 5.0), epsilon: 1.0)) 27 | } 28 | 29 | func testCenter() { 30 | XCTAssertTrue(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).center 31 | .isNearlyEqual(to: CGPoint(x: 2.5, y: 4.0), epsilon: torelance)) 32 | } 33 | 34 | func testDescription() { 35 | XCTAssertEqual(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0).description, "((1.0, 2.0), (3.0, 4.0))") 36 | } 37 | 38 | func testMatmul() { 39 | print(CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0) * CGAffineTransform(a: 0, b: 1, c: -1, d: 0, tx: 0, ty: 0)) 40 | XCTAssertTrue((CGRect(x: 1.0, y: 2.0, width: 3.0, height: 4.0) * CGAffineTransform(a: 0, b: 1, c: -1, d: 0, tx: 0, ty: 0)) 41 | .isNearlyEqual(to: CGRect(x: -6.0, y: 1.0, width: 4.0, height: 3.0), epsilon: torelance)) 42 | } 43 | 44 | static var allTests : [(String, (CGRectTests) -> () throws -> Void)] { 45 | return [ 46 | ("testisNearlyEqual", testisNearlyEqual), 47 | ("testCenter", testCenter), 48 | ("testDescription", testDescription), 49 | ("testMatmul", testMatmul), 50 | ] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Tests/CGPointVectorTests/CGSizeTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import CGPointVector 3 | 4 | class CGSizeTests: XCTestCase { 5 | let torelance: CGFloat = 1.0e-5; 6 | 7 | func testisNearlyEqual() { 8 | XCTAssertFalse(CGSize(width: 1.0, height: 2.0).isNearlyEqual(to: CGSize(width: 0.5, height: 2.0), epsilon: 0.5)) 9 | XCTAssertTrue(CGSize(width: 1.0, height: 2.0).isNearlyEqual(to: CGSize(width: 0.51, height: 2.0), epsilon: 0.5)) 10 | XCTAssertTrue(CGSize(width: 1.0, height: 2.0).isNearlyEqual(to: CGSize(width: 1.49, height: 2.0), epsilon: 0.5)) 11 | XCTAssertFalse(CGSize(width: 1.0, height: 2.0).isNearlyEqual(to: CGSize(width: 0.4, height: 2.0), epsilon: 0.5)) 12 | 13 | XCTAssertFalse(CGSize(width: 1.0, height: 2.0).isNearlyEqual(to: CGSize(width: 1.0, height: 1.0), epsilon: 1.0)) 14 | XCTAssertTrue(CGSize(width: 1.0, height: 2.0).isNearlyEqual(to: CGSize(width: 1.0, height: 1.1), epsilon: 1.0)) 15 | XCTAssertTrue(CGSize(width: 1.0, height: 2.0).isNearlyEqual(to: CGSize(width: 1.0, height: 2.9), epsilon: 1.0)) 16 | XCTAssertFalse(CGSize(width: 1.0, height: 2.0).isNearlyEqual(to: CGSize(width: 1.0, height: 3.0), epsilon: 1.0)) 17 | } 18 | 19 | func testLength() { 20 | XCTAssertEqual(CGSize(width: 3.0, height: -4.0).length, 5.0, accuracy: torelance) 21 | XCTAssertEqual(CGSize(width: .greatestFiniteMagnitude, height: 0.0).length, .greatestFiniteMagnitude) 22 | XCTAssertEqual(CGSize(width: 0.0, height: .leastNonzeroMagnitude).length, .leastNonzeroMagnitude) 23 | } 24 | 25 | func testSquareLength() { 26 | XCTAssertEqual(CGSize(width: 3.0, height: -4.0).squareLength, 25.0, accuracy: torelance) 27 | } 28 | 29 | func testUnit() { 30 | XCTAssertTrue(CGSize(width: 3.0, height: -4.0).unit.isNearlyEqual(to: CGSize(width: 0.6, height: -0.8), epsilon: torelance)) 31 | } 32 | 33 | func testPhase() { 34 | XCTAssertEqual(CGSize(width: 1.0, height: sqrt(3)).phase, CGFloat.pi / 3, accuracy: torelance) 35 | } 36 | 37 | func testDistance() { 38 | XCTAssertEqual(CGSize(width: 1.0, height: 2.0).distance(from: CGSize(width: -3.0, height: 5.0)), 5.0, accuracy: torelance) 39 | } 40 | 41 | func testSquareDistance() { 42 | XCTAssertEqual(CGSize(width: 1.0, height: 2.0).squareDistance(from: CGSize(width: -3.0, height: 5.0)), 25.0, accuracy: torelance) 43 | } 44 | 45 | func testAngle() { 46 | XCTAssertEqual(CGSize(width: 1.0, height: 0.0).angle(from: CGSize(width: sqrt(3.0), height: 1.0)), CGFloat.pi / 6, accuracy: torelance) 47 | XCTAssertEqual(CGSize(width: 1.0, height: 0.0).angle(from: .zero), 0.0, accuracy: torelance) 48 | XCTAssertEqual(CGSize.zero.angle(from: CGSize(width: 0.0, height: 1.0)), 0.0, accuracy: torelance) 49 | XCTAssertEqual(CGSize.zero.angle(from: .zero), 0.0, accuracy: torelance) 50 | } 51 | 52 | func testCos() { 53 | XCTAssertEqual(CGSize(width: 1.0, height: 0.0).cos(from: CGSize(width: 1.0, height: sqrt(3.0))), 0.5, accuracy: torelance) 54 | XCTAssertEqual(CGSize(width: 1.0, height: 0.0).cos(from: .zero), 1.0, accuracy: torelance) 55 | XCTAssertEqual(CGSize.zero.cos(from: CGSize(width: 0.0, height: 1.0)), 1.0, accuracy: torelance) 56 | XCTAssertEqual(CGSize.zero.cos(from: .zero), 1.0, accuracy: torelance) 57 | } 58 | 59 | func testDot() { 60 | XCTAssertEqual(CGSize(width: 1.0, height: 2.0).dot(CGSize(width: -3.0, height: 4.0)), 5.0, accuracy: torelance) 61 | } 62 | 63 | func testDescription() { 64 | XCTAssertEqual(CGSize(width: 1.0, height: 2.0).description, "(1.0, 2.0)") 65 | } 66 | 67 | func testPrefixPlus() { 68 | XCTAssertTrue((+CGSize(width: 1.0, height: -2.0)).isNearlyEqual(to: CGSize(width: 1.0, height: -2.0), epsilon: torelance)) 69 | } 70 | 71 | func testNegate() { 72 | XCTAssertTrue((-CGSize(width: 1.0, height: -2.0)).isNearlyEqual(to: CGSize(width: -1.0, height: 2.0), epsilon: torelance)) 73 | } 74 | 75 | func testAdd() { 76 | XCTAssertTrue((CGSize(width: 1.0, height: 2.0) + CGSize(width: 3.0, height: -4.0)).isNearlyEqual(to: CGSize(width: 4.0, height: -2.0), epsilon: torelance)) 77 | XCTAssertTrue((CGSize(width: 1.0, height: 2.0) + CGPoint(x: 3.0, y: -4.0)).isNearlyEqual(to: CGPoint(x: 4.0, y: -2.0), epsilon: torelance)) 78 | } 79 | 80 | func testSubtract() { 81 | XCTAssertTrue((CGSize(width: 3.0, height: 2.0) - CGSize(width: 1.0, height: 4.0)).isNearlyEqual(to: CGSize(width: 2.0, height: -2.0), epsilon: torelance)) 82 | XCTAssertTrue((CGSize(width: 3.0, height: 2.0) - CGPoint(x: 1.0, y: 4.0)).isNearlyEqual(to: CGPoint(x: 2.0, y: -2.0), epsilon: torelance)) 83 | } 84 | 85 | func testMultiply() { 86 | XCTAssertTrue((CGSize(width: 2.0, height: 3.0) * CGSize(width: 5.0, height: 7.0)).isNearlyEqual(to: CGSize(width: 10.0, height: 21.0), epsilon: torelance)) 87 | XCTAssertTrue((CGSize(width: 2.0, height: 3.0) * CGPoint(x: 5.0, y: 7.0)).isNearlyEqual(to: CGPoint(x: 10.0, y: 21.0), epsilon: torelance)) 88 | XCTAssertTrue((CGSize(width: 1.0, height: -2.0) * 3.0).isNearlyEqual(to: CGSize(width: 3.0, height: -6.0), epsilon: torelance)) 89 | XCTAssertTrue((3.0 * CGSize(width: 1.0, height: -2.0)).isNearlyEqual(to: CGSize(width: 3.0, height: -6.0), epsilon: torelance)) 90 | } 91 | 92 | func testDivide() { 93 | XCTAssertTrue((CGSize(width: 8.0, height: 27.0) / CGSize(width: 2.0, height: 3.0)).isNearlyEqual(to: CGSize(width: 4.0, height: 9.0), epsilon: torelance)) 94 | XCTAssertTrue((CGSize(width: 8.0, height: 27.0) / CGPoint(x: 2.0, y: 3.0)).isNearlyEqual(to: CGPoint(x: 4.0, y: 9.0), epsilon: torelance)) 95 | XCTAssertTrue((CGSize(width: 8.0, height: -2.0) / 4.0).isNearlyEqual(to: CGSize(width: 2.0, height: -0.5), epsilon: torelance)) 96 | } 97 | 98 | func testAdditionAssignment() { 99 | var a = CGSize(width: 1.0, height: 2.0) 100 | a += CGSize(width: 3.0, height: -4.0) 101 | XCTAssertTrue(a.isNearlyEqual(to: CGSize(width: 1.0, height: 2.0) 102 | + CGSize(width: 3.0, height: -4.0), epsilon: torelance)) 103 | } 104 | 105 | func testSuntractionAssignment() { 106 | var a = CGSize(width: 3.0, height: 2.0) 107 | a -= CGSize(width: 1.0, height: 4.0) 108 | XCTAssertTrue(a.isNearlyEqual(to: CGSize(width: 3.0, height: 2.0) 109 | - CGSize(width: 1.0, height: 4.0), epsilon: torelance)) 110 | } 111 | 112 | func testMultiplicationAssignment() { 113 | var a = CGSize(width: 1.0, height: -2.0) 114 | a *= 3.0 115 | XCTAssertTrue(a.isNearlyEqual(to: CGSize(width: 1.0, height: -2.0) * 3, epsilon: torelance)) 116 | } 117 | 118 | func testDivisionAssignment() { 119 | var a = CGSize(width: 8.0, height: -2.0) 120 | a /= 4.0 121 | XCTAssertTrue(a.isNearlyEqual(to: CGSize(width: 8.0, height: -2.0) / 4.0, epsilon: torelance)) 122 | } 123 | 124 | static var allTests : [(String, (CGSizeTests) -> () throws -> Void)] { 125 | return [ 126 | ("testisNearlyEqual", testisNearlyEqual), 127 | ("testLength", testLength), 128 | ("testSquareLength", testSquareLength), 129 | ("testUnit", testUnit), 130 | ("testPhase", testPhase), 131 | ("testDistance", testDistance), 132 | ("testSquareDistance", testSquareDistance), 133 | ("testAngle", testAngle), 134 | ("testCos", testCos), 135 | ("testDot", testDot), 136 | ("testDescription", testDescription), 137 | ("testPrefixPlus", testPrefixPlus), 138 | ("testNegate", testNegate), 139 | ("testAdd", testAdd), 140 | ("testSubtract", testSubtract), 141 | ("testMultiply", testMultiply), 142 | ("testDivide", testDivide), 143 | ("testAdditionAssignment", testAdditionAssignment), 144 | ("testSuntractionAssignment", testSuntractionAssignment), 145 | ("testMultiplicationAssignment", testMultiplicationAssignment), 146 | ("testDivisionAssignment", testDivisionAssignment), 147 | ] 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /Tests/CGPointVectorTests/CGVectorTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import CGPointVector 3 | 4 | class CGVectorTests: XCTestCase { 5 | let torelance: CGFloat = 1.0e-5; 6 | 7 | func testisNearlyEqual() { 8 | XCTAssertFalse(CGVector(dx: 1.0, dy: 2.0).isNearlyEqual(to: CGVector(dx: 0.5, dy: 2.0), epsilon: 0.5)) 9 | XCTAssertTrue(CGVector(dx: 1.0, dy: 2.0).isNearlyEqual(to: CGVector(dx: 0.51, dy: 2.0), epsilon: 0.5)) 10 | XCTAssertTrue(CGVector(dx: 1.0, dy: 2.0).isNearlyEqual(to: CGVector(dx: 1.49, dy: 2.0), epsilon: 0.5)) 11 | XCTAssertFalse(CGVector(dx: 1.0, dy: 2.0).isNearlyEqual(to: CGVector(dx: 0.4, dy: 2.0), epsilon: 0.5)) 12 | 13 | XCTAssertFalse(CGVector(dx: 1.0, dy: 2.0).isNearlyEqual(to: CGVector(dx: 1.0, dy: 1.0), epsilon: 1.0)) 14 | XCTAssertTrue(CGVector(dx: 1.0, dy: 2.0).isNearlyEqual(to: CGVector(dx: 1.0, dy: 1.1), epsilon: 1.0)) 15 | XCTAssertTrue(CGVector(dx: 1.0, dy: 2.0).isNearlyEqual(to: CGVector(dx: 1.0, dy: 2.9), epsilon: 1.0)) 16 | XCTAssertFalse(CGVector(dx: 1.0, dy: 2.0).isNearlyEqual(to: CGVector(dx: 1.0, dy: 3.0), epsilon: 1.0)) 17 | } 18 | 19 | func testLength() { 20 | XCTAssertEqual(CGVector(dx: 3.0, dy: -4.0).length, 5.0, accuracy: torelance) 21 | XCTAssertEqual(CGVector(dx: .greatestFiniteMagnitude, dy: 0.0).length, .greatestFiniteMagnitude) 22 | XCTAssertEqual(CGVector(dx: 0.0, dy: .leastNonzeroMagnitude).length, .leastNonzeroMagnitude) 23 | } 24 | 25 | func testSquareLength() { 26 | XCTAssertEqual(CGVector(dx: 3.0, dy: -4.0).squareLength, 25.0, accuracy: torelance) 27 | } 28 | 29 | func testUnit() { 30 | XCTAssertTrue(CGVector(dx: 3.0, dy: -4.0).unit.isNearlyEqual(to: CGVector(dx: 0.6, dy: -0.8), epsilon: torelance)) 31 | } 32 | 33 | func testPhase() { 34 | XCTAssertEqual(CGVector(dx: 1.0, dy: sqrt(3)).phase, CGFloat.pi / 3, accuracy: torelance) 35 | } 36 | 37 | func testDistance() { 38 | XCTAssertEqual(CGVector(dx: 1.0, dy: 2.0).distance(from: CGVector(dx: -3.0, dy: 5.0)), 5.0, accuracy: torelance) 39 | } 40 | 41 | func testSquareDistance() { 42 | XCTAssertEqual(CGVector(dx: 1.0, dy: 2.0).squareDistance(from: CGVector(dx: -3.0, dy: 5.0)), 25.0, accuracy: torelance) 43 | } 44 | 45 | func testAngle() { 46 | XCTAssertEqual(CGVector(dx: 1.0, dy: 0.0).angle(from: CGVector(dx: sqrt(3.0), dy: 1.0)), CGFloat.pi / 6, accuracy: torelance) 47 | XCTAssertEqual(CGVector(dx: 1.0, dy: 0.0).angle(from: .zero), 0.0, accuracy: torelance) 48 | XCTAssertEqual(CGVector.zero.angle(from: CGVector(dx: 0.0, dy: 1.0)), 0.0, accuracy: torelance) 49 | XCTAssertEqual(CGVector.zero.angle(from: .zero), 0.0, accuracy: torelance) 50 | } 51 | 52 | func testCos() { 53 | XCTAssertEqual(CGVector(dx: 1.0, dy: 0.0).cos(from: CGVector(dx: 1.0, dy: sqrt(3.0))), 0.5, accuracy: torelance) 54 | XCTAssertEqual(CGVector(dx: 1.0, dy: 0.0).cos(from: .zero), 1.0, accuracy: torelance) 55 | XCTAssertEqual(CGVector.zero.cos(from: CGVector(dx: 0.0, dy: 1.0)), 1.0, accuracy: torelance) 56 | XCTAssertEqual(CGVector.zero.cos(from: .zero), 1.0, accuracy: torelance) 57 | } 58 | 59 | func testDot() { 60 | XCTAssertEqual(CGVector(dx: 1.0, dy: 2.0).dot(CGVector(dx: -3.0, dy: 4.0)), 5.0, accuracy: torelance) 61 | } 62 | 63 | func testDescription() { 64 | XCTAssertEqual(CGVector(dx: 1.0, dy: 2.0).description, "(1.0, 2.0)") 65 | } 66 | 67 | func testPrefixPlus() { 68 | XCTAssertTrue((+CGVector(dx: 1.0, dy: -2.0)).isNearlyEqual(to: CGVector(dx: 1.0, dy: -2.0), epsilon: torelance)) 69 | } 70 | 71 | func testNegate() { 72 | XCTAssertTrue((-CGVector(dx: 1.0, dy: -2.0)).isNearlyEqual(to: CGVector(dx: -1.0, dy: 2.0), epsilon: torelance)) 73 | } 74 | 75 | func testAdd() { 76 | XCTAssertTrue((CGVector(dx: 1.0, dy: 2.0) + CGVector(dx: 3.0, dy: -4.0)).isNearlyEqual(to: CGVector(dx: 4.0, dy: -2.0), epsilon: torelance)) 77 | XCTAssertTrue((CGVector(dx: 1.0, dy: 2.0) + CGPoint(x: 3.0, y: -4.0)).isNearlyEqual(to: CGPoint(x: 4.0, y: -2.0), epsilon: torelance)) 78 | } 79 | 80 | func testSubtract() { 81 | XCTAssertTrue((CGVector(dx: 3.0, dy: 2.0) - CGVector(dx: 1.0, dy: 4.0)).isNearlyEqual(to: CGVector(dx: 2.0, dy: -2.0), epsilon: torelance)) 82 | XCTAssertTrue((CGVector(dx: 3.0, dy: 2.0) - CGPoint(x: 1.0, y: 4.0)).isNearlyEqual(to: CGPoint(x: 2.0, y: -2.0), epsilon: torelance)) 83 | } 84 | 85 | func testMultiply() { 86 | XCTAssertTrue((CGVector(dx: 2.0, dy: 3.0) * CGVector(dx: 5.0, dy: 7.0)).isNearlyEqual(to: CGVector(dx: 10.0, dy: 21.0), epsilon: torelance)) 87 | XCTAssertTrue((CGVector(dx: 2.0, dy: 3.0) * CGPoint(x: 5.0, y: 7.0)).isNearlyEqual(to: CGPoint(x: 10.0, y: 21.0), epsilon: torelance)) 88 | XCTAssertTrue((CGVector(dx: 1.0, dy: -2.0) * 3.0).isNearlyEqual(to: CGVector(dx: 3.0, dy: -6.0), epsilon: torelance)) 89 | XCTAssertTrue((3.0 * CGVector(dx: 1.0, dy: -2.0)).isNearlyEqual(to: CGVector(dx: 3.0, dy: -6.0), epsilon: torelance)) 90 | } 91 | 92 | func testDivide() { 93 | XCTAssertTrue((CGVector(dx: 8.0, dy: 27.0) / CGVector(dx: 2.0, dy: 3.0)).isNearlyEqual(to: CGVector(dx: 4.0, dy: 9.0), epsilon: torelance)) 94 | XCTAssertTrue((CGVector(dx: 8.0, dy: 27.0) / CGPoint(x: 2.0, y: 3.0)).isNearlyEqual(to: CGPoint(x: 4.0, y: 9.0), epsilon: torelance)) 95 | XCTAssertTrue((CGVector(dx: 8.0, dy: -2.0) / 4.0).isNearlyEqual(to: CGVector(dx: 2.0, dy: -0.5), epsilon: torelance)) 96 | } 97 | 98 | func testMatmul() { 99 | XCTAssertTrue((CGVector(dx: 1.0, dy: 1.0) * CGAffineTransform(rotationAngle: CGFloat.pi / 4)).isNearlyEqual(to: CGVector(dx: 0.0, dy: sqrt(2)), epsilon: torelance)) 100 | XCTAssertTrue((CGVector(dx: 1.0, dy: 1.0) * CGAffineTransform(translationX: 1.0, y: -2.0)).isNearlyEqual(to: CGVector(dx: 2.0, dy: -1.0), epsilon: torelance)) 101 | XCTAssertTrue((CGVector(dx: 1.0, dy: 2.0) * CGAffineTransform(a: 3.0, b: 4.0, c: 5.0, d: 6.0, tx: 7.0, ty: 8.0)).isNearlyEqual(to: CGVector(dx: 20, dy: 24), epsilon: torelance)) 102 | } 103 | 104 | func testAdditionAssignment() { 105 | var a = CGVector(dx: 1.0, dy: 2.0) 106 | a += CGVector(dx: 3.0, dy: -4.0) 107 | XCTAssertTrue(a.isNearlyEqual(to: CGVector(dx: 1.0, dy: 2.0) 108 | + CGVector(dx: 3.0, dy: -4.0), epsilon: torelance)) 109 | } 110 | 111 | func testSuntractionAssignment() { 112 | var a = CGVector(dx: 3.0, dy: 2.0) 113 | a -= CGVector(dx: 1.0, dy: 4.0) 114 | XCTAssertTrue(a.isNearlyEqual(to: CGVector(dx: 3.0, dy: 2.0) 115 | - CGVector(dx: 1.0, dy: 4.0), epsilon: torelance)) 116 | } 117 | 118 | func testMultiplicationAssignment() { 119 | var a = CGVector(dx: 1.0, dy: -2.0) 120 | a *= 3.0 121 | XCTAssertTrue(a.isNearlyEqual(to: CGVector(dx: 1.0, dy: -2.0) * 3, epsilon: torelance)) 122 | } 123 | 124 | func testDivisionAssignment() { 125 | var a = CGVector(dx: 8.0, dy: -2.0) 126 | a /= 4.0 127 | XCTAssertTrue(a.isNearlyEqual(to: CGVector(dx: 8.0, dy: -2.0) / 4.0, epsilon: torelance)) 128 | } 129 | 130 | func testMatmulAssignment() { 131 | var a = CGVector(dx: 1.0, dy: 1.0) 132 | a *= CGAffineTransform(rotationAngle: CGFloat.pi / 4) 133 | XCTAssertTrue(a.isNearlyEqual(to: CGVector(dx: 0.0, dy: sqrt(2)), epsilon: torelance)) 134 | } 135 | 136 | static var allTests : [(String, (CGVectorTests) -> () throws -> Void)] { 137 | return [ 138 | ("testisNearlyEqual", testisNearlyEqual), 139 | ("testLength", testLength), 140 | ("testSquareLength", testSquareLength), 141 | ("testUnit", testUnit), 142 | ("testPhase", testPhase), 143 | ("testDistance", testDistance), 144 | ("testSquareDistance", testSquareDistance), 145 | ("testAngle", testAngle), 146 | ("testCos", testCos), 147 | ("testDot", testDot), 148 | ("testDescription", testDescription), 149 | ("testPrefixPlus", testPrefixPlus), 150 | ("testNegate", testNegate), 151 | ("testAdd", testAdd), 152 | ("testSubtract", testSubtract), 153 | ("testMultiply", testMultiply), 154 | ("testDivide", testDivide), 155 | ("testMatmul", testMatmul), 156 | ("testAdditionAssignment", testAdditionAssignment), 157 | ("testSuntractionAssignment", testSuntractionAssignment), 158 | ("testMultiplicationAssignment", testMultiplicationAssignment), 159 | ("testDivisionAssignment", testDivisionAssignment), 160 | ("testMatmulAssignment", testMatmulAssignment), 161 | ] 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import CGPointVectorTests 3 | 4 | XCTMain([ 5 | testCase(CGPointVectorTests.allTests), 6 | testCase(CGAffineTransormTests.allTests), 7 | testCase(CGPointTests.allTests), 8 | testCase(CGRectTests.allTests), 9 | testCase(CGSizeTests.allTests), 10 | ]) 11 | --------------------------------------------------------------------------------