diff --git a/iOS12_Sampler/ios12 Sampler.xcodeproj/project.pbxproj b/iOS12_Sampler/ios12 Sampler.xcodeproj/project.pbxproj index ca40288..3309020 100644 --- a/iOS12_Sampler/ios12 Sampler.xcodeproj/project.pbxproj +++ b/iOS12_Sampler/ios12 Sampler.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 2E04C9072B4EE2F3000B4936 /* ARImageLocator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E04C9062B4EE2F3000B4936 /* ARImageLocator.swift */; }; + 2E04C9092B503318000B4936 /* StatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E04C9082B503318000B4936 /* StatusViewController.swift */; }; + 2E04C90B2B503A6D000B4936 /* ARImageLocator+ARSessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E04C90A2B503A6D000B4936 /* ARImageLocator+ARSessionDelegate.swift */; }; 2E15A5982B32F720001EA792 /* RectangleDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E15A5972B32F720001EA792 /* RectangleDetector.swift */; }; 2E15A59A2B32FE85001EA792 /* ARImageDetectorVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E15A5992B32FE85001EA792 /* ARImageDetectorVC.swift */; }; 2E7503282B30640100DF78E1 /* ARSurfaceDetectionVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E7503272B30640100DF78E1 /* ARSurfaceDetectionVC.swift */; }; @@ -83,6 +86,9 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 2E04C9062B4EE2F3000B4936 /* ARImageLocator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARImageLocator.swift; sourceTree = ""; }; + 2E04C9082B503318000B4936 /* StatusViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusViewController.swift; sourceTree = ""; }; + 2E04C90A2B503A6D000B4936 /* ARImageLocator+ARSessionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ARImageLocator+ARSessionDelegate.swift"; sourceTree = ""; }; 2E15A5972B32F720001EA792 /* RectangleDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RectangleDetector.swift; sourceTree = ""; }; 2E15A5992B32FE85001EA792 /* ARImageDetectorVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARImageDetectorVC.swift; sourceTree = ""; }; 2E7503272B30640100DF78E1 /* ARSurfaceDetectionVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARSurfaceDetectionVC.swift; sourceTree = ""; }; @@ -172,6 +178,16 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 2E04C9032B4EE267000B4936 /* Detecting Images in AR */ = { + isa = PBXGroup; + children = ( + 2E04C9062B4EE2F3000B4936 /* ARImageLocator.swift */, + 2E04C9082B503318000B4936 /* StatusViewController.swift */, + 2E04C90A2B503A6D000B4936 /* ARImageLocator+ARSessionDelegate.swift */, + ); + path = "Detecting Images in AR"; + sourceTree = ""; + }; 2E15A5962B32F6FC001EA792 /* Utilities */ = { isa = PBXGroup; children = ( @@ -324,6 +340,7 @@ 4968C0E020D12FE500D384F0 /* AVReadARObjectVC.swift */, 4931C78C20D3988E002F907B /* AVTextureEnvironment.swift */, 8127E0E220D7E5B500D8CD7F /* AVImageDetaction.swift */, + 2E04C9032B4EE267000B4936 /* Detecting Images in AR */, 2E75034B2B31E00400DF78E1 /* Tracking and altering images */, 2E7503222B30227F00DF78E1 /* Surface Detection */, 4968C0E720D1569C00D384F0 /* ScanningObjectHelperController */, @@ -525,8 +542,10 @@ 4968C0DA20D12AA700D384F0 /* ThresholdPinchGestureRecognizer.swift in Sources */, 4968C0DF20D12BF500D384F0 /* ViewController+ApplicationState.swift in Sources */, 49C5721020D269E300602C7B /* AVMainVC.swift in Sources */, + 2E04C90B2B503A6D000B4936 /* ARImageLocator+ARSessionDelegate.swift in Sources */, 2E9300F62B4683DC002BF5D6 /* AlteredImage.swift in Sources */, 4904E81020D776B3002F5210 /* DetectedBoundingBox.swift in Sources */, + 2E04C9072B4EE2F3000B4936 /* ARImageLocator.swift in Sources */, 4904E80E20D776B3002F5210 /* ObjectOriginAxis.swift in Sources */, 4904E7EB20D77386002F5210 /* ViewController+SessionInfo.swift in Sources */, 4968C0CB20D12AA700D384F0 /* FlashlightButton.swift in Sources */, @@ -552,6 +571,7 @@ 4904E80D20D776B3002F5210 /* DetectedPointCloud.swift in Sources */, 8127E0E620D7E60100D8CD7F /* iOSDevCenters+GIF.swift in Sources */, 4904E7F820D7767E002F5210 /* Utilities.swift in Sources */, + 2E04C9092B503318000B4936 /* StatusViewController.swift in Sources */, 4904E80820D776B3002F5210 /* ScannedObject.swift in Sources */, 4968C0E320D14B1B00D384F0 /* AVScannedObjectListVC.swift in Sources */, 4904E7EE20D77386002F5210 /* Scan.swift in Sources */, diff --git a/iOS12_Sampler/ios12 Sampler/AVMainVC.swift b/iOS12_Sampler/ios12 Sampler/AVMainVC.swift index c5f0fd9..3a9ae46 100644 --- a/iOS12_Sampler/ios12 Sampler/AVMainVC.swift +++ b/iOS12_Sampler/ios12 Sampler/AVMainVC.swift @@ -34,7 +34,7 @@ class AVMainVC: UIViewController, AVCaptureMetadataOutputObjectsDelegate { } @IBAction func btnActionWorldSharing(_ sender: Any) { - let vc = self.storyboard?.instantiateViewController(withIdentifier: "ARImageDetectorVC") as? ARImageDetectorVC + let vc = self.storyboard?.instantiateViewController(withIdentifier: "ARImageLocator") as? ARImageLocator self.navigationController?.pushViewController(vc!, animated: true) // let vc = self.storyboard?.instantiateViewController(withIdentifier: "ARSurfaceDetectionVC") as? ARSurfaceDetectionVC // self.navigationController?.pushViewController(vc!, animated: true) diff --git a/iOS12_Sampler/ios12 Sampler/Assets.xcassets/AR Resources.arresourcegroup/Contents.json b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/AR Resources.arresourcegroup/Contents.json new file mode 100644 index 0000000..4868a1d --- /dev/null +++ b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/AR Resources.arresourcegroup/Contents.json @@ -0,0 +1,11 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "resources" : [ + { + "filename" : "IMG_0060.arreferenceimage" + } + ] +} diff --git a/iOS12_Sampler/ios12 Sampler/Assets.xcassets/AR Resources.arresourcegroup/IMG_0060.arreferenceimage/Contents.json b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/AR Resources.arresourcegroup/IMG_0060.arreferenceimage/Contents.json new file mode 100644 index 0000000..27bd3df --- /dev/null +++ b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/AR Resources.arresourcegroup/IMG_0060.arreferenceimage/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "IMG_0060.HEIC", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "unit" : "inches", + "width" : 42 + } +} diff --git a/iOS12_Sampler/ios12 Sampler/Assets.xcassets/AR Resources.arresourcegroup/IMG_0060.arreferenceimage/IMG_0060.HEIC b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/AR Resources.arresourcegroup/IMG_0060.arreferenceimage/IMG_0060.HEIC new file mode 100644 index 0000000..55af2c5 Binary files /dev/null and b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/AR Resources.arresourcegroup/IMG_0060.arreferenceimage/IMG_0060.HEIC differ diff --git a/iOS12_Sampler/ios12 Sampler/Assets.xcassets/Random.imageset/Contents.json b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/Random.imageset/Contents.json new file mode 100644 index 0000000..0c0bf97 --- /dev/null +++ b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/Random.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "merge_from_ofoct (1).jpg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iOS12_Sampler/ios12 Sampler/Assets.xcassets/Random.imageset/merge_from_ofoct (1).jpg b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/Random.imageset/merge_from_ofoct (1).jpg new file mode 100644 index 0000000..9bdeae2 Binary files /dev/null and b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/Random.imageset/merge_from_ofoct (1).jpg differ diff --git a/iOS12_Sampler/ios12 Sampler/Assets.xcassets/refresh.imageset/Contents.json b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/refresh.imageset/Contents.json new file mode 100644 index 0000000..971a7d4 --- /dev/null +++ b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/refresh.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "refresh@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "refresh@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iOS12_Sampler/ios12 Sampler/Assets.xcassets/refresh.imageset/refresh@2x.png b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/refresh.imageset/refresh@2x.png new file mode 100644 index 0000000..365ed49 Binary files /dev/null and b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/refresh.imageset/refresh@2x.png differ diff --git a/iOS12_Sampler/ios12 Sampler/Assets.xcassets/refresh.imageset/refresh@3x.png b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/refresh.imageset/refresh@3x.png new file mode 100644 index 0000000..4bea81f Binary files /dev/null and b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/refresh.imageset/refresh@3x.png differ diff --git a/iOS12_Sampler/ios12 Sampler/Assets.xcassets/tick.imageset/Contents.json b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/tick.imageset/Contents.json new file mode 100644 index 0000000..90558ea --- /dev/null +++ b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/tick.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "checked.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iOS12_Sampler/ios12 Sampler/Assets.xcassets/tick.imageset/checked.png b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/tick.imageset/checked.png new file mode 100644 index 0000000..951ed8f Binary files /dev/null and b/iOS12_Sampler/ios12 Sampler/Assets.xcassets/tick.imageset/checked.png differ diff --git a/iOS12_Sampler/ios12 Sampler/Base.lproj/Main.storyboard b/iOS12_Sampler/ios12 Sampler/Base.lproj/Main.storyboard index a6fdd27..e81e1e4 100644 --- a/iOS12_Sampler/ios12 Sampler/Base.lproj/Main.storyboard +++ b/iOS12_Sampler/ios12 Sampler/Base.lproj/Main.storyboard @@ -1116,49 +1116,75 @@ New Object - - + + - + - - + + - - + + - - + + + + + + - - - - - - - - + + + + + + + + + + + - - - + + + + @@ -1179,13 +1205,14 @@ New Object - + + @@ -1195,6 +1222,126 @@ New Object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1220,8 +1367,10 @@ New Object + + diff --git a/iOS12_Sampler/ios12 Sampler/Detecting Images in AR/ARImageLocator+ARSessionDelegate.swift b/iOS12_Sampler/ios12 Sampler/Detecting Images in AR/ARImageLocator+ARSessionDelegate.swift new file mode 100644 index 0000000..5d65fa0 --- /dev/null +++ b/iOS12_Sampler/ios12 Sampler/Detecting Images in AR/ARImageLocator+ARSessionDelegate.swift @@ -0,0 +1,26 @@ +// +// ARImageLocator+ARSessionDelegate.swift +// ios12 Sampler +// +// Created by Dhruvil Vora on 11/01/24. +// Copyright © 2024 Testing. All rights reserved. +// + +import ARKit + +extension ARImageLocator: ARSessionDelegate { + + func session(_ session: ARSession, cameraDidChangeTrackingState camera: ARCamera) { + /// Notify users about current tracking camera quality + statusViewController.showCameraQualityInfo(trackingState: camera.trackingState, autoHide: true) + + switch camera.trackingState { + case .notAvailable: + statusViewController.showRecommendationForCameraQuality(trackingState: camera.trackingState, + duration: 3, autoHide: false) + default: + break + } + } + +} diff --git a/iOS12_Sampler/ios12 Sampler/Detecting Images in AR/ARImageLocator.swift b/iOS12_Sampler/ios12 Sampler/Detecting Images in AR/ARImageLocator.swift new file mode 100644 index 0000000..0a35dcf --- /dev/null +++ b/iOS12_Sampler/ios12 Sampler/Detecting Images in AR/ARImageLocator.swift @@ -0,0 +1,173 @@ +// +// ARImageLocator.swift +// ios12 Sampler +// +// Created by Dhruvil Vora on 10/01/24. +// Copyright © 2024 Testing. All rights reserved. +// + +import Foundation +import ARKit + +class ARImageLocator: UIViewController { + + @IBOutlet weak var sceneView: ARSCNView! + + @IBOutlet weak var blurVIew: UIVisualEffectView! + + lazy var statusViewController: StatusViewController = { + children.lazy.compactMap({ $0 as? StatusViewController }).first! + }() + + /// Need to create a serial queue for thread safety, when modifying scenekit node graph + let serialQueue = DispatchQueue(label: "\(Bundle.main.bundleIdentifier ?? "") + .serialScenekitQueue") + + /// Session accessor which is hold by sceneview + var session: ARSession { + sceneView.session + } + + var isRestartAvailable = true + + // MARK: View life cycle + override func viewDidLoad() { + super.viewDidLoad() + + sceneView.delegate = self + + // Create a new scene + let scene = SCNScene(named: "art.scnassets/ship.scn")! + sceneView.scene = scene + + sceneView.session.delegate = self + + // Hook up status view controller callback(s). + statusViewController.restartExperienceHandler = { [unowned self] in + self.restartExperience() + } + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + /// Prevent screen from being dimmed after it's let ideal for sometime + UIApplication.shared.isIdleTimerDisabled = true + statusViewController.scheduleGenericMessage(genericMsg: "Look for an image", duration: 7.5, + autoHide: true, messageType: .cameraQualityInfo) + resetTracking() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + session.pause() + } + + /// Create a new arconfig to run on a `session` + func resetTracking() { + + guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else { + fatalError("Didn't found any resourcses") + } + let config = ARWorldTrackingConfiguration() + /// Need to provide detection images + config.detectionImages = referenceImages + session.run(config, options: [.resetTracking, .removeExistingAnchors]) + } + + private func restartExperience() { + guard isRestartAvailable else { return } + isRestartAvailable = false + statusViewController.showHideResetButton(isHidden: isRestartAvailable) + statusViewController.removeAllTimers() + + DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) { [weak self] in + guard let self else { return } + self.isRestartAvailable = true + self.statusViewController.showHideResetButton(isHidden: self.isRestartAvailable) + } + } +} + +extension ARImageLocator: ARSCNViewDelegate { + func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) { + guard let imageAnchor = anchor as? ARImageAnchor else { return } + serialQueue.async { + // first create a plane from the added anchor + let plane = SCNPlane(width: imageAnchor.referenceImage.physicalSize.width, + height: imageAnchor.referenceImage.physicalSize.height) + let planeNode = SCNNode(geometry: plane) + planeNode.opacity = 0.25 + + // As SCNPlane is a 2d it is vertically oriented and the ARImageAnchor is horizontally oriented + /// So by default SCNPlane is in a 2D format whose orientation is vertical & image anchor being 3D format its + /// horizontally align so inorder to matchb with imageanchor we need to rotate the plane's angle + planeNode.eulerAngles.x = -.pi / 2 + + node.addChildNode(planeNode) + } + DispatchQueue.main.async { + let name = imageAnchor.referenceImage.name + print("Image Name :- ",name) + self.animateObject(node) + } + } + + func animateObject(_ node: SCNNode) { + + guard let nodeToAnimate = sceneView.scene.rootNode.childNode(withName: "ship", recursively: true) else { + return + } + + // let forwardAction = SCNAction.moveBy(x: 0, y: 0, z: 5, duration: 1.0) + // let rotateAction1 = SCNAction.rotateBy(x: -.pi/2,y: 0, z: 0, duration: 2.0) + // let backwardAction = SCNAction.moveBy(x: 0, y: 0, z: -5, duration: 1.0) + // let rotateAction2 = SCNAction.rotateBy(x: -.pi/2,y: 0, z: 0, duration: 2.0) + // let abc = SCNAction.group([backwardAction, rotateAction1]) + // let sequenceAction = SCNAction.sequence([forwardAction, rotateAction1, backwardAction, rotateAction2]) + + let forwardAction = SCNAction.moveBy(x: 0, y: 0, z: 5, duration: 1.0) + let rotateAction1 = SCNAction.rotateBy(x: (-.pi),y: 0, z: 0, duration: 5.0) + let backwardAction = SCNAction.moveBy(x: 0, y: 0, z: -5, duration: 1.0) + let rotateAction2 = SCNAction.rotateBy(x: .pi/2,y: 0, z: 0, duration: 2.0) + let rotation = SCNAction.rotateBy(x: 0,y: 0, z: .pi, duration: 2.0) + var verticalPosition0: CGFloat = 0.0 + // Create a custom action to update the position based on a parabolic function + let parabolicAction = SCNAction.customAction(duration: 2) { (node, elapsedTime) in + // Calculate the vertical position using a parabolic function + verticalPosition0 = 0.5 * 9.8 * pow(elapsedTime, 1) + print("vertical Pos :- ", verticalPosition0) + // Update the node's position based on the parabolic function + node.position = SCNVector3(nodeToAnimate.position.x, + Float(verticalPosition0) > 4.9 ? (9.8 - Float(verticalPosition0)) : Float(verticalPosition0), + -Float(verticalPosition0)) + } + + let parabolicBackAction = SCNAction.customAction(duration: 2) { (node, elapsedTime) in + // Calculate the vertical position using a parabolic function + let verticalPosition = -0.5 * 9.8 * pow(elapsedTime, 1) + print("vertical Pos :- ", verticalPosition) + // Update the node's position based on the parabolic function + node.position = SCNVector3(Float(node.position.x), Float(verticalPosition), node.position.z) + } + // let sequenceAction = SCNAction.sequence([forwardAction, rotateAction1, backwardAction, rotateAction1]) + + let groupAction1 = SCNAction.group([forwardAction, rotation, parabolicAction]) + let groupAction2 = SCNAction.group([rotateAction1, backwardAction]) + let sequenceAction = SCNAction.sequence([groupAction1]) + + let repeatAction = SCNAction.repeatForever(parabolicAction.reversed()) + + nodeToAnimate.runAction(repeatAction) + } + + var imageHighlightAction: SCNAction { + return .sequence([ + .wait(duration: 0.25), + .fadeOpacity(to: 0.85, duration: 0.25), + .fadeOpacity(to: 0.15, duration: 0.25), + .fadeOpacity(to: 0.85, duration: 0.25), + .fadeOut(duration: 0.5), + .removeFromParentNode() + ]) + } +} + diff --git a/iOS12_Sampler/ios12 Sampler/Detecting Images in AR/StatusViewController.swift b/iOS12_Sampler/ios12 Sampler/Detecting Images in AR/StatusViewController.swift new file mode 100644 index 0000000..398cc79 --- /dev/null +++ b/iOS12_Sampler/ios12 Sampler/Detecting Images in AR/StatusViewController.swift @@ -0,0 +1,80 @@ +// +// StatusViewController.swift +// ios12 Sampler +// +// Created by Dhruvil Vora on 11/01/24. +// Copyright © 2024 Testing. All rights reserved. +// + +import ARKit + +class StatusViewController: UIViewController { + + enum MessageType: CaseIterable { + case cameraQualityInfo + case cameraQualityRecommendation + } + + @IBOutlet weak var messageLabelView: UIVisualEffectView! + + @IBOutlet weak var resetButton: UIButton! + + @IBOutlet weak var messageLabel: UILabel! + + private var timers: [MessageType: Timer] = [:] + + private var autoHideDuration = 6 + + var restartExperienceHandler: () -> Void = {} + + func showCameraQualityInfo(trackingState: ARCamera.TrackingState, autoHide: Bool) { + cancelTimer(for: .cameraQualityInfo) + showMessage(trackingState.presentationString, autoHide: autoHide) + } + + func showRecommendationForCameraQuality(trackingState: ARCamera.TrackingState, duration: TimeInterval, autoHide: Bool) { + cancelTimer(for: .cameraQualityRecommendation) + showMessage(trackingState.recommendation ?? "", autoHide: autoHide) + + let timer = Timer.scheduledTimer(withTimeInterval: duration, repeats: false) { [weak self] _ in + self?.messageLabel.text = "\(trackingState.presentationString): \(trackingState.recommendation ?? "Not available")" + } + timers[.cameraQualityRecommendation] = timer + } + + func showMessage(_ message: String, autoHide: Bool) { + messageLabel.text = message + if autoHide { + let timer = Timer.scheduledTimer(withTimeInterval: TimeInterval(autoHideDuration), repeats: false) { [weak self] _ in + self?.messageLabel.text = message + } + } + } + + func cancelTimer(for messageType: MessageType) { + timers[messageType]?.invalidate() + timers[messageType] = nil + } + + func removeAllTimers() { + for messageType in MessageType.allCases { + cancelTimer(for: messageType) + } + } + + func showHideResetButton(isHidden: Bool) { + resetButton.isHidden = isHidden + } + + func scheduleGenericMessage(genericMsg: String, duration: TimeInterval, autoHide: Bool, messageType: MessageType) { + showMessage(genericMsg, autoHide: autoHide) + + let timer = Timer.scheduledTimer(withTimeInterval: duration, repeats: false) { [weak self] _ in + self?.messageLabel.text = genericMsg + } + timers[messageType] = timer + } + @IBAction func onRestartButtonPressed(_ sender: UIButton) { + restartExperienceHandler() + } +} diff --git a/iOS12_Sampler/ios12 Sampler/Tracking and altering images/ARImageDetectorVC.swift b/iOS12_Sampler/ios12 Sampler/Tracking and altering images/ARImageDetectorVC.swift index 2e0eb81..14d3564 100644 --- a/iOS12_Sampler/ios12 Sampler/Tracking and altering images/ARImageDetectorVC.swift +++ b/iOS12_Sampler/ios12 Sampler/Tracking and altering images/ARImageDetectorVC.swift @@ -13,8 +13,9 @@ import ARKit class ARImageDetectorVC: UIViewController { @IBOutlet weak var sceneView: ARSCNView! - @IBOutlet weak var messagePanel: UIView! - @IBOutlet weak var messageLabel: UILabel! + @IBOutlet private weak var messagePanel: UIView! + @IBOutlet private weak var messageLabel: UILabel! + @IBOutlet private weak var filterCollectionVw: UICollectionView! /// need to create an instance as this class's sceneView Outlet will be accessible /// from the RectangleDetector class inorder to track an image @@ -34,6 +35,9 @@ class ARImageDetectorVC: UIViewController { rectangleDetector.rectangleDelegate = self } + /// Filter Data + var filterData = getFilterData() + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) ARImageDetectorVC.instance = self @@ -42,6 +46,7 @@ class ARImageDetectorVC: UIViewController { UIApplication.shared.isIdleTimerDisabled = true searchForNewImageToTrack() + showMessage("Look for a rectangular image.", autoHide: false) } private func searchForNewImageToTrack() { @@ -130,15 +135,14 @@ extension ARImageDetectorVC: RectangleDetectorDelegate { extension ARImageDetectorVC: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return getFilterData().count + return filterData.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - let data = getFilterData() guard let cell: FilterCell = collectionView.dequeueReusableCell(withReuseIdentifier: "FilterCell", for: indexPath) as? FilterCell else { return UICollectionViewCell() } - cell.configureUI(filterModel: data[indexPath.item], index: indexPath.item) + cell.configureUI(filterModel: filterData[indexPath.item], index: indexPath.item) cell.filterCellTapDelegate = self return cell } @@ -146,8 +150,11 @@ extension ARImageDetectorVC: UICollectionViewDataSource { extension ARImageDetectorVC: FilterCellTapDelegate { func filterCellTapped(index: Int) { + filterData.map { $0.isSelected = false } + filterData[index].isSelected = true + filterCollectionVw.reloadData() guard let alterImage = alteredImage else { return } - alterImage.selectPreferredStyle(index: index) + alterImage.selectPreferredStyle(index: index, filterData: filterData[index]) } } diff --git a/iOS12_Sampler/ios12 Sampler/Tracking and altering images/Cell/FilterCell.swift b/iOS12_Sampler/ios12 Sampler/Tracking and altering images/Cell/FilterCell.swift index f91d051..0866705 100644 --- a/iOS12_Sampler/ios12 Sampler/Tracking and altering images/Cell/FilterCell.swift +++ b/iOS12_Sampler/ios12 Sampler/Tracking and altering images/Cell/FilterCell.swift @@ -15,7 +15,9 @@ protocol FilterCellTapDelegate: AnyObject { class FilterCell: UICollectionViewCell { @IBOutlet weak var imgFilter: UIImageView! @IBOutlet weak var lblFilterName: UILabel! - + @IBOutlet weak var dimVw: UIView! + @IBOutlet weak var imgTick: UIImageView! + weak var filterCellTapDelegate: FilterCellTapDelegate? var tappedIndex: Int = 0 @@ -25,9 +27,11 @@ class FilterCell: UICollectionViewCell { contentView.addGestureRecognizer(tapGesture) imgFilter.image = filterModel.filterDummyImage lblFilterName.text = filterModel.filterName + dimVw.isHidden = !filterModel.isSelected } @objc func onFilterCellTap() { + dimVw.isHidden = false filterCellTapDelegate?.filterCellTapped(index: tappedIndex) } } diff --git a/iOS12_Sampler/ios12 Sampler/Tracking and altering images/Utilities/AlteredImage.swift b/iOS12_Sampler/ios12 Sampler/Tracking and altering images/Utilities/AlteredImage.swift index 702c911..2562152 100644 --- a/iOS12_Sampler/ios12 Sampler/Tracking and altering images/Utilities/AlteredImage.swift +++ b/iOS12_Sampler/ios12 Sampler/Tracking and altering images/Utilities/AlteredImage.swift @@ -68,6 +68,8 @@ class AlteredImage { /// The index of the current image's style. private var styleIndex = 0 + private var selectedStyle: SelectedFilterStyle = .randomStyle + /// A delegate to tell when image tracking fails. weak var delegate: AlteredImageDelegate? @@ -161,9 +163,11 @@ class AlteredImage { print("StyleIndex new :- ", styleIndex) } - func selectPreferredStyle(index: Int) { + func selectPreferredStyle(index: Int, filterData: FilterModel) { + selectedStyle = filterData.selectedFilterStyle guard fadeBetweenImages, anchor != nil else { return } - styleIndexArray.setOnlyThisIndexToOne(index: index) + // as we have added a new "random" style in filter array so need to decrease more + styleIndex = index - 1 createAlteredImage() } @@ -215,7 +219,7 @@ class AlteredImage { extension AlteredImage: VisualizationNodeDelegate { func animationDidFinish() { - guard fadeBetweenImages, anchor != nil else { return } + guard fadeBetweenImages, anchor != nil, selectedStyle == .randomStyle else { return } selectNextStyle() createAlteredImage() } diff --git a/iOS12_Sampler/ios12 Sampler/Tracking and altering images/Utilities/ImageTrackingUtility.swift b/iOS12_Sampler/ios12 Sampler/Tracking and altering images/Utilities/ImageTrackingUtility.swift index 85b14e8..d051083 100644 --- a/iOS12_Sampler/ios12 Sampler/Tracking and altering images/Utilities/ImageTrackingUtility.swift +++ b/iOS12_Sampler/ios12 Sampler/Tracking and altering images/Utilities/ImageTrackingUtility.swift @@ -11,9 +11,23 @@ import CoreImage import CoreML import SceneKit -struct FilterModel { +class FilterModel { var filterDummyImage: UIImage var filterName: String + var isSelected: Bool + var selectedFilterStyle: SelectedFilterStyle + + init(filterDummyImage: UIImage, filterName: String, isSelected: Bool, selectedFilterStyle: SelectedFilterStyle = .otherStyle) { + self.filterDummyImage = filterDummyImage + self.filterName = filterName + self.isSelected = isSelected + self.selectedFilterStyle = selectedFilterStyle + } +} + +enum SelectedFilterStyle { + case randomStyle + case otherStyle } extension CIImage { @@ -77,12 +91,13 @@ func createPlaneNode(size: CGSize, rotation: Float, content: Any?) -> SCNNode { } func getFilterData() -> [FilterModel] { - return [FilterModel(filterDummyImage: UIImage(named: "style1")!, filterName: "style1"), - FilterModel(filterDummyImage: UIImage(named: "style2")!, filterName: "style2"), - FilterModel(filterDummyImage: UIImage(named: "style3")!, filterName: "style3"), - FilterModel(filterDummyImage: UIImage(named: "style4")!, filterName: "style4"), - FilterModel(filterDummyImage: UIImage(named: "style5")!, filterName: "style5"), - FilterModel(filterDummyImage: UIImage(named: "style6")!, filterName: "style6"), - FilterModel(filterDummyImage: UIImage(named: "style7")!, filterName: "style7"), - FilterModel(filterDummyImage: UIImage(named: "style8")!, filterName: "style8"),] + return [FilterModel(filterDummyImage: UIImage(named: "random")!, filterName: "Random", isSelected: true, selectedFilterStyle: .randomStyle), + FilterModel(filterDummyImage: UIImage(named: "style1")!, filterName: "Style1", isSelected: false), + FilterModel(filterDummyImage: UIImage(named: "style2")!, filterName: "Style2", isSelected: false), + FilterModel(filterDummyImage: UIImage(named: "style3")!, filterName: "Style3", isSelected: false), + FilterModel(filterDummyImage: UIImage(named: "style4")!, filterName: "Style4", isSelected: false), + FilterModel(filterDummyImage: UIImage(named: "style5")!, filterName: "Style5", isSelected: false), + FilterModel(filterDummyImage: UIImage(named: "style6")!, filterName: "Style6", isSelected: false), + FilterModel(filterDummyImage: UIImage(named: "style7")!, filterName: "Style7", isSelected: false), + FilterModel(filterDummyImage: UIImage(named: "style8")!, filterName: "Style8", isSelected: false)] } diff --git a/iOS12_Sampler/ios12 Sampler/art.scnassets/ship.scn b/iOS12_Sampler/ios12 Sampler/art.scnassets/ship.scn index 31886a0..89cc818 100644 Binary files a/iOS12_Sampler/ios12 Sampler/art.scnassets/ship.scn and b/iOS12_Sampler/ios12 Sampler/art.scnassets/ship.scn differ