mirror of
https://github.com/zhigang1992/PerspectiveTransform.git
synced 2026-01-12 09:14:11 +08:00
lint
This commit is contained in:
@@ -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
3
.swiftlint.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
excluded:
|
||||
- Carthage
|
||||
- Pods
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -43,4 +43,3 @@ public extension CATransform3D {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -67,8 +67,6 @@ class CALayerTransformSpec: QuickSpec {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -205,7 +205,6 @@ class ProjectionSpec: QuickSpec {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
context("affine 2D") {
|
||||
var scale2D: CGAffineTransform!
|
||||
var translate2D: CGAffineTransform!
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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())")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import CoreGraphics
|
||||
|
||||
extension CGPoint {
|
||||
var homogeneous3dvector : Vector3Type {
|
||||
var homogeneous3dvector: Vector3Type {
|
||||
return Vector3Type(ScalarType(x), ScalarType(y), ScalarType.one)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user