From 8c1890ef9a72148463cd6c8c0ae3031e5dc39d8e Mon Sep 17 00:00:00 2001 From: denkoul Date: Thu, 14 Jul 2022 10:23:26 +0300 Subject: [PATCH 01/47] upgrades --- ios/Classes/IosARView.swift | 68 ++++++++++++++-------------- lib/managers/ar_session_manager.dart | 37 ++++++++------- 2 files changed, 55 insertions(+), 50 deletions(-) diff --git a/ios/Classes/IosARView.swift b/ios/Classes/IosARView.swift index fb332a98..fa898b7b 100644 --- a/ios/Classes/IosARView.swift +++ b/ios/Classes/IosARView.swift @@ -81,6 +81,10 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco //result(nil) initializeARView(arguments: arguments!, result: result) break + case "placeBasedOnCoordinates": + let coordinates = CGPoint(x: CGFloat( arguments!["x"] as! Float), y: CGFloat( arguments!["y"] as! Float)); + parseTouchLocation(touchLocation: coordinates); + break; case "getCameraPose": if let cameraPose = sceneView.session.currentFrame?.camera.transform { result(serializeMatrix(cameraPose)) @@ -116,7 +120,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco func onObjectMethodCalled(_ call :FlutterMethodCall, _ result: @escaping FlutterResult) { let arguments = call.arguments as? Dictionary - + switch call.method { case "init": self.objectManagerChannel.invokeMethod("onError", arguments: ["ObjectTEST from iOS"]) @@ -153,7 +157,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco func onAnchorMethodCalled(_ call :FlutterMethodCall, _ result: @escaping FlutterResult) { let arguments = call.arguments as? Dictionary - + switch call.method { case "init": self.objectManagerChannel.invokeMethod("onError", arguments: ["ObjectTEST from iOS"]) @@ -171,7 +175,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco break default: result(false) - + } } result(nil) @@ -190,11 +194,11 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco arcoreSession?.setConfiguration(configuration, error: nil); if let token = JWTGenerator().generateWebToken(){ arcoreSession!.setAuthToken(token) - + cloudAnchorHandler = CloudAnchorHandler(session: arcoreSession!) arcoreSession!.delegate = cloudAnchorHandler arcoreSession!.delegateQueue = DispatchQueue.main - + arcoreMode = true } else { sessionManagerChannel.invokeMethod("onError", arguments: ["Error generating JWT, have you added cloudAnchorKey.json into the example/ios/Runner directory?"]) @@ -202,7 +206,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco } else { sessionManagerChannel.invokeMethod("onError", arguments: ["Error initializing Google AR Session"]) } - + break case "uploadAnchor": if let anchorName = arguments!["name"] as? String, let anchor = anchorCollection[anchorName] { @@ -232,18 +236,18 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco self.configuration = ARWorldTrackingConfiguration() if let planeDetectionConfig = arguments["planeDetectionConfig"] as? Int { switch planeDetectionConfig { - case 1: + case 1: configuration.planeDetection = .horizontal - - case 2: + + case 2: if #available(iOS 11.3, *) { configuration.planeDetection = .vertical } - case 3: + case 3: if #available(iOS 11.3, *) { configuration.planeDetection = [.horizontal, .vertical] } - default: + default: configuration.planeDetection = [] } } @@ -280,7 +284,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco } } self.sceneView.debugOptions = ARSCNDebugOptions(rawValue: debugOptions) - + if let configHandleTaps = arguments["handleTaps"] as? Bool { if (configHandleTaps){ let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:))) @@ -297,7 +301,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco self.sceneView.gestureRecognizers?.append(panGestureRecognizer) } } - + if let configHandleRotation = arguments["handleRotation"] as? Bool { if (configHandleRotation){ let rotationGestureRecognizer = UIRotationGestureRecognizer(target: self, action: #selector(handleRotation(_:))) @@ -305,7 +309,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco self.sceneView.gestureRecognizers?.append(rotationGestureRecognizer) } } - + // Add coaching view if let configShowAnimatedGuide = arguments["showAnimatedGuide"] as? Bool { if configShowAnimatedGuide { @@ -335,13 +339,13 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco } } } - + // Update session configuration self.sceneView.session.run(configuration) } func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) { - + if let planeAnchor = anchor as? ARPlaneAnchor{ let plane = modelBuilder.makePlane(anchor: planeAnchor, flutterAssetFile: customPlaneTexturePath) trackedPlanes[anchor.identifier] = (node, plane) @@ -352,7 +356,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco } func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) { - + if let planeAnchor = anchor as? ARPlaneAnchor, let plane = trackedPlanes[anchor.identifier] { modelBuilder.updatePlaneNode(planeNode: plane.1, anchor: planeAnchor) } @@ -361,7 +365,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco func renderer(_ renderer: SCNSceneRenderer, didRemove node: SCNNode, for anchor: ARAnchor) { trackedPlanes.removeValue(forKey: anchor.identifier) } - + func session(_ session: ARSession, didUpdate frame: ARFrame) { if (arcoreMode) { do { @@ -375,7 +379,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco func addNode(dict_node: Dictionary, dict_anchor: Dictionary? = nil) -> Future { return Future {promise in - + switch (dict_node["type"] as! Int) { case 0: // GLTF2 Model from Flutter asset folder // Get path to given Flutter asset @@ -388,14 +392,13 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco if let anchor = self.anchorCollection[anchorName]{ // Attach node to the top-level node of the specified anchor self.sceneView.node(for: anchor)?.addChildNode(node) - promise(.success(true)) } else { promise(.success(false)) } default: promise(.success(false)) } - + } else { // Attach to top-level node of the scene self.sceneView.scene.rootNode.addChildNode(node) @@ -420,14 +423,13 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco if let anchor = self.anchorCollection[anchorName]{ // Attach node to the top-level node of the specified anchor self.sceneView.node(for: anchor)?.addChildNode(node) - promise(.success(true)) } else { promise(.success(false)) } default: promise(.success(false)) } - + } else { // Attach to top-level node of the scene self.sceneView.scene.rootNode.addChildNode(node) @@ -445,7 +447,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) let documentsDirectory = paths[0] let targetPath = documentsDirectory.appendingPathComponent(dict_node["uri"] as! String).path - + // Add object to scene if let node: SCNNode = self.modelBuilder.makeNodeFromFileSystemGLB(name: dict_node["name"] as! String, modelPath: targetPath, transformation: dict_node["transformation"] as? Array) { if let anchorName = dict_anchor?["name"] as? String, let anchorType = dict_anchor?["type"] as? Int { @@ -454,14 +456,13 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco if let anchor = self.anchorCollection[anchorName]{ // Attach node to the top-level node of the specified anchor self.sceneView.node(for: anchor)?.addChildNode(node) - promise(.success(true)) } else { promise(.success(false)) } default: promise(.success(false)) } - + } else { // Attach to top-level node of the scene self.sceneView.scene.rootNode.addChildNode(node) @@ -487,14 +488,13 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco if let anchor = self.anchorCollection[anchorName]{ // Attach node to the top-level node of the specified anchor self.sceneView.node(for: anchor)?.addChildNode(node) - promise(.success(true)) } else { promise(.success(false)) } default: promise(.success(false)) } - + } else { // Attach to top-level node of the scene self.sceneView.scene.rootNode.addChildNode(node) @@ -509,21 +509,23 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco default: promise(.success(false)) } - + } } - + func transformNode(name: String, transform: Array) { let node = sceneView.scene.rootNode.childNode(withName: name, recursively: true) node?.transform = deserializeMatrix4(transform) } - + @objc func handleTap(_ recognizer: UITapGestureRecognizer) { guard let sceneView = recognizer.view as? ARSCNView else { return } - let touchLocation = recognizer.location(in: sceneView) - + parseTouchLocation(touchLocation: recognizer.location(in: sceneView)) + } + + func parseTouchLocation(touchLocation: CGPoint) { let allHitResults = sceneView.hitTest(touchLocation, options: [SCNHitTestOption.searchMode : SCNHitTestSearchMode.closest.rawValue]) // Because 3D model loading can lead to composed nodes, we have to traverse through a node's parent until the parent node with the name assigned by the Flutter API is found let nodeHitResults: Array = allHitResults.compactMap { nearestParentWithNameStart(node: $0.node, characters: "[#")?.name } diff --git a/lib/managers/ar_session_manager.dart b/lib/managers/ar_session_manager.dart index 20d3b83a..4cb91502 100644 --- a/lib/managers/ar_session_manager.dart +++ b/lib/managers/ar_session_manager.dart @@ -29,8 +29,7 @@ class ARSessionManager { /// Receives hit results from user taps with tracked planes or feature points late ARHitResultHandler onPlaneOrPointTap; - ARSessionManager(int id, this.buildContext, this.planeDetectionConfig, - {this.debug = false}) { + ARSessionManager(int id, this.buildContext, this.planeDetectionConfig, {this.debug = false}) { _channel = MethodChannel('arsession_$id'); _channel.setMethodCallHandler(_platformCallHandler); if (debug) { @@ -41,8 +40,7 @@ class ARSessionManager { /// Returns the camera pose in Matrix4 format with respect to the world coordinate system of the [ARView] Future getCameraPose() async { try { - final serializedCameraPose = - await _channel.invokeMethod>('getCameraPose', {}); + final serializedCameraPose = await _channel.invokeMethod>('getCameraPose', {}); return MatrixConverter().fromJson(serializedCameraPose!); } catch (e) { print('Error caught: ' + e.toString()); @@ -50,14 +48,27 @@ class ARSessionManager { } } + /// Places anchor in given 2D coordinates (starting from the top-left side of the screen) + Future placeBasedOnScreenCoordinates(double x, double y) async { + try { + await _channel.invokeMethod>('placeBasedOnCoordinates', { + "x" : x, + "y" : y + }); + return true; + } catch (e) { + print('Error caught: ' + e.toString()); + return false; + } + } + /// Returns the given anchor pose in Matrix4 format with respect to the world coordinate system of the [ARView] Future getPose(ARAnchor anchor) async { try { if (anchor.name.isEmpty) { throw Exception("Anchor can not be resolved. Anchor name is empty."); } - final serializedCameraPose = - await _channel.invokeMethod>('getAnchorPose', { + final serializedCameraPose = await _channel.invokeMethod>('getAnchorPose', { "anchorId": anchor.name, }); return MatrixConverter().fromJson(serializedCameraPose!); @@ -68,8 +79,7 @@ class ARSessionManager { } /// Returns the distance in meters between @anchor1 and @anchor2. - Future getDistanceBetweenAnchors( - ARAnchor anchor1, ARAnchor anchor2) async { + Future getDistanceBetweenAnchors(ARAnchor anchor1, ARAnchor anchor2) async { var anchor1Pose = await getPose(anchor1); var anchor2Pose = await getPose(anchor2); var anchor1Translation = anchor1Pose?.getTranslation(); @@ -118,10 +128,7 @@ class ARSessionManager { case 'onPlaneOrPointTap': if (onPlaneOrPointTap != null) { final rawHitTestResults = call.arguments as List; - final serializedHitTestResults = rawHitTestResults - .map( - (hitTestResult) => Map.from(hitTestResult)) - .toList(); + final serializedHitTestResults = rawHitTestResults.map((hitTestResult) => Map.from(hitTestResult)).toList(); final hitTestResults = serializedHitTestResults.map((e) { return ARHitTestResult.fromJson(e); }).toList(); @@ -171,11 +178,7 @@ class ARSessionManager { /// Displays the [errorMessage] in a snackbar of the parent widget onError(String errorMessage) { ScaffoldMessenger.of(buildContext).showSnackBar(SnackBar( - content: Text(errorMessage), - action: SnackBarAction( - label: 'HIDE', - onPressed: - ScaffoldMessenger.of(buildContext).hideCurrentSnackBar))); + content: Text(errorMessage), action: SnackBarAction(label: 'HIDE', onPressed: ScaffoldMessenger.of(buildContext).hideCurrentSnackBar))); } /// Dispose the AR view on the platforms to pause the scenes and disconnect the platform handlers. From cd953460f9a9732d69fdc7682020c8eb3673993c Mon Sep 17 00:00:00 2001 From: denkoul Date: Thu, 14 Jul 2022 10:36:42 +0300 Subject: [PATCH 02/47] parse touch location --- .../lars/ar_flutter_plugin/AndroidARView.kt | 20 +++++++++++++ ios/Classes/IosARView.swift | 28 ++++++++++++------- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index 6ffb177b..b30236c5 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -116,6 +116,26 @@ internal class AndroidARView( result.error("Error", "could not get camera pose", null) } } + "placeBasedOnCoordinates" -> { + val cpuCoordinates = floatArrayOf(call.arguments['x'], call.arguments['y']) + val viewCoordinates = FloatArray(2) + if (arSceneView.arFrame != null) { + arSceneView.arFrame!!.transformCoordinates2d( + Coordinates2d.IMAGE_PIXELS, + cpuCoordinates, + Coordinates2d.VIEW, + viewCoordinates + ) + val allHitResults = arSceneView.arFrame!!.hitTest(viewCoordinates[0], viewCoordinates[1]) + val planeAndPointHitResults = allHitResults.filter { ((it.trackable is Plane) || (it.trackable is Point)) } + val serializedPlaneAndPointHitResults: ArrayList> = + ArrayList(planeAndPointHitResults.map { serializeHitResult(it) }) + result.success(serializedPlaneAndPointHitResults) + } else { + result.success(null) + } + + } "snapshot" -> { var bitmap = Bitmap.createBitmap(arSceneView.width, arSceneView.height, Bitmap.Config.ARGB_8888); diff --git a/ios/Classes/IosARView.swift b/ios/Classes/IosARView.swift index fa898b7b..7e1ef538 100644 --- a/ios/Classes/IosARView.swift +++ b/ios/Classes/IosARView.swift @@ -83,7 +83,8 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco break case "placeBasedOnCoordinates": let coordinates = CGPoint(x: CGFloat( arguments!["x"] as! Float), y: CGFloat( arguments!["y"] as! Float)); - parseTouchLocation(touchLocation: coordinates); + let htResult = parseTouchLocation(touchLocation: coordinates, returnHitResult: true); + result(htResult); break; case "getCameraPose": if let cameraPose = sceneView.session.currentFrame?.camera.transform { @@ -522,36 +523,43 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco guard let sceneView = recognizer.view as? ARSCNView else { return } - parseTouchLocation(touchLocation: recognizer.location(in: sceneView)) + parseTouchLocation(touchLocation: recognizer.location(in: sceneView), returnHitResult: false) } - func parseTouchLocation(touchLocation: CGPoint) { + func parseTouchLocation(touchLocation: CGPoint, returnHitResult: Bool) -> Any? { let allHitResults = sceneView.hitTest(touchLocation, options: [SCNHitTestOption.searchMode : SCNHitTestSearchMode.closest.rawValue]) // Because 3D model loading can lead to composed nodes, we have to traverse through a node's parent until the parent node with the name assigned by the Flutter API is found let nodeHitResults: Array = allHitResults.compactMap { nearestParentWithNameStart(node: $0.node, characters: "[#")?.name } - if (nodeHitResults.count != 0) { + if (nodeHitResults.count != 0 && !returnHitResult) { self.objectManagerChannel.invokeMethod("onNodeTap", arguments: Array(Set(nodeHitResults))) // Chaining of Array and Set is used to remove duplicates - return + return nil; } - + let planeTypes: ARHitTestResult.ResultType if #available(iOS 11.3, *){ planeTypes = ARHitTestResult.ResultType([.existingPlaneUsingGeometry, .featurePoint]) }else { planeTypes = ARHitTestResult.ResultType([.existingPlaneUsingExtent, .featurePoint]) } - + let planeAndPointHitResults = sceneView.hitTest(touchLocation, types: planeTypes) - + // store the alignment of the tapped plane anchor so we can refer to is later when transforming the node if planeAndPointHitResults.count > 0, let hitAnchor = planeAndPointHitResults.first?.anchor as? ARPlaneAnchor { self.tappedPlaneAnchorAlignment = hitAnchor.alignment } - + let serializedPlaneAndPointHitResults = planeAndPointHitResults.map{serializeHitResult($0)} if (serializedPlaneAndPointHitResults.count != 0) { - self.sessionManagerChannel.invokeMethod("onPlaneOrPointTap", arguments: serializedPlaneAndPointHitResults) + + if (returnHitResult) { + return serializedPlaneAndPointHitResults; + } else { + self.sessionManagerChannel.invokeMethod("onPlaneOrPointTap", arguments: serializedPlaneAndPointHitResults) + } + } + return nil; } @objc func handlePan(_ recognizer: UIPanGestureRecognizer) { From 3306369332162c14d8f553510eb2b1a97401232d Mon Sep 17 00:00:00 2001 From: denkoul Date: Thu, 14 Jul 2022 10:39:31 +0300 Subject: [PATCH 03/47] fix session mgr --- lib/managers/ar_session_manager.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/managers/ar_session_manager.dart b/lib/managers/ar_session_manager.dart index 4cb91502..c7360d91 100644 --- a/lib/managers/ar_session_manager.dart +++ b/lib/managers/ar_session_manager.dart @@ -49,16 +49,15 @@ class ARSessionManager { } /// Places anchor in given 2D coordinates (starting from the top-left side of the screen) - Future placeBasedOnScreenCoordinates(double x, double y) async { + Future placeBasedOnScreenCoordinates(double x, double y) async { try { - await _channel.invokeMethod>('placeBasedOnCoordinates', { + return await _channel.invokeMethod>('placeBasedOnCoordinates', { "x" : x, "y" : y }); - return true; } catch (e) { print('Error caught: ' + e.toString()); - return false; + return null; } } From 3015c0f7c11d4c3bfd3a463fa5af43355c8bafeb Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Fri, 7 Oct 2022 17:06:14 +0300 Subject: [PATCH 04/47] fix minor android issue --- .../lars/ar_flutter_plugin/AndroidARView.kt | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index b30236c5..30540179 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -117,24 +117,27 @@ internal class AndroidARView( } } "placeBasedOnCoordinates" -> { - val cpuCoordinates = floatArrayOf(call.arguments['x'], call.arguments['y']) - val viewCoordinates = FloatArray(2) - if (arSceneView.arFrame != null) { - arSceneView.arFrame!!.transformCoordinates2d( - Coordinates2d.IMAGE_PIXELS, - cpuCoordinates, - Coordinates2d.VIEW, - viewCoordinates - ) - val allHitResults = arSceneView.arFrame!!.hitTest(viewCoordinates[0], viewCoordinates[1]) - val planeAndPointHitResults = allHitResults.filter { ((it.trackable is Plane) || (it.trackable is Point)) } - val serializedPlaneAndPointHitResults: ArrayList> = - ArrayList(planeAndPointHitResults.map { serializeHitResult(it) }) - result.success(serializedPlaneAndPointHitResults) + if (call.arguments is Map<*,*>) { + val cpuCoordinates = floatArrayOf((call.arguments as Map<*, *>)['x'] as Float, (call.arguments as Map<*, *>)['y'] as Float) + val viewCoordinates = FloatArray(2) + if (arSceneView.arFrame != null) { + arSceneView.arFrame!!.transformCoordinates2d( + Coordinates2d.IMAGE_PIXELS, + cpuCoordinates, + Coordinates2d.VIEW, + viewCoordinates + ) + val allHitResults = arSceneView.arFrame!!.hitTest(viewCoordinates[0], viewCoordinates[1]) + val planeAndPointHitResults = allHitResults.filter { ((it.trackable is Plane) || (it.trackable is Point)) } + val serializedPlaneAndPointHitResults: ArrayList> = + ArrayList(planeAndPointHitResults.map { serializeHitResult(it) }) + result.success(serializedPlaneAndPointHitResults) + } else { + result.success(null) + } } else { result.success(null) } - } "snapshot" -> { var bitmap = Bitmap.createBitmap(arSceneView.width, arSceneView.height, From 3b1dc9c66e8cf4c66d6d03b119b50d9c53bed30b Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 14:55:39 +0300 Subject: [PATCH 05/47] fixes --- ios/ar_flutter_plugin.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index 4af5e5f8..311ad4d4 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -20,7 +20,7 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. s.static_framework = true #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' #s.dependency 'ARCore', '~> 1.2.0' - s.dependency 'ARCore/CloudAnchors', '~> 1.32.0' + s.dependency 'ARCore/CloudAnchors', '~> 1.34.0' s.platform = :ios, '13.0' From 24830c2495ddd291d719aea37293f9f210d88a91 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 14:59:05 +0300 Subject: [PATCH 06/47] core --- ios/ar_flutter_plugin.podspec | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index 311ad4d4..e4d4782b 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -21,6 +21,7 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' #s.dependency 'ARCore', '~> 1.2.0' s.dependency 'ARCore/CloudAnchors', '~> 1.34.0' + s.dependency 'GTMSessionFetcher/Core', '~> 2.1' s.platform = :ios, '13.0' From 7d117e1eb4d07ff4c016db9f7f372e2a0f0df0f1 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 15:00:08 +0300 Subject: [PATCH 07/47] remove core --- ios/ar_flutter_plugin.podspec | 1 - 1 file changed, 1 deletion(-) diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index e4d4782b..311ad4d4 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -21,7 +21,6 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' #s.dependency 'ARCore', '~> 1.2.0' s.dependency 'ARCore/CloudAnchors', '~> 1.34.0' - s.dependency 'GTMSessionFetcher/Core', '~> 2.1' s.platform = :ios, '13.0' From 5389f11b64bb2e92b45fb0f1669e4643ddd35eed Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 15:18:55 +0300 Subject: [PATCH 08/47] upgrade android versions --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index dbdff724..9f34b800 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -37,7 +37,7 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.google.ar:core:1.22.0" + implementation "com.google.ar:core:1.33.0" implementation 'com.google.ar.sceneform:core:1.15.0' implementation 'com.google.ar.sceneform:assets:1.15.0' From a63245deeb1d33e2776dffa6a04b2d43717dff83 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 17:10:38 +0300 Subject: [PATCH 09/47] detach anchors --- .../kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index 30540179..2aa63865 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -475,6 +475,9 @@ internal class AndroidARView( fun onDestroy() { try { + for (anchor in arSceneView.session!!.allAnchors) { + anchor?.detach(); + } arSceneView.session?.close() arSceneView.destroy() arSceneView.scene?.removeOnUpdateListener(sceneUpdateListener) From 1728864115ff16cd2b2a8a6ca923248da19f20d3 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 17:18:45 +0300 Subject: [PATCH 10/47] prints --- .../kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index 2aa63865..acd93955 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -476,7 +476,8 @@ internal class AndroidARView( fun onDestroy() { try { for (anchor in arSceneView.session!!.allAnchors) { - anchor?.detach(); + Log.d(TAG, "detaching" + anchor?.cloudAnchorId) + anchor?.detach() } arSceneView.session?.close() arSceneView.destroy() @@ -488,6 +489,7 @@ internal class AndroidARView( } private fun initializeARView(call: MethodCall, result: MethodChannel.Result) { + Log.d(TAG, "initializeARView") // Unpack call arguments val argShowFeaturePoints: Boolean? = call.argument("showFeaturePoints") val argPlaneDetectionConfig: Int? = call.argument("planeDetectionConfig") From 873a41d1ad9f256066e07c8aec8645b7d97990d6 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 20:00:54 +0300 Subject: [PATCH 11/47] remove active notes before finish --- .../kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt | 1 - lib/managers/ar_session_manager.dart | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index acd93955..08067a36 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -476,7 +476,6 @@ internal class AndroidARView( fun onDestroy() { try { for (anchor in arSceneView.session!!.allAnchors) { - Log.d(TAG, "detaching" + anchor?.cloudAnchorId) anchor?.detach() } arSceneView.session?.close() diff --git a/lib/managers/ar_session_manager.dart b/lib/managers/ar_session_manager.dart index c7360d91..d36aeb66 100644 --- a/lib/managers/ar_session_manager.dart +++ b/lib/managers/ar_session_manager.dart @@ -183,6 +183,7 @@ class ARSessionManager { /// Dispose the AR view on the platforms to pause the scenes and disconnect the platform handlers. /// You should call this before removing the AR view to prevent out of memory erros dispose() async { + print('calling dispose from flutter'); try { await _channel.invokeMethod("dispose"); } catch (e) { From c6188e44cac839e6a58706c1b44d6e86692eb450 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 20:24:06 +0300 Subject: [PATCH 12/47] minor upgrade dep --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 9f34b800..043d9820 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -37,7 +37,7 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.google.ar:core:1.33.0" + implementation "com.google.ar:core:1.34.0" implementation 'com.google.ar.sceneform:core:1.15.0' implementation 'com.google.ar.sceneform:assets:1.15.0' From 692a36a61897299ea95915d29727b2ce627b75e4 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 20:31:07 +0300 Subject: [PATCH 13/47] fixes --- android/build.gradle | 2 +- .../io/carius/lars/ar_flutter_plugin/AndroidARView.kt | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 043d9820..9f34b800 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -37,7 +37,7 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.google.ar:core:1.34.0" + implementation "com.google.ar:core:1.33.0" implementation 'com.google.ar.sceneform:core:1.15.0' implementation 'com.google.ar.sceneform:assets:1.15.0' diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index 08067a36..1101bf46 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -475,9 +475,12 @@ internal class AndroidARView( fun onDestroy() { try { - for (anchor in arSceneView.session!!.allAnchors) { - anchor?.detach() + if (arSceneView.session != null) { + for (anchor in arSceneView.session!!.allAnchors) { + anchor?.detach() + } } + arSceneView.session?.close() arSceneView.destroy() arSceneView.scene?.removeOnUpdateListener(sceneUpdateListener) From 828c1fbe440a15189061e413b4410f7d704663ad Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Thu, 27 Oct 2022 11:12:09 +0300 Subject: [PATCH 14/47] upgrade sceneform detach anchors before closing scene view --- android/build.gradle | 7 ++++--- .../lars/ar_flutter_plugin/AndroidARView.kt | 21 ++++++------------- .../ar_flutter_plugin/CloudAnchorHandler.kt | 10 ++++++++- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 9f34b800..9edd61c4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -37,14 +37,15 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.google.ar:core:1.33.0" + implementation "com.google.ar:core:1.34.0" - implementation 'com.google.ar.sceneform:core:1.15.0' - implementation 'com.google.ar.sceneform:assets:1.15.0' + implementation 'com.google.ar.sceneform:core:1.17.1' + implementation 'com.google.ar.sceneform:assets:1.17.1' implementation 'com.google.android.gms:play-services-auth:16+' implementation 'com.google.ar.sceneform.ux:sceneform-ux:1.17.1' implementation 'androidx.appcompat:appcompat:1.3.0' + } afterEvaluate { diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index 1101bf46..2e3d8f06 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -39,18 +39,9 @@ import com.google.ar.sceneform.rendering.* import android.view.ViewGroup import com.google.ar.core.TrackingState - - - - - - - - - - - - +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking internal class AndroidARView( @@ -480,11 +471,11 @@ internal class AndroidARView( anchor?.detach() } } - - arSceneView.session?.close() - arSceneView.destroy() + cloudAnchorHandler.dispose(); arSceneView.scene?.removeOnUpdateListener(sceneUpdateListener) arSceneView.scene?.removeOnPeekTouchListener(onNodeTapListener) + arSceneView.session?.close() + arSceneView.destroy() }catch (e : Exception){ e.printStackTrace(); } diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/CloudAnchorHandler.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/CloudAnchorHandler.kt index 5e0724d4..b73cd667 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/CloudAnchorHandler.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/CloudAnchorHandler.kt @@ -15,7 +15,7 @@ internal class CloudAnchorHandler( arSession: Session ) { } private val TAG: String = CloudAnchorHandler::class.java.simpleName - private val pendingAnchors = HashMap>() + val pendingAnchors = HashMap>() private val session: Session = arSession @Synchronized @@ -52,6 +52,14 @@ internal class CloudAnchorHandler( arSession: Session ) { } } + @Synchronized + fun dispose() { + for (pendingAnchor in pendingAnchors) { + pendingAnchor.key.detach() + } + clearListeners() + } + // Remove all listeners @Synchronized fun clearListeners() { From d76e03f0613f199f5015e43f769a47c58c45ea61 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Thu, 27 Oct 2022 14:22:10 +0300 Subject: [PATCH 15/47] revert ios version --- ios/ar_flutter_plugin.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index 311ad4d4..4af5e5f8 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -20,7 +20,7 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. s.static_framework = true #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' #s.dependency 'ARCore', '~> 1.2.0' - s.dependency 'ARCore/CloudAnchors', '~> 1.34.0' + s.dependency 'ARCore/CloudAnchors', '~> 1.32.0' s.platform = :ios, '13.0' From 4653a6c96adf9796cc3193dfe8bbcda4e57e5cb4 Mon Sep 17 00:00:00 2001 From: "dnkoulouris@macbook" Date: Thu, 15 Dec 2022 16:46:29 +0200 Subject: [PATCH 16/47] update arcore api to 1.35.0 --- android/build.gradle | 2 +- ios/Classes/JWTGenerator.swift | 2 +- ios/ar_flutter_plugin.podspec | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 9edd61c4..db8e9dca 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -37,7 +37,7 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.google.ar:core:1.34.0" + implementation "com.google.ar:core:1.35.0" implementation 'com.google.ar.sceneform:core:1.17.1' implementation 'com.google.ar.sceneform:assets:1.17.1' diff --git a/ios/Classes/JWTGenerator.swift b/ios/Classes/JWTGenerator.swift index f5c509b4..32a23799 100644 --- a/ios/Classes/JWTGenerator.swift +++ b/ios/Classes/JWTGenerator.swift @@ -36,7 +36,7 @@ class JWTGenerator { let exp: Date let aud: String } - let jwtTokenClaims = JWTTokenClaims(iss: clientEmail, sub: clientEmail, iat: Date(), exp: Date(timeIntervalSinceNow: 3600), aud: "https://arcorecloudanchor.googleapis.com/") + let jwtTokenClaims = JWTTokenClaims(iss: clientEmail, sub: clientEmail, iat: Date(), exp: Date(timeIntervalSinceNow: 3600), aud: "https://arcore.googleapis.com/") var jwtToken = JWT(header: jwtTokenHeader, claims: jwtTokenClaims) diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index 4af5e5f8..a9badd29 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -20,7 +20,7 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. s.static_framework = true #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' #s.dependency 'ARCore', '~> 1.2.0' - s.dependency 'ARCore/CloudAnchors', '~> 1.32.0' + s.dependency 'ARCore/CloudAnchors', '~> 1.35.0' s.platform = :ios, '13.0' From 16fa29a8d30a3422c33631486bf3de3e50d3dcb2 Mon Sep 17 00:00:00 2001 From: Jonathan Cole Date: Fri, 23 Dec 2022 14:13:38 -0500 Subject: [PATCH 17/47] Bump up ARCore version to 1.33 for Apple Silicon (#164) https://github.com/google-ar/arcore-ios-sdk/issues/59#issuecomment-1219756010 --- ios/ar_flutter_plugin.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index 4af5e5f8..7ded92d5 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -20,7 +20,7 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. s.static_framework = true #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' #s.dependency 'ARCore', '~> 1.2.0' - s.dependency 'ARCore/CloudAnchors', '~> 1.32.0' + s.dependency 'ARCore/CloudAnchors', '~> 1.33.0' # Updated from 1.32 to 1.33 to support Apple Silicon, info here: https://github.com/google-ar/arcore-ios-sdk/issues/59#issuecomment-1219756010 s.platform = :ios, '13.0' From e67bf7f81587b8732e02098bc925af969fc9cde9 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Tue, 10 Jan 2023 17:34:25 +0200 Subject: [PATCH 18/47] fixes --- ios/ar_flutter_plugin.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index a9badd29..ecb91b21 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -20,7 +20,7 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. s.static_framework = true #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' #s.dependency 'ARCore', '~> 1.2.0' - s.dependency 'ARCore/CloudAnchors', '~> 1.35.0' + s.dependency 'ARCore/CloudAnchors', '~> 1.33.0' s.platform = :ios, '13.0' From 3f0e74bfbc40b083b29da55a0d16693ab6f0a759 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Tue, 10 Jan 2023 17:34:55 +0200 Subject: [PATCH 19/47] fixes --- ios/ar_flutter_plugin.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index ecb91b21..a9badd29 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -20,7 +20,7 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. s.static_framework = true #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' #s.dependency 'ARCore', '~> 1.2.0' - s.dependency 'ARCore/CloudAnchors', '~> 1.33.0' + s.dependency 'ARCore/CloudAnchors', '~> 1.35.0' s.platform = :ios, '13.0' From 795ee0c14ad8947a4c96d4b209a03916da131ff8 Mon Sep 17 00:00:00 2001 From: denkoul Date: Thu, 14 Jul 2022 10:23:26 +0300 Subject: [PATCH 20/47] upgrades --- ios/Classes/IosARView.swift | 68 ++++++++++++++-------------- lib/managers/ar_session_manager.dart | 37 ++++++++------- 2 files changed, 55 insertions(+), 50 deletions(-) diff --git a/ios/Classes/IosARView.swift b/ios/Classes/IosARView.swift index 49b239fc..f70ec878 100644 --- a/ios/Classes/IosARView.swift +++ b/ios/Classes/IosARView.swift @@ -81,6 +81,10 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco //result(nil) initializeARView(arguments: arguments!, result: result) break + case "placeBasedOnCoordinates": + let coordinates = CGPoint(x: CGFloat( arguments!["x"] as! Float), y: CGFloat( arguments!["y"] as! Float)); + parseTouchLocation(touchLocation: coordinates); + break; case "getCameraPose": if let cameraPose = sceneView.session.currentFrame?.camera.transform { result(serializeMatrix(cameraPose)) @@ -116,7 +120,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco func onObjectMethodCalled(_ call :FlutterMethodCall, _ result: @escaping FlutterResult) { let arguments = call.arguments as? Dictionary - + switch call.method { case "init": self.objectManagerChannel.invokeMethod("onError", arguments: ["ObjectTEST from iOS"]) @@ -153,7 +157,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco func onAnchorMethodCalled(_ call :FlutterMethodCall, _ result: @escaping FlutterResult) { let arguments = call.arguments as? Dictionary - + switch call.method { case "init": self.objectManagerChannel.invokeMethod("onError", arguments: ["ObjectTEST from iOS"]) @@ -171,7 +175,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco break default: result(false) - + } } result(nil) @@ -190,11 +194,11 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco arcoreSession?.setConfiguration(configuration, error: nil); if let token = JWTGenerator().generateWebToken(){ arcoreSession!.setAuthToken(token) - + cloudAnchorHandler = CloudAnchorHandler(session: arcoreSession!) arcoreSession!.delegate = cloudAnchorHandler arcoreSession!.delegateQueue = DispatchQueue.main - + arcoreMode = true } else { sessionManagerChannel.invokeMethod("onError", arguments: ["Error generating JWT, have you added cloudAnchorKey.json into the example/ios/Runner directory?"]) @@ -202,7 +206,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco } else { sessionManagerChannel.invokeMethod("onError", arguments: ["Error initializing Google AR Session"]) } - + break case "uploadAnchor": if let anchorName = arguments!["name"] as? String, let anchor = anchorCollection[anchorName] { @@ -233,18 +237,18 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco self.configuration.environmentTexturing = .automatic if let planeDetectionConfig = arguments["planeDetectionConfig"] as? Int { switch planeDetectionConfig { - case 1: + case 1: configuration.planeDetection = .horizontal - - case 2: + + case 2: if #available(iOS 11.3, *) { configuration.planeDetection = .vertical } - case 3: + case 3: if #available(iOS 11.3, *) { configuration.planeDetection = [.horizontal, .vertical] } - default: + default: configuration.planeDetection = [] } } @@ -281,7 +285,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco } } self.sceneView.debugOptions = ARSCNDebugOptions(rawValue: debugOptions) - + if let configHandleTaps = arguments["handleTaps"] as? Bool { if (configHandleTaps){ let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:))) @@ -298,7 +302,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco self.sceneView.gestureRecognizers?.append(panGestureRecognizer) } } - + if let configHandleRotation = arguments["handleRotation"] as? Bool { if (configHandleRotation){ let rotationGestureRecognizer = UIRotationGestureRecognizer(target: self, action: #selector(handleRotation(_:))) @@ -306,7 +310,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco self.sceneView.gestureRecognizers?.append(rotationGestureRecognizer) } } - + // Add coaching view if let configShowAnimatedGuide = arguments["showAnimatedGuide"] as? Bool { if configShowAnimatedGuide { @@ -336,13 +340,13 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco } } } - + // Update session configuration self.sceneView.session.run(configuration) } func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) { - + if let planeAnchor = anchor as? ARPlaneAnchor{ let plane = modelBuilder.makePlane(anchor: planeAnchor, flutterAssetFile: customPlaneTexturePath) trackedPlanes[anchor.identifier] = (node, plane) @@ -353,7 +357,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco } func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) { - + if let planeAnchor = anchor as? ARPlaneAnchor, let plane = trackedPlanes[anchor.identifier] { modelBuilder.updatePlaneNode(planeNode: plane.1, anchor: planeAnchor) } @@ -362,7 +366,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco func renderer(_ renderer: SCNSceneRenderer, didRemove node: SCNNode, for anchor: ARAnchor) { trackedPlanes.removeValue(forKey: anchor.identifier) } - + func session(_ session: ARSession, didUpdate frame: ARFrame) { if (arcoreMode) { do { @@ -376,7 +380,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco func addNode(dict_node: Dictionary, dict_anchor: Dictionary? = nil) -> Future { return Future {promise in - + switch (dict_node["type"] as! Int) { case 0: // GLTF2 Model from Flutter asset folder // Get path to given Flutter asset @@ -389,14 +393,13 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco if let anchor = self.anchorCollection[anchorName]{ // Attach node to the top-level node of the specified anchor self.sceneView.node(for: anchor)?.addChildNode(node) - promise(.success(true)) } else { promise(.success(false)) } default: promise(.success(false)) } - + } else { // Attach to top-level node of the scene self.sceneView.scene.rootNode.addChildNode(node) @@ -421,14 +424,13 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco if let anchor = self.anchorCollection[anchorName]{ // Attach node to the top-level node of the specified anchor self.sceneView.node(for: anchor)?.addChildNode(node) - promise(.success(true)) } else { promise(.success(false)) } default: promise(.success(false)) } - + } else { // Attach to top-level node of the scene self.sceneView.scene.rootNode.addChildNode(node) @@ -446,7 +448,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) let documentsDirectory = paths[0] let targetPath = documentsDirectory.appendingPathComponent(dict_node["uri"] as! String).path - + // Add object to scene if let node: SCNNode = self.modelBuilder.makeNodeFromFileSystemGLB(name: dict_node["name"] as! String, modelPath: targetPath, transformation: dict_node["transformation"] as? Array) { if let anchorName = dict_anchor?["name"] as? String, let anchorType = dict_anchor?["type"] as? Int { @@ -455,14 +457,13 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco if let anchor = self.anchorCollection[anchorName]{ // Attach node to the top-level node of the specified anchor self.sceneView.node(for: anchor)?.addChildNode(node) - promise(.success(true)) } else { promise(.success(false)) } default: promise(.success(false)) } - + } else { // Attach to top-level node of the scene self.sceneView.scene.rootNode.addChildNode(node) @@ -488,14 +489,13 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco if let anchor = self.anchorCollection[anchorName]{ // Attach node to the top-level node of the specified anchor self.sceneView.node(for: anchor)?.addChildNode(node) - promise(.success(true)) } else { promise(.success(false)) } default: promise(.success(false)) } - + } else { // Attach to top-level node of the scene self.sceneView.scene.rootNode.addChildNode(node) @@ -510,21 +510,23 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco default: promise(.success(false)) } - + } } - + func transformNode(name: String, transform: Array) { let node = sceneView.scene.rootNode.childNode(withName: name, recursively: true) node?.transform = deserializeMatrix4(transform) } - + @objc func handleTap(_ recognizer: UITapGestureRecognizer) { guard let sceneView = recognizer.view as? ARSCNView else { return } - let touchLocation = recognizer.location(in: sceneView) - + parseTouchLocation(touchLocation: recognizer.location(in: sceneView)) + } + + func parseTouchLocation(touchLocation: CGPoint) { let allHitResults = sceneView.hitTest(touchLocation, options: [SCNHitTestOption.searchMode : SCNHitTestSearchMode.closest.rawValue]) // Because 3D model loading can lead to composed nodes, we have to traverse through a node's parent until the parent node with the name assigned by the Flutter API is found let nodeHitResults: Array = allHitResults.compactMap { nearestParentWithNameStart(node: $0.node, characters: "[#")?.name } diff --git a/lib/managers/ar_session_manager.dart b/lib/managers/ar_session_manager.dart index 20d3b83a..4cb91502 100644 --- a/lib/managers/ar_session_manager.dart +++ b/lib/managers/ar_session_manager.dart @@ -29,8 +29,7 @@ class ARSessionManager { /// Receives hit results from user taps with tracked planes or feature points late ARHitResultHandler onPlaneOrPointTap; - ARSessionManager(int id, this.buildContext, this.planeDetectionConfig, - {this.debug = false}) { + ARSessionManager(int id, this.buildContext, this.planeDetectionConfig, {this.debug = false}) { _channel = MethodChannel('arsession_$id'); _channel.setMethodCallHandler(_platformCallHandler); if (debug) { @@ -41,8 +40,7 @@ class ARSessionManager { /// Returns the camera pose in Matrix4 format with respect to the world coordinate system of the [ARView] Future getCameraPose() async { try { - final serializedCameraPose = - await _channel.invokeMethod>('getCameraPose', {}); + final serializedCameraPose = await _channel.invokeMethod>('getCameraPose', {}); return MatrixConverter().fromJson(serializedCameraPose!); } catch (e) { print('Error caught: ' + e.toString()); @@ -50,14 +48,27 @@ class ARSessionManager { } } + /// Places anchor in given 2D coordinates (starting from the top-left side of the screen) + Future placeBasedOnScreenCoordinates(double x, double y) async { + try { + await _channel.invokeMethod>('placeBasedOnCoordinates', { + "x" : x, + "y" : y + }); + return true; + } catch (e) { + print('Error caught: ' + e.toString()); + return false; + } + } + /// Returns the given anchor pose in Matrix4 format with respect to the world coordinate system of the [ARView] Future getPose(ARAnchor anchor) async { try { if (anchor.name.isEmpty) { throw Exception("Anchor can not be resolved. Anchor name is empty."); } - final serializedCameraPose = - await _channel.invokeMethod>('getAnchorPose', { + final serializedCameraPose = await _channel.invokeMethod>('getAnchorPose', { "anchorId": anchor.name, }); return MatrixConverter().fromJson(serializedCameraPose!); @@ -68,8 +79,7 @@ class ARSessionManager { } /// Returns the distance in meters between @anchor1 and @anchor2. - Future getDistanceBetweenAnchors( - ARAnchor anchor1, ARAnchor anchor2) async { + Future getDistanceBetweenAnchors(ARAnchor anchor1, ARAnchor anchor2) async { var anchor1Pose = await getPose(anchor1); var anchor2Pose = await getPose(anchor2); var anchor1Translation = anchor1Pose?.getTranslation(); @@ -118,10 +128,7 @@ class ARSessionManager { case 'onPlaneOrPointTap': if (onPlaneOrPointTap != null) { final rawHitTestResults = call.arguments as List; - final serializedHitTestResults = rawHitTestResults - .map( - (hitTestResult) => Map.from(hitTestResult)) - .toList(); + final serializedHitTestResults = rawHitTestResults.map((hitTestResult) => Map.from(hitTestResult)).toList(); final hitTestResults = serializedHitTestResults.map((e) { return ARHitTestResult.fromJson(e); }).toList(); @@ -171,11 +178,7 @@ class ARSessionManager { /// Displays the [errorMessage] in a snackbar of the parent widget onError(String errorMessage) { ScaffoldMessenger.of(buildContext).showSnackBar(SnackBar( - content: Text(errorMessage), - action: SnackBarAction( - label: 'HIDE', - onPressed: - ScaffoldMessenger.of(buildContext).hideCurrentSnackBar))); + content: Text(errorMessage), action: SnackBarAction(label: 'HIDE', onPressed: ScaffoldMessenger.of(buildContext).hideCurrentSnackBar))); } /// Dispose the AR view on the platforms to pause the scenes and disconnect the platform handlers. From fb697c09abf7e0f616ddc54d34ee9295dbb46c93 Mon Sep 17 00:00:00 2001 From: denkoul Date: Thu, 14 Jul 2022 10:36:42 +0300 Subject: [PATCH 21/47] parse touch location --- .../lars/ar_flutter_plugin/AndroidARView.kt | 20 +++++++++++++ ios/Classes/IosARView.swift | 28 ++++++++++++------- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index 6ffb177b..b30236c5 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -116,6 +116,26 @@ internal class AndroidARView( result.error("Error", "could not get camera pose", null) } } + "placeBasedOnCoordinates" -> { + val cpuCoordinates = floatArrayOf(call.arguments['x'], call.arguments['y']) + val viewCoordinates = FloatArray(2) + if (arSceneView.arFrame != null) { + arSceneView.arFrame!!.transformCoordinates2d( + Coordinates2d.IMAGE_PIXELS, + cpuCoordinates, + Coordinates2d.VIEW, + viewCoordinates + ) + val allHitResults = arSceneView.arFrame!!.hitTest(viewCoordinates[0], viewCoordinates[1]) + val planeAndPointHitResults = allHitResults.filter { ((it.trackable is Plane) || (it.trackable is Point)) } + val serializedPlaneAndPointHitResults: ArrayList> = + ArrayList(planeAndPointHitResults.map { serializeHitResult(it) }) + result.success(serializedPlaneAndPointHitResults) + } else { + result.success(null) + } + + } "snapshot" -> { var bitmap = Bitmap.createBitmap(arSceneView.width, arSceneView.height, Bitmap.Config.ARGB_8888); diff --git a/ios/Classes/IosARView.swift b/ios/Classes/IosARView.swift index f70ec878..f036ca68 100644 --- a/ios/Classes/IosARView.swift +++ b/ios/Classes/IosARView.swift @@ -83,7 +83,8 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco break case "placeBasedOnCoordinates": let coordinates = CGPoint(x: CGFloat( arguments!["x"] as! Float), y: CGFloat( arguments!["y"] as! Float)); - parseTouchLocation(touchLocation: coordinates); + let htResult = parseTouchLocation(touchLocation: coordinates, returnHitResult: true); + result(htResult); break; case "getCameraPose": if let cameraPose = sceneView.session.currentFrame?.camera.transform { @@ -523,36 +524,43 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco guard let sceneView = recognizer.view as? ARSCNView else { return } - parseTouchLocation(touchLocation: recognizer.location(in: sceneView)) + parseTouchLocation(touchLocation: recognizer.location(in: sceneView), returnHitResult: false) } - func parseTouchLocation(touchLocation: CGPoint) { + func parseTouchLocation(touchLocation: CGPoint, returnHitResult: Bool) -> Any? { let allHitResults = sceneView.hitTest(touchLocation, options: [SCNHitTestOption.searchMode : SCNHitTestSearchMode.closest.rawValue]) // Because 3D model loading can lead to composed nodes, we have to traverse through a node's parent until the parent node with the name assigned by the Flutter API is found let nodeHitResults: Array = allHitResults.compactMap { nearestParentWithNameStart(node: $0.node, characters: "[#")?.name } - if (nodeHitResults.count != 0) { + if (nodeHitResults.count != 0 && !returnHitResult) { self.objectManagerChannel.invokeMethod("onNodeTap", arguments: Array(Set(nodeHitResults))) // Chaining of Array and Set is used to remove duplicates - return + return nil; } - + let planeTypes: ARHitTestResult.ResultType if #available(iOS 11.3, *){ planeTypes = ARHitTestResult.ResultType([.existingPlaneUsingGeometry, .featurePoint]) }else { planeTypes = ARHitTestResult.ResultType([.existingPlaneUsingExtent, .featurePoint]) } - + let planeAndPointHitResults = sceneView.hitTest(touchLocation, types: planeTypes) - + // store the alignment of the tapped plane anchor so we can refer to is later when transforming the node if planeAndPointHitResults.count > 0, let hitAnchor = planeAndPointHitResults.first?.anchor as? ARPlaneAnchor { self.tappedPlaneAnchorAlignment = hitAnchor.alignment } - + let serializedPlaneAndPointHitResults = planeAndPointHitResults.map{serializeHitResult($0)} if (serializedPlaneAndPointHitResults.count != 0) { - self.sessionManagerChannel.invokeMethod("onPlaneOrPointTap", arguments: serializedPlaneAndPointHitResults) + + if (returnHitResult) { + return serializedPlaneAndPointHitResults; + } else { + self.sessionManagerChannel.invokeMethod("onPlaneOrPointTap", arguments: serializedPlaneAndPointHitResults) + } + } + return nil; } @objc func handlePan(_ recognizer: UIPanGestureRecognizer) { From e5e97b45534aa97a3044c43070787a345c280cf3 Mon Sep 17 00:00:00 2001 From: denkoul Date: Thu, 14 Jul 2022 10:39:31 +0300 Subject: [PATCH 22/47] fix session mgr --- lib/managers/ar_session_manager.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/managers/ar_session_manager.dart b/lib/managers/ar_session_manager.dart index 4cb91502..c7360d91 100644 --- a/lib/managers/ar_session_manager.dart +++ b/lib/managers/ar_session_manager.dart @@ -49,16 +49,15 @@ class ARSessionManager { } /// Places anchor in given 2D coordinates (starting from the top-left side of the screen) - Future placeBasedOnScreenCoordinates(double x, double y) async { + Future placeBasedOnScreenCoordinates(double x, double y) async { try { - await _channel.invokeMethod>('placeBasedOnCoordinates', { + return await _channel.invokeMethod>('placeBasedOnCoordinates', { "x" : x, "y" : y }); - return true; } catch (e) { print('Error caught: ' + e.toString()); - return false; + return null; } } From 11d98d6afb4b4ae303d8a1d144d1ced78ea2e3d2 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Fri, 7 Oct 2022 17:06:14 +0300 Subject: [PATCH 23/47] fix minor android issue --- .../lars/ar_flutter_plugin/AndroidARView.kt | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index b30236c5..30540179 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -117,24 +117,27 @@ internal class AndroidARView( } } "placeBasedOnCoordinates" -> { - val cpuCoordinates = floatArrayOf(call.arguments['x'], call.arguments['y']) - val viewCoordinates = FloatArray(2) - if (arSceneView.arFrame != null) { - arSceneView.arFrame!!.transformCoordinates2d( - Coordinates2d.IMAGE_PIXELS, - cpuCoordinates, - Coordinates2d.VIEW, - viewCoordinates - ) - val allHitResults = arSceneView.arFrame!!.hitTest(viewCoordinates[0], viewCoordinates[1]) - val planeAndPointHitResults = allHitResults.filter { ((it.trackable is Plane) || (it.trackable is Point)) } - val serializedPlaneAndPointHitResults: ArrayList> = - ArrayList(planeAndPointHitResults.map { serializeHitResult(it) }) - result.success(serializedPlaneAndPointHitResults) + if (call.arguments is Map<*,*>) { + val cpuCoordinates = floatArrayOf((call.arguments as Map<*, *>)['x'] as Float, (call.arguments as Map<*, *>)['y'] as Float) + val viewCoordinates = FloatArray(2) + if (arSceneView.arFrame != null) { + arSceneView.arFrame!!.transformCoordinates2d( + Coordinates2d.IMAGE_PIXELS, + cpuCoordinates, + Coordinates2d.VIEW, + viewCoordinates + ) + val allHitResults = arSceneView.arFrame!!.hitTest(viewCoordinates[0], viewCoordinates[1]) + val planeAndPointHitResults = allHitResults.filter { ((it.trackable is Plane) || (it.trackable is Point)) } + val serializedPlaneAndPointHitResults: ArrayList> = + ArrayList(planeAndPointHitResults.map { serializeHitResult(it) }) + result.success(serializedPlaneAndPointHitResults) + } else { + result.success(null) + } } else { result.success(null) } - } "snapshot" -> { var bitmap = Bitmap.createBitmap(arSceneView.width, arSceneView.height, From dd760f926a86ebb088006266e749f739721eae72 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 14:55:39 +0300 Subject: [PATCH 24/47] fixes --- ios/ar_flutter_plugin.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index 7ded92d5..311ad4d4 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -20,7 +20,7 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. s.static_framework = true #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' #s.dependency 'ARCore', '~> 1.2.0' - s.dependency 'ARCore/CloudAnchors', '~> 1.33.0' # Updated from 1.32 to 1.33 to support Apple Silicon, info here: https://github.com/google-ar/arcore-ios-sdk/issues/59#issuecomment-1219756010 + s.dependency 'ARCore/CloudAnchors', '~> 1.34.0' s.platform = :ios, '13.0' From 20dbfeea985e5737ccc17641ea4f417ee6e327b8 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 14:59:05 +0300 Subject: [PATCH 25/47] core --- ios/ar_flutter_plugin.podspec | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index 311ad4d4..e4d4782b 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -21,6 +21,7 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' #s.dependency 'ARCore', '~> 1.2.0' s.dependency 'ARCore/CloudAnchors', '~> 1.34.0' + s.dependency 'GTMSessionFetcher/Core', '~> 2.1' s.platform = :ios, '13.0' From 1d4fb3a361425a728bd7ef72c101da39980e2c54 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 15:00:08 +0300 Subject: [PATCH 26/47] remove core --- ios/ar_flutter_plugin.podspec | 1 - 1 file changed, 1 deletion(-) diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index e4d4782b..311ad4d4 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -21,7 +21,6 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' #s.dependency 'ARCore', '~> 1.2.0' s.dependency 'ARCore/CloudAnchors', '~> 1.34.0' - s.dependency 'GTMSessionFetcher/Core', '~> 2.1' s.platform = :ios, '13.0' From d754d7c415482a4641a4eb655e3b52aadc28ffe0 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 15:18:55 +0300 Subject: [PATCH 27/47] upgrade android versions --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index dbdff724..9f34b800 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -37,7 +37,7 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.google.ar:core:1.22.0" + implementation "com.google.ar:core:1.33.0" implementation 'com.google.ar.sceneform:core:1.15.0' implementation 'com.google.ar.sceneform:assets:1.15.0' From 08913661845b5c845286606ad17af62e4e87bc35 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 17:10:38 +0300 Subject: [PATCH 28/47] detach anchors --- .../kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index 30540179..2aa63865 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -475,6 +475,9 @@ internal class AndroidARView( fun onDestroy() { try { + for (anchor in arSceneView.session!!.allAnchors) { + anchor?.detach(); + } arSceneView.session?.close() arSceneView.destroy() arSceneView.scene?.removeOnUpdateListener(sceneUpdateListener) From bbc7bb81c8fed1bab8a02a1603cd70baf4db06f3 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 17:18:45 +0300 Subject: [PATCH 29/47] prints --- .../kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index 2aa63865..acd93955 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -476,7 +476,8 @@ internal class AndroidARView( fun onDestroy() { try { for (anchor in arSceneView.session!!.allAnchors) { - anchor?.detach(); + Log.d(TAG, "detaching" + anchor?.cloudAnchorId) + anchor?.detach() } arSceneView.session?.close() arSceneView.destroy() @@ -488,6 +489,7 @@ internal class AndroidARView( } private fun initializeARView(call: MethodCall, result: MethodChannel.Result) { + Log.d(TAG, "initializeARView") // Unpack call arguments val argShowFeaturePoints: Boolean? = call.argument("showFeaturePoints") val argPlaneDetectionConfig: Int? = call.argument("planeDetectionConfig") From 9fd0a46a82ff1f06ffeffcefa05bd64059cd921a Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 20:00:54 +0300 Subject: [PATCH 30/47] remove active notes before finish --- .../kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt | 1 - lib/managers/ar_session_manager.dart | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index acd93955..08067a36 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -476,7 +476,6 @@ internal class AndroidARView( fun onDestroy() { try { for (anchor in arSceneView.session!!.allAnchors) { - Log.d(TAG, "detaching" + anchor?.cloudAnchorId) anchor?.detach() } arSceneView.session?.close() diff --git a/lib/managers/ar_session_manager.dart b/lib/managers/ar_session_manager.dart index c7360d91..d36aeb66 100644 --- a/lib/managers/ar_session_manager.dart +++ b/lib/managers/ar_session_manager.dart @@ -183,6 +183,7 @@ class ARSessionManager { /// Dispose the AR view on the platforms to pause the scenes and disconnect the platform handlers. /// You should call this before removing the AR view to prevent out of memory erros dispose() async { + print('calling dispose from flutter'); try { await _channel.invokeMethod("dispose"); } catch (e) { From 3d2b5ee973100e50f7e3f56ea99b95725cf4da8f Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 20:24:06 +0300 Subject: [PATCH 31/47] minor upgrade dep --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 9f34b800..043d9820 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -37,7 +37,7 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.google.ar:core:1.33.0" + implementation "com.google.ar:core:1.34.0" implementation 'com.google.ar.sceneform:core:1.15.0' implementation 'com.google.ar.sceneform:assets:1.15.0' From 81d8204c305360a14cb2de099f086af09741777d Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Wed, 26 Oct 2022 20:31:07 +0300 Subject: [PATCH 32/47] fixes --- android/build.gradle | 2 +- .../io/carius/lars/ar_flutter_plugin/AndroidARView.kt | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 043d9820..9f34b800 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -37,7 +37,7 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.google.ar:core:1.34.0" + implementation "com.google.ar:core:1.33.0" implementation 'com.google.ar.sceneform:core:1.15.0' implementation 'com.google.ar.sceneform:assets:1.15.0' diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index 08067a36..1101bf46 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -475,9 +475,12 @@ internal class AndroidARView( fun onDestroy() { try { - for (anchor in arSceneView.session!!.allAnchors) { - anchor?.detach() + if (arSceneView.session != null) { + for (anchor in arSceneView.session!!.allAnchors) { + anchor?.detach() + } } + arSceneView.session?.close() arSceneView.destroy() arSceneView.scene?.removeOnUpdateListener(sceneUpdateListener) From d0d589abea6578f134cd13699f1ce3f9e058a081 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Thu, 27 Oct 2022 11:12:09 +0300 Subject: [PATCH 33/47] upgrade sceneform detach anchors before closing scene view --- android/build.gradle | 7 ++++--- .../lars/ar_flutter_plugin/AndroidARView.kt | 21 ++++++------------- .../ar_flutter_plugin/CloudAnchorHandler.kt | 10 ++++++++- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 9f34b800..9edd61c4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -37,14 +37,15 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.google.ar:core:1.33.0" + implementation "com.google.ar:core:1.34.0" - implementation 'com.google.ar.sceneform:core:1.15.0' - implementation 'com.google.ar.sceneform:assets:1.15.0' + implementation 'com.google.ar.sceneform:core:1.17.1' + implementation 'com.google.ar.sceneform:assets:1.17.1' implementation 'com.google.android.gms:play-services-auth:16+' implementation 'com.google.ar.sceneform.ux:sceneform-ux:1.17.1' implementation 'androidx.appcompat:appcompat:1.3.0' + } afterEvaluate { diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index 1101bf46..2e3d8f06 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -39,18 +39,9 @@ import com.google.ar.sceneform.rendering.* import android.view.ViewGroup import com.google.ar.core.TrackingState - - - - - - - - - - - - +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking internal class AndroidARView( @@ -480,11 +471,11 @@ internal class AndroidARView( anchor?.detach() } } - - arSceneView.session?.close() - arSceneView.destroy() + cloudAnchorHandler.dispose(); arSceneView.scene?.removeOnUpdateListener(sceneUpdateListener) arSceneView.scene?.removeOnPeekTouchListener(onNodeTapListener) + arSceneView.session?.close() + arSceneView.destroy() }catch (e : Exception){ e.printStackTrace(); } diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/CloudAnchorHandler.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/CloudAnchorHandler.kt index 5e0724d4..b73cd667 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/CloudAnchorHandler.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/CloudAnchorHandler.kt @@ -15,7 +15,7 @@ internal class CloudAnchorHandler( arSession: Session ) { } private val TAG: String = CloudAnchorHandler::class.java.simpleName - private val pendingAnchors = HashMap>() + val pendingAnchors = HashMap>() private val session: Session = arSession @Synchronized @@ -52,6 +52,14 @@ internal class CloudAnchorHandler( arSession: Session ) { } } + @Synchronized + fun dispose() { + for (pendingAnchor in pendingAnchors) { + pendingAnchor.key.detach() + } + clearListeners() + } + // Remove all listeners @Synchronized fun clearListeners() { From 917b30ebd13948ff3b87b80dca1aab9ece828363 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Thu, 27 Oct 2022 14:22:10 +0300 Subject: [PATCH 34/47] revert ios version --- ios/ar_flutter_plugin.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index 311ad4d4..4af5e5f8 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -20,7 +20,7 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. s.static_framework = true #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' #s.dependency 'ARCore', '~> 1.2.0' - s.dependency 'ARCore/CloudAnchors', '~> 1.34.0' + s.dependency 'ARCore/CloudAnchors', '~> 1.32.0' s.platform = :ios, '13.0' From b3f8b9286f7ba2114852ccdbcb7f7e970b76b431 Mon Sep 17 00:00:00 2001 From: "dnkoulouris@macbook" Date: Thu, 15 Dec 2022 16:46:29 +0200 Subject: [PATCH 35/47] update arcore api to 1.35.0 --- android/build.gradle | 2 +- ios/Classes/JWTGenerator.swift | 2 +- ios/ar_flutter_plugin.podspec | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 9edd61c4..db8e9dca 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -37,7 +37,7 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.google.ar:core:1.34.0" + implementation "com.google.ar:core:1.35.0" implementation 'com.google.ar.sceneform:core:1.17.1' implementation 'com.google.ar.sceneform:assets:1.17.1' diff --git a/ios/Classes/JWTGenerator.swift b/ios/Classes/JWTGenerator.swift index f5c509b4..32a23799 100644 --- a/ios/Classes/JWTGenerator.swift +++ b/ios/Classes/JWTGenerator.swift @@ -36,7 +36,7 @@ class JWTGenerator { let exp: Date let aud: String } - let jwtTokenClaims = JWTTokenClaims(iss: clientEmail, sub: clientEmail, iat: Date(), exp: Date(timeIntervalSinceNow: 3600), aud: "https://arcorecloudanchor.googleapis.com/") + let jwtTokenClaims = JWTTokenClaims(iss: clientEmail, sub: clientEmail, iat: Date(), exp: Date(timeIntervalSinceNow: 3600), aud: "https://arcore.googleapis.com/") var jwtToken = JWT(header: jwtTokenHeader, claims: jwtTokenClaims) diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index 4af5e5f8..a9badd29 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -20,7 +20,7 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. s.static_framework = true #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' #s.dependency 'ARCore', '~> 1.2.0' - s.dependency 'ARCore/CloudAnchors', '~> 1.32.0' + s.dependency 'ARCore/CloudAnchors', '~> 1.35.0' s.platform = :ios, '13.0' From d1b942cc7f75acb910a68b1757725f6dd3cecfdb Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Tue, 10 Jan 2023 17:34:25 +0200 Subject: [PATCH 36/47] fixes --- ios/ar_flutter_plugin.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index a9badd29..ecb91b21 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -20,7 +20,7 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. s.static_framework = true #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' #s.dependency 'ARCore', '~> 1.2.0' - s.dependency 'ARCore/CloudAnchors', '~> 1.35.0' + s.dependency 'ARCore/CloudAnchors', '~> 1.33.0' s.platform = :ios, '13.0' From 75c65709b316632c42437a16beb2452632e0aab4 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Tue, 10 Jan 2023 17:34:55 +0200 Subject: [PATCH 37/47] fixes --- ios/ar_flutter_plugin.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index ecb91b21..a9badd29 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -20,7 +20,7 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. s.static_framework = true #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' #s.dependency 'ARCore', '~> 1.2.0' - s.dependency 'ARCore/CloudAnchors', '~> 1.33.0' + s.dependency 'ARCore/CloudAnchors', '~> 1.35.0' s.platform = :ios, '13.0' From e8bfb7e6a14db37635115038b9a22ac643a72b13 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Tue, 10 Jan 2023 17:42:32 +0200 Subject: [PATCH 38/47] README.md updates and version bump CHANGELOG.md updates pubspec.yaml version bump --- CHANGELOG.md | 4 ++++ README.md | 2 +- cloudAnchorSetup.md | 4 ++-- pubspec.yaml | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42e30719..2dc69d2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +##0.7.4 +* Uses New ARCore API 1.35.0 +* Place an anchor at point (X,Y) of screen programmatically + ##0.7.3 * Update the examples with null-safety diff --git a/README.md b/README.md index 2b7ecb6f..98d3e78c 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Or manually add this to your `pubspec.yaml` file (and run `flutter pub get`): ```yaml dependencies: - ar_flutter_plugin: ^0.7.3 + ar_flutter_plugin: ^0.7.4 ``` ### Importing diff --git a/cloudAnchorSetup.md b/cloudAnchorSetup.md index 8115c41c..f283c073 100644 --- a/cloudAnchorSetup.md +++ b/cloudAnchorSetup.md @@ -5,9 +5,9 @@ Follow the steps below to set up your application. ## Set up Google Cloud Anchor Service -The Google Cloud Anchor API is used by the plugin to upload, store and download AR anchors. If your app uses the plugin's shared AR experience features, the following setup steps are required: +The Google ARCore API is used by the plugin to upload, store and download AR anchors. If your app uses the plugin's shared AR experience features, the following setup steps are required: -1. Activate the [Cloud Anchor API](https://console.cloud.google.com/apis/api/arcorecloudanchor.googleapis.com) in your [Google Cloud Console](https://console.cloud.google.com) for the respective project +1. Activate the [ARCore API](https://console.cloud.google.com/apis/library/arcore) in your [Google Cloud Console](https://console.cloud.google.com) for the respective project 2. Register the Android part of your Flutter Application * Perform the following steps to create a OAuth2 project (based on the [Android Cloud Anchors Developer Guide](https://developers.google.com/ar/develop/java/cloud-anchors/developer-guide-android?hl=en) and the [Guide for setting up OAuth 2.0](https://support.google.com/cloud/answer/6158849#zippy=)): * Go to the [Google Cloud Platform Console](https://console.cloud.google.com). diff --git a/pubspec.yaml b/pubspec.yaml index 8a25261f..c77a5da8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: ar_flutter_plugin description: Flutter Plugin for creating (collaborative) Augmented Reality experiences - Supports ARKit for iOS and ARCore for Android devices. -version: 0.7.3 +version: 0.7.4 homepage: https://lars.carius.io repository: https://github.com/CariusLars/ar_flutter_plugin From 32c36234f4c03dee1a2e656a6e30e85aea653712 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Tue, 10 Jan 2023 17:45:36 +0200 Subject: [PATCH 39/47] README.md updates and version bump CHANGELOG.md updates pubspec.yaml version bump --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dc69d2c..9553480c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Changelog ##0.7.4 -* Uses New ARCore API 1.35.0 +* Uses New ARCore API 1.35.0 (ARCore API required to be enabled in Google Cloud Console) * Place an anchor at point (X,Y) of screen programmatically ##0.7.3 From 33ef55ec4d6186637350899ad639479e828d3939 Mon Sep 17 00:00:00 2001 From: "dnkoulouris@macbook" Date: Fri, 19 May 2023 00:02:45 +0300 Subject: [PATCH 40/47] initial geospatial api implementation --- ios/Classes/IosARView.swift | 40 +++++++++++++++++++++++----- ios/ar_flutter_plugin.podspec | 6 ++--- lib/managers/ar_session_manager.dart | 27 +++++++++++++++---- lib/models/ar_anchor.dart | 10 +++---- 4 files changed, 63 insertions(+), 20 deletions(-) diff --git a/ios/Classes/IosARView.swift b/ios/Classes/IosARView.swift index f036ca68..49b1a508 100644 --- a/ios/Classes/IosARView.swift +++ b/ios/Classes/IosARView.swift @@ -4,6 +4,7 @@ import Foundation import ARKit import Combine import ARCoreCloudAnchors +import ARCoreGeospatial class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureRecognizerDelegate, ARSessionDelegate { let sceneView: ARSCNView @@ -86,6 +87,26 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco let htResult = parseTouchLocation(touchLocation: coordinates, returnHitResult: true); result(htResult); break; + case "placeGeospatial": + do { + var coordinates = CLLocationCoordinate2D(); + coordinates.latitude = arguments!["lat"] as! Double; + coordinates.longitude = arguments!["lon"] as! Double; + var anchor = try self.arcoreSession?.createAnchor( + coordinate: coordinates, + altitude: arguments!["alt"] as! Double, + eastUpSouthQAnchor: simd_quatf(vector: simd_float4(x: 0, y: 0, z: 0, w: 0)) + ); + + let arAnchor = ARAnchor(transform: anchor!.transform) + self.sceneView.session.add(anchor: arAnchor); + result(serializeAnchor(anchor: arAnchor, anchorNode: nil, ganchor: anchor!, name: arguments!["name"] as! String)); + + } catch { + print(error) + } + result(nil); + break; case "getCameraPose": if let cameraPose = sceneView.session.currentFrame?.camera.transform { result(serializeMatrix(cameraPose)) @@ -190,15 +211,19 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco arcoreSession = try! GARSession.session() if (arcoreSession != nil){ - let configuration = GARSessionConfiguration(); - configuration.cloudAnchorMode = .enabled; - arcoreSession?.setConfiguration(configuration, error: nil); + +// configuration.cloudAnchorMode = .enabled; + if let token = JWTGenerator().generateWebToken(){ arcoreSession!.setAuthToken(token) cloudAnchorHandler = CloudAnchorHandler(session: arcoreSession!) arcoreSession!.delegate = cloudAnchorHandler arcoreSession!.delegateQueue = DispatchQueue.main + + let configuration = GARSessionConfiguration(); + configuration.geospatialMode = .enabled; + arcoreSession?.setConfiguration(configuration, error: nil); arcoreMode = true } else { @@ -524,7 +549,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco guard let sceneView = recognizer.view as? ARSCNView else { return } - parseTouchLocation(touchLocation: recognizer.location(in: sceneView), returnHitResult: false) + parseTouchLocation(touchLocation: recognizer.location(in: sceneView), returnHitResult: false); } func parseTouchLocation(touchLocation: CGPoint, returnHitResult: Bool) -> Any? { @@ -538,18 +563,19 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco let planeTypes: ARHitTestResult.ResultType if #available(iOS 11.3, *){ - planeTypes = ARHitTestResult.ResultType([.existingPlaneUsingGeometry, .featurePoint]) + planeTypes = ARHitTestResult.ResultType([.existingPlaneUsingGeometry, .featurePoint]); }else { - planeTypes = ARHitTestResult.ResultType([.existingPlaneUsingExtent, .featurePoint]) + planeTypes = ARHitTestResult.ResultType([.existingPlaneUsingExtent, .featurePoint]); } - let planeAndPointHitResults = sceneView.hitTest(touchLocation, types: planeTypes) + let planeAndPointHitResults = sceneView.hitTest(touchLocation, types: planeTypes); // store the alignment of the tapped plane anchor so we can refer to is later when transforming the node if planeAndPointHitResults.count > 0, let hitAnchor = planeAndPointHitResults.first?.anchor as? ARPlaneAnchor { self.tappedPlaneAnchorAlignment = hitAnchor.alignment } + let serializedPlaneAndPointHitResults = planeAndPointHitResults.map{serializeHitResult($0)} if (serializedPlaneAndPointHitResults.count != 0) { diff --git a/ios/ar_flutter_plugin.podspec b/ios/ar_flutter_plugin.podspec index a9badd29..6fd35552 100644 --- a/ios/ar_flutter_plugin.podspec +++ b/ios/ar_flutter_plugin.podspec @@ -18,9 +18,9 @@ A Flutter plugin for shared AR experiences supporting Android and iOS. s.dependency 'GLTFSceneKit' s.dependency 'SwiftJWT' s.static_framework = true - #s.dependency 'ARCore/CloudAnchors', '~> 1.12.0' - #s.dependency 'ARCore', '~> 1.2.0' - s.dependency 'ARCore/CloudAnchors', '~> 1.35.0' + s.dependency 'ARCore', '~> 1.37.0' + s.dependency 'ARCore/CloudAnchors', '~> 1.37.0' + s.dependency 'ARCore/Geospatial', '~> 1.37.0' s.platform = :ios, '13.0' diff --git a/lib/managers/ar_session_manager.dart b/lib/managers/ar_session_manager.dart index d36aeb66..3ee655c0 100644 --- a/lib/managers/ar_session_manager.dart +++ b/lib/managers/ar_session_manager.dart @@ -51,10 +51,25 @@ class ARSessionManager { /// Places anchor in given 2D coordinates (starting from the top-left side of the screen) Future placeBasedOnScreenCoordinates(double x, double y) async { try { - return await _channel.invokeMethod>('placeBasedOnCoordinates', { - "x" : x, - "y" : y + return await _channel.invokeMethod>('placeBasedOnCoordinates', {"x": x, "y": y}); + } catch (e) { + print('Error caught: ' + e.toString()); + return null; + } + } + + /// Places anchor in lat-lon-alt coordinates using GeoSpatial API + Future placeGeospatial(double lat, double lon, double alt, String name) async { + try { + var result = await _channel.invokeMethod('placeGeospatial', { + "lat": lat, + "lon": lon, + "alt": alt, + "name": name, }); + + var anchor = ARAnchor.fromJson(result); + return anchor; } catch (e) { print('Error caught: ' + e.toString()); return null; @@ -127,7 +142,8 @@ class ARSessionManager { case 'onPlaneOrPointTap': if (onPlaneOrPointTap != null) { final rawHitTestResults = call.arguments as List; - final serializedHitTestResults = rawHitTestResults.map((hitTestResult) => Map.from(hitTestResult)).toList(); + final serializedHitTestResults = + rawHitTestResults.map((hitTestResult) => Map.from(hitTestResult)).toList(); final hitTestResults = serializedHitTestResults.map((e) { return ARHitTestResult.fromJson(e); }).toList(); @@ -177,7 +193,8 @@ class ARSessionManager { /// Displays the [errorMessage] in a snackbar of the parent widget onError(String errorMessage) { ScaffoldMessenger.of(buildContext).showSnackBar(SnackBar( - content: Text(errorMessage), action: SnackBarAction(label: 'HIDE', onPressed: ScaffoldMessenger.of(buildContext).hideCurrentSnackBar))); + content: Text(errorMessage), + action: SnackBarAction(label: 'HIDE', onPressed: ScaffoldMessenger.of(buildContext).hideCurrentSnackBar))); } /// Dispose the AR view on the platforms to pause the scenes and disconnect the platform handlers. diff --git a/lib/models/ar_anchor.dart b/lib/models/ar_anchor.dart index 4ab87e84..3cb197cd 100644 --- a/lib/models/ar_anchor.dart +++ b/lib/models/ar_anchor.dart @@ -20,7 +20,7 @@ abstract class ARAnchor { final String name; /// Constructs an [ARAnchor] from a serialized anchor object - factory ARAnchor.fromJson(Map arguments) { + factory ARAnchor.fromJson(Map arguments) { final type = arguments['type']; switch (type) { case 0: //(= AnchorType.plane) @@ -59,7 +59,7 @@ class ARPlaneAnchor extends ARAnchor { /// Time to live of the anchor: Determines how long the anchor is stored once it is uploaded to the google cloud anchor API (optional, defaults to 1 day (24hours)) int? ttl; - static ARPlaneAnchor fromJson(Map json) => + static ARPlaneAnchor fromJson(Map json) => aRPlaneAnchorFromJson(json); @override @@ -67,7 +67,7 @@ class ARPlaneAnchor extends ARAnchor { } /// Constructs an [ARPlaneAnchor] from a serialized PlaneAnchor object -ARPlaneAnchor aRPlaneAnchorFromJson(Map json) { +ARPlaneAnchor aRPlaneAnchorFromJson(Map json) { return ARPlaneAnchor( transformation: const MatrixConverter().fromJson(json['transformation'] as List), @@ -99,14 +99,14 @@ class ARUnkownAnchor extends ARAnchor { {required AnchorType type, required Matrix4 transformation, String? name}) : super(type: type, transformation: transformation, name: name); - static ARUnkownAnchor fromJson(Map json) => + static ARUnkownAnchor fromJson(Map json) => aRUnkownAnchorFromJson(json); @override Map toJson() => aRUnkownAnchorToJson(this); } -ARUnkownAnchor aRUnkownAnchorFromJson(Map json) { +ARUnkownAnchor aRUnkownAnchorFromJson(Map json) { return ARUnkownAnchor( type: json['type'], transformation: From 2a93712575b81510cb8e9b7a2b839989b1805040 Mon Sep 17 00:00:00 2001 From: dnkoulouris Date: Fri, 19 May 2023 17:46:08 +0300 Subject: [PATCH 41/47] ios implementation --- ios/Classes/IosARView.swift | 53 +++++++++++++++++++++++------ lib/managers/ar_anchor_manager.dart | 5 +++ pubspec.yaml | 8 ++--- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/ios/Classes/IosARView.swift b/ios/Classes/IosARView.swift index 49b1a508..89a77da3 100644 --- a/ios/Classes/IosARView.swift +++ b/ios/Classes/IosARView.swift @@ -73,7 +73,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco result(nil) } - func onSessionMethodCalled(_ call :FlutterMethodCall, _ result:FlutterResult) { + func onSessionMethodCalled(_ call :FlutterMethodCall, _ result:@escaping FlutterResult) { let arguments = call.arguments as? Dictionary switch call.method { @@ -92,20 +92,24 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco var coordinates = CLLocationCoordinate2D(); coordinates.latitude = arguments!["lat"] as! Double; coordinates.longitude = arguments!["lon"] as! Double; - var anchor = try self.arcoreSession?.createAnchor( + try arcoreSession!.createAnchorOnTerrain( coordinate: coordinates, - altitude: arguments!["alt"] as! Double, - eastUpSouthQAnchor: simd_quatf(vector: simd_float4(x: 0, y: 0, z: 0, w: 0)) + altitudeAboveTerrain: 0, + eastUpSouthQAnchor: simd_quatf(vector: simd_float4(x: 0, y: 0, z: 0, w: 0)), + completionHandler: { anchor, state in + print(state.rawValue); + if (state == GARTerrainAnchorState.success) { + let newAnchor = ARAnchor(transform: anchor!.transform); + result(serializeAnchor(anchor: newAnchor, anchorNode: nil, ganchor: anchor!, name: arguments!["name"] as! String)); + } else { + result(nil); + } + } ); - - let arAnchor = ARAnchor(transform: anchor!.transform) - self.sceneView.session.add(anchor: arAnchor); - result(serializeAnchor(anchor: arAnchor, anchorNode: nil, ganchor: anchor!, name: arguments!["name"] as! String)); - } catch { print(error) + result(nil); } - result(nil); break; case "getCameraPose": if let cameraPose = sceneView.session.currentFrame?.camera.transform { @@ -207,6 +211,33 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco deleteAnchor(anchorName: name) } break + case "initGeoSpatialMode": + arcoreSession = try! GARSession.session() + + if (arcoreSession != nil){ + +// configuration.cloudAnchorMode = .enabled; + + if let token = JWTGenerator().generateWebToken(){ + arcoreSession!.setAuthToken(token) + +// cloudAnchorHandler = CloudAnchorHandler(session: arcoreSession!) +// arcoreSession!.delegate = cloudAnchorHandler + arcoreSession!.delegateQueue = DispatchQueue.main + + let configuration = GARSessionConfiguration(); + configuration.geospatialMode = .enabled; + arcoreSession?.setConfiguration(configuration, error: nil); + + arcoreMode = true + } else { + sessionManagerChannel.invokeMethod("onError", arguments: ["Error generating JWT, have you added cloudAnchorKey.json into the example/ios/Runner directory?"]) + } + } else { + sessionManagerChannel.invokeMethod("onError", arguments: ["Error initializing Google AR Session"]) + } + + break case "initGoogleCloudAnchorMode": arcoreSession = try! GARSession.session() @@ -222,7 +253,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco arcoreSession!.delegateQueue = DispatchQueue.main let configuration = GARSessionConfiguration(); - configuration.geospatialMode = .enabled; + configuration.cloudAnchorMode = .enabled; arcoreSession?.setConfiguration(configuration, error: nil); arcoreMode = true diff --git a/lib/managers/ar_anchor_manager.dart b/lib/managers/ar_anchor_manager.dart index 817bc27e..5d30b244 100644 --- a/lib/managers/ar_anchor_manager.dart +++ b/lib/managers/ar_anchor_manager.dart @@ -37,6 +37,11 @@ class ARAnchorManager { _channel.invokeMethod('initGoogleCloudAnchorMode', {}); } + /// Activates collaborative AR mode (using Google Cloud Anchors) + initGeoSpatialMode() async { + _channel.invokeMethod('initGeoSpatialMode', {}); + } + Future _platformCallHandler(MethodCall call) async { if (debug) { print('_platformCallHandler call ${call.method} ${call.arguments}'); diff --git a/pubspec.yaml b/pubspec.yaml index c77a5da8..6d3fbc4a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,10 +11,10 @@ environment: dependencies: flutter: sdk: flutter - permission_handler: ^10.1.0 - vector_math: ^2.1.1 - json_annotation: ^4.5.0 - geolocator: ^9.0.0 + permission_handler: ^10.2.0 + vector_math: ^2.1.4 + json_annotation: ^4.8.1 + geolocator: ^9.0.2 dev_dependencies: flutter_test: From be799e941077c9c5290afc4f4c01b22d4888cd95 Mon Sep 17 00:00:00 2001 From: "dnkoulouris@macbook" Date: Mon, 29 May 2023 19:17:24 +0300 Subject: [PATCH 42/47] add alt --- ios/Classes/IosARView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Classes/IosARView.swift b/ios/Classes/IosARView.swift index 89a77da3..3fd3dd54 100644 --- a/ios/Classes/IosARView.swift +++ b/ios/Classes/IosARView.swift @@ -94,7 +94,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco coordinates.longitude = arguments!["lon"] as! Double; try arcoreSession!.createAnchorOnTerrain( coordinate: coordinates, - altitudeAboveTerrain: 0, + altitudeAboveTerrain: arguments!["alt"] as! Double, eastUpSouthQAnchor: simd_quatf(vector: simd_float4(x: 0, y: 0, z: 0, w: 0)), completionHandler: { anchor, state in print(state.rawValue); From aaa33a41d1cb65229bb9f545df7583c6cf3e332a Mon Sep 17 00:00:00 2001 From: "dnkoulouris@macbook" Date: Fri, 2 Jun 2023 17:50:40 +0300 Subject: [PATCH 43/47] 0.0.1 --- .../carius/lars/ar_flutter_plugin/AndroidARView.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index 2e3d8f06..6eb3e23e 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -273,6 +273,19 @@ internal class AndroidARView( sessionManagerChannel.invokeMethod("onError", listOf("Error initializing cloud anchor mode: Session is null")) } } + "initGeospatialMode" -> { + if (arSceneView.session != null) { + val config = Config(arSceneView.session) + config.cloudAnchorMode = Config.CloudAnchorMode.ENABLED + config.updateMode = Config.UpdateMode.LATEST_CAMERA_IMAGE + config.focusMode = Config.FocusMode.AUTO + arSceneView.session?.configure(config) + + cloudAnchorHandler = CloudAnchorHandler(arSceneView.session!!) + } else { + sessionManagerChannel.invokeMethod("onError", listOf("Error initializing cloud anchor mode: Session is null")) + } + } "uploadAnchor" -> { val anchorName: String? = call.argument("name") val ttl: Int? = call.argument("ttl") From 283053535ab97f4cd87edf9c8379a146e3cfd59c Mon Sep 17 00:00:00 2001 From: "denkoul@desktop-home" Date: Sun, 14 Jul 2024 19:54:39 +0300 Subject: [PATCH 44/47] test --- android/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index db8e9dca..e89ba9bf 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,14 +2,14 @@ group 'io.carius.lars.ar_flutter_plugin' version '1.0-SNAPSHOT' buildscript { - ext.kotlin_version = '1.3.50' + ext.kotlin_version = '1.7.10' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' + classpath 'com.android.tools.build:gradle:7.3.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -25,7 +25,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - compileSdkVersion 30 + compileSdkVersion 34 sourceSets { main.java.srcDirs += 'src/main/kotlin' From 6ab19f7392998c8195ecd62bfde8f0a70ca3c360 Mon Sep 17 00:00:00 2001 From: "dnkoulouris@macbook" Date: Tue, 16 Jul 2024 12:13:47 +0300 Subject: [PATCH 45/47] update libraries migrate android --- android/build.gradle | 11 +++++------ android/gradle/wrapper/gradle-wrapper.properties | 3 ++- pubspec.yaml | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index e89ba9bf..14660244 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -5,11 +5,11 @@ buildscript { ext.kotlin_version = '1.7.10' repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' + classpath 'com.android.tools.build:gradle:8.5.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -25,12 +25,12 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - compileSdkVersion 34 - + namespace 'io.carius.lars.ar_flutter_plugin' sourceSets { main.java.srcDirs += 'src/main/kotlin' } defaultConfig { + compileSdk 34 minSdkVersion 24 } } @@ -54,8 +54,7 @@ afterEvaluate { for (def dependency : configuration.dependencies) { if (dependency.group == 'io.flutter' && dependency.name.startsWith('flutter_embedding') && - dependency.isTransitive()) - { + dependency.isTransitive()) { containsEmbeddingDependencies = true break } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 3c9d0852..9f9d85f5 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Mon Jul 15 18:10:20 EEST 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/pubspec.yaml b/pubspec.yaml index c77a5da8..1f4da32e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,10 +11,10 @@ environment: dependencies: flutter: sdk: flutter - permission_handler: ^10.1.0 - vector_math: ^2.1.1 - json_annotation: ^4.5.0 - geolocator: ^9.0.0 + permission_handler: ^11.3.1 + vector_math: ^2.1.4 + json_annotation: ^4.9.0 + geolocator: ^12.0.0 dev_dependencies: flutter_test: From 8caf9893559b909f753bd06619dce1c37b2fa04f Mon Sep 17 00:00:00 2001 From: "dnkoulouris@macbook" Date: Tue, 16 Jul 2024 12:15:41 +0300 Subject: [PATCH 46/47] 0.0.2 --- pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pubspec.yaml b/pubspec.yaml index 1f4da32e..88658a3e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,6 +8,7 @@ environment: sdk: ">=2.16.1 <3.0.0" flutter: ">=1.20.0" + dependencies: flutter: sdk: flutter From 8825fe69949490069ca7fdc17c67f11113ee0c01 Mon Sep 17 00:00:00 2001 From: "denkoul@pir-desktop" Date: Mon, 19 May 2025 11:14:10 +0300 Subject: [PATCH 47/47] place geospatial addition --- .../kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt index 6eb3e23e..01240552 100644 --- a/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt +++ b/android/src/main/kotlin/io/carius/lars/ar_flutter_plugin/AndroidARView.kt @@ -106,6 +106,9 @@ internal class AndroidARView( } else { result.error("Error", "could not get camera pose", null) } + } + "placeGeospatial" -> { + } "placeBasedOnCoordinates" -> { if (call.arguments is Map<*,*>) {