olexale / arkit_flutter_plugin

ARKit Flutter Plugin
MIT License
798 stars 228 forks source link

Geolocation based AR #200

Open jeromeDms opened 1 year ago

jeromeDms commented 1 year ago

Hi there I do not see any example showing how we can achieve geo-based AR. I'd like to place POIs on AR view, based on their location (Latitude, longitude). POIs would be simple images.

Is there a way to achieve this ? Thanks

justintoth commented 1 year ago

@jeromeDms Did you figure it out? I'm trying to do the same (but with properties instead of POIs) using the code below, however none of my properties display in the AR view. It's as if the X/Y/Z coordinates is set to 0/0/0 being the phone's location...

@injectable
class ArViewModel extends BaseViewModelWithProps<ArProps> {
  final ILocationService _locationService;
  late ARKitController arkitController;
  late SearchResultsModel model;

  ArViewModel(this._locationService);

  void onARKitViewCreated(ARKitController arkitController) {
    this.arkitController = arkitController;

    // Add test node, just to confirm that it works...
    final material = ARKitMaterial(diffuse: ARKitMaterialProperty.color(Colors.blue), specular: ARKitMaterialProperty.color(Colors.blue));
    final node = ARKitNode(geometry: ARKitSphere(radius: 0.1, materials: [material]), position: vector.Vector3(0, 0, -0.5));
    this.arkitController.add(node);

    // Add surrounding properties nodes.
    unawaited(_addSurroundingProperties());
  }

  Future<void> _addSurroundingProperties() async {
    // Get user's location.
    var position = await _locationService.getPosition();
    if (position == null) {
      // TODO:[JT] Show to user that they can't view surrounding properties with location services disabled.
      return;
    }

    // Get properties surrounding the user.
    var properties = await _getSurroundingProperties(position);
    if (!properties.isNullOrEmpty) {
      print('AR: found ${properties.length} surrounding properties...');
      // Add property nodes to AR view.
      for (var property in properties.where((sr) => sr.centroid != null)) {
        final vector = _convertCoordinatesToVector(property.centroid!, position.altitude);
        // TODO:[JT] Show for sale / for lease / off market signs instead of spheres.
        final material = ARKitMaterial(diffuse: ARKitMaterialProperty.color(Colors.red));
        final node = ARKitNode(geometry: ARKitSphere(radius: 0.5, materials: [material]), position: vector);
        await arkitController.add(node);
      }
    }
  }

  // TODO:[JT] Refresh surrounding properties as user moves...
  Future<List<SurroundingPropertyOutputModel>> _getSurroundingProperties(Position position) async {
    var rectangle = GeoRectangleModel();
    var latLongRange = 0.002;
    rectangle.updateSouthWestCorner(GeoPointModel()
      ..latitude = position.latitude - latLongRange
      ..longitude = position.longitude - latLongRange);
    rectangle.updateNorthEastCorner(GeoPointModel()
      ..latitude = position.latitude + latLongRange
      ..longitude = position.longitude + latLongRange);
    // TODO:[JT] Show inline progress indicator as surrounding properties refresh.
    var surroundingPropertiesResponse = await executeApiAction(
        () async => await propertySearchesService.getSurroundingSearchResults(
              rectangle.fromRectangle(),
              propertyMode: propertyMode,
            ),
        behavior: DialogBehavior.none);

    var properties = <SurroundingPropertyOutputModel>[];
    if (surroundingPropertiesResponse?.nonPublicRecords?.isNotEmpty == true) {
      properties = surroundingPropertiesResponse!.nonPublicRecords!;
    }
    if (surroundingPropertiesResponse?.publicRecords?.isNotEmpty == true) {
      properties.addAll(surroundingPropertiesResponse!.publicRecords!);
    }
    return properties;
  }

  vector.Vector3 _convertCoordinatesToVector(GeoPointModel geoPoint, double altitude) {
    var cosLat = cos(geoPoint.latitude! * pi / 180.0);
    var sinLat = sin(geoPoint.latitude! * pi / 180.0);
    var cosLon = cos(geoPoint.longitude! * pi / 180.0);
    var sinLon = sin(geoPoint.longitude! * pi / 180.0);
    var rad = 6378137.0;
    var f = 1.0 / 298.257224;
    var C = 1.0 / sqrt(cosLat * cosLat + (1 - f) * (1 - f) * sinLat * sinLat);
    var S = (1.0 - f) * (1.0 - f) * C;
    var h = altitude;
    var x = (rad * C + h) * cosLat * cosLon;
    var y = (rad * C + h) * cosLat * sinLon;
    var z = (rad * S + h) * sinLat;
    return vector.Vector3(x, y, z);
  }

  @override
  void dispose() {
    arkitController.dispose();
    super.dispose();
  }
}
jeromeDms commented 1 year ago

Hi No, unfortunately I did not find a way to achieve using this plugin.

bawantha commented 3 months ago

still no ?