Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support to calculate distance between device and anchor and distance between two anchors #115

Merged
merged 7 commits into from Jul 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Expand Up @@ -16,10 +16,11 @@ flutter pub add ar_flutter_plugin
```

Or manually add this to your `pubspec.yaml` file (and run `flutter pub get`):
# ar_flutter_plugin package extension

```yaml
dependencies:
ar_flutter_plugin: ^0.6.4
ar_flutter_plugin: ^0.6.5
```

### Importing
Expand Down Expand Up @@ -92,3 +93,4 @@ Contributions to this plugin are very welcome. To contribute code and discuss id
This is a rough sketch of the architecture the plugin implements:

![ar_plugin_architecture](./AR_Plugin_Architecture_highlevel.svg)

Expand Up @@ -21,6 +21,7 @@ import com.google.ar.sceneform.ux.*
import io.carius.lars.ar_flutter_plugin.Serialization.deserializeMatrix4
import io.carius.lars.ar_flutter_plugin.Serialization.serializeAnchor
import io.carius.lars.ar_flutter_plugin.Serialization.serializeHitResult
import io.carius.lars.ar_flutter_plugin.Serialization.serializePose
import io.flutter.FlutterInjector
import io.flutter.embedding.engine.loader.FlutterLoader
import io.flutter.plugin.common.BinaryMessenger
Expand Down Expand Up @@ -99,6 +100,22 @@ internal class AndroidARView(
"init" -> {
initializeARView(call, result)
}
"getAnchorPose" -> {
val anchorNode = arSceneView.scene.findByName(call.argument("anchorId")) as AnchorNode?
if (anchorNode != null) {
result.success(serializePose(anchorNode.anchor!!.pose))
} else {
result.error("Error", "could not get anchor pose", null)
}
}
"getCameraPose" -> {
val cameraPose = arSceneView.arFrame?.camera?.displayOrientedPose
if (cameraPose != null) {
result.success(serializePose(cameraPose!!))
} else {
result.error("Error", "could not get camera pose", null)
}
}
"snapshot" -> {
var bitmap = Bitmap.createBitmap(arSceneView.width, arSceneView.height,
Bitmap.Config.ARGB_8888);
Expand Down
2 changes: 1 addition & 1 deletion example/ios/Runner.xcodeproj/project.pbxproj
Expand Up @@ -166,7 +166,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1020;
LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
Expand Down
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1300"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
2 changes: 2 additions & 0 deletions example/ios/Runner/Info.plist
Expand Up @@ -47,5 +47,7 @@
<string>This app needs access to location when open.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to location when in the background.</string>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
</dict>
</plist>
14 changes: 14 additions & 0 deletions ios/Classes/IosARView.swift
Expand Up @@ -81,6 +81,20 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco
//result(nil)
initializeARView(arguments: arguments!, result: result)
break
case "getCameraPose":
if let cameraPose = sceneView.session.currentFrame?.camera.transform {
result(serializeMatrix(cameraPose))
} else {
result(FlutterError())
}
break
case "getAnchorPose":
if let cameraPose = anchorCollection[arguments?["anchorId"] as! String]?.transform {
result(serializeMatrix(cameraPose))
} else {
result(FlutterError())
}
break
case "snapshot":
// call the SCNView Snapshot method and return the Image
let snapshotImage = sceneView.snapshot()
Expand Down
2 changes: 1 addition & 1 deletion ios/ar_flutter_plugin.podspec
Expand Up @@ -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.26.0'
s.dependency 'ARCore/CloudAnchors', '~> 1.32.0'
s.platform = :ios, '13.0'


Expand Down
2 changes: 1 addition & 1 deletion lib/managers/ar_location_manager.dart
Expand Up @@ -78,7 +78,7 @@ class ARLocationManager {
// When we reach here, permissions are granted and we can
// continue accessing the position of the device.
locationStream =
Geolocator.getPositionStream(desiredAccuracy: LocationAccuracy.high)
Geolocator.getPositionStream(locationSettings: LocationSettings(accuracy: LocationAccuracy.high))
.listen((Position position) {
//print(position.latitude.toString() + ', ' + position.longitude.toString());
currentLocation = position;
Expand Down
83 changes: 71 additions & 12 deletions lib/managers/ar_session_manager.dart
@@ -1,8 +1,13 @@
import 'dart:math' show sqrt;
import 'dart:typed_data';

import 'package:ar_flutter_plugin/datatypes/config_planedetection.dart';
import 'package:ar_flutter_plugin/models/ar_anchor.dart';
import 'package:ar_flutter_plugin/models/ar_hittest_result.dart';
import 'package:ar_flutter_plugin/utils/json_converters.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:ar_flutter_plugin/datatypes/config_planedetection.dart';
import 'package:vector_math/vector_math_64.dart';

// Type definitions to enforce a consistent use of the API
typedef ARHitResultHandler = void Function(List<ARHitTestResult> hits);
Expand All @@ -24,15 +29,76 @@ 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) {
print("ARSessionManager initialized");
}
}

/// Returns the camera pose in Matrix4 format with respect to the world coordinate system of the [ARView]
Future<Matrix4?> getCameraPose() async {
try {
final serializedCameraPose = await _channel.invokeMethod<List<dynamic>>('getCameraPose', {});
return MatrixConverter().fromJson(serializedCameraPose!);
} catch (e) {
print('Error caught: ' + e.toString());
return null;
}
}

/// Returns the given anchor pose in Matrix4 format with respect to the world coordinate system of the [ARView]
Future<Matrix4?> 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<List<dynamic>>('getAnchorPose', {
"anchorId": anchor.name,
});
return MatrixConverter().fromJson(serializedCameraPose!);
} catch (e) {
print('Error caught: ' + e.toString());
return null;
}
}

/// Returns the distance in meters between @anchor1 and @anchor2.
Future<double?> getDistanceBetweenAnchors(ARAnchor anchor1, ARAnchor anchor2) async {
var anchor1Pose = await getPose(anchor1);
var anchor2Pose = await getPose(anchor2);
var anchor1Translation = anchor1Pose?.getTranslation();
var anchor2Translation = anchor2Pose?.getTranslation();
if (anchor1Translation != null && anchor2Translation != null) {
return getDistanceBetweenVectors(anchor1Translation, anchor2Translation);
} else {
return null;
}
}

/// Returns the distance in meters between @anchor and device's camera.
Future<double?> getDistanceFromAnchor(ARAnchor anchor) async {
Matrix4? cameraPose = await getCameraPose();
Matrix4? anchorPose = await getPose(anchor);
Vector3? cameraTranslation = cameraPose?.getTranslation();
Vector3? anchorTranslation = anchorPose?.getTranslation();
if (anchorTranslation != null && cameraTranslation != null) {
return getDistanceBetweenVectors(anchorTranslation, cameraTranslation);
} else {
return null;
}
}

/// Returns the distance in meters between @vector1 and @vector2.
double getDistanceBetweenVectors(Vector3 vector1, Vector3 vector2) {
num dx = vector1.x - vector2.x;
num dy = vector1.y - vector2.y;
num dz = vector1.z - vector2.z;
double distance = sqrt(dx * dx + dy * dy + dz * dz);
return distance;
}

Future<void> _platformCallHandler(MethodCall call) {
if (debug) {
print('_platformCallHandler call ${call.method} ${call.arguments}');
Expand All @@ -48,10 +114,7 @@ class ARSessionManager {
case 'onPlaneOrPointTap':
if (onPlaneOrPointTap != null) {
final rawHitTestResults = call.arguments as List<dynamic>;
final serializedHitTestResults = rawHitTestResults
.map(
(hitTestResult) => Map<String, dynamic>.from(hitTestResult))
.toList();
final serializedHitTestResults = rawHitTestResults.map((hitTestResult) => Map<String, dynamic>.from(hitTestResult)).toList();
final hitTestResults = serializedHitTestResults.map((e) {
return ARHitTestResult.fromJson(e);
}).toList();
Expand Down Expand Up @@ -101,11 +164,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.
Expand Down
10 changes: 5 additions & 5 deletions 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.6.4
version: 0.6.5
homepage: https://lars.carius.io
repository: https://github.com/CariusLars/ar_flutter_plugin

Expand All @@ -11,10 +11,10 @@ environment:
dependencies:
flutter:
sdk: flutter
permission_handler: ^8.1.6
vector_math: ^2.1.0
json_annotation: ^4.0.1
geolocator: ^7.6.2
permission_handler: ^10.0.0
vector_math: ^2.1.2
json_annotation: ^4.5.0
geolocator: ^9.0.0

dev_dependencies:
flutter_test:
Expand Down