├── 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 | ![](art/logo.png) 2 | 3 | Let Augmented Reality help you to create a perfect sliced pizza in 5 different shapes! 4 | 5 | ![](art/pizzas.png) 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 | --------------------------------------------------------------------------------