This commit is contained in:
Paul Zabelin
2019-01-21 22:05:25 -08:00
parent 02391df459
commit f464010f74
32 changed files with 139 additions and 130 deletions

View File

@@ -23,13 +23,13 @@ jobs:
command: |
curl https://cocoapods-specs.circleci.com/fetch-cocoapods-repo-from-s3.sh | bash -s cf
pod install --project-directory=Example
- run:
name: Build and run tests
command: xcodebuild -workspace Example/PerspectiveTransform.xcworkspace -scheme Example test -destination "$DESTINATION" | xcpretty -r junit
- save_cache:
key: 2-pods-{{ checksum "Example/Podfile.lock" }}
paths:
- Example/Pods
- run:
name: Build and run tests
command: xcodebuild -workspace Example/PerspectiveTransform.xcworkspace -scheme Example test -destination "$DESTINATION" | xcpretty -r junit
- store_test_results:
path: build/reports
- store_artifacts:

3
.swiftlint.yml Normal file
View File

@@ -0,0 +1,3 @@
excluded:
- Carthage
- Pods

View File

@@ -1,7 +1,7 @@
import Quick
import Nimble
typealias Transformer = (Quadrilateral,Quadrilateral)->CATransform3D
typealias Transformer = (Quadrilateral, Quadrilateral) -> CATransform3D
class CompareTransformSpecConfiguration: QuickConfiguration {
override class func configure(_ configuration: Configuration) {
@@ -25,7 +25,7 @@ class CompareTransformSpecConfiguration: QuickConfiguration {
CGPoint(x: 108.315837, y: 80.1687782),
CGPoint(x: 377.282671, y: 41.4352201),
CGPoint(x: 193.321418, y: 330.023027),
CGPoint(x: 459.781253, y: 251.836131),
CGPoint(x: 459.781253, y: 251.836131)
]
let frame = CGRect(origin: CGPoint.zero,
size: CGSize(width: 20, height: 10))

View File

@@ -379,6 +379,7 @@
607FACCD1AFB9204008FA782 /* Frameworks */,
607FACCE1AFB9204008FA782 /* Resources */,
125261E66BB239DB9C4C2C55 /* [CP] Embed Pods Frameworks */,
4BD29D3B21F6E985009729A5 /* ShellScript */,
);
buildRules = (
);
@@ -576,6 +577,23 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Application Specs/Pods-Application Specs-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
4BD29D3B21F6E985009729A5 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = "/bin/bash -l";
shellScript = "if which swiftlint >/dev/null; then\n /usr/local/bin/swiftlint autocorrect\nelse\n echo \"warning: SwiftLint not installed\"\n echo \"brew install swiftlint\"\nfi\n";
};
70CD543F2A946479825D6587 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;

View File

