├── art
├── logo.png
└── pizzas.png
├── ARSlicer
├── Assets.xcassets
│ ├── Contents.json
│ ├── pizza-1.imageset
│ │ ├── pizza-1.png
│ │ └── Contents.json
│ ├── pizza-2.imageset
│ │ ├── pizza-2.png
│ │ └── Contents.json
│ ├── pizza-3.imageset
│ │ ├── pizza-3.png
│ │ └── Contents.json
│ ├── pizza-4.imageset
│ │ ├── pizza-4.png
│ │ └── Contents.json
│ ├── pizza-5.imageset
│ │ ├── pizza-5.png
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── icon@2x.png
│ │ ├── icon@3x.png
│ │ └── Contents.json
│ ├── logosmall.imageset
│ │ ├── logosmall.png
│ │ └── Contents.json
│ ├── pizza-1-small.imageset
│ │ ├── pizza-1-small.png
│ │ └── Contents.json
│ ├── pizza-2-small.imageset
│ │ ├── pizza-2-small.png
│ │ └── Contents.json
│ ├── pizza-3-small.imageset
│ │ ├── pizza-3-small.png
│ │ └── Contents.json
│ ├── pizza-4-small.imageset
│ │ ├── pizza-4-small.png
│ │ └── Contents.json
│ └── pizza-5-small.imageset
│ │ ├── pizza-5-small.png
│ │ └── Contents.json
├── art.scnassets
│ └── plane.scn
├── AppDelegate.swift
├── Info.plist
├── GyroManager.swift
├── Cell.swift
├── Collection.swift
├── Base.lproj
│ └── LaunchScreen.storyboard
└── ViewController.swift
├── ARSlicer.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── project.pbxproj
├── .gitignore
└── README.md
/art/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/art/logo.png
--------------------------------------------------------------------------------
/art/pizzas.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/art/pizzas.png
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/ARSlicer/art.scnassets/plane.scn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/ARSlicer/art.scnassets/plane.scn
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-1.imageset/pizza-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/ARSlicer/Assets.xcassets/pizza-1.imageset/pizza-1.png
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-2.imageset/pizza-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/ARSlicer/Assets.xcassets/pizza-2.imageset/pizza-2.png
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-3.imageset/pizza-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/ARSlicer/Assets.xcassets/pizza-3.imageset/pizza-3.png
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-4.imageset/pizza-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/ARSlicer/Assets.xcassets/pizza-4.imageset/pizza-4.png
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-5.imageset/pizza-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/ARSlicer/Assets.xcassets/pizza-5.imageset/pizza-5.png
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/AppIcon.appiconset/icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/ARSlicer/Assets.xcassets/AppIcon.appiconset/icon@2x.png
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/AppIcon.appiconset/icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/ARSlicer/Assets.xcassets/AppIcon.appiconset/icon@3x.png
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/logosmall.imageset/logosmall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/ARSlicer/Assets.xcassets/logosmall.imageset/logosmall.png
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-1-small.imageset/pizza-1-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/ARSlicer/Assets.xcassets/pizza-1-small.imageset/pizza-1-small.png
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-2-small.imageset/pizza-2-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/ARSlicer/Assets.xcassets/pizza-2-small.imageset/pizza-2-small.png
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-3-small.imageset/pizza-3-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/ARSlicer/Assets.xcassets/pizza-3-small.imageset/pizza-3-small.png
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-4-small.imageset/pizza-4-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/ARSlicer/Assets.xcassets/pizza-4-small.imageset/pizza-4-small.png
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-5-small.imageset/pizza-5-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roberthein/AR-Pizza-Slicer/HEAD/ARSlicer/Assets.xcassets/pizza-5-small.imageset/pizza-5-small.png
--------------------------------------------------------------------------------
/ARSlicer.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ARSlicer.xcodeproj/project.xcworkspace/xcuserdata/roberthein.xcuserdatad/UserInterfaceState.xcuserstate
2 | ARSlicer.xcodeproj/xcuserdata/roberthein.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
3 | ARSlicer.xcodeproj/xcuserdata/roberthein.xcuserdatad/xcschemes/ARSlicer.xcscheme
4 | ARSlicer.xcodeproj/xcuserdata/roberthein.xcuserdatad/xcschemes/xcschememanagement.plist
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | Let Augmented Reality help you to create a perfect sliced pizza in 5 different shapes!
4 |
5 | 
6 |
7 | ## Suggestions or feedback?
8 |
9 | Feel free to create a pull request, open an issue or find me [on Twitter](https://twitter.com/roberthein).
10 |
11 | Inspiration: [link](http://gizmodo.com/mathematicians-have-found-crazy-new-ways-to-cut-pizza-i-1751776752)
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "pizza-1.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "pizza-2.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "pizza-3.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "pizza-4.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "pizza-5.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/logosmall.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "logosmall.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-1-small.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "pizza-1-small.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-2-small.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "pizza-2-small.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-3-small.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "pizza-3-small.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-4-small.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "pizza-4-small.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/pizza-5-small.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "pizza-5-small.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/ARSlicer/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | @UIApplicationMain
4 | class AppDelegate: UIResponder, UIApplicationDelegate {
5 |
6 | var window: UIWindow?
7 |
8 |
9 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
10 |
11 | let viewController = ViewController()
12 |
13 | window = UIWindow(frame: UIScreen.main.bounds)
14 | window?.rootViewController = viewController
15 | window?.makeKeyAndVisible()
16 |
17 | return true
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/ARSlicer/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "60x60",
35 | "idiom" : "iphone",
36 | "filename" : "icon@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "icon@3x.png",
43 | "scale" : "3x"
44 | }
45 | ],
46 | "info" : {
47 | "version" : 1,
48 | "author" : "xcode"
49 | }
50 | }
--------------------------------------------------------------------------------
/ARSlicer/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | NSCameraUsageDescription
24 | can I please use your camera PLEASE!!
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UIStatusBarHidden
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/ARSlicer/GyroManager.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import CoreMotion
3 | import SceneKit
4 |
5 | protocol GyroManagerDelegate {
6 | func update(rotation: SCNVector3)
7 | }
8 |
9 | class GyroManager {
10 |
11 | var delegate: GyroManagerDelegate?
12 | let manager = CMMotionManager()
13 |
14 | var rotation: SCNVector3 = SCNVector3(0, 0, 0) {
15 | didSet{
16 | delegate?.update(rotation: rotation)
17 | }
18 | }
19 |
20 | init() {
21 | manager.stopGyroUpdates()
22 | if manager.isGyroAvailable {
23 | manager.gyroUpdateInterval = 0.01
24 | manager.startGyroUpdates()
25 |
26 | let queue = OperationQueue.main
27 | manager.startGyroUpdates(to: queue) { data, error in
28 |
29 | if self.manager.isDeviceMotionAvailable {
30 | self.manager.deviceMotionUpdateInterval = 0.01
31 |
32 | self.manager.startDeviceMotionUpdates(to: OperationQueue.main) {data, error in
33 | guard let data = data else { return }
34 | let vertical = atan2(data.gravity.y, data.gravity.z) - Double.pi
35 | self.rotation = SCNVector3(vertical, 0, 0)
36 | }
37 | }
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/ARSlicer/Cell.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import UIKit
3 |
4 | class Cell: UICollectionViewCell {
5 |
6 | lazy var imageView: UIImageView = {
7 | let view = UIImageView()
8 | view.translatesAutoresizingMaskIntoConstraints = false
9 | view.contentMode = .scaleAspectFit
10 | return view
11 | }()
12 |
13 | lazy var label: UILabel = {
14 | let view = UILabel()
15 | view.translatesAutoresizingMaskIntoConstraints = false
16 | view.font = UIFont.boldSystemFont(ofSize: 30)
17 | view.textColor = .white
18 | view.textAlignment = .center
19 | return view
20 | }()
21 |
22 | required init?(coder aDecoder: NSCoder) {
23 | fatalError("init(coder:) has not been implemented")
24 | }
25 |
26 | override init(frame: CGRect) {
27 | super.init(frame: frame)
28 |
29 | contentView.addSubview(imageView)
30 |
31 | NSLayoutConstraint.activate([
32 | imageView.heightAnchor.constraint(equalToConstant: 100),
33 | imageView.leftAnchor.constraint(equalTo: contentView.leftAnchor),
34 | imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10),
35 | imageView.rightAnchor.constraint(equalTo: contentView.rightAnchor),
36 | ])
37 |
38 | contentView.addSubview(label)
39 |
40 | NSLayoutConstraint.activate([
41 | label.heightAnchor.constraint(equalToConstant: 100),
42 | label.leftAnchor.constraint(equalTo: contentView.leftAnchor),
43 | label.topAnchor.constraint(equalTo: contentView.topAnchor),
44 | label.rightAnchor.constraint(equalTo: contentView.rightAnchor),
45 | ])
46 | }
47 |
48 | var shape: Shape? = nil {
49 | didSet {
50 | guard let shape = shape else { return }
51 | imageView.image = UIImage(named: "\(shape.imageName)-small")
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/ARSlicer/Collection.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import UIKit
3 |
4 | struct Shape {
5 | let name: String
6 | let imageName: String
7 | }
8 |
9 | protocol CollectionIndexDelegate {
10 | func didScroll(to shape: Shape)
11 | }
12 |
13 | class Collection: UICollectionView {
14 |
15 | var indexDelegate: CollectionIndexDelegate?
16 |
17 | let shapes = [
18 | Shape(name: "1", imageName: "pizza-1"),
19 | Shape(name: "2", imageName: "pizza-2"),
20 | Shape(name: "3", imageName: "pizza-3"),
21 | Shape(name: "4", imageName: "pizza-4"),
22 | Shape(name: "5", imageName: "pizza-5")]
23 |
24 | required init?(coder aDecoder: NSCoder) {
25 | fatalError("init(coder:) has not been implemented")
26 | }
27 |
28 | override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
29 | super.init(frame: frame, collectionViewLayout: layout)
30 | dataSource = self
31 | delegate = self
32 | alwaysBounceHorizontal = true
33 | backgroundColor = nil
34 | isOpaque = false
35 | isPagingEnabled = true
36 |
37 | register(Cell.self, forCellWithReuseIdentifier: "cell")
38 | }
39 | }
40 |
41 | extension Collection: UICollectionViewDataSource {
42 |
43 | func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
44 | guard let cell = cell as? Cell else { return }
45 | cell.shape = shapes[indexPath.row]
46 | }
47 |
48 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
49 | return shapes.count
50 | }
51 |
52 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
53 | return collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
54 | }
55 | }
56 |
57 |
58 | extension Collection: UICollectionViewDelegate {
59 |
60 | func scrollViewDidScroll(_ scrollView: UIScrollView) {
61 | update()
62 | }
63 |
64 | func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
65 |
66 | if !decelerate {
67 | update()
68 | }
69 | }
70 |
71 | func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
72 | update()
73 | }
74 |
75 | func update() {
76 | let index: Int = Int(round(contentOffset.x / frame.width))
77 | indexDelegate?.didScroll(to: shapes[index])
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/ARSlicer/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/ARSlicer/ViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import QuartzCore
3 | import SceneKit
4 | import AVFoundation
5 |
6 | class ViewController: UIViewController {
7 |
8 | let scene = SCNScene()
9 | var collection: Collection!
10 |
11 | override func viewDidLoad() {
12 | super.viewDidLoad()
13 |
14 | let gyro = GyroManager()
15 | gyro.delegate = self
16 |
17 | let captureSession = AVCaptureSession()
18 | guard let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) else { return }
19 | previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
20 |
21 | do {
22 | let captureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
23 | let input = try AVCaptureDeviceInput(device: captureDevice)
24 |
25 | if (captureSession.canAddInput(input as AVCaptureInput)) {
26 | captureSession.addInput(input as AVCaptureDeviceInput)
27 | }
28 |
29 | } catch let error as NSError {
30 | print(error)
31 | }
32 |
33 | captureSession.startRunning()
34 |
35 | previewLayer.frame = self.view.bounds
36 | view.layer.addSublayer(previewLayer)
37 |
38 | let cameraNode = SCNNode()
39 | cameraNode.camera = SCNCamera()
40 | scene.rootNode.addChildNode(cameraNode)
41 | cameraNode.position = SCNVector3(x: 0, y: 0, z: 12)
42 |
43 | let scnView = SCNView()
44 | scnView.frame = self.view.bounds
45 | scnView.backgroundColor = UIColor.clear
46 | previewLayer.frame = self.view.bounds
47 | self.view.addSubview(scnView)
48 |
49 | guard let plane = SCNScene(named: "art.scnassets/plane.scn")?.rootNode.childNode(withName: "plane", recursively: true) else { return }
50 |
51 | scnView.autoenablesDefaultLighting = true
52 | scnView.allowsCameraControl = false
53 | scene.rootNode.addChildNode(plane)
54 | scnView.scene = scene
55 |
56 | let layout = UICollectionViewFlowLayout()
57 | layout.itemSize = view.bounds.size
58 | layout.scrollDirection = .horizontal
59 | layout.minimumLineSpacing = 0
60 | layout.minimumInteritemSpacing = 0
61 |
62 | collection = Collection(frame: view.bounds, collectionViewLayout: layout)
63 | collection.indexDelegate = self
64 | view.addSubview(collection)
65 | }
66 |
67 | override var prefersStatusBarHidden: Bool {
68 | return true
69 | }
70 |
71 | override func viewWillAppear(_ animated: Bool) {
72 | super.viewWillAppear(animated)
73 | collection.update()
74 | }
75 | }
76 |
77 | extension ViewController: GyroManagerDelegate {
78 |
79 | func update(rotation: SCNVector3) {
80 | let plane = scene.rootNode.childNode(withName: "plane", recursively: true)
81 | plane?.runAction(SCNAction.rotateTo(x: CGFloat(rotation.x) + CGFloat(Double.pi), y: 0, z: CGFloat(Double.pi), duration: 0.1))
82 | }
83 | }
84 |
85 | extension ViewController: CollectionIndexDelegate {
86 |
87 | func didScroll(to shape: Shape) {
88 | guard let plane = scene.rootNode.childNode(withName: "plane", recursively: true) else { return }
89 |
90 | if let material = plane.geometry?.materials.first {
91 | let image = UIImage(named: shape.imageName)
92 | material.diffuse.contents = image
93 | material.selfIllumination.contents = UIColor.white
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/ARSlicer.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | A927BB171EBE0C5000E2AEAA /* Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = A927BB161EBE0C5000E2AEAA /* Collection.swift */; };
11 | A927BB191EBE131000E2AEAA /* Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A927BB181EBE131000E2AEAA /* Cell.swift */; };
12 | A927BB1B1EBE285A00E2AEAA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A927BB1A1EBE285A00E2AEAA /* Assets.xcassets */; };
13 | A94094941EBDD80500203841 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A94094931EBDD80500203841 /* AppDelegate.swift */; };
14 | A94094961EBDD80500203841 /* art.scnassets in Resources */ = {isa = PBXBuildFile; fileRef = A94094951EBDD80500203841 /* art.scnassets */; };
15 | A94094981EBDD80500203841 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A94094971EBDD80500203841 /* ViewController.swift */; };
16 | A94094A01EBDD80500203841 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A940949E1EBDD80500203841 /* LaunchScreen.storyboard */; };
17 | A9719F831EBDDBB4001D668F /* GyroManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9719F821EBDDBB4001D668F /* GyroManager.swift */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXFileReference section */
21 | A927BB161EBE0C5000E2AEAA /* Collection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Collection.swift; sourceTree = ""; };
22 | A927BB181EBE131000E2AEAA /* Cell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cell.swift; sourceTree = ""; };
23 | A927BB1A1EBE285A00E2AEAA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
24 | A94094901EBDD80500203841 /* ARSlicer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ARSlicer.app; sourceTree = BUILT_PRODUCTS_DIR; };
25 | A94094931EBDD80500203841 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
26 | A94094951EBDD80500203841 /* art.scnassets */ = {isa = PBXFileReference; lastKnownFileType = wrapper.scnassets; path = art.scnassets; sourceTree = ""; };
27 | A94094971EBDD80500203841 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
28 | A940949F1EBDD80500203841 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
29 | A94094A11EBDD80500203841 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
30 | A9719F821EBDDBB4001D668F /* GyroManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GyroManager.swift; sourceTree = ""; };
31 | /* End PBXFileReference section */
32 |
33 | /* Begin PBXFrameworksBuildPhase section */
34 | A940948D1EBDD80500203841 /* Frameworks */ = {
35 | isa = PBXFrameworksBuildPhase;
36 | buildActionMask = 2147483647;
37 | files = (
38 | );
39 | runOnlyForDeploymentPostprocessing = 0;
40 | };
41 | /* End PBXFrameworksBuildPhase section */
42 |
43 | /* Begin PBXGroup section */
44 | A94094871EBDD80500203841 = {
45 | isa = PBXGroup;
46 | children = (
47 | A94094921EBDD80500203841 /* ARSlicer */,
48 | A94094911EBDD80500203841 /* Products */,
49 | );
50 | sourceTree = "";
51 | };
52 | A94094911EBDD80500203841 /* Products */ = {
53 | isa = PBXGroup;
54 | children = (
55 | A94094901EBDD80500203841 /* ARSlicer.app */,
56 | );
57 | name = Products;
58 | sourceTree = "";
59 | };
60 | A94094921EBDD80500203841 /* ARSlicer */ = {
61 | isa = PBXGroup;
62 | children = (
63 | A94094931EBDD80500203841 /* AppDelegate.swift */,
64 | A94094971EBDD80500203841 /* ViewController.swift */,
65 | A9719F821EBDDBB4001D668F /* GyroManager.swift */,
66 | A927BB161EBE0C5000E2AEAA /* Collection.swift */,
67 | A927BB181EBE131000E2AEAA /* Cell.swift */,
68 | A940949E1EBDD80500203841 /* LaunchScreen.storyboard */,
69 | A94094A11EBDD80500203841 /* Info.plist */,
70 | A927BB1A1EBE285A00E2AEAA /* Assets.xcassets */,
71 | A94094951EBDD80500203841 /* art.scnassets */,
72 | );
73 | path = ARSlicer;
74 | sourceTree = "";
75 | };
76 | /* End PBXGroup section */
77 |
78 | /* Begin PBXNativeTarget section */
79 | A940948F1EBDD80500203841 /* ARSlicer */ = {
80 | isa = PBXNativeTarget;
81 | buildConfigurationList = A94094A41EBDD80500203841 /* Build configuration list for PBXNativeTarget "ARSlicer" */;
82 | buildPhases = (
83 | A940948C1EBDD80500203841 /* Sources */,
84 | A940948D1EBDD80500203841 /* Frameworks */,
85 | A940948E1EBDD80500203841 /* Resources */,
86 | );
87 | buildRules = (
88 | );
89 | dependencies = (
90 | );
91 | name = ARSlicer;
92 | productName = ARSlicer;
93 | productReference = A94094901EBDD80500203841 /* ARSlicer.app */;
94 | productType = "com.apple.product-type.application";
95 | };
96 | /* End PBXNativeTarget section */
97 |
98 | /* Begin PBXProject section */
99 | A94094881EBDD80500203841 /* Project object */ = {
100 | isa = PBXProject;
101 | attributes = {
102 | LastSwiftUpdateCheck = 0830;
103 | LastUpgradeCheck = 0830;
104 | ORGANIZATIONNAME = "Robert-Hein Hooijmans";
105 | TargetAttributes = {
106 | A940948F1EBDD80500203841 = {
107 | CreatedOnToolsVersion = 8.3.2;
108 | DevelopmentTeam = 29X3GG489T;
109 | ProvisioningStyle = Automatic;
110 | };
111 | };
112 | };
113 | buildConfigurationList = A940948B1EBDD80500203841 /* Build configuration list for PBXProject "ARSlicer" */;
114 | compatibilityVersion = "Xcode 3.2";
115 | developmentRegion = English;
116 | hasScannedForEncodings = 0;
117 | knownRegions = (
118 | en,
119 | Base,
120 | );
121 | mainGroup = A94094871EBDD80500203841;
122 | productRefGroup = A94094911EBDD80500203841 /* Products */;
123 | projectDirPath = "";
124 | projectRoot = "";
125 | targets = (
126 | A940948F1EBDD80500203841 /* ARSlicer */,
127 | );
128 | };
129 | /* End PBXProject section */
130 |
131 | /* Begin PBXResourcesBuildPhase section */
132 | A940948E1EBDD80500203841 /* Resources */ = {
133 | isa = PBXResourcesBuildPhase;
134 | buildActionMask = 2147483647;
135 | files = (
136 | A94094961EBDD80500203841 /* art.scnassets in Resources */,
137 | A927BB1B1EBE285A00E2AEAA /* Assets.xcassets in Resources */,
138 | A94094A01EBDD80500203841 /* LaunchScreen.storyboard in Resources */,
139 | );
140 | runOnlyForDeploymentPostprocessing = 0;
141 | };
142 | /* End PBXResourcesBuildPhase section */
143 |
144 | /* Begin PBXSourcesBuildPhase section */
145 | A940948C1EBDD80500203841 /* Sources */ = {
146 | isa = PBXSourcesBuildPhase;
147 | buildActionMask = 2147483647;
148 | files = (
149 | A94094981EBDD80500203841 /* ViewController.swift in Sources */,
150 | A9719F831EBDDBB4001D668F /* GyroManager.swift in Sources */,
151 | A927BB191EBE131000E2AEAA /* Cell.swift in Sources */,
152 | A94094941EBDD80500203841 /* AppDelegate.swift in Sources */,
153 | A927BB171EBE0C5000E2AEAA /* Collection.swift in Sources */,
154 | );
155 | runOnlyForDeploymentPostprocessing = 0;
156 | };
157 | /* End PBXSourcesBuildPhase section */
158 |
159 | /* Begin PBXVariantGroup section */
160 | A940949E1EBDD80500203841 /* LaunchScreen.storyboard */ = {
161 | isa = PBXVariantGroup;
162 | children = (
163 | A940949F1EBDD80500203841 /* Base */,
164 | );
165 | name = LaunchScreen.storyboard;
166 | sourceTree = "";
167 | };
168 | /* End PBXVariantGroup section */
169 |
170 | /* Begin XCBuildConfiguration section */
171 | A94094A21EBDD80500203841 /* Debug */ = {
172 | isa = XCBuildConfiguration;
173 | buildSettings = {
174 | ALWAYS_SEARCH_USER_PATHS = NO;
175 | CLANG_ANALYZER_NONNULL = YES;
176 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
177 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
178 | CLANG_CXX_LIBRARY = "libc++";
179 | CLANG_ENABLE_MODULES = YES;
180 | CLANG_ENABLE_OBJC_ARC = YES;
181 | CLANG_WARN_BOOL_CONVERSION = YES;
182 | CLANG_WARN_CONSTANT_CONVERSION = YES;
183 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
184 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
185 | CLANG_WARN_EMPTY_BODY = YES;
186 | CLANG_WARN_ENUM_CONVERSION = YES;
187 | CLANG_WARN_INFINITE_RECURSION = YES;
188 | CLANG_WARN_INT_CONVERSION = YES;
189 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
190 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
191 | CLANG_WARN_UNREACHABLE_CODE = YES;
192 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
193 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
194 | COPY_PHASE_STRIP = NO;
195 | DEBUG_INFORMATION_FORMAT = dwarf;
196 | ENABLE_STRICT_OBJC_MSGSEND = YES;
197 | ENABLE_TESTABILITY = YES;
198 | GCC_C_LANGUAGE_STANDARD = gnu99;
199 | GCC_DYNAMIC_NO_PIC = NO;
200 | GCC_NO_COMMON_BLOCKS = YES;
201 | GCC_OPTIMIZATION_LEVEL = 0;
202 | GCC_PREPROCESSOR_DEFINITIONS = (
203 | "DEBUG=1",
204 | "$(inherited)",
205 | );
206 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
207 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
208 | GCC_WARN_UNDECLARED_SELECTOR = YES;
209 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
210 | GCC_WARN_UNUSED_FUNCTION = YES;
211 | GCC_WARN_UNUSED_VARIABLE = YES;
212 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
213 | MTL_ENABLE_DEBUG_INFO = YES;
214 | ONLY_ACTIVE_ARCH = YES;
215 | SDKROOT = iphoneos;
216 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
217 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
218 | };
219 | name = Debug;
220 | };
221 | A94094A31EBDD80500203841 /* Release */ = {
222 | isa = XCBuildConfiguration;
223 | buildSettings = {
224 | ALWAYS_SEARCH_USER_PATHS = NO;
225 | CLANG_ANALYZER_NONNULL = YES;
226 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
227 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
228 | CLANG_CXX_LIBRARY = "libc++";
229 | CLANG_ENABLE_MODULES = YES;
230 | CLANG_ENABLE_OBJC_ARC = YES;
231 | CLANG_WARN_BOOL_CONVERSION = YES;
232 | CLANG_WARN_CONSTANT_CONVERSION = YES;
233 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
234 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
235 | CLANG_WARN_EMPTY_BODY = YES;
236 | CLANG_WARN_ENUM_CONVERSION = YES;
237 | CLANG_WARN_INFINITE_RECURSION = YES;
238 | CLANG_WARN_INT_CONVERSION = YES;
239 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
240 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
241 | CLANG_WARN_UNREACHABLE_CODE = YES;
242 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
243 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
244 | COPY_PHASE_STRIP = NO;
245 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
246 | ENABLE_NS_ASSERTIONS = NO;
247 | ENABLE_STRICT_OBJC_MSGSEND = YES;
248 | GCC_C_LANGUAGE_STANDARD = gnu99;
249 | GCC_NO_COMMON_BLOCKS = YES;
250 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
251 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
252 | GCC_WARN_UNDECLARED_SELECTOR = YES;
253 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
254 | GCC_WARN_UNUSED_FUNCTION = YES;
255 | GCC_WARN_UNUSED_VARIABLE = YES;
256 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
257 | MTL_ENABLE_DEBUG_INFO = NO;
258 | SDKROOT = iphoneos;
259 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
260 | VALIDATE_PRODUCT = YES;
261 | };
262 | name = Release;
263 | };
264 | A94094A51EBDD80500203841 /* Debug */ = {
265 | isa = XCBuildConfiguration;
266 | buildSettings = {
267 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
268 | DEVELOPMENT_TEAM = 29X3GG489T;
269 | INFOPLIST_FILE = ARSlicer/Info.plist;
270 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
271 | PRODUCT_BUNDLE_IDENTIFIER = com.creative.slicing.ARSlicer;
272 | PRODUCT_NAME = "$(TARGET_NAME)";
273 | SWIFT_VERSION = 3.0;
274 | };
275 | name = Debug;
276 | };
277 | A94094A61EBDD80500203841 /* Release */ = {
278 | isa = XCBuildConfiguration;
279 | buildSettings = {
280 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
281 | DEVELOPMENT_TEAM = 29X3GG489T;
282 | INFOPLIST_FILE = ARSlicer/Info.plist;
283 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
284 | PRODUCT_BUNDLE_IDENTIFIER = com.creative.slicing.ARSlicer;
285 | PRODUCT_NAME = "$(TARGET_NAME)";
286 | SWIFT_VERSION = 3.0;
287 | };
288 | name = Release;
289 | };
290 | /* End XCBuildConfiguration section */
291 |
292 | /* Begin XCConfigurationList section */
293 | A940948B1EBDD80500203841 /* Build configuration list for PBXProject "ARSlicer" */ = {
294 | isa = XCConfigurationList;
295 | buildConfigurations = (
296 | A94094A21EBDD80500203841 /* Debug */,
297 | A94094A31EBDD80500203841 /* Release */,
298 | );
299 | defaultConfigurationIsVisible = 0;
300 | defaultConfigurationName = Release;
301 | };
302 | A94094A41EBDD80500203841 /* Build configuration list for PBXNativeTarget "ARSlicer" */ = {
303 | isa = XCConfigurationList;
304 | buildConfigurations = (
305 | A94094A51EBDD80500203841 /* Debug */,
306 | A94094A61EBDD80500203841 /* Release */,
307 | );
308 | defaultConfigurationIsVisible = 0;
309 | defaultConfigurationName = Release;
310 | };
311 | /* End XCConfigurationList section */
312 | };
313 | rootObject = A94094881EBDD80500203841 /* Project object */;
314 | }
315 |
--------------------------------------------------------------------------------