{"id":24169783,"url":"https://github.com/paulz/perspectivetransform","last_synced_at":"2025-05-09T00:05:03.014Z","repository":{"id":4333482,"uuid":"52354538","full_name":"paulz/PerspectiveTransform","owner":"paulz","description":"Calculate CATransform3D between two Perspectives","archived":false,"fork":false,"pushed_at":"2023-01-25T13:08:48.000Z","size":15171,"stargazers_count":172,"open_issues_count":11,"forks_count":15,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-09T00:04:54.768Z","etag":null,"topics":["3d-graphics","agumentedreality","animation","catransform3d","matrix","perspective","polygon","swift","xcode"],"latest_commit_sha":null,"homepage":"https://cocoapods.org/pods/PerspectiveTransform","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paulz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-02-23T11:37:57.000Z","updated_at":"2025-04-28T02:55:44.000Z","dependencies_parsed_at":"2023-02-14T07:45:58.453Z","dependency_job_id":null,"html_url":"https://github.com/paulz/PerspectiveTransform","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulz%2FPerspectiveTransform","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulz%2FPerspectiveTransform/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulz%2FPerspectiveTransform/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulz%2FPerspectiveTransform/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paulz","download_url":"https://codeload.github.com/paulz/PerspectiveTransform/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253166514,"owners_count":21864475,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3d-graphics","agumentedreality","animation","catransform3d","matrix","perspective","polygon","swift","xcode"],"created_at":"2025-01-12T23:14:44.302Z","updated_at":"2025-05-09T00:05:02.967Z","avatar_url":"https://github.com/paulz.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Perspective Transform\n\n[![macOS](https://github.com/paulz/PerspectiveTransform/workflows/macOS/badge.svg)](https://github.com/paulz/PerspectiveTransform/actions?query=workflow%3AmacOS)\n[![iOS](https://github.com/paulz/PerspectiveTransform/workflows/iOS/badge.svg)](https://github.com/paulz/PerspectiveTransform/actions?query=workflow%3AiOS)\n[![codecov](https://codecov.io/gh/paulz/PerspectiveTransform/branch/master/graph/badge.svg)](https://codecov.io/gh/paulz/PerspectiveTransform)\n[![Version](https://img.shields.io/cocoapods/v/PerspectiveTransform.svg?style=flat)](http://cocoapods.org/pods/PerspectiveTransform)\n[![License](https://img.shields.io/cocoapods/l/PerspectiveTransform.svg?style=flat)](http://cocoapods.org/pods/PerspectiveTransform)\n[![Platform](https://img.shields.io/cocoapods/p/PerspectiveTransform.svg?style=flat)](http://cocoapods.org/pods/PerspectiveTransform)\n[![Carthage compatible][carthage-badge]](https://github.com/Carthage/Carthage)\n[![Swift][swift-badge]][swift-url]\n\n\nPerspectiveTransform caclulates homogeneous transformation matrix for a view 3D projection in 2D. It can be used to place views within given image visual perspective using Core Animation `CATransform3D` and [`CALayer.tranform`](https://developer.apple.com/documentation/quartzcore/calayer/1410836-transform). Projection is caclulated between source and destination perspectives that are defined by 4 corners, assuming they form a [Quadrilateral](https://en.wikipedia.org/wiki/Quadrilateral).\n\n## [CATransform3D](https://developer.apple.com/documentation/quartzcore/catransform3d)\n\nTo place an overlay image on top of a container image with matching persperctive we can use Core Animation transform matrix. `CATransform3D` is a tranformation matrix that is used to rotate, scale, translate, skew, and project the layer content. It can also be used to describe a perspective projectection of 2D shape in 3D space.\n\n| Container  | Overlay | Combination |\n| ------------- | ------------- | --- |\n| \u003cimg src=\"https://raw.githubusercontent.com/paulz/PerspectiveTransform/master/Example/Tests/container.jpg\" alt=\"Container\"/\u003e  | \u003cimg src=\"https://raw.githubusercontent.com/paulz/PerspectiveTransform/master/Example/Tests/sky.jpg\" alt=\"Overlay\"/\u003e  | \u003cimg src=\"https://github.com/paulz/PerspectiveTransform/wiki/images/withOverlay-example.png\" alt=\"Combined image\"/\u003e |\n\nCore Animation allow applying `CATransform3D` to `CALayer` via `transform` property:\n\n```swift\nlet layer = UIView().layer\nlayer.transform = CATransform3D(m11: sX,  m12: r12, m13: r13, m14: 0,\n                                m21: r21, m22: sY,  m23: r23, m24: 0,\n                                m31: r31, m32: r32, m33: 0,   m34: 0,\n                                m41: tX,  m42: tY,  m43: 0,   m44: 1)\n```\nIn detail `CATransform3D` is a 4 x 4 matrix which takes 16 parameters to build.\n\nTranslation and scale are represented by their axis components: (tX, tY) and (sX, sY) within the matrix.  While 3D rotation is represented by multiple values: r12, r21, r13, r31, r32, r23.\n\n## Perspective Transform based on 4 corners\n\nWe can easily see 4 points with container image where the corners of the overlay image should be. In general it is a 4 point polygon. Using an SVG editor we can draw that polygon using container image as a background. Here is preview of the SVG file desribing placement of iPad screen corners\n\n[\u003cimg src=\"https://github.com/paulz/PerspectiveTransform/blob/master/Example/Tests/with-overlay.svg\" alt=\"SVG polygon\"  width=\"50%\"/\u003e](https://github.com/paulz/PerspectiveTransform/blob/master/Example/Tests/with-overlay.svg)\n\nClick image to see original SVG file defining `polygon` with `points`. From those 4 points we can calculate nessesary `CATransform3D` matrix using this `PerspectiveTransform` library.\n\n## Visual Example\n\nWe can see how 4 points polygon fits on the background image:\n\n\u003cimg src=\"https://github.com/paulz/PerspectiveTransform/wiki/images/container-with-green-polygon.png\" alt=\"SVG polygon\" width=50%/\u003e\n\n### SVG Points\nWe can even take coordinates of those 4 points from SVG file:\n\n```xml\n\u003cpolygon points=\"377.282671 41.4352201 459.781253 251.836131 193.321418 330.023027 108.315837 80.1687782 \"\u003e\u003c/polygon\u003e\n```\n\nThose are 4 pairs of X and Y coordinates:\n\n```\n377.282671 41.4352201\n459.781253 251.836131\n193.321418 330.023027\n108.315837 80.1687782\n```\n### Swift Code Example\nHere is complete example of placing overlay view using those coordinates:\n\n```swift\nimport PerspectiveTransform\n\n// note order: top left, top right, bottom left, bottom right\nlet destination = Perspective(\n    CGPoint(x: 108.315837, y: 80.1687782),\n    CGPoint(x: 377.282671, y: 41.4352201),\n    CGPoint(x: 193.321418, y: 330.023027),\n    CGPoint(x: 459.781253, y: 251.836131)\n)\n\n// Starting perspective is the current overlay frame\nlet start = Perspective(overlayView.frame)\n\n// Caclulate CATransform3D from start to destination\noverlayView.layer.transform = start.projectiveTransform(destination: destination)\n\n```\n\n### `CALayer` transform\nSince `CALayer` transform is animatable property we can easily define smooth transition:\n\n\u003cimg src=\"https://github.com/paulz/PerspectiveTransform/wiki/images/perspective-transform-animated.gif\" alt=\"SVG polygon\" width=50%/\u003e\n\n\n## Example Project\n\nSee [Example iOS project](https://github.com/paulz/PerspectiveTransform/tree/master/Example) illustating animation and interactive tranform within view controllers. To build Example project run `pod install` within Example folder.\n\nExample project also includes [Swift Playground](https://github.com/paulz/PerspectiveTransform/tree/master/Example/PerspectiveTransform/Visual.playground) with couple of live examples.\n\n\n## Installation\n\nPerspectiveTransform is available through [CocoaPods](http://cocoapods.org). To install\nit, simply add the following line to your Podfile:\n\n```ruby\npod 'PerspectiveTransform'\n```\n\n### Useful Links\n * [Explaining Homogeneous Coordinates \u0026 Projective Geometry](https://www.tomdalling.com/blog/modern-opengl/explaining-homogenous-coordinates-and-projective-geometry/)\n\n## Author\n\nPaul Zabelin, http://github.com/paulz\n\n## License\n\nPerspectiveTransform is available under the MIT license. See the LICENSE file for more info.\n\n[swift-badge]: https://img.shields.io/badge/Swift-5.0-orange.svg?style=flat\n[swift-url]: https://swift.org\n[carthage-badge]: https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulz%2Fperspectivetransform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaulz%2Fperspectivetransform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulz%2Fperspectivetransform/lists"}