@@ -12,14 +12,14 @@ import CoreGraphics
class FittingPolygon {
var points: [CGPoint] = []
init(svgPointsString:String) {
init(svgPointsString: String) {
let formatter = NumberFormatter()
let eightNumbers: [CGFloat] = svgPointsString.split(separator: " ").map { substring in
let string = String(substring)
let number = formatter.number(from: string)
return CGFloat(truncating: number!)
}
for point in stride(from:0, to: 7, by: 2) {
for point in stride(from: 0, to: 7, by: 2) {
let x = eightNumbers[point]
let y = eightNumbers[point + 1]
points.append(CGPoint(x: x, y: y))
@@ -34,4 +34,3 @@ class FittingPolygon {
return FittingPolygon(svgPointsString: loader.loadPoints())
}
}

View File

@@ -17,7 +17,7 @@ extension UIPanGestureRecognizer {
let pan = translation(in: controlPoint.superview)
let transform = CGAffineTransform(translationX: pan.x, y: pan.y)
controlPoint.center = controlPoint.center.applying(transform)
setTranslation(CGPoint.zero, in:controlPoint.superview)
setTranslation(CGPoint.zero, in: controlPoint.superview)
}
}
@@ -53,7 +53,7 @@ class PanViewController: UIViewController {
return start.projectiveTransform(destination: destination)
}
private lazy var start : Perspective = createStartingPerspective()
private lazy var start: Perspective = createStartingPerspective()
private func createStartingPerspective() -> Perspective {
transView.resetAnchorPoint()
@@ -62,7 +62,7 @@ class PanViewController: UIViewController {
private var destination: Perspective {
get {
return Perspective(cornerViews.map{$0.center})
return Perspective(cornerViews.map {$0.center})
}
}
}

View File

@@ -36,7 +36,7 @@ extension PolygonLoader: XMLParserDelegate {
didStartElement elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
attributes attributeDict: [String : String] = [:]) {
attributes attributeDict: [String: String] = [:]) {
if elementName == "polygon" {
pointString = attributeDict["points"]?.trimmingCharacters(in: .whitespacesAndNewlines)
}

View File

@@ -33,7 +33,7 @@ let points = [
CGPoint(x: 108.315837, y: 80.1687782),
CGPoint(x: 377.282671, y: 41.4352201),
CGPoint(x: 193.321418, y: 330.023027),
CGPoint(x: 459.781253, y: 251.836131),
CGPoint(x: 459.781253, y: 251.836131)
]
let destination = QuadrilateralCalc()
@@ -62,15 +62,13 @@ CATransform3DEqualToTransform(matrix, toPlace)
overlayView.layer.transform = toPlace
overlayView2.layer.transform = matrix
//: Single point rect should produce identity matrix
let q = QuadrilateralCalc()
q.topLeft = CGPoint(x:0, y:0)
q.topRight = CGPoint(x:1, y:0)
q.bottomLeft = CGPoint(x:0, y:1)
q.bottomRight = CGPoint(x:1, y:1)
q.topLeft = CGPoint(x: 0, y: 0)
q.topRight = CGPoint(x: 1, y: 0)
q.bottomLeft = CGPoint(x: 0, y: 1)
q.bottomRight = CGPoint(x: 1, y: 1)
q.box()
q.box() == CGRect(x: 0, y: 0, width: 1, height: 1)

View File

@@ -32,10 +32,10 @@ containerView.addSubview(destinationView)
containerView.addSubview(view)
let start = Perspective(view.frame)
let transform = start.projectiveTransform(destination:Perspective(destinationView.frame))
let transform = start.projectiveTransform(destination: Perspective(destinationView.frame))
print(transform)
UIView.animate(withDuration:1.0,
UIView.animate(withDuration: 1.0,
delay: 0,
options: [.repeat, .autoreverse],
animations: {
@@ -49,4 +49,3 @@ transform.m33 == 1
transform.m41 == 100
transform.m42 == 100
transform.m43 == 0

View File

@@ -21,7 +21,7 @@ let points = [
CGPoint(x: 108.315837, y: 80.1687782),
CGPoint(x: 377.282671, y: 41.4352201),
CGPoint(x: 193.321418, y: 330.023027),
CGPoint(x: 459.781253, y: 251.836131),
CGPoint(x: 459.781253, y: 251.836131)
]
let destination = Perspective(points)

View File

@@ -43,4 +43,3 @@ public extension CATransform3D {
}
}
}

View File

@@ -16,7 +16,7 @@ public class QuadrilateralCalc {
return CGRect(origin: CGPoint(x: xmin, y: ymin), size: CGSize(width: xmax - xmin, height: ymax - ymin))
}
public func modifyPoints(transform:(CGPoint)->CGPoint) {
public func modifyPoints(transform: (CGPoint) -> CGPoint) {
topLeft = transform(topLeft)
topRight = transform(topRight)
bottomLeft = transform(bottomLeft)
@@ -85,13 +85,13 @@ public class QuadrilateralCalc {
let kEpsilon = CGFloat(0.0001)
if abs(i) < kEpsilon {
i = kEpsilon * (i > 0 ? 1.0 : -1.0);
i = kEpsilon * (i > 0 ? 1.0 : -1.0)
}
return CATransform3D(m11:a/i, m12:d/i, m13:0, m14:g/i,
m21:b/i, m22:e/i, m23:0, m24:h/i,
m31:0, m32:0, m33:1, m34:0,
m41:c/i, m42:f/i, m43:0, m44:1.0)
return CATransform3D(m11: a/i, m12: d/i, m13: 0, m14: g/i,
m21: b/i, m22: e/i, m23: 0, m24: h/i,
m31: 0, m32: 0, m33: 1, m34: 0,
m41: c/i, m42: f/i, m43: 0, m44: 1.0)
}
}

View File

@@ -67,8 +67,6 @@ class CALayerTransformSpec: QuickSpec {
}
}
}
}
}

View File

@@ -10,14 +10,14 @@ class CATransform3Dfrom2DSpec: QuickSpec {
context("2D to 3D") {
it("should add row and column and set 1 for z") {
let projection2D = Matrix3x3Type([
Vector3Type(11,12,13),
Vector3Type(21,22,23),
Vector3Type(31,32,1),
Vector3Type(11, 12, 13),
Vector3Type(21, 22, 23),
Vector3Type(31, 32, 1)
])
let projection3D = CATransform3D(
m11: 11, m12: 12, m13: 0, m14: 13,
m21: 21, m22: 22, m23: 0, m24: 23,
m31: 0, m32: 0, m33: 1, m34: 0,
m31: 0, m32: 0, m33: 1, m34: 0,
m41: 31, m42: 32, m43: 0, m44: 1)
expect(CATransform3D(projection2D.to3d())) == projection3D
}
@@ -33,15 +33,15 @@ class CATransform3Dfrom2DSpec: QuickSpec {
it("should have zeros in third column and row") {
let projection3D = matrix.to3d()
let third = 2
expect(projection3D[0,third]) == 0
expect(projection3D[1,third]) == 0
expect(projection3D[2,third]) == 1
expect(projection3D[3,third]) == 0
expect(projection3D[0, third]) == 0
expect(projection3D[1, third]) == 0
expect(projection3D[2, third]) == 1
expect(projection3D[3, third]) == 0
expect(projection3D[third,0]) == 0
expect(projection3D[third,1]) == 0
expect(projection3D[third,2]) == 1
expect(projection3D[third,3]) == 0
expect(projection3D[third, 0]) == 0
expect(projection3D[third, 1]) == 0
expect(projection3D[third, 2]) == 1
expect(projection3D[third, 3]) == 0
}
context("layer") {
@@ -54,14 +54,14 @@ class CATransform3Dfrom2DSpec: QuickSpec {
scale.y = layer.value(forKeyPath: "transform.scale.y") as! Double
scale.z = layer.value(forKeyPath: "transform.scale.z") as! Double
let madeScale = CATransform3DMakeScale(CGFloat(scale.x), CGFloat(scale.y), CGFloat(scale.z))
print("madeScale:",madeScale)
print("madeScale:", madeScale)
var translate = Vector3Type()
translate.x = layer.value(forKeyPath: "transform.translation.x") as! Double
translate.y = layer.value(forKeyPath: "transform.translation.y") as! Double
translate.z = layer.value(forKeyPath: "transform.translation.z") as! Double
let madeTranslation = CATransform3DMakeTranslation(CGFloat(translate.x), CGFloat(translate.y), CGFloat(translate.z))
print("madeTranslation:",madeTranslation)
print("madeTranslation:", madeTranslation)
let rotate = transform.layerRotation()
print("scale, translate, rotate = ", scale, translate, rotate)
@@ -70,7 +70,7 @@ class CATransform3Dfrom2DSpec: QuickSpec {
let h = atan(transform.m31/transform.m33)
let angle = b*b + p*p + h*h
let madeRotation = CATransform3DMakeRotation(angle, b, p, h)
print("madeRotation:",madeRotation)
print("madeRotation:", madeRotation)
}
}
}

View File

@@ -8,8 +8,8 @@ class MatrixSpec: QuickSpec {
describe("matrix") {
let m = float2x2(rows: [
float2( 4, 3),
float2( 3, 2)
float2( 4, 3),
float2( 3, 2)
])
context("inverse") {
@@ -18,7 +18,7 @@ class MatrixSpec: QuickSpec {
it("should match expected") {
// http://www.mathwords.com/i/inverse_of_a_matrix.htm
let expectInvert = float2x2(rows: [
float2( -2, 3),
float2( -2, 3),
float2( 3, -4)
])
expect(inverse) == expectInvert
@@ -42,7 +42,7 @@ class MatrixSpec: QuickSpec {
// | 1 2 |
// | | = 1*4-2*3 = -2
// | 3 4 |
expect(float2x2([float2(1,2), float2(3,4)]).determinant) == -2
expect(float2x2([float2(1, 2), float2(3, 4)]).determinant) == -2
}
it("should match math word 3x3 example") {
@@ -51,10 +51,9 @@ class MatrixSpec: QuickSpec {
// | 4 5 6 | = (1*5*9+2*6*7+3*4*8)-(3*5*7+2*4*9+1*6*8) = 0
// | 7 8 9 |
// See: https://www.google.com/search?client=safari&rls=en&q=(1*5*9%2B2*6*7%2B3*4*8)-(3*5*7%2B2*4*9%2B1*6*8)+=&ie=UTF-8&oe=UTF-8
expect(Matrix3x3Type([1,2,3,4,5,6,7,8,9]).determinant) == 0
expect(Matrix3x3Type([1, 2, 3, 4, 5, 6, 7, 8, 9]).determinant) == 0
}
}
}
}
}

View File

@@ -34,7 +34,7 @@ class PerspectiveSpec: QuickSpec {
var values = perspective.projectiveTransform(destination: perspective).flattened()
expect(values[10]) == 1.0
values.remove(at: 10)
expect(values).to(allPass{$0!.isNaN})
expect(values).to(allPass {$0!.isNaN})
}
it("should create Not A Number matrix to a valid perspective") {
@@ -42,7 +42,7 @@ class PerspectiveSpec: QuickSpec {
var values = perspective.projectiveTransform(destination: destination).flattened()
expect(values[10]) == 1.0
values.remove(at: 10)
expect(values).to(allPass{$0!.isNaN})
expect(values).to(allPass {$0!.isNaN})
}
}

View File

@@ -205,7 +205,6 @@ class ProjectionSpec: QuickSpec {
}
}
context("affine 2D") {
var scale2D: CGAffineTransform!
var translate2D: CGAffineTransform!

View File

@@ -6,11 +6,11 @@ class VectorProjectionSpec: QuickSpec {
override func spec() {
describe("vector projection") {
it("should be 0 orthogonally") {
let v12 = vector_float2(1,0)
let v23 = vector_float2(0,1)
let p = project(v12, v23)
expect(p.x) == 0
expect(p.y) == 0
let v12 = vector_float2(1, 0)
let v23 = vector_float2(0, 1)
let projection = project(v12, v23)
expect(projection.x) == 0
expect(projection.y) == 0
}
}
}

View File

@@ -8,7 +8,7 @@ class WorkaroundForXcodeCompleteCoverageSpec: QuickSpec {
describe(String(describing: Quadrilateral.init(_:_:))) {
context("to workaround Xcode coverage bug we add this silly test in order to maintain 100% test coverage") {
it("should be covered by tests") {
let optional:Quadrilateral? = Quadrilateral(CGPoint.zero, CGSize.zero)
let optional: Quadrilateral? = Quadrilateral(CGPoint.zero, CGSize.zero)
expect(optional).notTo(beNil())
}
}

View File

@@ -11,19 +11,19 @@ import Accelerate
@testable import PerspectiveTransform
@discardableResult
func solve(_ A:[Double], _ B:[Double] ) -> [Double] {
var inMatrix:[Double] = A
var solution:[Double] = B
func solve(_ A: [Double], _ B: [Double] ) -> [Double] {
var inMatrix: [Double] = A
var solution: [Double] = B
// Get the dimensions of the matrix. An NxN matrix has N^2
// elements, so sqrt( N^2 ) will return N, the dimension
var N:__CLPK_integer = __CLPK_integer( sqrt( Double( A.count ) ) )
var N: __CLPK_integer = __CLPK_integer( sqrt( Double( A.count ) ) )
// Number of columns on the RHS
var NRHS:__CLPK_integer = 1
var NRHS: __CLPK_integer = 1
// Leading dimension of A and B
var LDA:__CLPK_integer = N
var LDB:__CLPK_integer = N
var LDA: __CLPK_integer = N
var LDB: __CLPK_integer = N
// Initialize some arrays for the dgetrf_(), and dgetri_() functions
var pivots:[__CLPK_integer] = [__CLPK_integer](repeating: 0, count: Int(N))
var pivots: [__CLPK_integer] = [__CLPK_integer](repeating: 0, count: Int(N))
var error: __CLPK_integer = -1
// Perform LU factorization
dgetrf_(&LDA, &LDB, &inMatrix, &N, &pivots, &error)
@@ -61,21 +61,21 @@ class AccelerateSolvePerfTest: XCTestCase {
print(start.corners)
print(destination.corners)
func row1(p1:CGPoint, p2:CGPoint) -> [Double] {
return [p1.x,p1.y,1,0,0,0,-p2.x*p1.x,-p2.x*p1.y].map{Double($0)}
func row1(p1: CGPoint, p2: CGPoint) -> [Double] {
return [p1.x, p1.y, 1, 0, 0, 0, -p2.x*p1.x, -p2.x*p1.y].map {Double($0)}
}
func row2(p1:CGPoint, p2:CGPoint) -> [Double] {
return [0,0,0,p1.x,p1.y,1,-p2.y*p1.x,-p2.y*p1.y].map{Double($0)}
func row2(p1: CGPoint, p2: CGPoint) -> [Double] {
return [0, 0, 0, p1.x, p1.y, 1, -p2.y*p1.x, -p2.y*p1.y].map {Double($0)}
}
// let empty: [Double] = []
A = stride(from: 0, through: 3, by: 1).map{
A = stride(from: 0, through: 3, by: 1).map {
row1(p1: start.corners[$0], p2: destination.corners[$0]) +
row2(p1: start.corners[$0], p2: destination.corners[$0])
}.reduce([],{$0! + $1})
}.reduce([], {$0! + $1})
B = stride(from: 0, through: 3, by: 1).map{[destination.corners[$0].x, destination.corners[$0].y]}.reduce([], +).map{Double($0)}
B = stride(from: 0, through: 3, by: 1).map {[destination.corners[$0].x, destination.corners[$0].y]}.reduce([], +).map {Double($0)}
}
func testSolvePerspectiveCorrectness() {
@@ -92,7 +92,6 @@ class AccelerateSolvePerfTest: XCTestCase {
XCTAssertEqual(solution[7], 0, accuracy: accuracy)
}
func testSolvePerformance() {
preparePerspective()
measure {

View File

@@ -2,7 +2,7 @@ import Quick
import Nimble
import PerspectiveTransform
typealias Transformer = (CGRect,[CGPoint])->CATransform3D
typealias Transformer = (CGRect, [CGPoint]) -> CATransform3D
class CompareTransformSpecConfiguration: QuickConfiguration {
override class func configure(_ configuration: Configuration) {
@@ -13,7 +13,7 @@ class CompareTransformSpecConfiguration: QuickConfiguration {
CGPoint(x: 108.315837, y: 80.1687782),
CGPoint(x: 377.282671, y: 41.4352201),
CGPoint(x: 193.321418, y: 330.023027),
CGPoint(x: 459.781253, y: 251.836131),
CGPoint(x: 459.781253, y: 251.836131)
]
let frame = CGRect(origin: CGPoint.zero,
size: CGSize(width: 20, height: 10))
@@ -22,14 +22,14 @@ class CompareTransformSpecConfiguration: QuickConfiguration {
}
it("should be identity for same start and destination") {
let points = [CGPoint(x:0,y:0),CGPoint(x:20,y:0),CGPoint(x:0,y:10),CGPoint(x:20,y:10)]
let points = [CGPoint(x: 0, y: 0), CGPoint(x: 20, y: 0), CGPoint(x: 0, y: 10), CGPoint(x: 20, y: 10)]
let toItself = transformer.transform(frame: frame, points: points)
expect(toItself) CATransform3DIdentity
}
it("produce the same solution as algebraic method") {
let algebra = AlgebraMethod()
expect(transformer.transform(frame: frame, points: points)) algebra.transform(frame:frame, points:points)
expect(transformer.transform(frame: frame, points: points)) algebra.transform(frame: frame, points: points)
}
}
}

View File

@@ -16,7 +16,7 @@ extension CATransform3D {
m11, m12, m13, m14,
m21, m22, m23, m24,
m31, m32, m33, m34,
m41, m42, m43, m44,
m41, m42, m43, m44
]
}
}
@@ -48,8 +48,8 @@ public func beCloseTo(_ expectedValue: CGPoint, within delta: CGFloat = CGFloat(
if actual == expectedValue {
return .matches
} else {
let eachCoordinate = beCloseTo([expectedValue.x, expectedValue.y].map{Double($0)})
return try! eachCoordinate.satisfies(actualExpression.cast{[$0!.x,$0!.y].map{Double($0)}}).status
let eachCoordinate = beCloseTo([expectedValue.x, expectedValue.y].map {Double($0)})
return try! eachCoordinate.satisfies(actualExpression.cast {[$0!.x, $0!.y].map {Double($0)}}).status
}
}
return .doesNotMatch
@@ -70,7 +70,7 @@ extension CATransform3D: Equatable {
}
extension Int {
func times(block: ()->Void) {
func times(block: () -> Void) {
for _ in 1...self {
block()
}

View File

@@ -27,7 +27,7 @@ class PerformanceTest: XCTestCase {
CGPoint(x: 108.315837, y: 80.1687782),
CGPoint(x: 377.282671, y: 41.4352201),
CGPoint(x: 193.321418, y: 330.023027),
CGPoint(x: 459.781253, y: 251.836131),
CGPoint(x: 459.781253, y: 251.836131)
]
let destination = QuadrilateralCalc()
@@ -62,8 +62,8 @@ class PerformanceTest: XCTestCase {
}
private struct Path {
let start:Perspective
let destination:Perspective
let start: Perspective
let destination: Perspective
func performProjectiveTransform() {
_ = start.projectiveTransform(destination: destination)
@@ -74,7 +74,7 @@ class PerformanceTest: XCTestCase {
return Path(start: Perspective(startRect),
destination: Perspective(destinationRect))
}
private func repeatTransform(path: Path) {
repeatTimes.times {
path.performProjectiveTransform()

View File

@@ -51,7 +51,7 @@ public func ≈(lhs: Expectation<Vector3Type>, rhs: (expected: Vector3Type, delt
}
extension Matrix3x3Type {
init(_ array:[ScalarType]) {
init(_ array: [ScalarType]) {
let rows = 3
let scalars = rows * rows
precondition(array.count == scalars, "should have 9 values for 3x3 matrix")
@@ -81,8 +81,8 @@ extension Vector3Type {
var dehomogenized: CGPoint {return CGPoint(x: z.isZero ? 0 : x/z, y: z.isZero ? 0 : y/z)}
}
func arrayWith<S>(_ factory: (()->S)) -> [S] {
return Array(Vector3Type.indexSlice).map{_ in factory()}
func arrayWith<S>(_ factory: (() -> S)) -> [S] {
return Array(Vector3Type.indexSlice).map {_ in factory()}
}
extension GKRandomSource {

View File

@@ -18,7 +18,7 @@ public class QuadrilateralCalc {
return CGRect(origin: CGPoint(x: xmin, y: ymin), size: CGSize(width: xmax - xmin, height: ymax - ymin))
}
public func modifyPoints(transform:(CGPoint)->CGPoint) {
public func modifyPoints(transform: (CGPoint) -> CGPoint) {
topLeft = transform(topLeft)
topRight = transform(topRight)
bottomLeft = transform(bottomLeft)
@@ -87,13 +87,13 @@ public class QuadrilateralCalc {
let kEpsilon = CGFloat(0.0001)
if abs(i) < kEpsilon {
i = kEpsilon * (i > 0 ? 1.0 : -1.0);
i = kEpsilon * (i > 0 ? 1.0 : -1.0)
}
return CATransform3D(m11:a/i, m12:d/i, m13:0, m14:g/i,
m21:b/i, m22:e/i, m23:0, m24:h/i,
m31:0, m32:0, m33:1, m34:0,
m41:c/i, m42:f/i, m43:0, m44:1.0)
return CATransform3D(m11: a/i, m12: d/i, m13: 0, m14: g/i,
m21: b/i, m22: e/i, m23: 0, m24: h/i,
m31: 0, m32: 0, m33: 1, m34: 0,
m41: c/i, m42: f/i, m43: 0, m44: 1.0)
}
}

View File

@@ -9,8 +9,8 @@ class SnapshotSpec: QuickSpec {
let runningOnIphone5s = ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] == "iPhone 5s"
describe("overlay placement") {
var containerView : UIView!
var overlayView : UIView!
var containerView: UIView!
var overlayView: UIView!
func testImage(named imageName: String) -> UIImage {
return UIImage(named: imageName,
@@ -49,7 +49,7 @@ class SnapshotSpec: QuickSpec {
tolerance = 0.3
fputs("images compared on iPhone 5s with \(toleranceMessage())\n".uppercased(), __stderrp)
}
expect(containerView).to(haveValidSnapshot(usesDrawRect:true, tolerance:tolerance), description: "should match with \(toleranceMessage())")
expect(containerView).to(haveValidSnapshot(usesDrawRect: true, tolerance: tolerance), description: "should match with \(toleranceMessage())")
}
}
}

View File

@@ -11,10 +11,10 @@ import QuartzCore
extension CATransform3D {
init(_ m: Matrix4x4Type) {
self.init(
m11: CGFloat(m[0,0]), m12: CGFloat(m[0,1]), m13: CGFloat(m[0,2]), m14: CGFloat(m[0,3]),
m21: CGFloat(m[1,0]), m22: CGFloat(m[1,1]), m23: CGFloat(m[1,2]), m24: CGFloat(m[1,3]),
m31: CGFloat(m[2,0]), m32: CGFloat(m[2,1]), m33: CGFloat(m[2,2]), m34: CGFloat(m[2,3]),
m41: CGFloat(m[3,0]), m42: CGFloat(m[3,1]), m43: CGFloat(m[3,2]), m44: CGFloat(m[3,3])
m11: CGFloat(m[0, 0]), m12: CGFloat(m[0, 1]), m13: CGFloat(m[0, 2]), m14: CGFloat(m[0, 3]),
m21: CGFloat(m[1, 0]), m22: CGFloat(m[1, 1]), m23: CGFloat(m[1, 2]), m24: CGFloat(m[1, 3]),
m31: CGFloat(m[2, 0]), m32: CGFloat(m[2, 1]), m33: CGFloat(m[2, 2]), m34: CGFloat(m[2, 3]),
m41: CGFloat(m[3, 0]), m42: CGFloat(m[3, 1]), m43: CGFloat(m[3, 2]), m44: CGFloat(m[3, 3])
)
}
}

View File

@@ -9,7 +9,7 @@
import CoreGraphics
extension CGPoint {
var homogeneous3dvector : Vector3Type {
var homogeneous3dvector: Vector3Type {
return Vector3Type(ScalarType(x), ScalarType(y), ScalarType.one)
}
}

View File

@@ -21,16 +21,16 @@ extension ScalarType {
}
extension Matrix4x3Type {
static let zeroColumnBeforeLast : Matrix4x3Type = {
static let zeroColumnBeforeLast: Matrix4x3Type = {
let identity = Matrix3x3Type(diagonal: Vector3Type.one)
var columns = Vector3Type.indexArray.map{identity[$0]}
var columns = Vector3Type.indexArray.map {identity[$0]}
columns.insert(Vector3Type.zero, at: Vector3Type.lastIndex)
return Matrix4x3Type(columns)
}()
}
extension Matrix3x4Type {
static let zeroRowBeforeLast : Matrix3x4Type = {
static let zeroRowBeforeLast: Matrix3x4Type = {
return Matrix4x3Type.zeroColumnBeforeLast.transpose
}()
@@ -55,10 +55,8 @@ extension Matrix3x3Type {
}
private var normalizationFactor: ScalarType {
get {
let zScale = self[Vector3Type.lastIndex, Vector3Type.lastIndex]
assert(zScale.isZero == false, "since we use homogenized vectors, z != 0")
return ScalarType.one / zScale
}
let zScale = self[Vector3Type.lastIndex, Vector3Type.lastIndex]
assert(zScale.isZero == false, "since we use homogenized vectors, z != 0")
return ScalarType.one / zScale
}
}

View File

@@ -15,7 +15,7 @@ public extension Perspective {
- parameter bottomLeft: bottom left corner
- parameter bottomRight: bottom right corner
*/
public convenience init(_ topLeft:CGPoint, _ topRight:CGPoint, _ bottomLeft:CGPoint, _ bottomRight:CGPoint) {
public convenience init(_ topLeft: CGPoint, _ topRight: CGPoint, _ bottomLeft: CGPoint, _ bottomRight: CGPoint) {
self.init(Quadrilateral(topLeft, topRight, bottomLeft, bottomRight))
}
/**
@@ -23,7 +23,7 @@ public extension Perspective {
- parameter points: corner points, must be size 4
*/
public convenience init(_ points:[CGPoint]) {
public convenience init(_ points: [CGPoint]) {
self.init(Quadrilateral(points))
}
/**
@@ -31,7 +31,7 @@ public extension Perspective {
- parameter rect: defines the corners
*/
public convenience init(_ rect:CGRect) {
public convenience init(_ rect: CGRect) {
self.init(Quadrilateral(rect))
}
@@ -41,7 +41,7 @@ public extension Perspective {
- parameter destination: perspective to transform to
- returns: tranformation matrix from this perspective to destination
*/
public func projectiveTransform(destination:Perspective) -> CATransform3D {
public func projectiveTransform(destination: Perspective) -> CATransform3D {
return CATransform3D(projection(to: destination).to3d())
}
}

View File

@@ -12,17 +12,17 @@ import simd
3D Perspective represented on 2D by 4 corners polygon
*/
public final class Perspective {
let vectors : [Vector3Type]
let vectors: [Vector3Type]
init(_ q: Quadrilateral) {
vectors = q.corners.map{$0.homogeneous3dvector}
init(_ quad: Quadrilateral) {
vectors = quad.corners.map {$0.homogeneous3dvector}
}
internal lazy var basisVectorsToPointsMap = calculateBasisVectorsToPointsMap()
internal lazy var pointsToBasisVectorsMap = basisVectorsToPointsMap.inverse
internal func projection(to:Perspective) -> Matrix3x3Type {
return to.basisVectorsToPointsMap * pointsToBasisVectorsMap
internal func projection(to destination: Perspective) -> Matrix3x3Type {
return destination.basisVectorsToPointsMap * pointsToBasisVectorsMap
}
private func calculateBasisVectorsToPointsMap() -> Matrix3x3Type {

View File

@@ -9,27 +9,27 @@
import CoreGraphics
final class Quadrilateral {
var corners : [CGPoint] {
var corners: [CGPoint] {
return [topLeft, topRight, bottomLeft, bottomRight]
}
private let topLeft: CGPoint
private let topRight: CGPoint
private let bottomLeft: CGPoint
private let bottomRight: CGPoint
init(_ topLeft:CGPoint, _ topRight:CGPoint, _ bottomLeft:CGPoint, _ bottomRight:CGPoint) {
init(_ topLeft: CGPoint, _ topRight: CGPoint, _ bottomLeft: CGPoint, _ bottomRight: CGPoint) {
self.topLeft = topLeft
self.topRight = topRight
self.bottomLeft = bottomLeft
self.bottomRight = bottomRight
}
convenience init(_ points:[CGPoint]) {
convenience init(_ points: [CGPoint]) {
self.init(points[0], points[1], points[2], points[3])
}
convenience init(_ origin:CGPoint, _ size:CGSize) {
convenience init(_ origin: CGPoint, _ size: CGSize) {
let stayPut = CGAffineTransform.identity
let shiftRight = CGAffineTransform(translationX: size.width, y: 0)
let shiftDown = CGAffineTransform(translationX: 0, y: size.height)
@@ -43,7 +43,7 @@ final class Quadrilateral {
self.init(originToCornerTransform.map{origin.applying($0)})
}
convenience init(_ rect:CGRect) {
convenience init(_ rect: CGRect) {
self.init(rect.origin, rect.size)
}
}