diff --git a/ARKitProject.xcodeproj/project.pbxproj b/ARKitProject.xcodeproj/project.pbxproj index dc31a63..06a208c 100644 --- a/ARKitProject.xcodeproj/project.pbxproj +++ b/ARKitProject.xcodeproj/project.pbxproj @@ -20,6 +20,7 @@ 39D4A8BE1EA1AF530006EC65 /* PlaneDebugVisualization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D4A8BD1EA1AF530006EC65 /* PlaneDebugVisualization.swift */; }; 39D8DC1B1E8ADAE600386B05 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39D8DC1A1E8ADAE600386B05 /* LaunchScreen.storyboard */; }; 582FB0721F43EAC600AD8041 /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = 582FB0711F43EAC600AD8041 /* .swiftlint.yml */; }; + 58DE9FC71FDDA042008E25AF /* VirtualObjectsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58DE9FC61FDDA041008E25AF /* VirtualObjectsManager.swift */; }; A35A11CF1EF4EB070072FE74 /* ScieneView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A35A11CE1EF4EB070072FE74 /* ScieneView+Extension.swift */; }; A3D672ED1EF0E7C500110E48 /* Cup.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3D672EC1EF0E7C500110E48 /* Cup.swift */; }; A3D672EF1EF0E80200110E48 /* Candle.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3D672EE1EF0E80200110E48 /* Candle.swift */; }; @@ -49,6 +50,7 @@ 39D4A8BD1EA1AF530006EC65 /* PlaneDebugVisualization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlaneDebugVisualization.swift; sourceTree = ""; }; 39D8DC1A1E8ADAE600386B05 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 582FB0711F43EAC600AD8041 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .swiftlint.yml; sourceTree = ""; }; + 58DE9FC61FDDA041008E25AF /* VirtualObjectsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VirtualObjectsManager.swift; sourceTree = ""; }; A35A11CE1EF4EB070072FE74 /* ScieneView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ScieneView+Extension.swift"; sourceTree = ""; }; A3D672E41EF0E64100110E48 /* ARKitProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ARKitProject.app; sourceTree = BUILT_PRODUCTS_DIR; }; A3D672EC1EF0E7C500110E48 /* Cup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cup.swift; sourceTree = ""; }; @@ -122,6 +124,7 @@ isa = PBXGroup; children = ( C4E87DD81EA6B40F002117D6 /* VirtualObject.swift */, + 58DE9FC61FDDA041008E25AF /* VirtualObjectsManager.swift */, A3D672EC1EF0E7C500110E48 /* Cup.swift */, A3D672EE1EF0E80200110E48 /* Candle.swift */, A3D672F01EF0E81B00110E48 /* Chair.swift */, @@ -243,6 +246,7 @@ 3929C48C1E89EC2C00E00B60 /* AppDelegate.swift in Sources */, A3D672EF1EF0E80200110E48 /* Candle.swift in Sources */, C4FBC02B1EC6438B003F7864 /* ARCameraTrackingState.swift in Sources */, + 58DE9FC71FDDA042008E25AF /* VirtualObjectsManager.swift in Sources */, A3D672F31EF0E84D00110E48 /* Lamp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ARKitProject/MainViewController.swift b/ARKitProject/MainViewController.swift index 2caae62..cbf3f85 100644 --- a/ARKitProject/MainViewController.swift +++ b/ARKitProject/MainViewController.swift @@ -73,7 +73,6 @@ class MainViewController: UIViewController { } // MARK: - Virtual Object Loading - var virtualObject: VirtualObject? // TODO: Remove this and create an array with virtualobject var isLoadingObject: Bool = false { didSet { DispatchQueue.main.async { @@ -122,7 +121,7 @@ class MainViewController: UIViewController { textManager.cancelScheduledMessage(forType: .planeEstimation) textManager.showMessage("SURFACE DETECTED") - if virtualObject == nil { + if !VirtualObjectsManager.shared.isAVirtualObjectPlaced() { textManager.scheduleMessage("TAP + TO PLACE AN OBJECT", inSeconds: 7.5, messageType: .contentPlacement) } } @@ -157,7 +156,8 @@ class MainViewController: UIViewController { func updateFocusSquare() { guard let screenCenter = screenCenter else { return } - + + let virtualObject = VirtualObjectsManager.shared.getVirtualObjectSelected() if virtualObject != nil && sceneView.isNode(virtualObject!, insideFrustumOf: sceneView.pointOfView!) { focusSquare?.hide() } else { @@ -418,7 +418,7 @@ extension MainViewController { // MARK: Gesture Recognized extension MainViewController { override func touchesBegan(_ touches: Set, with event: UIEvent?) { - guard let object = virtualObject else { + guard let object = VirtualObjectsManager.shared.getVirtualObjectSelected() else { return } @@ -432,7 +432,7 @@ extension MainViewController { } override func touchesMoved(_ touches: Set, with event: UIEvent?) { - if virtualObject == nil { + if !VirtualObjectsManager.shared.isAVirtualObjectPlaced() { return } currentGesture = currentGesture?.updateGestureFromTouches(touches, .touchMoved) @@ -440,7 +440,7 @@ extension MainViewController { } override func touchesEnded(_ touches: Set, with event: UIEvent?) { - if virtualObject == nil { + if !VirtualObjectsManager.shared.isAVirtualObjectPlaced() { chooseObject(addObjectButton) return } @@ -449,7 +449,7 @@ extension MainViewController { } override func touchesCancelled(_ touches: Set, with event: UIEvent?) { - if virtualObject == nil { + if !VirtualObjectsManager.shared.isAVirtualObjectPlaced() { return } currentGesture = currentGesture?.updateGestureFromTouches(touches, .touchCancelled) @@ -485,7 +485,8 @@ extension MainViewController :VirtualObjectSelectionViewControllerDelegate { DispatchQueue.global().async { self.isLoadingObject = true object.viewController = self - self.virtualObject = object + VirtualObjectsManager.shared.addVirtualObject(virtualObject: object) + VirtualObjectsManager.shared.setVirtualObjectSelected(virtualObject: object) object.loadModel() @@ -559,7 +560,8 @@ extension MainViewController :ARSCNViewDelegate { // MARK: Virtual Object Manipulation extension MainViewController { func displayVirtualObjectTransform() { - guard let object = virtualObject, let cameraTransform = session.currentFrame?.camera.transform else { + guard let object = VirtualObjectsManager.shared.getVirtualObjectSelected(), + let cameraTransform = session.currentFrame?.camera.transform else { return } @@ -584,7 +586,7 @@ extension MainViewController { guard let newPosition = pos else { textManager.showMessage("CANNOT PLACE OBJECT\nTry moving left or right.") // Reset the content selection in the menu only if the content has not yet been initially placed. - if virtualObject == nil { + if !VirtualObjectsManager.shared.isAVirtualObjectPlaced() { resetVirtualObject() } return @@ -671,7 +673,8 @@ extension MainViewController { func setNewVirtualObjectPosition(_ pos: SCNVector3) { - guard let object = virtualObject, let cameraTransform = session.currentFrame?.camera.transform else { + guard let object = VirtualObjectsManager.shared.getVirtualObjectSelected(), + let cameraTransform = session.currentFrame?.camera.transform else { return } @@ -689,16 +692,14 @@ extension MainViewController { } func resetVirtualObject() { - virtualObject?.unloadModel() - virtualObject?.removeFromParentNode() - virtualObject = nil + VirtualObjectsManager.shared.resetVirtualObjects() addObjectButton.setImage(#imageLiteral(resourceName: "add"), for: []) addObjectButton.setImage(#imageLiteral(resourceName: "addPressed"), for: [.highlighted]) } func updateVirtualObjectPosition(_ pos: SCNVector3, _ filterPosition: Bool) { - guard let object = virtualObject else { + guard let object = VirtualObjectsManager.shared.getVirtualObjectSelected() else { return } @@ -733,7 +734,8 @@ extension MainViewController { } func checkIfObjectShouldMoveOntoPlane(anchor: ARPlaneAnchor) { - guard let object = virtualObject, let planeAnchorNode = sceneView.node(for: anchor) else { + guard let object = VirtualObjectsManager.shared.getVirtualObjectSelected(), + let planeAnchorNode = sceneView.node(for: anchor) else { return } diff --git a/ARKitProject/Virtual Objects/VirtualObjectsManager.swift b/ARKitProject/Virtual Objects/VirtualObjectsManager.swift new file mode 100644 index 0000000..b0fd969 --- /dev/null +++ b/ARKitProject/Virtual Objects/VirtualObjectsManager.swift @@ -0,0 +1,73 @@ +// +// virtualObjectsManager.swift +// ARKitProject +// +// Created by Ignacio Chiazzo on 2017-12-10. +// Copyright © 2017 Apple. All rights reserved. +// + +import Foundation +import os.log + +class VirtualObjectsManager { + + static let shared = VirtualObjectsManager() + + // AutoIncrement Unique Id + private var nextID = 1 + func generateUid() -> Int { + nextID += 1 + return nextID + } + + private var virtualObjects: [VirtualObject] = [VirtualObject]() + private var virtualObjectSelected: VirtualObject? + + func addVirtualObject(virtualObject: VirtualObject) { + virtualObjects.append(virtualObject) + } + + func resetVirtualObjects() { + for object in virtualObjects { + object.unloadModel() + object.removeFromParentNode() + } + virtualObjectSelected = nil + virtualObjects = [] + } + + func removeVirtualObject(virtualObject: VirtualObject) { + if let index = virtualObjects.index(where: { $0.id == virtualObject.id }) { + virtualObjects.remove(at: index) + } else { + os_log("Element not found", type: .error) + } + } + + func removeVirtualObjectSelected() { + guard let object = virtualObjectSelected else { + return + } + + removeVirtualObject(virtualObject: object) + object.unloadModel() + object.removeFromParentNode() + virtualObjectSelected = nil + } + + func getVirtualObjects() -> [VirtualObject] { + return self.virtualObjects + } + + func isAVirtualObjectPlaced() -> Bool { + return virtualObjectSelected != nil + } + + func setVirtualObjectSelected(virtualObject: VirtualObject) { + self.virtualObjectSelected = virtualObject + } + + func getVirtualObjectSelected() -> VirtualObject? { + return self.virtualObjectSelected + } +} diff --git a/ARKitProject/VirtualObject.swift b/ARKitProject/VirtualObject.swift index b672ca6..f139280 100644 --- a/ARKitProject/VirtualObject.swift +++ b/ARKitProject/VirtualObject.swift @@ -4,11 +4,12 @@ import ARKit class VirtualObject: SCNNode { static let ROOT_NAME = "Virtual object root node" - var modelName: String = "" var fileExtension: String = "" var thumbImage: UIImage! var title: String = "" + var modelName: String = "" var modelLoaded: Bool = false + var id: Int! var viewController: MainViewController? @@ -19,6 +20,7 @@ class VirtualObject: SCNNode { init(modelName: String, fileExtension: String, thumbImageFilename: String, title: String) { super.init() + self.id = VirtualObjectsManager.shared.generateUid() self.name = VirtualObject.ROOT_NAME self.modelName = modelName self.fileExtension = fileExtension